Import backports-3.18-rc1-1.

PREFIX=http://www.kernel.org/pub/linux/kernel/projects/backports
rm -rf *
curl -L $PREFIX/stable/v3.18-rc1/backports-3.18-rc1-1.tar.xz |
tar Jxv --strip-components=1

Change-Id: Ia14e6df34e278fd6295543696583b8981cb68a54
diff --git a/.local-symbols b/.local-symbols
index 7b8bcc1..8ed044e 100644
--- a/.local-symbols
+++ b/.local-symbols
@@ -17,6 +17,8 @@
 BACKPORT_USERSEL_BUILD_ALL=
 BACKPORT_CRYPTO_CCM=
 BACKPORT_BUILD_CRYPTO_CCM=
+BACKPORT_WANT_DEV_COREDUMP=
+BACKPORT_BUILD_WANT_DEV_COREDUMP=
 CFG80211=
 NL80211_TESTMODE=
 CFG80211_DEVELOPER_WARNINGS=
@@ -112,12 +114,12 @@
 ATH_COMMON=
 ATH_CARDS=
 ATH_DEBUG=
+ATH_TRACEPOINTS=
 ATH_REG_DYNAMIC_USER_REG_HINTS=
 ATH_REG_DYNAMIC_USER_CERT_TESTING=
 ATH5K=
 ATH5K_DEBUG=
 ATH5K_TRACER=
-ATH5K_AHB=
 ATH5K_PCI=
 ATH5K_TEST_CHANNELS=
 ATH9K_HW=
@@ -130,9 +132,11 @@
 ATH9K_DEBUGFS=
 ATH9K_STATION_STATISTICS=
 ATH9K_DFS_CERTIFIED=
+ATH9K_DYNACK=
 ATH9K_TX99=
 ATH9K_WOW=
 ATH9K_RFKILL=
+ATH9K_CHANNEL_CONTEXT=
 ATH9K_HTC=
 ATH9K_HTC_DEBUGFS=
 CARL9170=
@@ -150,6 +154,7 @@
 WIL6210=
 WIL6210_ISR_COR=
 WIL6210_TRACING=
+WIL6210_PLATFORM_MSM=
 ATH10K=
 ATH10K_PCI=
 ATH10K_DEBUG=
@@ -216,6 +221,7 @@
 IWLMVM=
 IWLWIFI_OPMODE_MODULAR=
 IWLWIFI_BCAST_FILTERING=
+IWLWIFI_UAPSD=
 IWLWIFI_DEBUG=
 IWLWIFI_DEBUGFS=
 IWLWIFI_DEBUG_EXPERIMENTAL_UCODE=
@@ -287,6 +293,8 @@
 RTL8723AE=
 RTL8723BE=
 RTL8188EE=
+RTL8192EE=
+RTL8821AE=
 RTL8192CU=
 RTLWIFI=
 RTLWIFI_PCI=
@@ -369,6 +377,8 @@
 I40E_VXLAN=
 I40E_DCB=
 I40EVF=
+FM10K=
+FM10K_VXLAN=
 USB_NET_DRIVERS=
 USB_CATC=
 USB_KAWETH=
@@ -488,6 +498,7 @@
 VIDEO_V4L2=
 VIDEO_ADV_DEBUG=
 VIDEO_FIXED_MINOR_RANGES=
+VIDEO_PCI_SKELETON=
 VIDEO_TUNER=
 V4L2_MEM2MEM_DEV=
 VIDEOBUF_GEN=
@@ -519,6 +530,7 @@
 RC_DEVICES=
 RC_ATI_REMOTE=
 IR_ENE=
+IR_HIX5HD2=
 IR_IMON=
 IR_MCEUSB=
 IR_ITE_CIR=
@@ -666,18 +678,21 @@
 DVB_USB_LME2510=
 DVB_USB_MXL111SF=
 DVB_USB_RTL28XXU=
+DVB_USB_DVBSKY=
 DVB_TTUSB_BUDGET=
 DVB_TTUSB_DEC=
 SMS_USB_DRV=
 DVB_B2C2_FLEXCOP_USB=
 DVB_B2C2_FLEXCOP_USB_DEBUG=
+DVB_AS102=
 VIDEO_EM28XX=
 VIDEO_EM28XX_V4L2=
 VIDEO_EM28XX_ALSA=
 VIDEO_EM28XX_DVB=
 VIDEO_EM28XX_RC=
-USB_MSI2500=
 USB_AIRSPY=
+USB_HACKRF=
+USB_MSI2500=
 MEDIA_PCI_SUPPORT=
 VIDEO_MEYE=
 STA2X11_VIP=
@@ -696,6 +711,7 @@
 VIDEO_HEXIUM_ORION=
 VIDEO_MXB=
 VIDEO_SOLO6X10=
+VIDEO_TW68=
 VIDEO_CX18=
 VIDEO_CX18_ALSA=
 VIDEO_CX23885=
@@ -715,7 +731,9 @@
 VIDEO_SAA7134_ALSA=
 VIDEO_SAA7134_RC=
 VIDEO_SAA7134_DVB=
+VIDEO_SAA7134_GO7007=
 VIDEO_SAA7164=
+DVB_AV7110_IR=
 DVB_AV7110=
 DVB_AV7110_OSD=
 DVB_BUDGET_CORE=
@@ -728,6 +746,7 @@
 DVB_PLUTO2=
 DVB_DM1105=
 DVB_PT1=
+DVB_PT3=
 MANTIS_CORE=
 DVB_MANTIS=
 DVB_HOPPER=
@@ -757,7 +776,6 @@
 VIDEO_TI_VPE=
 VIDEO_TI_VPE_DEBUG=
 V4L_TEST_DRIVERS=
-VIDEO_VIVI=
 VIDEO_MEM2MEM_TESTDEV=
 VIDEO_CAFE_CCIC=
 VIDEO_MMP_CAMERA=
@@ -797,6 +815,7 @@
 VIDEO_SAMSUNG_S5P_SDO=
 VIDEO_SAMSUNG_S5P_MIXER=
 VIDEO_SAMSUNG_S5P_MIXER_DEBUG=
+VIDEO_VIVID=
 SMS_SDIO_DRV=
 MEDIA_PARPORT_SUPPORT=
 VIDEO_BWQCAM=
@@ -989,6 +1008,8 @@
 MEDIA_TUNER_SI2157=
 MEDIA_TUNER_IT913X=
 MEDIA_TUNER_R820T=
+MEDIA_TUNER_MXL301RF=
+MEDIA_TUNER_QM1D1C0042=
 DVB_STB0899=
 DVB_STB6100=
 DVB_STV090x=
@@ -1049,6 +1070,7 @@
 DVB_RTL2832=
 DVB_RTL2832_SDR=
 DVB_SI2168=
+DVB_AS102_FE=
 DVB_VES1820=
 DVB_TDA10021=
 DVB_TDA10023=
@@ -1068,6 +1090,7 @@
 DVB_S921=
 DVB_DIB8000=
 DVB_MB86A20S=
+DVB_TC90522=
 DVB_PLL=
 DVB_TUNER_DIB0070=
 DVB_TUNER_DIB0090=
@@ -1077,6 +1100,7 @@
 DVB_ISL6421=
 DVB_ISL6423=
 DVB_A8293=
+DVB_SP2=
 DVB_LGS8GL5=
 DVB_LGS8GXX=
 DVB_ATBM8830=
diff --git a/MAINTAINERS b/MAINTAINERS
index f10ed39..a20df9b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -152,8 +152,9 @@
 
 6LOWPAN GENERIC (BTLE/IEEE 802.15.4)
 M:	Alexander Aring <alex.aring@gmail.com>
-L:	linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers)
+M:	Jukka Rissanen <jukka.rissanen@linux.intel.com>
 L:	linux-bluetooth@vger.kernel.org
+L:	linux-wpan@vger.kernel.org
 S:	Maintained
 F:	net/6lowpan/
 F:	include/net/6lowpan.h
@@ -563,7 +564,7 @@
 F:	arch/alpha/
 
 ALTERA TRIPLE SPEED ETHERNET DRIVER
-M:	Vince Bridgers <vbridgers2013@gmail.com>
+M:	Vince Bridgers <vbridger@opensource.altera.com>
 L:	netdev@vger.kernel.org
 L:	nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
 S:	Maintained
@@ -685,6 +686,17 @@
 W:	http://blackfin.uclinux.org/
 S:	Supported
 F:	sound/soc/blackfin/*
+ 
+ANALOG DEVICES INC IIO DRIVERS
+M:	Lars-Peter Clausen <lars@metafoo.de>
+M:	Michael Hennerich <Michael.Hennerich@analog.com>
+W:	http://wiki.analog.com/
+W:	http://ez.analog.com/community/linux-device-drivers
+S:	Supported
+F:	drivers/iio/*/ad*
+X:	drivers/iio/*/adjd*
+F:	drivers/staging/iio/*/ad*
+F:	staging/iio/trigger/iio-trig-bfin-timer.c
 
 AOA (Apple Onboard Audio) ALSA DRIVER
 M:	Johannes Berg <johannes@sipsolutions.net>
@@ -722,7 +734,6 @@
 APPLIED MICRO (APM) X-GENE SOC ETHERNET DRIVER
 M:	Iyappan Subramanian <isubramanian@apm.com>
 M:	Keyur Chudgar <kchudgar@apm.com>
-M:	Ravi Patel <rapatel@apm.com>
 S:	Supported
 F:	drivers/net/ethernet/apm/xgene/
 F:	Documentation/devicetree/bindings/net/apm-xgene-enet.txt
@@ -835,6 +846,12 @@
 S:	Maintained
 F:	drivers/clk/sunxi/
 
+ARM/Amlogic MesonX SoC support
+M:	Carlo Caione <carlo@caione.org>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+N:	meson[x68]
+
 ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
 M:	Andrew Victor <linux@maxim.org.za>
 M:	Nicolas Ferre <nicolas.ferre@atmel.com>
@@ -861,10 +878,9 @@
 F:	arch/arm/mach-highbank/
 
 ARM/CAVIUM NETWORKS CNS3XXX MACHINE SUPPORT
-M:	Anton Vorontsov <anton@enomsg.org>
+M:	Krzysztof Halasa <khalasa@piap.pl>
 S:	Maintained
 F:	arch/arm/mach-cns3xxx/
-T:	git git://git.infradead.org/users/cbou/linux-cns3xxx.git
 
 ARM/CIRRUS LOGIC CLPS711X ARM ARCHITECTURE
 M:	Alexander Shiyan <shc_work@mail.ru>
@@ -964,7 +980,7 @@
 F:	arch/arm/mach-footbridge/
 
 ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
-M:	Shawn Guo <shawn.guo@freescale.com>
+M:	Shawn Guo <shawn.guo@linaro.org>
 M:	Sascha Hauer <kernel@pengutronix.de>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
@@ -1025,24 +1041,20 @@
 
 ARM/INTEL IOP32X ARM ARCHITECTURE
 M:	Lennert Buytenhek <kernel@wantstofly.org>
-M:	Dan Williams <dan.j.williams@intel.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 
 ARM/INTEL IOP33X ARM ARCHITECTURE
-M:	Dan Williams <dan.j.williams@intel.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:	Maintained
+S:	Orphan
 
 ARM/INTEL IOP13XX ARM ARCHITECTURE
 M:	Lennert Buytenhek <kernel@wantstofly.org>
-M:	Dan Williams <dan.j.williams@intel.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 
 ARM/INTEL IQ81342EX MACHINE SUPPORT
 M:	Lennert Buytenhek <kernel@wantstofly.org>
-M:	Dan Williams <dan.j.williams@intel.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 
@@ -1053,7 +1065,7 @@
 
 ARM/INTEL IXP4XX ARM ARCHITECTURE
 M:	Imre Kaloz <kaloz@openwrt.org>
-M:	Krzysztof Halasa <khc@pm.waw.pl>
+M:	Krzysztof Halasa <khalasa@piap.pl>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 F:	arch/arm/mach-ixp4xx/
@@ -1067,7 +1079,6 @@
 
 ARM/INTEL XSC3 (MANZANO) ARM CORE
 M:	Lennert Buytenhek <kernel@wantstofly.org>
-M:	Dan Williams <dan.j.williams@intel.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 
@@ -1077,33 +1088,33 @@
 S:	Maintained
 
 ARM/TEXAS INSTRUMENT KEYSTONE ARCHITECTURE
-M:	Santosh Shilimkar <santosh.shilimkar@ti.com>
+M:	Santosh Shilimkar <ssantosh@kernel.org>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 F:	arch/arm/mach-keystone/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
 
 ARM/TEXAS INSTRUMENT KEYSTONE CLOCK FRAMEWORK
-M:	Santosh Shilimkar <santosh.shilimkar@ti.com>
+M:	Santosh Shilimkar <ssantosh@kernel.org>
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 F:	drivers/clk/keystone/
 
 ARM/TEXAS INSTRUMENT KEYSTONE ClOCKSOURCE
-M:	Santosh Shilimkar <santosh.shilimkar@ti.com>
+M:	Santosh Shilimkar <ssantosh@kernel.org>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 F:	drivers/clocksource/timer-keystone.c
 
 ARM/TEXAS INSTRUMENT KEYSTONE RESET DRIVER
-M:	Santosh Shilimkar <santosh.shilimkar@ti.com>
+M:	Santosh Shilimkar <ssantosh@kernel.org>
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 F:	drivers/power/reset/keystone-reset.c
 
 ARM/TEXAS INSTRUMENT AEMIF/EMIF DRIVERS
-M:	Santosh Shilimkar <santosh.shilimkar@ti.com>
+M:	Santosh Shilimkar <ssantosh@kernel.org>
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 F:	drivers/memory/*emif*
@@ -1150,6 +1161,16 @@
 S:	Maintained
 F:	arch/arm/mach-orion5x/ts78xx-*
 
+ARM/Mediatek SoC support
+M:	Matthias Brugger <matthias.bgg@gmail.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	arch/arm/boot/dts/mt6*
+F:	arch/arm/boot/dts/mt8*
+F:	arch/arm/mach-mediatek/
+N:	mtk
+K:	mediatek
+
 ARM/MICREL KS8695 ARCHITECTURE
 M:	Greg Ungerer <gerg@uclinux.org>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1317,8 +1338,7 @@
 M:	Kyungmin Park <kyungmin.park@samsung.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
-F:	arch/arm/mach-s5pv210/mach-aquila.c
-F:	arch/arm/mach-s5pv210/mach-goni.c
+F:	arch/arm/mach-s5pv210/
 
 ARM/SAMSUNG S5P SERIES 2D GRAPHICS ACCELERATION (G2D) SUPPORT
 M:	Kyungmin Park <kyungmin.park@samsung.com>
@@ -1361,7 +1381,6 @@
 F:	arch/arm/configs/ape6evm_defconfig
 F:	arch/arm/configs/armadillo800eva_defconfig
 F:	arch/arm/configs/bockw_defconfig
-F:	arch/arm/configs/genmai_defconfig
 F:	arch/arm/configs/koelsch_defconfig
 F:	arch/arm/configs/kzm9g_defconfig
 F:	arch/arm/configs/lager_defconfig
@@ -1372,15 +1391,23 @@
 F:	drivers/sh/
 
 ARM/SOCFPGA ARCHITECTURE
-M:	Dinh Nguyen <dinguyen@altera.com>
+M:	Dinh Nguyen <dinguyen@opensource.altera.com>
 S:	Maintained
 F:	arch/arm/mach-socfpga/
+W:	http://www.rocketboards.org
+T:	git://git.rocketboards.org/linux-socfpga.git
+T:	git://git.rocketboards.org/linux-socfpga-next.git
 
 ARM/SOCFPGA CLOCK FRAMEWORK SUPPORT
-M:	Dinh Nguyen <dinguyen@altera.com>
+M:	Dinh Nguyen <dinguyen@opensource.altera.com>
 S:	Maintained
 F:	drivers/clk/socfpga/
 
+ARM/SOCFPGA EDAC SUPPORT
+M:	Thor Thayer <tthayer@opensource.altera.com>
+S:	Maintained
+F:	drivers/edac/altera_edac.
+
 ARM/STI ARCHITECTURE
 M:	Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
 M:	Maxime Coquelin <maxime.coquelin@st.com>
@@ -1392,12 +1419,17 @@
 F:	arch/arm/mach-sti/
 F:	arch/arm/boot/dts/sti*
 F:	drivers/clocksource/arm_global_timer.c
-F:	drivers/reset/sti/
-F:	drivers/pinctrl/pinctrl-st.c
-F:	drivers/media/rc/st_rc.c
 F:	drivers/i2c/busses/i2c-st.c
-F:	drivers/tty/serial/st-asc.c
+F:	drivers/media/rc/st_rc.c
 F:	drivers/mmc/host/sdhci-st.c
+F:	drivers/phy/phy-stih407-usb.c
+F:	drivers/phy/phy-stih41x-usb.c
+F:	drivers/pinctrl/pinctrl-st.c
+F:	drivers/reset/sti/
+F:	drivers/tty/serial/st-asc.c
+F:	drivers/usb/dwc3/dwc3-st.c
+F:	drivers/usb/host/ehci-st.c
+F:	drivers/usb/host/ohci-st.c
 
 ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
 M:	Lennert Buytenhek <kernel@wantstofly.org>
@@ -1517,6 +1549,7 @@
 S:	Supported
 F:	arch/arm/mach-zynq/
 F:	drivers/cpuidle/cpuidle-zynq.c
+F:	drivers/block/xsysace.c
 N:	zynq
 N:	xilinx
 F:	drivers/clocksource/cadence_ttc_timer.c
@@ -1562,9 +1595,9 @@
 F:	drivers/platform/x86/eeepc*.c
 
 ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
-M:	Dan Williams <dan.j.williams@intel.com>
+R:	Dan Williams <dan.j.williams@intel.com>
 W:	http://sourceforge.net/projects/xscaleiop
-S:	Maintained
+S:	Odd fixes
 F:	Documentation/crypto/async-tx-api.txt
 F:	crypto/async_tx/
 F:	drivers/dma/
@@ -1616,6 +1649,7 @@
 S:	Supported
 W:	http://wireless.kernel.org/en/users/Drivers/wil6210
 F:	drivers/net/wireless/ath/wil6210/
+F:	include/uapi/linux/wil6210_uapi.h
 
 CARL9170 LINUX COMMUNITY WIRELESS DRIVER
 M:	Christian Lamparter <chunkeey@googlemail.com>
@@ -1704,6 +1738,12 @@
 S:	Supported
 F:	drivers/net/ethernet/cadence/
 
+ATMEL NAND DRIVER
+M:	Josh Wu <josh.wu@atmel.com>
+L:	linux-mtd@lists.infradead.org
+S:	Supported
+F:	drivers/mtd/nand/atmel_nand*
+
 ATMEL SPI DRIVER
 M:	Nicolas Ferre <nicolas.ferre@atmel.com>
 S:	Supported
@@ -2010,6 +2050,7 @@
 BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITECTURE
 M:	Christian Daudt <bcm@fixthebug.org>
 M:	Matt Porter <mporter@linaro.org>
+M:	Florian Fainelli <f.fainelli@gmail.com>
 L:	bcm-kernel-feedback-list@broadcom.com
 T:	git git://github.com/broadcom/mach-bcm
 S:	Maintained
@@ -2021,17 +2062,14 @@
 F:	drivers/mmc/host/sdhci-bcm-kona.c
 F:	drivers/clocksource/bcm_kona_timer.c
 
-BROADCOM BCM2835 ARM ARCHICTURE
+BROADCOM BCM2835 ARM ARCHITECTURE
 M:	Stephen Warren <swarren@wwwdotorg.org>
 L:	linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers)
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-rpi.git
 S:	Maintained
-F:	arch/arm/mach-bcm/board_bcm2835.c
-F:	arch/arm/boot/dts/bcm2835*
-F:	arch/arm/configs/bcm2835_defconfig
-F:	drivers/*/*bcm2835*
+N:	bcm2835
 
-BROADCOM BCM5301X ARM ARCHICTURE
+BROADCOM BCM5301X ARM ARCHITECTURE
 M:	Hauke Mehrtens <hauke@hauke-m.de>
 L:	linux-arm-kernel@lists.infradead.org
 S:	Maintained
@@ -2039,6 +2077,14 @@
 F:	arch/arm/boot/dts/bcm5301x.dtsi
 F:	arch/arm/boot/dts/bcm470*
 
+BROADCOM BCM63XX ARM ARCHITECTURE
+M:	Florian Fainelli <f.fainelli@gmail.com>
+L:	linux-arm-kernel@lists.infradead.org
+T:	git git://git.github.com/brcm/linux.git
+S:	Maintained
+F:	arch/arm/mach-bcm/bcm63xx.c
+F:	arch/arm/include/debug/bcm63xx.S
+
 BROADCOM BCM7XXX ARM ARCHITECTURE
 M:	Marc Carino <marc.ceeeee@gmail.com>
 M:	Brian Norris <computersforpeace@gmail.com>
@@ -2717,6 +2763,18 @@
 S:	Supported
 F:	drivers/net/ethernet/chelsio/cxgb4vf/
 
+CXL (IBM Coherent Accelerator Processor Interface CAPI) DRIVER
+M:	Ian Munsie <imunsie@au1.ibm.com>
+M:	Michael Neuling <mikey@neuling.org>
+L:	linuxppc-dev@lists.ozlabs.org
+S:	Supported
+F:	drivers/misc/cxl/
+F:	include/misc/cxl.h
+F:	include/uapi/misc/cxl.h
+F:	Documentation/powerpc/cxl.txt
+F:	Documentation/powerpc/cxl.txt
+F:	Documentation/ABI/testing/sysfs-class-cxl
+
 STMMAC ETHERNET DRIVER
 M:	Giuseppe Cavallaro <peppe.cavallaro@st.com>
 L:	netdev@vger.kernel.org
@@ -2854,6 +2912,7 @@
 DESIGNWARE USB2 DRD IP DRIVER
 M:	Paul Zimmerman <paulz@synopsys.com>
 L:	linux-usb@vger.kernel.org
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:	Maintained
 F:	drivers/usb/dwc2/
 
@@ -2865,6 +2924,13 @@
 S:	Maintained
 F:	drivers/usb/dwc3/
 
+DEVICE COREDUMP (DEV_COREDUMP)
+M:	Johannes Berg <johannes@sipsolutions.net>
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+F:	drivers/base/devcoredump.c
+F:	include/linux/devcoredump.h
+
 DEVICE FREQUENCY (DEVFREQ)
 M:	MyungJoo Ham <myungjoo.ham@samsung.com>
 M:	Kyungmin Park <kyungmin.park@samsung.com>
@@ -2985,7 +3051,7 @@
 S:	Maintained
 L:	linux-media@vger.kernel.org
 L:	dri-devel@lists.freedesktop.org
-L:	linaro-mm-sig@lists.linaro.org
+L:	linaro-mm-sig@lists.linaro.org (moderated for non-subscribers)
 F:	drivers/dma-buf/
 F:	include/linux/dma-buf*
 F:	include/linux/reservation.h
@@ -2995,13 +3061,11 @@
 
 DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
 M:	Vinod Koul <vinod.koul@intel.com>
-M:	Dan Williams <dan.j.williams@intel.com>
 L:	dmaengine@vger.kernel.org
 Q:	https://patchwork.kernel.org/project/linux-dmaengine/list/
-S:	Supported
+S:	Maintained
 F:	drivers/dma/
 F:	include/linux/dma*
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx.git
 T:	git git://git.infradead.org/users/vkoul/slave-dma.git (slave-dma)
 
 DME1737 HARDWARE MONITOR DRIVER
@@ -3018,7 +3082,7 @@
 F:	drivers/acpi/dock.c
 
 DOCUMENTATION
-M:	Jiri Kosina <jkosina@suse.cz>
+M:	Jonathan Corbet <corbet@lwn.net>
 L:	linux-doc@vger.kernel.org
 S:	Maintained
 F:	Documentation/
@@ -3096,7 +3160,7 @@
 F:	Documentation/devicetree/bindings/panel/
 
 INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
-M:	Daniel Vetter <daniel.vetter@ffwll.ch>
+M:	Daniel Vetter <daniel.vetter@intel.com>
 M:	Jani Nikula <jani.nikula@linux.intel.com>
 L:	intel-gfx@lists.freedesktop.org
 L:	dri-devel@lists.freedesktop.org
@@ -3556,6 +3620,11 @@
 F:	drivers/video/fbdev/s1d13xxxfb.c
 F:	include/video/s1d13xxxfb.h
 
+ET131X NETWORK DRIVER
+M:	Mark Einon <mark.einon@gmail.com>
+S:	Odd Fixes
+F:	drivers/net/ethernet/agere/
+
 ETHERNET BRIDGE
 M:	Stephen Hemminger <stephen@networkplumber.org>
 L:	bridge@lists.linux-foundation.org
@@ -4177,6 +4246,16 @@
 S:	Odd Fixes
 F:	drivers/tty/hvc/
 
+HACKRF MEDIA DRIVER
+M:	Antti Palosaari <crope@iki.fi>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org/
+W:	http://palosaari.fi/linux/
+Q:	http://patchwork.linuxtv.org/project/linux-media/list/
+T:	git git://linuxtv.org/anttip/media_tree.git
+S:	Maintained
+F:	drivers/media/usb/hackrf/
+
 HARDWARE MONITORING
 M:	Jean Delvare <jdelvare@suse.de>
 M:	Guenter Roeck <linux@roeck-us.net>
@@ -4220,9 +4299,8 @@
 F:	drivers/media/dvb-frontends/hd29l2*
 
 HEWLETT-PACKARD SMART2 RAID DRIVER
-M:	Chirag Kantharia <chirag.kantharia@hp.com>
 L:	iss_storagedev@hp.com
-S:	Maintained
+S:	Orphan
 F:	Documentation/blockdev/cpqarray.txt
 F:	drivers/block/cpqarray.*
 
@@ -4601,13 +4679,14 @@
 
 IEEE 802.15.4 SUBSYSTEM
 M:	Alexander Aring <alex.aring@gmail.com>
-L:	linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers)
-W:	http://apps.sourceforge.net/trac/linux-zigbee
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan.git
+L:	linux-wpan@vger.kernel.org
+W:	https://github.com/linux-wpan
+T:	git git://github.com/linux-wpan/linux-wpan-next.git
 S:	Maintained
 F:	net/ieee802154/
 F:	net/mac802154/
 F:	drivers/net/ieee802154/
+F:	Documentation/networking/ieee802154.txt
 
 IGUANAWORKS USB IR TRANSCEIVER
 M:	Sean Young <sean@mess.org>
@@ -4617,6 +4696,9 @@
 
 IIO SUBSYSTEM AND DRIVERS
 M:	Jonathan Cameron <jic23@kernel.org>
+R:	Hartmut Knaack <knaack.h@gmx.de>
+R:	Lars-Peter Clausen <lars@metafoo.de>
+R:	Peter Meerwald <pmeerw@pmeerw.net>
 L:	linux-iio@vger.kernel.org
 S:	Maintained
 F:	drivers/iio/
@@ -4754,8 +4836,8 @@
 F:	arch/x86/kernel/cpu/microcode/intel*
 
 INTEL I/OAT DMA DRIVER
-M:	Dan Williams <dan.j.williams@intel.com>
 M:	Dave Jiang <dave.jiang@intel.com>
+R:	Dan Williams <dan.j.williams@intel.com>
 L:	dmaengine@vger.kernel.org
 Q:	https://patchwork.kernel.org/project/linux-dmaengine/list/
 S:	Supported
@@ -4770,12 +4852,12 @@
 F:	include/linux/intel-iommu.h
 
 INTEL IOP-ADMA DMA DRIVER
-M:	Dan Williams <dan.j.williams@intel.com>
+R:	Dan Williams <dan.j.williams@intel.com>
 S:	Odd fixes
 F:	drivers/dma/iop-adma.c
 
 INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
-M:	Krzysztof Halasa <khc@pm.waw.pl>
+M:	Krzysztof Halasa <khalasa@piap.pl>
 S:	Maintained
 F:	arch/arm/mach-ixp4xx/include/mach/qmgr.h
 F:	arch/arm/mach-ixp4xx/include/mach/npe.h
@@ -4789,14 +4871,14 @@
 S:	Maintained
 F:	drivers/char/hw_random/ixp4xx-rng.c
 
-INTEL ETHERNET DRIVERS (e100/e1000/e1000e/igb/igbvf/ixgb/ixgbe/ixgbevf/i40e/i40evf)
+INTEL ETHERNET DRIVERS (e100/e1000/e1000e/fm10k/igb/igbvf/ixgb/ixgbe/ixgbevf/i40e/i40evf)
 M:	Jeff Kirsher <jeffrey.t.kirsher@intel.com>
 M:	Jesse Brandeburg <jesse.brandeburg@intel.com>
 M:	Bruce Allan <bruce.w.allan@intel.com>
 M:	Carolyn Wyborny <carolyn.wyborny@intel.com>
 M:	Don Skidmore <donald.c.skidmore@intel.com>
 M:	Greg Rose <gregory.v.rose@intel.com>
-M:	Alex Duyck <alexander.h.duyck@intel.com>
+M:	Matthew Vick <matthew.vick@intel.com>
 M:	John Ronciak <john.ronciak@intel.com>
 M:	Mitch Williams <mitch.a.williams@intel.com>
 M:	Linux NICS <linux.nics@intel.com>
@@ -4985,6 +5067,7 @@
 S:	Maintained
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
 T:	git git://git.infradead.org/users/jcooper/linux.git irqchip/core
+F:	Documentation/devicetree/bindings/interrupt-controller/
 F:	drivers/irqchip/
 
 IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
@@ -5026,6 +5109,7 @@
 
 ISCSI EXTENSIONS FOR RDMA (ISER) INITIATOR
 M:	Or Gerlitz <ogerlitz@mellanox.com>
+M:	Sagi Grimberg <sagig@mellanox.com>
 M:	Roi Dayan <roid@mellanox.com>
 L:	linux-rdma@vger.kernel.org
 S:	Supported
@@ -5070,7 +5154,7 @@
 Q:	http://patchwork.linuxtv.org/project/linux-media/list/
 T:	git git://linuxtv.org/anttip/media_tree.git
 S:	Maintained
-F:	drivers/media/tuners/tuner_it913x*
+F:	drivers/media/tuners/it913x*
 
 IVTV VIDEO4LINUX DRIVER
 M:	Andy Walls <awalls@md.metrocast.net>
@@ -5218,6 +5302,13 @@
 F:	include/linux/sunrpc/
 F:	include/uapi/linux/sunrpc/
 
+KERNEL SELFTEST FRAMEWORK
+M:	Shuah Khan <shuahkh@osg.samsung.com>
+L:	linux-api@vger.kernel.org
+T:	git git://git.kernel.org/pub/scm/shuah/linux-kselftest
+S:	Maintained
+F:	tools/testing/selftests
+
 KERNEL VIRTUAL MACHINE (KVM)
 M:	Gleb Natapov <gleb@kernel.org>
 M:	Paolo Bonzini <pbonzini@redhat.com>
@@ -5598,8 +5689,8 @@
 L:	linux-kernel@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core/locking
 S:	Maintained
-F:	Documentation/lockdep*.txt
-F:	Documentation/lockstat.txt
+F:	Documentation/locking/lockdep*.txt
+F:	Documentation/locking/lockstat.txt
 F:	include/linux/lockdep.h
 F:	kernel/locking/
 
@@ -5664,11 +5755,8 @@
 S:	Maintained
 
 M32R ARCHITECTURE
-M:	Hirokazu Takata <takata@linux-m32r.org>
-L:	linux-m32r@ml.linux-m32r.org (moderated for non-subscribers)
-L:	linux-m32r-ja@ml.linux-m32r.org (in Japanese)
 W:	http://www.linux-m32r.org/
-S:	Maintained
+S:	Orphan
 F:	arch/m32r/
 
 M68K ARCHITECTURE
@@ -5902,6 +5990,7 @@
 W:	http://www.linux-mtd.infradead.org/
 Q:	http://patchwork.ozlabs.org/project/linux-mtd/list/
 T:	git git://git.infradead.org/linux-mtd.git
+T:	git git://git.infradead.org/l2-mtd.git
 S:	Maintained
 F:	drivers/mtd/
 F:	include/linux/mtd/
@@ -5919,6 +6008,15 @@
 F:	drivers/mcb/
 F:	include/linux/mcb.h
 
+MEN F21BMC (Board Management Controller)
+M:	Andreas Werner <andreas.werner@men.de>
+S:	Supported
+F:	drivers/mfd/menf21bmc.c
+F:	drivers/watchdog/menf21bmc_wdt.c
+F:	drivers/leds/leds-menf21bmc.c
+F:	drivers/hwmon/menf21bmc_hwmon.c
+F:	Documentation/hwmon/menf21bmc
+
 METAG ARCHITECTURE
 M:	James Hogan <james.hogan@imgtec.com>
 L:	linux-metag@vger.kernel.org
@@ -6377,7 +6475,7 @@
 M:	Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
 M:	Samuel Ortiz <sameo@linux.intel.com>
 L:	linux-wireless@vger.kernel.org
-L:	linux-nfc@lists.01.org (moderated for non-subscribers)
+L:	linux-nfc@lists.01.org (subscribers-only)
 S:	Supported
 F:	net/nfc/
 F:	include/net/nfc/
@@ -6545,10 +6643,9 @@
 F:	drivers/mmc/host/omap.c
 
 OMAP HS MMC SUPPORT
-M:	Balaji T K <balajitk@ti.com>
 L:	linux-mmc@vger.kernel.org
 L:	linux-omap@vger.kernel.org
-S:	Maintained
+S:	Orphan
 F:	drivers/mmc/host/omap_hsmmc.c
 
 OMAP RANDOM NUMBER GENERATOR SUPPORT
@@ -6587,7 +6684,7 @@
 
 OMAP GPIO DRIVER
 M:	Javier Martinez Canillas <javier@dowhile0.org>
-M:	Santosh Shilimkar <santosh.shilimkar@ti.com>
+M:	Santosh Shilimkar <ssantosh@kernel.org>
 M:	Kevin Hilman <khilman@deeprootsystems.com>
 L:	linux-omap@vger.kernel.org
 S:	Maintained
@@ -6878,6 +6975,14 @@
 F:	arch/x86/pci/
 F:	arch/x86/kernel/quirks.c
 
+PCI DRIVER FOR APPLIEDMICRO XGENE
+M:	Tanmay Inamdar <tinamdar@apm.com>
+L:	linux-pci@vger.kernel.org
+L:	linux-arm-kernel@lists.infradead.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/pci/xgene-pci.txt
+F:	drivers/pci/host/pci-xgene.c
+
 PCI DRIVER FOR IMX6
 M:	Richard Zhu <r65037@freescale.com>
 M:	Lucas Stach <l.stach@pengutronix.de>
@@ -6886,6 +6991,13 @@
 S:	Maintained
 F:	drivers/pci/host/*imx6*
 
+PCI DRIVER FOR TI KEYSTONE
+M:	Murali Karicheri <m-karicheri2@ti.com>
+L:	linux-pci@vger.kernel.org
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	drivers/pci/host/*keystone*
+
 PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
 M:	Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
 M:	Jason Cooper <jason@lakedaemon.net>
@@ -7288,6 +7400,14 @@
 S:	Maintained
 F:	drivers/media/usb/pwc/*
 
+PWM FAN DRIVER
+M:	Kamil Debski <k.debski@samsung.com>
+L:	lm-sensors@lm-sensors.org
+S:	Supported
+F:	Documentation/devicetree/bindings/hwmon/pwm-fan.txt
+F:	Documentation/hwmon/pwm-fan
+F:	drivers/hwmon/pwm-fan.c
+
 PWM SUBSYSTEM
 M:	Thierry Reding <thierry.reding@gmail.com>
 L:	linux-pwm@vger.kernel.org
@@ -7301,12 +7421,12 @@
 F:	include/linux/pwm_backlight.h
 
 PXA2xx/PXA3xx SUPPORT
-M:	Eric Miao <eric.y.miao@gmail.com>
-M:	Russell King <linux@arm.linux.org.uk>
+M:	Daniel Mack <daniel@zonque.org>
 M:	Haojian Zhuang <haojian.zhuang@gmail.com>
+M:	Robert Jarzmik <robert.jarzmik@free.fr>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:	git git://github.com/hzhuang1/linux.git
-T:	git git://git.linaro.org/people/ycmiao/pxa-linux.git
+T:	git git://github.com/rjarzmik/linux.git
 S:	Maintained
 F:	arch/arm/mach-pxa/
 F:	drivers/pcmcia/pxa2xx*
@@ -7383,15 +7503,15 @@
 
 QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
 M:	Shahed Shaikh <shahed.shaikh@qlogic.com>
-M:	Dept-HSGLinuxNICDev@qlogic.com
+M:	Dept-GELinuxNICDev@qlogic.com
 L:	netdev@vger.kernel.org
 S:	Supported
 F:	drivers/net/ethernet/qlogic/qlcnic/
 
 QLOGIC QLGE 10Gb ETHERNET DRIVER
-M:	Shahed Shaikh <shahed.shaikh@qlogic.com>
-M:	Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
-M:	Ron Mercer <ron.mercer@qlogic.com>
+M:	Harish Patil <harish.patil@qlogic.com>
+M:	Sudarsana Kalluru <sudarsana.kalluru@qlogic.com>
+M:	Dept-GELinuxNICDev@qlogic.com
 M:	linux-driver@qlogic.com
 L:	netdev@vger.kernel.org
 S:	Supported
@@ -7494,13 +7614,12 @@
 
 RALINK RT2X00 WIRELESS LAN DRIVER
 P:	rt2x00 project
-M:	Ivo van Doorn <IvDoorn@gmail.com>
+M:	Stanislaw Gruszka <sgruszka@redhat.com>
 M:	Helmut Schaa <helmut.schaa@googlemail.com>
 L:	linux-wireless@vger.kernel.org
 L:	users@rt2x00.serialmonkey.com (moderated for non-subscribers)
 W:	http://rt2x00.serialmonkey.com/
 S:	Maintained
-T:	git git://git.kernel.org/pub/scm/linux/kernel/git/ivd/rt2x00.git
 F:	drivers/net/wireless/rt2x00/
 
 RAMDISK RAM BLOCK DEVICE DRIVER
@@ -7602,6 +7721,7 @@
 
 REGISTER MAP ABSTRACTION
 M:	Mark Brown <broonie@kernel.org>
+L:	linux-kernel@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git
 S:	Supported
 F:	drivers/base/regmap/
@@ -7870,7 +7990,6 @@
 F:	drivers/mfd/sec*.c
 F:	drivers/regulator/s2m*.c
 F:	drivers/regulator/s5m*.c
-F:	drivers/rtc/rtc-sec.c
 F:	include/linux/mfd/samsung/
 
 SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
@@ -7941,7 +8060,7 @@
 M:	Viresh Kumar <viresh.linux@gmail.com>
 M:	Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 S:	Maintained
-F:	include/linux/dw_dmac.h
+F:	include/linux/platform_data/dma-dw.h
 F:	drivers/dma/dw/
 
 SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
@@ -8094,6 +8213,8 @@
 
 SECURE COMPUTING
 M:	Kees Cook <keescook@chromium.org>
+R:	Andy Lutomirski <luto@amacapital.net>
+R:	Will Drewry <wad@chromium.org>
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
 S:	Supported
 F:	kernel/seccomp.c
@@ -8414,11 +8535,11 @@
 F:	Documentation/security/Smack.txt
 F:	security/smack/
 
-SMARTREFLEX DRIVERS FOR ADAPTIVE VOLTAGE SCALING (AVS)
+DRIVERS FOR ADAPTIVE VOLTAGE SCALING (AVS)
 M:	Kevin Hilman <khilman@kernel.org>
 M:	Nishanth Menon <nm@ti.com>
 S:	Maintained
-F:	drivers/power/avs/smartreflex.c
+F:	drivers/power/avs/
 F:	include/linux/power/smartreflex.h
 L:	linux-pm@vger.kernel.org
 
@@ -8588,6 +8709,14 @@
 F:	sound/core/pcm_dmaengine.c
 F:	sound/soc/soc-generic-dmaengine-pcm.c
 
+SP2 MEDIA DRIVER
+M:	Olli Salonen <olli.salonen@iki.fi>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org/
+Q:	http://patchwork.linuxtv.org/project/linux-media/list/
+S:	Maintained
+F:	drivers/media/dvb-frontends/sp2*
+
 SPARC + UltraSPARC (sparc/sparc64)
 M:	"David S. Miller" <davem@davemloft.net>
 L:	sparclinux@vger.kernel.org
@@ -8699,11 +8828,6 @@
 S:	Odd Fixes
 F:	drivers/staging/comedi/
 
-STAGING - ET131X NETWORK DRIVER
-M:	Mark Einon <mark.einon@gmail.com>
-S:	Odd Fixes
-F:	drivers/staging/et131x/
-
 STAGING - FLARION FT1000 DRIVERS
 M:	Marek Belisko <marek.belisko@gmail.com>
 S:	Odd Fixes
@@ -8721,6 +8845,14 @@
 S:	Odd Fixes
 F:	drivers/staging/media/lirc/
 
+STAGING - LUSTRE PARALLEL FILESYSTEM
+M:	Oleg Drokin <oleg.drokin@intel.com>
+M:	Andreas Dilger <andreas.dilger@intel.com>
+L:	HPDD-discuss@lists.01.org (moderated for non-subscribers)
+W:	http://lustre.opensfs.org/
+S:	Maintained
+F:	drivers/staging/lustre
+
 STAGING - NVIDIA COMPLIANT EMBEDDED CONTROLLER INTERFACE (nvec)
 M:	Julian Andres Klode <jak@jak-linux.org>
 M:	Marc Dietrich <marvin24@gmx.de>
@@ -9014,17 +9146,13 @@
 TEGRA ARCHITECTURE SUPPORT
 M:	Stephen Warren <swarren@wwwdotorg.org>
 M:	Thierry Reding <thierry.reding@gmail.com>
+M:	Alexandre Courbot <gnurou@gmail.com>
 L:	linux-tegra@vger.kernel.org
 Q:	http://patchwork.ozlabs.org/project/linux-tegra/list/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git
 S:	Supported
 N:	[^a-z]tegra
 
-TEGRA ASOC DRIVER
-M:	Stephen Warren <swarren@wwwdotorg.org>
-S:	Supported
-F:	sound/soc/tegra/
-
 TEGRA CLOCK DRIVER
 M:	Peter De Schrijver <pdeschrijver@nvidia.com>
 M:	Prashant Gaikwad <pgaikwad@nvidia.com>
@@ -9036,11 +9164,6 @@
 S:	Supported
 F:	drivers/dma/tegra20-apb-dma.c
 
-TEGRA GPIO DRIVER
-M:	Stephen Warren <swarren@wwwdotorg.org>
-S:	Supported
-F:	drivers/gpio/gpio-tegra.c
-
 TEGRA I2C DRIVER
 M:	Laxman Dewangan <ldewangan@nvidia.com>
 S:	Supported
@@ -9057,11 +9180,6 @@
 S:	Supported
 F:	drivers/input/keyboard/tegra-kbc.c
 
-TEGRA PINCTRL DRIVER
-M:	Stephen Warren <swarren@wwwdotorg.org>
-S:	Supported
-F:	drivers/pinctrl/pinctrl-tegra*
-
 TEGRA PWM DRIVER
 M:	Thierry Reding <thierry.reding@gmail.com>
 S:	Supported
@@ -9152,6 +9270,15 @@
 F:	drivers/mmc/host/tifm_sd.c
 F:	include/linux/tifm.h
 
+TI KEYSTONE MULTICORE NAVIGATOR DRIVERS
+M:	Santosh Shilimkar <ssantosh@kernel.org>
+L:	linux-kernel@vger.kernel.org
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	drivers/soc/ti/*
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
+
+
 TI LM49xxx FAMILY ASoC CODEC DRIVERS
 M:	M R Swami Reddy <mr.swami.reddy@ti.com>
 M:	Vishwas A Deshpande <vishwas.a.deshpande@ti.com>
@@ -9293,6 +9420,14 @@
 S:	Odd fixes
 F:	drivers/media/usb/tm6000/
 
+TW68 VIDEO4LINUX DRIVER
+M:	Hans Verkuil <hverkuil@xs4all.nl>
+L:	linux-media@vger.kernel.org
+T:	git git://linuxtv.org/media_tree.git
+W:	http://linuxtv.org
+S:	Odd Fixes
+F:	drivers/media/pci/tw68/
+
 TPM DEVICE DRIVER
 M:	Peter Huewe <peterhuewe@gmx.de>
 M:	Ashley Lai <ashley@ashleylai.com>
@@ -9314,6 +9449,7 @@
 F:	include/linux/trace*.h
 F:	include/trace/
 F:	kernel/trace/
+F:	tools/testing/selftests/ftrace/
 
 TRIVIAL PATCHES
 M:	Jiri Kosina <trivial@kernel.org>
@@ -9687,7 +9823,7 @@
 M:	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:	linux-usb@vger.kernel.org
 S:	Maintained
-F:	drivers/usb/gadget/function/*uvc*.c
+F:	drivers/usb/gadget/function/*uvc*
 F:	drivers/usb/gadget/legacy/webcam.c
 
 USB WIRELESS RNDIS DRIVER (rndis_wlan)
@@ -9901,6 +10037,7 @@
 VOLTAGE AND CURRENT REGULATOR FRAMEWORK
 M:	Liam Girdwood <lgirdwood@gmail.com>
 M:	Mark Brown <broonie@kernel.org>
+L:	linux-kernel@vger.kernel.org
 W:	http://opensource.wolfsonmicro.com/node/15
 W:	http://www.slimlogic.co.uk/?p=48
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
@@ -10160,6 +10297,15 @@
 F:	drivers/block/xen-blkback/*
 F:	drivers/block/xen*
 
+XEN PVSCSI DRIVERS
+M:	Juergen Gross <jgross@suse.com>
+L:	xen-devel@lists.xenproject.org (moderated for non-subscribers)
+L:	linux-scsi@vger.kernel.org
+S:	Supported
+F:	drivers/scsi/xen-scsifront.c
+F:	drivers/xen/xen-scsiback.c
+F:	include/xen/interface/io/vscsiif.h
+
 XEN SWIOTLB SUBSYSTEM
 M:	Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
 L:	xen-devel@lists.xenproject.org (moderated for non-subscribers)
@@ -10184,16 +10330,18 @@
 S:	Maintained
 F:	drivers/net/ethernet/xilinx/xilinx_axienet*
 
-XILINX SYSTEMACE DRIVER
-S:	Orphan
-F:	drivers/block/xsysace.c
-
 XILINX UARTLITE SERIAL DRIVER
 M:	Peter Korsgaard <jacmet@sunsite.dk>
 L:	linux-serial@vger.kernel.org
 S:	Maintained
 F:	drivers/tty/serial/uartlite.c
 
+XILLYBUS DRIVER
+M:	Eli Billauer <eli.billauer@gmail.com>
+L:	linux-kernel@vger.kernel.org
+S:	Supported
+F:	drivers/char/xillybus/
+
 XTENSA XTFPGA PLATFORM SUPPORT
 M:	Max Filippov <jcmvbkbc@gmail.com>
 L:	linux-xtensa@linux-xtensa.org
diff --git a/backport-include/linux/device.h b/backport-include/linux/device.h
index 830105d..41f06c3 100644
--- a/backport-include/linux/device.h
+++ b/backport-include/linux/device.h
@@ -110,6 +110,12 @@
 	device_unlock(dev);
 }
 #define device_release_driver LINUX_BACKPORT(device_release_driver)
+
+#define kobj_to_dev LINUX_BACKPORT(kobj_to_dev)
+static inline struct device *kobj_to_dev(struct kobject *kobj)
+{
+	return container_of(kobj, struct device, kobj);
+}
 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0) */
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0) && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)
diff --git a/backport-include/linux/etherdevice.h b/backport-include/linux/etherdevice.h
index cc2ee0a..70decd2 100644
--- a/backport-include/linux/etherdevice.h
+++ b/backport-include/linux/etherdevice.h
@@ -173,4 +173,9 @@
 }
 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) */
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
+#define eth_get_headlen LINUX_BACKPORT(eth_get_headlen)
+int eth_get_headlen(unsigned char *data, unsigned int max_len);
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0) */
+
 #endif /* _BACKPORT_LINUX_ETHERDEVICE_H */
diff --git a/backport-include/linux/freezer.h b/backport-include/linux/freezer.h
new file mode 100644
index 0000000..6bd6985
--- /dev/null
+++ b/backport-include/linux/freezer.h
@@ -0,0 +1,32 @@
+#ifndef __BACKPORT_FREEZER_H_INCLUDED
+#define __BACKPORT_FREEZER_H_INCLUDED
+#include_next <linux/freezer.h>
+
+#ifdef CONFIG_FREEZER
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
+/*
+ * Like schedule_hrtimeout_range(), but should not block the freezer.  Do not
+ * call this with locks held.
+ */
+#define freezable_schedule_hrtimeout_range LINUX_BACKPORT(freezable_schedule_hrtimeout_range)
+static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
+		unsigned long delta, const enum hrtimer_mode mode)
+{
+	int __retval;
+	freezer_do_not_count();
+	__retval = schedule_hrtimeout_range(expires, delta, mode);
+	freezer_count();
+	return __retval;
+}
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0) */
+
+#else /* !CONFIG_FREEZER */
+
+#ifndef freezable_schedule_hrtimeout_range
+#define freezable_schedule_hrtimeout_range(expires, delta, mode)	\
+	schedule_hrtimeout_range(expires, delta, mode)
+#endif
+
+#endif /* !CONFIG_FREEZER */
+
+#endif /* __BACKPORT_FREEZER_H_INCLUDED */
diff --git a/backport-include/linux/skbuff.h b/backport-include/linux/skbuff.h
index 4b4ca50..5a1725d 100644
--- a/backport-include/linux/skbuff.h
+++ b/backport-include/linux/skbuff.h
@@ -15,12 +15,17 @@
 #define __pskb_copy LINUX_BACKPORT(__pskb_copy)
 extern struct sk_buff *__pskb_copy(struct sk_buff *skb,
 				   int headroom, gfp_t gfp_mask);
+#endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
 #define skb_complete_wifi_ack LINUX_BACKPORT(skb_complete_wifi_ack)
 static inline void skb_complete_wifi_ack(struct sk_buff *skb, bool acked)
 {
 	WARN_ON(1);
 }
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
+#define skb_complete_wifi_ack LINUX_BACKPORT(skb_complete_wifi_ack)
+void skb_complete_wifi_ack(struct sk_buff *skb, bool acked);
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)
@@ -386,4 +391,9 @@
 }
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
+#define skb_clone_sk LINUX_BACKPORT(skb_clone_sk)
+struct sk_buff *skb_clone_sk(struct sk_buff *skb);
+#endif
+
 #endif /* __BACKPORT_SKBUFF_H */
diff --git a/compat/Kconfig b/compat/Kconfig
index dc8bfe3..d501092 100644
--- a/compat/Kconfig
+++ b/compat/Kconfig
@@ -125,3 +125,15 @@
 	default n if CRYPTO_CCM
 	default y if BACKPORT_CRYPTO_CCM
 	#c-file crypto/ccm.c
+
+config BACKPORT_WANT_DEV_COREDUMP
+	bool
+
+config BACKPORT_BUILD_WANT_DEV_COREDUMP
+	depends on n
+	bool
+	default n if DEV_COREDUMP
+	default n if DISABLE_DEV_COREDUMP
+	default y if BACKPORT_WANT_DEV_COREDUMP
+	#h-file linux/devcoredump.h
+	#c-file drivers/base/devcoredump.c
diff --git a/compat/Makefile b/compat/Makefile
index 472af12..1df6225 100644
--- a/compat/Makefile
+++ b/compat/Makefile
@@ -19,6 +19,7 @@
 compat-$(CPTCFG_BACKPORT_KERNEL_3_14) += backport-3.14.o
 compat-$(CPTCFG_BACKPORT_KERNEL_3_15) += backport-3.15.o
 compat-$(CPTCFG_BACKPORT_KERNEL_3_17) += backport-3.17.o
+compat-$(CPTCFG_BACKPORT_KERNEL_3_18) += backport-3.18.o
 
 compat-$(CPTCFG_BACKPORT_BUILD_CRYPTO_CCM) += crypto-ccm.o
 compat-$(CPTCFG_BACKPORT_BUILD_DMA_SHARED_HELPERS) += dma-shared-helpers.o
diff --git a/compat/backport-3.18.c b/compat/backport-3.18.c
new file mode 100644
index 0000000..b3c3f21
--- /dev/null
+++ b/compat/backport-3.18.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2014  Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Backport functionality introduced in Linux 3.18.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <scsi/fc/fc_fcoe.h>
+#include <linux/skbuff.h>
+#include <linux/errqueue.h>
+
+/**
+ * eth_get_headlen - determine the the length of header for an ethernet frame
+ * @data: pointer to start of frame
+ * @len: total length of frame
+ *
+ * Make a best effort attempt to pull the length for all of the headers for
+ * a given frame in a linear buffer.
+ */
+int eth_get_headlen(unsigned char *data, unsigned int max_len)
+{
+	union {
+		unsigned char *network;
+		/* l2 headers */
+		struct ethhdr *eth;
+		struct vlan_hdr *vlan;
+		/* l3 headers */
+		struct iphdr *ipv4;
+		struct ipv6hdr *ipv6;
+	} hdr;
+	__be16 protocol;
+	u8 nexthdr = 0;	/* default to not TCP */
+	u8 hlen;
+
+	/* this should never happen, but better safe than sorry */
+	if (max_len < ETH_HLEN)
+		return max_len;
+
+	/* initialize network frame pointer */
+	hdr.network = data;
+
+	/* set first protocol and move network header forward */
+	protocol = hdr.eth->h_proto;
+	hdr.network += ETH_HLEN;
+
+	/* handle any vlan tag if present */
+	if (protocol == htons(ETH_P_8021Q)) {
+		if ((hdr.network - data) > (max_len - VLAN_HLEN))
+			return max_len;
+
+		protocol = hdr.vlan->h_vlan_encapsulated_proto;
+		hdr.network += VLAN_HLEN;
+	}
+
+	/* handle L3 protocols */
+	if (protocol == htons(ETH_P_IP)) {
+		if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
+			return max_len;
+
+		/* access ihl as a u8 to avoid unaligned access on ia64 */
+		hlen = (hdr.network[0] & 0x0F) << 2;
+
+		/* verify hlen meets minimum size requirements */
+		if (hlen < sizeof(struct iphdr))
+			return hdr.network - data;
+
+		/* record next protocol if header is present */
+		if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
+			nexthdr = hdr.ipv4->protocol;
+	} else if (protocol == htons(ETH_P_IPV6)) {
+		if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
+			return max_len;
+
+		/* record next protocol */
+		nexthdr = hdr.ipv6->nexthdr;
+		hlen = sizeof(struct ipv6hdr);
+	} else if (protocol == htons(ETH_P_FCOE)) {
+		if ((hdr.network - data) > (max_len - FCOE_HEADER_LEN))
+			return max_len;
+		hlen = FCOE_HEADER_LEN;
+	} else {
+		return hdr.network - data;
+	}
+
+	/* relocate pointer to start of L4 header */
+	hdr.network += hlen;
+
+	/* finally sort out TCP/UDP */
+	if (nexthdr == IPPROTO_TCP) {
+		if ((hdr.network - data) > (max_len - sizeof(struct tcphdr)))
+			return max_len;
+
+		/* access doff as a u8 to avoid unaligned access on ia64 */
+		hlen = (hdr.network[12] & 0xF0) >> 2;
+
+		/* verify hlen meets minimum size requirements */
+		if (hlen < sizeof(struct tcphdr))
+			return hdr.network - data;
+
+		hdr.network += hlen;
+	} else if (nexthdr == IPPROTO_UDP) {
+		if ((hdr.network - data) > (max_len - sizeof(struct udphdr)))
+			return max_len;
+
+		hdr.network += sizeof(struct udphdr);
+	}
+
+	/*
+	 * If everything has gone correctly hdr.network should be the
+	 * data section of the packet and will be the end of the header.
+	 * If not then it probably represents the end of the last recognized
+	 * header.
+	 */
+	if ((hdr.network - data) < max_len)
+		return hdr.network - data;
+	else
+		return max_len;
+}
+EXPORT_SYMBOL_GPL(eth_get_headlen);
+
+#define sock_efree LINUX_BACKPORT(sock_efree)
+static void sock_efree(struct sk_buff *skb)
+{
+	sock_put(skb->sk);
+}
+
+/**
+ * skb_clone_sk - create clone of skb, and take reference to socket
+ * @skb: the skb to clone
+ *
+ * This function creates a clone of a buffer that holds a reference on
+ * sk_refcnt.  Buffers created via this function are meant to be
+ * returned using sock_queue_err_skb, or free via kfree_skb.
+ *
+ * When passing buffers allocated with this function to sock_queue_err_skb
+ * it is necessary to wrap the call with sock_hold/sock_put in order to
+ * prevent the socket from being released prior to being enqueued on
+ * the sk_error_queue.
+ */
+struct sk_buff *skb_clone_sk(struct sk_buff *skb)
+{
+	struct sock *sk = skb->sk;
+	struct sk_buff *clone;
+
+	if (!sk || !atomic_inc_not_zero(&sk->sk_refcnt))
+		return NULL;
+
+	clone = skb_clone(skb, GFP_ATOMIC);
+	if (!clone) {
+		sock_put(sk);
+		return NULL;
+	}
+
+	clone->sk = sk;
+	clone->destructor = sock_efree;
+
+	return clone;
+}
+EXPORT_SYMBOL_GPL(skb_clone_sk);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
+/*
+ * skb_complete_wifi_ack() needs to get backported, because the version from
+ * 3.18 added the sock_hold() and sock_put() calles missing in older versions.
+ */
+void skb_complete_wifi_ack(struct sk_buff *skb, bool acked)
+{
+	struct sock *sk = skb->sk;
+	struct sock_exterr_skb *serr;
+	int err;
+
+	skb->wifi_acked_valid = 1;
+	skb->wifi_acked = acked;
+
+	serr = SKB_EXT_ERR(skb);
+	memset(serr, 0, sizeof(*serr));
+	serr->ee.ee_errno = ENOMSG;
+	serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS;
+
+	/* take a reference to prevent skb_orphan() from freeing the socket */
+	sock_hold(sk);
+
+	err = sock_queue_err_skb(sk, skb);
+	if (err)
+		kfree_skb(skb);
+
+	sock_put(sk);
+}
+EXPORT_SYMBOL_GPL(skb_complete_wifi_ack);
+#endif
diff --git a/compat/backports.h b/compat/backports.h
index ed946b5..c9094ac 100644
--- a/compat/backports.h
+++ b/compat/backports.h
@@ -13,4 +13,14 @@
 {}
 #endif
 
+#ifdef CPTCFG_BACKPORT_BUILD_WANT_DEV_COREDUMP
+int devcoredump_init(void);
+void devcoredump_exit(void);
+#else
+static inline int devcoredump_init(void)
+{ return 0; }
+static inline void devcoredump_exit(void)
+{}
+#endif
+
 #endif /* LINUX_BACKPORTS_PRIVATE_H */
diff --git a/compat/main.c b/compat/main.c
index e38eed3..d3f8944 100644
--- a/compat/main.c
+++ b/compat/main.c
@@ -57,6 +57,12 @@
 	if (ret)
 		return ret;
 
+	ret = devcoredump_init();
+	if (ret) {
+		crypto_ccm_module_exit();
+		return ret;
+	}
+
 	printk(KERN_INFO "Loading modules backported from " BACKPORTED_KERNEL_NAME
 #ifndef BACKPORTS_GIT_TRACKED
 		" version " BACKPORTED_KERNEL_VERSION
@@ -75,5 +81,6 @@
 static void __exit backport_exit(void)
 {
 	crypto_ccm_module_exit();
+	devcoredump_exit();
 }
 module_exit(backport_exit);
diff --git a/defconfigs/brcmfmac b/defconfigs/brcmfmac
index 72b2859..f4657c7 100644
--- a/defconfigs/brcmfmac
+++ b/defconfigs/brcmfmac
@@ -4,3 +4,4 @@
 CPTCFG_BRCMFMAC=m
 CPTCFG_BRCMFMAC_SDIO=y
 CPTCFG_BRCMFMAC_USB=y
+CPTCFG_BRCMFMAC_PCIE=y
diff --git a/defconfigs/media b/defconfigs/media
new file mode 100644
index 0000000..7b1bfa9
--- /dev/null
+++ b/defconfigs/media
@@ -0,0 +1,513 @@
+CPTCFG_DVB_A8293=m
+CPTCFG_DVB_AF9013=m
+CPTCFG_DVB_AF9033=m
+CPTCFG_DVB_AS102=m
+CPTCFG_DVB_AS102_FE=m
+CPTCFG_DVB_ATBM8830=m
+CPTCFG_DVB_AU8522=m
+CPTCFG_DVB_AU8522_DTV=m
+CPTCFG_DVB_AU8522_V4L=m
+CPTCFG_DVB_AV7110=m
+CPTCFG_DVB_B2C2_FLEXCOP=m
+CPTCFG_DVB_B2C2_FLEXCOP_PCI=m
+CPTCFG_DVB_B2C2_FLEXCOP_USB=m
+CPTCFG_DVB_BCM3510=m
+CPTCFG_DVB_BT8XX=m
+CPTCFG_DVB_BUDGET=m
+CPTCFG_DVB_BUDGET_AV=m
+CPTCFG_DVB_BUDGET_CI=m
+CPTCFG_DVB_BUDGET_CORE=m
+CPTCFG_DVB_BUDGET_PATCH=m
+CPTCFG_DVB_CORE=m
+CPTCFG_DVB_CX22700=m
+CPTCFG_DVB_CX22702=m
+CPTCFG_DVB_CX24110=m
+CPTCFG_DVB_CX24116=m
+CPTCFG_DVB_CX24123=m
+CPTCFG_DVB_CXD2820R=m
+CPTCFG_DVB_DDBRIDGE=m
+CPTCFG_DVB_DIB3000MB=m
+CPTCFG_DVB_DIB3000MC=m
+CPTCFG_DVB_DIB7000M=m
+CPTCFG_DVB_DIB7000P=m
+CPTCFG_DVB_DIB8000=m
+CPTCFG_DVB_DIB9000=m
+CPTCFG_DVB_DM1105=m
+CPTCFG_DVB_DRXD=m
+CPTCFG_DVB_DRXK=m
+CPTCFG_DVB_DS3000=m
+CPTCFG_DVB_DUMMY_FE=m
+CPTCFG_DVB_EC100=m
+CPTCFG_DVB_FIREDTV=m
+CPTCFG_DVB_FIREDTV_INPUT=y
+CPTCFG_DVB_HD29L2=m
+CPTCFG_DVB_HOPPER=m
+CPTCFG_DVB_ISL6405=m
+CPTCFG_DVB_ISL6421=m
+CPTCFG_DVB_ISL6423=m
+CPTCFG_DVB_IX2505V=m
+CPTCFG_DVB_L64781=m
+CPTCFG_DVB_LG2160=m
+CPTCFG_DVB_LGDT3305=m
+CPTCFG_DVB_LGDT330X=m
+CPTCFG_DVB_LGS8GL5=m
+CPTCFG_DVB_LGS8GXX=m
+CPTCFG_DVB_LNBP21=m
+CPTCFG_DVB_LNBP22=m
+CPTCFG_DVB_M88RS2000=m
+CPTCFG_DVB_MANTIS=m
+CPTCFG_DVB_MB86A16=m
+CPTCFG_DVB_MB86A20S=m
+CPTCFG_DVB_MT312=m
+CPTCFG_DVB_MT352=m
+CPTCFG_DVB_NGENE=m
+CPTCFG_DVB_NXT200X=m
+CPTCFG_DVB_NXT6000=m
+CPTCFG_DVB_OR51132=m
+CPTCFG_DVB_OR51211=m
+CPTCFG_DVB_PLL=m
+CPTCFG_DVB_PLUTO2=m
+CPTCFG_DVB_PT1=m
+CPTCFG_DVB_PT3=m
+CPTCFG_DVB_RTL2830=m
+CPTCFG_DVB_RTL2832=m
+CPTCFG_DVB_S5H1409=m
+CPTCFG_DVB_S5H1411=m
+CPTCFG_DVB_S5H1420=m
+CPTCFG_DVB_S5H1432=m
+CPTCFG_DVB_S921=m
+CPTCFG_DVB_SI21XX=m
+CPTCFG_DVB_SP8870=m
+CPTCFG_DVB_SP887X=m
+CPTCFG_DVB_STB0899=m
+CPTCFG_DVB_STB6000=m
+CPTCFG_DVB_STB6100=m
+CPTCFG_DVB_STV0288=m
+CPTCFG_DVB_STV0297=m
+CPTCFG_DVB_STV0299=m
+CPTCFG_DVB_STV0367=m
+CPTCFG_DVB_STV0900=m
+CPTCFG_DVB_STV090x=m
+CPTCFG_DVB_STV6110=m
+CPTCFG_DVB_STV6110x=m
+CPTCFG_DVB_TDA10021=m
+CPTCFG_DVB_TDA10023=m
+CPTCFG_DVB_TDA10048=m
+CPTCFG_DVB_TDA1004X=m
+CPTCFG_DVB_TDA10071=m
+CPTCFG_DVB_TDA10086=m
+CPTCFG_DVB_TDA18271C2DD=m
+CPTCFG_DVB_TDA665x=m
+CPTCFG_DVB_TDA8083=m
+CPTCFG_DVB_TDA8261=m
+CPTCFG_DVB_TDA826X=m
+CPTCFG_DVB_TS2020=m
+CPTCFG_DVB_TTUSB_BUDGET=m
+CPTCFG_DVB_TTUSB_DEC=m
+CPTCFG_DVB_TUA6100=m
+CPTCFG_DVB_TUNER_CX24113=m
+CPTCFG_DVB_TUNER_DIB0070=m
+CPTCFG_DVB_TUNER_DIB0090=m
+CPTCFG_DVB_TUNER_ITD1000=m
+CPTCFG_DVB_USB=m
+CPTCFG_DVB_USB_A800=m
+CPTCFG_DVB_USB_AF9005=m
+CPTCFG_DVB_USB_AF9005_REMOTE=m
+CPTCFG_DVB_USB_AF9015=m
+CPTCFG_DVB_USB_AF9035=m
+CPTCFG_DVB_USB_ANYSEE=m
+CPTCFG_DVB_USB_AU6610=m
+CPTCFG_DVB_USB_AZ6007=m
+CPTCFG_DVB_USB_AZ6027=m
+CPTCFG_DVB_USB_CE6230=m
+CPTCFG_DVB_USB_CINERGY_T2=m
+CPTCFG_DVB_USB_CXUSB=m
+CPTCFG_DVB_USB_CYPRESS_FIRMWARE=m
+CPTCFG_DVB_USB_DIB0700=m
+CPTCFG_DVB_USB_DIBUSB_MB=m
+CPTCFG_DVB_USB_DIBUSB_MC=m
+CPTCFG_DVB_USB_DIGITV=m
+CPTCFG_DVB_USB_DTT200U=m
+CPTCFG_DVB_USB_DTV5100=m
+CPTCFG_DVB_USB_DVBSKY=m
+CPTCFG_DVB_USB_DW2102=m
+CPTCFG_DVB_USB_EC168=m
+CPTCFG_DVB_USB_FRIIO=m
+CPTCFG_DVB_USB_GL861=m
+CPTCFG_DVB_USB_GP8PSK=m
+CPTCFG_DVB_USB_LME2510=m
+CPTCFG_DVB_USB_M920X=m
+CPTCFG_DVB_USB_MXL111SF=m
+CPTCFG_DVB_USB_NOVA_T_USB2=m
+CPTCFG_DVB_USB_OPERA1=m
+CPTCFG_DVB_USB_PCTV452E=m
+CPTCFG_DVB_USB_RTL28XXU=m
+CPTCFG_DVB_USB_TECHNISAT_USB2=m
+CPTCFG_DVB_USB_TTUSB2=m
+CPTCFG_DVB_USB_UMT_010=m
+CPTCFG_DVB_USB_V2=m
+CPTCFG_DVB_USB_VP702X=m
+CPTCFG_DVB_USB_VP7045=m
+CPTCFG_DVB_VES1820=m
+CPTCFG_DVB_VES1X93=m
+CPTCFG_DVB_ZL10036=m
+CPTCFG_DVB_ZL10039=m
+CPTCFG_DVB_ZL10353=m
+CPTCFG_I2C_SI470X=m
+CPTCFG_I2C_SI4713=m
+CPTCFG_IR_ENE=m
+CPTCFG_IR_FINTEK=m
+CPTCFG_IR_GPIO_CIR=m
+CPTCFG_IR_IGUANA=m
+CPTCFG_IR_IMG=m
+CPTCFG_IR_IMG_HW=y
+CPTCFG_IR_IMG_JVC=y
+CPTCFG_IR_IMG_NEC=y
+CPTCFG_IR_IMG_RAW=y
+CPTCFG_IR_IMG_SANYO=y
+CPTCFG_IR_IMG_SHARP=y
+CPTCFG_IR_IMG_SONY=y
+CPTCFG_IR_IMON=m
+CPTCFG_IR_ITE_CIR=m
+CPTCFG_IR_JVC_DECODER=m
+CPTCFG_IR_LIRC_CODEC=m
+CPTCFG_IR_MCEUSB=m
+CPTCFG_IR_MCE_KBD_DECODER=m
+CPTCFG_IR_NEC_DECODER=m
+CPTCFG_IR_NUVOTON=m
+CPTCFG_IR_RC5_DECODER=m
+CPTCFG_IR_RC6_DECODER=m
+CPTCFG_IR_REDRAT3=m
+CPTCFG_IR_RX51=m
+CPTCFG_IR_SANYO_DECODER=m
+CPTCFG_IR_SONY_DECODER=m
+CPTCFG_IR_STREAMZAP=m
+CPTCFG_IR_TTUSBIR=m
+CPTCFG_IR_WINBOND_CIR=m
+CPTCFG_LIRC=m
+CPTCFG_MANTIS_CORE=m
+CPTCFG_MEDIA_ALTERA_CI=m
+CPTCFG_MEDIA_ANALOG_TV_SUPPORT=y
+CPTCFG_MEDIA_CAMERA_SUPPORT=y
+CPTCFG_MEDIA_CONTROLLER=y
+CPTCFG_MEDIA_DIGITAL_TV_SUPPORT=y
+CPTCFG_MEDIA_PARPORT_SUPPORT=y
+CPTCFG_MEDIA_PCI_SUPPORT=y
+CPTCFG_MEDIA_RADIO_SUPPORT=y
+CPTCFG_MEDIA_RC_SUPPORT=y
+CPTCFG_MEDIA_SDR_SUPPORT=y
+CPTCFG_MEDIA_SUPPORT=m
+CPTCFG_MEDIA_USB_SUPPORT=y
+CPTCFG_PLATFORM_SI4713=m
+CPTCFG_RADIO_AZTECH=m
+CPTCFG_RADIO_CADET=m
+CPTCFG_RADIO_GEMTEK=m
+CPTCFG_RADIO_ISA=m
+CPTCFG_RADIO_MAXIRADIO=m
+CPTCFG_RADIO_MIROPCM20=m
+CPTCFG_RADIO_RTRACK2=m
+CPTCFG_RADIO_RTRACK=m
+CPTCFG_RADIO_SAA7706H=m
+CPTCFG_RADIO_SF16FMI=m
+CPTCFG_RADIO_SF16FMR2=m
+CPTCFG_RADIO_SHARK2=m
+CPTCFG_RADIO_SHARK=m
+CPTCFG_RADIO_SI470X=y
+CPTCFG_RADIO_SI4713=m
+CPTCFG_RADIO_SI476X=m
+CPTCFG_RADIO_TEA5764=m
+CPTCFG_RADIO_TEF6862=m
+CPTCFG_RADIO_TERRATEC=m
+CPTCFG_RADIO_TIMBERDALE=m
+CPTCFG_RADIO_TRUST=m
+CPTCFG_RADIO_TYPHOON=m
+CPTCFG_RADIO_WL1273=m
+CPTCFG_RADIO_WL128X=m
+CPTCFG_RADIO_ZOLTRIX=m
+CPTCFG_RC_ATI_REMOTE=m
+CPTCFG_RC_CORE=m
+CPTCFG_RC_DEVICES=y
+CPTCFG_RC_LOOPBACK=m
+CPTCFG_RC_MAP=m
+CPTCFG_SMS_SDIO_DRV=m
+CPTCFG_SMS_SIANO_MDTV=m
+CPTCFG_SMS_USB_DRV=m
+CPTCFG_SOC_CAMERA=m
+CPTCFG_SOC_CAMERA_IMX074=m
+CPTCFG_SOC_CAMERA_MT9M001=m
+CPTCFG_SOC_CAMERA_MT9M111=m
+CPTCFG_SOC_CAMERA_MT9T031=m
+CPTCFG_SOC_CAMERA_MT9T112=m
+CPTCFG_SOC_CAMERA_MT9V022=m
+CPTCFG_SOC_CAMERA_OV2640=m
+CPTCFG_SOC_CAMERA_OV5642=m
+CPTCFG_SOC_CAMERA_OV6650=m
+CPTCFG_SOC_CAMERA_OV772X=m
+CPTCFG_SOC_CAMERA_OV9640=m
+CPTCFG_SOC_CAMERA_OV9740=m
+CPTCFG_SOC_CAMERA_PLATFORM=m
+CPTCFG_SOC_CAMERA_RJ54N1=m
+CPTCFG_SOC_CAMERA_TW9910=m
+CPTCFG_STA2X11_VIP=m
+CPTCFG_TTPCI_EEPROM=m
+CPTCFG_USB_AIRSPY=m
+CPTCFG_USB_DSBR=m
+CPTCFG_USB_GL860=m
+CPTCFG_USB_GSPCA=m
+CPTCFG_USB_GSPCA_BENQ=m
+CPTCFG_USB_GSPCA_CONEX=m
+CPTCFG_USB_GSPCA_CPIA1=m
+CPTCFG_USB_GSPCA_DTCS033=m
+CPTCFG_USB_GSPCA_ETOMS=m
+CPTCFG_USB_GSPCA_FINEPIX=m
+CPTCFG_USB_GSPCA_JEILINJ=m
+CPTCFG_USB_GSPCA_JL2005BCD=m
+CPTCFG_USB_GSPCA_KINECT=m
+CPTCFG_USB_GSPCA_KONICA=m
+CPTCFG_USB_GSPCA_MARS=m
+CPTCFG_USB_GSPCA_MR97310A=m
+CPTCFG_USB_GSPCA_NW80X=m
+CPTCFG_USB_GSPCA_OV519=m
+CPTCFG_USB_GSPCA_OV534=m
+CPTCFG_USB_GSPCA_OV534_9=m
+CPTCFG_USB_GSPCA_PAC207=m
+CPTCFG_USB_GSPCA_PAC7302=m
+CPTCFG_USB_GSPCA_PAC7311=m
+CPTCFG_USB_GSPCA_SE401=m
+CPTCFG_USB_GSPCA_SN9C2028=m
+CPTCFG_USB_GSPCA_SN9C20X=m
+CPTCFG_USB_GSPCA_SONIXB=m
+CPTCFG_USB_GSPCA_SONIXJ=m
+CPTCFG_USB_GSPCA_SPCA1528=m
+CPTCFG_USB_GSPCA_SPCA500=m
+CPTCFG_USB_GSPCA_SPCA501=m
+CPTCFG_USB_GSPCA_SPCA505=m
+CPTCFG_USB_GSPCA_SPCA506=m
+CPTCFG_USB_GSPCA_SPCA508=m
+CPTCFG_USB_GSPCA_SPCA561=m
+CPTCFG_USB_GSPCA_SQ905=m
+CPTCFG_USB_GSPCA_SQ905C=m
+CPTCFG_USB_GSPCA_SQ930X=m
+CPTCFG_USB_GSPCA_STK014=m
+CPTCFG_USB_GSPCA_STK1135=m
+CPTCFG_USB_GSPCA_STV0680=m
+CPTCFG_USB_GSPCA_SUNPLUS=m
+CPTCFG_USB_GSPCA_T613=m
+CPTCFG_USB_GSPCA_TOPRO=m
+CPTCFG_USB_GSPCA_TV8532=m
+CPTCFG_USB_GSPCA_VC032X=m
+CPTCFG_USB_GSPCA_VICAM=m
+CPTCFG_USB_GSPCA_XIRLINK_CIT=m
+CPTCFG_USB_GSPCA_ZC3XX=m
+CPTCFG_USB_HACKRF=m
+CPTCFG_USB_KEENE=m
+CPTCFG_USB_M5602=m
+CPTCFG_USB_MA901=m
+CPTCFG_USB_MR800=m
+CPTCFG_USB_MSI2500=m
+CPTCFG_USB_PWC=m
+CPTCFG_USB_RAREMONO=m
+CPTCFG_USB_S2255=m
+CPTCFG_USB_SI470X=m
+CPTCFG_USB_SI4713=m
+CPTCFG_USB_STKWEBCAM=m
+CPTCFG_USB_STV06XX=m
+CPTCFG_USB_VIDEO_CLASS=m
+CPTCFG_USB_ZR364XX=m
+CPTCFG_V4L2_MEM2MEM_DEV=m
+CPTCFG_V4L_MEM2MEM_DRIVERS=y
+CPTCFG_V4L_PLATFORM_DRIVERS=y
+CPTCFG_VIDEOBUF2_CORE=m
+CPTCFG_VIDEOBUF2_DMA_CONTIG=m
+CPTCFG_VIDEOBUF2_DMA_SG=m
+CPTCFG_VIDEOBUF2_MEMOPS=m
+CPTCFG_VIDEOBUF2_VMALLOC=m
+CPTCFG_VIDEOBUF_DMA_CONTIG=m
+CPTCFG_VIDEOBUF_DMA_SG=m
+CPTCFG_VIDEOBUF_DVB=m
+CPTCFG_VIDEOBUF_GEN=m
+CPTCFG_VIDEOBUF_VMALLOC=m
+CPTCFG_VIDEO_AD9389B=m
+CPTCFG_VIDEO_ADP1653=m
+CPTCFG_VIDEO_ADV7170=m
+CPTCFG_VIDEO_ADV7175=m
+CPTCFG_VIDEO_ADV7180=m
+CPTCFG_VIDEO_ADV7183=m
+CPTCFG_VIDEO_ADV7343=m
+CPTCFG_VIDEO_ADV7393=m
+CPTCFG_VIDEO_ADV7604=m
+CPTCFG_VIDEO_AK881X=m
+CPTCFG_VIDEO_APTINA_PLL=m
+CPTCFG_VIDEO_AS3645A=m
+CPTCFG_VIDEO_ATMEL_ISI=m
+CPTCFG_VIDEO_AU0828=m
+CPTCFG_VIDEO_AU0828_RC=y
+CPTCFG_VIDEO_BLACKFIN_CAPTURE=m
+CPTCFG_VIDEO_BLACKFIN_PPI=m
+CPTCFG_VIDEO_BT819=m
+CPTCFG_VIDEO_BT848=m
+CPTCFG_VIDEO_BT856=m
+CPTCFG_VIDEO_BT866=m
+CPTCFG_VIDEO_BTCX=m
+CPTCFG_VIDEO_BWQCAM=m
+CPTCFG_VIDEO_CAFE_CCIC=m
+CPTCFG_VIDEO_CODA=m
+CPTCFG_VIDEO_CPIA2=m
+CPTCFG_VIDEO_CQCAM=m
+CPTCFG_VIDEO_CS5345=m
+CPTCFG_VIDEO_CS53L32A=m
+CPTCFG_VIDEO_CX18=m
+CPTCFG_VIDEO_CX18_ALSA=m
+CPTCFG_VIDEO_CX231XX=m
+CPTCFG_VIDEO_CX231XX_ALSA=m
+CPTCFG_VIDEO_CX231XX_DVB=m
+CPTCFG_VIDEO_CX231XX_RC=y
+CPTCFG_VIDEO_CX2341X=m
+CPTCFG_VIDEO_CX23885=m
+CPTCFG_VIDEO_CX25821=m
+CPTCFG_VIDEO_CX25821_ALSA=m
+CPTCFG_VIDEO_CX25840=m
+CPTCFG_VIDEO_CX88=m
+CPTCFG_VIDEO_CX88_ALSA=m
+CPTCFG_VIDEO_CX88_BLACKBIRD=m
+CPTCFG_VIDEO_CX88_DVB=m
+CPTCFG_VIDEO_CX88_MPEG=m
+CPTCFG_VIDEO_CX88_VP3054=m
+CPTCFG_VIDEO_DAVINCI_VPBE_DISPLAY=m
+CPTCFG_VIDEO_DAVINCI_VPIF_CAPTURE=m
+CPTCFG_VIDEO_DAVINCI_VPIF_DISPLAY=m
+CPTCFG_VIDEO_DEV=m
+CPTCFG_VIDEO_DM355_CCDC=m
+CPTCFG_VIDEO_DM6446_CCDC=m
+CPTCFG_VIDEO_EM28XX=m
+CPTCFG_VIDEO_EM28XX_ALSA=m
+CPTCFG_VIDEO_EM28XX_DVB=m
+CPTCFG_VIDEO_EM28XX_RC=m
+CPTCFG_VIDEO_EM28XX_V4L2=m
+CPTCFG_VIDEO_EXYNOS_FIMC_LITE=m
+CPTCFG_VIDEO_FB_IVTV=m
+CPTCFG_VIDEO_GO7007=m
+CPTCFG_VIDEO_GO7007_USB=m
+CPTCFG_VIDEO_GO7007_USB_S2250_BOARD=m
+CPTCFG_VIDEO_HDPVR=m
+CPTCFG_VIDEO_HEXIUM_GEMINI=m
+CPTCFG_VIDEO_HEXIUM_ORION=m
+CPTCFG_VIDEO_IR_I2C=m
+CPTCFG_VIDEO_IVTV=m
+CPTCFG_VIDEO_IVTV_ALSA=m
+CPTCFG_VIDEO_KS0127=m
+CPTCFG_VIDEO_M32R_AR_M64278=m
+CPTCFG_VIDEO_M52790=m
+CPTCFG_VIDEO_M5MOLS=m
+CPTCFG_VIDEO_MEM2MEM_DEINTERLACE=m
+CPTCFG_VIDEO_MEM2MEM_TESTDEV=m
+CPTCFG_VIDEO_MEYE=m
+CPTCFG_VIDEO_MMP_CAMERA=m
+CPTCFG_VIDEO_MSP3400=m
+CPTCFG_VIDEO_MT9M032=m
+CPTCFG_VIDEO_MT9P031=m
+CPTCFG_VIDEO_MT9T001=m
+CPTCFG_VIDEO_MT9V011=m
+CPTCFG_VIDEO_MT9V032=m
+CPTCFG_VIDEO_MX2=m
+CPTCFG_VIDEO_MX2_EMMAPRP=m
+CPTCFG_VIDEO_MX3=m
+CPTCFG_VIDEO_MXB=m
+CPTCFG_VIDEO_NOON010PC30=m
+CPTCFG_VIDEO_OMAP1=m
+CPTCFG_VIDEO_OMAP2_VOUT=m
+CPTCFG_VIDEO_OMAP3=m
+CPTCFG_VIDEO_OV7640=m
+CPTCFG_VIDEO_OV7670=m
+CPTCFG_VIDEO_OV9650=m
+CPTCFG_VIDEO_PMS=m
+CPTCFG_VIDEO_PVRUSB2=m
+CPTCFG_VIDEO_PXA27x=m
+CPTCFG_VIDEO_S3C_CAMIF=m
+CPTCFG_VIDEO_S5C73M3=m
+CPTCFG_VIDEO_S5K4ECGX=m
+CPTCFG_VIDEO_S5K6AA=m
+CPTCFG_VIDEO_S5P_FIMC=m
+CPTCFG_VIDEO_S5P_MIPI_CSIS=m
+CPTCFG_VIDEO_SAA6588=m
+CPTCFG_VIDEO_SAA7110=m
+CPTCFG_VIDEO_SAA711X=m
+CPTCFG_VIDEO_SAA7127=m
+CPTCFG_VIDEO_SAA7134=m
+CPTCFG_VIDEO_SAA7134_ALSA=m
+CPTCFG_VIDEO_SAA7134_DVB=m
+CPTCFG_VIDEO_SAA7134_GO7007=m
+CPTCFG_VIDEO_SAA7134_RC=y
+CPTCFG_VIDEO_SAA7146=m
+CPTCFG_VIDEO_SAA7146_VV=m
+CPTCFG_VIDEO_SAA7164=m
+CPTCFG_VIDEO_SAA717X=m
+CPTCFG_VIDEO_SAA7185=m
+CPTCFG_VIDEO_SAA7191=m
+CPTCFG_VIDEO_SAMSUNG_EXYNOS_GSC=m
+CPTCFG_VIDEO_SAMSUNG_S5P_G2D=m
+CPTCFG_VIDEO_SAMSUNG_S5P_HDMI=m
+CPTCFG_VIDEO_SAMSUNG_S5P_HDMIPHY=m
+CPTCFG_VIDEO_SAMSUNG_S5P_JPEG=m
+CPTCFG_VIDEO_SAMSUNG_S5P_MFC=m
+CPTCFG_VIDEO_SAMSUNG_S5P_MIXER=m
+CPTCFG_VIDEO_SAMSUNG_S5P_SDO=m
+CPTCFG_VIDEO_SAMSUNG_S5P_SII9234=m
+CPTCFG_VIDEO_SAMSUNG_S5P_TV=y
+CPTCFG_VIDEO_SH_MOBILE_CEU=m
+CPTCFG_VIDEO_SH_MOBILE_CSI2=m
+CPTCFG_VIDEO_SH_VEU=m
+CPTCFG_VIDEO_SH_VOU=m
+CPTCFG_VIDEO_SMIAPP=m
+CPTCFG_VIDEO_SMIAPP_PLL=m
+CPTCFG_VIDEO_SOLO6X10=m
+CPTCFG_VIDEO_SONY_BTF_MPX=m
+CPTCFG_VIDEO_SR030PC30=m
+CPTCFG_VIDEO_STK1160=m
+CPTCFG_VIDEO_STK1160_AC97=y
+CPTCFG_VIDEO_STK1160_COMMON=m
+CPTCFG_VIDEO_TDA7432=m
+CPTCFG_VIDEO_TDA9840=m
+CPTCFG_VIDEO_TEA6415C=m
+CPTCFG_VIDEO_TEA6420=m
+CPTCFG_VIDEO_THS7303=m
+CPTCFG_VIDEO_TIMBERDALE=m
+CPTCFG_VIDEO_TLG2300=m
+CPTCFG_VIDEO_TLV320AIC23B=m
+CPTCFG_VIDEO_TM6000=m
+CPTCFG_VIDEO_TM6000_ALSA=m
+CPTCFG_VIDEO_TM6000_DVB=m
+CPTCFG_VIDEO_TUNER=m
+CPTCFG_VIDEO_TVAUDIO=m
+CPTCFG_VIDEO_TVEEPROM=m
+CPTCFG_VIDEO_TVP514X=m
+CPTCFG_VIDEO_TVP5150=m
+CPTCFG_VIDEO_TVP7002=m
+CPTCFG_VIDEO_TW2804=m
+CPTCFG_VIDEO_TW68=m
+CPTCFG_VIDEO_TW9903=m
+CPTCFG_VIDEO_TW9906=m
+CPTCFG_VIDEO_UDA1342=m
+CPTCFG_VIDEO_UPD64031A=m
+CPTCFG_VIDEO_UPD64083=m
+CPTCFG_VIDEO_USBTV=m
+CPTCFG_VIDEO_USBVISION=m
+CPTCFG_VIDEO_V4L2=m
+CPTCFG_VIDEO_V4L2_SUBDEV_API=y
+CPTCFG_VIDEO_VIA_CAMERA=m
+CPTCFG_VIDEO_VINO=m
+CPTCFG_VIDEO_VIU=m
+CPTCFG_VIDEO_VP27SMPX=m
+CPTCFG_VIDEO_VPX3220=m
+CPTCFG_VIDEO_VS6624=m
+CPTCFG_VIDEO_W9966=m
+CPTCFG_VIDEO_WM8739=m
+CPTCFG_VIDEO_WM8775=m
+CPTCFG_VIDEO_ZORAN=m
+CPTCFG_VIDEO_ZORAN_AVS6EYES=m
+CPTCFG_VIDEO_ZORAN_BUZ=m
+CPTCFG_VIDEO_ZORAN_DC10=m
+CPTCFG_VIDEO_ZORAN_DC30=m
+CPTCFG_VIDEO_ZORAN_LML33=m
+CPTCFG_VIDEO_ZORAN_LML33R10=m
+CPTCFG_VIDEO_ZORAN_ZR36060=m
diff --git a/defconfigs/rtlwifi b/defconfigs/rtlwifi
index 20f22c6..6c465fc 100644
--- a/defconfigs/rtlwifi
+++ b/defconfigs/rtlwifi
@@ -19,3 +19,5 @@
 CPTCFG_RTL8188EE=m
 CPTCFG_RTL8192CU=m
 CPTCFG_RTL8192C_COMMON=m
+CPTCFG_RTL8192EE=m
+CPTCFG_RTL8821AE=m
diff --git a/defconfigs/wifi b/defconfigs/wifi
index 4202055..96496ed 100644
--- a/defconfigs/wifi
+++ b/defconfigs/wifi
@@ -1,14 +1,14 @@
 CPTCFG_ADM8211=m
 CPTCFG_AR5523=m
 CPTCFG_AT76C50X_USB=m
+CPTCFG_ATH10K=m
+CPTCFG_ATH10K_PCI=m
 CPTCFG_ATH5K=m
 CPTCFG_ATH6KL=m
 CPTCFG_ATH6KL_SDIO=m
 CPTCFG_ATH6KL_USB=m
 CPTCFG_ATH9K_HTC=m
 CPTCFG_ATH9K=m
-CPTCFG_ATH10K=m
-CPTCFG_ATH10K_PCI=m
 CPTCFG_ATH_CARDS=m
 CPTCFG_B43LEGACY=m
 CPTCFG_B43=m
@@ -20,6 +20,7 @@
 CPTCFG_BCMA_HOST_PCI=y
 CPTCFG_BCMA=m
 CPTCFG_BRCMFMAC=m
+CPTCFG_BRCMFMAC_PCIE=y
 CPTCFG_BRCMFMAC_USB=y
 CPTCFG_BRCMSMAC=m
 CPTCFG_CARL9170=m
@@ -75,9 +76,9 @@
 CPTCFG_RT2500USB=m
 CPTCFG_RT2800PCI=m
 CPTCFG_RT2800USB=m
+CPTCFG_RT2800USB_RT3573=y
 CPTCFG_RT2800USB_RT53XX=y
 CPTCFG_RT2800USB_RT55XX=y
-CPTCFG_RT2800USB_RT3573=y
 CPTCFG_RT2800USB_UNKNOWN=y
 CPTCFG_RT2X00=m
 CPTCFG_RT61PCI=m
@@ -89,9 +90,11 @@
 CPTCFG_RTL8192CE=m
 CPTCFG_RTL8192CU=m
 CPTCFG_RTL8192DE=m
+CPTCFG_RTL8192EE=m
 CPTCFG_RTL8192SE=m
 CPTCFG_RTL8723AE=m
 CPTCFG_RTL8723BE=m
+CPTCFG_RTL8821AE=m
 CPTCFG_RTLWIFI=m
 CPTCFG_SSB=m
 CPTCFG_SSB_PCMCIAHOST=y
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
index 50065b1..f6c9aab 100644
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
@@ -1,5 +1,6 @@
 bcma-y					+= main.o scan.o core.o sprom.o
 bcma-y					+= driver_chipcommon.o driver_chipcommon_pmu.o
+bcma-y					+= driver_chipcommon_b.o
 bcma-$(CPTCFG_BCMA_SFLASH)		+= driver_chipcommon_sflash.o
 bcma-$(CPTCFG_BCMA_NFLASH)		+= driver_chipcommon_nflash.o
 bcma-y					+= driver_pci.o
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index e5ed463..16fc849 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -50,6 +50,10 @@
 extern struct platform_device bcma_pflash_dev;
 #endif /* CPTCFG_BCMA_DRIVER_MIPS */
 
+/* driver_chipcommon_b.c */
+int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
+void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb);
+
 /* driver_chipcommon_pmu.c */
 u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
 u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
@@ -84,6 +88,20 @@
 extern void __exit bcma_host_pci_exit(void);
 #endif /* CPTCFG_BCMA_HOST_PCI */
 
+/* host_soc.c */
+#if defined(CPTCFG_BCMA_HOST_SOC) && defined(CONFIG_OF)
+extern int __init bcma_host_soc_register_driver(void);
+extern void __exit bcma_host_soc_unregister_driver(void);
+#else
+static inline int __init bcma_host_soc_register_driver(void)
+{
+	return 0;
+}
+static inline void __exit bcma_host_soc_unregister_driver(void)
+{
+}
+#endif /* CPTCFG_BCMA_HOST_SOC && CONFIG_OF */
+
 /* driver_pci.c */
 u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
 
diff --git a/drivers/bcma/driver_chipcommon_b.c b/drivers/bcma/driver_chipcommon_b.c
new file mode 100644
index 0000000..c20b5f4
--- /dev/null
+++ b/drivers/bcma/driver_chipcommon_b.c
@@ -0,0 +1,61 @@
+/*
+ * Broadcom specific AMBA
+ * ChipCommon B Unit driver
+ *
+ * Copyright 2014, Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/export.h>
+#include <linux/bcma/bcma.h>
+
+static bool bcma_wait_reg(struct bcma_bus *bus, void __iomem *addr, u32 mask,
+			  u32 value, int timeout)
+{
+	unsigned long deadline = jiffies + timeout;
+	u32 val;
+
+	do {
+		val = readl(addr);
+		if ((val & mask) == value)
+			return true;
+		cpu_relax();
+		udelay(10);
+	} while (!time_after_eq(jiffies, deadline));
+
+	bcma_err(bus, "Timeout waiting for register %p\n", addr);
+
+	return false;
+}
+
+void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value)
+{
+	struct bcma_bus *bus = ccb->core->bus;
+
+	writel(offset, ccb->mii + 0x00);
+	bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
+	writel(value, ccb->mii + 0x04);
+	bcma_wait_reg(bus, ccb->mii + 0x00, 0x0100, 0x0000, 100);
+}
+EXPORT_SYMBOL_GPL(bcma_chipco_b_mii_write);
+
+int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb)
+{
+	if (ccb->setup_done)
+		return 0;
+
+	ccb->setup_done = 1;
+	ccb->mii = ioremap_nocache(ccb->core->addr_s[1], BCMA_CORE_SIZE);
+	if (!ccb->mii)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb)
+{
+	if (ccb->mii)
+		iounmap(ccb->mii);
+}
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c
index 61ee945..706b9ae 100644
--- a/drivers/bcma/driver_gpio.c
+++ b/drivers/bcma/driver_gpio.c
@@ -76,7 +76,7 @@
 	bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
 }
 
-#if IS_BUILTIN(CPTCFG_BCMA_HOST_SOC)
+#if IS_BUILTIN(CONFIG_BCM47XX)
 static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
 {
 	struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
@@ -215,9 +215,13 @@
 	chip->set		= bcma_gpio_set_value;
 	chip->direction_input	= bcma_gpio_direction_input;
 	chip->direction_output	= bcma_gpio_direction_output;
-#if IS_BUILTIN(CPTCFG_BCMA_HOST_SOC)
+#if IS_BUILTIN(CONFIG_BCM47XX)
 	chip->to_irq		= bcma_gpio_to_irq;
 #endif
+#if IS_BUILTIN(CONFIG_OF)
+	if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
+		chip->of_node	= cc->core->dev.of_node;
+#endif
 	switch (cc->core->bus->chipinfo.id) {
 	case BCMA_CHIP_ID_BCM5357:
 	case BCMA_CHIP_ID_BCM53572:
@@ -251,5 +255,6 @@
 int bcma_gpio_unregister(struct bcma_drv_cc *cc)
 {
 	bcma_gpio_irq_domain_exit(cc);
-	return gpiochip_remove(&cc->gpio);
+	gpiochip_remove(&cc->gpio);
+	return 0;
 }
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c
index 11115bb..004d6aa 100644
--- a/drivers/bcma/driver_mips.c
+++ b/drivers/bcma/driver_mips.c
@@ -21,6 +21,14 @@
 #include <linux/serial_reg.h>
 #include <linux/time.h>
 
+enum bcma_boot_dev {
+	BCMA_BOOT_DEV_UNK = 0,
+	BCMA_BOOT_DEV_ROM,
+	BCMA_BOOT_DEV_PARALLEL,
+	BCMA_BOOT_DEV_SERIAL,
+	BCMA_BOOT_DEV_NAND,
+};
+
 static const char * const part_probes[] = { "bcm47xxpart", NULL };
 
 static struct physmap_flash_data bcma_pflash_data = {
@@ -229,11 +237,51 @@
 }
 EXPORT_SYMBOL(bcma_cpu_clock);
 
+static enum bcma_boot_dev bcma_boot_dev(struct bcma_bus *bus)
+{
+	struct bcma_drv_cc *cc = &bus->drv_cc;
+	u8 cc_rev = cc->core->id.rev;
+
+	if (cc_rev == 42) {
+		struct bcma_device *core;
+
+		core = bcma_find_core(bus, BCMA_CORE_NS_ROM);
+		if (core) {
+			switch (bcma_aread32(core, BCMA_IOST) &
+				BCMA_NS_ROM_IOST_BOOT_DEV_MASK) {
+			case BCMA_NS_ROM_IOST_BOOT_DEV_NOR:
+				return BCMA_BOOT_DEV_SERIAL;
+			case BCMA_NS_ROM_IOST_BOOT_DEV_NAND:
+				return BCMA_BOOT_DEV_NAND;
+			case BCMA_NS_ROM_IOST_BOOT_DEV_ROM:
+			default:
+				return BCMA_BOOT_DEV_ROM;
+			}
+		}
+	} else {
+		if (cc_rev == 38) {
+			if (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT)
+				return BCMA_BOOT_DEV_NAND;
+			else if (cc->status & BIT(5))
+				return BCMA_BOOT_DEV_ROM;
+		}
+
+		if ((cc->capabilities & BCMA_CC_CAP_FLASHT) ==
+		    BCMA_CC_FLASHT_PARA)
+			return BCMA_BOOT_DEV_PARALLEL;
+		else
+			return BCMA_BOOT_DEV_SERIAL;
+	}
+
+	return BCMA_BOOT_DEV_SERIAL;
+}
+
 static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
 {
 	struct bcma_bus *bus = mcore->core->bus;
 	struct bcma_drv_cc *cc = &bus->drv_cc;
 	struct bcma_pflash *pflash = &cc->pflash;
+	enum bcma_boot_dev boot_dev;
 
 	switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
 	case BCMA_CC_FLASHT_STSER:
@@ -269,6 +317,20 @@
 			bcma_nflash_init(cc);
 		}
 	}
+
+	/* Determine flash type this SoC boots from */
+	boot_dev = bcma_boot_dev(bus);
+	switch (boot_dev) {
+	case BCMA_BOOT_DEV_PARALLEL:
+	case BCMA_BOOT_DEV_SERIAL:
+		/* TODO: Init NVRAM using BCMA_SOC_FLASH2 window */
+		break;
+	case BCMA_BOOT_DEV_NAND:
+		/* TODO: Init NVRAM using BCMA_SOC_FLASH1 window */
+		break;
+	default:
+		break;
+	}
 }
 
 void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c
index f3c05ab..6a76e68 100644
--- a/drivers/bcma/host_pci.c
+++ b/drivers/bcma/host_pci.c
@@ -208,6 +208,9 @@
 	bus->boardinfo.vendor = bus->host_pci->subsystem_vendor;
 	bus->boardinfo.type = bus->host_pci->subsystem_device;
 
+	/* Initialize struct, detect chip */
+	bcma_init_bus(bus);
+
 	/* Register */
 	err = bcma_bus_register(bus);
 	if (err)
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
index 426b46c..1e1e679 100644
--- a/drivers/bcma/host_soc.c
+++ b/drivers/bcma/host_soc.c
@@ -7,6 +7,9 @@
 
 #include "bcma_private.h"
 #include "scan.h"
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
 #include <linux/bcma/bcma.h>
 #include <linux/bcma/bcma_soc.h>
 
@@ -134,12 +137,16 @@
 
 static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
 {
+	if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n"))
+		return ~0;
 	return readl(core->io_wrap + offset);
 }
 
 static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
 				  u32 value)
 {
+	if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n"))
+		return;
 	writel(value, core->io_wrap + offset);
 }
 
@@ -161,7 +168,6 @@
 int __init bcma_host_soc_register(struct bcma_soc *soc)
 {
 	struct bcma_bus *bus = &soc->bus;
-	int err;
 
 	/* iomap only first core. We have to read some register on this core
 	 * to scan the bus.
@@ -173,11 +179,100 @@
 	/* Host specific */
 	bus->hosttype = BCMA_HOSTTYPE_SOC;
 	bus->ops = &bcma_host_soc_ops;
+	bus->host_pdev = NULL;
 
-	/* Register */
+	/* Initialize struct, detect chip */
+	bcma_init_bus(bus);
+
+	return 0;
+}
+
+int __init bcma_host_soc_init(struct bcma_soc *soc)
+{
+	struct bcma_bus *bus = &soc->bus;
+	int err;
+
+	/* Scan bus and initialize it */
 	err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
 	if (err)
 		iounmap(bus->mmio);
 
 	return err;
 }
+
+#ifdef CONFIG_OF
+static int bcma_host_soc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct bcma_bus *bus;
+	int err;
+
+	/* Alloc */
+	bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL);
+	if (!bus)
+		return -ENOMEM;
+
+	/* Map MMIO */
+	bus->mmio = of_iomap(np, 0);
+	if (!bus->mmio)
+		return -ENOMEM;
+
+	/* Host specific */
+	bus->hosttype = BCMA_HOSTTYPE_SOC;
+	bus->ops = &bcma_host_soc_ops;
+	bus->host_pdev = pdev;
+
+	/* Initialize struct, detect chip */
+	bcma_init_bus(bus);
+
+	/* Register */
+	err = bcma_bus_register(bus);
+	if (err)
+		goto err_unmap_mmio;
+
+	platform_set_drvdata(pdev, bus);
+
+	return err;
+
+err_unmap_mmio:
+	iounmap(bus->mmio);
+	return err;
+}
+
+static int bcma_host_soc_remove(struct platform_device *pdev)
+{
+	struct bcma_bus *bus = platform_get_drvdata(pdev);
+
+	bcma_bus_unregister(bus);
+	iounmap(bus->mmio);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id bcma_host_soc_of_match[] = {
+	{ .compatible = "brcm,bus-axi", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bcma_host_soc_of_match);
+
+static struct platform_driver bcma_host_soc_driver = {
+	.driver = {
+		.name = "bcma-host-soc",
+		.of_match_table = bcma_host_soc_of_match,
+	},
+	.probe		= bcma_host_soc_probe,
+	.remove		= bcma_host_soc_remove,
+};
+
+int __init bcma_host_soc_register_driver(void)
+{
+	return platform_driver_register(&bcma_host_soc_driver);
+}
+
+void __exit bcma_host_soc_unregister_driver(void)
+{
+	platform_driver_unregister(&bcma_host_soc_driver);
+}
+#endif /* CONFIG_OF */
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 375242b..5379919 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -10,6 +10,7 @@
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 #include <linux/slab.h>
+#include <linux/of_address.h>
 
 MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
 MODULE_LICENSE("GPL");
@@ -129,16 +130,103 @@
 	kfree(core);
 }
 
-static int bcma_register_cores(struct bcma_bus *bus)
+static bool bcma_is_core_needed_early(u16 core_id)
+{
+	switch (core_id) {
+	case BCMA_CORE_NS_NAND:
+	case BCMA_CORE_NS_QSPI:
+		return true;
+	}
+
+	return false;
+}
+
+#ifdef CONFIG_OF
+static struct device_node *bcma_of_find_child_device(struct platform_device *parent,
+						     struct bcma_device *core)
+{
+	struct device_node *node;
+	u64 size;
+	const __be32 *reg;
+
+	if (!parent || !parent->dev.of_node)
+		return NULL;
+
+	for_each_child_of_node(parent->dev.of_node, node) {
+		reg = of_get_address(node, 0, &size, NULL);
+		if (!reg)
+			continue;
+		if (of_translate_address(node, reg) == core->addr)
+			return node;
+	}
+	return NULL;
+}
+
+static void bcma_of_fill_device(struct platform_device *parent,
+				struct bcma_device *core)
+{
+	struct device_node *node;
+
+	node = bcma_of_find_child_device(parent, core);
+	if (node)
+		core->dev.of_node = node;
+}
+#else
+static void bcma_of_fill_device(struct platform_device *parent,
+				struct bcma_device *core)
+{
+}
+#endif /* CONFIG_OF */
+
+static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
+{
+	int err;
+
+	core->dev.release = bcma_release_core_dev;
+	core->dev.bus = &bcma_bus_type;
+	dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
+
+	switch (bus->hosttype) {
+	case BCMA_HOSTTYPE_PCI:
+		core->dev.parent = &bus->host_pci->dev;
+		core->dma_dev = &bus->host_pci->dev;
+		core->irq = bus->host_pci->irq;
+		break;
+	case BCMA_HOSTTYPE_SOC:
+		core->dev.dma_mask = &core->dev.coherent_dma_mask;
+		if (bus->host_pdev) {
+			core->dma_dev = &bus->host_pdev->dev;
+			core->dev.parent = &bus->host_pdev->dev;
+			bcma_of_fill_device(bus->host_pdev, core);
+		} else {
+			core->dma_dev = &core->dev;
+		}
+		break;
+	case BCMA_HOSTTYPE_SDIO:
+		break;
+	}
+
+	err = device_register(&core->dev);
+	if (err) {
+		bcma_err(bus, "Could not register dev for core 0x%03X\n",
+			 core->id.id);
+		put_device(&core->dev);
+		return;
+	}
+	core->dev_registered = true;
+}
+
+static int bcma_register_devices(struct bcma_bus *bus)
 {
 	struct bcma_device *core;
-	int err, dev_id = 0;
+	int err;
 
 	list_for_each_entry(core, &bus->cores, list) {
 		/* We support that cores ourself */
 		switch (core->id.id) {
 		case BCMA_CORE_4706_CHIPCOMMON:
 		case BCMA_CORE_CHIPCOMMON:
+		case BCMA_CORE_NS_CHIPCOMMON_B:
 		case BCMA_CORE_PCI:
 		case BCMA_CORE_PCIE:
 		case BCMA_CORE_PCIE2:
@@ -147,39 +235,16 @@
 			continue;
 		}
 
+		/* Early cores were already registered */
+		if (bcma_is_core_needed_early(core->id.id))
+			continue;
+
 		/* Only first GMAC core on BCM4706 is connected and working */
 		if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
 		    core->core_unit > 0)
 			continue;
 
-		core->dev.release = bcma_release_core_dev;
-		core->dev.bus = &bcma_bus_type;
-		dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id);
-
-		switch (bus->hosttype) {
-		case BCMA_HOSTTYPE_PCI:
-			core->dev.parent = &bus->host_pci->dev;
-			core->dma_dev = &bus->host_pci->dev;
-			core->irq = bus->host_pci->irq;
-			break;
-		case BCMA_HOSTTYPE_SOC:
-			core->dev.dma_mask = &core->dev.coherent_dma_mask;
-			core->dma_dev = &core->dev;
-			break;
-		case BCMA_HOSTTYPE_SDIO:
-			break;
-		}
-
-		err = device_register(&core->dev);
-		if (err) {
-			bcma_err(bus,
-				 "Could not register dev for core 0x%03X\n",
-				 core->id.id);
-			put_device(&core->dev);
-			continue;
-		}
-		core->dev_registered = true;
-		dev_id++;
+		bcma_register_core(bus, core);
 	}
 
 #ifdef CPTCFG_BCMA_DRIVER_MIPS
@@ -256,6 +321,12 @@
 		bcma_core_chipcommon_early_init(&bus->drv_cc);
 	}
 
+	/* Cores providing flash access go before SPROM init */
+	list_for_each_entry(core, &bus->cores, list) {
+		if (bcma_is_core_needed_early(core->id.id))
+			bcma_register_core(bus, core);
+	}
+
 	/* Try to get SPROM */
 	err = bcma_sprom_get(bus);
 	if (err == -ENOENT) {
@@ -270,6 +341,13 @@
 		bcma_core_chipcommon_init(&bus->drv_cc);
 	}
 
+	/* Init CC core */
+	core = bcma_find_core(bus, BCMA_CORE_NS_CHIPCOMMON_B);
+	if (core) {
+		bus->drv_cc_b.core = core;
+		bcma_core_chipcommon_b_init(&bus->drv_cc_b);
+	}
+
 	/* Init MIPS core */
 	core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
 	if (core) {
@@ -306,7 +384,7 @@
 	}
 
 	/* Register found cores */
-	bcma_register_cores(bus);
+	bcma_register_devices(bus);
 
 	bcma_info(bus, "Bus registered\n");
 
@@ -324,6 +402,8 @@
 	else if (err)
 		bcma_err(bus, "Can not unregister GPIO driver: %i\n", err);
 
+	bcma_core_chipcommon_b_free(&bus->drv_cc_b);
+
 	cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
 	cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
 	cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
@@ -343,8 +423,6 @@
 	struct bcma_device *core;
 	struct bcma_device_id match;
 
-	bcma_init_bus(bus);
-
 	match.manuf = BCMA_MANUF_BCM;
 	match.id = bcma_cc_core_id(bus);
 	match.class = BCMA_CL_SIM;
@@ -504,6 +582,11 @@
 	if (err)
 		return err;
 
+	err = bcma_host_soc_register_driver();
+	if (err) {
+		pr_err("SoC host initialization failed\n");
+		err = 0;
+	}
 #ifdef CPTCFG_BCMA_HOST_PCI
 	err = bcma_host_pci_init();
 	if (err) {
@@ -521,6 +604,7 @@
 #ifdef CPTCFG_BCMA_HOST_PCI
 	bcma_host_pci_exit();
 #endif
+	bcma_host_soc_unregister_driver();
 	bus_unregister(&bcma_bus_type);
 }
 module_exit(bcma_modexit)
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index b4764c6..14b5656 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -276,7 +276,7 @@
 			      struct bcma_device *core)
 {
 	u32 tmp;
-	u8 i, j;
+	u8 i, j, k;
 	s32 cia, cib;
 	u8 ports[2], wrappers[2];
 
@@ -314,6 +314,7 @@
 		/* Some specific cores don't need wrappers */
 		switch (core->id.id) {
 		case BCMA_CORE_4706_MAC_GBIT_COMMON:
+		case BCMA_CORE_NS_CHIPCOMMON_B:
 		/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
 			break;
 		default:
@@ -367,6 +368,7 @@
 	core->addr = tmp;
 
 	/* get & parse slave ports */
+	k = 0;
 	for (i = 0; i < ports[1]; i++) {
 		for (j = 0; ; j++) {
 			tmp = bcma_erom_get_addr_desc(bus, eromptr,
@@ -376,9 +378,9 @@
 				/* pr_debug("erom: slave port %d "
 				 * "has %d descriptors\n", i, j); */
 				break;
-			} else {
-				if (i == 0 && j == 0)
-					core->addr1 = tmp;
+			} else if (k < ARRAY_SIZE(core->addr_s)) {
+				core->addr_s[k] = tmp;
+				k++;
 			}
 		}
 	}
@@ -421,10 +423,13 @@
 		core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
 		if (!core->io_addr)
 			return -ENOMEM;
-		core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
-		if (!core->io_wrap) {
-			iounmap(core->io_addr);
-			return -ENOMEM;
+		if (core->wrap) {
+			core->io_wrap = ioremap_nocache(core->wrap,
+							BCMA_CORE_SIZE);
+			if (!core->io_wrap) {
+				iounmap(core->io_addr);
+				return -ENOMEM;
+			}
 		}
 	}
 	return 0;
@@ -434,9 +439,7 @@
 {
 	s32 tmp;
 	struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
-
-	if (bus->init_done)
-		return;
+	char chip_id[8];
 
 	INIT_LIST_HEAD(&bus->cores);
 	bus->nr_cores = 0;
@@ -447,10 +450,11 @@
 	chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
 	chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
 	chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
-	bcma_info(bus, "Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
-		  chipinfo->id, chipinfo->rev, chipinfo->pkg);
 
-	bus->init_done = true;
+	snprintf(chip_id, ARRAY_SIZE(chip_id),
+		 (chipinfo->id > 0x9999) ? "%d" : "0x%04X", chipinfo->id);
+	bcma_info(bus, "Found chip with id %s, rev 0x%02X and package 0x%02X\n",
+		  chip_id, chipinfo->rev, chipinfo->pkg);
 }
 
 int bcma_bus_scan(struct bcma_bus *bus)
@@ -460,8 +464,6 @@
 
 	int err, core_num = 0;
 
-	bcma_init_bus(bus);
-
 	erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
 	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
 		eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index acf719b..dcc4d71 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -213,7 +213,7 @@
 	  The core driver to support Marvell Bluetooth devices.
 
 	  This driver is required if you want to support
-	  Marvell Bluetooth devices, such as 8688/8787/8797/8897.
+	  Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897.
 
 	  Say Y here to compile Marvell Bluetooth driver
 	  into the kernel or say M to compile it as module.
@@ -227,7 +227,7 @@
 	  The driver for Marvell Bluetooth chipsets with SDIO interface.
 
 	  This driver is required if you want to use Marvell Bluetooth
-	  devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8897
+	  devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897
 	  chipsets are supported.
 
 	  Say Y here to compile support for Marvell BT-over-SDIO driver
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index eaefe3c..1723b6e 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -88,6 +88,7 @@
 	{ USB_DEVICE(0x04CA, 0x300b) },
 	{ USB_DEVICE(0x0930, 0x0219) },
 	{ USB_DEVICE(0x0930, 0x0220) },
+	{ USB_DEVICE(0x0930, 0x0227) },
 	{ USB_DEVICE(0x0b05, 0x17d0) },
 	{ USB_DEVICE(0x0CF3, 0x0036) },
 	{ USB_DEVICE(0x0CF3, 0x3004) },
@@ -138,6 +139,7 @@
 	{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index dfa5043..35e63aa 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -61,7 +61,7 @@
 /* ======================== Local structures ======================== */
 
 
-typedef struct bluecard_info_t {
+struct bluecard_info {
 	struct pcmcia_device *p_dev;
 
 	struct hci_dev *hdev;
@@ -78,7 +78,7 @@
 
 	unsigned char ctrl_reg;
 	unsigned long hw_state;		/* Status of the hardware and LED control */
-} bluecard_info_t;
+};
 
 
 static int bluecard_config(struct pcmcia_device *link);
@@ -157,7 +157,7 @@
 
 static void bluecard_activity_led_timeout(u_long arg)
 {
-	bluecard_info_t *info = (bluecard_info_t *)arg;
+	struct bluecard_info *info = (struct bluecard_info *)arg;
 	unsigned int iobase = info->p_dev->resource[0]->start;
 
 	if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
@@ -173,7 +173,7 @@
 }
 
 
-static void bluecard_enable_activity_led(bluecard_info_t *info)
+static void bluecard_enable_activity_led(struct bluecard_info *info)
 {
 	unsigned int iobase = info->p_dev->resource[0]->start;
 
@@ -215,7 +215,7 @@
 }
 
 
-static void bluecard_write_wakeup(bluecard_info_t *info)
+static void bluecard_write_wakeup(struct bluecard_info *info)
 {
 	if (!info) {
 		BT_ERR("Unknown device");
@@ -368,7 +368,8 @@
 }
 
 
-static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
+static void bluecard_receive(struct bluecard_info *info,
+			     unsigned int offset)
 {
 	unsigned int iobase;
 	unsigned char buf[31];
@@ -497,7 +498,7 @@
 
 static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
 {
-	bluecard_info_t *info = dev_inst;
+	struct bluecard_info *info = dev_inst;
 	unsigned int iobase;
 	unsigned char reg;
 
@@ -562,7 +563,7 @@
 
 static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
 {
-	bluecard_info_t *info = hci_get_drvdata(hdev);
+	struct bluecard_info *info = hci_get_drvdata(hdev);
 	struct sk_buff *skb;
 
 	/* Ericsson baud rate command */
@@ -611,7 +612,7 @@
 
 static int bluecard_hci_flush(struct hci_dev *hdev)
 {
-	bluecard_info_t *info = hci_get_drvdata(hdev);
+	struct bluecard_info *info = hci_get_drvdata(hdev);
 
 	/* Drop TX queue */
 	skb_queue_purge(&(info->txq));
@@ -622,7 +623,7 @@
 
 static int bluecard_hci_open(struct hci_dev *hdev)
 {
-	bluecard_info_t *info = hci_get_drvdata(hdev);
+	struct bluecard_info *info = hci_get_drvdata(hdev);
 
 	if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
 		bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
@@ -643,7 +644,7 @@
 
 static int bluecard_hci_close(struct hci_dev *hdev)
 {
-	bluecard_info_t *info = hci_get_drvdata(hdev);
+	struct bluecard_info *info = hci_get_drvdata(hdev);
 
 	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
 		return 0;
@@ -663,7 +664,7 @@
 
 static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	bluecard_info_t *info = hci_get_drvdata(hdev);
+	struct bluecard_info *info = hci_get_drvdata(hdev);
 
 	switch (bt_cb(skb)->pkt_type) {
 	case HCI_COMMAND_PKT:
@@ -691,7 +692,7 @@
 /* ======================== Card services HCI interaction ======================== */
 
 
-static int bluecard_open(bluecard_info_t *info)
+static int bluecard_open(struct bluecard_info *info)
 {
 	unsigned int iobase = info->p_dev->resource[0]->start;
 	struct hci_dev *hdev;
@@ -806,7 +807,7 @@
 }
 
 
-static int bluecard_close(bluecard_info_t *info)
+static int bluecard_close(struct bluecard_info *info)
 {
 	unsigned int iobase = info->p_dev->resource[0]->start;
 	struct hci_dev *hdev = info->hdev;
@@ -833,7 +834,7 @@
 
 static int bluecard_probe(struct pcmcia_device *link)
 {
-	bluecard_info_t *info;
+	struct bluecard_info *info;
 
 	/* Create new info device */
 	info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
@@ -857,7 +858,7 @@
 
 static int bluecard_config(struct pcmcia_device *link)
 {
-	bluecard_info_t *info = link->priv;
+	struct bluecard_info *info = link->priv;
 	int i, n;
 
 	link->config_index = 0x20;
@@ -897,7 +898,7 @@
 
 static void bluecard_release(struct pcmcia_device *link)
 {
-	bluecard_info_t *info = link->priv;
+	struct bluecard_info *info = link->priv;
 
 	bluecard_close(info);
 
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 1d82721..4f7e8d4 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -67,7 +67,7 @@
 /* ======================== Local structures ======================== */
 
 
-typedef struct bt3c_info_t {
+struct bt3c_info {
 	struct pcmcia_device *p_dev;
 
 	struct hci_dev *hdev;
@@ -80,7 +80,7 @@
 	unsigned long rx_state;
 	unsigned long rx_count;
 	struct sk_buff *rx_skb;
-} bt3c_info_t;
+};
 
 
 static int bt3c_config(struct pcmcia_device *link);
@@ -175,7 +175,7 @@
 }
 
 
-static void bt3c_write_wakeup(bt3c_info_t *info)
+static void bt3c_write_wakeup(struct bt3c_info *info)
 {
 	if (!info) {
 		BT_ERR("Unknown device");
@@ -214,7 +214,7 @@
 }
 
 
-static void bt3c_receive(bt3c_info_t *info)
+static void bt3c_receive(struct bt3c_info *info)
 {
 	unsigned int iobase;
 	int size = 0, avail;
@@ -336,7 +336,7 @@
 
 static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
 {
-	bt3c_info_t *info = dev_inst;
+	struct bt3c_info *info = dev_inst;
 	unsigned int iobase;
 	int iir;
 	irqreturn_t r = IRQ_NONE;
@@ -388,7 +388,7 @@
 
 static int bt3c_hci_flush(struct hci_dev *hdev)
 {
-	bt3c_info_t *info = hci_get_drvdata(hdev);
+	struct bt3c_info *info = hci_get_drvdata(hdev);
 
 	/* Drop TX queue */
 	skb_queue_purge(&(info->txq));
@@ -418,7 +418,7 @@
 
 static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	bt3c_info_t *info = hci_get_drvdata(hdev);
+	struct bt3c_info *info = hci_get_drvdata(hdev);
 	unsigned long flags;
 
 	switch (bt_cb(skb)->pkt_type) {
@@ -451,7 +451,8 @@
 /* ======================== Card services HCI interaction ======================== */
 
 
-static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware,
+static int bt3c_load_firmware(struct bt3c_info *info,
+			      const unsigned char *firmware,
 			      int count)
 {
 	char *ptr = (char *) firmware;
@@ -536,7 +537,7 @@
 }
 
 
-static int bt3c_open(bt3c_info_t *info)
+static int bt3c_open(struct bt3c_info *info)
 {
 	const struct firmware *firmware;
 	struct hci_dev *hdev;
@@ -603,7 +604,7 @@
 }
 
 
-static int bt3c_close(bt3c_info_t *info)
+static int bt3c_close(struct bt3c_info *info)
 {
 	struct hci_dev *hdev = info->hdev;
 
@@ -620,7 +621,7 @@
 
 static int bt3c_probe(struct pcmcia_device *link)
 {
-	bt3c_info_t *info;
+	struct bt3c_info *info;
 
 	/* Create new info device */
 	info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
@@ -683,7 +684,7 @@
 
 static int bt3c_config(struct pcmcia_device *link)
 {
-	bt3c_info_t *info = link->priv;
+	struct bt3c_info *info = link->priv;
 	int i;
 	unsigned long try;
 
@@ -724,7 +725,7 @@
 
 static void bt3c_release(struct pcmcia_device *link)
 {
-	bt3c_info_t *info = link->priv;
+	struct bt3c_info *info = link->priv;
 
 	bt3c_close(info);
 
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 3e683b1..550bce0 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -84,7 +84,27 @@
 	.int_read_to_clear = false,
 };
 
-static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
+static const struct btmrvl_sdio_card_reg btmrvl_reg_8887 = {
+	.cfg = 0x00,
+	.host_int_mask = 0x08,
+	.host_intstatus = 0x0C,
+	.card_status = 0x5C,
+	.sq_read_base_addr_a0 = 0x6C,
+	.sq_read_base_addr_a1 = 0x6D,
+	.card_revision = 0xC8,
+	.card_fw_status0 = 0x88,
+	.card_fw_status1 = 0x89,
+	.card_rx_len = 0x8A,
+	.card_rx_unit = 0x8B,
+	.io_port_0 = 0xE4,
+	.io_port_1 = 0xE5,
+	.io_port_2 = 0xE6,
+	.int_read_to_clear = true,
+	.host_int_rsr = 0x04,
+	.card_misc_cfg = 0xD8,
+};
+
+static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = {
 	.cfg = 0x00,
 	.host_int_mask = 0x02,
 	.host_intstatus = 0x03,
@@ -128,10 +148,18 @@
 	.sd_blksz_fw_dl	= 256,
 };
 
+static const struct btmrvl_sdio_device btmrvl_sdio_sd8887 = {
+	.helper		= NULL,
+	.firmware	= "mrvl/sd8887_uapsta.bin",
+	.reg		= &btmrvl_reg_8887,
+	.support_pscan_win_report = true,
+	.sd_blksz_fw_dl	= 256,
+};
+
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
 	.helper		= NULL,
 	.firmware	= "mrvl/sd8897_uapsta.bin",
-	.reg		= &btmrvl_reg_88xx,
+	.reg		= &btmrvl_reg_8897,
 	.support_pscan_win_report = true,
 	.sd_blksz_fw_dl	= 256,
 };
@@ -149,6 +177,9 @@
 	/* Marvell SD8797 Bluetooth device */
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
 			.driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
+	/* Marvell SD8887 Bluetooth device */
+	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9136),
+			.driver_data = (unsigned long)&btmrvl_sdio_sd8887 },
 	/* Marvell SD8897 Bluetooth device */
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
 			.driver_data = (unsigned long) &btmrvl_sdio_sd8897 },
@@ -1280,4 +1311,5 @@
 MODULE_FIRMWARE("mrvl/sd8688.bin");
 MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
+MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index fb948f0..abb4d21 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -62,7 +62,7 @@
 /* ======================== Local structures ======================== */
 
 
-typedef struct btuart_info_t {
+struct btuart_info {
 	struct pcmcia_device *p_dev;
 
 	struct hci_dev *hdev;
@@ -75,7 +75,7 @@
 	unsigned long rx_state;
 	unsigned long rx_count;
 	struct sk_buff *rx_skb;
-} btuart_info_t;
+};
 
 
 static int btuart_config(struct pcmcia_device *link);
@@ -127,7 +127,7 @@
 }
 
 
-static void btuart_write_wakeup(btuart_info_t *info)
+static void btuart_write_wakeup(struct btuart_info *info)
 {
 	if (!info) {
 		BT_ERR("Unknown device");
@@ -172,7 +172,7 @@
 }
 
 
-static void btuart_receive(btuart_info_t *info)
+static void btuart_receive(struct btuart_info *info)
 {
 	unsigned int iobase;
 	int boguscount = 0;
@@ -286,7 +286,7 @@
 
 static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
 {
-	btuart_info_t *info = dev_inst;
+	struct btuart_info *info = dev_inst;
 	unsigned int iobase;
 	int boguscount = 0;
 	int iir, lsr;
@@ -340,7 +340,8 @@
 }
 
 
-static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
+static void btuart_change_speed(struct btuart_info *info,
+				unsigned int speed)
 {
 	unsigned long flags;
 	unsigned int iobase;
@@ -397,7 +398,7 @@
 
 static int btuart_hci_flush(struct hci_dev *hdev)
 {
-	btuart_info_t *info = hci_get_drvdata(hdev);
+	struct btuart_info *info = hci_get_drvdata(hdev);
 
 	/* Drop TX queue */
 	skb_queue_purge(&(info->txq));
@@ -427,7 +428,7 @@
 
 static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	btuart_info_t *info = hci_get_drvdata(hdev);
+	struct btuart_info *info = hci_get_drvdata(hdev);
 
 	switch (bt_cb(skb)->pkt_type) {
 	case HCI_COMMAND_PKT:
@@ -455,7 +456,7 @@
 /* ======================== Card services HCI interaction ======================== */
 
 
-static int btuart_open(btuart_info_t *info)
+static int btuart_open(struct btuart_info *info)
 {
 	unsigned long flags;
 	unsigned int iobase = info->p_dev->resource[0]->start;
@@ -521,7 +522,7 @@
 }
 
 
-static int btuart_close(btuart_info_t *info)
+static int btuart_close(struct btuart_info *info)
 {
 	unsigned long flags;
 	unsigned int iobase = info->p_dev->resource[0]->start;
@@ -550,7 +551,7 @@
 
 static int btuart_probe(struct pcmcia_device *link)
 {
-	btuart_info_t *info;
+	struct btuart_info *info;
 
 	/* Create new info device */
 	info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
@@ -613,7 +614,7 @@
 
 static int btuart_config(struct pcmcia_device *link)
 {
-	btuart_info_t *info = link->priv;
+	struct btuart_info *info = link->priv;
 	int i;
 	int try;
 
@@ -654,7 +655,7 @@
 
 static void btuart_release(struct pcmcia_device *link)
 {
-	btuart_info_t *info = link->priv;
+	struct btuart_info *info = link->priv;
 
 	btuart_close(info);
 
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 3c94799..f9db709 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -165,6 +165,7 @@
 	{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
+	{ USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
 	{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
@@ -267,20 +268,24 @@
 	struct usb_interface *intf;
 	struct usb_interface *isoc;
 
-	spinlock_t lock;
-
 	unsigned long flags;
 
 	struct work_struct work;
 	struct work_struct waker;
 
+	struct usb_anchor deferred;
 	struct usb_anchor tx_anchor;
+	int tx_in_flight;
+	spinlock_t txlock;
+
 	struct usb_anchor intr_anchor;
 	struct usb_anchor bulk_anchor;
 	struct usb_anchor isoc_anchor;
-	struct usb_anchor deferred;
-	int tx_in_flight;
-	spinlock_t txlock;
+	spinlock_t rxlock;
+
+	struct sk_buff *evt_skb;
+	struct sk_buff *acl_skb;
+	struct sk_buff *sco_skb;
 
 	struct usb_endpoint_descriptor *intr_ep;
 	struct usb_endpoint_descriptor *bulk_tx_ep;
@@ -295,18 +300,189 @@
 	int suspend_count;
 };
 
-static int inc_tx(struct btusb_data *data)
+static inline void btusb_free_frags(struct btusb_data *data)
 {
 	unsigned long flags;
-	int rv;
 
-	spin_lock_irqsave(&data->txlock, flags);
-	rv = test_bit(BTUSB_SUSPENDING, &data->flags);
-	if (!rv)
-		data->tx_in_flight++;
-	spin_unlock_irqrestore(&data->txlock, flags);
+	spin_lock_irqsave(&data->rxlock, flags);
 
-	return rv;
+	kfree_skb(data->evt_skb);
+	data->evt_skb = NULL;
+
+	kfree_skb(data->acl_skb);
+	data->acl_skb = NULL;
+
+	kfree_skb(data->sco_skb);
+	data->sco_skb = NULL;
+
+	spin_unlock_irqrestore(&data->rxlock, flags);
+}
+
+static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
+{
+	struct sk_buff *skb;
+	int err = 0;
+
+	spin_lock(&data->rxlock);
+	skb = data->evt_skb;
+
+	while (count) {
+		int len;
+
+		if (!skb) {
+			skb = bt_skb_alloc(HCI_MAX_EVENT_SIZE, GFP_ATOMIC);
+			if (!skb) {
+				err = -ENOMEM;
+				break;
+			}
+
+			bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
+			bt_cb(skb)->expect = HCI_EVENT_HDR_SIZE;
+		}
+
+		len = min_t(uint, bt_cb(skb)->expect, count);
+		memcpy(skb_put(skb, len), buffer, len);
+
+		count -= len;
+		buffer += len;
+		bt_cb(skb)->expect -= len;
+
+		if (skb->len == HCI_EVENT_HDR_SIZE) {
+			/* Complete event header */
+			bt_cb(skb)->expect = hci_event_hdr(skb)->plen;
+
+			if (skb_tailroom(skb) < bt_cb(skb)->expect) {
+				kfree_skb(skb);
+				skb = NULL;
+
+				err = -EILSEQ;
+				break;
+			}
+		}
+
+		if (bt_cb(skb)->expect == 0) {
+			/* Complete frame */
+			hci_recv_frame(data->hdev, skb);
+			skb = NULL;
+		}
+	}
+
+	data->evt_skb = skb;
+	spin_unlock(&data->rxlock);
+
+	return err;
+}
+
+static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
+{
+	struct sk_buff *skb;
+	int err = 0;
+
+	spin_lock(&data->rxlock);
+	skb = data->acl_skb;
+
+	while (count) {
+		int len;
+
+		if (!skb) {
+			skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+			if (!skb) {
+				err = -ENOMEM;
+				break;
+			}
+
+			bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
+			bt_cb(skb)->expect = HCI_ACL_HDR_SIZE;
+		}
+
+		len = min_t(uint, bt_cb(skb)->expect, count);
+		memcpy(skb_put(skb, len), buffer, len);
+
+		count -= len;
+		buffer += len;
+		bt_cb(skb)->expect -= len;
+
+		if (skb->len == HCI_ACL_HDR_SIZE) {
+			__le16 dlen = hci_acl_hdr(skb)->dlen;
+
+			/* Complete ACL header */
+			bt_cb(skb)->expect = __le16_to_cpu(dlen);
+
+			if (skb_tailroom(skb) < bt_cb(skb)->expect) {
+				kfree_skb(skb);
+				skb = NULL;
+
+				err = -EILSEQ;
+				break;
+			}
+		}
+
+		if (bt_cb(skb)->expect == 0) {
+			/* Complete frame */
+			hci_recv_frame(data->hdev, skb);
+			skb = NULL;
+		}
+	}
+
+	data->acl_skb = skb;
+	spin_unlock(&data->rxlock);
+
+	return err;
+}
+
+static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
+{
+	struct sk_buff *skb;
+	int err = 0;
+
+	spin_lock(&data->rxlock);
+	skb = data->sco_skb;
+
+	while (count) {
+		int len;
+
+		if (!skb) {
+			skb = bt_skb_alloc(HCI_MAX_SCO_SIZE, GFP_ATOMIC);
+			if (!skb) {
+				err = -ENOMEM;
+				break;
+			}
+
+			bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
+			bt_cb(skb)->expect = HCI_SCO_HDR_SIZE;
+		}
+
+		len = min_t(uint, bt_cb(skb)->expect, count);
+		memcpy(skb_put(skb, len), buffer, len);
+
+		count -= len;
+		buffer += len;
+		bt_cb(skb)->expect -= len;
+
+		if (skb->len == HCI_SCO_HDR_SIZE) {
+			/* Complete SCO header */
+			bt_cb(skb)->expect = hci_sco_hdr(skb)->dlen;
+
+			if (skb_tailroom(skb) < bt_cb(skb)->expect) {
+				kfree_skb(skb);
+				skb = NULL;
+
+				err = -EILSEQ;
+				break;
+			}
+		}
+
+		if (bt_cb(skb)->expect == 0) {
+			/* Complete frame */
+			hci_recv_frame(data->hdev, skb);
+			skb = NULL;
+		}
+	}
+
+	data->sco_skb = skb;
+	spin_unlock(&data->rxlock);
+
+	return err;
 }
 
 static void btusb_intr_complete(struct urb *urb)
@@ -315,8 +491,8 @@
 	struct btusb_data *data = hci_get_drvdata(hdev);
 	int err;
 
-	BT_DBG("%s urb %p status %d count %d", hdev->name,
-					urb, urb->status, urb->actual_length);
+	BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
+	       urb->actual_length);
 
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return;
@@ -324,12 +500,14 @@
 	if (urb->status == 0) {
 		hdev->stat.byte_rx += urb->actual_length;
 
-		if (hci_recv_fragment(hdev, HCI_EVENT_PKT,
-						urb->transfer_buffer,
-						urb->actual_length) < 0) {
+		if (btusb_recv_intr(data, urb->transfer_buffer,
+				    urb->actual_length) < 0) {
 			BT_ERR("%s corrupted event packet", hdev->name);
 			hdev->stat.err_rx++;
 		}
+	} else if (urb->status == -ENOENT) {
+		/* Avoid suspend failed when usb_kill_urb */
+		return;
 	}
 
 	if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
@@ -344,7 +522,7 @@
 		 * -ENODEV: device got disconnected */
 		if (err != -EPERM && err != -ENODEV)
 			BT_ERR("%s urb %p failed to resubmit (%d)",
-						hdev->name, urb, -err);
+			       hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
 	}
 }
@@ -377,8 +555,7 @@
 	pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress);
 
 	usb_fill_int_urb(urb, data->udev, pipe, buf, size,
-						btusb_intr_complete, hdev,
-						data->intr_ep->bInterval);
+			 btusb_intr_complete, hdev, data->intr_ep->bInterval);
 
 	urb->transfer_flags |= URB_FREE_BUFFER;
 
@@ -388,7 +565,7 @@
 	if (err < 0) {
 		if (err != -EPERM && err != -ENODEV)
 			BT_ERR("%s urb %p submission failed (%d)",
-						hdev->name, urb, -err);
+			       hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
 	}
 
@@ -403,8 +580,8 @@
 	struct btusb_data *data = hci_get_drvdata(hdev);
 	int err;
 
-	BT_DBG("%s urb %p status %d count %d", hdev->name,
-					urb, urb->status, urb->actual_length);
+	BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
+	       urb->actual_length);
 
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return;
@@ -412,12 +589,14 @@
 	if (urb->status == 0) {
 		hdev->stat.byte_rx += urb->actual_length;
 
-		if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,
-						urb->transfer_buffer,
-						urb->actual_length) < 0) {
+		if (btusb_recv_bulk(data, urb->transfer_buffer,
+				    urb->actual_length) < 0) {
 			BT_ERR("%s corrupted ACL packet", hdev->name);
 			hdev->stat.err_rx++;
 		}
+	} else if (urb->status == -ENOENT) {
+		/* Avoid suspend failed when usb_kill_urb */
+		return;
 	}
 
 	if (!test_bit(BTUSB_BULK_RUNNING, &data->flags))
@@ -432,7 +611,7 @@
 		 * -ENODEV: device got disconnected */
 		if (err != -EPERM && err != -ENODEV)
 			BT_ERR("%s urb %p failed to resubmit (%d)",
-						hdev->name, urb, -err);
+			       hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
 	}
 }
@@ -462,8 +641,8 @@
 
 	pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
 
-	usb_fill_bulk_urb(urb, data->udev, pipe,
-					buf, size, btusb_bulk_complete, hdev);
+	usb_fill_bulk_urb(urb, data->udev, pipe, buf, size,
+			  btusb_bulk_complete, hdev);
 
 	urb->transfer_flags |= URB_FREE_BUFFER;
 
@@ -474,7 +653,7 @@
 	if (err < 0) {
 		if (err != -EPERM && err != -ENODEV)
 			BT_ERR("%s urb %p submission failed (%d)",
-						hdev->name, urb, -err);
+			       hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
 	}
 
@@ -489,8 +668,8 @@
 	struct btusb_data *data = hci_get_drvdata(hdev);
 	int i, err;
 
-	BT_DBG("%s urb %p status %d count %d", hdev->name,
-					urb, urb->status, urb->actual_length);
+	BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
+	       urb->actual_length);
 
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return;
@@ -505,13 +684,15 @@
 
 			hdev->stat.byte_rx += length;
 
-			if (hci_recv_fragment(hdev, HCI_SCODATA_PKT,
-						urb->transfer_buffer + offset,
-								length) < 0) {
+			if (btusb_recv_isoc(data, urb->transfer_buffer + offset,
+					    length) < 0) {
 				BT_ERR("%s corrupted SCO packet", hdev->name);
 				hdev->stat.err_rx++;
 			}
 		}
+	} else if (urb->status == -ENOENT) {
+		/* Avoid suspend failed when usb_kill_urb */
+		return;
 	}
 
 	if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags))
@@ -525,7 +706,7 @@
 		 * -ENODEV: device got disconnected */
 		if (err != -EPERM && err != -ENODEV)
 			BT_ERR("%s urb %p failed to resubmit (%d)",
-						hdev->name, urb, -err);
+			       hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
 	}
 }
@@ -580,12 +761,12 @@
 	pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress);
 
 	usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete,
-				hdev, data->isoc_rx_ep->bInterval);
+			 hdev, data->isoc_rx_ep->bInterval);
 
-	urb->transfer_flags  = URB_FREE_BUFFER | URB_ISO_ASAP;
+	urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
 
 	__fill_isoc_descriptor(urb, size,
-			le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));
+			       le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));
 
 	usb_anchor_urb(urb, &data->isoc_anchor);
 
@@ -593,7 +774,7 @@
 	if (err < 0) {
 		if (err != -EPERM && err != -ENODEV)
 			BT_ERR("%s urb %p submission failed (%d)",
-						hdev->name, urb, -err);
+			       hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
 	}
 
@@ -605,11 +786,11 @@
 static void btusb_tx_complete(struct urb *urb)
 {
 	struct sk_buff *skb = urb->context;
-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+	struct hci_dev *hdev = (struct hci_dev *)skb->dev;
 	struct btusb_data *data = hci_get_drvdata(hdev);
 
-	BT_DBG("%s urb %p status %d count %d", hdev->name,
-					urb, urb->status, urb->actual_length);
+	BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
+	       urb->actual_length);
 
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		goto done;
@@ -632,10 +813,10 @@
 static void btusb_isoc_tx_complete(struct urb *urb)
 {
 	struct sk_buff *skb = urb->context;
-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+	struct hci_dev *hdev = (struct hci_dev *)skb->dev;
 
-	BT_DBG("%s urb %p status %d count %d", hdev->name,
-					urb, urb->status, urb->actual_length);
+	BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
+	       urb->actual_length);
 
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		goto done;
@@ -719,6 +900,8 @@
 	clear_bit(BTUSB_INTR_RUNNING, &data->flags);
 
 	btusb_stop_traffic(data);
+	btusb_free_frags(data);
+
 	err = usb_autopm_get_interface(data->intf);
 	if (err < 0)
 		goto failed;
@@ -738,122 +921,181 @@
 	BT_DBG("%s", hdev->name);
 
 	usb_kill_anchored_urbs(&data->tx_anchor);
+	btusb_free_frags(data);
 
 	return 0;
 }
 
-static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
+static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct btusb_data *data = hci_get_drvdata(hdev);
 	struct usb_ctrlrequest *dr;
 	struct urb *urb;
 	unsigned int pipe;
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb)
+		return ERR_PTR(-ENOMEM);
+
+	dr = kmalloc(sizeof(*dr), GFP_KERNEL);
+	if (!dr) {
+		usb_free_urb(urb);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	dr->bRequestType = data->cmdreq_type;
+	dr->bRequest     = 0;
+	dr->wIndex       = 0;
+	dr->wValue       = 0;
+	dr->wLength      = __cpu_to_le16(skb->len);
+
+	pipe = usb_sndctrlpipe(data->udev, 0x00);
+
+	usb_fill_control_urb(urb, data->udev, pipe, (void *)dr,
+			     skb->data, skb->len, btusb_tx_complete, skb);
+
+	skb->dev = (void *)hdev;
+
+	return urb;
+}
+
+static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct btusb_data *data = hci_get_drvdata(hdev);
+	struct urb *urb;
+	unsigned int pipe;
+
+	if (!data->bulk_tx_ep)
+		return ERR_PTR(-ENODEV);
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb)
+		return ERR_PTR(-ENOMEM);
+
+	pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress);
+
+	usb_fill_bulk_urb(urb, data->udev, pipe,
+			  skb->data, skb->len, btusb_tx_complete, skb);
+
+	skb->dev = (void *)hdev;
+
+	return urb;
+}
+
+static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct btusb_data *data = hci_get_drvdata(hdev);
+	struct urb *urb;
+	unsigned int pipe;
+
+	if (!data->isoc_tx_ep)
+		return ERR_PTR(-ENODEV);
+
+	urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL);
+	if (!urb)
+		return ERR_PTR(-ENOMEM);
+
+	pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress);
+
+	usb_fill_int_urb(urb, data->udev, pipe,
+			 skb->data, skb->len, btusb_isoc_tx_complete,
+			 skb, data->isoc_tx_ep->bInterval);
+
+	urb->transfer_flags  = URB_ISO_ASAP;
+
+	__fill_isoc_descriptor(urb, skb->len,
+			       le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
+
+	skb->dev = (void *)hdev;
+
+	return urb;
+}
+
+static int submit_tx_urb(struct hci_dev *hdev, struct urb *urb)
+{
+	struct btusb_data *data = hci_get_drvdata(hdev);
 	int err;
 
-	BT_DBG("%s", hdev->name);
-
-	if (!test_bit(HCI_RUNNING, &hdev->flags))
-		return -EBUSY;
-
-	skb->dev = (void *) hdev;
-
-	switch (bt_cb(skb)->pkt_type) {
-	case HCI_COMMAND_PKT:
-		urb = usb_alloc_urb(0, GFP_ATOMIC);
-		if (!urb)
-			return -ENOMEM;
-
-		dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
-		if (!dr) {
-			usb_free_urb(urb);
-			return -ENOMEM;
-		}
-
-		dr->bRequestType = data->cmdreq_type;
-		dr->bRequest     = 0;
-		dr->wIndex       = 0;
-		dr->wValue       = 0;
-		dr->wLength      = __cpu_to_le16(skb->len);
-
-		pipe = usb_sndctrlpipe(data->udev, 0x00);
-
-		usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
-				skb->data, skb->len, btusb_tx_complete, skb);
-
-		hdev->stat.cmd_tx++;
-		break;
-
-	case HCI_ACLDATA_PKT:
-		if (!data->bulk_tx_ep)
-			return -ENODEV;
-
-		urb = usb_alloc_urb(0, GFP_ATOMIC);
-		if (!urb)
-			return -ENOMEM;
-
-		pipe = usb_sndbulkpipe(data->udev,
-					data->bulk_tx_ep->bEndpointAddress);
-
-		usb_fill_bulk_urb(urb, data->udev, pipe,
-				skb->data, skb->len, btusb_tx_complete, skb);
-
-		hdev->stat.acl_tx++;
-		break;
-
-	case HCI_SCODATA_PKT:
-		if (!data->isoc_tx_ep || hci_conn_num(hdev, SCO_LINK) < 1)
-			return -ENODEV;
-
-		urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC);
-		if (!urb)
-			return -ENOMEM;
-
-		pipe = usb_sndisocpipe(data->udev,
-					data->isoc_tx_ep->bEndpointAddress);
-
-		usb_fill_int_urb(urb, data->udev, pipe,
-				skb->data, skb->len, btusb_isoc_tx_complete,
-				skb, data->isoc_tx_ep->bInterval);
-
-		urb->transfer_flags  = URB_ISO_ASAP;
-
-		__fill_isoc_descriptor(urb, skb->len,
-				le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
-
-		hdev->stat.sco_tx++;
-		goto skip_waking;
-
-	default:
-		return -EILSEQ;
-	}
-
-	err = inc_tx(data);
-	if (err) {
-		usb_anchor_urb(urb, &data->deferred);
-		schedule_work(&data->waker);
-		err = 0;
-		goto done;
-	}
-
-skip_waking:
 	usb_anchor_urb(urb, &data->tx_anchor);
 
-	err = usb_submit_urb(urb, GFP_ATOMIC);
+	err = usb_submit_urb(urb, GFP_KERNEL);
 	if (err < 0) {
 		if (err != -EPERM && err != -ENODEV)
 			BT_ERR("%s urb %p submission failed (%d)",
-						hdev->name, urb, -err);
+			       hdev->name, urb, -err);
 		kfree(urb->setup_packet);
 		usb_unanchor_urb(urb);
 	} else {
 		usb_mark_last_busy(data->udev);
 	}
 
-done:
 	usb_free_urb(urb);
 	return err;
 }
 
+static int submit_or_queue_tx_urb(struct hci_dev *hdev, struct urb *urb)
+{
+	struct btusb_data *data = hci_get_drvdata(hdev);
+	unsigned long flags;
+	bool suspending;
+
+	spin_lock_irqsave(&data->txlock, flags);
+	suspending = test_bit(BTUSB_SUSPENDING, &data->flags);
+	if (!suspending)
+		data->tx_in_flight++;
+	spin_unlock_irqrestore(&data->txlock, flags);
+
+	if (!suspending)
+		return submit_tx_urb(hdev, urb);
+
+	usb_anchor_urb(urb, &data->deferred);
+	schedule_work(&data->waker);
+
+	usb_free_urb(urb);
+	return 0;
+}
+
+static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct urb *urb;
+
+	BT_DBG("%s", hdev->name);
+
+	if (!test_bit(HCI_RUNNING, &hdev->flags))
+		return -EBUSY;
+
+	switch (bt_cb(skb)->pkt_type) {
+	case HCI_COMMAND_PKT:
+		urb = alloc_ctrl_urb(hdev, skb);
+		if (IS_ERR(urb))
+			return PTR_ERR(urb);
+
+		hdev->stat.cmd_tx++;
+		return submit_or_queue_tx_urb(hdev, urb);
+
+	case HCI_ACLDATA_PKT:
+		urb = alloc_bulk_urb(hdev, skb);
+		if (IS_ERR(urb))
+			return PTR_ERR(urb);
+
+		hdev->stat.acl_tx++;
+		return submit_or_queue_tx_urb(hdev, urb);
+
+	case HCI_SCODATA_PKT:
+		if (hci_conn_num(hdev, SCO_LINK) < 1)
+			return -ENODEV;
+
+		urb = alloc_isoc_urb(hdev, skb);
+		if (IS_ERR(urb))
+			return PTR_ERR(urb);
+
+		hdev->stat.sco_tx++;
+		return submit_tx_urb(hdev, urb);
+	}
+
+	return -EILSEQ;
+}
+
 static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
 {
 	struct btusb_data *data = hci_get_drvdata(hdev);
@@ -930,6 +1172,7 @@
 
 		if (hdev->voice_setting & 0x0020) {
 			static const int alts[3] = { 2, 4, 5 };
+
 			new_alts = alts[data->sco_num - 1];
 		} else {
 			new_alts = data->sco_num;
@@ -1002,7 +1245,7 @@
 		return -PTR_ERR(skb);
 	}
 
-	rp = (struct hci_rp_read_local_version *) skb->data;
+	rp = (struct hci_rp_read_local_version *)skb->data;
 
 	if (!rp->status) {
 		if (le16_to_cpu(rp->manufacturer) != 10) {
@@ -1040,7 +1283,7 @@
 } __packed;
 
 static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev,
-						struct intel_version *ver)
+						       struct intel_version *ver)
 {
 	const struct firmware *fw;
 	char fwname[64];
@@ -1216,7 +1459,7 @@
 		return -EIO;
 	}
 
-	rp = (struct hci_rp_read_bd_addr *) skb->data;
+	rp = (struct hci_rp_read_bd_addr *)skb->data;
 	if (rp->status) {
 		BT_ERR("%s Intel device address result failed (%02x)",
 		       hdev->name, rp->status);
@@ -1346,6 +1589,7 @@
 
 	if (skb->data[0]) {
 		u8 evt_status = skb->data[0];
+
 		BT_ERR("%s enable Intel manufacturer mode event failed (%02x)",
 		       hdev->name, evt_status);
 		kfree_skb(skb);
@@ -1455,7 +1699,7 @@
 	if (IS_ERR(skb)) {
 		ret = PTR_ERR(skb);
 		BT_ERR("%s: changing Intel device address failed (%ld)",
-			hdev->name, ret);
+		       hdev->name, ret);
 		return ret;
 	}
 	kfree_skb(skb);
@@ -1530,19 +1774,19 @@
 	if (IS_ERR(skb)) {
 		ret = PTR_ERR(skb);
 		BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
-			hdev->name, ret);
+		       hdev->name, ret);
 		goto done;
 	}
 
 	if (skb->len != sizeof(*ver)) {
 		BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
-			hdev->name);
+		       hdev->name);
 		kfree_skb(skb);
 		ret = -EIO;
 		goto done;
 	}
 
-	ver = (struct hci_rp_read_local_version *) skb->data;
+	ver = (struct hci_rp_read_local_version *)skb->data;
 	BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
 		"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
 		ver->lmp_ver, ver->lmp_subver);
@@ -1553,7 +1797,7 @@
 	if (IS_ERR(skb)) {
 		ret = PTR_ERR(skb);
 		BT_ERR("%s: BCM: Download Minidrv command failed (%ld)",
-			hdev->name, ret);
+		       hdev->name, ret);
 		goto reset_fw;
 	}
 	kfree_skb(skb);
@@ -1565,13 +1809,13 @@
 	fw_size = fw->size;
 
 	while (fw_size >= sizeof(*cmd)) {
-		cmd = (struct hci_command_hdr *) fw_ptr;
+		cmd = (struct hci_command_hdr *)fw_ptr;
 		fw_ptr += sizeof(*cmd);
 		fw_size -= sizeof(*cmd);
 
 		if (fw_size < cmd->plen) {
 			BT_ERR("%s: BCM: patch %s is corrupted",
-				hdev->name, fw_name);
+			       hdev->name, fw_name);
 			ret = -EINVAL;
 			goto reset_fw;
 		}
@@ -1587,7 +1831,7 @@
 		if (IS_ERR(skb)) {
 			ret = PTR_ERR(skb);
 			BT_ERR("%s: BCM: patch command %04x failed (%ld)",
-				hdev->name, opcode, ret);
+			       hdev->name, opcode, ret);
 			goto reset_fw;
 		}
 		kfree_skb(skb);
@@ -1612,19 +1856,19 @@
 	if (IS_ERR(skb)) {
 		ret = PTR_ERR(skb);
 		BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
-			hdev->name, ret);
+		       hdev->name, ret);
 		goto done;
 	}
 
 	if (skb->len != sizeof(*ver)) {
 		BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
-			hdev->name);
+		       hdev->name);
 		kfree_skb(skb);
 		ret = -EIO;
 		goto done;
 	}
 
-	ver = (struct hci_rp_read_local_version *) skb->data;
+	ver = (struct hci_rp_read_local_version *)skb->data;
 	BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
 		"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
 		ver->lmp_ver, ver->lmp_subver);
@@ -1636,19 +1880,19 @@
 	if (IS_ERR(skb)) {
 		ret = PTR_ERR(skb);
 		BT_ERR("%s: HCI_OP_READ_BD_ADDR failed (%ld)",
-			hdev->name, ret);
+		       hdev->name, ret);
 		goto done;
 	}
 
 	if (skb->len != sizeof(*bda)) {
 		BT_ERR("%s: HCI_OP_READ_BD_ADDR event length mismatch",
-			hdev->name);
+		       hdev->name);
 		kfree_skb(skb);
 		ret = -EIO;
 		goto done;
 	}
 
-	bda = (struct hci_rp_read_bd_addr *) skb->data;
+	bda = (struct hci_rp_read_bd_addr *)skb->data;
 	if (bda->status) {
 		BT_ERR("%s: HCI_OP_READ_BD_ADDR error status (%02x)",
 		       hdev->name, bda->status);
@@ -1683,7 +1927,7 @@
 	if (IS_ERR(skb)) {
 		ret = PTR_ERR(skb);
 		BT_ERR("%s: BCM: Change address command failed (%ld)",
-			hdev->name, ret);
+		       hdev->name, ret);
 		return ret;
 	}
 	kfree_skb(skb);
@@ -1692,7 +1936,7 @@
 }
 
 static int btusb_probe(struct usb_interface *intf,
-				const struct usb_device_id *id)
+		       const struct usb_device_id *id)
 {
 	struct usb_endpoint_descriptor *ep_desc;
 	struct btusb_data *data;
@@ -1707,6 +1951,7 @@
 
 	if (!id->driver_info) {
 		const struct usb_device_id *match;
+
 		match = usb_match_id(intf, blacklist_table);
 		if (match)
 			id = match;
@@ -1755,17 +2000,16 @@
 	data->udev = interface_to_usbdev(intf);
 	data->intf = intf;
 
-	spin_lock_init(&data->lock);
-
 	INIT_WORK(&data->work, btusb_work);
 	INIT_WORK(&data->waker, btusb_waker);
+	init_usb_anchor(&data->deferred);
+	init_usb_anchor(&data->tx_anchor);
 	spin_lock_init(&data->txlock);
 
-	init_usb_anchor(&data->tx_anchor);
 	init_usb_anchor(&data->intr_anchor);
 	init_usb_anchor(&data->bulk_anchor);
 	init_usb_anchor(&data->isoc_anchor);
-	init_usb_anchor(&data->deferred);
+	spin_lock_init(&data->rxlock);
 
 	hdev = hci_alloc_dev();
 	if (!hdev)
@@ -1857,7 +2101,7 @@
 
 	if (data->isoc) {
 		err = usb_driver_claim_interface(&btusb_driver,
-							data->isoc, data);
+						 data->isoc, data);
 		if (err < 0) {
 			hci_free_dev(hdev);
 			return err;
@@ -1898,6 +2142,7 @@
 	else if (data->isoc)
 		usb_driver_release_interface(&btusb_driver, data->isoc);
 
+	btusb_free_frags(data);
 	hci_free_dev(hdev);
 }
 
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 2bd8fad..78e10f0 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -62,7 +62,7 @@
 /* ======================== Local structures ======================== */
 
 
-typedef struct dtl1_info_t {
+struct dtl1_info {
 	struct pcmcia_device *p_dev;
 
 	struct hci_dev *hdev;
@@ -78,7 +78,7 @@
 	unsigned long rx_state;
 	unsigned long rx_count;
 	struct sk_buff *rx_skb;
-} dtl1_info_t;
+};
 
 
 static int dtl1_config(struct pcmcia_device *link);
@@ -94,11 +94,11 @@
 #define RECV_WAIT_DATA  1
 
 
-typedef struct {
+struct nsh {
 	u8 type;
 	u8 zero;
 	u16 len;
-} __packed nsh_t;	/* Nokia Specific Header */
+} __packed;	/* Nokia Specific Header */
 
 #define NSHL  4				/* Nokia Specific Header Length */
 
@@ -126,7 +126,7 @@
 }
 
 
-static void dtl1_write_wakeup(dtl1_info_t *info)
+static void dtl1_write_wakeup(struct dtl1_info *info)
 {
 	if (!info) {
 		BT_ERR("Unknown device");
@@ -176,7 +176,7 @@
 }
 
 
-static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
+static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb)
 {
 	u8 flowmask = *(u8 *)skb->data;
 	int i;
@@ -199,10 +199,10 @@
 }
 
 
-static void dtl1_receive(dtl1_info_t *info)
+static void dtl1_receive(struct dtl1_info *info)
 {
 	unsigned int iobase;
-	nsh_t *nsh;
+	struct nsh *nsh;
 	int boguscount = 0;
 
 	if (!info) {
@@ -227,7 +227,7 @@
 		}
 
 		*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
-		nsh = (nsh_t *)info->rx_skb->data;
+		nsh = (struct nsh *)info->rx_skb->data;
 
 		info->rx_count--;
 
@@ -287,7 +287,7 @@
 
 static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
 {
-	dtl1_info_t *info = dev_inst;
+	struct dtl1_info *info = dev_inst;
 	unsigned int iobase;
 	unsigned char msr;
 	int boguscount = 0;
@@ -365,7 +365,7 @@
 
 static int dtl1_hci_flush(struct hci_dev *hdev)
 {
-	dtl1_info_t *info = hci_get_drvdata(hdev);
+	struct dtl1_info *info = hci_get_drvdata(hdev);
 
 	/* Drop TX queue */
 	skb_queue_purge(&(info->txq));
@@ -387,9 +387,9 @@
 
 static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	dtl1_info_t *info = hci_get_drvdata(hdev);
+	struct dtl1_info *info = hci_get_drvdata(hdev);
 	struct sk_buff *s;
-	nsh_t nsh;
+	struct nsh nsh;
 
 	switch (bt_cb(skb)->pkt_type) {
 	case HCI_COMMAND_PKT:
@@ -436,7 +436,7 @@
 /* ======================== Card services HCI interaction ======================== */
 
 
-static int dtl1_open(dtl1_info_t *info)
+static int dtl1_open(struct dtl1_info *info)
 {
 	unsigned long flags;
 	unsigned int iobase = info->p_dev->resource[0]->start;
@@ -505,7 +505,7 @@
 }
 
 
-static int dtl1_close(dtl1_info_t *info)
+static int dtl1_close(struct dtl1_info *info)
 {
 	unsigned long flags;
 	unsigned int iobase = info->p_dev->resource[0]->start;
@@ -534,7 +534,7 @@
 
 static int dtl1_probe(struct pcmcia_device *link)
 {
-	dtl1_info_t *info;
+	struct dtl1_info *info;
 
 	/* Create new info device */
 	info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
@@ -552,7 +552,7 @@
 
 static void dtl1_detach(struct pcmcia_device *link)
 {
-	dtl1_info_t *info = link->priv;
+	struct dtl1_info *info = link->priv;
 
 	dtl1_close(info);
 	pcmcia_disable_device(link);
@@ -571,7 +571,7 @@
 
 static int dtl1_config(struct pcmcia_device *link)
 {
-	dtl1_info_t *info = link->priv;
+	struct dtl1_info *info = link->priv;
 	int ret;
 
 	/* Look for a generic full-sized window */
diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c
index caacb42..a228386 100644
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -237,7 +237,7 @@
 			break;
 
 		to_remove--;
-		seq = (seq - 1) % 8;
+		seq = (seq - 1) & 0x07;
 	}
 
 	if (seq != h5->rx_ack)
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 5bb5872..3c34c5c 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -159,6 +159,15 @@
 	return 0;
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)
+static inline ssize_t vhci_get_user(struct vhci_data *data,
+				    struct iov_iter *from)
+{
+	size_t len = iov_iter_count(from);
+	struct sk_buff *skb;
+	__u8 pkt_type, opcode;
+	int ret;
+#else
 static inline ssize_t vhci_get_user(struct vhci_data *data,
 				    const struct iovec *iov,
 				    unsigned long count)
@@ -168,6 +177,7 @@
 	__u8 pkt_type, opcode;
 	unsigned long i;
 	int ret;
+#endif
 
 	if (len < 2 || len > HCI_MAX_FRAME_SIZE)
 		return -EINVAL;
@@ -176,6 +186,12 @@
 	if (!skb)
 		return -ENOMEM;
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)
+	if (copy_from_iter(skb_put(skb, len), len, from) != len) {
+		kfree_skb(skb);
+		return -EFAULT;
+	}
+#else
 	for (i = 0; i < count; i++) {
 		if (copy_from_user(skb_put(skb, iov[i].iov_len),
 				   iov[i].iov_base, iov[i].iov_len)) {
@@ -183,6 +199,7 @@
 			return -EFAULT;
 		}
 	}
+#endif
 
 	pkt_type = *((__u8 *) skb->data);
 	skb_pull(skb, 1);
@@ -294,13 +311,21 @@
 	return ret;
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)
+static ssize_t vhci_write(struct kiocb *iocb, struct iov_iter *from)
+#else
 static ssize_t vhci_write(struct kiocb *iocb, const struct iovec *iov,
 			  unsigned long count, loff_t pos)
+#endif
 {
 	struct file *file = iocb->ki_filp;
 	struct vhci_data *data = file->private_data;
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)
+	return vhci_get_user(data, from);
+#else
 	return vhci_get_user(data, iov, count);
+#endif
 }
 
 static unsigned int vhci_poll(struct file *file, poll_table *wait)
@@ -365,7 +390,11 @@
 static const struct file_operations vhci_fops = {
 	.owner		= THIS_MODULE,
 	.read		= vhci_read,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)
+	.write_iter	= vhci_write,
+#else
 	.aio_write	= vhci_write,
+#endif
 	.poll		= vhci_poll,
 	.open		= vhci_open,
 	.release	= vhci_release,
diff --git a/drivers/media/common/b2c2/flexcop.h b/drivers/media/common/b2c2/flexcop.h
index b6d5925..7494089 100644
--- a/drivers/media/common/b2c2/flexcop.h
+++ b/drivers/media/common/b2c2/flexcop.h
@@ -4,7 +4,7 @@
  * see flexcop.c for copyright information
  */
 #ifndef __FLEXCOP_H__
-#define __FLEXCOP_H___
+#define __FLEXCOP_H__
 
 #define FC_LOG_PREFIX "b2c2-flexcop"
 #include "flexcop-common.h"
diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
index 6c47f3f..b7d6393 100644
--- a/drivers/media/common/saa7146/saa7146_fops.c
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -311,7 +311,6 @@
 		}
 	default:
 		BUG();
-		return 0;
 	}
 
 	if (mutex_lock_interruptible(vdev->lock))
@@ -399,7 +398,6 @@
 		return -EINVAL;
 	default:
 		BUG();
-		return 0;
 	}
 }
 
@@ -423,7 +421,6 @@
 		return -EINVAL;
 	default:
 		BUG();
-		return -EINVAL;
 	}
 }
 
diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c
index 8276999..82c7a12 100644
--- a/drivers/media/common/siano/sms-cards.c
+++ b/drivers/media/common/siano/sms-cards.c
@@ -157,6 +157,12 @@
 		.type = SMS_DENVER_2160,
 		.default_mode = DEVICE_MODE_DAB_TDMB,
 	},
+	[SMS1XXX_BOARD_PCTV_77E] = {
+		.name	= "Hauppauge microStick 77e",
+		.type	= SMS_NOVA_B0,
+		.fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ_B0,
+		.default_mode = DEVICE_MODE_DVBT_BDA,
+	},
 };
 
 struct sms_board *sms_get_board(unsigned id)
diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h
index c63b544..4c4cadd 100644
--- a/drivers/media/common/siano/sms-cards.h
+++ b/drivers/media/common/siano/sms-cards.h
@@ -45,6 +45,7 @@
 #define SMS1XXX_BOARD_SIANO_RIO		18
 #define SMS1XXX_BOARD_SIANO_DENVER_1530	19
 #define SMS1XXX_BOARD_SIANO_DENVER_2160 20
+#define SMS1XXX_BOARD_PCTV_77E		21
 
 struct sms_board_gpio_cfg {
 	int lna_vhf_exist;
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
index 050984c..a367743 100644
--- a/drivers/media/common/siano/smscoreapi.c
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -2129,8 +2129,6 @@
 
 static int __init smscore_module_init(void)
 {
-	int rc = 0;
-
 	INIT_LIST_HEAD(&g_smscore_notifyees);
 	INIT_LIST_HEAD(&g_smscore_devices);
 	kmutex_init(&g_smscore_deviceslock);
@@ -2138,7 +2136,7 @@
 	INIT_LIST_HEAD(&g_smscore_registry);
 	kmutex_init(&g_smscore_registrylock);
 
-	return rc;
+	return 0;
 }
 
 static void __exit smscore_module_exit(void)
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index c0363f1..abff803 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -1087,8 +1087,8 @@
 	struct dmxdev_filter *dmxdevfilter = file->private_data;
 	unsigned int mask = 0;
 
-	if (!dmxdevfilter)
-		return -EINVAL;
+	if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
+		return POLLERR;
 
 	poll_wait(file, &dmxdevfilter->buffer.queue, wait);
 
@@ -1181,6 +1181,9 @@
 
 	dprintk("function : %s\n", __func__);
 
+	if (dmxdev->exit)
+		return POLLERR;
+
 	poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
 
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 12ce19c..e07a84e 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -144,6 +144,7 @@
 #define USB_PID_ITETECH_IT9135				0x9135
 #define USB_PID_ITETECH_IT9135_9005			0x9005
 #define USB_PID_ITETECH_IT9135_9006			0x9006
+#define USB_PID_ITETECH_IT9303				0x9306
 #define USB_PID_KWORLD_399U				0xe399
 #define USB_PID_KWORLD_399U_2				0xe400
 #define USB_PID_KWORLD_395U				0xe396
@@ -244,6 +245,7 @@
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM	0x3009
 #define USB_PID_TECHNOTREND_CONNECT_CT3650		0x300d
+#define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI		0x3012
 #define USB_PID_TECHNOTREND_TVSTICK_CT2_4400		0x3014
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2	0x0081
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index eb8ef6c..7e9b079 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -1934,15 +1934,13 @@
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int err = 0;
 
-	struct dtv_properties *tvps = NULL;
+	struct dtv_properties *tvps = parg;
 	struct dtv_property *tvp = NULL;
 	int i;
 
 	dev_dbg(fe->dvb->device, "%s:\n", __func__);
 
-	if(cmd == FE_SET_PROPERTY) {
-		tvps = (struct dtv_properties __user *)parg;
-
+	if (cmd == FE_SET_PROPERTY) {
 		dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
 		dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
 
@@ -1957,7 +1955,8 @@
 			goto out;
 		}
 
-		if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+		if (copy_from_user(tvp, (void __user *)tvps->props,
+				   tvps->num * sizeof(struct dtv_property))) {
 			err = -EFAULT;
 			goto out;
 		}
@@ -1972,10 +1971,7 @@
 		if (c->state == DTV_TUNE)
 			dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__);
 
-	} else
-	if(cmd == FE_GET_PROPERTY) {
-		tvps = (struct dtv_properties __user *)parg;
-
+	} else if (cmd == FE_GET_PROPERTY) {
 		dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
 		dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
 
@@ -1990,7 +1986,8 @@
 			goto out;
 		}
 
-		if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+		if (copy_from_user(tvp, (void __user *)tvps->props,
+				   tvps->num * sizeof(struct dtv_property))) {
 			err = -EFAULT;
 			goto out;
 		}
@@ -2012,7 +2009,8 @@
 			(tvp + i)->result = err;
 		}
 
-		if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+		if (copy_to_user((void __user *)tvps->props, tvp,
+				 tvps->num * sizeof(struct dtv_property))) {
 			err = -EFAULT;
 			goto out;
 		}
@@ -2072,6 +2070,23 @@
 	case SYS_DVBC_ANNEX_C:
 		rolloff = 113;
 		break;
+	case SYS_DVBS:
+	case SYS_TURBO:
+		rolloff = 135;
+		break;
+	case SYS_DVBS2:
+		switch (c->rolloff) {
+		case ROLLOFF_20:
+			rolloff = 120;
+			break;
+		case ROLLOFF_25:
+			rolloff = 125;
+			break;
+		default:
+		case ROLLOFF_35:
+			rolloff = 135;
+		}
+		break;
 	default:
 		break;
 	}
@@ -2550,7 +2565,9 @@
 	dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
 			fe->id);
 
-	if (fe->ops.tuner_ops.sleep)
+	if (fe->ops.tuner_ops.suspend)
+		ret = fe->ops.tuner_ops.suspend(fe);
+	else if (fe->ops.tuner_ops.sleep)
 		ret = fe->ops.tuner_ops.sleep(fe);
 
 	if (fe->ops.sleep)
@@ -2572,7 +2589,9 @@
 	if (fe->ops.init)
 		ret = fe->ops.init(fe);
 
-	if (fe->ops.tuner_ops.init)
+	if (fe->ops.tuner_ops.resume)
+		ret = fe->ops.tuner_ops.resume(fe);
+	else if (fe->ops.tuner_ops.init)
 		ret = fe->ops.tuner_ops.init(fe);
 
 	fe->exit = DVB_FE_NO_EXIT;
diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
index d398de4..816269e 100644
--- a/drivers/media/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb-core/dvb_frontend.h
@@ -201,6 +201,8 @@
 	int (*release)(struct dvb_frontend *fe);
 	int (*init)(struct dvb_frontend *fe);
 	int (*sleep)(struct dvb_frontend *fe);
+	int (*suspend)(struct dvb_frontend *fe);
+	int (*resume)(struct dvb_frontend *fe);
 
 	/** This is for simple PLLs - set all parameters in one go. */
 	int (*set_params)(struct dvb_frontend *fe);
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c
index a5712cd..1100e98 100644
--- a/drivers/media/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb-core/dvb_ringbuffer.c
@@ -166,6 +166,31 @@
 	return len;
 }
 
+ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
+				  const u8 __user *buf, size_t len)
+{
+	int status;
+	size_t todo = len;
+	size_t split;
+
+	split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
+
+	if (split > 0) {
+		status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split);
+		if (status)
+			return len - todo;
+		buf += split;
+		todo -= split;
+		rbuf->pwrite = 0;
+	}
+	status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo);
+	if (status)
+		return len - todo;
+	rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
+
+	return len;
+}
+
 ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
 {
 	int status;
@@ -297,3 +322,4 @@
 EXPORT_SYMBOL(dvb_ringbuffer_read_user);
 EXPORT_SYMBOL(dvb_ringbuffer_read);
 EXPORT_SYMBOL(dvb_ringbuffer_write);
+EXPORT_SYMBOL(dvb_ringbuffer_write_user);
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb-core/dvb_ringbuffer.h
index 41f04da..9e1e11b 100644
--- a/drivers/media/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb-core/dvb_ringbuffer.h
@@ -133,6 +133,8 @@
 */
 extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
 				    size_t len);
+extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
+				         const u8 __user *buf, size_t len);
 
 
 /**
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index ee0c57a..8971120 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -531,6 +531,12 @@
 	help
 	  Say Y when you want to support this frontend.
 
+config DVB_AS102_FE
+	tristate
+	depends on m
+	depends on DVB_CORE
+	default DVB_AS102
+
 comment "DVB-C (cable) frontends"
 	depends on DVB_CORE
 
@@ -722,6 +728,15 @@
 	  A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
 	  Say Y when you want to support this frontend.
 
+config DVB_TC90522
+	tristate "Toshiba TC90522"
+	depends on m
+	depends on DVB_CORE && I2C
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  A Toshiba TC90522 2xISDB-T + 2xISDB-S demodulator.
+	  Say Y when you want to support this frontend.
+
 comment "Digital terrestrial only tuners/PLL"
 	depends on DVB_CORE
 
@@ -808,6 +823,14 @@
 	depends on DVB_CORE && I2C
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 
+config DVB_SP2
+	tristate "CIMaX SP2"
+	depends on m
+	depends on DVB_CORE && I2C
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  CIMaX SP2/SP2HF Common Interface module.
+
 config DVB_LGS8GL5
 	tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
 	depends on m
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 03f691e..1b93c47 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -107,10 +107,12 @@
 obj-$(CPTCFG_DVB_TDA18271C2DD) += tda18271c2dd.o
 obj-$(CPTCFG_DVB_SI2165) += si2165.o
 obj-$(CPTCFG_DVB_A8293) += a8293.o
+obj-$(CPTCFG_DVB_SP2) += sp2.o
 obj-$(CPTCFG_DVB_TDA10071) += tda10071.o
 obj-$(CPTCFG_DVB_RTL2830) += rtl2830.o
 obj-$(CPTCFG_DVB_RTL2832) += rtl2832.o
 obj-$(CPTCFG_DVB_RTL2832_SDR) += rtl2832_sdr.o
 obj-$(CPTCFG_DVB_M88RS2000) += m88rs2000.o
 obj-$(CPTCFG_DVB_AF9033) += af9033.o
-
+obj-$(CPTCFG_DVB_AS102_FE) += as102_fe.o
+obj-$(CPTCFG_DVB_TC90522) += tc90522.o
diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c
index ecf6388..8001690 100644
--- a/drivers/media/dvb-frontends/af9013.c
+++ b/drivers/media/dvb-frontends/af9013.c
@@ -683,7 +683,7 @@
 
 	switch (c->transmission_mode) {
 	case TRANSMISSION_MODE_AUTO:
-		auto_mode = 1;
+		auto_mode = true;
 		break;
 	case TRANSMISSION_MODE_2K:
 		break;
@@ -693,12 +693,12 @@
 	default:
 		dev_dbg(&state->i2c->dev, "%s: invalid transmission_mode\n",
 				__func__);
-		auto_mode = 1;
+		auto_mode = true;
 	}
 
 	switch (c->guard_interval) {
 	case GUARD_INTERVAL_AUTO:
-		auto_mode = 1;
+		auto_mode = true;
 		break;
 	case GUARD_INTERVAL_1_32:
 		break;
@@ -714,12 +714,12 @@
 	default:
 		dev_dbg(&state->i2c->dev, "%s: invalid guard_interval\n",
 				__func__);
-		auto_mode = 1;
+		auto_mode = true;
 	}
 
 	switch (c->hierarchy) {
 	case HIERARCHY_AUTO:
-		auto_mode = 1;
+		auto_mode = true;
 		break;
 	case HIERARCHY_NONE:
 		break;
@@ -734,12 +734,12 @@
 		break;
 	default:
 		dev_dbg(&state->i2c->dev, "%s: invalid hierarchy\n", __func__);
-		auto_mode = 1;
+		auto_mode = true;
 	}
 
 	switch (c->modulation) {
 	case QAM_AUTO:
-		auto_mode = 1;
+		auto_mode = true;
 		break;
 	case QPSK:
 		break;
@@ -751,7 +751,7 @@
 		break;
 	default:
 		dev_dbg(&state->i2c->dev, "%s: invalid modulation\n", __func__);
-		auto_mode = 1;
+		auto_mode = true;
 	}
 
 	/* Use HP. How and which case we can switch to LP? */
@@ -759,7 +759,7 @@
 
 	switch (c->code_rate_HP) {
 	case FEC_AUTO:
-		auto_mode = 1;
+		auto_mode = true;
 		break;
 	case FEC_1_2:
 		break;
@@ -778,12 +778,12 @@
 	default:
 		dev_dbg(&state->i2c->dev, "%s: invalid code_rate_HP\n",
 				__func__);
-		auto_mode = 1;
+		auto_mode = true;
 	}
 
 	switch (c->code_rate_LP) {
 	case FEC_AUTO:
-		auto_mode = 1;
+		auto_mode = true;
 		break;
 	case FEC_1_2:
 		break;
@@ -804,7 +804,7 @@
 	default:
 		dev_dbg(&state->i2c->dev, "%s: invalid code_rate_LP\n",
 				__func__);
-		auto_mode = 1;
+		auto_mode = true;
 	}
 
 	switch (c->bandwidth_hz) {
diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c
index 5c90ea6..63a89c1 100644
--- a/drivers/media/dvb-frontends/af9033.c
+++ b/drivers/media/dvb-frontends/af9033.c
@@ -24,29 +24,35 @@
 /* Max transfer size done by I2C transfer functions */
 #define MAX_XFER_SIZE  64
 
-struct af9033_state {
-	struct i2c_adapter *i2c;
+struct af9033_dev {
+	struct i2c_client *client;
 	struct dvb_frontend fe;
 	struct af9033_config cfg;
+	bool is_af9035;
+	bool is_it9135;
 
 	u32 bandwidth_hz;
 	bool ts_mode_parallel;
 	bool ts_mode_serial;
 
-	u32 ber;
-	u32 ucb;
-	unsigned long last_stat_check;
+	fe_status_t fe_status;
+	u64 post_bit_error_prev; /* for old read_ber we return (curr - prev) */
+	u64 post_bit_error;
+	u64 post_bit_count;
+	u64 error_block_count;
+	u64 total_block_count;
+	struct delayed_work stat_work;
 };
 
 /* write multiple registers */
-static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
+static int af9033_wr_regs(struct af9033_dev *dev, u32 reg, const u8 *val,
 		int len)
 {
 	int ret;
 	u8 buf[MAX_XFER_SIZE];
 	struct i2c_msg msg[1] = {
 		{
-			.addr = state->cfg.i2c_addr,
+			.addr = dev->client->addr,
 			.flags = 0,
 			.len = 3 + len,
 			.buf = buf,
@@ -54,9 +60,9 @@
 	};
 
 	if (3 + len > sizeof(buf)) {
-		dev_warn(&state->i2c->dev,
-			 "%s: i2c wr reg=%04x: len=%d is too big!\n",
-			 KBUILD_MODNAME, reg, len);
+		dev_warn(&dev->client->dev,
+				"i2c wr reg=%04x: len=%d is too big!\n",
+				reg, len);
 		return -EINVAL;
 	}
 
@@ -65,12 +71,12 @@
 	buf[2] = (reg >>  0) & 0xff;
 	memcpy(&buf[3], val, len);
 
-	ret = i2c_transfer(state->i2c, msg, 1);
+	ret = i2c_transfer(dev->client->adapter, msg, 1);
 	if (ret == 1) {
 		ret = 0;
 	} else {
-		dev_warn(&state->i2c->dev, "%s: i2c wr failed=%d reg=%06x " \
-				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
+		dev_warn(&dev->client->dev, "i2c wr failed=%d reg=%06x len=%d\n",
+				ret, reg, len);
 		ret = -EREMOTEIO;
 	}
 
@@ -78,31 +84,31 @@
 }
 
 /* read multiple registers */
-static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len)
+static int af9033_rd_regs(struct af9033_dev *dev, u32 reg, u8 *val, int len)
 {
 	int ret;
 	u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff,
 			(reg >> 0) & 0xff };
 	struct i2c_msg msg[2] = {
 		{
-			.addr = state->cfg.i2c_addr,
+			.addr = dev->client->addr,
 			.flags = 0,
 			.len = sizeof(buf),
 			.buf = buf
 		}, {
-			.addr = state->cfg.i2c_addr,
+			.addr = dev->client->addr,
 			.flags = I2C_M_RD,
 			.len = len,
 			.buf = val
 		}
 	};
 
-	ret = i2c_transfer(state->i2c, msg, 2);
+	ret = i2c_transfer(dev->client->adapter, msg, 2);
 	if (ret == 2) {
 		ret = 0;
 	} else {
-		dev_warn(&state->i2c->dev, "%s: i2c rd failed=%d reg=%06x " \
-				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
+		dev_warn(&dev->client->dev, "i2c rd failed=%d reg=%06x len=%d\n",
+				ret, reg, len);
 		ret = -EREMOTEIO;
 	}
 
@@ -111,19 +117,19 @@
 
 
 /* write single register */
-static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val)
+static int af9033_wr_reg(struct af9033_dev *dev, u32 reg, u8 val)
 {
-	return af9033_wr_regs(state, reg, &val, 1);
+	return af9033_wr_regs(dev, reg, &val, 1);
 }
 
 /* read single register */
-static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val)
+static int af9033_rd_reg(struct af9033_dev *dev, u32 reg, u8 *val)
 {
-	return af9033_rd_regs(state, reg, val, 1);
+	return af9033_rd_regs(dev, reg, val, 1);
 }
 
 /* write single register with mask */
-static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val,
+static int af9033_wr_reg_mask(struct af9033_dev *dev, u32 reg, u8 val,
 		u8 mask)
 {
 	int ret;
@@ -131,7 +137,7 @@
 
 	/* no need for read if whole reg is written */
 	if (mask != 0xff) {
-		ret = af9033_rd_regs(state, reg, &tmp, 1);
+		ret = af9033_rd_regs(dev, reg, &tmp, 1);
 		if (ret)
 			return ret;
 
@@ -140,17 +146,17 @@
 		val |= tmp;
 	}
 
-	return af9033_wr_regs(state, reg, &val, 1);
+	return af9033_wr_regs(dev, reg, &val, 1);
 }
 
 /* read single register with mask */
-static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val,
+static int af9033_rd_reg_mask(struct af9033_dev *dev, u32 reg, u8 *val,
 		u8 mask)
 {
 	int ret, i;
 	u8 tmp;
 
-	ret = af9033_rd_regs(state, reg, &tmp, 1);
+	ret = af9033_rd_regs(dev, reg, &tmp, 1);
 	if (ret)
 		return ret;
 
@@ -167,18 +173,17 @@
 }
 
 /* write reg val table using reg addr auto increment */
-static int af9033_wr_reg_val_tab(struct af9033_state *state,
+static int af9033_wr_reg_val_tab(struct af9033_dev *dev,
 		const struct reg_val *tab, int tab_len)
 {
 #define MAX_TAB_LEN 212
 	int ret, i, j;
 	u8 buf[1 + MAX_TAB_LEN];
 
-	dev_dbg(&state->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len);
+	dev_dbg(&dev->client->dev, "tab_len=%d\n", tab_len);
 
 	if (tab_len > sizeof(buf)) {
-		dev_warn(&state->i2c->dev, "%s: tab len %d is too big\n",
-				KBUILD_MODNAME, tab_len);
+		dev_warn(&dev->client->dev, "tab len %d is too big\n", tab_len);
 		return -EINVAL;
 	}
 
@@ -186,7 +191,7 @@
 		buf[j] = tab[i].val;
 
 		if (i == tab_len - 1 || tab[i].reg != tab[i + 1].reg - 1) {
-			ret = af9033_wr_regs(state, tab[i].reg - j, buf, j + 1);
+			ret = af9033_wr_regs(dev, tab[i].reg - j, buf, j + 1);
 			if (ret < 0)
 				goto err;
 
@@ -199,16 +204,16 @@
 	return 0;
 
 err:
-	dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
 
-static u32 af9033_div(struct af9033_state *state, u32 a, u32 b, u32 x)
+static u32 af9033_div(struct af9033_dev *dev, u32 a, u32 b, u32 x)
 {
 	u32 r = 0, c = 0, i;
 
-	dev_dbg(&state->i2c->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x);
+	dev_dbg(&dev->client->dev, "a=%d b=%d x=%d\n", a, b, x);
 
 	if (a > b) {
 		c = a / b;
@@ -225,22 +230,15 @@
 	}
 	r = (c << (u32)x) + r;
 
-	dev_dbg(&state->i2c->dev, "%s: a=%d b=%d x=%d r=%d r=%x\n",
-			__func__, a, b, x, r, r);
+	dev_dbg(&dev->client->dev, "a=%d b=%d x=%d r=%d r=%x\n", a, b, x, r, r);
 
 	return r;
 }
 
-static void af9033_release(struct dvb_frontend *fe)
-{
-	struct af9033_state *state = fe->demodulator_priv;
-
-	kfree(state);
-}
-
 static int af9033_init(struct dvb_frontend *fe)
 {
-	struct af9033_state *state = fe->demodulator_priv;
+	struct af9033_dev *dev = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret, i, len;
 	const struct reg_val *init;
 	u8 buf[4];
@@ -248,7 +246,7 @@
 	struct reg_val_mask tab[] = {
 		{ 0x80fb24, 0x00, 0x08 },
 		{ 0x80004c, 0x00, 0xff },
-		{ 0x00f641, state->cfg.tuner, 0xff },
+		{ 0x00f641, dev->cfg.tuner, 0xff },
 		{ 0x80f5ca, 0x01, 0x01 },
 		{ 0x80f715, 0x01, 0x01 },
 		{ 0x00f41f, 0x04, 0x04 },
@@ -267,88 +265,82 @@
 		{ 0x00d830, 0x01, 0xff },
 		{ 0x00d831, 0x00, 0xff },
 		{ 0x00d832, 0x00, 0xff },
-		{ 0x80f985, state->ts_mode_serial, 0x01 },
-		{ 0x80f986, state->ts_mode_parallel, 0x01 },
+		{ 0x80f985, dev->ts_mode_serial, 0x01 },
+		{ 0x80f986, dev->ts_mode_parallel, 0x01 },
 		{ 0x00d827, 0x00, 0xff },
 		{ 0x00d829, 0x00, 0xff },
-		{ 0x800045, state->cfg.adc_multiplier, 0xff },
+		{ 0x800045, dev->cfg.adc_multiplier, 0xff },
 	};
 
 	/* program clock control */
-	clock_cw = af9033_div(state, state->cfg.clock, 1000000ul, 19ul);
+	clock_cw = af9033_div(dev, dev->cfg.clock, 1000000ul, 19ul);
 	buf[0] = (clock_cw >>  0) & 0xff;
 	buf[1] = (clock_cw >>  8) & 0xff;
 	buf[2] = (clock_cw >> 16) & 0xff;
 	buf[3] = (clock_cw >> 24) & 0xff;
 
-	dev_dbg(&state->i2c->dev, "%s: clock=%d clock_cw=%08x\n",
-			__func__, state->cfg.clock, clock_cw);
+	dev_dbg(&dev->client->dev, "clock=%d clock_cw=%08x\n",
+			dev->cfg.clock, clock_cw);
 
-	ret = af9033_wr_regs(state, 0x800025, buf, 4);
+	ret = af9033_wr_regs(dev, 0x800025, buf, 4);
 	if (ret < 0)
 		goto err;
 
 	/* program ADC control */
 	for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
-		if (clock_adc_lut[i].clock == state->cfg.clock)
+		if (clock_adc_lut[i].clock == dev->cfg.clock)
 			break;
 	}
 
-	adc_cw = af9033_div(state, clock_adc_lut[i].adc, 1000000ul, 19ul);
+	adc_cw = af9033_div(dev, clock_adc_lut[i].adc, 1000000ul, 19ul);
 	buf[0] = (adc_cw >>  0) & 0xff;
 	buf[1] = (adc_cw >>  8) & 0xff;
 	buf[2] = (adc_cw >> 16) & 0xff;
 
-	dev_dbg(&state->i2c->dev, "%s: adc=%d adc_cw=%06x\n",
-			__func__, clock_adc_lut[i].adc, adc_cw);
+	dev_dbg(&dev->client->dev, "adc=%d adc_cw=%06x\n",
+			clock_adc_lut[i].adc, adc_cw);
 
-	ret = af9033_wr_regs(state, 0x80f1cd, buf, 3);
+	ret = af9033_wr_regs(dev, 0x80f1cd, buf, 3);
 	if (ret < 0)
 		goto err;
 
 	/* program register table */
 	for (i = 0; i < ARRAY_SIZE(tab); i++) {
-		ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val,
+		ret = af9033_wr_reg_mask(dev, tab[i].reg, tab[i].val,
 				tab[i].mask);
 		if (ret < 0)
 			goto err;
 	}
 
-	/* feed clock to RF tuner */
-	switch (state->cfg.tuner) {
-	case AF9033_TUNER_IT9135_38:
-	case AF9033_TUNER_IT9135_51:
-	case AF9033_TUNER_IT9135_52:
-	case AF9033_TUNER_IT9135_60:
-	case AF9033_TUNER_IT9135_61:
-	case AF9033_TUNER_IT9135_62:
-		ret = af9033_wr_reg(state, 0x80fba8, 0x00);
+	/* clock output */
+	if (dev->cfg.dyn0_clk) {
+		ret = af9033_wr_reg(dev, 0x80fba8, 0x00);
 		if (ret < 0)
 			goto err;
 	}
 
 	/* settings for TS interface */
-	if (state->cfg.ts_mode == AF9033_TS_MODE_USB) {
-		ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01);
+	if (dev->cfg.ts_mode == AF9033_TS_MODE_USB) {
+		ret = af9033_wr_reg_mask(dev, 0x80f9a5, 0x00, 0x01);
 		if (ret < 0)
 			goto err;
 
-		ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01);
+		ret = af9033_wr_reg_mask(dev, 0x80f9b5, 0x01, 0x01);
 		if (ret < 0)
 			goto err;
 	} else {
-		ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01);
+		ret = af9033_wr_reg_mask(dev, 0x80f990, 0x00, 0x01);
 		if (ret < 0)
 			goto err;
 
-		ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01);
+		ret = af9033_wr_reg_mask(dev, 0x80f9b5, 0x00, 0x01);
 		if (ret < 0)
 			goto err;
 	}
 
 	/* load OFSM settings */
-	dev_dbg(&state->i2c->dev, "%s: load ofsm settings\n", __func__);
-	switch (state->cfg.tuner) {
+	dev_dbg(&dev->client->dev, "load ofsm settings\n");
+	switch (dev->cfg.tuner) {
 	case AF9033_TUNER_IT9135_38:
 	case AF9033_TUNER_IT9135_51:
 	case AF9033_TUNER_IT9135_52:
@@ -367,14 +359,13 @@
 		break;
 	}
 
-	ret = af9033_wr_reg_val_tab(state, init, len);
+	ret = af9033_wr_reg_val_tab(dev, init, len);
 	if (ret < 0)
 		goto err;
 
 	/* load tuner specific settings */
-	dev_dbg(&state->i2c->dev, "%s: load tuner specific settings\n",
-			__func__);
-	switch (state->cfg.tuner) {
+	dev_dbg(&dev->client->dev, "load tuner specific settings\n");
+	switch (dev->cfg.tuner) {
 	case AF9033_TUNER_TUA9001:
 		len = ARRAY_SIZE(tuner_init_tua9001);
 		init = tuner_init_tua9001;
@@ -424,90 +415,108 @@
 		init = tuner_init_it9135_62;
 		break;
 	default:
-		dev_dbg(&state->i2c->dev, "%s: unsupported tuner ID=%d\n",
-				__func__, state->cfg.tuner);
+		dev_dbg(&dev->client->dev, "unsupported tuner ID=%d\n",
+				dev->cfg.tuner);
 		ret = -ENODEV;
 		goto err;
 	}
 
-	ret = af9033_wr_reg_val_tab(state, init, len);
+	ret = af9033_wr_reg_val_tab(dev, init, len);
 	if (ret < 0)
 		goto err;
 
-	if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
-		ret = af9033_wr_reg_mask(state, 0x00d91c, 0x01, 0x01);
+	if (dev->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
+		ret = af9033_wr_reg_mask(dev, 0x00d91c, 0x01, 0x01);
 		if (ret < 0)
 			goto err;
 
-		ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01);
+		ret = af9033_wr_reg_mask(dev, 0x00d917, 0x00, 0x01);
 		if (ret < 0)
 			goto err;
 
-		ret = af9033_wr_reg_mask(state, 0x00d916, 0x00, 0x01);
+		ret = af9033_wr_reg_mask(dev, 0x00d916, 0x00, 0x01);
 		if (ret < 0)
 			goto err;
 	}
 
-	switch (state->cfg.tuner) {
+	switch (dev->cfg.tuner) {
 	case AF9033_TUNER_IT9135_60:
 	case AF9033_TUNER_IT9135_61:
 	case AF9033_TUNER_IT9135_62:
-		ret = af9033_wr_reg(state, 0x800000, 0x01);
+		ret = af9033_wr_reg(dev, 0x800000, 0x01);
 		if (ret < 0)
 			goto err;
 	}
 
-	state->bandwidth_hz = 0; /* force to program all parameters */
+	dev->bandwidth_hz = 0; /* force to program all parameters */
+	/* init stats here in order signal app which stats are supported */
+	c->strength.len = 1;
+	c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->cnr.len = 1;
+	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->block_count.len = 1;
+	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->block_error.len = 1;
+	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_count.len = 1;
+	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_error.len = 1;
+	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	/* start statistics polling */
+	schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
 
 	return 0;
 
 err:
-	dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
 
 static int af9033_sleep(struct dvb_frontend *fe)
 {
-	struct af9033_state *state = fe->demodulator_priv;
+	struct af9033_dev *dev = fe->demodulator_priv;
 	int ret, i;
 	u8 tmp;
 
-	ret = af9033_wr_reg(state, 0x80004c, 1);
+	/* stop statistics polling */
+	cancel_delayed_work_sync(&dev->stat_work);
+
+	ret = af9033_wr_reg(dev, 0x80004c, 1);
 	if (ret < 0)
 		goto err;
 
-	ret = af9033_wr_reg(state, 0x800000, 0);
+	ret = af9033_wr_reg(dev, 0x800000, 0);
 	if (ret < 0)
 		goto err;
 
 	for (i = 100, tmp = 1; i && tmp; i--) {
-		ret = af9033_rd_reg(state, 0x80004c, &tmp);
+		ret = af9033_rd_reg(dev, 0x80004c, &tmp);
 		if (ret < 0)
 			goto err;
 
 		usleep_range(200, 10000);
 	}
 
-	dev_dbg(&state->i2c->dev, "%s: loop=%d\n", __func__, i);
+	dev_dbg(&dev->client->dev, "loop=%d\n", i);
 
 	if (i == 0) {
 		ret = -ETIMEDOUT;
 		goto err;
 	}
 
-	ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08);
+	ret = af9033_wr_reg_mask(dev, 0x80fb24, 0x08, 0x08);
 	if (ret < 0)
 		goto err;
 
 	/* prevent current leak (?) */
-	if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
+	if (dev->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
 		/* enable parallel TS */
-		ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01);
+		ret = af9033_wr_reg_mask(dev, 0x00d917, 0x00, 0x01);
 		if (ret < 0)
 			goto err;
 
-		ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01);
+		ret = af9033_wr_reg_mask(dev, 0x00d916, 0x01, 0x01);
 		if (ret < 0)
 			goto err;
 	}
@@ -515,7 +524,7 @@
 	return 0;
 
 err:
-	dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
@@ -533,14 +542,14 @@
 
 static int af9033_set_frontend(struct dvb_frontend *fe)
 {
-	struct af9033_state *state = fe->demodulator_priv;
+	struct af9033_dev *dev = fe->demodulator_priv;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret, i, spec_inv, sampling_freq;
 	u8 tmp, buf[3], bandwidth_reg_val;
 	u32 if_frequency, freq_cw, adc_freq;
 
-	dev_dbg(&state->i2c->dev, "%s: frequency=%d bandwidth_hz=%d\n",
-			__func__, c->frequency, c->bandwidth_hz);
+	dev_dbg(&dev->client->dev, "frequency=%d bandwidth_hz=%d\n",
+			c->frequency, c->bandwidth_hz);
 
 	/* check bandwidth */
 	switch (c->bandwidth_hz) {
@@ -554,8 +563,7 @@
 		bandwidth_reg_val = 0x02;
 		break;
 	default:
-		dev_dbg(&state->i2c->dev, "%s: invalid bandwidth_hz\n",
-				__func__);
+		dev_dbg(&dev->client->dev, "invalid bandwidth_hz\n");
 		ret = -EINVAL;
 		goto err;
 	}
@@ -565,23 +573,23 @@
 		fe->ops.tuner_ops.set_params(fe);
 
 	/* program CFOE coefficients */
-	if (c->bandwidth_hz != state->bandwidth_hz) {
+	if (c->bandwidth_hz != dev->bandwidth_hz) {
 		for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) {
-			if (coeff_lut[i].clock == state->cfg.clock &&
+			if (coeff_lut[i].clock == dev->cfg.clock &&
 				coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
 				break;
 			}
 		}
-		ret =  af9033_wr_regs(state, 0x800001,
+		ret =  af9033_wr_regs(dev, 0x800001,
 				coeff_lut[i].val, sizeof(coeff_lut[i].val));
 	}
 
 	/* program frequency control */
-	if (c->bandwidth_hz != state->bandwidth_hz) {
-		spec_inv = state->cfg.spec_inv ? -1 : 1;
+	if (c->bandwidth_hz != dev->bandwidth_hz) {
+		spec_inv = dev->cfg.spec_inv ? -1 : 1;
 
 		for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
-			if (clock_adc_lut[i].clock == state->cfg.clock)
+			if (clock_adc_lut[i].clock == dev->cfg.clock)
 				break;
 		}
 		adc_freq = clock_adc_lut[i].adc;
@@ -602,12 +610,12 @@
 		else
 			sampling_freq *= -1;
 
-		freq_cw = af9033_div(state, sampling_freq, adc_freq, 23ul);
+		freq_cw = af9033_div(dev, sampling_freq, adc_freq, 23ul);
 
 		if (spec_inv == -1)
 			freq_cw = 0x800000 - freq_cw;
 
-		if (state->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X)
+		if (dev->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X)
 			freq_cw /= 2;
 
 		buf[0] = (freq_cw >>  0) & 0xff;
@@ -618,26 +626,26 @@
 		if (if_frequency == 0)
 			buf[2] = 0;
 
-		ret = af9033_wr_regs(state, 0x800029, buf, 3);
+		ret = af9033_wr_regs(dev, 0x800029, buf, 3);
 		if (ret < 0)
 			goto err;
 
-		state->bandwidth_hz = c->bandwidth_hz;
+		dev->bandwidth_hz = c->bandwidth_hz;
 	}
 
-	ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03);
+	ret = af9033_wr_reg_mask(dev, 0x80f904, bandwidth_reg_val, 0x03);
 	if (ret < 0)
 		goto err;
 
-	ret = af9033_wr_reg(state, 0x800040, 0x00);
+	ret = af9033_wr_reg(dev, 0x800040, 0x00);
 	if (ret < 0)
 		goto err;
 
-	ret = af9033_wr_reg(state, 0x800047, 0x00);
+	ret = af9033_wr_reg(dev, 0x800047, 0x00);
 	if (ret < 0)
 		goto err;
 
-	ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01);
+	ret = af9033_wr_reg_mask(dev, 0x80f999, 0x00, 0x01);
 	if (ret < 0)
 		goto err;
 
@@ -646,33 +654,33 @@
 	else
 		tmp = 0x01; /* UHF */
 
-	ret = af9033_wr_reg(state, 0x80004b, tmp);
+	ret = af9033_wr_reg(dev, 0x80004b, tmp);
 	if (ret < 0)
 		goto err;
 
-	ret = af9033_wr_reg(state, 0x800000, 0x00);
+	ret = af9033_wr_reg(dev, 0x800000, 0x00);
 	if (ret < 0)
 		goto err;
 
 	return 0;
 
 err:
-	dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
 
 static int af9033_get_frontend(struct dvb_frontend *fe)
 {
-	struct af9033_state *state = fe->demodulator_priv;
+	struct af9033_dev *dev = fe->demodulator_priv;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret;
 	u8 buf[8];
 
-	dev_dbg(&state->i2c->dev, "%s:\n", __func__);
+	dev_dbg(&dev->client->dev, "\n");
 
 	/* read all needed registers */
-	ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf));
+	ret = af9033_rd_regs(dev, 0x80f900, buf, sizeof(buf));
 	if (ret < 0)
 		goto err;
 
@@ -784,21 +792,21 @@
 	return 0;
 
 err:
-	dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
 
 static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
-	struct af9033_state *state = fe->demodulator_priv;
+	struct af9033_dev *dev = fe->demodulator_priv;
 	int ret;
 	u8 tmp;
 
 	*status = 0;
 
 	/* radio channel status, 0=no result, 1=has signal, 2=no signal */
-	ret = af9033_rd_reg(state, 0x800047, &tmp);
+	ret = af9033_rd_reg(dev, 0x800047, &tmp);
 	if (ret < 0)
 		goto err;
 
@@ -808,7 +816,7 @@
 
 	if (tmp != 0x02) {
 		/* TPS lock */
-		ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01);
+		ret = af9033_rd_reg_mask(dev, 0x80f5a9, &tmp, 0x01);
 		if (ret < 0)
 			goto err;
 
@@ -817,7 +825,7 @@
 					FE_HAS_VITERBI;
 
 		/* full lock */
-		ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01);
+		ret = af9033_rd_reg_mask(dev, 0x80f999, &tmp, 0x01);
 		if (ret < 0)
 			goto err;
 
@@ -827,76 +835,38 @@
 					FE_HAS_LOCK;
 	}
 
+	dev->fe_status = *status;
+
 	return 0;
 
 err:
-	dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
 
 static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-	struct af9033_state *state = fe->demodulator_priv;
-	int ret, i, len;
-	u8 buf[3], tmp;
-	u32 snr_val;
-	const struct val_snr *uninitialized_var(snr_lut);
+	struct af9033_dev *dev = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
 
-	/* read value */
-	ret = af9033_rd_regs(state, 0x80002c, buf, 3);
-	if (ret < 0)
-		goto err;
-
-	snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0];
-
-	/* read current modulation */
-	ret = af9033_rd_reg(state, 0x80f903, &tmp);
-	if (ret < 0)
-		goto err;
-
-	switch ((tmp >> 0) & 3) {
-	case 0:
-		len = ARRAY_SIZE(qpsk_snr_lut);
-		snr_lut = qpsk_snr_lut;
-		break;
-	case 1:
-		len = ARRAY_SIZE(qam16_snr_lut);
-		snr_lut = qam16_snr_lut;
-		break;
-	case 2:
-		len = ARRAY_SIZE(qam64_snr_lut);
-		snr_lut = qam64_snr_lut;
-		break;
-	default:
-		goto err;
-	}
-
-	for (i = 0; i < len; i++) {
-		tmp = snr_lut[i].snr;
-
-		if (snr_val < snr_lut[i].val)
-			break;
-	}
-
-	*snr = tmp * 10; /* dB/10 */
+	/* use DVBv5 CNR */
+	if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL)
+		*snr = div_s64(c->cnr.stat[0].svalue, 100); /* 1000x => 10x */
+	else
+		*snr = 0;
 
 	return 0;
-
-err:
-	dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
-
-	return ret;
 }
 
 static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
-	struct af9033_state *state = fe->demodulator_priv;
+	struct af9033_dev *dev = fe->demodulator_priv;
 	int ret;
 	u8 strength2;
 
 	/* read signal strength of 0-100 scale */
-	ret = af9033_rd_reg(state, 0x800048, &strength2);
+	ret = af9033_rd_reg(dev, 0x800048, &strength2);
 	if (ret < 0)
 		goto err;
 
@@ -906,244 +876,225 @@
 	return 0;
 
 err:
-	dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int af9033_update_ch_stat(struct af9033_state *state)
-{
-	int ret = 0;
-	u32 err_cnt, bit_cnt;
-	u16 abort_cnt;
-	u8 buf[7];
-
-	/* only update data every half second */
-	if (time_after(jiffies, state->last_stat_check + msecs_to_jiffies(500))) {
-		ret = af9033_rd_regs(state, 0x800032, buf, sizeof(buf));
-		if (ret < 0)
-			goto err;
-		/* in 8 byte packets? */
-		abort_cnt = (buf[1] << 8) + buf[0];
-		/* in bits */
-		err_cnt = (buf[4] << 16) + (buf[3] << 8) + buf[2];
-		/* in 8 byte packets? always(?) 0x2710 = 10000 */
-		bit_cnt = (buf[6] << 8) + buf[5];
-
-		if (bit_cnt < abort_cnt) {
-			abort_cnt = 1000;
-			state->ber = 0xffffffff;
-		} else {
-			/* 8 byte packets, that have not been rejected already */
-			bit_cnt -= (u32)abort_cnt;
-			if (bit_cnt == 0) {
-				state->ber = 0xffffffff;
-			} else {
-				err_cnt -= (u32)abort_cnt * 8 * 8;
-				bit_cnt *= 8 * 8;
-				state->ber = err_cnt * (0xffffffff / bit_cnt);
-			}
-		}
-		state->ucb += abort_cnt;
-		state->last_stat_check = jiffies;
-	}
-
-	return 0;
-err:
-	dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
 
 static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-	struct af9033_state *state = fe->demodulator_priv;
-	int ret;
+	struct af9033_dev *dev = fe->demodulator_priv;
 
-	ret = af9033_update_ch_stat(state);
-	if (ret < 0)
-		return ret;
-
-	*ber = state->ber;
+	*ber = (dev->post_bit_error - dev->post_bit_error_prev);
+	dev->post_bit_error_prev = dev->post_bit_error;
 
 	return 0;
 }
 
 static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-	struct af9033_state *state = fe->demodulator_priv;
-	int ret;
+	struct af9033_dev *dev = fe->demodulator_priv;
 
-	ret = af9033_update_ch_stat(state);
-	if (ret < 0)
-		return ret;
-
-	*ucblocks = state->ucb;
-
+	*ucblocks = dev->error_block_count;
 	return 0;
 }
 
 static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
-	struct af9033_state *state = fe->demodulator_priv;
+	struct af9033_dev *dev = fe->demodulator_priv;
 	int ret;
 
-	dev_dbg(&state->i2c->dev, "%s: enable=%d\n", __func__, enable);
+	dev_dbg(&dev->client->dev, "enable=%d\n", enable);
 
-	ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01);
+	ret = af9033_wr_reg_mask(dev, 0x00fa04, enable, 0x01);
 	if (ret < 0)
 		goto err;
 
 	return 0;
 
 err:
-	dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
 
 static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
 {
-	struct af9033_state *state = fe->demodulator_priv;
+	struct af9033_dev *dev = fe->demodulator_priv;
 	int ret;
 
-	dev_dbg(&state->i2c->dev, "%s: onoff=%d\n", __func__, onoff);
+	dev_dbg(&dev->client->dev, "onoff=%d\n", onoff);
 
-	ret = af9033_wr_reg_mask(state, 0x80f993, onoff, 0x01);
+	ret = af9033_wr_reg_mask(dev, 0x80f993, onoff, 0x01);
 	if (ret < 0)
 		goto err;
 
 	return 0;
 
 err:
-	dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
 
-static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int onoff)
+static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid,
+		int onoff)
 {
-	struct af9033_state *state = fe->demodulator_priv;
+	struct af9033_dev *dev = fe->demodulator_priv;
 	int ret;
 	u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff};
 
-	dev_dbg(&state->i2c->dev, "%s: index=%d pid=%04x onoff=%d\n",
-			__func__, index, pid, onoff);
+	dev_dbg(&dev->client->dev, "index=%d pid=%04x onoff=%d\n",
+			index, pid, onoff);
 
 	if (pid > 0x1fff)
 		return 0;
 
-	ret = af9033_wr_regs(state, 0x80f996, wbuf, 2);
+	ret = af9033_wr_regs(dev, 0x80f996, wbuf, 2);
 	if (ret < 0)
 		goto err;
 
-	ret = af9033_wr_reg(state, 0x80f994, onoff);
+	ret = af9033_wr_reg(dev, 0x80f994, onoff);
 	if (ret < 0)
 		goto err;
 
-	ret = af9033_wr_reg(state, 0x80f995, index);
+	ret = af9033_wr_reg(dev, 0x80f995, index);
 	if (ret < 0)
 		goto err;
 
 	return 0;
 
 err:
-	dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
 
-static struct dvb_frontend_ops af9033_ops;
-
-struct dvb_frontend *af9033_attach(const struct af9033_config *config,
-				   struct i2c_adapter *i2c,
-				   struct af9033_ops *ops)
+static void af9033_stat_work(struct work_struct *work)
 {
-	int ret;
-	struct af9033_state *state;
-	u8 buf[8];
+	struct af9033_dev *dev = container_of(work, struct af9033_dev, stat_work.work);
+	struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
+	int ret, tmp, i, len;
+	u8 u8tmp, buf[7];
 
-	dev_dbg(&i2c->dev, "%s:\n", __func__);
+	dev_dbg(&dev->client->dev, "\n");
 
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL);
-	if (state == NULL)
-		goto err;
-
-	/* setup the state */
-	state->i2c = i2c;
-	memcpy(&state->cfg, config, sizeof(struct af9033_config));
-
-	if (state->cfg.clock != 12000000) {
-		dev_err(&state->i2c->dev, "%s: af9033: unsupported clock=%d, " \
-				"only 12000000 Hz is supported currently\n",
-				KBUILD_MODNAME, state->cfg.clock);
-		goto err;
-	}
-
-	/* firmware version */
-	ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4);
-	if (ret < 0)
-		goto err;
-
-	ret = af9033_rd_regs(state, 0x804191, &buf[4], 4);
-	if (ret < 0)
-		goto err;
-
-	dev_info(&state->i2c->dev, "%s: firmware version: LINK=%d.%d.%d.%d " \
-			"OFDM=%d.%d.%d.%d\n", KBUILD_MODNAME, buf[0], buf[1],
-			buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
-
-	/* sleep */
-	switch (state->cfg.tuner) {
-	case AF9033_TUNER_IT9135_38:
-	case AF9033_TUNER_IT9135_51:
-	case AF9033_TUNER_IT9135_52:
-	case AF9033_TUNER_IT9135_60:
-	case AF9033_TUNER_IT9135_61:
-	case AF9033_TUNER_IT9135_62:
-		/* IT9135 did not like to sleep at that early */
-		break;
-	default:
-		ret = af9033_wr_reg(state, 0x80004c, 1);
-		if (ret < 0)
+	/* signal strength */
+	if (dev->fe_status & FE_HAS_SIGNAL) {
+		if (dev->is_af9035) {
+			ret = af9033_rd_reg(dev, 0x80004a, &u8tmp);
+			tmp = -u8tmp * 1000;
+		} else {
+			ret = af9033_rd_reg(dev, 0x8000f7, &u8tmp);
+			tmp = (u8tmp - 100) * 1000;
+		}
+		if (ret)
 			goto err;
 
-		ret = af9033_wr_reg(state, 0x800000, 0);
-		if (ret < 0)
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+		c->strength.stat[0].svalue = tmp;
+	} else {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	}
+
+	/* CNR */
+	if (dev->fe_status & FE_HAS_VITERBI) {
+		u32 snr_val;
+		const struct val_snr *snr_lut;
+
+		/* read value */
+		ret = af9033_rd_regs(dev, 0x80002c, buf, 3);
+		if (ret)
 			goto err;
+
+		snr_val = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0);
+
+		/* read current modulation */
+		ret = af9033_rd_reg(dev, 0x80f903, &u8tmp);
+		if (ret)
+			goto err;
+
+		switch ((u8tmp >> 0) & 3) {
+		case 0:
+			len = ARRAY_SIZE(qpsk_snr_lut);
+			snr_lut = qpsk_snr_lut;
+			break;
+		case 1:
+			len = ARRAY_SIZE(qam16_snr_lut);
+			snr_lut = qam16_snr_lut;
+			break;
+		case 2:
+			len = ARRAY_SIZE(qam64_snr_lut);
+			snr_lut = qam64_snr_lut;
+			break;
+		default:
+			goto err_schedule_delayed_work;
+		}
+
+		for (i = 0; i < len; i++) {
+			tmp = snr_lut[i].snr * 1000;
+			if (snr_val < snr_lut[i].val)
+				break;
+		}
+
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		c->cnr.stat[0].svalue = tmp;
+	} else {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 	}
 
-	/* configure internal TS mode */
-	switch (state->cfg.ts_mode) {
-	case AF9033_TS_MODE_PARALLEL:
-		state->ts_mode_parallel = true;
-		break;
-	case AF9033_TS_MODE_SERIAL:
-		state->ts_mode_serial = true;
-		break;
-	case AF9033_TS_MODE_USB:
-		/* usb mode for AF9035 */
-	default:
-		break;
+	/* UCB/PER/BER */
+	if (dev->fe_status & FE_HAS_LOCK) {
+		/* outer FEC, 204 byte packets */
+		u16 abort_packet_count, rsd_packet_count;
+		/* inner FEC, bits */
+		u32 rsd_bit_err_count;
+
+		/*
+		 * Packet count used for measurement is 10000
+		 * (rsd_packet_count). Maybe it should be increased?
+		 */
+
+		ret = af9033_rd_regs(dev, 0x800032, buf, 7);
+		if (ret)
+			goto err;
+
+		abort_packet_count = (buf[1] << 8) | (buf[0] << 0);
+		rsd_bit_err_count = (buf[4] << 16) | (buf[3] << 8) | buf[2];
+		rsd_packet_count = (buf[6] << 8) | (buf[5] << 0);
+
+		dev->error_block_count += abort_packet_count;
+		dev->total_block_count += rsd_packet_count;
+		dev->post_bit_error += rsd_bit_err_count;
+		dev->post_bit_count += rsd_packet_count * 204 * 8;
+
+		c->block_count.len = 1;
+		c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+		c->block_count.stat[0].uvalue = dev->total_block_count;
+
+		c->block_error.len = 1;
+		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->block_error.stat[0].uvalue = dev->error_block_count;
+
+		c->post_bit_count.len = 1;
+		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+		c->post_bit_count.stat[0].uvalue = dev->post_bit_count;
+
+		c->post_bit_error.len = 1;
+		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+		c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
 	}
 
-	/* create dvb_frontend */
-	memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops));
-	state->fe.demodulator_priv = state;
-
-	if (ops) {
-		ops->pid_filter = af9033_pid_filter;
-		ops->pid_filter_ctrl = af9033_pid_filter_ctrl;
-	}
-
-	return &state->fe;
-
+err_schedule_delayed_work:
+	schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+	return;
 err:
-	kfree(state);
-	return NULL;
+	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 }
-EXPORT_SYMBOL(af9033_attach);
 
 static struct dvb_frontend_ops af9033_ops = {
 	.delsys = { SYS_DVBT },
@@ -1170,8 +1121,6 @@
 			FE_CAN_MUTE_TS
 	},
 
-	.release = af9033_release,
-
 	.init = af9033_init,
 	.sleep = af9033_sleep,
 
@@ -1188,6 +1137,150 @@
 	.i2c_gate_ctrl = af9033_i2c_gate_ctrl,
 };
 
+static int af9033_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct af9033_config *cfg = client->dev.platform_data;
+	struct af9033_dev *dev;
+	int ret;
+	u8 buf[8];
+	u32 reg;
+
+	/* allocate memory for the internal state */
+	dev = kzalloc(sizeof(struct af9033_dev), GFP_KERNEL);
+	if (dev == NULL) {
+		ret = -ENOMEM;
+		dev_err(&client->dev, "Could not allocate memory for state\n");
+		goto err;
+	}
+
+	/* setup the state */
+	dev->client = client;
+	INIT_DELAYED_WORK(&dev->stat_work, af9033_stat_work);
+	memcpy(&dev->cfg, cfg, sizeof(struct af9033_config));
+
+	if (dev->cfg.clock != 12000000) {
+		ret = -ENODEV;
+		dev_err(&dev->client->dev,
+				"unsupported clock %d Hz, only 12000000 Hz is supported currently\n",
+				dev->cfg.clock);
+		goto err_kfree;
+	}
+
+	/* firmware version */
+	switch (dev->cfg.tuner) {
+	case AF9033_TUNER_IT9135_38:
+	case AF9033_TUNER_IT9135_51:
+	case AF9033_TUNER_IT9135_52:
+	case AF9033_TUNER_IT9135_60:
+	case AF9033_TUNER_IT9135_61:
+	case AF9033_TUNER_IT9135_62:
+		dev->is_it9135 = true;
+		reg = 0x004bfc;
+		break;
+	default:
+		dev->is_af9035 = true;
+		reg = 0x0083e9;
+		break;
+	}
+
+	ret = af9033_rd_regs(dev, reg, &buf[0], 4);
+	if (ret < 0)
+		goto err_kfree;
+
+	ret = af9033_rd_regs(dev, 0x804191, &buf[4], 4);
+	if (ret < 0)
+		goto err_kfree;
+
+	dev_info(&dev->client->dev,
+			"firmware version: LINK %d.%d.%d.%d - OFDM %d.%d.%d.%d\n",
+			buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
+			buf[7]);
+
+	/* sleep */
+	switch (dev->cfg.tuner) {
+	case AF9033_TUNER_IT9135_38:
+	case AF9033_TUNER_IT9135_51:
+	case AF9033_TUNER_IT9135_52:
+	case AF9033_TUNER_IT9135_60:
+	case AF9033_TUNER_IT9135_61:
+	case AF9033_TUNER_IT9135_62:
+		/* IT9135 did not like to sleep at that early */
+		break;
+	default:
+		ret = af9033_wr_reg(dev, 0x80004c, 1);
+		if (ret < 0)
+			goto err_kfree;
+
+		ret = af9033_wr_reg(dev, 0x800000, 0);
+		if (ret < 0)
+			goto err_kfree;
+	}
+
+	/* configure internal TS mode */
+	switch (dev->cfg.ts_mode) {
+	case AF9033_TS_MODE_PARALLEL:
+		dev->ts_mode_parallel = true;
+		break;
+	case AF9033_TS_MODE_SERIAL:
+		dev->ts_mode_serial = true;
+		break;
+	case AF9033_TS_MODE_USB:
+		/* usb mode for AF9035 */
+	default:
+		break;
+	}
+
+	/* create dvb_frontend */
+	memcpy(&dev->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops));
+	dev->fe.demodulator_priv = dev;
+	*cfg->fe = &dev->fe;
+	if (cfg->ops) {
+		cfg->ops->pid_filter = af9033_pid_filter;
+		cfg->ops->pid_filter_ctrl = af9033_pid_filter_ctrl;
+	}
+	i2c_set_clientdata(client, dev);
+
+	dev_info(&dev->client->dev, "Afatech AF9033 successfully attached\n");
+	return 0;
+err_kfree:
+	kfree(dev);
+err:
+	dev_dbg(&client->dev, "failed=%d\n", ret);
+	return ret;
+}
+
+static int af9033_remove(struct i2c_client *client)
+{
+	struct af9033_dev *dev = i2c_get_clientdata(client);
+
+	dev_dbg(&dev->client->dev, "\n");
+
+	dev->fe.ops.release = NULL;
+	dev->fe.demodulator_priv = NULL;
+	kfree(dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id af9033_id_table[] = {
+	{"af9033", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, af9033_id_table);
+
+static struct i2c_driver af9033_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "af9033",
+	},
+	.probe		= af9033_probe,
+	.remove		= af9033_remove,
+	.id_table	= af9033_id_table,
+};
+
+module_i2c_driver(af9033_driver);
+
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h
index a950daa..6ad22b6 100644
--- a/drivers/media/dvb-frontends/af9033.h
+++ b/drivers/media/dvb-frontends/af9033.h
@@ -24,13 +24,12 @@
 
 #include <linux/kconfig.h>
 
+/*
+ * I2C address (TODO: are these in 8-bit format?)
+ * 0x38, 0x3a, 0x3c, 0x3e
+ */
 struct af9033_config {
 	/*
-	 * I2C address
-	 */
-	u8 i2c_addr;
-
-	/*
 	 * clock Hz
 	 * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000,
 	 * 30000000, 36000000, 20480000, 16384000
@@ -75,8 +74,23 @@
 	 * input spectrum inversion
 	 */
 	bool spec_inv;
-};
 
+	/*
+	 *
+	 */
+	bool dyn0_clk;
+
+	/*
+	 * PID filter ops
+	 */
+	struct af9033_ops *ops;
+
+	/*
+	 * frontend
+	 * returned by that driver
+	 */
+	struct dvb_frontend **fe;
+};
 
 struct af9033_ops {
 	int (*pid_filter_ctrl)(struct dvb_frontend *fe, int onoff);
@@ -84,36 +98,4 @@
 			  int onoff);
 };
 
-
-#if IS_ENABLED(CPTCFG_DVB_AF9033)
-extern
-struct dvb_frontend *af9033_attach(const struct af9033_config *config,
-				   struct i2c_adapter *i2c,
-				   struct af9033_ops *ops);
-
-#else
-static inline
-struct dvb_frontend *af9033_attach(const struct af9033_config *config,
-				   struct i2c_adapter *i2c,
-				   struct af9033_ops *ops)
-{
-	pr_warn("%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-
-static inline int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
-{
-	pr_warn("%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-static inline int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid,
-	int onoff)
-{
-	pr_warn("%s: driver disabled by Kconfig\n", __func__);
-	return -ENODEV;
-}
-
-#endif
-
 #endif /* AF9033_H */
diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h
index ded7b67..c12c92c 100644
--- a/drivers/media/dvb-frontends/af9033_priv.h
+++ b/drivers/media/dvb-frontends/af9033_priv.h
@@ -24,6 +24,7 @@
 
 #include "dvb_frontend.h"
 #include "af9033.h"
+#include <linux/math64.h>
 
 struct reg_val {
 	u32 reg;
diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c
new file mode 100644
index 0000000..4936658
--- /dev/null
+++ b/drivers/media/dvb-frontends/as102_fe.c
@@ -0,0 +1,480 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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 <dvb_frontend.h>
+
+#include "as102_fe.h"
+
+struct as102_state {
+	struct dvb_frontend frontend;
+	struct as10x_demod_stats demod_stats;
+
+	const struct as102_fe_ops *ops;
+	void *priv;
+	uint8_t elna_cfg;
+
+	/* signal strength */
+	uint16_t signal_strength;
+	/* bit error rate */
+	uint32_t ber;
+};
+
+static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg)
+{
+	uint8_t c;
+
+	switch (arg) {
+	case FEC_1_2:
+		c = CODE_RATE_1_2;
+		break;
+	case FEC_2_3:
+		c = CODE_RATE_2_3;
+		break;
+	case FEC_3_4:
+		c = CODE_RATE_3_4;
+		break;
+	case FEC_5_6:
+		c = CODE_RATE_5_6;
+		break;
+	case FEC_7_8:
+		c = CODE_RATE_7_8;
+		break;
+	default:
+		c = CODE_RATE_UNKNOWN;
+		break;
+	}
+
+	return c;
+}
+
+static int as102_fe_set_frontend(struct dvb_frontend *fe)
+{
+	struct as102_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct as10x_tune_args tune_args = { 0 };
+
+	/* set frequency */
+	tune_args.freq = c->frequency / 1000;
+
+	/* fix interleaving_mode */
+	tune_args.interleaving_mode = INTLV_NATIVE;
+
+	switch (c->bandwidth_hz) {
+	case 8000000:
+		tune_args.bandwidth = BW_8_MHZ;
+		break;
+	case 7000000:
+		tune_args.bandwidth = BW_7_MHZ;
+		break;
+	case 6000000:
+		tune_args.bandwidth = BW_6_MHZ;
+		break;
+	default:
+		tune_args.bandwidth = BW_8_MHZ;
+	}
+
+	switch (c->guard_interval) {
+	case GUARD_INTERVAL_1_32:
+		tune_args.guard_interval = GUARD_INT_1_32;
+		break;
+	case GUARD_INTERVAL_1_16:
+		tune_args.guard_interval = GUARD_INT_1_16;
+		break;
+	case GUARD_INTERVAL_1_8:
+		tune_args.guard_interval = GUARD_INT_1_8;
+		break;
+	case GUARD_INTERVAL_1_4:
+		tune_args.guard_interval = GUARD_INT_1_4;
+		break;
+	case GUARD_INTERVAL_AUTO:
+	default:
+		tune_args.guard_interval = GUARD_UNKNOWN;
+		break;
+	}
+
+	switch (c->modulation) {
+	case QPSK:
+		tune_args.modulation = CONST_QPSK;
+		break;
+	case QAM_16:
+		tune_args.modulation = CONST_QAM16;
+		break;
+	case QAM_64:
+		tune_args.modulation = CONST_QAM64;
+		break;
+	default:
+		tune_args.modulation = CONST_UNKNOWN;
+		break;
+	}
+
+	switch (c->transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+		tune_args.transmission_mode = TRANS_MODE_2K;
+		break;
+	case TRANSMISSION_MODE_8K:
+		tune_args.transmission_mode = TRANS_MODE_8K;
+		break;
+	default:
+		tune_args.transmission_mode = TRANS_MODE_UNKNOWN;
+	}
+
+	switch (c->hierarchy) {
+	case HIERARCHY_NONE:
+		tune_args.hierarchy = HIER_NONE;
+		break;
+	case HIERARCHY_1:
+		tune_args.hierarchy = HIER_ALPHA_1;
+		break;
+	case HIERARCHY_2:
+		tune_args.hierarchy = HIER_ALPHA_2;
+		break;
+	case HIERARCHY_4:
+		tune_args.hierarchy = HIER_ALPHA_4;
+		break;
+	case HIERARCHY_AUTO:
+		tune_args.hierarchy = HIER_UNKNOWN;
+		break;
+	}
+
+	pr_debug("as102: tuner parameters: freq: %d  bw: 0x%02x  gi: 0x%02x\n",
+			c->frequency,
+			tune_args.bandwidth,
+			tune_args.guard_interval);
+
+	/*
+	 * Detect a hierarchy selection
+	 * if HP/LP are both set to FEC_NONE, HP will be selected.
+	 */
+	if ((tune_args.hierarchy != HIER_NONE) &&
+		       ((c->code_rate_LP == FEC_NONE) ||
+			(c->code_rate_HP == FEC_NONE))) {
+
+		if (c->code_rate_LP == FEC_NONE) {
+			tune_args.hier_select = HIER_HIGH_PRIORITY;
+			tune_args.code_rate =
+			   as102_fe_get_code_rate(c->code_rate_HP);
+		}
+
+		if (c->code_rate_HP == FEC_NONE) {
+			tune_args.hier_select = HIER_LOW_PRIORITY;
+			tune_args.code_rate =
+			   as102_fe_get_code_rate(c->code_rate_LP);
+		}
+
+		pr_debug("as102: \thierarchy: 0x%02x  selected: %s  code_rate_%s: 0x%02x\n",
+			tune_args.hierarchy,
+			tune_args.hier_select == HIER_HIGH_PRIORITY ?
+			"HP" : "LP",
+			tune_args.hier_select == HIER_HIGH_PRIORITY ?
+			"HP" : "LP",
+			tune_args.code_rate);
+	} else {
+		tune_args.code_rate =
+			as102_fe_get_code_rate(c->code_rate_HP);
+	}
+
+	/* Set frontend arguments */
+	return state->ops->set_tune(state->priv, &tune_args);
+}
+
+static int as102_fe_get_frontend(struct dvb_frontend *fe)
+{
+	struct as102_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret = 0;
+	struct as10x_tps tps = { 0 };
+
+	/* send abilis command: GET_TPS */
+	ret = state->ops->get_tps(state->priv, &tps);
+	if (ret < 0)
+		return ret;
+
+	/* extract constellation */
+	switch (tps.modulation) {
+	case CONST_QPSK:
+		c->modulation = QPSK;
+		break;
+	case CONST_QAM16:
+		c->modulation = QAM_16;
+		break;
+	case CONST_QAM64:
+		c->modulation = QAM_64;
+		break;
+	}
+
+	/* extract hierarchy */
+	switch (tps.hierarchy) {
+	case HIER_NONE:
+		c->hierarchy = HIERARCHY_NONE;
+		break;
+	case HIER_ALPHA_1:
+		c->hierarchy = HIERARCHY_1;
+		break;
+	case HIER_ALPHA_2:
+		c->hierarchy = HIERARCHY_2;
+		break;
+	case HIER_ALPHA_4:
+		c->hierarchy = HIERARCHY_4;
+		break;
+	}
+
+	/* extract code rate HP */
+	switch (tps.code_rate_HP) {
+	case CODE_RATE_1_2:
+		c->code_rate_HP = FEC_1_2;
+		break;
+	case CODE_RATE_2_3:
+		c->code_rate_HP = FEC_2_3;
+		break;
+	case CODE_RATE_3_4:
+		c->code_rate_HP = FEC_3_4;
+		break;
+	case CODE_RATE_5_6:
+		c->code_rate_HP = FEC_5_6;
+		break;
+	case CODE_RATE_7_8:
+		c->code_rate_HP = FEC_7_8;
+		break;
+	}
+
+	/* extract code rate LP */
+	switch (tps.code_rate_LP) {
+	case CODE_RATE_1_2:
+		c->code_rate_LP = FEC_1_2;
+		break;
+	case CODE_RATE_2_3:
+		c->code_rate_LP = FEC_2_3;
+		break;
+	case CODE_RATE_3_4:
+		c->code_rate_LP = FEC_3_4;
+		break;
+	case CODE_RATE_5_6:
+		c->code_rate_LP = FEC_5_6;
+		break;
+	case CODE_RATE_7_8:
+		c->code_rate_LP = FEC_7_8;
+		break;
+	}
+
+	/* extract guard interval */
+	switch (tps.guard_interval) {
+	case GUARD_INT_1_32:
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case GUARD_INT_1_16:
+		c->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case GUARD_INT_1_8:
+		c->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case GUARD_INT_1_4:
+		c->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+
+	/* extract transmission mode */
+	switch (tps.transmission_mode) {
+	case TRANS_MODE_2K:
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		break;
+	case TRANS_MODE_8K:
+		c->transmission_mode = TRANSMISSION_MODE_8K;
+		break;
+	}
+
+	return 0;
+}
+
+static int as102_fe_get_tune_settings(struct dvb_frontend *fe,
+			struct dvb_frontend_tune_settings *settings) {
+
+	settings->min_delay_ms = 1000;
+
+	return 0;
+}
+
+static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	int ret = 0;
+	struct as102_state *state = fe->demodulator_priv;
+	struct as10x_tune_status tstate = { 0 };
+
+	/* send abilis command: GET_TUNE_STATUS */
+	ret = state->ops->get_status(state->priv, &tstate);
+	if (ret < 0)
+		return ret;
+
+	state->signal_strength  = tstate.signal_strength;
+	state->ber  = tstate.BER;
+
+	switch (tstate.tune_state) {
+	case TUNE_STATUS_SIGNAL_DVB_OK:
+		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+		break;
+	case TUNE_STATUS_STREAM_DETECTED:
+		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
+			  FE_HAS_VITERBI;
+		break;
+	case TUNE_STATUS_STREAM_TUNED:
+		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
+			  FE_HAS_LOCK | FE_HAS_VITERBI;
+		break;
+	default:
+		*status = TUNE_STATUS_NOT_TUNED;
+	}
+
+	pr_debug("as102: tuner status: 0x%02x, strength %d, per: %d, ber: %d\n",
+		 tstate.tune_state, tstate.signal_strength,
+		 tstate.PER, tstate.BER);
+
+	if (!(*status & FE_HAS_LOCK)) {
+		memset(&state->demod_stats, 0, sizeof(state->demod_stats));
+		return 0;
+	}
+
+	ret = state->ops->get_stats(state->priv, &state->demod_stats);
+	if (ret < 0)
+		memset(&state->demod_stats, 0, sizeof(state->demod_stats));
+
+	return ret;
+}
+
+/*
+ * Note:
+ * - in AS102 SNR=MER
+ *   - the SNR will be returned in linear terms, i.e. not in dB
+ *   - the accuracy equals ±2dB for a SNR range from 4dB to 30dB
+ *   - the accuracy is >2dB for SNR values outside this range
+ */
+static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct as102_state *state = fe->demodulator_priv;
+
+	*snr = state->demod_stats.mer;
+
+	return 0;
+}
+
+static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	struct as102_state *state = fe->demodulator_priv;
+
+	*ber = state->ber;
+
+	return 0;
+}
+
+static int as102_fe_read_signal_strength(struct dvb_frontend *fe,
+					 u16 *strength)
+{
+	struct as102_state *state = fe->demodulator_priv;
+
+	*strength = (((0xffff * 400) * state->signal_strength + 41000) * 2);
+
+	return 0;
+}
+
+static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct as102_state *state = fe->demodulator_priv;
+
+	if (state->demod_stats.has_started)
+		*ucblocks = state->demod_stats.bad_frame_count;
+	else
+		*ucblocks = 0;
+
+	return 0;
+}
+
+static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+	struct as102_state *state = fe->demodulator_priv;
+
+	return state->ops->stream_ctrl(state->priv, acquire,
+				      state->elna_cfg);
+}
+
+static void as102_fe_release(struct dvb_frontend *fe)
+{
+	struct as102_state *state = fe->demodulator_priv;
+
+	kfree(state);
+}
+
+
+static struct dvb_frontend_ops as102_fe_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name			= "Abilis AS102 DVB-T",
+		.frequency_min		= 174000000,
+		.frequency_max		= 862000000,
+		.frequency_stepsize	= 166667,
+		.caps = FE_CAN_INVERSION_AUTO
+			| FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
+			| FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO
+			| FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK
+			| FE_CAN_QAM_AUTO
+			| FE_CAN_TRANSMISSION_MODE_AUTO
+			| FE_CAN_GUARD_INTERVAL_AUTO
+			| FE_CAN_HIERARCHY_AUTO
+			| FE_CAN_RECOVER
+			| FE_CAN_MUTE_TS
+	},
+
+	.set_frontend		= as102_fe_set_frontend,
+	.get_frontend		= as102_fe_get_frontend,
+	.get_tune_settings	= as102_fe_get_tune_settings,
+
+	.read_status		= as102_fe_read_status,
+	.read_snr		= as102_fe_read_snr,
+	.read_ber		= as102_fe_read_ber,
+	.read_signal_strength	= as102_fe_read_signal_strength,
+	.read_ucblocks		= as102_fe_read_ucblocks,
+	.ts_bus_ctrl		= as102_fe_ts_bus_ctrl,
+	.release		= as102_fe_release,
+};
+
+struct dvb_frontend *as102_attach(const char *name,
+				  const struct as102_fe_ops *ops,
+				  void *priv,
+				  uint8_t elna_cfg)
+{
+	struct as102_state *state;
+	struct dvb_frontend *fe;
+
+	state = kzalloc(sizeof(struct as102_state), GFP_KERNEL);
+	if (state == NULL) {
+		pr_err("%s: unable to allocate memory for state\n", __func__);
+		return NULL;
+	}
+	fe = &state->frontend;
+	fe->demodulator_priv = state;
+	state->ops = ops;
+	state->priv = priv;
+	state->elna_cfg = elna_cfg;
+
+	/* init frontend callback ops */
+	memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops));
+	strncpy(fe->ops.info.name, name, sizeof(fe->ops.info.name));
+
+	return fe;
+
+}
+EXPORT_SYMBOL_GPL(as102_attach);
+
+MODULE_DESCRIPTION("as102-fe");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
diff --git a/drivers/media/dvb-frontends/as102_fe.h b/drivers/media/dvb-frontends/as102_fe.h
new file mode 100644
index 0000000..a7c9143
--- /dev/null
+++ b/drivers/media/dvb-frontends/as102_fe.h
@@ -0,0 +1,29 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2014 Mauro Carvalho Chehab <m.chehab@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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 "as102_fe_types.h"
+
+struct as102_fe_ops {
+	int (*set_tune)(void *priv, struct as10x_tune_args *tune_args);
+	int (*get_tps)(void *priv, struct as10x_tps *tps);
+	int (*get_status)(void *priv, struct as10x_tune_status *tstate);
+	int (*get_stats)(void *priv, struct as10x_demod_stats *demod_stats);
+	int (*stream_ctrl)(void *priv, int acquire, uint32_t elna_cfg);
+};
+
+struct dvb_frontend *as102_attach(const char *name,
+				  const struct as102_fe_ops *ops,
+				  void *priv,
+				  uint8_t elna_cfg);
diff --git a/drivers/media/dvb-frontends/as102_fe_types.h b/drivers/media/dvb-frontends/as102_fe_types.h
new file mode 100644
index 0000000..80a5398
--- /dev/null
+++ b/drivers/media/dvb-frontends/as102_fe_types.h
@@ -0,0 +1,188 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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.
+ */
+#ifndef _AS10X_TYPES_H_
+#define _AS10X_TYPES_H_
+
+/*********************************/
+/*       MACRO DEFINITIONS       */
+/*********************************/
+
+/* bandwidth constant values */
+#define BW_5_MHZ		0x00
+#define BW_6_MHZ		0x01
+#define BW_7_MHZ		0x02
+#define BW_8_MHZ		0x03
+
+/* hierarchy priority selection values */
+#define HIER_NO_PRIORITY	0x00
+#define HIER_LOW_PRIORITY	0x01
+#define HIER_HIGH_PRIORITY	0x02
+
+/* constellation available values */
+#define CONST_QPSK		0x00
+#define CONST_QAM16		0x01
+#define CONST_QAM64		0x02
+#define CONST_UNKNOWN		0xFF
+
+/* hierarchy available values */
+#define HIER_NONE		0x00
+#define HIER_ALPHA_1		0x01
+#define HIER_ALPHA_2		0x02
+#define HIER_ALPHA_4		0x03
+#define HIER_UNKNOWN		0xFF
+
+/* interleaving available values */
+#define INTLV_NATIVE		0x00
+#define INTLV_IN_DEPTH		0x01
+#define INTLV_UNKNOWN		0xFF
+
+/* code rate available values */
+#define CODE_RATE_1_2		0x00
+#define CODE_RATE_2_3		0x01
+#define CODE_RATE_3_4		0x02
+#define CODE_RATE_5_6		0x03
+#define CODE_RATE_7_8		0x04
+#define CODE_RATE_UNKNOWN	0xFF
+
+/* guard interval available values */
+#define GUARD_INT_1_32		0x00
+#define GUARD_INT_1_16		0x01
+#define GUARD_INT_1_8		0x02
+#define GUARD_INT_1_4		0x03
+#define GUARD_UNKNOWN		0xFF
+
+/* transmission mode available values */
+#define TRANS_MODE_2K		0x00
+#define TRANS_MODE_8K		0x01
+#define TRANS_MODE_4K		0x02
+#define TRANS_MODE_UNKNOWN	0xFF
+
+/* DVBH signalling available values */
+#define TIMESLICING_PRESENT	0x01
+#define MPE_FEC_PRESENT		0x02
+
+/* tune state available */
+#define TUNE_STATUS_NOT_TUNED		0x00
+#define TUNE_STATUS_IDLE		0x01
+#define TUNE_STATUS_LOCKING		0x02
+#define TUNE_STATUS_SIGNAL_DVB_OK	0x03
+#define TUNE_STATUS_STREAM_DETECTED	0x04
+#define TUNE_STATUS_STREAM_TUNED	0x05
+#define TUNE_STATUS_ERROR		0xFF
+
+/* available TS FID filter types */
+#define TS_PID_TYPE_TS		0
+#define TS_PID_TYPE_PSI_SI	1
+#define TS_PID_TYPE_MPE		2
+
+/* number of echos available */
+#define MAX_ECHOS	15
+
+/* Context types */
+#define CONTEXT_LNA			1010
+#define CONTEXT_ELNA_HYSTERESIS		4003
+#define CONTEXT_ELNA_GAIN		4004
+#define CONTEXT_MER_THRESHOLD		5005
+#define CONTEXT_MER_OFFSET		5006
+#define CONTEXT_IR_STATE		7000
+#define CONTEXT_TSOUT_MSB_FIRST		7004
+#define CONTEXT_TSOUT_FALLING_EDGE	7005
+
+/* Configuration modes */
+#define CFG_MODE_ON	0
+#define CFG_MODE_OFF	1
+#define CFG_MODE_AUTO	2
+
+struct as10x_tps {
+	uint8_t modulation;
+	uint8_t hierarchy;
+	uint8_t interleaving_mode;
+	uint8_t code_rate_HP;
+	uint8_t code_rate_LP;
+	uint8_t guard_interval;
+	uint8_t transmission_mode;
+	uint8_t DVBH_mask_HP;
+	uint8_t DVBH_mask_LP;
+	uint16_t cell_ID;
+} __packed;
+
+struct as10x_tune_args {
+	/* frequency */
+	uint32_t freq;
+	/* bandwidth */
+	uint8_t bandwidth;
+	/* hierarchy selection */
+	uint8_t hier_select;
+	/* constellation */
+	uint8_t modulation;
+	/* hierarchy */
+	uint8_t hierarchy;
+	/* interleaving mode */
+	uint8_t interleaving_mode;
+	/* code rate */
+	uint8_t code_rate;
+	/* guard interval */
+	uint8_t guard_interval;
+	/* transmission mode */
+	uint8_t transmission_mode;
+} __packed;
+
+struct as10x_tune_status {
+	/* tune status */
+	uint8_t tune_state;
+	/* signal strength */
+	int16_t signal_strength;
+	/* packet error rate 10^-4 */
+	uint16_t PER;
+	/* bit error rate 10^-4 */
+	uint16_t BER;
+} __packed;
+
+struct as10x_demod_stats {
+	/* frame counter */
+	uint32_t frame_count;
+	/* Bad frame counter */
+	uint32_t bad_frame_count;
+	/* Number of wrong bytes fixed by Reed-Solomon */
+	uint32_t bytes_fixed_by_rs;
+	/* Averaged MER */
+	uint16_t mer;
+	/* statistics calculation state indicator (started or not) */
+	uint8_t has_started;
+} __packed;
+
+struct as10x_ts_filter {
+	uint16_t pid;  /* valid PID value 0x00 : 0x2000 */
+	uint8_t  type; /* Red TS_PID_TYPE_<N> values */
+	uint8_t  idx;  /* index in filtering table */
+} __packed;
+
+struct as10x_register_value {
+	uint8_t mode;
+	union {
+		uint8_t  value8;   /* 8 bit value */
+		uint16_t value16;  /* 16 bit value */
+		uint32_t value32;  /* 32 bit value */
+	} __packed u;
+} __packed;
+
+struct as10x_register_addr {
+	/* register addr */
+	uint32_t addr;
+	/* register mode access */
+	uint8_t mode;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c
index 39a29dd..638c7aa 100644
--- a/drivers/media/dvb-frontends/bcm3510.c
+++ b/drivers/media/dvb-frontends/bcm3510.c
@@ -639,12 +639,12 @@
 		err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
 		return ret;
 	}
-	deb_info("got firmware: %zd\n",fw->size);
+	deb_info("got firmware: %zu\n", fw->size);
 
 	b = fw->data;
 	for (i = 0; i < fw->size;) {
-		addr = le16_to_cpu( *( (u16 *)&b[i] ) );
-		len  = le16_to_cpu( *( (u16 *)&b[i+2] ) );
+		addr = le16_to_cpu(*((__le16 *)&b[i]));
+		len  = le16_to_cpu(*((__le16 *)&b[i+2]));
 		deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size);
 		if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
 			err("firmware download failed: %d\n",ret);
diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c
index 0f4657e..149fdca 100644
--- a/drivers/media/dvb-frontends/cxd2820r_c.c
+++ b/drivers/media/dvb-frontends/cxd2820r_c.c
@@ -65,7 +65,7 @@
 	}
 
 	priv->delivery_system = SYS_DVBC_ANNEX_A;
-	priv->ber_running = 0; /* tune stops BER counter */
+	priv->ber_running = false; /* tune stops BER counter */
 
 	/* program IF frequency */
 	if (fe->ops.tuner_ops.get_if_frequency) {
@@ -168,7 +168,7 @@
 			start_ber = 1;
 		}
 	} else {
-		priv->ber_running = 1;
+		priv->ber_running = true;
 		start_ber = 1;
 	}
 
diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c
index 03930d5..422e84b 100644
--- a/drivers/media/dvb-frontends/cxd2820r_core.c
+++ b/drivers/media/dvb-frontends/cxd2820r_core.c
@@ -564,10 +564,10 @@
 
 	/* check if we have a valid signal */
 	if (status & FE_HAS_LOCK) {
-		priv->last_tune_failed = 0;
+		priv->last_tune_failed = false;
 		return DVBFE_ALGO_SEARCH_SUCCESS;
 	} else {
-		priv->last_tune_failed = 1;
+		priv->last_tune_failed = true;
 		return DVBFE_ALGO_SEARCH_AGAIN;
 	}
 
@@ -584,18 +584,14 @@
 static void cxd2820r_release(struct dvb_frontend *fe)
 {
 	struct cxd2820r_priv *priv = fe->demodulator_priv;
-	int uninitialized_var(ret); /* silence compiler warning */
 
 	dev_dbg(&priv->i2c->dev, "%s\n", __func__);
 
 #ifdef CONFIG_GPIOLIB
 	/* remove GPIOs */
-	if (priv->gpio_chip.label) {
-		ret = gpiochip_remove(&priv->gpio_chip);
-		if (ret)
-			dev_err(&priv->i2c->dev, "%s: gpiochip_remove() " \
-					"failed=%d\n", KBUILD_MODNAME, ret);
-	}
+	if (priv->gpio_chip.label)
+		gpiochip_remove(&priv->gpio_chip);
+
 #endif
 	kfree(priv);
 	return;
diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c
index 9b5a45b..51401d0 100644
--- a/drivers/media/dvb-frontends/cxd2820r_t.c
+++ b/drivers/media/dvb-frontends/cxd2820r_t.c
@@ -89,7 +89,7 @@
 	}
 
 	priv->delivery_system = SYS_DVBT;
-	priv->ber_running = 0; /* tune stops BER counter */
+	priv->ber_running = false; /* tune stops BER counter */
 
 	/* program IF frequency */
 	if (fe->ops.tuner_ops.get_if_frequency) {
@@ -272,7 +272,7 @@
 			start_ber = 1;
 		}
 	} else {
-		priv->ber_running = 1;
+		priv->ber_running = true;
 		start_ber = 1;
 	}
 
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index 661760d..589134e 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -2559,7 +2559,7 @@
 	dib7000p_write_word(state, 1288, reg_1288);
 }
 
-int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
+static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
 	u16 reg_1287;
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c
index 7ca7a21..5ec221f 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -2174,7 +2174,7 @@
 				     u32 addr,
 				     u32 *data, u32 flags)
 {
-	u8 buf[sizeof(*data)];
+	u8 buf[sizeof(*data)] = { 0 };
 	int rc = -EIO;
 	u32 word = 0;
 
@@ -4193,7 +4193,7 @@
 					 u32 addr,
 					 u16 *data, u32 flags)
 {
-	u8 buf[2];
+	u8 buf[2] = { 0 };
 	int rc = -EIO;
 	u16 word = 0;
 
@@ -10667,7 +10667,7 @@
 	enum drx_standard standard = ext_attr->standard;
 	int rc;
 	u32 ber, cnt, err, pkt;
-	u16 mer, strength;
+	u16 mer, strength = 0;
 
 	rc = get_sig_strength(demod, &strength);
 	if (rc < 0) {
@@ -11602,7 +11602,7 @@
 	u32 carry = 0;
 
 	while (i < nr_words) {
-		crc_word |= (u32)be16_to_cpu(*(u32 *)(block_data));
+		crc_word |= (u32)be16_to_cpu(*(__be16 *)(block_data));
 		for (j = 0; j < 16; j++) {
 			crc_word <<= 1;
 			if (carry != 0)
@@ -11629,7 +11629,7 @@
 	int i;
 	unsigned count = 2 * sizeof(u16);
 	u32 mc_dev_type, mc_version, mc_base_version;
-	u16 mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data + sizeof(u16)));
+	u16 mc_nr_of_blks = be16_to_cpu(*(__be16 *)(mc_data + sizeof(u16)));
 
 	/*
 	 * Scan microcode blocks first for version info
@@ -11647,13 +11647,13 @@
 			goto eof;
 
 		/* Process block header */
-		block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data + count));
+		block_hdr.addr = be32_to_cpu(*(__be32 *)(mc_data + count));
 		count += sizeof(u32);
-		block_hdr.size = be16_to_cpu(*(u32 *)(mc_data + count));
+		block_hdr.size = be16_to_cpu(*(__be16 *)(mc_data + count));
 		count += sizeof(u16);
-		block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data + count));
+		block_hdr.flags = be16_to_cpu(*(__be16 *)(mc_data + count));
 		count += sizeof(u16);
-		block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data + count));
+		block_hdr.CRC = be16_to_cpu(*(__be16 *)(mc_data + count));
 		count += sizeof(u16);
 
 		pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
@@ -11667,7 +11667,7 @@
 			if (block_hdr.addr + sizeof(u16) > size)
 				goto eof;
 
-			auxtype = be16_to_cpu(*(u32 *)(auxblk));
+			auxtype = be16_to_cpu(*(__be16 *)(auxblk));
 
 			/* Aux block. Check type */
 			if (DRX_ISMCVERTYPE(auxtype)) {
@@ -11675,11 +11675,11 @@
 					goto eof;
 
 				auxblk += sizeof(u16);
-				mc_dev_type = be32_to_cpu(*(u32 *)(auxblk));
+				mc_dev_type = be32_to_cpu(*(__be32 *)(auxblk));
 				auxblk += sizeof(u32);
-				mc_version = be32_to_cpu(*(u32 *)(auxblk));
+				mc_version = be32_to_cpu(*(__be32 *)(auxblk));
 				auxblk += sizeof(u32);
-				mc_base_version = be32_to_cpu(*(u32 *)(auxblk));
+				mc_base_version = be32_to_cpu(*(__be32 *)(auxblk));
 
 				DRX_ATTR_MCRECORD(demod).aux_type = auxtype;
 				DRX_ATTR_MCRECORD(demod).mc_dev_type = mc_dev_type;
@@ -11765,9 +11765,9 @@
 
 	mc_data = (void *)mc_data_init;
 	/* Check data */
-	mc_magic_word = be16_to_cpu(*(u32 *)(mc_data));
+	mc_magic_word = be16_to_cpu(*(__be16 *)(mc_data));
 	mc_data += sizeof(u16);
-	mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data));
+	mc_nr_of_blks = be16_to_cpu(*(__be16 *)(mc_data));
 	mc_data += sizeof(u16);
 
 	if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) {
@@ -11791,13 +11791,13 @@
 		u16 mc_block_nr_bytes = 0;
 
 		/* Process block header */
-		block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data));
+		block_hdr.addr = be32_to_cpu(*(__be32 *)(mc_data));
 		mc_data += sizeof(u32);
-		block_hdr.size = be16_to_cpu(*(u32 *)(mc_data));
+		block_hdr.size = be16_to_cpu(*(__be16 *)(mc_data));
 		mc_data += sizeof(u16);
-		block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data));
+		block_hdr.flags = be16_to_cpu(*(__be16 *)(mc_data));
 		mc_data += sizeof(u16);
-		block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data));
+		block_hdr.CRC = be16_to_cpu(*(__be16 *)(mc_data));
 		mc_data += sizeof(u16);
 
 		pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c
index ae2276d..687e893 100644
--- a/drivers/media/dvb-frontends/drxd_hard.c
+++ b/drivers/media/dvb-frontends/drxd_hard.c
@@ -2628,10 +2628,11 @@
 			break;
 
 		/* Apply I2c address patch to B1 */
-		if (!state->type_A && state->m_HiI2cPatch != NULL)
+		if (!state->type_A && state->m_HiI2cPatch != NULL) {
 			status = WriteTable(state, state->m_HiI2cPatch);
 			if (status < 0)
 				break;
+		}
 
 		if (state->type_A) {
 			/* HI firmware patch for UIO readout,
@@ -2830,14 +2831,8 @@
 static int drxd_init(struct dvb_frontend *fe)
 {
 	struct drxd_state *state = fe->demodulator_priv;
-	int err = 0;
 
-/*	if (request_firmware(&state->fw, "drxd.fw", state->dev)<0) */
 	return DRXD_init(state, NULL, 0);
-
-	err = DRXD_init(state, state->fw->data, state->fw->size);
-	release_firmware(state->fw);
-	return err;
 }
 
 static int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index cce94a7..6721951 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -1028,7 +1028,7 @@
 		    ((state->m_hi_cfg_ctrl) &
 		     SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) ==
 		    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ);
-	if (powerdown_cmd == false) {
+	if (!powerdown_cmd) {
 		/* Wait until command rdy */
 		u32 retry_count = 0;
 		u16 wait_cmd;
@@ -1129,7 +1129,7 @@
 	if (status < 0)
 		goto error;
 
-	if (mpeg_enable == false) {
+	if (!mpeg_enable) {
 		/*  Set MPEG TS pads to inputmode */
 		status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000);
 		if (status < 0)
@@ -1190,7 +1190,7 @@
 		if (status < 0)
 			goto error;
 
-		if (state->m_enable_parallel == true) {
+		if (state->m_enable_parallel) {
 			/* parallel -> enable MD1 to MD7 */
 			status = write16(state, SIO_PDR_MD1_CFG__A,
 					 sio_pdr_mdx_cfg);
@@ -1392,7 +1392,7 @@
 
 	dprintk(1, "\n");
 
-	if (enable == false) {
+	if (!enable) {
 		desired_ctrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF;
 		desired_status = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN;
 	}
@@ -2012,7 +2012,7 @@
 		goto error;
 	fec_oc_reg_mode &= (~FEC_OC_MODE_PARITY__M);
 	fec_oc_reg_ipr_mode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
-	if (state->m_insert_rs_byte == true) {
+	if (state->m_insert_rs_byte) {
 		/* enable parity symbol forward */
 		fec_oc_reg_mode |= FEC_OC_MODE_PARITY__M;
 		/* MVAL disable during parity bytes */
@@ -2023,7 +2023,7 @@
 
 	/* Check serial or parallel output */
 	fec_oc_reg_ipr_mode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
-	if (state->m_enable_parallel == false) {
+	if (!state->m_enable_parallel) {
 		/* MPEG data output is serial -> set ipr_mode[0] */
 		fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_SERIAL__M;
 	}
@@ -2136,19 +2136,19 @@
 
 	/* Control selective inversion of output bits */
 	fec_oc_reg_ipr_invert &= (~(invert_data_mask));
-	if (state->m_invert_data == true)
+	if (state->m_invert_data)
 		fec_oc_reg_ipr_invert |= invert_data_mask;
 	fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MERR__M));
-	if (state->m_invert_err == true)
+	if (state->m_invert_err)
 		fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MERR__M;
 	fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
-	if (state->m_invert_str == true)
+	if (state->m_invert_str)
 		fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MSTRT__M;
 	fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
-	if (state->m_invert_val == true)
+	if (state->m_invert_val)
 		fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MVAL__M;
 	fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
-	if (state->m_invert_clk == true)
+	if (state->m_invert_clk)
 		fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MCLK__M;
 
 	return write16(state, FEC_OC_IPR_INVERT__A, fec_oc_reg_ipr_invert);
@@ -2220,12 +2220,13 @@
 		}
 
 		/* Set TOP, only if IF-AGC is in AUTO mode */
-		if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO)
+		if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO) {
 			status = write16(state,
 					 SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A,
 					 p_agc_cfg->top);
 			if (status < 0)
 				goto error;
+		}
 
 		/* Cut-Off current */
 		status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A,
@@ -3352,7 +3353,7 @@
 	int status;
 
 	dprintk(1, "\n");
-	if (*enabled == true)
+	if (*enabled)
 		status = write16(state, IQM_CF_BYPASSDET__A, 0);
 	else
 		status = write16(state, IQM_CF_BYPASSDET__A, 1);
@@ -3368,7 +3369,7 @@
 	int status;
 
 	dprintk(1, "\n");
-	if (*enabled == true) {
+	if (*enabled) {
 		/* write mask to 1 */
 		status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A,
 				   DEFAULT_FR_THRES_8K);
@@ -6794,11 +6795,11 @@
 	state->enable_merr_cfg = config->enable_merr_cfg;
 
 	if (config->dynamic_clk) {
-		state->m_dvbt_static_clk = 0;
-		state->m_dvbc_static_clk = 0;
+		state->m_dvbt_static_clk = false;
+		state->m_dvbc_static_clk = false;
 	} else {
-		state->m_dvbt_static_clk = 1;
-		state->m_dvbc_static_clk = 1;
+		state->m_dvbt_static_clk = true;
+		state->m_dvbc_static_clk = true;
 	}
 
 
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index dfe0c2f..81657e9 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -159,6 +159,7 @@
 {
 	int ret, i, j;
 	u8 buf[83];
+
 	dev_dbg(&priv->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len);
 
 	if (tab_len > 83) {
@@ -247,8 +248,9 @@
 	u8 u8tmp, u8tmp1, u8tmp2;
 	u8 buf[2];
 	u16 u16tmp, divide_ratio;
-	u32 tuner_frequency, target_mclk, ts_clk;
+	u32 tuner_frequency, target_mclk;
 	s32 s32tmp;
+
 	dev_dbg(&priv->i2c->dev,
 			"%s: delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n",
 			__func__, c->delivery_system,
@@ -316,9 +318,6 @@
 				target_mclk = 144000;
 			break;
 		case M88DS3103_TS_PARALLEL:
-		case M88DS3103_TS_PARALLEL_12:
-		case M88DS3103_TS_PARALLEL_16:
-		case M88DS3103_TS_PARALLEL_19_2:
 		case M88DS3103_TS_CI:
 			if (c->symbol_rate < 18000000)
 				target_mclk = 96000;
@@ -352,33 +351,17 @@
 	switch (priv->cfg->ts_mode) {
 	case M88DS3103_TS_SERIAL:
 		u8tmp1 = 0x00;
-		ts_clk = 0;
-		u8tmp = 0x46;
+		u8tmp = 0x06;
 		break;
 	case M88DS3103_TS_SERIAL_D7:
 		u8tmp1 = 0x20;
-		ts_clk = 0;
-		u8tmp = 0x46;
+		u8tmp = 0x06;
 		break;
 	case M88DS3103_TS_PARALLEL:
-		ts_clk = 24000;
-		u8tmp = 0x42;
-		break;
-	case M88DS3103_TS_PARALLEL_12:
-		ts_clk = 12000;
-		u8tmp = 0x42;
-		break;
-	case M88DS3103_TS_PARALLEL_16:
-		ts_clk = 16000;
-		u8tmp = 0x42;
-		break;
-	case M88DS3103_TS_PARALLEL_19_2:
-		ts_clk = 19200;
-		u8tmp = 0x42;
+		u8tmp = 0x02;
 		break;
 	case M88DS3103_TS_CI:
-		ts_clk = 6000;
-		u8tmp = 0x43;
+		u8tmp = 0x03;
 		break;
 	default:
 		dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n", __func__);
@@ -386,6 +369,9 @@
 		goto err;
 	}
 
+	if (priv->cfg->ts_clk_pol)
+		u8tmp |= 0x40;
+
 	/* TS mode */
 	ret = m88ds3103_wr_reg(priv, 0xfd, u8tmp);
 	if (ret)
@@ -399,8 +385,8 @@
 			goto err;
 	}
 
-	if (ts_clk) {
-		divide_ratio = DIV_ROUND_UP(target_mclk, ts_clk);
+	if (priv->cfg->ts_clk) {
+		divide_ratio = DIV_ROUND_UP(target_mclk, priv->cfg->ts_clk);
 		u8tmp1 = divide_ratio / 2;
 		u8tmp2 = DIV_ROUND_UP(divide_ratio, 2);
 	} else {
@@ -411,7 +397,7 @@
 
 	dev_dbg(&priv->i2c->dev,
 			"%s: target_mclk=%d ts_clk=%d divide_ratio=%d\n",
-			__func__, target_mclk, ts_clk, divide_ratio);
+			__func__, target_mclk, priv->cfg->ts_clk, divide_ratio);
 
 	u8tmp1--;
 	u8tmp2--;
@@ -536,6 +522,7 @@
 	const struct firmware *fw = NULL;
 	u8 *fw_file = M88DS3103_FIRMWARE;
 	u8 u8tmp;
+
 	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
 	/* set cold state by default */
@@ -648,6 +635,7 @@
 {
 	struct m88ds3103_priv *priv = fe->demodulator_priv;
 	int ret;
+
 	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
 	priv->delivery_system = SYS_UNDEFINED;
@@ -682,6 +670,7 @@
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret;
 	u8 buf[3];
+
 	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
 	if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) {
@@ -857,6 +846,7 @@
 	u8 buf[3];
 	u16 noise, signal;
 	u32 noise_tot, signal_tot;
+
 	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 	/* reports SNR in resolution of 0.1 dB */
 
@@ -933,6 +923,7 @@
 	int ret;
 	unsigned int utmp;
 	u8 buf[3], u8tmp;
+
 	dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
 
 	switch (c->delivery_system) {
@@ -1013,6 +1004,7 @@
 	struct m88ds3103_priv *priv = fe->demodulator_priv;
 	int ret;
 	u8 u8tmp, tone, reg_a1_mask;
+
 	dev_dbg(&priv->i2c->dev, "%s: fe_sec_tone_mode=%d\n", __func__,
 			fe_sec_tone_mode);
 
@@ -1053,12 +1045,64 @@
 	return ret;
 }
 
+static int m88ds3103_set_voltage(struct dvb_frontend *fe,
+	fe_sec_voltage_t fe_sec_voltage)
+{
+	struct m88ds3103_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 u8tmp;
+	bool voltage_sel, voltage_dis;
+
+	dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__,
+			fe_sec_voltage);
+
+	if (!priv->warm) {
+		ret = -EAGAIN;
+		goto err;
+	}
+
+	switch (fe_sec_voltage) {
+	case SEC_VOLTAGE_18:
+		voltage_sel = true;
+		voltage_dis = false;
+		break;
+	case SEC_VOLTAGE_13:
+		voltage_sel = false;
+		voltage_dis = false;
+		break;
+	case SEC_VOLTAGE_OFF:
+		voltage_sel = false;
+		voltage_dis = true;
+		break;
+	default:
+		dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_voltage\n",
+				__func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* output pin polarity */
+	voltage_sel ^= priv->cfg->lnb_hv_pol;
+	voltage_dis ^= priv->cfg->lnb_en_pol;
+
+	u8tmp = voltage_dis << 1 | voltage_sel << 0;
+	ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0x03);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
 static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe,
 		struct dvb_diseqc_master_cmd *diseqc_cmd)
 {
 	struct m88ds3103_priv *priv = fe->demodulator_priv;
 	int ret, i;
 	u8 u8tmp;
+
 	dev_dbg(&priv->i2c->dev, "%s: msg=%*ph\n", __func__,
 			diseqc_cmd->msg_len, diseqc_cmd->msg);
 
@@ -1130,6 +1174,7 @@
 	struct m88ds3103_priv *priv = fe->demodulator_priv;
 	int ret, i;
 	u8 u8tmp, burst;
+
 	dev_dbg(&priv->i2c->dev, "%s: fe_sec_mini_cmd=%d\n", __func__,
 			fe_sec_mini_cmd);
 
@@ -1202,6 +1247,7 @@
 static void m88ds3103_release(struct dvb_frontend *fe)
 {
 	struct m88ds3103_priv *priv = fe->demodulator_priv;
+
 	i2c_del_mux_adapter(priv->i2c_adapter);
 	kfree(priv);
 }
@@ -1370,6 +1416,7 @@
 	.diseqc_send_burst = m88ds3103_diseqc_send_burst,
 
 	.set_tone = m88ds3103_set_tone,
+	.set_voltage = m88ds3103_set_voltage,
 };
 
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/dvb-frontends/m88ds3103.h b/drivers/media/dvb-frontends/m88ds3103.h
index 2fac2b2..ca13246 100644
--- a/drivers/media/dvb-frontends/m88ds3103.h
+++ b/drivers/media/dvb-frontends/m88ds3103.h
@@ -47,14 +47,23 @@
 	 */
 #define M88DS3103_TS_SERIAL             0 /* TS output pin D0, normal */
 #define M88DS3103_TS_SERIAL_D7          1 /* TS output pin D7 */
-#define M88DS3103_TS_PARALLEL           2 /* 24 MHz, normal */
-#define M88DS3103_TS_PARALLEL_12        3 /* 12 MHz */
-#define M88DS3103_TS_PARALLEL_16        4 /* 16 MHz */
-#define M88DS3103_TS_PARALLEL_19_2      5 /* 19.2 MHz */
-#define M88DS3103_TS_CI                 6 /* 6 MHz */
+#define M88DS3103_TS_PARALLEL           2 /* TS Parallel mode */
+#define M88DS3103_TS_CI                 3 /* TS CI Mode */
 	u8 ts_mode;
 
 	/*
+	 * TS clk in KHz
+	 * Default: 0.
+	 */
+	u32 ts_clk;
+
+	/*
+	 * TS clk polarity.
+	 * Default: 0. 1-active at falling edge; 0-active at rising edge.
+	 */
+	u8 ts_clk_pol:1;
+
+	/*
 	 * spectrum inversion
 	 * Default: 0
 	 */
@@ -86,6 +95,22 @@
 	 * Default: none, must set
 	 */
 	u8 agc;
+
+	/*
+	 * LNB H/V pin polarity
+	 * Default: 0.
+	 * 1: pin high set to VOLTAGE_13, pin low to set VOLTAGE_18.
+	 * 0: pin high set to VOLTAGE_18, pin low to set VOLTAGE_13.
+	 */
+	u8 lnb_hv_pol:1;
+
+	/*
+	 * LNB enable pin polarity
+	 * Default: 0.
+	 * 1: pin high to enable, pin low to disable.
+	 * 0: pin high to disable, pin low to enable.
+	 */
+	u8 lnb_en_pol:1;
 };
 
 /*
diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c
index 9ae40ab..3ddea44 100644
--- a/drivers/media/dvb-frontends/mb86a16.c
+++ b/drivers/media/dvb-frontends/mb86a16.c
@@ -28,7 +28,7 @@
 #include "mb86a16.h"
 #include "mb86a16_priv.h"
 
-unsigned int verbose = 5;
+static unsigned int verbose = 5;
 module_param(verbose, int, 0644);
 
 #define ABS(x)		((x) < 0 ? (-x) : (x))
@@ -115,9 +115,11 @@
 	};
 	ret = i2c_transfer(state->i2c_adap, msg, 2);
 	if (ret != 2) {
-		dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)",
+		dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=%i)",
 			reg, ret);
 
+		if (ret < 0)
+			return ret;
 		return -EREMOTEIO;
 	}
 	*val = b1[0];
diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c
index b931179..e6f165a 100644
--- a/drivers/media/dvb-frontends/mb86a20s.c
+++ b/drivers/media/dvb-frontends/mb86a20s.c
@@ -33,7 +33,7 @@
 	MB86A20S_3SEG = 3,
 };
 
-u8 mb86a20s_subchannel[] = {
+static u8 mb86a20s_subchannel[] = {
 	0xb0, 0xc0, 0xd0, 0xe0,
 	0xf0, 0x00, 0x10, 0x20,
 };
@@ -1228,7 +1228,7 @@
  * All tables below return a dB/1000 measurement
  */
 
-static struct linear_segments cnr_to_db_table[] = {
+static const struct linear_segments cnr_to_db_table[] = {
 	{ 19648,     0},
 	{ 18187,  1000},
 	{ 16534,  2000},
@@ -1262,7 +1262,7 @@
 	{   788, 30000},
 };
 
-static struct linear_segments cnr_64qam_table[] = {
+static const struct linear_segments cnr_64qam_table[] = {
 	{ 3922688,     0},
 	{ 3920384,  1000},
 	{ 3902720,  2000},
@@ -1296,7 +1296,7 @@
 	{  388864, 30000},
 };
 
-static struct linear_segments cnr_16qam_table[] = {
+static const struct linear_segments cnr_16qam_table[] = {
 	{ 5314816,     0},
 	{ 5219072,  1000},
 	{ 5118720,  2000},
@@ -1330,7 +1330,7 @@
 	{   95744, 30000},
 };
 
-struct linear_segments cnr_qpsk_table[] = {
+static const struct linear_segments cnr_qpsk_table[] = {
 	{ 2834176,     0},
 	{ 2683648,  1000},
 	{ 2536960,  2000},
@@ -1364,7 +1364,7 @@
 	{   11520, 30000},
 };
 
-static u32 interpolate_value(u32 value, struct linear_segments *segments,
+static u32 interpolate_value(u32 value, const struct linear_segments *segments,
 			     unsigned len)
 {
 	u64 tmp64;
@@ -1448,7 +1448,7 @@
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	u32 mer, cnr;
 	int rc, val, layer;
-	struct linear_segments *segs;
+	const struct linear_segments *segs;
 	unsigned segs_len;
 
 	dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c
index a74ac0d..2163490 100644
--- a/drivers/media/dvb-frontends/mt312.c
+++ b/drivers/media/dvb-frontends/mt312.c
@@ -103,7 +103,7 @@
 
 	if (1 + count > sizeof(buf)) {
 		printk(KERN_WARNING
-		       "mt312: write: len=%zd is too big!\n", count);
+		       "mt312: write: len=%zu is too big!\n", count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c
index 10cfc05..873ea1d 100644
--- a/drivers/media/dvb-frontends/or51211.c
+++ b/drivers/media/dvb-frontends/or51211.c
@@ -111,7 +111,7 @@
 	u8 tudata[585];
 	int i;
 
-	dprintk("Firmware is %zd bytes\n",fw->size);
+	dprintk("Firmware is %zu bytes\n", fw->size);
 
 	/* Get eprom data */
 	tudata[0] = 17;
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index fdbed35..eb737cf 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -936,7 +936,7 @@
 	if (ret != 1)
 		goto err;
 
-	priv->i2c_gate_state = 0;
+	priv->i2c_gate_state = false;
 
 	return;
 err:
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index 023e0f4..7bf98cf 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -329,7 +329,7 @@
 static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf(
 		struct rtl2832_sdr_state *s)
 {
-	unsigned long flags = 0;
+	unsigned long flags;
 	struct rtl2832_sdr_frame_buf *buf = NULL;
 
 	spin_lock_irqsave(&s->queued_bufs_lock, flags);
@@ -365,17 +365,19 @@
 		dst_len = 0;
 	}
 
-	/* calculate samping rate and output it in 10 seconds intervals */
+	/* calculate sample rate and output it in 10 seconds intervals */
 	if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
-#define MSECS 10000UL
+		#define MSECS 10000UL
+		unsigned int msecs = jiffies_to_msecs(jiffies -
+				s->jiffies_next + msecs_to_jiffies(MSECS));
 		unsigned int samples = s->sample - s->sample_measured;
 
 		s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
 		s->sample_measured = s->sample;
 		dev_dbg(&s->udev->dev,
-				"slen=%d samples=%u msecs=%lu sampling rate=%lu\n",
-				src_len, samples, MSECS,
-				samples * 1000UL / MSECS);
+				"slen=%u samples=%u msecs=%u sample rate=%lu\n",
+				src_len, samples, msecs,
+				samples * 1000UL / msecs);
 	}
 
 	/* total number of I+Q pairs */
@@ -394,8 +396,8 @@
 	struct rtl2832_sdr_frame_buf *fbuf;
 
 	dev_dbg_ratelimited(&s->udev->dev,
-			"%s: status=%d length=%d/%d errors=%d\n",
-			__func__, urb->status, urb->actual_length,
+			"status=%d length=%d/%d errors=%d\n",
+			urb->status, urb->actual_length,
 			urb->transfer_buffer_length, urb->error_count);
 
 	switch (urb->status) {
@@ -443,7 +445,7 @@
 	int i;
 
 	for (i = s->urbs_submitted - 1; i >= 0; i--) {
-		dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i);
+		dev_dbg(&s->udev->dev, "kill urb=%d\n", i);
 		/* stop the URB */
 		usb_kill_urb(s->urb_list[i]);
 	}
@@ -457,7 +459,7 @@
 	int i, ret;
 
 	for (i = 0; i < s->urbs_initialized; i++) {
-		dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i);
+		dev_dbg(&s->udev->dev, "submit urb=%d\n", i);
 		ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC);
 		if (ret) {
 			dev_err(&s->udev->dev,
@@ -477,8 +479,7 @@
 	if (s->flags & USB_STATE_URB_BUF) {
 		while (s->buf_num) {
 			s->buf_num--;
-			dev_dbg(&s->udev->dev, "%s: free buf=%d\n",
-					__func__, s->buf_num);
+			dev_dbg(&s->udev->dev, "free buf=%d\n", s->buf_num);
 			usb_free_coherent(s->udev, s->buf_size,
 					  s->buf_list[s->buf_num],
 					  s->dma_addr[s->buf_num]);
@@ -494,24 +495,22 @@
 	s->buf_num = 0;
 	s->buf_size = BULK_BUFFER_SIZE;
 
-	dev_dbg(&s->udev->dev,
-			"%s: all in all I will use %u bytes for streaming\n",
-			__func__,  MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+	dev_dbg(&s->udev->dev, "all in all I will use %u bytes for streaming\n",
+			MAX_BULK_BUFS * BULK_BUFFER_SIZE);
 
 	for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) {
 		s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev,
 				BULK_BUFFER_SIZE, GFP_ATOMIC,
 				&s->dma_addr[s->buf_num]);
 		if (!s->buf_list[s->buf_num]) {
-			dev_dbg(&s->udev->dev, "%s: alloc buf=%d failed\n",
-					__func__, s->buf_num);
+			dev_dbg(&s->udev->dev, "alloc buf=%d failed\n",
+					s->buf_num);
 			rtl2832_sdr_free_stream_bufs(s);
 			return -ENOMEM;
 		}
 
-		dev_dbg(&s->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
-				__func__, s->buf_num,
-				s->buf_list[s->buf_num],
+		dev_dbg(&s->udev->dev, "alloc buf=%d %p (dma %llu)\n",
+				s->buf_num, s->buf_list[s->buf_num],
 				(long long)s->dma_addr[s->buf_num]);
 		s->flags |= USB_STATE_URB_BUF;
 	}
@@ -527,8 +526,7 @@
 
 	for (i = s->urbs_initialized - 1; i >= 0; i--) {
 		if (s->urb_list[i]) {
-			dev_dbg(&s->udev->dev, "%s: free urb=%d\n",
-					__func__, i);
+			dev_dbg(&s->udev->dev, "free urb=%d\n", i);
 			/* free the URBs */
 			usb_free_urb(s->urb_list[i]);
 		}
@@ -544,10 +542,10 @@
 
 	/* allocate the URBs */
 	for (i = 0; i < MAX_BULK_BUFS; i++) {
-		dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+		dev_dbg(&s->udev->dev, "alloc urb=%d\n", i);
 		s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
 		if (!s->urb_list[i]) {
-			dev_dbg(&s->udev->dev, "%s: failed\n", __func__);
+			dev_dbg(&s->udev->dev, "failed\n");
 			for (j = 0; j < i; j++)
 				usb_free_urb(s->urb_list[j]);
 			return -ENOMEM;
@@ -570,9 +568,9 @@
 /* Must be called with vb_queue_lock hold */
 static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s)
 {
-	unsigned long flags = 0;
+	unsigned long flags;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(&s->udev->dev, "\n");
 
 	spin_lock_irqsave(&s->queued_bufs_lock, flags);
 	while (!list_empty(&s->queued_bufs)) {
@@ -591,7 +589,7 @@
 {
 	struct rtl2832_sdr_state *s = fe->sec_priv;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(&s->udev->dev, "\n");
 
 	mutex_lock(&s->vb_queue_lock);
 	mutex_lock(&s->v4l2_lock);
@@ -613,7 +611,7 @@
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(&s->udev->dev, "\n");
 
 	strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
 	strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
@@ -631,15 +629,15 @@
 {
 	struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
 
-	dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
+	dev_dbg(&s->udev->dev, "nbuffers=%d\n", *nbuffers);
 
 	/* Need at least 8 buffers */
 	if (vq->num_buffers + *nbuffers < 8)
 		*nbuffers = 8 - vq->num_buffers;
 	*nplanes = 1;
 	sizes[0] = PAGE_ALIGN(s->buffersize);
-	dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
-			__func__, *nbuffers, sizes[0]);
+	dev_dbg(&s->udev->dev, "nbuffers=%d sizes[0]=%d\n",
+			*nbuffers, sizes[0]);
 	return 0;
 }
 
@@ -659,7 +657,7 @@
 	struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue);
 	struct rtl2832_sdr_frame_buf *buf =
 			container_of(vb, struct rtl2832_sdr_frame_buf, vb);
-	unsigned long flags = 0;
+	unsigned long flags;
 
 	/* Check the device has not disconnected between prep and queuing */
 	if (!s->udev) {
@@ -681,7 +679,7 @@
 	u64 u64tmp;
 	u32 u32tmp;
 
-	dev_dbg(&s->udev->dev, "%s: f_adc=%u\n", __func__, s->f_adc);
+	dev_dbg(&s->udev->dev, "f_adc=%u\n", s->f_adc);
 
 	if (!test_bit(POWER_ON, &s->flags))
 		return 0;
@@ -715,8 +713,7 @@
 	u64tmp = -u64tmp;
 	u32tmp = u64tmp & 0x3fffff;
 
-	dev_dbg(&s->udev->dev, "%s: f_if=%u if_ctl=%08x\n",
-			__func__, f_if, u32tmp);
+	dev_dbg(&s->udev->dev, "f_if=%u if_ctl=%08x\n", f_if, u32tmp);
 
 	buf[0] = (u32tmp >> 16) & 0xff;
 	buf[1] = (u32tmp >>  8) & 0xff;
@@ -903,7 +900,7 @@
 {
 	int ret;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(&s->udev->dev, "\n");
 
 	/* PID filter */
 	ret = rtl2832_sdr_wr_regs(s, 0x061, "\xe0", 1);
@@ -964,8 +961,8 @@
 	c->frequency = s->f_tuner;
 	c->delivery_system = SYS_DVBT;
 
-	dev_dbg(&s->udev->dev, "%s: frequency=%u bandwidth=%d\n",
-			__func__, c->frequency, c->bandwidth_hz);
+	dev_dbg(&s->udev->dev, "frequency=%u bandwidth=%d\n",
+			c->frequency, c->bandwidth_hz);
 
 	if (!test_bit(POWER_ON, &s->flags))
 		return 0;
@@ -980,7 +977,7 @@
 {
 	struct dvb_frontend *fe = s->fe;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(&s->udev->dev, "\n");
 
 	if (fe->ops.tuner_ops.init)
 		fe->ops.tuner_ops.init(fe);
@@ -992,7 +989,7 @@
 {
 	struct dvb_frontend *fe = s->fe;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(&s->udev->dev, "\n");
 
 	if (fe->ops.tuner_ops.sleep)
 		fe->ops.tuner_ops.sleep(fe);
@@ -1005,7 +1002,7 @@
 	struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
 	int ret;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(&s->udev->dev, "\n");
 
 	if (!s->udev)
 		return -ENODEV;
@@ -1054,7 +1051,7 @@
 {
 	struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(&s->udev->dev, "\n");
 
 	mutex_lock(&s->v4l2_lock);
 
@@ -1088,8 +1085,7 @@
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
 
-	dev_dbg(&s->udev->dev, "%s: index=%d type=%d\n",
-			__func__, v->index, v->type);
+	dev_dbg(&s->udev->dev, "index=%d type=%d\n", v->index, v->type);
 
 	if (v->index == 0) {
 		strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name));
@@ -1115,7 +1111,7 @@
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(&s->udev->dev, "\n");
 
 	if (v->index > 1)
 		return -EINVAL;
@@ -1127,8 +1123,8 @@
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
 
-	dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
-			__func__, band->tuner, band->type, band->index);
+	dev_dbg(&s->udev->dev, "tuner=%d type=%d index=%d\n",
+			band->tuner, band->type, band->index);
 
 	if (band->tuner == 0) {
 		if (band->index >= ARRAY_SIZE(bands_adc))
@@ -1153,8 +1149,8 @@
 	struct rtl2832_sdr_state *s = video_drvdata(file);
 	int ret  = 0;
 
-	dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
-			__func__, f->tuner, f->type);
+	dev_dbg(&s->udev->dev, "tuner=%d type=%d\n",
+			f->tuner, f->type);
 
 	if (f->tuner == 0) {
 		f->frequency = s->f_adc;
@@ -1175,8 +1171,8 @@
 	struct rtl2832_sdr_state *s = video_drvdata(file);
 	int ret, band;
 
-	dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
-			__func__, f->tuner, f->type, f->frequency);
+	dev_dbg(&s->udev->dev, "tuner=%d type=%d frequency=%u\n",
+			f->tuner, f->type, f->frequency);
 
 	/* ADC band midpoints */
 	#define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2)
@@ -1194,15 +1190,13 @@
 				bands_adc[band].rangelow,
 				bands_adc[band].rangehigh);
 
-		dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
-				__func__, s->f_adc);
+		dev_dbg(&s->udev->dev, "ADC frequency=%u Hz\n", s->f_adc);
 		ret = rtl2832_sdr_set_adc(s);
 	} else if (f->tuner == 1) {
 		s->f_tuner = clamp_t(unsigned int, f->frequency,
 				bands_fm[0].rangelow,
 				bands_fm[0].rangehigh);
-		dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n",
-				__func__, f->frequency);
+		dev_dbg(&s->udev->dev, "RF frequency=%u Hz\n", f->frequency);
 
 		ret = rtl2832_sdr_set_tuner_freq(s);
 	} else {
@@ -1217,7 +1211,7 @@
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(&s->udev->dev, "\n");
 
 	if (f->index >= s->num_formats)
 		return -EINVAL;
@@ -1233,7 +1227,7 @@
 {
 	struct rtl2832_sdr_state *s = video_drvdata(file);
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(&s->udev->dev, "\n");
 
 	f->fmt.sdr.pixelformat = s->pixelformat;
 	f->fmt.sdr.buffersize = s->buffersize;
@@ -1250,7 +1244,7 @@
 	struct vb2_queue *q = &s->vb_queue;
 	int i;
 
-	dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+	dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n",
 			(char *)&f->fmt.sdr.pixelformat);
 
 	if (vb2_is_busy(q))
@@ -1280,7 +1274,7 @@
 	struct rtl2832_sdr_state *s = video_drvdata(file);
 	int i;
 
-	dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+	dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n",
 			(char *)&f->fmt.sdr.pixelformat);
 
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
@@ -1354,8 +1348,8 @@
 	int ret;
 
 	dev_dbg(&s->udev->dev,
-			"%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
-			__func__, ctrl->id, ctrl->name, ctrl->val,
+			"id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
+			ctrl->id, ctrl->name, ctrl->val,
 			ctrl->minimum, ctrl->maximum, ctrl->step);
 
 	switch (ctrl->id) {
@@ -1432,7 +1426,7 @@
 	s->pixelformat = formats[0].pixelformat;
 	s->buffersize = formats[0].buffersize;
 	s->num_formats = NUM_FORMATS;
-	if (rtl2832_sdr_emulated_fmt == false)
+	if (!rtl2832_sdr_emulated_fmt)
 		s->num_formats -= 1;
 
 	mutex_init(&s->v4l2_lock);
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c
index 3a2d6c5..98ddb49 100644
--- a/drivers/media/dvb-frontends/si2165.c
+++ b/drivers/media/dvb-frontends/si2165.c
@@ -1,5 +1,5 @@
 /*
-    Driver for Silicon Labs SI2165 DVB-C/-T Demodulator
+    Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator
 
     Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org>
 
@@ -44,9 +44,7 @@
 
 	struct si2165_config config;
 
-	/* chip revision */
-	u8 revcode;
-	/* chip type */
+	u8 chip_revcode;
 	u8 chip_type;
 
 	/* calculated by xtal and div settings */
@@ -312,7 +310,7 @@
 	return state->adc_clk;
 }
 
-static bool si2165_wait_init_done(struct si2165_state *state)
+static int si2165_wait_init_done(struct si2165_state *state)
 {
 	int ret = -EINVAL;
 	u8 val = 0;
@@ -407,7 +405,7 @@
 	int ret;
 
 	const struct firmware *fw = NULL;
-	u8 *fw_file = SI2165_FIRMWARE;
+	u8 *fw_file;
 	const u8 *data;
 	u32 len;
 	u32 offset;
@@ -415,10 +413,20 @@
 	u8 block_count;
 	u16 crc_expected;
 
+	switch (state->chip_revcode) {
+	case 0x03: /* revision D */
+		fw_file = SI2165_FIRMWARE_REV_D;
+		break;
+	default:
+		dev_info(&state->i2c->dev, "%s: no firmware file for revision=%d\n",
+			KBUILD_MODNAME, state->chip_revcode);
+		return 0;
+	}
+
 	/* request the firmware, this will block and timeout */
 	ret = request_firmware(&fw, fw_file, state->i2c->dev.parent);
 	if (ret) {
-		dev_warn(&state->i2c->dev, "%s: firmare file '%s' not found\n",
+		dev_warn(&state->i2c->dev, "%s: firmware file '%s' not found\n",
 				KBUILD_MODNAME, fw_file);
 		goto error;
 	}
@@ -908,7 +916,7 @@
 
 static struct dvb_frontend_ops si2165_ops = {
 	.info = {
-		.name = "Silicon Labs Si2165",
+		.name = "Silicon Labs ",
 		.caps =	FE_CAN_FEC_1_2 |
 			FE_CAN_FEC_2_3 |
 			FE_CAN_FEC_3_4 |
@@ -948,6 +956,8 @@
 	int n;
 	int io_ret;
 	u8 val;
+	char rev_char;
+	const char *chip_name;
 
 	if (config == NULL || i2c == NULL)
 		goto error;
@@ -984,7 +994,7 @@
 	if (val != state->config.chip_mode)
 		goto error;
 
-	io_ret = si2165_readreg8(state, 0x0023 , &state->revcode);
+	io_ret = si2165_readreg8(state, 0x0023, &state->chip_revcode);
 	if (io_ret < 0)
 		goto error;
 
@@ -997,22 +1007,35 @@
 	if (io_ret < 0)
 		goto error;
 
-	dev_info(&state->i2c->dev, "%s: hardware revision 0x%02x, chip type 0x%02x\n",
-		 KBUILD_MODNAME, state->revcode, state->chip_type);
+	if (state->chip_revcode < 26)
+		rev_char = 'A' + state->chip_revcode;
+	else
+		rev_char = '?';
 
-	/* It is a guess that register 0x0118 (chip type?) can be used to
-	 * differ between si2161, si2163 and si2165
-	 * Only si2165 has been tested.
-	 */
-	if (state->revcode == 0x03 && state->chip_type == 0x07) {
+	switch (state->chip_type) {
+	case 0x06:
+		chip_name = "Si2161";
+		state->has_dvbt = true;
+		break;
+	case 0x07:
+		chip_name = "Si2165";
 		state->has_dvbt = true;
 		state->has_dvbc = true;
-	} else {
-		dev_err(&state->i2c->dev, "%s: Unsupported chip.\n",
-			KBUILD_MODNAME);
+		break;
+	default:
+		dev_err(&state->i2c->dev, "%s: Unsupported Silicon Labs chip (type %d, rev %d)\n",
+			KBUILD_MODNAME, state->chip_type, state->chip_revcode);
 		goto error;
 	}
 
+	dev_info(&state->i2c->dev,
+		"%s: Detected Silicon Labs %s-%c (type %d, rev %d)\n",
+		KBUILD_MODNAME, chip_name, rev_char, state->chip_type,
+		state->chip_revcode);
+
+	strlcat(state->frontend.ops.info.name, chip_name,
+			sizeof(state->frontend.ops.info.name));
+
 	n = 0;
 	if (state->has_dvbt) {
 		state->frontend.ops.delsys[n++] = SYS_DVBT;
@@ -1037,4 +1060,4 @@
 MODULE_DESCRIPTION("Silicon Labs Si2165 DVB-C/-T Demodulator driver");
 MODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>");
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(SI2165_FIRMWARE);
+MODULE_FIRMWARE(SI2165_FIRMWARE_REV_D);
diff --git a/drivers/media/dvb-frontends/si2165_priv.h b/drivers/media/dvb-frontends/si2165_priv.h
index d4cc93f..2b70cf1 100644
--- a/drivers/media/dvb-frontends/si2165_priv.h
+++ b/drivers/media/dvb-frontends/si2165_priv.h
@@ -18,6 +18,6 @@
 #ifndef _DVB_SI2165_PRIV
 #define _DVB_SI2165_PRIV
 
-#define SI2165_FIRMWARE "dvb-demod-si2165.fw"
+#define SI2165_FIRMWARE_REV_D "dvb-demod-si2165.fw"
 
 #endif /* _DVB_SI2165_PRIV */
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 8f81d97..1cd93be 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -55,8 +55,7 @@
 				break;
 		}
 
-		dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n",
-				__func__,
+		dev_dbg(&s->client->dev, "cmd execution took %d ms\n",
 				jiffies_to_msecs(jiffies) -
 				(jiffies_to_msecs(timeout) - TIMEOUT));
 
@@ -75,7 +74,7 @@
 
 	return 0;
 err:
-	dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&s->client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -150,12 +149,12 @@
 		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 	}
 
-	dev_dbg(&s->client->dev, "%s: status=%02x args=%*ph\n",
-			__func__, *status, cmd.rlen, cmd.args);
+	dev_dbg(&s->client->dev, "status=%02x args=%*ph\n",
+			*status, cmd.rlen, cmd.args);
 
 	return 0;
 err:
-	dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&s->client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -168,10 +167,10 @@
 	u8 bandwidth, delivery_system;
 
 	dev_dbg(&s->client->dev,
-			"%s: delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u\n",
-			__func__, c->delivery_system, c->modulation,
+			"delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u, stream_id=%d\n",
+			c->delivery_system, c->modulation,
 			c->frequency, c->bandwidth_hz, c->symbol_rate,
-			c->inversion);
+			c->inversion, c->stream_id);
 
 	if (!s->active) {
 		ret = -EAGAIN;
@@ -235,6 +234,18 @@
 	if (ret)
 		goto err;
 
+	if (c->delivery_system == SYS_DVBT2) {
+		/* select PLP */
+		cmd.args[0] = 0x52;
+		cmd.args[1] = c->stream_id & 0xff;
+		cmd.args[2] = c->stream_id == NO_STREAM_ID_FILTER ? 0 : 1;
+		cmd.wlen = 3;
+		cmd.rlen = 1;
+		ret = si2168_cmd_execute(s, &cmd);
+		if (ret)
+			goto err;
+	}
+
 	memcpy(cmd.args, "\x51\x03", 2);
 	cmd.wlen = 2;
 	cmd.rlen = 12;
@@ -297,13 +308,6 @@
 	if (ret)
 		goto err;
 
-	memcpy(cmd.args, "\x14\x00\x01\x10\x16\x00", 6);
-	cmd.wlen = 6;
-	cmd.rlen = 4;
-	ret = si2168_cmd_execute(s, &cmd);
-	if (ret)
-		goto err;
-
 	memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x18", 6);
 	cmd.wlen = 6;
 	cmd.rlen = 4;
@@ -343,7 +347,7 @@
 
 	return 0;
 err:
-	dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&s->client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -357,8 +361,9 @@
 	struct si2168_cmd cmd;
 	unsigned int chip_id;
 
-	dev_dbg(&s->client->dev, "%s:\n", __func__);
+	dev_dbg(&s->client->dev, "\n");
 
+	/* initialize */
 	memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13);
 	cmd.wlen = 13;
 	cmd.rlen = 0;
@@ -366,6 +371,26 @@
 	if (ret)
 		goto err;
 
+	if (s->fw_loaded) {
+		/* resume */
+		memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8);
+		cmd.wlen = 8;
+		cmd.rlen = 1;
+		ret = si2168_cmd_execute(s, &cmd);
+		if (ret)
+			goto err;
+
+		memcpy(cmd.args, "\x85", 1);
+		cmd.wlen = 1;
+		cmd.rlen = 1;
+		ret = si2168_cmd_execute(s, &cmd);
+		if (ret)
+			goto err;
+
+		goto warm;
+	}
+
+	/* power up */
 	memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8);
 	cmd.wlen = 8;
 	cmd.rlen = 1;
@@ -400,16 +425,16 @@
 		break;
 	default:
 		dev_err(&s->client->dev,
-				"%s: unkown chip version Si21%d-%c%c%c\n",
-				KBUILD_MODNAME, cmd.args[2], cmd.args[1],
+				"unknown chip version Si21%d-%c%c%c\n",
+				cmd.args[2], cmd.args[1],
 				cmd.args[3], cmd.args[4]);
 		ret = -EINVAL;
 		goto err;
 	}
 
 	/* cold state - try to download firmware */
-	dev_info(&s->client->dev, "%s: found a '%s' in cold state\n",
-			KBUILD_MODNAME, si2168_ops.info.name);
+	dev_info(&s->client->dev, "found a '%s' in cold state\n",
+			si2168_ops.info.name);
 
 	/* request the firmware, this will block and timeout */
 	ret = request_firmware(&fw, fw_file, &s->client->dev);
@@ -422,18 +447,18 @@
 
 		if (ret == 0) {
 			dev_notice(&s->client->dev,
-					"%s: please install firmware file '%s'\n",
-					KBUILD_MODNAME, SI2168_B40_FIRMWARE);
+					"please install firmware file '%s'\n",
+					SI2168_B40_FIRMWARE);
 		} else {
 			dev_err(&s->client->dev,
-					"%s: firmware file '%s' not found\n",
-					KBUILD_MODNAME, fw_file);
+					"firmware file '%s' not found\n",
+					fw_file);
 			goto err;
 		}
 	}
 
-	dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n",
-			KBUILD_MODNAME, fw_file);
+	dev_info(&s->client->dev, "downloading firmware from file '%s'\n",
+			fw_file);
 
 	for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) {
 		len = remaining;
@@ -446,8 +471,8 @@
 		ret = si2168_cmd_execute(s, &cmd);
 		if (ret) {
 			dev_err(&s->client->dev,
-					"%s: firmware download failed=%d\n",
-					KBUILD_MODNAME, ret);
+					"firmware download failed=%d\n",
+					ret);
 			goto err;
 		}
 	}
@@ -462,8 +487,20 @@
 	if (ret)
 		goto err;
 
-	dev_info(&s->client->dev, "%s: found a '%s' in warm state\n",
-			KBUILD_MODNAME, si2168_ops.info.name);
+	/* set ts mode */
+	memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
+	cmd.args[4] |= s->ts_mode;
+	cmd.wlen = 6;
+	cmd.rlen = 4;
+	ret = si2168_cmd_execute(s, &cmd);
+	if (ret)
+		goto err;
+
+	s->fw_loaded = true;
+
+warm:
+	dev_info(&s->client->dev, "found a '%s' in warm state\n",
+			si2168_ops.info.name);
 
 	s->active = true;
 
@@ -472,7 +509,7 @@
 	if (fw)
 		release_firmware(fw);
 
-	dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&s->client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -482,7 +519,7 @@
 	int ret;
 	struct si2168_cmd cmd;
 
-	dev_dbg(&s->client->dev, "%s:\n", __func__);
+	dev_dbg(&s->client->dev, "\n");
 
 	s->active = false;
 
@@ -495,7 +532,7 @@
 
 	return 0;
 err:
-	dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&s->client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -528,8 +565,7 @@
 	/* open tuner I2C gate */
 	ret = __i2c_transfer(s->client->adapter, &gate_open_msg, 1);
 	if (ret != 1) {
-		dev_warn(&s->client->dev, "%s: i2c write failed=%d\n",
-				KBUILD_MODNAME, ret);
+		dev_warn(&s->client->dev, "i2c write failed=%d\n", ret);
 		if (ret >= 0)
 			ret = -EREMOTEIO;
 	} else {
@@ -553,8 +589,7 @@
 	/* close tuner I2C gate */
 	ret = __i2c_transfer(s->client->adapter, &gate_close_msg, 1);
 	if (ret != 1) {
-		dev_warn(&s->client->dev, "%s: i2c write failed=%d\n",
-				KBUILD_MODNAME, ret);
+		dev_warn(&s->client->dev, "i2c write failed=%d\n", ret);
 		if (ret >= 0)
 			ret = -EREMOTEIO;
 	} else {
@@ -587,7 +622,8 @@
 			FE_CAN_GUARD_INTERVAL_AUTO |
 			FE_CAN_HIERARCHY_AUTO |
 			FE_CAN_MUTE_TS |
-			FE_CAN_2G_MODULATION
+			FE_CAN_2G_MODULATION |
+			FE_CAN_MULTISTREAM
 	},
 
 	.get_tune_settings = si2168_get_tune_settings,
@@ -607,12 +643,12 @@
 	struct si2168 *s;
 	int ret;
 
-	dev_dbg(&client->dev, "%s:\n", __func__);
+	dev_dbg(&client->dev, "\n");
 
 	s = kzalloc(sizeof(struct si2168), GFP_KERNEL);
 	if (!s) {
 		ret = -ENOMEM;
-		dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+		dev_err(&client->dev, "kzalloc() failed\n");
 		goto err;
 	}
 
@@ -633,16 +669,17 @@
 
 	*config->i2c_adapter = s->adapter;
 	*config->fe = &s->fe;
+	s->ts_mode = config->ts_mode;
+	s->fw_loaded = false;
 
 	i2c_set_clientdata(client, s);
 
 	dev_info(&s->client->dev,
-			"%s: Silicon Labs Si2168 successfully attached\n",
-			KBUILD_MODNAME);
+			"Silicon Labs Si2168 successfully attached\n");
 	return 0;
 err:
 	kfree(s);
-	dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -650,7 +687,7 @@
 {
 	struct si2168 *s = i2c_get_clientdata(client);
 
-	dev_dbg(&client->dev, "%s:\n", __func__);
+	dev_dbg(&client->dev, "\n");
 
 	i2c_del_mux_adapter(s->adapter);
 
diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
index 3c5b5ab..e086d67 100644
--- a/drivers/media/dvb-frontends/si2168.h
+++ b/drivers/media/dvb-frontends/si2168.h
@@ -34,6 +34,12 @@
 	 * returned by driver
 	 */
 	struct i2c_adapter **i2c_adapter;
+
+	/* TS mode */
+	u8 ts_mode;
 };
 
+#define SI2168_TS_PARALLEL	0x06
+#define SI2168_TS_SERIAL	0x03
+
 #endif
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
index ebbf502..e13983e 100644
--- a/drivers/media/dvb-frontends/si2168_priv.h
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -36,6 +36,8 @@
 	fe_delivery_system_t delivery_system;
 	fe_status_t fe_status;
 	bool active;
+	bool fw_loaded;
+	u8 ts_mode;
 };
 
 /* firmare command struct */
diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c
index 73b47cc..16850e2 100644
--- a/drivers/media/dvb-frontends/si21xx.c
+++ b/drivers/media/dvb-frontends/si21xx.c
@@ -236,6 +236,9 @@
 				.len = len + 1
 	};
 
+	if (len > sizeof(buf) - 1)
+		return -EINVAL;
+
 	msg.buf[0] =  reg1;
 	memcpy(msg.buf + 1, data, len);
 
diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c
new file mode 100644
index 0000000..9b684d5
--- /dev/null
+++ b/drivers/media/dvb-frontends/sp2.c
@@ -0,0 +1,441 @@
+/*
+ * CIMaX SP2/SP2HF (Atmel T90FJR) CI driver
+ *
+ * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi>
+ *
+ * Heavily based on CIMax2(R) SP2 driver in conjunction with NetUp Dual
+ * DVB-S2 CI card (cimax2) with following copyrights:
+ *
+ *  Copyright (C) 2009 NetUP Inc.
+ *  Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
+ *  Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    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 "sp2_priv.h"
+
+static int sp2_read_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
+{
+	int ret;
+	struct i2c_client *client = s->client;
+	struct i2c_adapter *adap = client->adapter;
+	struct i2c_msg msg[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.buf = &reg,
+			.len = 1
+		}, {
+			.addr = client->addr,
+			.flags	= I2C_M_RD,
+			.buf = buf,
+			.len = len
+		}
+	};
+
+	ret = i2c_transfer(adap, msg, 2);
+
+	if (ret != 2) {
+		dev_err(&client->dev, "i2c read error, reg = 0x%02x, status = %d\n",
+				reg, ret);
+		if (ret < 0)
+			return ret;
+		else
+			return -EIO;
+	}
+
+	dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %02x\n",
+				client->addr, reg, buf[0]);
+
+	return 0;
+}
+
+static int sp2_write_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
+{
+	int ret;
+	u8 buffer[35];
+	struct i2c_client *client = s->client;
+	struct i2c_adapter *adap = client->adapter;
+	struct i2c_msg msg = {
+		.addr = client->addr,
+		.flags = 0,
+		.buf = &buffer[0],
+		.len = len + 1
+	};
+
+	if ((len + 1) > sizeof(buffer)) {
+		dev_err(&client->dev, "i2c wr reg=%02x: len=%d is too big!\n",
+				reg, len);
+		return -EINVAL;
+	}
+
+	buffer[0] = reg;
+	memcpy(&buffer[1], buf, len);
+
+	ret = i2c_transfer(adap, &msg, 1);
+
+	if (ret != 1) {
+		dev_err(&client->dev, "i2c write error, reg = 0x%02x, status = %d\n",
+				reg, ret);
+		if (ret < 0)
+			return ret;
+		else
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs,
+			u8 read, int addr, u8 data)
+{
+	struct sp2 *s = en50221->data;
+	u8 store;
+	int mem, ret;
+	int (*ci_op_cam)(void*, u8, int, u8, int*) = s->ci_control;
+
+	dev_dbg(&s->client->dev, "slot=%d, acs=0x%02x, addr=0x%04x, data = 0x%02x",
+			slot, acs, addr, data);
+
+	if (slot != 0)
+		return -EINVAL;
+
+	/*
+	 * change module access type between IO space and attribute memory
+	 * when needed
+	 */
+	if (s->module_access_type != acs) {
+		ret = sp2_read_i2c(s, 0x00, &store, 1);
+
+		if (ret)
+			return ret;
+
+		store &= ~(SP2_MOD_CTL_ACS1 | SP2_MOD_CTL_ACS0);
+		store |= acs;
+
+		ret = sp2_write_i2c(s, 0x00, &store, 1);
+		if (ret)
+			return ret;
+	}
+
+	s->module_access_type = acs;
+
+	/* implementation of ci_op_cam is device specific */
+	if (ci_op_cam) {
+		ret = ci_op_cam(s->priv, read, addr, data, &mem);
+	} else {
+		dev_err(&s->client->dev, "callback not defined");
+		return -EINVAL;
+	}
+
+	if (ret)
+		return ret;
+
+	if (read) {
+		dev_dbg(&s->client->dev, "cam read, addr=0x%04x, data = 0x%04x",
+				addr, mem);
+		return mem;
+	} else {
+		return 0;
+	}
+}
+
+int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+				int slot, int addr)
+{
+	return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS,
+			SP2_CI_RD, addr, 0);
+}
+
+int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+				int slot, int addr, u8 data)
+{
+	return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS,
+			SP2_CI_WR, addr, data);
+}
+
+int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221,
+				int slot, u8 addr)
+{
+	return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS,
+			SP2_CI_RD, addr, 0);
+}
+
+int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221,
+				int slot, u8 addr, u8 data)
+{
+	return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS,
+			SP2_CI_WR, addr, data);
+}
+
+int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+	struct sp2 *s = en50221->data;
+	u8 buf;
+	int ret;
+
+	dev_dbg(&s->client->dev, "slot: %d\n", slot);
+
+	if (slot != 0)
+		return -EINVAL;
+
+	/* RST on */
+	buf = SP2_MOD_CTL_RST;
+	ret = sp2_write_i2c(s, 0x00, &buf, 1);
+
+	if (ret)
+		return ret;
+
+	usleep_range(500, 600);
+
+	/* RST off */
+	buf = 0x00;
+	ret = sp2_write_i2c(s, 0x00, &buf, 1);
+
+	if (ret)
+		return ret;
+
+	msleep(1000);
+
+	return 0;
+}
+
+int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+	struct sp2 *s = en50221->data;
+
+	dev_dbg(&s->client->dev, "slot:%d\n", slot);
+
+	/* not implemented */
+	return 0;
+}
+
+int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot)
+{
+	struct sp2 *s = en50221->data;
+	u8 buf;
+
+	dev_dbg(&s->client->dev, "slot:%d\n", slot);
+
+	if (slot != 0)
+		return -EINVAL;
+
+	sp2_read_i2c(s, 0x00, &buf, 1);
+
+	/* disable bypass and enable TS */
+	buf |= (SP2_MOD_CTL_TSOEN | SP2_MOD_CTL_TSIEN);
+	return sp2_write_i2c(s, 0, &buf, 1);
+}
+
+int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221,
+				int slot, int open)
+{
+	struct sp2 *s = en50221->data;
+	u8 buf[2];
+	int ret;
+
+	dev_dbg(&s->client->dev, "slot:%d open:%d\n", slot, open);
+
+	/*
+	 * CAM module INSERT/REMOVE processing. Slow operation because of i2c
+	 * transfers. Throttle read to one per sec.
+	 */
+	if (time_after(jiffies, s->next_status_checked_time)) {
+		ret = sp2_read_i2c(s, 0x00, buf, 1);
+		s->next_status_checked_time = jiffies +	msecs_to_jiffies(1000);
+
+		if (ret)
+			return 0;
+
+		if (buf[0] & SP2_MOD_CTL_DET)
+			s->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
+					DVB_CA_EN50221_POLL_CAM_READY;
+		else
+			s->status = 0;
+	}
+
+	return s->status;
+}
+
+int sp2_init(struct sp2 *s)
+{
+	int ret = 0;
+	u8 buf;
+	u8 cimax_init[34] = {
+		0x00, /* module A control*/
+		0x00, /* auto select mask high A */
+		0x00, /* auto select mask low A */
+		0x00, /* auto select pattern high A */
+		0x00, /* auto select pattern low A */
+		0x44, /* memory access time A, 600 ns */
+		0x00, /* invert input A */
+		0x00, /* RFU */
+		0x00, /* RFU */
+		0x00, /* module B control*/
+		0x00, /* auto select mask high B */
+		0x00, /* auto select mask low B */
+		0x00, /* auto select pattern high B */
+		0x00, /* auto select pattern low B */
+		0x44, /* memory access time B, 600 ns */
+		0x00, /* invert input B */
+		0x00, /* RFU */
+		0x00, /* RFU */
+		0x00, /* auto select mask high Ext */
+		0x00, /* auto select mask low Ext */
+		0x00, /* auto select pattern high Ext */
+		0x00, /* auto select pattern low Ext */
+		0x00, /* RFU */
+		0x02, /* destination - module A */
+		0x01, /* power control reg, VCC power on */
+		0x00, /* RFU */
+		0x00, /* int status read only */
+		0x00, /* Interrupt Mask Register */
+		0x05, /* EXTINT=active-high, INT=push-pull */
+		0x00, /* USCG1 */
+		0x04, /* ack active low */
+		0x00, /* LOCK = 0 */
+		0x22, /* unknown */
+		0x00, /* synchronization? */
+	};
+
+	dev_dbg(&s->client->dev, "\n");
+
+	s->ca.owner = THIS_MODULE;
+	s->ca.read_attribute_mem = sp2_ci_read_attribute_mem;
+	s->ca.write_attribute_mem = sp2_ci_write_attribute_mem;
+	s->ca.read_cam_control = sp2_ci_read_cam_control;
+	s->ca.write_cam_control = sp2_ci_write_cam_control;
+	s->ca.slot_reset = sp2_ci_slot_reset;
+	s->ca.slot_shutdown = sp2_ci_slot_shutdown;
+	s->ca.slot_ts_enable = sp2_ci_slot_ts_enable;
+	s->ca.poll_slot_status = sp2_ci_poll_slot_status;
+	s->ca.data = s;
+	s->module_access_type = 0;
+
+	/* initialize all regs */
+	ret = sp2_write_i2c(s, 0x00, &cimax_init[0], 34);
+	if (ret)
+		goto err;
+
+	/* lock registers */
+	buf = 1;
+	ret = sp2_write_i2c(s, 0x1f, &buf, 1);
+	if (ret)
+		goto err;
+
+	/* power on slots */
+	ret = sp2_write_i2c(s, 0x18, &buf, 1);
+	if (ret)
+		goto err;
+
+	ret = dvb_ca_en50221_init(s->dvb_adap, &s->ca, 0, 1);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	dev_dbg(&s->client->dev, "init failed=%d\n", ret);
+	return ret;
+}
+
+int sp2_exit(struct i2c_client *client)
+{
+	struct sp2 *s;
+
+	dev_dbg(&client->dev, "\n");
+
+	if (client == NULL)
+		return 0;
+
+	s = i2c_get_clientdata(client);
+	if (s == NULL)
+		return 0;
+
+	if (s->ca.data == NULL)
+		return 0;
+
+	dvb_ca_en50221_release(&s->ca);
+
+	return 0;
+}
+
+static int sp2_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct sp2_config *cfg = client->dev.platform_data;
+	struct sp2 *s;
+	int ret;
+
+	dev_dbg(&client->dev, "\n");
+
+	s = kzalloc(sizeof(struct sp2), GFP_KERNEL);
+	if (!s) {
+		ret = -ENOMEM;
+		dev_err(&client->dev, "kzalloc() failed\n");
+		goto err;
+	}
+
+	s->client = client;
+	s->dvb_adap = cfg->dvb_adap;
+	s->priv = cfg->priv;
+	s->ci_control = cfg->ci_control;
+
+	i2c_set_clientdata(client, s);
+
+	ret = sp2_init(s);
+	if (ret)
+		goto err;
+
+	dev_info(&s->client->dev, "CIMaX SP2 successfully attached\n");
+	return 0;
+err:
+	dev_dbg(&client->dev, "init failed=%d\n", ret);
+	kfree(s);
+
+	return ret;
+}
+
+static int sp2_remove(struct i2c_client *client)
+{
+	struct si2157 *s = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "\n");
+
+	sp2_exit(client);
+	if (s != NULL)
+		kfree(s);
+
+	return 0;
+}
+
+static const struct i2c_device_id sp2_id[] = {
+	{"sp2", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, sp2_id);
+
+static struct i2c_driver sp2_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "sp2",
+	},
+	.probe		= sp2_probe,
+	.remove		= sp2_remove,
+	.id_table	= sp2_id,
+};
+
+module_i2c_driver(sp2_driver);
+
+MODULE_DESCRIPTION("CIMaX SP2/HF CI driver");
+MODULE_AUTHOR("Olli Salonen <olli.salonen@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/sp2.h b/drivers/media/dvb-frontends/sp2.h
new file mode 100644
index 0000000..6cceea0
--- /dev/null
+++ b/drivers/media/dvb-frontends/sp2.h
@@ -0,0 +1,53 @@
+/*
+ * CIMaX SP2/HF CI driver
+ *
+ * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    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.
+ */
+
+#ifndef SP2_H
+#define SP2_H
+
+#include <linux/kconfig.h>
+#include "dvb_ca_en50221.h"
+
+/*
+ * I2C address
+ * 0x40 (port 0)
+ * 0x41 (port 1)
+ */
+struct sp2_config {
+	/* dvb_adapter to attach the ci to */
+	struct dvb_adapter *dvb_adap;
+
+	/* function ci_control handles the device specific ci ops */
+	void *ci_control;
+
+	/* priv is passed back to function ci_control */
+	void *priv;
+};
+
+extern int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+					int slot, int addr);
+extern int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+					int slot, int addr, u8 data);
+extern int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221,
+					int slot, u8 addr);
+extern int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221,
+					int slot, u8 addr, u8 data);
+extern int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot);
+extern int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot);
+extern int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot);
+extern int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221,
+					int slot, int open);
+
+#endif
diff --git a/drivers/media/dvb-frontends/sp2_priv.h b/drivers/media/dvb-frontends/sp2_priv.h
new file mode 100644
index 0000000..37fef7b
--- /dev/null
+++ b/drivers/media/dvb-frontends/sp2_priv.h
@@ -0,0 +1,50 @@
+/*
+ * CIMaX SP2/HF CI driver
+ *
+ * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    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.
+ */
+
+#ifndef SP2_PRIV_H
+#define SP2_PRIV_H
+
+#include "sp2.h"
+#include "dvb_frontend.h"
+
+/* state struct */
+struct sp2 {
+	int status;
+	struct i2c_client *client;
+	struct dvb_adapter *dvb_adap;
+	struct dvb_ca_en50221 ca;
+	int module_access_type;
+	unsigned long next_status_checked_time;
+	void *priv;
+	void *ci_control;
+};
+
+#define SP2_CI_ATTR_ACS		0x00
+#define SP2_CI_IO_ACS		0x04
+#define SP2_CI_WR		0
+#define SP2_CI_RD		1
+
+/* Module control register (0x00 module A, 0x09 module B) bits */
+#define SP2_MOD_CTL_DET		0x01
+#define SP2_MOD_CTL_AUTO	0x02
+#define SP2_MOD_CTL_ACS0	0x04
+#define SP2_MOD_CTL_ACS1	0x08
+#define SP2_MOD_CTL_HAD		0x10
+#define SP2_MOD_CTL_TSIEN	0x20
+#define SP2_MOD_CTL_TSOEN	0x40
+#define SP2_MOD_CTL_RST		0x80
+
+#endif
diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c
index 2aa8ef7..57dc2ab 100644
--- a/drivers/media/dvb-frontends/sp8870.c
+++ b/drivers/media/dvb-frontends/sp8870.c
@@ -394,8 +394,7 @@
 	if (ret < 0)
 		return -EIO;
 
-	 tmp = ret << 6;
-
+	tmp = ret << 6;
 	if (tmp >= 0x3FFF0)
 		tmp = ~0;
 
diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c
index 59b6e66..b31ff26 100644
--- a/drivers/media/dvb-frontends/stv0367.c
+++ b/drivers/media/dvb-frontends/stv0367.c
@@ -59,7 +59,6 @@
 	int locked;			/* channel found		*/
 	u32 freq_khz;			/* found frequency (in kHz)	*/
 	u32 symbol_rate;		/* found symbol rate (in Bds)	*/
-	enum stv0367cab_mod modulation;	/* modulation			*/
 	fe_spectral_inversion_t	spect_inv; /* Spectrum Inversion	*/
 };
 
@@ -554,7 +553,7 @@
 #define RF_LOOKUP_TABLE_SIZE  31
 #define RF_LOOKUP_TABLE2_SIZE 16
 /* RF Level (for RF AGC->AGC1) Lookup Table, depends on the board and tuner.*/
-s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = {
+static const s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = {
 	{/*AGC1*/
 		48, 50, 51, 53, 54, 56, 57, 58, 60, 61, 62, 63,
 		64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
@@ -566,7 +565,7 @@
 	}
 };
 /* RF Level (for IF AGC->AGC2) Lookup Table, depends on the board and tuner.*/
-s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = {
+static const s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = {
 	{/*AGC2*/
 		28, 29, 31, 32, 34, 35, 36, 37,
 		38, 39, 40, 41, 42, 43, 44, 45,
@@ -1935,8 +1934,6 @@
 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 	struct stv0367_state *state = fe->demodulator_priv;
 	struct stv0367ter_state *ter_state = state->ter_state;
-
-	int error = 0;
 	enum stv0367_ter_mode mode;
 	int constell = 0,/* snr = 0,*/ Data = 0;
 
@@ -2020,7 +2017,7 @@
 
 	p->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD);
 
-	return error;
+	return 0;
 }
 
 static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr)
@@ -2999,7 +2996,6 @@
 
 	if (QAMFEC_Lock) {
 		signalType = FE_CAB_DATAOK;
-		cab_state->modulation = p->modulation;
 		cab_state->spect_inv = stv0367_readbits(state,
 							F367CAB_QUAD_INV);
 #if 0
@@ -3165,7 +3161,7 @@
 	case FE_CAB_MOD_QAM128:
 		p->modulation = QAM_128;
 		break;
-	case QAM_256:
+	case FE_CAB_MOD_QAM256:
 		p->modulation = QAM_256;
 		break;
 	default:
diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c
index e5a87b5..2c88abf 100644
--- a/drivers/media/dvb-frontends/stv0900_core.c
+++ b/drivers/media/dvb-frontends/stv0900_core.c
@@ -1270,7 +1270,6 @@
 					enum fe_stv0900_demod_mode LDPC_Mode,
 					enum fe_stv0900_demod_num demod)
 {
-	enum fe_stv0900_error error = STV0900_NO_ERROR;
 	s32 reg_ind;
 
 	dprintk("%s\n", __func__);
@@ -1337,7 +1336,7 @@
 		break;
 	}
 
-	return error;
+	return STV0900_NO_ERROR;
 }
 
 static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
@@ -1555,8 +1554,6 @@
 static int stv0900_set_mis(struct stv0900_internal *intp,
 				enum fe_stv0900_demod_num demod, int mis)
 {
-	enum fe_stv0900_error error = STV0900_NO_ERROR;
-
 	dprintk("%s\n", __func__);
 
 	if (mis < 0 || mis > 255) {
@@ -1569,7 +1566,7 @@
 		stv0900_write_reg(intp, ISIBITENA, 0xff);
 	}
 
-	return error;
+	return STV0900_NO_ERROR;
 }
 
 
diff --git a/drivers/media/dvb-frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c
index 4ce1d26..a0a7b16 100644
--- a/drivers/media/dvb-frontends/stv0900_sw.c
+++ b/drivers/media/dvb-frontends/stv0900_sw.c
@@ -1733,9 +1733,10 @@
 		break;
 	case STV0900_SEARCH_DSS:
 		dprintk("Search Standard = DSS\n");
-	case STV0900_SEARCH_DVBS2:
 		break;
+	case STV0900_SEARCH_DVBS2:
 		dprintk("Search Standard = DVBS2\n");
+		break;
 	case STV0900_AUTO_SEARCH:
 	default:
 		dprintk("Search Standard = AUTO\n");
diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c
new file mode 100644
index 0000000..d9905fb
--- /dev/null
+++ b/drivers/media/dvb-frontends/tc90522.c
@@ -0,0 +1,840 @@
+/*
+ * Toshiba TC90522 Demodulator
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * NOTICE:
+ * This driver is incomplete and lacks init/config of the chips,
+ * as the necessary info is not disclosed.
+ * It assumes that users of this driver (such as a PCI bridge of
+ * DTV receiver cards) properly init and configure the chip
+ * via I2C *before* calling this driver's init() function.
+ *
+ * Currently, PT3 driver is the only one that uses this driver,
+ * and contains init/config code in its firmware.
+ * Thus some part of the code might be dependent on PT3 specific config.
+ */
+
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/dvb/frontend.h>
+#include "dvb_math.h"
+#include "tc90522.h"
+
+#define TC90522_I2C_THRU_REG 0xfe
+
+#define TC90522_MODULE_IDX(addr) (((u8)(addr) & 0x02U) >> 1)
+
+struct tc90522_state {
+	struct tc90522_config cfg;
+	struct dvb_frontend fe;
+	struct i2c_client *i2c_client;
+	struct i2c_adapter tuner_i2c;
+
+	bool lna;
+};
+
+struct reg_val {
+	u8 reg;
+	u8 val;
+};
+
+static int
+reg_write(struct tc90522_state *state, const struct reg_val *regs, int num)
+{
+	int i, ret;
+	struct i2c_msg msg;
+
+	ret = 0;
+	msg.addr = state->i2c_client->addr;
+	msg.flags = 0;
+	msg.len = 2;
+	for (i = 0; i < num; i++) {
+		msg.buf = (u8 *)&regs[i];
+		ret = i2c_transfer(state->i2c_client->adapter, &msg, 1);
+		if (ret == 0)
+			ret = -EIO;
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static int reg_read(struct tc90522_state *state, u8 reg, u8 *val, u8 len)
+{
+	struct i2c_msg msgs[2] = {
+		{
+			.addr = state->i2c_client->addr,
+			.flags = 0,
+			.buf = &reg,
+			.len = 1,
+		},
+		{
+			.addr = state->i2c_client->addr,
+			.flags = I2C_M_RD,
+			.buf = val,
+			.len = len,
+		},
+	};
+	int ret;
+
+	ret = i2c_transfer(state->i2c_client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret == ARRAY_SIZE(msgs))
+		ret = 0;
+	else if (ret >= 0)
+		ret = -EIO;
+	return ret;
+}
+
+static struct tc90522_state *cfg_to_state(struct tc90522_config *c)
+{
+	return container_of(c, struct tc90522_state, cfg);
+}
+
+
+static int tc90522s_set_tsid(struct dvb_frontend *fe)
+{
+	struct reg_val set_tsid[] = {
+		{ 0x8f, 00 },
+		{ 0x90, 00 }
+	};
+
+	set_tsid[0].val = (fe->dtv_property_cache.stream_id & 0xff00) >> 8;
+	set_tsid[1].val = fe->dtv_property_cache.stream_id & 0xff;
+	return reg_write(fe->demodulator_priv, set_tsid, ARRAY_SIZE(set_tsid));
+}
+
+static int tc90522t_set_layers(struct dvb_frontend *fe)
+{
+	struct reg_val rv;
+	u8 laysel;
+
+	laysel = ~fe->dtv_property_cache.isdbt_layer_enabled & 0x07;
+	laysel = (laysel & 0x01) << 2 | (laysel & 0x02) | (laysel & 0x04) >> 2;
+	rv.reg = 0x71;
+	rv.val = laysel;
+	return reg_write(fe->demodulator_priv, &rv, 1);
+}
+
+/* frontend ops */
+
+static int tc90522s_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct tc90522_state *state;
+	int ret;
+	u8 reg;
+
+	state = fe->demodulator_priv;
+	ret = reg_read(state, 0xc3, &reg, 1);
+	if (ret < 0)
+		return ret;
+
+	*status = 0;
+	if (reg & 0x80) /* input level under min ? */
+		return 0;
+	*status |= FE_HAS_SIGNAL;
+
+	if (reg & 0x60) /* carrier? */
+		return 0;
+	*status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC;
+
+	if (reg & 0x10)
+		return 0;
+	if (reg_read(state, 0xc5, &reg, 1) < 0 || !(reg & 0x03))
+		return 0;
+	*status |= FE_HAS_LOCK;
+	return 0;
+}
+
+static int tc90522t_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct tc90522_state *state;
+	int ret;
+	u8 reg;
+
+	state = fe->demodulator_priv;
+	ret = reg_read(state, 0x96, &reg, 1);
+	if (ret < 0)
+		return ret;
+
+	*status = 0;
+	if (reg & 0xe0) {
+		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI
+				| FE_HAS_SYNC | FE_HAS_LOCK;
+		return 0;
+	}
+
+	ret = reg_read(state, 0x80, &reg, 1);
+	if (ret < 0)
+		return ret;
+
+	if (reg & 0xf0)
+		return 0;
+	*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
+	if (reg & 0x0c)
+		return 0;
+	*status |= FE_HAS_SYNC | FE_HAS_VITERBI;
+
+	if (reg & 0x02)
+		return 0;
+	*status |= FE_HAS_LOCK;
+	return 0;
+}
+
+static const fe_code_rate_t fec_conv_sat[] = {
+	FEC_NONE, /* unused */
+	FEC_1_2, /* for BPSK */
+	FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, /* for QPSK */
+	FEC_2_3, /* for 8PSK. (trellis code) */
+};
+
+static int tc90522s_get_frontend(struct dvb_frontend *fe)
+{
+	struct tc90522_state *state;
+	struct dtv_frontend_properties *c;
+	struct dtv_fe_stats *stats;
+	int ret, i;
+	int layers;
+	u8 val[10];
+	u32 cndat;
+
+	state = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+	c->delivery_system = SYS_ISDBS;
+
+	layers = 0;
+	ret = reg_read(state, 0xe8, val, 3);
+	if (ret == 0) {
+		int slots;
+		u8 v;
+
+		/* high/single layer */
+		v = (val[0] & 0x70) >> 4;
+		c->modulation = (v == 7) ? PSK_8 : QPSK;
+		c->fec_inner = fec_conv_sat[v];
+		c->layer[0].fec = c->fec_inner;
+		c->layer[0].modulation = c->modulation;
+		c->layer[0].segment_count = val[1] & 0x3f; /* slots */
+
+		/* low layer */
+		v = (val[0] & 0x07);
+		c->layer[1].fec = fec_conv_sat[v];
+		if (v == 0)  /* no low layer */
+			c->layer[1].segment_count = 0;
+		else
+			c->layer[1].segment_count = val[2] & 0x3f; /* slots */
+		/* actually, BPSK if v==1, but not defined in fe_modulation_t */
+		c->layer[1].modulation = QPSK;
+		layers = (v > 0) ? 2 : 1;
+
+		slots =  c->layer[0].segment_count +  c->layer[1].segment_count;
+		c->symbol_rate = 28860000 * slots / 48;
+	}
+
+	/* statistics */
+
+	stats = &c->strength;
+	stats->len = 0;
+	/* let the connected tuner set RSSI property cache */
+	if (fe->ops.tuner_ops.get_rf_strength) {
+		u16 dummy;
+
+		fe->ops.tuner_ops.get_rf_strength(fe, &dummy);
+	}
+
+	stats = &c->cnr;
+	stats->len = 1;
+	stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	cndat = 0;
+	ret = reg_read(state, 0xbc, val, 2);
+	if (ret == 0)
+		cndat = val[0] << 8 | val[1];
+	if (cndat >= 3000) {
+		u32 p, p4;
+		s64 cn;
+
+		cndat -= 3000;  /* cndat: 4.12 fixed point float */
+		/*
+		 * cnr[mdB] = -1634.6 * P^5 + 14341 * P^4 - 50259 * P^3
+		 *                 + 88977 * P^2 - 89565 * P + 58857
+		 *  (P = sqrt(cndat) / 64)
+		 */
+		/* p := sqrt(cndat) << 8 = P << 14, 2.14 fixed  point float */
+		/* cn = cnr << 3 */
+		p = int_sqrt(cndat << 16);
+		p4 = cndat * cndat;
+		cn = div64_s64(-16346LL * p4 * p, 10) >> 35;
+		cn += (14341LL * p4) >> 21;
+		cn -= (50259LL * cndat * p) >> 23;
+		cn += (88977LL * cndat) >> 9;
+		cn -= (89565LL * p) >> 11;
+		cn += 58857  << 3;
+		stats->stat[0].svalue = cn >> 3;
+		stats->stat[0].scale = FE_SCALE_DECIBEL;
+	}
+
+	/* per-layer post viterbi BER (or PER? config dependent?) */
+	stats = &c->post_bit_error;
+	memset(stats, 0, sizeof(*stats));
+	stats->len = layers;
+	ret = reg_read(state, 0xeb, val, 10);
+	if (ret < 0)
+		for (i = 0; i < layers; i++)
+			stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+	else {
+		for (i = 0; i < layers; i++) {
+			stats->stat[i].scale = FE_SCALE_COUNTER;
+			stats->stat[i].uvalue = val[i * 5] << 16
+				| val[i * 5 + 1] << 8 | val[i * 5 + 2];
+		}
+	}
+	stats = &c->post_bit_count;
+	memset(stats, 0, sizeof(*stats));
+	stats->len = layers;
+	if (ret < 0)
+		for (i = 0; i < layers; i++)
+			stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+	else {
+		for (i = 0; i < layers; i++) {
+			stats->stat[i].scale = FE_SCALE_COUNTER;
+			stats->stat[i].uvalue =
+				val[i * 5 + 3] << 8 | val[i * 5 + 4];
+			stats->stat[i].uvalue *= 204 * 8;
+		}
+	}
+
+	return 0;
+}
+
+
+static const fe_transmit_mode_t tm_conv[] = {
+	TRANSMISSION_MODE_2K,
+	TRANSMISSION_MODE_4K,
+	TRANSMISSION_MODE_8K,
+	0
+};
+
+static const fe_code_rate_t fec_conv_ter[] = {
+	FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, 0, 0, 0
+};
+
+static const fe_modulation_t mod_conv[] = {
+	DQPSK, QPSK, QAM_16, QAM_64, 0, 0, 0, 0
+};
+
+static int tc90522t_get_frontend(struct dvb_frontend *fe)
+{
+	struct tc90522_state *state;
+	struct dtv_frontend_properties *c;
+	struct dtv_fe_stats *stats;
+	int ret, i;
+	int layers;
+	u8 val[15], mode;
+	u32 cndat;
+
+	state = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+	c->delivery_system = SYS_ISDBT;
+	c->bandwidth_hz = 6000000;
+	mode = 1;
+	ret = reg_read(state, 0xb0, val, 1);
+	if (ret == 0) {
+		mode = (val[0] & 0xc0) >> 2;
+		c->transmission_mode = tm_conv[mode];
+		c->guard_interval = (val[0] & 0x30) >> 4;
+	}
+
+	ret = reg_read(state, 0xb2, val, 6);
+	layers = 0;
+	if (ret == 0) {
+		u8 v;
+
+		c->isdbt_partial_reception = val[0] & 0x01;
+		c->isdbt_sb_mode = (val[0] & 0xc0) == 0x01;
+
+		/* layer A */
+		v = (val[2] & 0x78) >> 3;
+		if (v == 0x0f)
+			c->layer[0].segment_count = 0;
+		else {
+			layers++;
+			c->layer[0].segment_count = v;
+			c->layer[0].fec = fec_conv_ter[(val[1] & 0x1c) >> 2];
+			c->layer[0].modulation = mod_conv[(val[1] & 0xe0) >> 5];
+			v = (val[1] & 0x03) << 1 | (val[2] & 0x80) >> 7;
+			c->layer[0].interleaving = v;
+		}
+
+		/* layer B */
+		v = (val[3] & 0x03) << 1 | (val[4] & 0xc0) >> 6;
+		if (v == 0x0f)
+			c->layer[1].segment_count = 0;
+		else {
+			layers++;
+			c->layer[1].segment_count = v;
+			c->layer[1].fec = fec_conv_ter[(val[3] & 0xe0) >> 5];
+			c->layer[1].modulation = mod_conv[(val[2] & 0x07)];
+			c->layer[1].interleaving = (val[3] & 0x1c) >> 2;
+		}
+
+		/* layer C */
+		v = (val[5] & 0x1e) >> 1;
+		if (v == 0x0f)
+			c->layer[2].segment_count = 0;
+		else {
+			layers++;
+			c->layer[2].segment_count = v;
+			c->layer[2].fec = fec_conv_ter[(val[4] & 0x07)];
+			c->layer[2].modulation = mod_conv[(val[4] & 0x38) >> 3];
+			c->layer[2].interleaving = (val[5] & 0xe0) >> 5;
+		}
+	}
+
+	/* statistics */
+
+	stats = &c->strength;
+	stats->len = 0;
+	/* let the connected tuner set RSSI property cache */
+	if (fe->ops.tuner_ops.get_rf_strength) {
+		u16 dummy;
+
+		fe->ops.tuner_ops.get_rf_strength(fe, &dummy);
+	}
+
+	stats = &c->cnr;
+	stats->len = 1;
+	stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	cndat = 0;
+	ret = reg_read(state, 0x8b, val, 3);
+	if (ret == 0)
+		cndat = val[0] << 16 | val[1] << 8 | val[2];
+	if (cndat != 0) {
+		u32 p, tmp;
+		s64 cn;
+
+		/*
+		 * cnr[mdB] = 0.024 P^4 - 1.6 P^3 + 39.8 P^2 + 549.1 P + 3096.5
+		 * (P = 10log10(5505024/cndat))
+		 */
+		/* cn = cnr << 3 (61.3 fixed point float */
+		/* p = 10log10(5505024/cndat) << 24  (8.24 fixed point float)*/
+		p = intlog10(5505024) - intlog10(cndat);
+		p *= 10;
+
+		cn = 24772;
+		cn += div64_s64(43827LL * p, 10) >> 24;
+		tmp = p >> 8;
+		cn += div64_s64(3184LL * tmp * tmp, 10) >> 32;
+		tmp = p >> 13;
+		cn -= div64_s64(128LL * tmp * tmp * tmp, 10) >> 33;
+		tmp = p >> 18;
+		cn += div64_s64(192LL * tmp * tmp * tmp * tmp, 1000) >> 24;
+
+		stats->stat[0].svalue = cn >> 3;
+		stats->stat[0].scale = FE_SCALE_DECIBEL;
+	}
+
+	/* per-layer post viterbi BER (or PER? config dependent?) */
+	stats = &c->post_bit_error;
+	memset(stats, 0, sizeof(*stats));
+	stats->len = layers;
+	ret = reg_read(state, 0x9d, val, 15);
+	if (ret < 0)
+		for (i = 0; i < layers; i++)
+			stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+	else {
+		for (i = 0; i < layers; i++) {
+			stats->stat[i].scale = FE_SCALE_COUNTER;
+			stats->stat[i].uvalue = val[i * 3] << 16
+				| val[i * 3 + 1] << 8 | val[i * 3 + 2];
+		}
+	}
+	stats = &c->post_bit_count;
+	memset(stats, 0, sizeof(*stats));
+	stats->len = layers;
+	if (ret < 0)
+		for (i = 0; i < layers; i++)
+			stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+	else {
+		for (i = 0; i < layers; i++) {
+			stats->stat[i].scale = FE_SCALE_COUNTER;
+			stats->stat[i].uvalue =
+				val[9 + i * 2] << 8 | val[9 + i * 2 + 1];
+			stats->stat[i].uvalue *= 204 * 8;
+		}
+	}
+
+	return 0;
+}
+
+static const struct reg_val reset_sat = { 0x03, 0x01 };
+static const struct reg_val reset_ter = { 0x01, 0x40 };
+
+static int tc90522_set_frontend(struct dvb_frontend *fe)
+{
+	struct tc90522_state *state;
+	int ret;
+
+	state = fe->demodulator_priv;
+
+	if (fe->ops.tuner_ops.set_params)
+		ret = fe->ops.tuner_ops.set_params(fe);
+	else
+		ret = -ENODEV;
+	if (ret < 0)
+		goto failed;
+
+	if (fe->ops.delsys[0] == SYS_ISDBS) {
+		ret = tc90522s_set_tsid(fe);
+		if (ret < 0)
+			goto failed;
+		ret = reg_write(state, &reset_sat, 1);
+	} else {
+		ret = tc90522t_set_layers(fe);
+		if (ret < 0)
+			goto failed;
+		ret = reg_write(state, &reset_ter, 1);
+	}
+	if (ret < 0)
+		goto failed;
+
+	return 0;
+
+failed:
+	dev_warn(&state->tuner_i2c.dev, "(%s) failed. [adap%d-fe%d]\n",
+			__func__, fe->dvb->num, fe->id);
+	return ret;
+}
+
+static int tc90522_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *settings)
+{
+	if (fe->ops.delsys[0] == SYS_ISDBS) {
+		settings->min_delay_ms = 250;
+		settings->step_size = 1000;
+		settings->max_drift = settings->step_size * 2;
+	} else {
+		settings->min_delay_ms = 400;
+		settings->step_size = 142857;
+		settings->max_drift = settings->step_size;
+	}
+	return 0;
+}
+
+static int tc90522_set_if_agc(struct dvb_frontend *fe, bool on)
+{
+	struct reg_val agc_sat[] = {
+		{ 0x0a, 0x00 },
+		{ 0x10, 0x30 },
+		{ 0x11, 0x00 },
+		{ 0x03, 0x01 },
+	};
+	struct reg_val agc_ter[] = {
+		{ 0x25, 0x00 },
+		{ 0x23, 0x4c },
+		{ 0x01, 0x40 },
+	};
+	struct tc90522_state *state;
+	struct reg_val *rv;
+	int num;
+
+	state = fe->demodulator_priv;
+	if (fe->ops.delsys[0] == SYS_ISDBS) {
+		agc_sat[0].val = on ? 0xff : 0x00;
+		agc_sat[1].val |= 0x80;
+		agc_sat[1].val |= on ? 0x01 : 0x00;
+		agc_sat[2].val |= on ? 0x40 : 0x00;
+		rv = agc_sat;
+		num = ARRAY_SIZE(agc_sat);
+	} else {
+		agc_ter[0].val = on ? 0x40 : 0x00;
+		agc_ter[1].val |= on ? 0x00 : 0x01;
+		rv = agc_ter;
+		num = ARRAY_SIZE(agc_ter);
+	}
+	return reg_write(state, rv, num);
+}
+
+static const struct reg_val sleep_sat = { 0x17, 0x01 };
+static const struct reg_val sleep_ter = { 0x03, 0x90 };
+
+static int tc90522_sleep(struct dvb_frontend *fe)
+{
+	struct tc90522_state *state;
+	int ret;
+
+	state = fe->demodulator_priv;
+	if (fe->ops.delsys[0] == SYS_ISDBS)
+		ret = reg_write(state, &sleep_sat, 1);
+	else {
+		ret = reg_write(state, &sleep_ter, 1);
+		if (ret == 0 && fe->ops.set_lna &&
+		    fe->dtv_property_cache.lna == LNA_AUTO) {
+			fe->dtv_property_cache.lna = 0;
+			ret = fe->ops.set_lna(fe);
+			fe->dtv_property_cache.lna = LNA_AUTO;
+		}
+	}
+	if (ret < 0)
+		dev_warn(&state->tuner_i2c.dev,
+			"(%s) failed. [adap%d-fe%d]\n",
+			__func__, fe->dvb->num, fe->id);
+	return ret;
+}
+
+static const struct reg_val wakeup_sat = { 0x17, 0x00 };
+static const struct reg_val wakeup_ter = { 0x03, 0x80 };
+
+static int tc90522_init(struct dvb_frontend *fe)
+{
+	struct tc90522_state *state;
+	int ret;
+
+	/*
+	 * Because the init sequence is not public,
+	 * the parent device/driver should have init'ed the device before.
+	 * just wake up the device here.
+	 */
+
+	state = fe->demodulator_priv;
+	if (fe->ops.delsys[0] == SYS_ISDBS)
+		ret = reg_write(state, &wakeup_sat, 1);
+	else {
+		ret = reg_write(state, &wakeup_ter, 1);
+		if (ret == 0 && fe->ops.set_lna &&
+		    fe->dtv_property_cache.lna == LNA_AUTO) {
+			fe->dtv_property_cache.lna = 1;
+			ret = fe->ops.set_lna(fe);
+			fe->dtv_property_cache.lna = LNA_AUTO;
+		}
+	}
+	if (ret < 0) {
+		dev_warn(&state->tuner_i2c.dev,
+			"(%s) failed. [adap%d-fe%d]\n",
+			__func__, fe->dvb->num, fe->id);
+		return ret;
+	}
+
+	/* prefer 'all-layers' to 'none' as a default */
+	if (fe->dtv_property_cache.isdbt_layer_enabled == 0)
+		fe->dtv_property_cache.isdbt_layer_enabled = 7;
+	return tc90522_set_if_agc(fe, true);
+}
+
+
+/*
+ * tuner I2C adapter functions
+ */
+
+static int
+tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct tc90522_state *state;
+	struct i2c_msg *new_msgs;
+	int i, j;
+	int ret, rd_num;
+	u8 wbuf[256];
+	u8 *p, *bufend;
+
+	if (num <= 0)
+		return -EINVAL;
+
+	rd_num = 0;
+	for (i = 0; i < num; i++)
+		if (msgs[i].flags & I2C_M_RD)
+			rd_num++;
+	new_msgs = kmalloc(sizeof(*new_msgs) * (num + rd_num), GFP_KERNEL);
+	if (!new_msgs)
+		return -ENOMEM;
+
+	state = i2c_get_adapdata(adap);
+	p = wbuf;
+	bufend = wbuf + sizeof(wbuf);
+	for (i = 0, j = 0; i < num; i++, j++) {
+		new_msgs[j].addr = state->i2c_client->addr;
+		new_msgs[j].flags = msgs[i].flags;
+
+		if (msgs[i].flags & I2C_M_RD) {
+			new_msgs[j].flags &= ~I2C_M_RD;
+			if (p + 2 > bufend)
+				break;
+			p[0] = TC90522_I2C_THRU_REG;
+			p[1] = msgs[i].addr << 1 | 0x01;
+			new_msgs[j].buf = p;
+			new_msgs[j].len = 2;
+			p += 2;
+			j++;
+			new_msgs[j].addr = state->i2c_client->addr;
+			new_msgs[j].flags = msgs[i].flags;
+			new_msgs[j].buf = msgs[i].buf;
+			new_msgs[j].len = msgs[i].len;
+			continue;
+		}
+
+		if (p + msgs[i].len + 2 > bufend)
+			break;
+		p[0] = TC90522_I2C_THRU_REG;
+		p[1] = msgs[i].addr << 1;
+		memcpy(p + 2, msgs[i].buf, msgs[i].len);
+		new_msgs[j].buf = p;
+		new_msgs[j].len = msgs[i].len + 2;
+		p += new_msgs[j].len;
+	}
+
+	if (i < num)
+		ret = -ENOMEM;
+	else
+		ret = i2c_transfer(state->i2c_client->adapter, new_msgs, j);
+	if (ret >= 0 && ret < j)
+		ret = -EIO;
+	kfree(new_msgs);
+	return (ret == j) ? num : ret;
+}
+
+static u32 tc90522_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm tc90522_tuner_i2c_algo = {
+	.master_xfer   = &tc90522_master_xfer,
+	.functionality = &tc90522_functionality,
+};
+
+
+/*
+ * I2C driver functions
+ */
+
+static const struct dvb_frontend_ops tc90522_ops_sat = {
+	.delsys = { SYS_ISDBS },
+	.info = {
+		.name = "Toshiba TC90522 ISDB-S module",
+		.frequency_min =  950000,
+		.frequency_max = 2150000,
+		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.init = tc90522_init,
+	.sleep = tc90522_sleep,
+	.set_frontend = tc90522_set_frontend,
+	.get_tune_settings = tc90522_get_tune_settings,
+
+	.get_frontend = tc90522s_get_frontend,
+	.read_status = tc90522s_read_status,
+};
+
+static const struct dvb_frontend_ops tc90522_ops_ter = {
+	.delsys = { SYS_ISDBT },
+	.info = {
+		.name = "Toshiba TC90522 ISDB-T module",
+		.frequency_min = 470000000,
+		.frequency_max = 770000000,
+		.frequency_stepsize = 142857,
+		.caps = FE_CAN_INVERSION_AUTO |
+			FE_CAN_FEC_1_2  | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6  | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK     | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
+			FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.init = tc90522_init,
+	.sleep = tc90522_sleep,
+	.set_frontend = tc90522_set_frontend,
+	.get_tune_settings = tc90522_get_tune_settings,
+
+	.get_frontend = tc90522t_get_frontend,
+	.read_status = tc90522t_read_status,
+};
+
+
+static int tc90522_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct tc90522_state *state;
+	struct tc90522_config *cfg;
+	const struct dvb_frontend_ops *ops;
+	struct i2c_adapter *adap;
+	int ret;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+	state->i2c_client = client;
+
+	cfg = client->dev.platform_data;
+	memcpy(&state->cfg, cfg, sizeof(state->cfg));
+	cfg->fe = state->cfg.fe = &state->fe;
+	ops =  id->driver_data == 0 ? &tc90522_ops_sat : &tc90522_ops_ter;
+	memcpy(&state->fe.ops, ops, sizeof(*ops));
+	state->fe.demodulator_priv = state;
+
+	adap = &state->tuner_i2c;
+	adap->owner = THIS_MODULE;
+	adap->algo = &tc90522_tuner_i2c_algo;
+	adap->dev.parent = &client->dev;
+	strlcpy(adap->name, "tc90522_sub", sizeof(adap->name));
+	i2c_set_adapdata(adap, state);
+	ret = i2c_add_adapter(adap);
+	if (ret < 0)
+		goto err;
+	cfg->tuner_i2c = state->cfg.tuner_i2c = adap;
+
+	i2c_set_clientdata(client, &state->cfg);
+	dev_info(&client->dev, "Toshiba TC90522 attached.\n");
+	return 0;
+
+err:
+	kfree(state);
+	return ret;
+}
+
+static int tc90522_remove(struct i2c_client *client)
+{
+	struct tc90522_state *state;
+
+	state = cfg_to_state(i2c_get_clientdata(client));
+	i2c_del_adapter(&state->tuner_i2c);
+	kfree(state);
+	return 0;
+}
+
+
+static const struct i2c_device_id tc90522_id[] = {
+	{ TC90522_I2C_DEV_SAT, 0 },
+	{ TC90522_I2C_DEV_TER, 1 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, tc90522_id);
+
+static struct i2c_driver tc90522_driver = {
+	.driver = {
+		.name	= "tc90522",
+	},
+	.probe		= tc90522_probe,
+	.remove		= tc90522_remove,
+	.id_table	= tc90522_id,
+};
+
+module_i2c_driver(tc90522_driver);
+
+MODULE_DESCRIPTION("Toshiba TC90522 frontend");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/tc90522.h b/drivers/media/dvb-frontends/tc90522.h
new file mode 100644
index 0000000..b1cbddf
--- /dev/null
+++ b/drivers/media/dvb-frontends/tc90522.h
@@ -0,0 +1,42 @@
+/*
+ * Toshiba TC90522 Demodulator
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * The demod has 4 input (2xISDB-T and 2xISDB-S),
+ * and provides independent sub modules for each input.
+ * As the sub modules work in parallel and have the separate i2c addr's,
+ * this driver treats each sub module as one demod device.
+ */
+
+#ifndef TC90522_H
+#define TC90522_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/* I2C device types */
+#define TC90522_I2C_DEV_SAT "tc90522sat"
+#define TC90522_I2C_DEV_TER "tc90522ter"
+
+struct tc90522_config {
+	/* [OUT] frontend returned by driver */
+	struct dvb_frontend *fe;
+
+	/* [OUT] tuner I2C adapter returned by driver */
+	struct i2c_adapter *tuner_i2c;
+};
+
+#endif /* TC90522_H */
diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c
index 9619be5..4a19b85 100644
--- a/drivers/media/dvb-frontends/tda10071.c
+++ b/drivers/media/dvb-frontends/tda10071.c
@@ -1037,7 +1037,7 @@
 			ret = -EFAULT;
 			goto error;
 		} else {
-			priv->warm = 1;
+			priv->warm = true;
 		}
 
 		cmd.args[0] = CMD_GET_FW_VERSION;
diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c
index 91b6b2e..ee09ec2 100644
--- a/drivers/media/dvb-frontends/zl10039.c
+++ b/drivers/media/dvb-frontends/zl10039.c
@@ -111,7 +111,7 @@
 
 	if (1 + count > sizeof(buf)) {
 		printk(KERN_WARNING
-		       "%s: i2c wr reg=%04x: len=%zd is too big!\n",
+		       "%s: i2c wr reg=%04x: len=%zu is too big!\n",
 		       KBUILD_MODNAME, reg, count);
 		return -EINVAL;
 	}
diff --git a/drivers/media/firewire/firedtv-avc.c b/drivers/media/firewire/firedtv-avc.c
index d1a1a13..251a556 100644
--- a/drivers/media/firewire/firedtv-avc.c
+++ b/drivers/media/firewire/firedtv-avc.c
@@ -1157,6 +1157,10 @@
 		if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
 			dev_err(fdtv->device,
 				"invalid pmt_cmd_id %d\n", pmt_cmd_id);
+		if (program_info_length > sizeof(c->operand) - 4 - write_pos) {
+			ret = -EINVAL;
+			goto out;
+		}
 
 		memcpy(&c->operand[write_pos], &msg[read_pos],
 		       program_info_length);
@@ -1180,6 +1184,12 @@
 				dev_err(fdtv->device, "invalid pmt_cmd_id %d "
 					"at stream level\n", pmt_cmd_id);
 
+			if (es_info_length > sizeof(c->operand) - 4 -
+					     write_pos) {
+				ret = -EINVAL;
+				goto out;
+			}
+
 			memcpy(&c->operand[write_pos], &msg[read_pos],
 			       es_info_length);
 			read_pos += es_info_length;
diff --git a/drivers/media/i2c/adv7343_regs.h b/drivers/media/i2c/adv7343_regs.h
index 4466067..2f04ce4 100644
--- a/drivers/media/i2c/adv7343_regs.h
+++ b/drivers/media/i2c/adv7343_regs.h
@@ -13,7 +13,7 @@
  * GNU General Public License for more details.
  */
 
-#ifndef ADV7343_REG_H
+#ifndef ADV7343_REGS_H
 #define ADV7343_REGS_H
 
 struct adv7343_std_info {
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index a7d292a..bb6c3a4 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -1593,7 +1593,7 @@
 			bt->height += hdmi_read16(sd, 0x0b, 0xfff);
 			bt->il_vfrontporch = hdmi_read16(sd, 0x2c, 0x1fff) / 2;
 			bt->il_vsync = hdmi_read16(sd, 0x30, 0x1fff) / 2;
-			bt->vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2;
+			bt->il_vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2;
 		}
 		adv7604_fill_optional_dv_timings_fields(sd, timings);
 	} else {
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index fb7ea66..ba8e833 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -1435,6 +1435,8 @@
 
 	v4l2_dbg(1, debug, sd, "%s:\n", __func__);
 
+	memset(timings, 0, sizeof(struct v4l2_dv_timings));
+
 	/* SDP block */
 	if (state->mode == ADV7842_MODE_SDP)
 		return -ENODATA;
@@ -1483,7 +1485,7 @@
 					hdmi_read(sd, 0x2d)) / 2;
 			bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x1f) * 256 +
 					hdmi_read(sd, 0x31)) / 2;
-			bt->vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 +
+			bt->il_vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 +
 					hdmi_read(sd, 0x35)) / 2;
 		}
 		adv7842_fill_optional_dv_timings_fields(sd, timings);
diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
index e6588ee..4cf8f18 100644
--- a/drivers/media/i2c/cx25840/cx25840-ir.c
+++ b/drivers/media/i2c/cx25840/cx25840-ir.c
@@ -224,7 +224,7 @@
 }
 
 /*
- * FIFO register pulse width count compuations
+ * FIFO register pulse width count computations
  */
 static u32 clock_divider_to_resolution(u16 divider)
 {
diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
index c23de59..d9ece4b 100644
--- a/drivers/media/i2c/lm3560.c
+++ b/drivers/media/i2c/lm3560.c
@@ -100,14 +100,14 @@
 	int rval;
 
 	if (led_no == LM3560_LED0) {
-		if (on == true)
+		if (on)
 			rval = regmap_update_bits(flash->regmap,
 						  REG_ENABLE, 0x08, 0x08);
 		else
 			rval = regmap_update_bits(flash->regmap,
 						  REG_ENABLE, 0x08, 0x00);
 	} else {
-		if (on == true)
+		if (on)
 			rval = regmap_update_bits(flash->regmap,
 						  REG_ENABLE, 0x10, 0x10);
 		else
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index ce7e384..ad8795f 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -19,6 +19,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-mediabus.h>
+#include <media/v4l2-image-sizes.h>
 #include <media/ov7670.h>
 
 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
@@ -30,19 +31,6 @@
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 /*
- * Basic window sizes.  These probably belong somewhere more globally
- * useful.
- */
-#define VGA_WIDTH	640
-#define VGA_HEIGHT	480
-#define QVGA_WIDTH	320
-#define QVGA_HEIGHT	240
-#define CIF_WIDTH	352
-#define CIF_HEIGHT	288
-#define QCIF_WIDTH	176
-#define	QCIF_HEIGHT	144
-
-/*
  * The 7670 sits on i2c with ID 0x42
  */
 #define OV7670_I2C_ADDR 0x42
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 564f05f..0e461a6 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -816,7 +816,7 @@
 				 "error setting frame interval: %d\n", err);
 			state->error = -EINVAL;
 		}
-	};
+	}
 	v4l2_err(&state->sd, "cannot find correct frame interval\n");
 	state->error = -ERANGE;
 }
diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c
index 04e9e55..4024ea6 100644
--- a/drivers/media/i2c/saa6752hs.c
+++ b/drivers/media/i2c/saa6752hs.c
@@ -660,7 +660,7 @@
 static int saa6752hs_probe(struct i2c_client *client,
 		const struct i2c_device_id *id)
 {
-	struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL);
+	struct saa6752hs_state *h;
 	struct v4l2_subdev *sd;
 	struct v4l2_ctrl_handler *hdl;
 	u8 addr = 0x13;
@@ -668,6 +668,8 @@
 
 	v4l_info(client, "chip found @ 0x%x (%s)\n",
 			client->addr << 1, client->adapter->name);
+
+	h = devm_kzalloc(&client->dev, sizeof(*h), GFP_KERNEL);
 	if (h == NULL)
 		return -ENOMEM;
 	sd = &h->sd;
@@ -752,7 +754,6 @@
 		int err = hdl->error;
 
 		v4l2_ctrl_handler_free(hdl);
-		kfree(h);
 		return err;
 	}
 	v4l2_ctrl_cluster(3, &h->video_bitrate_mode);
@@ -767,7 +768,6 @@
 
 	v4l2_device_unregister_subdev(sd);
 	v4l2_ctrl_handler_free(&to_state(sd)->hdl);
-	kfree(to_state(sd));
 	return 0;
 }
 
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 62acb10..932ed9b 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -31,8 +31,9 @@
 #include <linux/device.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
-#include <linux/slab.h>
 #include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/smiapp.h>
 #include <linux/v4l2-mediabus.h>
 #include <media/v4l2-device.h>
 
@@ -297,8 +298,9 @@
 	if (rval < 0)
 		return rval;
 
-	*sensor->pixel_rate_parray->p_cur.p_s64 = pll->vt_pix_clk_freq_hz;
-	*sensor->pixel_rate_csi->p_cur.p_s64 = pll->pixel_rate_csi;
+	__v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_parray,
+				 pll->vt_pix_clk_freq_hz);
+	__v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_csi, pll->pixel_rate_csi);
 
 	return 0;
 }
@@ -319,13 +321,7 @@
 		+ sensor->vblank->val
 		- sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
 
-	ctrl->maximum = max;
-	if (ctrl->default_value > max)
-		ctrl->default_value = max;
-	if (ctrl->val > max)
-		ctrl->val = max;
-	if (ctrl->cur.val > max)
-		ctrl->cur.val = max;
+	__v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max);
 }
 
 /*
@@ -404,6 +400,14 @@
 		pixel_order_str[pixel_order]);
 }
 
+static const char * const smiapp_test_patterns[] = {
+	"Disabled",
+	"Solid Colour",
+	"Eight Vertical Colour Bars",
+	"Colour Bars With Fade to Grey",
+	"Pseudorandom Sequence (PN9)",
+};
+
 static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct smiapp_sensor *sensor =
@@ -477,6 +481,39 @@
 
 		return smiapp_pll_update(sensor);
 
+	case V4L2_CID_TEST_PATTERN: {
+		unsigned int i;
+
+		for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++)
+			v4l2_ctrl_activate(
+				sensor->test_data[i],
+				ctrl->val ==
+				V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR);
+
+		return smiapp_write(
+			sensor, SMIAPP_REG_U16_TEST_PATTERN_MODE, ctrl->val);
+	}
+
+	case V4L2_CID_TEST_PATTERN_RED:
+		return smiapp_write(
+			sensor, SMIAPP_REG_U16_TEST_DATA_RED, ctrl->val);
+
+	case V4L2_CID_TEST_PATTERN_GREENR:
+		return smiapp_write(
+			sensor, SMIAPP_REG_U16_TEST_DATA_GREENR, ctrl->val);
+
+	case V4L2_CID_TEST_PATTERN_BLUE:
+		return smiapp_write(
+			sensor, SMIAPP_REG_U16_TEST_DATA_BLUE, ctrl->val);
+
+	case V4L2_CID_TEST_PATTERN_GREENB:
+		return smiapp_write(
+			sensor, SMIAPP_REG_U16_TEST_DATA_GREENB, ctrl->val);
+
+	case V4L2_CID_PIXEL_RATE:
+		/* For v4l2_ctrl_s_ctrl_int64() used internally. */
+		return 0;
+
 	default:
 		return -EINVAL;
 	}
@@ -489,10 +526,10 @@
 static int smiapp_init_controls(struct smiapp_sensor *sensor)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
-	unsigned int max;
+	unsigned int max, i;
 	int rval;
 
-	rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7);
+	rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12);
 	if (rval)
 		return rval;
 	sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
@@ -535,6 +572,20 @@
 		&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
 		V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
 
+	v4l2_ctrl_new_std_menu_items(&sensor->pixel_array->ctrl_handler,
+				     &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN,
+				     ARRAY_SIZE(smiapp_test_patterns) - 1,
+				     0, 0, smiapp_test_patterns);
+
+	for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) {
+		int max_value = (1 << sensor->csi_format->width) - 1;
+		sensor->test_data[i] =
+			v4l2_ctrl_new_std(
+				&sensor->pixel_array->ctrl_handler,
+				&smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i,
+				0, max_value, 1, max_value);
+	}
+
 	if (sensor->pixel_array->ctrl_handler.error) {
 		dev_err(&client->dev,
 			"pixel array controls initialization failed (%d)\n",
@@ -782,36 +833,25 @@
 {
 	struct v4l2_ctrl *vblank = sensor->vblank;
 	struct v4l2_ctrl *hblank = sensor->hblank;
+	int min, max;
 
-	vblank->minimum =
-		max_t(int,
-		      sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
-		      sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
-		      sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
-	vblank->maximum =
-		sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
+	min = max_t(int,
+		    sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
+		    sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
+		    sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
+	max = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
 		sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height;
 
-	vblank->val = clamp_t(int, vblank->val,
-			      vblank->minimum, vblank->maximum);
-	vblank->default_value = vblank->minimum;
-	vblank->val = vblank->val;
-	vblank->cur.val = vblank->val;
+	__v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min);
 
-	hblank->minimum =
-		max_t(int,
-		      sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
-		      sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width,
-		      sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
-	hblank->maximum =
-		sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
+	min = max_t(int,
+		    sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
+		    sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width,
+		    sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
+	max = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
 		sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width;
 
-	hblank->val = clamp_t(int, hblank->val,
-			      hblank->minimum, hblank->maximum);
-	hblank->default_value = hblank->minimum;
-	hblank->val = hblank->val;
-	hblank->cur.val = hblank->val;
+	__v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min);
 
 	__smiapp_update_exposure_limits(sensor);
 }
@@ -1272,7 +1312,7 @@
 		clk_disable_unprepare(sensor->ext_clk);
 	usleep_range(5000, 5000);
 	regulator_disable(sensor->vana);
-	sensor->streaming = 0;
+	sensor->streaming = false;
 }
 
 static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
@@ -1462,13 +1502,13 @@
 		return 0;
 
 	if (enable) {
-		sensor->streaming = 1;
+		sensor->streaming = true;
 		rval = smiapp_start_streaming(sensor);
 		if (rval < 0)
-			sensor->streaming = 0;
+			sensor->streaming = false;
 	} else {
 		rval = smiapp_stop_streaming(sensor);
-		sensor->streaming = 0;
+		sensor->streaming = false;
 	}
 
 	return rval;
@@ -1664,17 +1704,34 @@
 	if (fmt->pad == ssd->source_pad) {
 		u32 code = fmt->format.code;
 		int rval = __smiapp_get_format(subdev, fh, fmt);
+		bool range_changed = false;
+		unsigned int i;
 
 		if (!rval && subdev == &sensor->src->sd) {
 			const struct smiapp_csi_data_format *csi_format =
 				smiapp_validate_csi_data_format(sensor, code);
-			if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+
+			if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+				if (csi_format->width !=
+				    sensor->csi_format->width)
+					range_changed = true;
+
 				sensor->csi_format = csi_format;
+			}
+
 			fmt->format.code = csi_format->code;
 		}
 
 		mutex_unlock(&sensor->mutex);
-		return rval;
+		if (rval || !range_changed)
+			return rval;
+
+		for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++)
+			v4l2_ctrl_modify_range(
+				sensor->test_data[i],
+				0, (1 << sensor->csi_format->width) - 1, 1, 0);
+
+		return 0;
 	}
 
 	/* Sink pad. Width and height are changeable here. */
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h
index 7cc5aae..874b49f 100644
--- a/drivers/media/i2c/smiapp/smiapp.h
+++ b/drivers/media/i2c/smiapp/smiapp.h
@@ -54,6 +54,8 @@
 	(1000 +	(SMIAPP_RESET_DELAY_CLOCKS * 1000	\
 		 + (clk) / 1000 - 1) / ((clk) / 1000))
 
+#define SMIAPP_COLOUR_COMPONENTS	4
+
 #include "smiapp-limits.h"
 
 struct smiapp_quirk;
@@ -241,6 +243,8 @@
 	/* src controls */
 	struct v4l2_ctrl *link_freq;
 	struct v4l2_ctrl *pixel_rate_csi;
+	/* test pattern colour components */
+	struct v4l2_ctrl *test_data[SMIAPP_COLOUR_COMPONENTS];
 };
 
 #define to_smiapp_subdev(_sd)				\
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c
index 5c33849..7520e11 100644
--- a/drivers/media/i2c/soc_camera/mt9t112.c
+++ b/drivers/media/i2c/soc_camera/mt9t112.c
@@ -29,6 +29,7 @@
 #include <media/soc_camera.h>
 #include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-image-sizes.h>
 
 /* you can check PLL/clock info */
 /* #define EXT_CLOCK 24000000 */
@@ -42,9 +43,6 @@
 #define MAX_WIDTH   2048
 #define MAX_HEIGHT  1536
 
-#define VGA_WIDTH   640
-#define VGA_HEIGHT  480
-
 /*
  * macro of read/write
  */
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c
index e998c3c..8650c78 100644
--- a/drivers/media/i2c/soc_camera/ov772x.c
+++ b/drivers/media/i2c/soc_camera/ov772x.c
@@ -29,6 +29,7 @@
 #include <media/v4l2-clk.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-subdev.h>
+#include <media/v4l2-image-sizes.h>
 
 /*
  * register offset
@@ -360,10 +361,6 @@
 #define SCAL0_ACTRL     0x08 /* Auto scaling factor control */
 #define SCAL1_2_ACTRL   0x04 /* Auto scaling factor control */
 
-#define VGA_WIDTH		640
-#define VGA_HEIGHT		480
-#define QVGA_WIDTH		320
-#define QVGA_HEIGHT		240
 #define OV772X_MAX_WIDTH	VGA_WIDTH
 #define OV772X_MAX_HEIGHT	VGA_HEIGHT
 
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c
index 1c2e8d6..7e2656a 100644
--- a/drivers/media/i2c/soc_camera/ov9740.c
+++ b/drivers/media/i2c/soc_camera/ov9740.c
@@ -564,13 +564,13 @@
 	u32 y_start;
 	u32 x_end;
 	u32 y_end;
-	bool scaling = 0;
+	bool scaling = false;
 	u32 scale_input_x;
 	u32 scale_input_y;
 	int ret;
 
 	if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT))
-		scaling = 1;
+		scaling = true;
 
 	/*
 	 * Try to use as much of the sensor area as possible when supporting
diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c
index 72af644..cf93021 100644
--- a/drivers/media/i2c/tda7432.c
+++ b/drivers/media/i2c/tda7432.c
@@ -293,7 +293,7 @@
 		if (t->mute->val) {
 			lf |= TDA7432_MUTE;
 			lr |= TDA7432_MUTE;
-			lf |= TDA7432_MUTE;
+			rf |= TDA7432_MUTE;
 			rr |= TDA7432_MUTE;
 		}
 		/* Mute & update balance*/
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index cebe014..28f978e 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -775,25 +775,20 @@
 static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct tvp7002 *device = to_tvp7002(sd);
-	int error = 0;
+	int error;
 
 	if (device->streaming == enable)
 		return 0;
 
-	if (enable) {
-		/* Set output state on (low impedance means stream on) */
-		error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00);
-		device->streaming = enable;
-	} else {
-		/* Set output state off (high impedance means stream off) */
-		error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x03);
-		if (error)
-			v4l2_dbg(1, debug, sd, "Unable to stop streaming\n");
-
-		device->streaming = enable;
+	/* low impedance: on, high impedance: off */
+	error = tvp7002_write(sd, TVP7002_MISC_CTL_2, enable ? 0x00 : 0x03);
+	if (error) {
+		v4l2_dbg(1, debug, sd, "Fail to set streaming\n");
+		return error;
 	}
 
-	return error;
+	device->streaming = enable;
+	return 0;
 }
 
 /*
diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c
index 7107ad6..e315d8b 100644
--- a/drivers/media/i2c/vs6624.c
+++ b/drivers/media/i2c/vs6624.c
@@ -30,22 +30,10 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-mediabus.h>
+#include <media/v4l2-image-sizes.h>
 
 #include "vs6624_regs.h"
 
-#define VGA_WIDTH       640
-#define VGA_HEIGHT      480
-#define QVGA_WIDTH      320
-#define QVGA_HEIGHT     240
-#define QQVGA_WIDTH     160
-#define QQVGA_HEIGHT    120
-#define CIF_WIDTH       352
-#define CIF_HEIGHT      288
-#define QCIF_WIDTH      176
-#define QCIF_HEIGHT     144
-#define QQCIF_WIDTH     88
-#define QQCIF_HEIGHT    72
-
 #define MAX_FRAME_RATE  30
 
 struct vs6624 {
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 73a4329..7b39440 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -103,10 +103,8 @@
 		return -EINVAL;
 
 	u_ent.id = ent->id;
-	if (ent->name) {
-		strncpy(u_ent.name, ent->name, sizeof(u_ent.name));
-		u_ent.name[sizeof(u_ent.name) - 1] = '\0';
-	}
+	if (ent->name)
+		strlcpy(u_ent.name, ent->name, sizeof(u_ent.name));
 	u_ent.type = ent->type;
 	u_ent.revision = ent->revision;
 	u_ent.flags = ent->flags;
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index 7acd19c..ebf9626 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -192,7 +192,6 @@
 static int media_release(struct inode *inode, struct file *filp)
 {
 	struct media_devnode *mdev = media_devnode_data(filp);
-	int ret = 0;
 
 	if (mdev->fops->release)
 		mdev->fops->release(filp);
@@ -201,7 +200,7 @@
 	   return value is ignored. */
 	put_device(&mdev->dev);
 	filp->private_data = NULL;
-	return ret;
+	return 0;
 }
 
 static const struct file_operations media_devnode_fops = {
diff --git a/drivers/media/parport/pms.c b/drivers/media/parport/pms.c
index 9bc105b..e6b4975 100644
--- a/drivers/media/parport/pms.c
+++ b/drivers/media/parport/pms.c
@@ -629,11 +629,15 @@
 {
 	int y;
 	int dw = 2 * dev->width;
-	char tmp[dw + 32]; /* using a temp buffer is faster than direct  */
+	char *tmp; /* using a temp buffer is faster than direct  */
 	int cnt = 0;
 	int len = 0;
 	unsigned char r8 = 0x5;  /* value for reg8  */
 
+	tmp = kmalloc(dw + 32, GFP_KERNEL);
+	if (!tmp)
+		return 0;
+
 	if (rgb555)
 		r8 |= 0x20; /* else use untranslated rgb = 565 */
 	mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */
@@ -664,6 +668,7 @@
 			len += dt;
 		}
 	}
+	kfree(tmp);
 	return len;
 }
 
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig
index 5c16c9c..f8cec8e 100644
--- a/drivers/media/pci/Kconfig
+++ b/drivers/media/pci/Kconfig
@@ -20,6 +20,7 @@
 source "drivers/media/pci/zoran/Kconfig"
 source "drivers/media/pci/saa7146/Kconfig"
 source "drivers/media/pci/solo6x10/Kconfig"
+source "drivers/media/pci/tw68/Kconfig"
 endif
 
 if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
@@ -41,6 +42,7 @@
 source "drivers/media/pci/pluto2/Kconfig"
 source "drivers/media/pci/dm1105/Kconfig"
 source "drivers/media/pci/pt1/Kconfig"
+source "drivers/media/pci/pt3/Kconfig"
 source "drivers/media/pci/mantis/Kconfig"
 source "drivers/media/pci/ngene/Kconfig"
 source "drivers/media/pci/ddbridge/Kconfig"
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile
index bea25ea..abdb56a 100644
--- a/drivers/media/pci/Makefile
+++ b/drivers/media/pci/Makefile
@@ -7,10 +7,10 @@
 		pluto2/		\
 		dm1105/		\
 		pt1/		\
+		pt3/		\
 		mantis/		\
 		ngene/		\
 		ddbridge/	\
-		b2c2/		\
 		saa7146/
 
 obj-$(CPTCFG_VIDEO_IVTV) += ivtv/
@@ -22,6 +22,7 @@
 obj-$(CPTCFG_VIDEO_BT848) += bt8xx/
 obj-$(CPTCFG_VIDEO_SAA7134) += saa7134/
 obj-$(CPTCFG_VIDEO_SAA7164) += saa7164/
+obj-$(CPTCFG_VIDEO_TW68) += tw68/
 obj-$(CPTCFG_VIDEO_MEYE) += meye/
 obj-$(CPTCFG_STA2X11_VIP) += sta2x11/
 obj-$(CPTCFG_VIDEO_SOLO6X10) += solo6x10/
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 59586b0..7a787be 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -1531,7 +1531,6 @@
 {
 	struct bttv_buffer *old;
 	unsigned long flags;
-	int retval = 0;
 
 	dprintk("switch_overlay: enter [new=%p]\n", new);
 	if (new)
@@ -1551,7 +1550,7 @@
 	if (NULL == new)
 		free_btres_lock(btv,fh,RESOURCE_OVERLAY);
 	dprintk("switch_overlay: done\n");
-	return retval;
+	return 0;
 }
 
 /* ----------------------------------------------------------------------- */
@@ -3856,7 +3855,7 @@
 
 				btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
 						BT848_INT_MASK);
-			};
+			}
 
 			bttv_print_irqbits(stat,astat);
 
diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c
index 0e788fc..c22c4ae 100644
--- a/drivers/media/pci/bt8xx/dst_ca.c
+++ b/drivers/media/pci/bt8xx/dst_ca.c
@@ -674,11 +674,9 @@
 
 static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
 {
-	ssize_t bytes_read = 0;
-
 	dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
 
-	return bytes_read;
+	return 0;
 }
 
 static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.c b/drivers/media/pci/cx18/cx18-alsa-pcm.c
index 180077c..ffb6acd 100644
--- a/drivers/media/pci/cx18/cx18-alsa-pcm.c
+++ b/drivers/media/pci/cx18/cx18-alsa-pcm.c
@@ -80,7 +80,7 @@
 	int period_elapsed = 0;
 	int length;
 
-	dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zd\n", cxsc,
+	dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zu\n", cxsc,
 		pcm_data, num_bytes);
 
 	substream = cxsc->capture_pcm_substream;
diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c
index a1c1cec..c6c8344 100644
--- a/drivers/media/pci/cx18/cx18-firmware.c
+++ b/drivers/media/pci/cx18/cx18-firmware.c
@@ -130,7 +130,7 @@
 		}
 	}
 	if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
-		CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+		CX18_INFO("loaded %s firmware (%zu bytes)\n", fn, fw->size);
 	size = fw->size;
 	release_firmware(fw);
 	cx18_setup_page(cx, SCB_OFFSET);
@@ -164,7 +164,7 @@
 
 	apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
 	while (offset + sizeof(seghdr) < fw->size) {
-		const u32 *shptr = src + offset / 4;
+		const __le32 *shptr = (__force __le32 *)src + offset / 4;
 
 		seghdr.sync1 = le32_to_cpu(shptr[0]);
 		seghdr.sync2 = le32_to_cpu(shptr[1]);
@@ -202,7 +202,7 @@
 		offset += seghdr.size;
 	}
 	if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
-		CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n",
+		CX18_INFO("loaded %s firmware V%08x (%zu bytes)\n",
 				fn, apu_version, fw->size);
 	size = fw->size;
 	release_firmware(fw);
diff --git a/drivers/media/pci/cx18/cx18-queue.c b/drivers/media/pci/cx18/cx18-queue.c
index 8884537..2a247d2 100644
--- a/drivers/media/pci/cx18/cx18-queue.c
+++ b/drivers/media/pci/cx18/cx18-queue.c
@@ -364,7 +364,7 @@
 					((char __iomem *)cx->scb->cpu_mdl));
 
 		CX18_ERR("Too many buffers, cannot fit in SCB area\n");
-		CX18_ERR("Max buffers = %zd\n",
+		CX18_ERR("Max buffers = %zu\n",
 			bufsz / sizeof(struct cx18_mdl_ent));
 		return -ENOMEM;
 	}
diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig
index 80e128e..911c260 100644
--- a/drivers/media/pci/cx23885/Kconfig
+++ b/drivers/media/pci/cx23885/Kconfig
@@ -1,15 +1,15 @@
 config VIDEO_CX23885
+	depends on !BACKPORT_KERNEL_3_4
 	tristate "Conexant cx23885 (2388x successor) support"
 	depends on m
 	depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND
 	depends on SND_PCM
 	depends on I2C_ALGOBIT
-	select VIDEO_BTCX
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	depends on RC_CORE
-	select VIDEOBUF_DVB
-	select VIDEOBUF_DMA_SG
+	select VIDEOBUF2_DVB
+	select VIDEOBUF2_DMA_SG
 	select VIDEO_CX25840
 	select VIDEO_CX2341X
 	select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT
@@ -33,12 +33,16 @@
 	select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
 	select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
 	select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT
+	select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
+	select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
 	select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
+	select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
+	select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
 	select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
 	---help---
 	  This is a video4linux driver for Conexant 23885 based
diff --git a/drivers/media/pci/cx23885/Makefile b/drivers/media/pci/cx23885/Makefile
index 4d16641..90ccb78 100644
--- a/drivers/media/pci/cx23885/Makefile
+++ b/drivers/media/pci/cx23885/Makefile
@@ -8,7 +8,6 @@
 obj-$(CPTCFG_MEDIA_ALTERA_CI) += altera-ci.o
 
 ccflags-y += -I$(backport_srctree)/drivers/media/i2c
-ccflags-y += -I$(backport_srctree)/drivers/media/common
 ccflags-y += -I$(backport_srctree)/drivers/media/tuners
 ccflags-y += -I$(backport_srctree)/drivers/media/dvb-core
 ccflags-y += -I$(backport_srctree)/drivers/media/dvb-frontends
diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c
index 2926f7f..2bbbf54 100644
--- a/drivers/media/pci/cx23885/altera-ci.c
+++ b/drivers/media/pci/cx23885/altera-ci.c
@@ -16,10 +16,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 /*
@@ -52,8 +48,8 @@
  * |  DATA7|  DATA6|  DATA5|  DATA4|  DATA3|  DATA2|  DATA1|  DATA0|
  * +-------+-------+-------+-------+-------+-------+-------+-------+
  */
-#include <media/videobuf-dma-sg.h>
-#include <media/videobuf-dvb.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
 #include "altera-ci.h"
 #include "dvb_ca_en50221.h"
 
diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h
index 30b190d..0ade583 100644
--- a/drivers/media/pci/cx23885/altera-ci.h
+++ b/drivers/media/pci/cx23885/altera-ci.h
@@ -16,10 +16,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #ifndef __ALTERA_CI_H
 #define __ALTERA_CI_H
diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c
index 16fa7ea..631e4f2 100644
--- a/drivers/media/pci/cx23885/cimax2.c
+++ b/drivers/media/pci/cx23885/cimax2.c
@@ -17,10 +17,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include "cx23885.h"
diff --git a/drivers/media/pci/cx23885/cimax2.h b/drivers/media/pci/cx23885/cimax2.h
index 518744a..565e958 100644
--- a/drivers/media/pci/cx23885/cimax2.h
+++ b/drivers/media/pci/cx23885/cimax2.h
@@ -17,10 +17,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef CIMAX2_H
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index 1c12a5c..4a4f949 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -18,10 +18,6 @@
  *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/module.h>
@@ -865,6 +861,11 @@
 	return err;
 }
 
+static int cx23885_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
+{
+	return cx23885_mbox_func(priv, cmd, in, out, data);
+}
+
 static int cx23885_find_mailbox(struct cx23885_dev *dev)
 {
 	u32 signature[4] = {
@@ -941,7 +942,7 @@
 
 	if (firmware->size != CX23885_FIRM_IMAGE_SIZE) {
 		printk(KERN_ERR "ERROR: Firmware size mismatch "
-			"(have %zd, expected %d)\n",
+			"(have %zu, expected %d)\n",
 			firmware->size, CX23885_FIRM_IMAGE_SIZE);
 		release_firmware(firmware);
 		return -1;
@@ -1033,12 +1034,12 @@
 	cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
 				dev->ts1.height, dev->ts1.width);
 
-	dev->mpeg_params.width = dev->ts1.width;
-	dev->mpeg_params.height = dev->ts1.height;
-	dev->mpeg_params.is_50hz =
+	dev->cxhdl.width = dev->ts1.width;
+	dev->cxhdl.height = dev->ts1.height;
+	dev->cxhdl.is_50hz =
 		(dev->encodernorm.id & V4L2_STD_625_50) != 0;
 
-	cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params);
+	cx2341x_handler_setup(&dev->cxhdl);
 
 	cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
 	cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
@@ -1137,85 +1138,107 @@
 
 /* ------------------------------------------------------------------ */
 
-static int bb_buf_setup(struct videobuf_queue *q,
-	unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+			   unsigned int *num_buffers, unsigned int *num_planes,
+			   unsigned int sizes[], void *alloc_ctxs[])
 {
-	struct cx23885_fh *fh = q->priv_data;
+	struct cx23885_dev *dev = q->drv_priv;
 
-	fh->dev->ts1.ts_packet_size  = mpeglinesize;
-	fh->dev->ts1.ts_packet_count = mpeglines;
-
-	*size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
-	*count = mpegbufs;
-
+	dev->ts1.ts_packet_size  = mpeglinesize;
+	dev->ts1.ts_packet_count = mpeglines;
+	*num_planes = 1;
+	sizes[0] = mpeglinesize * mpeglines;
+	*num_buffers = mpegbufs;
 	return 0;
 }
 
-static int bb_buf_prepare(struct videobuf_queue *q,
-	struct videobuf_buffer *vb, enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-	struct cx23885_fh *fh = q->priv_data;
-	return cx23885_buf_prepare(q, &fh->dev->ts1,
-		(struct cx23885_buffer *)vb,
-		field);
+	struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+	struct cx23885_buffer *buf =
+		container_of(vb, struct cx23885_buffer, vb);
+
+	return cx23885_buf_prepare(buf, &dev->ts1);
 }
 
-static void bb_buf_queue(struct videobuf_queue *q,
-	struct videobuf_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
 {
-	struct cx23885_fh *fh = q->priv_data;
-	cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb);
+	struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+	struct cx23885_buffer *buf = container_of(vb,
+		struct cx23885_buffer, vb);
+	struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+
+	cx23885_free_buffer(dev, buf);
+
+	dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
 }
 
-static void bb_buf_release(struct videobuf_queue *q,
-	struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
 {
-	cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
+	struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+	struct cx23885_buffer   *buf = container_of(vb,
+		struct cx23885_buffer, vb);
+
+	cx23885_buf_queue(&dev->ts1, buf);
 }
 
-static struct videobuf_queue_ops cx23885_qops = {
-	.buf_setup    = bb_buf_setup,
-	.buf_prepare  = bb_buf_prepare,
-	.buf_queue    = bb_buf_queue,
-	.buf_release  = bb_buf_release,
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct cx23885_dev *dev = q->drv_priv;
+	struct cx23885_dmaqueue *dmaq = &dev->ts1.mpegq;
+	unsigned long flags;
+	int ret;
+
+	ret = cx23885_initialize_codec(dev, 1);
+	if (ret == 0) {
+		struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+			struct cx23885_buffer, queue);
+
+		cx23885_start_dma(&dev->ts1, dmaq, buf);
+		return 0;
+	}
+	spin_lock_irqsave(&dev->slock, flags);
+	while (!list_empty(&dmaq->active)) {
+		struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+			struct cx23885_buffer, queue);
+
+		list_del(&buf->queue);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+	}
+	spin_unlock_irqrestore(&dev->slock, flags);
+	return ret;
+}
+
+static void cx23885_stop_streaming(struct vb2_queue *q)
+{
+	struct cx23885_dev *dev = q->drv_priv;
+
+	/* stop mpeg capture */
+	cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+			CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+			CX23885_RAW_BITS_NONE);
+
+	msleep(500);
+	cx23885_417_check_encoder(dev);
+	cx23885_cancel_buffers(&dev->ts1);
+}
+
+static struct vb2_ops cx23885_qops = {
+	.queue_setup    = queue_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_finish = buffer_finish,
+	.buf_queue    = buffer_queue,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+	.start_streaming = cx23885_start_streaming,
+	.stop_streaming = cx23885_stop_streaming,
 };
 
 /* ------------------------------------------------------------------ */
 
-static const u32 *ctrl_classes[] = {
-	cx2341x_mpeg_ctrls,
-	NULL
-};
-
-static int cx23885_queryctrl(struct cx23885_dev *dev,
-	struct v4l2_queryctrl *qctrl)
-{
-	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
-	if (qctrl->id == 0)
-		return -EINVAL;
-
-	/* MPEG V4L2 controls */
-	if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
-		qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
-
-	return 0;
-}
-
-static int cx23885_querymenu(struct cx23885_dev *dev,
-	struct v4l2_querymenu *qmenu)
-{
-	struct v4l2_queryctrl qctrl;
-
-	qctrl.id = qmenu->id;
-	cx23885_queryctrl(dev, &qctrl);
-	return v4l2_ctrl_query_menu(qmenu, &qctrl,
-		cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
-}
-
 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 {
-	struct cx23885_fh  *fh  = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	*id = dev->tvnorm;
 	return 0;
@@ -1223,29 +1246,26 @@
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
 {
-	struct cx23885_fh  *fh  = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 	unsigned int i;
+	int ret;
 
 	for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
 		if (id & cx23885_tvnorms[i].id)
 			break;
 	if (i == ARRAY_SIZE(cx23885_tvnorms))
 		return -EINVAL;
-	dev->encodernorm = cx23885_tvnorms[i];
 
-	/* Have the drier core notify the subdevices */
-	mutex_lock(&dev->lock);
-	cx23885_set_tvnorm(dev, id);
-	mutex_unlock(&dev->lock);
-
-	return 0;
+	ret = cx23885_set_tvnorm(dev, id);
+	if (!ret)
+		dev->encodernorm = cx23885_tvnorms[i];
+	return ret;
 }
 
 static int vidioc_enum_input(struct file *file, void *priv,
 	struct v4l2_input *i)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 	dprintk(1, "%s()\n", __func__);
 	return cx23885_enum_input(dev, i);
 }
@@ -1263,8 +1283,7 @@
 static int vidioc_g_tuner(struct file *file, void *priv,
 				struct v4l2_tuner *t)
 {
-	struct cx23885_fh  *fh  = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	if (dev->tuner_type == TUNER_ABSENT)
 		return -EINVAL;
@@ -1281,8 +1300,7 @@
 static int vidioc_s_tuner(struct file *file, void *priv,
 				const struct v4l2_tuner *t)
 {
-	struct cx23885_fh  *fh  = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	if (dev->tuner_type == TUNER_ABSENT)
 		return -EINVAL;
@@ -1296,8 +1314,7 @@
 static int vidioc_g_frequency(struct file *file, void *priv,
 				struct v4l2_frequency *f)
 {
-	struct cx23885_fh  *fh  = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	if (dev->tuner_type == TUNER_ABSENT)
 		return -EINVAL;
@@ -1315,27 +1332,10 @@
 	return cx23885_set_frequency(file, priv, f);
 }
 
-static int vidioc_g_ctrl(struct file *file, void *priv,
-	struct v4l2_control *ctl)
-{
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
-	return cx23885_get_control(dev, ctl);
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-	struct v4l2_control *ctl)
-{
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
-	return cx23885_set_control(dev, ctl);
-}
-
 static int vidioc_querycap(struct file *file, void  *priv,
 				struct v4l2_capability *cap)
 {
-	struct cx23885_fh  *fh  = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 	struct cx23885_tsport  *tsport = &dev->ts1;
 
 	strlcpy(cap->driver, dev->name, sizeof(cap->driver));
@@ -1368,8 +1368,7 @@
 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
-	struct cx23885_fh  *fh  = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
 	f->fmt.pix.bytesperline = 0;
@@ -1378,285 +1377,63 @@
 	f->fmt.pix.colorspace   = 0;
 	f->fmt.pix.width        = dev->ts1.width;
 	f->fmt.pix.height       = dev->ts1.height;
-	f->fmt.pix.field        = fh->mpegq.field;
-	dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
-		dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+	f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
+	dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n",
+		dev->ts1.width, dev->ts1.height);
 	return 0;
 }
 
 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
-	struct cx23885_fh  *fh  = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
 	f->fmt.pix.bytesperline = 0;
 	f->fmt.pix.sizeimage    =
 		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
 	f->fmt.pix.colorspace   = 0;
-	dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
-		dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+	f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
+	dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
+		dev->ts1.width, dev->ts1.height);
 	return 0;
 }
 
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
-	struct cx23885_fh  *fh  = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
 	f->fmt.pix.bytesperline = 0;
 	f->fmt.pix.sizeimage    =
 		dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
 	f->fmt.pix.colorspace   = 0;
+	f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
 	dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
 		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
 	return 0;
 }
 
-static int vidioc_reqbufs(struct file *file, void *priv,
-				struct v4l2_requestbuffers *p)
-{
-	struct cx23885_fh  *fh  = file->private_data;
-
-	return videobuf_reqbufs(&fh->mpegq, p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
-				struct v4l2_buffer *p)
-{
-	struct cx23885_fh  *fh  = file->private_data;
-
-	return videobuf_querybuf(&fh->mpegq, p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv,
-				struct v4l2_buffer *p)
-{
-	struct cx23885_fh  *fh  = file->private_data;
-
-	return videobuf_qbuf(&fh->mpegq, p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
-	struct cx23885_fh  *fh  = priv;
-
-	return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK);
-}
-
-
-static int vidioc_streamon(struct file *file, void *priv,
-				enum v4l2_buf_type i)
-{
-	struct cx23885_fh  *fh  = file->private_data;
-
-	return videobuf_streamon(&fh->mpegq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx23885_fh  *fh  = file->private_data;
-
-	return videobuf_streamoff(&fh->mpegq);
-}
-
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
-				struct v4l2_ext_controls *f)
-{
-	struct cx23885_fh  *fh  = priv;
-	struct cx23885_dev *dev = fh->dev;
-
-	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-		return -EINVAL;
-	return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
-}
-
-static int vidioc_s_ext_ctrls(struct file *file, void *priv,
-				struct v4l2_ext_controls *f)
-{
-	struct cx23885_fh  *fh  = priv;
-	struct cx23885_dev *dev = fh->dev;
-	struct cx2341x_mpeg_params p;
-	int err;
-
-	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-		return -EINVAL;
-
-	p = dev->mpeg_params;
-	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
-
-	if (err == 0) {
-		err = cx2341x_update(dev, cx23885_mbox_func,
-			&dev->mpeg_params, &p);
-		dev->mpeg_params = p;
-	}
-	return err;
-}
-
-static int vidioc_try_ext_ctrls(struct file *file, void *priv,
-				struct v4l2_ext_controls *f)
-{
-	struct cx23885_fh  *fh  = priv;
-	struct cx23885_dev *dev = fh->dev;
-	struct cx2341x_mpeg_params p;
-	int err;
-
-	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-		return -EINVAL;
-
-	p = dev->mpeg_params;
-	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
-	return err;
-}
-
 static int vidioc_log_status(struct file *file, void *priv)
 {
-	struct cx23885_fh  *fh  = priv;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 	char name[32 + 2];
 
 	snprintf(name, sizeof(name), "%s/2", dev->name);
-	printk(KERN_INFO
-		"%s/2: ============  START LOG STATUS  ============\n",
-	       dev->name);
 	call_all(dev, core, log_status);
-	cx2341x_log_status(&dev->mpeg_params, name);
-	printk(KERN_INFO
-		"%s/2: =============  END LOG STATUS  =============\n",
-	       dev->name);
+	v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name);
 	return 0;
 }
 
-static int vidioc_querymenu(struct file *file, void *priv,
-				struct v4l2_querymenu *a)
-{
-	struct cx23885_fh  *fh  = priv;
-	struct cx23885_dev *dev = fh->dev;
-
-	return cx23885_querymenu(dev, a);
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-				struct v4l2_queryctrl *c)
-{
-	struct cx23885_fh  *fh  = priv;
-	struct cx23885_dev *dev = fh->dev;
-
-	return cx23885_queryctrl(dev, c);
-}
-
-static int mpeg_open(struct file *file)
-{
-	struct cx23885_dev *dev = video_drvdata(file);
-	struct cx23885_fh *fh;
-
-	dprintk(2, "%s()\n", __func__);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (!fh)
-		return -ENOMEM;
-
-	file->private_data = fh;
-	fh->dev      = dev;
-
-	videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops,
-			    &dev->pci->dev, &dev->ts1.slock,
-			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			    V4L2_FIELD_INTERLACED,
-			    sizeof(struct cx23885_buffer),
-			    fh, NULL);
-	return 0;
-}
-
-static int mpeg_release(struct file *file)
-{
-	struct cx23885_fh  *fh  = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
-
-	dprintk(2, "%s()\n", __func__);
-
-	/* FIXME: Review this crap */
-	/* Shut device down on last close */
-	if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
-		if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
-			/* stop mpeg capture */
-			cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
-				CX23885_END_NOW, CX23885_MPEG_CAPTURE,
-				CX23885_RAW_BITS_NONE);
-
-			msleep(500);
-			cx23885_417_check_encoder(dev);
-
-			cx23885_cancel_buffers(&fh->dev->ts1);
-		}
-	}
-
-	if (fh->mpegq.streaming)
-		videobuf_streamoff(&fh->mpegq);
-	if (fh->mpegq.reading)
-		videobuf_read_stop(&fh->mpegq);
-
-	videobuf_mmap_free(&fh->mpegq);
-	file->private_data = NULL;
-	kfree(fh);
-
-	return 0;
-}
-
-static ssize_t mpeg_read(struct file *file, char __user *data,
-	size_t count, loff_t *ppos)
-{
-	struct cx23885_fh *fh = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
-
-	dprintk(2, "%s()\n", __func__);
-
-	/* Deal w/ A/V decoder * and mpeg encoder sync issues. */
-	/* Start mpeg encoder on first read. */
-	if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
-		if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
-			if (cx23885_initialize_codec(dev, 1) < 0)
-				return -EINVAL;
-		}
-	}
-
-	return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
-				    file->f_flags & O_NONBLOCK);
-}
-
-static unsigned int mpeg_poll(struct file *file,
-	struct poll_table_struct *wait)
-{
-	struct cx23885_fh *fh = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
-
-	dprintk(2, "%s\n", __func__);
-
-	return videobuf_poll_stream(file, &fh->mpegq, wait);
-}
-
-static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct cx23885_fh *fh = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
-
-	dprintk(2, "%s()\n", __func__);
-
-	return videobuf_mmap_mapper(&fh->mpegq, vma);
-}
-
 static struct v4l2_file_operations mpeg_fops = {
 	.owner	       = THIS_MODULE,
-	.open	       = mpeg_open,
-	.release       = mpeg_release,
-	.read	       = mpeg_read,
-	.poll          = mpeg_poll,
-	.mmap	       = mpeg_mmap,
-	.ioctl	       = video_ioctl2,
+	.open           = v4l2_fh_open,
+	.release        = vb2_fop_release,
+	.read           = vb2_fop_read,
+	.poll		= vb2_fop_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap           = vb2_fop_mmap,
 };
 
 static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
@@ -1669,25 +1446,19 @@
 	.vidioc_s_tuner		 = vidioc_s_tuner,
 	.vidioc_g_frequency	 = vidioc_g_frequency,
 	.vidioc_s_frequency	 = vidioc_s_frequency,
-	.vidioc_s_ctrl		 = vidioc_s_ctrl,
-	.vidioc_g_ctrl		 = vidioc_g_ctrl,
 	.vidioc_querycap	 = vidioc_querycap,
 	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
 	.vidioc_g_fmt_vid_cap	 = vidioc_g_fmt_vid_cap,
 	.vidioc_try_fmt_vid_cap	 = vidioc_try_fmt_vid_cap,
 	.vidioc_s_fmt_vid_cap	 = vidioc_s_fmt_vid_cap,
-	.vidioc_reqbufs		 = vidioc_reqbufs,
-	.vidioc_querybuf	 = vidioc_querybuf,
-	.vidioc_qbuf		 = vidioc_qbuf,
-	.vidioc_dqbuf		 = vidioc_dqbuf,
-	.vidioc_streamon	 = vidioc_streamon,
-	.vidioc_streamoff	 = vidioc_streamoff,
-	.vidioc_g_ext_ctrls	 = vidioc_g_ext_ctrls,
-	.vidioc_s_ext_ctrls	 = vidioc_s_ext_ctrls,
-	.vidioc_try_ext_ctrls	 = vidioc_try_ext_ctrls,
+	.vidioc_reqbufs       = vb2_ioctl_reqbufs,
+	.vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
+	.vidioc_querybuf      = vb2_ioctl_querybuf,
+	.vidioc_qbuf          = vb2_ioctl_qbuf,
+	.vidioc_dqbuf         = vb2_ioctl_dqbuf,
+	.vidioc_streamon      = vb2_ioctl_streamon,
+	.vidioc_streamoff     = vb2_ioctl_streamoff,
 	.vidioc_log_status	 = vidioc_log_status,
-	.vidioc_querymenu	 = vidioc_querymenu,
-	.vidioc_queryctrl	 = vidioc_queryctrl,
 #ifdef CPTCFG_VIDEO_ADV_DEBUG
 	.vidioc_g_chip_info	 = cx23885_g_chip_info,
 	.vidioc_g_register	 = cx23885_g_register,
@@ -1711,6 +1482,7 @@
 			video_unregister_device(dev->v4l_device);
 		else
 			video_device_release(dev->v4l_device);
+		v4l2_ctrl_handler_free(&dev->cxhdl.hdl);
 		dev->v4l_device = NULL;
 	}
 }
@@ -1742,6 +1514,7 @@
 	/* FIXME: Port1 hardcoded here */
 	int err = -ENODEV;
 	struct cx23885_tsport *tsport = &dev->ts1;
+	struct vb2_queue *q;
 
 	dprintk(1, "%s()\n", __func__);
 
@@ -1757,14 +1530,36 @@
 		tsport->height = 576;
 
 	tsport->width = 720;
-	cx2341x_fill_defaults(&dev->mpeg_params);
-
-	dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+	dev->cxhdl.port = CX2341X_PORT_SERIAL;
+	err = cx2341x_handler_init(&dev->cxhdl, 50);
+	if (err)
+		return err;
+	dev->cxhdl.priv = dev;
+	dev->cxhdl.func = cx23885_api_func;
+	cx2341x_handler_set_50hz(&dev->cxhdl, tsport->height == 576);
+	v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL);
 
 	/* Allocate and initialize V4L video device */
 	dev->v4l_device = cx23885_video_dev_alloc(tsport,
 		dev->pci, &cx23885_mpeg_template, "mpeg");
+	q = &dev->vb2_mpegq;
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+	q->gfp_flags = GFP_DMA32;
+	q->min_buffers_needed = 2;
+	q->drv_priv = dev;
+	q->buf_struct_size = sizeof(struct cx23885_buffer);
+	q->ops = &cx23885_qops;
+	q->mem_ops = &vb2_dma_sg_memops;
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	q->lock = &dev->lock;
+
+	err = vb2_queue_init(q);
+	if (err < 0)
+		return err;
 	video_set_drvdata(dev->v4l_device, dev);
+	dev->v4l_device->lock = &dev->lock;
+	dev->v4l_device->queue = q;
 	err = video_register_device(dev->v4l_device,
 		VFL_TYPE_GRABBER, -1);
 	if (err < 0) {
diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c
index 554798d..ae7c2e8 100644
--- a/drivers/media/pci/cx23885/cx23885-alsa.c
+++ b/drivers/media/pci/cx23885/cx23885-alsa.c
@@ -15,10 +15,6 @@
  *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/module.h>
@@ -84,6 +80,82 @@
 #define AUD_INT_MCHG_IRQ        (1 << 21)
 #define GP_COUNT_CONTROL_RESET	0x3
 
+static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages)
+{
+	struct cx23885_audio_buffer *buf = chip->buf;
+	struct page *pg;
+	int i;
+
+	buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
+	if (NULL == buf->vaddr) {
+		dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
+		return -ENOMEM;
+	}
+
+	dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
+				(unsigned long)buf->vaddr,
+				nr_pages << PAGE_SHIFT);
+
+	memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);
+	buf->nr_pages = nr_pages;
+
+	buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist));
+	if (NULL == buf->sglist)
+		goto vzalloc_err;
+
+	sg_init_table(buf->sglist, buf->nr_pages);
+	for (i = 0; i < buf->nr_pages; i++) {
+		pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE);
+		if (NULL == pg)
+			goto vmalloc_to_page_err;
+		sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0);
+	}
+	return 0;
+
+vmalloc_to_page_err:
+	vfree(buf->sglist);
+	buf->sglist = NULL;
+vzalloc_err:
+	vfree(buf->vaddr);
+	buf->vaddr = NULL;
+	return -ENOMEM;
+}
+
+static int cx23885_alsa_dma_map(struct cx23885_audio_dev *dev)
+{
+	struct cx23885_audio_buffer *buf = dev->buf;
+
+	buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist,
+			buf->nr_pages, PCI_DMA_FROMDEVICE);
+
+	if (0 == buf->sglen) {
+		pr_warn("%s: cx23885_alsa_map_sg failed\n", __func__);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static int cx23885_alsa_dma_unmap(struct cx23885_audio_dev *dev)
+{
+	struct cx23885_audio_buffer *buf = dev->buf;
+
+	if (!buf->sglen)
+		return 0;
+
+	dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE);
+	buf->sglen = 0;
+	return 0;
+}
+
+static int cx23885_alsa_dma_free(struct cx23885_audio_buffer *buf)
+{
+	vfree(buf->sglist);
+	buf->sglist = NULL;
+	vfree(buf->vaddr);
+	buf->vaddr = NULL;
+	return 0;
+}
+
 /*
  * BOARD Specific: Sets audio DMA
  */
@@ -198,15 +270,18 @@
 
 static int dsp_buffer_free(struct cx23885_audio_dev *chip)
 {
+	struct cx23885_riscmem *risc;
+
 	BUG_ON(!chip->dma_size);
 
 	dprintk(2, "Freeing buffer\n");
-	videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
-	videobuf_dma_free(chip->dma_risc);
-	btcx_riscmem_free(chip->pci, &chip->buf->risc);
+	cx23885_alsa_dma_unmap(chip);
+	cx23885_alsa_dma_free(chip->buf);
+	risc = &chip->buf->risc;
+	pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma);
 	kfree(chip->buf);
 
-	chip->dma_risc = NULL;
+	chip->buf = NULL;
 	chip->dma_size = 0;
 
 	return 0;
@@ -289,6 +364,7 @@
 	return 0;
 }
 
+
 /*
  * hw_params callback
  */
@@ -296,8 +372,6 @@
 			      struct snd_pcm_hw_params *hw_params)
 {
 	struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
-	struct videobuf_dmabuf *dma;
-
 	struct cx23885_audio_buffer *buf;
 	int ret;
 
@@ -318,19 +392,18 @@
 		return -ENOMEM;
 
 	buf->bpl = chip->period_size;
+	chip->buf = buf;
 
-	dma = &buf->dma;
-	videobuf_dma_init(dma);
-	ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
+	ret = cx23885_alsa_dma_init(chip,
 			(PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
 	if (ret < 0)
 		goto error;
 
-	ret = videobuf_dma_map(&chip->pci->dev, dma);
+	ret = cx23885_alsa_dma_map(chip);
 	if (ret < 0)
 		goto error;
 
-	ret = cx23885_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+	ret = cx23885_risc_databuffer(chip->pci, &buf->risc, buf->sglist,
 				   chip->period_size, chip->num_periods, 1);
 	if (ret < 0)
 		goto error;
@@ -340,10 +413,7 @@
 	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
 
-	chip->buf = buf;
-	chip->dma_risc = dma;
-
-	substream->runtime->dma_area = chip->dma_risc->vaddr;
+	substream->runtime->dma_area = chip->buf->vaddr;
 	substream->runtime->dma_bytes = chip->dma_size;
 	substream->runtime->dma_addr = 0;
 
@@ -351,6 +421,7 @@
 
 error:
 	kfree(buf);
+	chip->buf = NULL;
 	return ret;
 }
 
diff --git a/drivers/media/pci/cx23885/cx23885-av.c b/drivers/media/pci/cx23885/cx23885-av.c
index c443b7a..877dad8 100644
--- a/drivers/media/pci/cx23885/cx23885-av.c
+++ b/drivers/media/pci/cx23885/cx23885-av.c
@@ -14,11 +14,6 @@
  *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #include "cx23885.h"
diff --git a/drivers/media/pci/cx23885/cx23885-av.h b/drivers/media/pci/cx23885/cx23885-av.h
index d2915c3..97f232f 100644
--- a/drivers/media/pci/cx23885/cx23885-av.h
+++ b/drivers/media/pci/cx23885/cx23885-av.h
@@ -14,11 +14,6 @@
  *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #ifndef _CX23885_AV_H_
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
index c2b6080..88c257d 100644
--- a/drivers/media/pci/cx23885/cx23885-cards.c
+++ b/drivers/media/pci/cx23885/cx23885-cards.c
@@ -13,10 +13,6 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/init.h>
@@ -679,6 +675,11 @@
 			.amux   = CX25840_AUDIO7,
 		} },
 	},
+	[CX23885_BOARD_DVBSKY_T9580] = {
+		.name		= "DVBSky T9580",
+		.portb		= CX23885_MPEG_DVB,
+		.portc		= CX23885_MPEG_DVB,
+	},
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -934,6 +935,10 @@
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb98,
 		.card      = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2,
+	}, {
+		.subvendor = 0x4254,
+		.subdevice = 0x9580,
+		.card      = CX23885_BOARD_DVBSKY_T9580,
 	},
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1528,6 +1533,14 @@
 		cx_set(GP0_IO, 0x00040004);
 		mdelay(60);
 		break;
+	case CX23885_BOARD_DVBSKY_T9580:
+		/* enable GPIO3-18 pins */
+		cx_write(MC417_CTL, 0x00000037);
+		cx23885_gpio_enable(dev, GPIO_2 | GPIO_11, 1);
+		cx23885_gpio_clear(dev, GPIO_2 | GPIO_11);
+		mdelay(100);
+		cx23885_gpio_set(dev, GPIO_2 | GPIO_11);
+		break;
 	}
 }
 
@@ -1851,6 +1864,14 @@
 		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
 		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
+	case CX23885_BOARD_DVBSKY_T9580:
+		ts1->gen_ctrl_val  = 0x5; /* Parallel */
+		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		ts2->gen_ctrl_val  = 0x8; /* Serial bus */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500:
 	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -1913,6 +1934,7 @@
 	case CX23885_BOARD_AVERMEDIA_HC81R:
 	case CX23885_BOARD_TBS_6980:
 	case CX23885_BOARD_TBS_6981:
+	case CX23885_BOARD_DVBSKY_T9580:
 		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
 				&dev->i2c_bus[2].i2c_adap,
 				"cx25840", 0x88 >> 1, NULL);
@@ -1970,5 +1992,3 @@
 	}
 	}
 }
-
-/* ------------------------------------------------------------------ */
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index edcd79d..331edda 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -13,10 +13,6 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/init.h>
@@ -420,39 +416,23 @@
 	return incr[risc >> 28] ? incr[risc >> 28] : 1;
 }
 
-void cx23885_wakeup(struct cx23885_tsport *port,
+static void cx23885_wakeup(struct cx23885_tsport *port,
 			   struct cx23885_dmaqueue *q, u32 count)
 {
 	struct cx23885_dev *dev = port->dev;
 	struct cx23885_buffer *buf;
-	int bc;
 
-	for (bc = 0;; bc++) {
-		if (list_empty(&q->active))
-			break;
-		buf = list_entry(q->active.next,
-				 struct cx23885_buffer, vb.queue);
-
-		/* count comes from the hw and is is 16bit wide --
-		 * this trick handles wrap-arounds correctly for
-		 * up to 32767 buffers in flight... */
-		if ((s16) (count - buf->count) < 0)
-			break;
-
-		v4l2_get_timestamp(&buf->vb.ts);
-		dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
-			count, buf->count);
-		buf->vb.state = VIDEOBUF_DONE;
-		list_del(&buf->vb.queue);
-		wake_up(&buf->vb.done);
-	}
 	if (list_empty(&q->active))
-		del_timer(&q->timeout);
-	else
-		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-	if (bc != 1)
-		printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n",
-		       __func__, bc);
+		return;
+	buf = list_entry(q->active.next,
+			 struct cx23885_buffer, queue);
+
+	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+	buf->vb.v4l2_buf.sequence = q->count++;
+	dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index,
+		count, q->count);
+	list_del(&buf->queue);
+	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
 }
 
 int cx23885_sram_channel_setup(struct cx23885_dev *dev,
@@ -482,8 +462,8 @@
 		lines = 6;
 	BUG_ON(lines < 2);
 
-	cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	cx_write(8 + 4, 8);
+	cx_write(8 + 0, RISC_JUMP | RISC_CNT_RESET);
+	cx_write(8 + 4, 12);
 	cx_write(8 + 8, 0);
 
 	/* write CDT */
@@ -590,7 +570,7 @@
 }
 
 static void cx23885_risc_disasm(struct cx23885_tsport *port,
-				struct btcx_riscmem *risc)
+				struct cx23885_riscmem *risc)
 {
 	struct cx23885_dev *dev = port->dev;
 	unsigned int i, j, n;
@@ -699,10 +679,6 @@
 	return -EBUSY;
 }
 
-static void cx23885_timeout(unsigned long data);
-int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-				u32 reg, u32 mask, u32 value);
-
 static int cx23885_init_tsport(struct cx23885_dev *dev,
 	struct cx23885_tsport *port, int portno)
 {
@@ -719,11 +695,6 @@
 	port->nr = portno;
 
 	INIT_LIST_HEAD(&port->mpegq.active);
-	INIT_LIST_HEAD(&port->mpegq.queued);
-	port->mpegq.timeout.function = cx23885_timeout;
-	port->mpegq.timeout.data = (unsigned long)port;
-	init_timer(&port->mpegq.timeout);
-
 	mutex_init(&port->frontends.lock);
 	INIT_LIST_HEAD(&port->frontends.felist);
 	port->frontends.active_fe_id = 0;
@@ -776,9 +747,6 @@
 		BUG();
 	}
 
-	cx23885_risc_stopper(dev->pci, &port->mpegq.stopper,
-		     port->reg_dma_ctl, port->dma_ctl_val, 0x00);
-
 	return 0;
 }
 
@@ -1089,11 +1057,18 @@
 static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
 			       unsigned int offset, u32 sync_line,
 			       unsigned int bpl, unsigned int padding,
-			       unsigned int lines,  unsigned int lpi)
+			       unsigned int lines,  unsigned int lpi, bool jump)
 {
 	struct scatterlist *sg;
 	unsigned int line, todo, sol;
 
+
+	if (jump) {
+		*(rp++) = cpu_to_le32(RISC_JUMP);
+		*(rp++) = cpu_to_le32(0);
+		*(rp++) = cpu_to_le32(0); /* bits 63-32 */
+	}
+
 	/* sync instruction */
 	if (sync_line != NO_SYNC_LINE)
 		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
@@ -1146,14 +1121,13 @@
 	return rp;
 }
 
-int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
 			struct scatterlist *sglist, unsigned int top_offset,
 			unsigned int bottom_offset, unsigned int bpl,
 			unsigned int padding, unsigned int lines)
 {
 	u32 instructions, fields;
 	__le32 *rp;
-	int rc;
 
 	fields = 0;
 	if (UNSET != top_offset)
@@ -1168,19 +1142,20 @@
 	/* write and jump need and extra dword */
 	instructions  = fields * (1 + ((bpl + padding) * lines)
 		/ PAGE_SIZE + lines);
-	instructions += 2;
-	rc = btcx_riscmem_alloc(pci, risc, instructions*12);
-	if (rc < 0)
-		return rc;
+	instructions += 5;
+	risc->size = instructions * 12;
+	risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
+	if (risc->cpu == NULL)
+		return -ENOMEM;
 
 	/* write risc instructions */
 	rp = risc->cpu;
 	if (UNSET != top_offset)
 		rp = cx23885_risc_field(rp, sglist, top_offset, 0,
-					bpl, padding, lines, 0);
+					bpl, padding, lines, 0, true);
 	if (UNSET != bottom_offset)
 		rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
-					bpl, padding, lines, 0);
+					bpl, padding, lines, 0, UNSET == top_offset);
 
 	/* save pointer to jmp instruction address */
 	risc->jmp = rp;
@@ -1189,14 +1164,13 @@
 }
 
 int cx23885_risc_databuffer(struct pci_dev *pci,
-				   struct btcx_riscmem *risc,
+				   struct cx23885_riscmem *risc,
 				   struct scatterlist *sglist,
 				   unsigned int bpl,
 				   unsigned int lines, unsigned int lpi)
 {
 	u32 instructions;
 	__le32 *rp;
-	int rc;
 
 	/* estimate risc mem: worst case is one write per page border +
 	   one write per scan line + syncs + jump (all 2 dwords).  Here
@@ -1204,16 +1178,17 @@
 	   than PAGE_SIZE */
 	/* Jump and write need an extra dword */
 	instructions  = 1 + (bpl * lines) / PAGE_SIZE + lines;
-	instructions += 1;
+	instructions += 4;
 
-	rc = btcx_riscmem_alloc(pci, risc, instructions*12);
-	if (rc < 0)
-		return rc;
+	risc->size = instructions * 12;
+	risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
+	if (risc->cpu == NULL)
+		return -ENOMEM;
 
 	/* write risc instructions */
 	rp = risc->cpu;
 	rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE,
-				bpl, 0, lines, lpi);
+				bpl, 0, lines, lpi, lpi == 0);
 
 	/* save pointer to jmp instruction address */
 	risc->jmp = rp;
@@ -1221,14 +1196,13 @@
 	return 0;
 }
 
-int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+int cx23885_risc_vbibuffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
 			struct scatterlist *sglist, unsigned int top_offset,
 			unsigned int bottom_offset, unsigned int bpl,
 			unsigned int padding, unsigned int lines)
 {
 	u32 instructions, fields;
 	__le32 *rp;
-	int rc;
 
 	fields = 0;
 	if (UNSET != top_offset)
@@ -1243,22 +1217,23 @@
 	/* write and jump need and extra dword */
 	instructions  = fields * (1 + ((bpl + padding) * lines)
 		/ PAGE_SIZE + lines);
-	instructions += 2;
-	rc = btcx_riscmem_alloc(pci, risc, instructions*12);
-	if (rc < 0)
-		return rc;
+	instructions += 5;
+	risc->size = instructions * 12;
+	risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
+	if (risc->cpu == NULL)
+		return -ENOMEM;
 	/* write risc instructions */
 	rp = risc->cpu;
 
 	/* Sync to line 6, so US CC line 21 will appear in line '12'
 	 * in the userland vbi payload */
 	if (UNSET != top_offset)
-		rp = cx23885_risc_field(rp, sglist, top_offset, 6,
-					bpl, padding, lines, 0);
+		rp = cx23885_risc_field(rp, sglist, top_offset, 0,
+					bpl, padding, lines, 0, true);
 
 	if (UNSET != bottom_offset)
-		rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207,
-					bpl, padding, lines, 0);
+		rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
+					bpl, padding, lines, 0, UNSET == top_offset);
 
 
 
@@ -1269,38 +1244,12 @@
 }
 
 
-int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-				u32 reg, u32 mask, u32 value)
+void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf)
 {
-	__le32 *rp;
-	int rc;
-
-	rc = btcx_riscmem_alloc(pci, risc, 4*16);
-	if (rc < 0)
-		return rc;
-
-	/* write risc instructions */
-	rp = risc->cpu;
-	*(rp++) = cpu_to_le32(RISC_WRITECR  | RISC_IRQ2);
-	*(rp++) = cpu_to_le32(reg);
-	*(rp++) = cpu_to_le32(value);
-	*(rp++) = cpu_to_le32(mask);
-	*(rp++) = cpu_to_le32(RISC_JUMP);
-	*(rp++) = cpu_to_le32(risc->dma);
-	*(rp++) = cpu_to_le32(0); /* bits 63-32 */
-	return 0;
-}
-
-void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
-{
-	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+	struct cx23885_riscmem *risc = &buf->risc;
 
 	BUG_ON(in_interrupt());
-	videobuf_waiton(q, &buf->vb, 0, 0);
-	videobuf_dma_unmap(q->dev, dma);
-	videobuf_dma_free(dma);
-	btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
-	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+	pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
 }
 
 static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
@@ -1355,7 +1304,7 @@
 		port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
 }
 
-static int cx23885_start_dma(struct cx23885_tsport *port,
+int cx23885_start_dma(struct cx23885_tsport *port,
 			     struct cx23885_dmaqueue *q,
 			     struct cx23885_buffer   *buf)
 {
@@ -1363,7 +1312,7 @@
 	u32 reg;
 
 	dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__,
-		buf->vb.width, buf->vb.height, buf->vb.field);
+		dev->width, dev->height, dev->field);
 
 	/* Stop the fifo and risc engine for this port */
 	cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
@@ -1379,7 +1328,7 @@
 	}
 
 	/* write TS length to chip */
-	cx_write(port->reg_lngth, buf->vb.width);
+	cx_write(port->reg_lngth, port->ts_packet_size);
 
 	if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
 		(!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) {
@@ -1408,7 +1357,7 @@
 	/* NOTE: this is 2 (reserved) for portb, does it matter? */
 	/* reset counter to zero */
 	cx_write(port->reg_gpcnt_ctl, 3);
-	q->count = 1;
+	q->count = 0;
 
 	/* Set VIDB pins to input */
 	if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
@@ -1497,134 +1446,83 @@
 	return 0;
 }
 
-int cx23885_restart_queue(struct cx23885_tsport *port,
-				struct cx23885_dmaqueue *q)
-{
-	struct cx23885_dev *dev = port->dev;
-	struct cx23885_buffer *buf;
-
-	dprintk(5, "%s()\n", __func__);
-	if (list_empty(&q->active)) {
-		struct cx23885_buffer *prev;
-		prev = NULL;
-
-		dprintk(5, "%s() queue is empty\n", __func__);
-
-		for (;;) {
-			if (list_empty(&q->queued))
-				return 0;
-			buf = list_entry(q->queued.next, struct cx23885_buffer,
-					 vb.queue);
-			if (NULL == prev) {
-				list_move_tail(&buf->vb.queue, &q->active);
-				cx23885_start_dma(port, q, buf);
-				buf->vb.state = VIDEOBUF_ACTIVE;
-				buf->count    = q->count++;
-				mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-				dprintk(5, "[%p/%d] restart_queue - f/active\n",
-					buf, buf->vb.i);
-
-			} else if (prev->vb.width  == buf->vb.width  &&
-				   prev->vb.height == buf->vb.height &&
-				   prev->fmt       == buf->fmt) {
-				list_move_tail(&buf->vb.queue, &q->active);
-				buf->vb.state = VIDEOBUF_ACTIVE;
-				buf->count    = q->count++;
-				prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-				/* 64 bit bits 63-32 */
-				prev->risc.jmp[2] = cpu_to_le32(0);
-				dprintk(5, "[%p/%d] restart_queue - m/active\n",
-					buf, buf->vb.i);
-			} else {
-				return 0;
-			}
-			prev = buf;
-		}
-		return 0;
-	}
-
-	buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
-	dprintk(2, "restart_queue [%p/%d]: restart dma\n",
-		buf, buf->vb.i);
-	cx23885_start_dma(port, q, buf);
-	list_for_each_entry(buf, &q->active, vb.queue)
-		buf->count = q->count++;
-	mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-	return 0;
-}
-
 /* ------------------------------------------------------------------ */
 
-int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
-			struct cx23885_buffer *buf, enum v4l2_field field)
+int cx23885_buf_prepare(struct cx23885_buffer *buf, struct cx23885_tsport *port)
 {
 	struct cx23885_dev *dev = port->dev;
 	int size = port->ts_packet_size * port->ts_packet_count;
+	struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb, 0);
 	int rc;
 
 	dprintk(1, "%s: %p\n", __func__, buf);
-	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+	if (vb2_plane_size(&buf->vb, 0) < size)
 		return -EINVAL;
+	vb2_set_plane_payload(&buf->vb, 0, size);
 
-	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-		buf->vb.width  = port->ts_packet_size;
-		buf->vb.height = port->ts_packet_count;
-		buf->vb.size   = size;
-		buf->vb.field  = field /*V4L2_FIELD_TOP*/;
+	rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+	if (!rc)
+		return -EIO;
 
-		rc = videobuf_iolock(q, &buf->vb, NULL);
-		if (0 != rc)
-			goto fail;
-		cx23885_risc_databuffer(dev->pci, &buf->risc,
-					videobuf_to_dma(&buf->vb)->sglist,
-					buf->vb.width, buf->vb.height, 0);
-	}
-	buf->vb.state = VIDEOBUF_PREPARED;
+	cx23885_risc_databuffer(dev->pci, &buf->risc,
+				sgt->sgl,
+				port->ts_packet_size, port->ts_packet_count, 0);
 	return 0;
-
- fail:
-	cx23885_free_buffer(q, buf);
-	return rc;
 }
 
+/*
+ * The risc program for each buffer works as follows: it starts with a simple
+ * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
+ * the initial JUMP).
+ *
+ * This is the risc program of the first buffer to be queued if the active list
+ * is empty and it just keeps DMAing this buffer without generating any
+ * interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the code for that buffer
+ * will generate an interrupt which signals that the previous buffer has been
+ * DMAed successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
 void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
 {
 	struct cx23885_buffer    *prev;
 	struct cx23885_dev *dev = port->dev;
 	struct cx23885_dmaqueue  *cx88q = &port->mpegq;
+	unsigned long flags;
 
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
+	buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
 	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
 
+	spin_lock_irqsave(&dev->slock, flags);
 	if (list_empty(&cx88q->active)) {
-		dprintk(1, "queue is empty - first active\n");
-		list_add_tail(&buf->vb.queue, &cx88q->active);
-		cx23885_start_dma(port, cx88q, buf);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count    = cx88q->count++;
-		mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
+		list_add_tail(&buf->queue, &cx88q->active);
 		dprintk(1, "[%p/%d] %s - first active\n",
-			buf, buf->vb.i, __func__);
+			buf, buf->vb.v4l2_buf.index, __func__);
 	} else {
-		dprintk(1, "queue is not empty - append to active\n");
+		buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
 		prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
-				  vb.queue);
-		list_add_tail(&buf->vb.queue, &cx88q->active);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count    = cx88q->count++;
+				  queue);
+		list_add_tail(&buf->queue, &cx88q->active);
 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-		prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
 		dprintk(1, "[%p/%d] %s - append to active\n",
-			 buf, buf->vb.i, __func__);
+			 buf, buf->vb.v4l2_buf.index, __func__);
 	}
+	spin_unlock_irqrestore(&dev->slock, flags);
 }
 
 /* ----------------------------------------------------------- */
 
-static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
-			      int restart)
+static void do_cancel_buffers(struct cx23885_tsport *port, char *reason)
 {
 	struct cx23885_dev *dev = port->dev;
 	struct cx23885_dmaqueue *q = &port->mpegq;
@@ -1634,16 +1532,11 @@
 	spin_lock_irqsave(&port->slock, flags);
 	while (!list_empty(&q->active)) {
 		buf = list_entry(q->active.next, struct cx23885_buffer,
-				 vb.queue);
-		list_del(&buf->vb.queue);
-		buf->vb.state = VIDEOBUF_ERROR;
-		wake_up(&buf->vb.done);
+				 queue);
+		list_del(&buf->queue);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
 		dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
-			buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
-	}
-	if (restart) {
-		dprintk(1, "restarting queue\n");
-		cx23885_restart_queue(port, q);
+			buf, buf->vb.v4l2_buf.index, reason, (unsigned long)buf->risc.dma);
 	}
 	spin_unlock_irqrestore(&port->slock, flags);
 }
@@ -1651,27 +1544,10 @@
 void cx23885_cancel_buffers(struct cx23885_tsport *port)
 {
 	struct cx23885_dev *dev = port->dev;
-	struct cx23885_dmaqueue *q = &port->mpegq;
 
 	dprintk(1, "%s()\n", __func__);
-	del_timer_sync(&q->timeout);
 	cx23885_stop_dma(port);
-	do_cancel_buffers(port, "cancel", 0);
-}
-
-static void cx23885_timeout(unsigned long data)
-{
-	struct cx23885_tsport *port = (struct cx23885_tsport *)data;
-	struct cx23885_dev *dev = port->dev;
-
-	dprintk(1, "%s()\n", __func__);
-
-	if (debug > 5)
-		cx23885_sram_channel_dump(dev,
-			&dev->sram_channels[port->sram_chno]);
-
-	cx23885_stop_dma(port);
-	do_cancel_buffers(port, "timeout", 1);
+	do_cancel_buffers(port, "cancel");
 }
 
 int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
@@ -1721,11 +1597,6 @@
 		spin_lock(&port->slock);
 		cx23885_wakeup(port, &port->mpegq, count);
 		spin_unlock(&port->slock);
-	} else if (status & VID_B_MSK_RISCI2) {
-		dprintk(7, "        VID_B_MSK_RISCI2\n");
-		spin_lock(&port->slock);
-		cx23885_restart_queue(port, &port->mpegq);
-		spin_unlock(&port->slock);
 	}
 	if (status) {
 		cx_write(port->reg_ts_int_stat, status);
@@ -1777,14 +1648,6 @@
 		cx23885_wakeup(port, &port->mpegq, count);
 		spin_unlock(&port->slock);
 
-	} else if (status & VID_BC_MSK_RISCI2) {
-
-		dprintk(7, " (RISCI2            0x%08x)\n", VID_BC_MSK_RISCI2);
-
-		spin_lock(&port->slock);
-		cx23885_restart_queue(port, &port->mpegq);
-		spin_unlock(&port->slock);
-
 	}
 	if (status) {
 		cx_write(port->reg_ts_int_stat, status);
@@ -2087,6 +1950,7 @@
 			   const struct pci_device_id *pci_id)
 {
 	struct cx23885_dev *dev;
+	struct v4l2_ctrl_handler *hdl;
 	int err;
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -2097,6 +1961,14 @@
 	if (err < 0)
 		goto fail_free;
 
+	hdl = &dev->ctrl_handler;
+	v4l2_ctrl_handler_init(hdl, 6);
+	if (hdl->error) {
+		err = hdl->error;
+		goto fail_ctrl;
+	}
+	dev->v4l2_dev.ctrl_handler = hdl;
+
 	/* Prepare to handle notifications from subdevices */
 	cx23885_v4l2_dev_notify_init(dev);
 
@@ -2104,12 +1976,12 @@
 	dev->pci = pci_dev;
 	if (pci_enable_device(pci_dev)) {
 		err = -EIO;
-		goto fail_unreg;
+		goto fail_ctrl;
 	}
 
 	if (cx23885_dev_setup(dev) < 0) {
 		err = -EINVAL;
-		goto fail_unreg;
+		goto fail_ctrl;
 	}
 
 	/* print pci info */
@@ -2157,7 +2029,8 @@
 
 fail_irq:
 	cx23885_dev_unregister(dev);
-fail_unreg:
+fail_ctrl:
+	v4l2_ctrl_handler_free(hdl);
 	v4l2_device_unregister(&dev->v4l2_dev);
 fail_free:
 	kfree(dev);
@@ -2180,6 +2053,7 @@
 	free_irq(pci_dev->irq, dev);
 
 	cx23885_dev_unregister(dev);
+	v4l2_ctrl_handler_free(&dev->ctrl_handler);
 	v4l2_device_unregister(v4l2_dev);
 	kfree(dev);
 }
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 968fecc..13734b8 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -13,10 +13,6 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/module.h>
@@ -73,6 +69,10 @@
 #include "a8293.h"
 #include "mb86a20s.h"
 #include "si2165.h"
+#include "si2168.h"
+#include "si2157.h"
+#include "m88ds3103.h"
+#include "m88ts2022.h"
 
 static unsigned int debug;
 
@@ -91,59 +91,95 @@
 
 /* ------------------------------------------------------------------ */
 
-static int dvb_buf_setup(struct videobuf_queue *q,
-			 unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+			   unsigned int *num_buffers, unsigned int *num_planes,
+			   unsigned int sizes[], void *alloc_ctxs[])
 {
-	struct cx23885_tsport *port = q->priv_data;
+	struct cx23885_tsport *port = q->drv_priv;
 
 	port->ts_packet_size  = 188 * 4;
 	port->ts_packet_count = 32;
-
-	*size  = port->ts_packet_size * port->ts_packet_count;
-	*count = 32;
+	*num_planes = 1;
+	sizes[0] = port->ts_packet_size * port->ts_packet_count;
+	*num_buffers = 32;
 	return 0;
 }
 
-static int dvb_buf_prepare(struct videobuf_queue *q,
-			   struct videobuf_buffer *vb, enum v4l2_field field)
+
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-	struct cx23885_tsport *port = q->priv_data;
-	return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field);
+	struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
+	struct cx23885_buffer *buf =
+		container_of(vb, struct cx23885_buffer, vb);
+
+	return cx23885_buf_prepare(buf, port);
 }
 
-static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
 {
-	struct cx23885_tsport *port = q->priv_data;
-	cx23885_buf_queue(port, (struct cx23885_buffer *)vb);
+	struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_buffer *buf = container_of(vb,
+		struct cx23885_buffer, vb);
+	struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+
+	cx23885_free_buffer(dev, buf);
+
+	dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
 }
 
-static void dvb_buf_release(struct videobuf_queue *q,
-			    struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
 {
-	cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
+	struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
+	struct cx23885_buffer   *buf = container_of(vb,
+		struct cx23885_buffer, vb);
+
+	cx23885_buf_queue(port, buf);
 }
 
 static void cx23885_dvb_gate_ctrl(struct cx23885_tsport  *port, int open)
 {
-	struct videobuf_dvb_frontends *f;
-	struct videobuf_dvb_frontend *fe;
+	struct vb2_dvb_frontends *f;
+	struct vb2_dvb_frontend *fe;
 
 	f = &port->frontends;
 
 	if (f->gate <= 1) /* undefined or fe0 */
-		fe = videobuf_dvb_get_frontend(f, 1);
+		fe = vb2_dvb_get_frontend(f, 1);
 	else
-		fe = videobuf_dvb_get_frontend(f, f->gate);
+		fe = vb2_dvb_get_frontend(f, f->gate);
 
 	if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
 		fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
 }
 
-static struct videobuf_queue_ops dvb_qops = {
-	.buf_setup    = dvb_buf_setup,
-	.buf_prepare  = dvb_buf_prepare,
-	.buf_queue    = dvb_buf_queue,
-	.buf_release  = dvb_buf_release,
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct cx23885_tsport *port = q->drv_priv;
+	struct cx23885_dmaqueue *dmaq = &port->mpegq;
+	struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+			struct cx23885_buffer, queue);
+
+	cx23885_start_dma(port, dmaq, buf);
+	return 0;
+}
+
+static void cx23885_stop_streaming(struct vb2_queue *q)
+{
+	struct cx23885_tsport *port = q->drv_priv;
+
+	cx23885_cancel_buffers(port);
+}
+
+static struct vb2_ops dvb_qops = {
+	.queue_setup    = queue_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_finish = buffer_finish,
+	.buf_queue    = buffer_queue,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+	.start_streaming = cx23885_start_streaming,
+	.stop_streaming = cx23885_stop_streaming,
 };
 
 static struct s5h1409_config hauppauge_generic_config = {
@@ -551,6 +587,35 @@
 	return 0;
 }
 
+static int dvbsky_t9580_set_voltage(struct dvb_frontend *fe,
+					fe_sec_voltage_t voltage)
+{
+	struct cx23885_tsport *port = fe->dvb->priv;
+	struct cx23885_dev *dev = port->dev;
+
+	cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1);
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		cx23885_gpio_set(dev, GPIO_1);
+		cx23885_gpio_clear(dev, GPIO_0);
+		break;
+	case SEC_VOLTAGE_18:
+		cx23885_gpio_set(dev, GPIO_1);
+		cx23885_gpio_set(dev, GPIO_0);
+		break;
+	case SEC_VOLTAGE_OFF:
+		cx23885_gpio_clear(dev, GPIO_1);
+		cx23885_gpio_clear(dev, GPIO_0);
+		break;
+	}
+
+	/* call the frontend set_voltage function */
+	port->fe_set_voltage(fe, voltage);
+
+	return 0;
+}
+
 static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
 {
 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
@@ -715,6 +780,19 @@
 	.ref_freq_Hz	= 16000000,
 };
 
+static const struct m88ds3103_config dvbsky_t9580_m88ds3103_config = {
+	.i2c_addr = 0x68,
+	.clock = 27000000,
+	.i2c_wr_max = 33,
+	.clock_out = 0,
+	.ts_mode = M88DS3103_TS_PARALLEL,
+	.ts_clk = 16000,
+	.ts_clk_pol = 1,
+	.lnb_en_pol = 1,
+	.lnb_hv_pol = 0,
+	.agc = 0x99,
+};
+
 static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
 {
 	struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -863,16 +941,23 @@
 	struct dib7000p_ops dib7000p_ops;
 	struct cx23885_dev *dev = port->dev;
 	struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
-	struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
+	struct vb2_dvb_frontend *fe0, *fe1 = NULL;
+	struct si2168_config si2168_config;
+	struct si2157_config si2157_config;
+	struct m88ts2022_config m88ts2022_config;
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client_demod;
+	struct i2c_client *client_tuner;
 	int mfe_shared = 0; /* bus not shared by default */
 	int ret;
 
 	/* Get the first frontend */
-	fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+	fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
 	if (!fe0)
 		return -EINVAL;
 
-	/* init struct videobuf_dvb */
+	/* init struct vb2_dvb */
 	fe0->dvb.name = dev->name;
 
 	/* multi-frontend gate control is undefined or defaults to fe0 */
@@ -1392,7 +1477,7 @@
 			fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
 		}
 		/* MFE frontend 2 */
-		fe1 = videobuf_dvb_get_frontend(&port->frontends, 2);
+		fe1 = vb2_dvb_get_frontend(&port->frontends, 2);
 		if (fe1 == NULL)
 			goto frontend_detach;
 		/* DVB-C init */
@@ -1491,7 +1576,7 @@
 					&hauppauge_hvr4400_si2165_config,
 					&i2c_bus->i2c_adap);
 			if (fe0->dvb.frontend != NULL) {
-				fe0->dvb.frontend->ops.i2c_gate_ctrl = 0;
+				fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
 				if (!dvb_attach(tda18271_attach,
 						fe0->dvb.frontend,
 						0x60, &i2c_bus2->i2c_adap,
@@ -1501,6 +1586,97 @@
 			break;
 		}
 		break;
+	case CX23885_BOARD_DVBSKY_T9580:
+		i2c_bus = &dev->i2c_bus[0];
+		i2c_bus2 = &dev->i2c_bus[1];
+		switch (port->nr) {
+		/* port b - satellite */
+		case 1:
+			/* attach frontend */
+			fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+					&dvbsky_t9580_m88ds3103_config,
+					&i2c_bus2->i2c_adap, &adapter);
+			if (fe0->dvb.frontend == NULL)
+				break;
+
+			/* attach tuner */
+			m88ts2022_config.fe = fe0->dvb.frontend;
+			m88ts2022_config.clock = 27000000;
+			memset(&info, 0, sizeof(struct i2c_board_info));
+			strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+			info.addr = 0x60;
+			info.platform_data = &m88ts2022_config;
+			request_module(info.type);
+			client_tuner = i2c_new_device(adapter, &info);
+			if (client_tuner == NULL ||
+					client_tuner->dev.driver == NULL)
+				goto frontend_detach;
+			if (!try_module_get(client_tuner->dev.driver->owner)) {
+				i2c_unregister_device(client_tuner);
+				goto frontend_detach;
+			}
+
+			/* delegate signal strength measurement to tuner */
+			fe0->dvb.frontend->ops.read_signal_strength =
+				fe0->dvb.frontend->ops.tuner_ops.get_rf_strength;
+
+			/*
+			 * for setting the voltage we need to set GPIOs on
+			 * the card.
+			 */
+			port->fe_set_voltage =
+				fe0->dvb.frontend->ops.set_voltage;
+			fe0->dvb.frontend->ops.set_voltage =
+				dvbsky_t9580_set_voltage;
+
+			port->i2c_client_tuner = client_tuner;
+
+			break;
+		/* port c - terrestrial/cable */
+		case 2:
+			/* attach frontend */
+			si2168_config.i2c_adapter = &adapter;
+			si2168_config.fe = &fe0->dvb.frontend;
+			si2168_config.ts_mode = SI2168_TS_SERIAL;
+			memset(&info, 0, sizeof(struct i2c_board_info));
+			strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+			info.addr = 0x64;
+			info.platform_data = &si2168_config;
+			request_module(info.type);
+			client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
+			if (client_demod == NULL ||
+					client_demod->dev.driver == NULL)
+				goto frontend_detach;
+			if (!try_module_get(client_demod->dev.driver->owner)) {
+				i2c_unregister_device(client_demod);
+				goto frontend_detach;
+			}
+			port->i2c_client_demod = client_demod;
+
+			/* attach tuner */
+			si2157_config.fe = fe0->dvb.frontend;
+			memset(&info, 0, sizeof(struct i2c_board_info));
+			strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+			info.addr = 0x60;
+			info.platform_data = &si2157_config;
+			request_module(info.type);
+			client_tuner = i2c_new_device(adapter, &info);
+			if (client_tuner == NULL ||
+					client_tuner->dev.driver == NULL) {
+				module_put(client_demod->dev.driver->owner);
+				i2c_unregister_device(client_demod);
+				goto frontend_detach;
+			}
+			if (!try_module_get(client_tuner->dev.driver->owner)) {
+				i2c_unregister_device(client_tuner);
+				module_put(client_demod->dev.driver->owner);
+				i2c_unregister_device(client_demod);
+				goto frontend_detach;
+			}
+			port->i2c_client_tuner = client_tuner;
+			break;
+		}
+		break;
 	default:
 		printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
 			" isn't supported yet\n",
@@ -1532,7 +1708,7 @@
 		fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
 
 	/* register everything */
-	ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+	ret = vb2_dvb_register_bus(&port->frontends, THIS_MODULE, port,
 					&dev->pci->dev, adapter_nr, mfe_shared);
 	if (ret)
 		goto frontend_detach;
@@ -1575,20 +1751,36 @@
 		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
 		break;
 		}
+	case CX23885_BOARD_DVBSKY_T9580: {
+		u8 eeprom[256]; /* 24C02 i2c eeprom */
+
+		if (port->nr > 2)
+			break;
+
+		/* Read entire EEPROM */
+		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
+				sizeof(eeprom));
+		printk(KERN_INFO "DVBSky T9580 port %d MAC address: %pM\n",
+			port->nr, eeprom + 0xc0 + (port->nr-1) * 8);
+		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 +
+			(port->nr-1) * 8, 6);
+		break;
+		}
 	}
 
 	return ret;
 
 frontend_detach:
 	port->gate_ctrl = NULL;
-	videobuf_dvb_dealloc_frontends(&port->frontends);
+	vb2_dvb_dealloc_frontends(&port->frontends);
 	return -EINVAL;
 }
 
 int cx23885_dvb_register(struct cx23885_tsport *port)
 {
 
-	struct videobuf_dvb_frontend *fe0;
+	struct vb2_dvb_frontend *fe0;
 	struct cx23885_dev *dev = port->dev;
 	int err, i;
 
@@ -1605,13 +1797,15 @@
 		port->num_frontends);
 
 	for (i = 1; i <= port->num_frontends; i++) {
-		if (videobuf_dvb_alloc_frontend(
+		struct vb2_queue *q;
+
+		if (vb2_dvb_alloc_frontend(
 			&port->frontends, i) == NULL) {
 			printk(KERN_ERR "%s() failed to alloc\n", __func__);
 			return -ENOMEM;
 		}
 
-		fe0 = videobuf_dvb_get_frontend(&port->frontends, i);
+		fe0 = vb2_dvb_get_frontend(&port->frontends, i);
 		if (!fe0)
 			err = -EINVAL;
 
@@ -1627,10 +1821,21 @@
 		/* dvb stuff */
 		/* We have to init the queue for each frontend on a port. */
 		printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name);
-		videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
-			    &dev->pci->dev, &port->slock,
-			    V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
-			    sizeof(struct cx23885_buffer), port, NULL);
+		q = &fe0->dvb.dvbq;
+		q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+		q->gfp_flags = GFP_DMA32;
+		q->min_buffers_needed = 2;
+		q->drv_priv = port;
+		q->buf_struct_size = sizeof(struct cx23885_buffer);
+		q->ops = &dvb_qops;
+		q->mem_ops = &vb2_dma_sg_memops;
+		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+		q->lock = &dev->lock;
+
+		err = vb2_queue_init(q);
+		if (err < 0)
+			return err;
 	}
 	err = dvb_register(port);
 	if (err != 0)
@@ -1642,18 +1847,27 @@
 
 int cx23885_dvb_unregister(struct cx23885_tsport *port)
 {
-	struct videobuf_dvb_frontend *fe0;
+	struct vb2_dvb_frontend *fe0;
+	struct i2c_client *client;
 
-	/* FIXME: in an error condition where the we have
-	 * an expected number of frontends (attach problem)
-	 * then this might not clean up correctly, if 1
-	 * is invalid.
-	 * This comment only applies to future boards IF they
-	 * implement MFE support.
-	 */
-	fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+	/* remove I2C client for tuner */
+	client = port->i2c_client_tuner;
+	if (client) {
+		module_put(client->dev.driver->owner);
+		i2c_unregister_device(client);
+	}
+
+	/* remove I2C client for demodulator */
+	client = port->i2c_client_demod;
+	if (client) {
+		module_put(client->dev.driver->owner);
+		i2c_unregister_device(client);
+	}
+
+	fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
+
 	if (fe0 && fe0->dvb.frontend)
-		videobuf_dvb_unregister_bus(&port->frontends);
+		vb2_dvb_unregister_bus(&port->frontends);
 
 	switch (port->dev->board) {
 	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
@@ -1668,4 +1882,3 @@
 
 	return 0;
 }
-
diff --git a/drivers/media/pci/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c
index 5444cc5..6f817d8 100644
--- a/drivers/media/pci/cx23885/cx23885-f300.c
+++ b/drivers/media/pci/cx23885/cx23885-f300.c
@@ -22,10 +22,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include "cx23885.h"
diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c
index 4887314..fd71306 100644
--- a/drivers/media/pci/cx23885/cx23885-i2c.c
+++ b/drivers/media/pci/cx23885/cx23885-i2c.c
@@ -13,10 +13,6 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/module.h>
@@ -386,11 +382,3 @@
 
 	i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);
 }
-
-/* ----------------------------------------------------------------------- */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index 1940c18..9d37fe6 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -28,11 +28,6 @@
  *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #include <linux/slab.h>
diff --git a/drivers/media/pci/cx23885/cx23885-input.h b/drivers/media/pci/cx23885/cx23885-input.h
index 87dc44e..6199c7e 100644
--- a/drivers/media/pci/cx23885/cx23885-input.h
+++ b/drivers/media/pci/cx23885/cx23885-input.h
@@ -14,11 +14,6 @@
  *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #ifndef _CX23885_INPUT_H_
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c
index f2c9215..90c130e 100644
--- a/drivers/media/pci/cx23885/cx23885-ioctl.c
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.c
@@ -15,10 +15,6 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include "cx23885.h"
@@ -28,7 +24,7 @@
 int cx23885_g_chip_info(struct file *file, void *fh,
 			 struct v4l2_dbg_chip_info *chip)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	if (chip->match.addr > 1)
 		return -EINVAL;
@@ -64,7 +60,7 @@
 int cx23885_g_register(struct file *file, void *fh,
 		       struct v4l2_dbg_register *reg)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	if (reg->match.addr > 1)
 		return -EINVAL;
@@ -96,7 +92,7 @@
 int cx23885_s_register(struct file *file, void *fh,
 		       const struct v4l2_dbg_register *reg)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	if (reg->match.addr > 1)
 		return -EINVAL;
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h
index 854a9c2..af281b9 100644
--- a/drivers/media/pci/cx23885/cx23885-ioctl.h
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.h
@@ -15,10 +15,6 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef _CX23885_IOCTL_H_
diff --git a/drivers/media/pci/cx23885/cx23885-ir.c b/drivers/media/pci/cx23885/cx23885-ir.c
index bfef193..89dc4cc 100644
--- a/drivers/media/pci/cx23885/cx23885-ir.c
+++ b/drivers/media/pci/cx23885/cx23885-ir.c
@@ -14,11 +14,6 @@
  *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #include <media/v4l2-device.h>
diff --git a/drivers/media/pci/cx23885/cx23885-ir.h b/drivers/media/pci/cx23885/cx23885-ir.h
index 0c9d8bd..8e93d1f 100644
--- a/drivers/media/pci/cx23885/cx23885-ir.h
+++ b/drivers/media/pci/cx23885/cx23885-ir.h
@@ -14,11 +14,6 @@
  *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #ifndef _CX23885_IR_H_
diff --git a/drivers/media/pci/cx23885/cx23885-reg.h b/drivers/media/pci/cx23885/cx23885-reg.h
index a99936e..2d3cbaf 100644
--- a/drivers/media/pci/cx23885/cx23885-reg.h
+++ b/drivers/media/pci/cx23885/cx23885-reg.h
@@ -13,10 +13,6 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef _CX23885_REG_H_
diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c
index a1154f0..a7c6ef8 100644
--- a/drivers/media/pci/cx23885/cx23885-vbi.c
+++ b/drivers/media/pci/cx23885/cx23885-vbi.c
@@ -13,10 +13,6 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/kernel.h>
@@ -42,33 +38,32 @@
 /* ------------------------------------------------------------------ */
 
 #define VBI_LINE_LENGTH 1440
-#define NTSC_VBI_START_LINE 10        /* line 10 - 21 */
-#define NTSC_VBI_END_LINE   21
-#define NTSC_VBI_LINES      (NTSC_VBI_END_LINE - NTSC_VBI_START_LINE + 1)
+#define VBI_NTSC_LINE_COUNT 12
+#define VBI_PAL_LINE_COUNT 18
 
 
 int cx23885_vbi_fmt(struct file *file, void *priv,
 	struct v4l2_format *f)
 {
-	struct cx23885_fh *fh = priv;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
+	f->fmt.vbi.sampling_rate = 27000000;
+	f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+	f->fmt.vbi.offset = 0;
+	f->fmt.vbi.flags = 0;
 	if (dev->tvnorm & V4L2_STD_525_60) {
 		/* ntsc */
-		f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
-		f->fmt.vbi.sampling_rate = 27000000;
-		f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
-		f->fmt.vbi.offset = 0;
-		f->fmt.vbi.flags = 0;
-		f->fmt.vbi.start[0] = 10;
-		f->fmt.vbi.count[0] = 17;
-		f->fmt.vbi.start[1] = 263 + 10 + 1;
-		f->fmt.vbi.count[1] = 17;
+		f->fmt.vbi.start[0] = V4L2_VBI_ITU_525_F1_START + 9;
+		f->fmt.vbi.start[1] = V4L2_VBI_ITU_525_F2_START + 9;
+		f->fmt.vbi.count[0] = VBI_NTSC_LINE_COUNT;
+		f->fmt.vbi.count[1] = VBI_NTSC_LINE_COUNT;
 	} else if (dev->tvnorm & V4L2_STD_625_50) {
 		/* pal */
-		f->fmt.vbi.sampling_rate = 35468950;
-		f->fmt.vbi.start[0] = 7 - 1;
-		f->fmt.vbi.start[1] = 319 - 1;
+		f->fmt.vbi.start[0] = V4L2_VBI_ITU_625_F1_START + 5;
+		f->fmt.vbi.start[1] = V4L2_VBI_ITU_625_F2_START + 5;
+		f->fmt.vbi.count[0] = VBI_PAL_LINE_COUNT;
+		f->fmt.vbi.count[1] = VBI_PAL_LINE_COUNT;
 	}
 
 	return 0;
@@ -94,15 +89,6 @@
 		handled++;
 	}
 
-	if (status & VID_BC_MSK_VBI_RISCI2) {
-		dprintk(1, "%s() VID_BC_MSK_VBI_RISCI2\n", __func__);
-		dprintk(2, "stopper vbi\n");
-		spin_lock(&dev->slock);
-		cx23885_restart_vbi_queue(dev, &dev->vbiq);
-		spin_unlock(&dev->slock);
-		handled++;
-	}
-
 	return handled;
 }
 
@@ -114,13 +100,13 @@
 
 	/* setup fifo + format */
 	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02],
-				buf->vb.width, buf->risc.dma);
+				VBI_LINE_LENGTH, buf->risc.dma);
 
 	/* reset counter */
 	cx_write(VID_A_GPCNT_CTL, 3);
 	cx_write(VID_A_VBI_CTRL, 3);
 	cx_write(VBI_A_GPCNT_CTL, 3);
-	q->count = 1;
+	q->count = 0;
 
 	/* enable irq */
 	cx23885_irq_add_enable(dev, 0x01);
@@ -133,163 +119,153 @@
 	return 0;
 }
 
-
-int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
-			     struct cx23885_dmaqueue *q)
-{
-	struct cx23885_buffer *buf;
-	struct list_head *item;
-
-	if (list_empty(&q->active))
-		return 0;
-
-	buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
-	dprintk(2, "restart_queue [%p/%d]: restart dma\n",
-		buf, buf->vb.i);
-	cx23885_start_vbi_dma(dev, q, buf);
-	list_for_each(item, &q->active) {
-		buf = list_entry(item, struct cx23885_buffer, vb.queue);
-		buf->count = q->count++;
-	}
-	mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
-	return 0;
-}
-
-void cx23885_vbi_timeout(unsigned long data)
-{
-	struct cx23885_dev *dev = (struct cx23885_dev *)data;
-	struct cx23885_dmaqueue *q = &dev->vbiq;
-	struct cx23885_buffer *buf;
-	unsigned long flags;
-
-	/* Stop the VBI engine */
-	cx_clear(VID_A_DMA_CTL, 0x22);
-
-	spin_lock_irqsave(&dev->slock, flags);
-	while (!list_empty(&q->active)) {
-		buf = list_entry(q->active.next, struct cx23885_buffer,
-			vb.queue);
-		list_del(&buf->vb.queue);
-		buf->vb.state = VIDEOBUF_ERROR;
-		wake_up(&buf->vb.done);
-		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name,
-		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
-	}
-	cx23885_restart_vbi_queue(dev, q);
-	spin_unlock_irqrestore(&dev->slock, flags);
-}
-
 /* ------------------------------------------------------------------ */
-#define VBI_LINE_LENGTH 1440
-#define VBI_LINE_COUNT 17
 
-static int
-vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+			   unsigned int *num_buffers, unsigned int *num_planes,
+			   unsigned int sizes[], void *alloc_ctxs[])
 {
-	*size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
-	if (0 == *count)
-		*count = vbibufs;
-	if (*count < 2)
-		*count = 2;
-	if (*count > 32)
-		*count = 32;
+	struct cx23885_dev *dev = q->drv_priv;
+	unsigned lines = VBI_PAL_LINE_COUNT;
+
+	if (dev->tvnorm & V4L2_STD_525_60)
+		lines = VBI_NTSC_LINE_COUNT;
+	*num_planes = 1;
+	sizes[0] = lines * VBI_LINE_LENGTH * 2;
 	return 0;
 }
 
-static int
-vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-	    enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-	struct cx23885_fh *fh  = q->priv_data;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
 	struct cx23885_buffer *buf = container_of(vb,
 		struct cx23885_buffer, vb);
-	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
-	unsigned int size;
-	int rc;
+	struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+	unsigned lines = VBI_PAL_LINE_COUNT;
+	int ret;
 
-	size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
-	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+	if (dev->tvnorm & V4L2_STD_525_60)
+		lines = VBI_NTSC_LINE_COUNT;
+
+	if (vb2_plane_size(vb, 0) < lines * VBI_LINE_LENGTH * 2)
 		return -EINVAL;
+	vb2_set_plane_payload(vb, 0, lines * VBI_LINE_LENGTH * 2);
 
-	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-		buf->vb.width  = VBI_LINE_LENGTH;
-		buf->vb.height = VBI_LINE_COUNT;
-		buf->vb.size   = size;
-		buf->vb.field  = V4L2_FIELD_SEQ_TB;
+	ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+	if (!ret)
+		return -EIO;
 
-		rc = videobuf_iolock(q, &buf->vb, NULL);
-		if (0 != rc)
-			goto fail;
-		cx23885_risc_vbibuffer(dev->pci, &buf->risc,
-				 dma->sglist,
-				 0, buf->vb.width * buf->vb.height,
-				 buf->vb.width, 0,
-				 buf->vb.height);
-	}
-	buf->vb.state = VIDEOBUF_PREPARED;
+	cx23885_risc_vbibuffer(dev->pci, &buf->risc,
+			 sgt->sgl,
+			 0, VBI_LINE_LENGTH * lines,
+			 VBI_LINE_LENGTH, 0,
+			 lines);
 	return 0;
-
- fail:
-	cx23885_free_buffer(q, buf);
-	return rc;
 }
 
-static void
-vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
 {
-	struct cx23885_buffer   *buf =
-		container_of(vb, struct cx23885_buffer, vb);
-	struct cx23885_buffer   *prev;
-	struct cx23885_fh       *fh   = vq->priv_data;
-	struct cx23885_dev      *dev  = fh->dev;
-	struct cx23885_dmaqueue *q    = &dev->vbiq;
+	struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+	struct cx23885_buffer *buf = container_of(vb,
+		struct cx23885_buffer, vb);
+	struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
 
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+	cx23885_free_buffer(vb->vb2_queue->drv_priv, buf);
+
+	dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+}
+
+/*
+ * The risc program for each buffer works as follows: it starts with a simple
+ * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
+ * the initial JUMP).
+ *
+ * This is the risc program of the first buffer to be queued if the active list
+ * is empty and it just keeps DMAing this buffer without generating any
+ * interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the code for that buffer
+ * will generate an interrupt which signals that the previous buffer has been
+ * DMAed successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
+static void buffer_queue(struct vb2_buffer *vb)
+{
+	struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+	struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb);
+	struct cx23885_buffer *prev;
+	struct cx23885_dmaqueue *q = &dev->vbiq;
+	unsigned long flags;
+
+	buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
 	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
 
 	if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx23885_start_vbi_dma(dev, q, buf);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count    = q->count++;
-		mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
+		spin_lock_irqsave(&dev->slock, flags);
+		list_add_tail(&buf->queue, &q->active);
+		spin_unlock_irqrestore(&dev->slock, flags);
 		dprintk(2, "[%p/%d] vbi_queue - first active\n",
-			buf, buf->vb.i);
+			buf, buf->vb.v4l2_buf.index);
 
 	} else {
+		buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
 		prev = list_entry(q->active.prev, struct cx23885_buffer,
-			vb.queue);
-		list_add_tail(&buf->vb.queue, &q->active);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count    = q->count++;
+			queue);
+		spin_lock_irqsave(&dev->slock, flags);
+		list_add_tail(&buf->queue, &q->active);
+		spin_unlock_irqrestore(&dev->slock, flags);
 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-		prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */
 		dprintk(2, "[%p/%d] buffer_queue - append to active\n",
-			buf, buf->vb.i);
+			buf, buf->vb.v4l2_buf.index);
 	}
 }
 
-static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
 {
-	struct cx23885_buffer *buf =
-		container_of(vb, struct cx23885_buffer, vb);
+	struct cx23885_dev *dev = q->drv_priv;
+	struct cx23885_dmaqueue *dmaq = &dev->vbiq;
+	struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+			struct cx23885_buffer, queue);
 
-	cx23885_free_buffer(q, buf);
+	cx23885_start_vbi_dma(dev, dmaq, buf);
+	return 0;
 }
 
-struct videobuf_queue_ops cx23885_vbi_qops = {
-	.buf_setup    = vbi_setup,
-	.buf_prepare  = vbi_prepare,
-	.buf_queue    = vbi_queue,
-	.buf_release  = vbi_release,
-};
+static void cx23885_stop_streaming(struct vb2_queue *q)
+{
+	struct cx23885_dev *dev = q->drv_priv;
+	struct cx23885_dmaqueue *dmaq = &dev->vbiq;
+	unsigned long flags;
 
-/* ------------------------------------------------------------------ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+	cx_clear(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */
+	spin_lock_irqsave(&dev->slock, flags);
+	while (!list_empty(&dmaq->active)) {
+		struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+			struct cx23885_buffer, queue);
+
+		list_del(&buf->queue);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+
+struct vb2_ops cx23885_vbi_qops = {
+	.queue_setup    = queue_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_finish = buffer_finish,
+	.buf_queue    = buffer_queue,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+	.start_streaming = cx23885_start_streaming,
+	.stop_streaming = cx23885_stop_streaming,
+};
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index a8f7017..f10469a 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -13,10 +13,6 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/init.h>
@@ -35,6 +31,7 @@
 #include "cx23885-video.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 #include "cx23885-ioctl.h"
 #include "tuner-xc2028.h"
 
@@ -48,15 +45,12 @@
 
 static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
 static unsigned int vbi_nr[]   = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
 
 module_param_array(video_nr, int, NULL, 0444);
 module_param_array(vbi_nr,   int, NULL, 0444);
-module_param_array(radio_nr, int, NULL, 0444);
 
 MODULE_PARM_DESC(video_nr, "video device numbers");
 MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
-MODULE_PARM_DESC(radio_nr, "radio device numbers");
 
 static unsigned int video_debug;
 module_param(video_debug, int, 0644);
@@ -79,77 +73,14 @@
 /* static data                                                         */
 
 #define FORMAT_FLAGS_PACKED       0x01
-#if 0
 static struct cx23885_fmt formats[] = {
 	{
-		.name     = "8 bpp, gray",
-		.fourcc   = V4L2_PIX_FMT_GREY,
-		.depth    = 8,
-		.flags    = FORMAT_FLAGS_PACKED,
-	}, {
-		.name     = "15 bpp RGB, le",
-		.fourcc   = V4L2_PIX_FMT_RGB555,
-		.depth    = 16,
-		.flags    = FORMAT_FLAGS_PACKED,
-	}, {
-		.name     = "15 bpp RGB, be",
-		.fourcc   = V4L2_PIX_FMT_RGB555X,
-		.depth    = 16,
-		.flags    = FORMAT_FLAGS_PACKED,
-	}, {
-		.name     = "16 bpp RGB, le",
-		.fourcc   = V4L2_PIX_FMT_RGB565,
-		.depth    = 16,
-		.flags    = FORMAT_FLAGS_PACKED,
-	}, {
-		.name     = "16 bpp RGB, be",
-		.fourcc   = V4L2_PIX_FMT_RGB565X,
-		.depth    = 16,
-		.flags    = FORMAT_FLAGS_PACKED,
-	}, {
-		.name     = "24 bpp RGB, le",
-		.fourcc   = V4L2_PIX_FMT_BGR24,
-		.depth    = 24,
-		.flags    = FORMAT_FLAGS_PACKED,
-	}, {
-		.name     = "32 bpp RGB, le",
-		.fourcc   = V4L2_PIX_FMT_BGR32,
-		.depth    = 32,
-		.flags    = FORMAT_FLAGS_PACKED,
-	}, {
-		.name     = "32 bpp RGB, be",
-		.fourcc   = V4L2_PIX_FMT_RGB32,
-		.depth    = 32,
-		.flags    = FORMAT_FLAGS_PACKED,
-	}, {
-		.name     = "4:2:2, packed, YUYV",
-		.fourcc   = V4L2_PIX_FMT_YUYV,
-		.depth    = 16,
-		.flags    = FORMAT_FLAGS_PACKED,
-	}, {
-		.name     = "4:2:2, packed, UYVY",
-		.fourcc   = V4L2_PIX_FMT_UYVY,
-		.depth    = 16,
-		.flags    = FORMAT_FLAGS_PACKED,
-	},
-};
-#else
-static struct cx23885_fmt formats[] = {
-	{
-#if 0
-		.name     = "4:2:2, packed, UYVY",
-		.fourcc   = V4L2_PIX_FMT_UYVY,
-		.depth    = 16,
-		.flags    = FORMAT_FLAGS_PACKED,
-	}, {
-#endif
 		.name     = "4:2:2, packed, YUYV",
 		.fourcc   = V4L2_PIX_FMT_YUYV,
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	}
 };
-#endif
 
 static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
 {
@@ -158,163 +89,27 @@
 	for (i = 0; i < ARRAY_SIZE(formats); i++)
 		if (formats[i].fourcc == fourcc)
 			return formats+i;
-
-	printk(KERN_ERR "%s(%c%c%c%c) NOT FOUND\n", __func__,
-		(fourcc & 0xff),
-		((fourcc >> 8) & 0xff),
-		((fourcc >> 16) & 0xff),
-		((fourcc >> 24) & 0xff)
-		);
 	return NULL;
 }
 
 /* ------------------------------------------------------------------- */
 
-static const struct v4l2_queryctrl no_ctl = {
-	.name  = "42",
-	.flags = V4L2_CTRL_FLAG_DISABLED,
-};
-
-static struct cx23885_ctrl cx23885_ctls[] = {
-	/* --- video --- */
-	{
-		.v = {
-			.id            = V4L2_CID_BRIGHTNESS,
-			.name          = "Brightness",
-			.minimum       = 0x00,
-			.maximum       = 0xff,
-			.step          = 1,
-			.default_value = 0x7f,
-			.type          = V4L2_CTRL_TYPE_INTEGER,
-		},
-		.off                   = 128,
-		.reg                   = LUMA_CTRL,
-		.mask                  = 0x00ff,
-		.shift                 = 0,
-	}, {
-		.v = {
-			.id            = V4L2_CID_CONTRAST,
-			.name          = "Contrast",
-			.minimum       = 0,
-			.maximum       = 0x7f,
-			.step          = 1,
-			.default_value = 0x3f,
-			.type          = V4L2_CTRL_TYPE_INTEGER,
-		},
-		.off                   = 0,
-		.reg                   = LUMA_CTRL,
-		.mask                  = 0xff00,
-		.shift                 = 8,
-	}, {
-		.v = {
-			.id            = V4L2_CID_HUE,
-			.name          = "Hue",
-			.minimum       = -127,
-			.maximum       = 128,
-			.step          = 1,
-			.default_value = 0x0,
-			.type          = V4L2_CTRL_TYPE_INTEGER,
-		},
-		.off                   = 128,
-		.reg                   = CHROMA_CTRL,
-		.mask                  = 0xff0000,
-		.shift                 = 16,
-	}, {
-		/* strictly, this only describes only U saturation.
-		 * V saturation is handled specially through code.
-		 */
-		.v = {
-			.id            = V4L2_CID_SATURATION,
-			.name          = "Saturation",
-			.minimum       = 0,
-			.maximum       = 0x7f,
-			.step          = 1,
-			.default_value = 0x3f,
-			.type          = V4L2_CTRL_TYPE_INTEGER,
-		},
-		.off                   = 0,
-		.reg                   = CHROMA_CTRL,
-		.mask                  = 0x00ff,
-		.shift                 = 0,
-	}, {
-	/* --- audio --- */
-		.v = {
-			.id            = V4L2_CID_AUDIO_MUTE,
-			.name          = "Mute",
-			.minimum       = 0,
-			.maximum       = 1,
-			.default_value = 1,
-			.type          = V4L2_CTRL_TYPE_BOOLEAN,
-		},
-		.reg                   = PATH1_CTL1,
-		.mask                  = (0x1f << 24),
-		.shift                 = 24,
-	}, {
-		.v = {
-			.id            = V4L2_CID_AUDIO_VOLUME,
-			.name          = "Volume",
-			.minimum       = 0,
-			.maximum       = 65535,
-			.step          = 65535 / 100,
-			.default_value = 65535,
-			.type          = V4L2_CTRL_TYPE_INTEGER,
-		},
-		.reg                   = PATH1_VOL_CTL,
-		.mask                  = 0xff,
-		.shift                 = 0,
-	}
-};
-static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
-
-/* Must be sorted from low to high control ID! */
-static const u32 cx23885_user_ctrls[] = {
-	V4L2_CID_USER_CLASS,
-	V4L2_CID_BRIGHTNESS,
-	V4L2_CID_CONTRAST,
-	V4L2_CID_SATURATION,
-	V4L2_CID_HUE,
-	V4L2_CID_AUDIO_VOLUME,
-	V4L2_CID_AUDIO_MUTE,
-	0
-};
-
-static const u32 *ctrl_classes[] = {
-	cx23885_user_ctrls,
-	NULL
-};
-
 void cx23885_video_wakeup(struct cx23885_dev *dev,
 	struct cx23885_dmaqueue *q, u32 count)
 {
 	struct cx23885_buffer *buf;
-	int bc;
 
-	for (bc = 0;; bc++) {
-		if (list_empty(&q->active))
-			break;
-		buf = list_entry(q->active.next,
-				 struct cx23885_buffer, vb.queue);
-
-		/* count comes from the hw and is is 16bit wide --
-		 * this trick handles wrap-arounds correctly for
-		 * up to 32767 buffers in flight... */
-		if ((s16) (count - buf->count) < 0)
-			break;
-
-		v4l2_get_timestamp(&buf->vb.ts);
-		dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
-			count, buf->count);
-		buf->vb.state = VIDEOBUF_DONE;
-		list_del(&buf->vb.queue);
-		wake_up(&buf->vb.done);
-	}
 	if (list_empty(&q->active))
-		del_timer(&q->timeout);
-	else
-		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-	if (bc != 1)
-		printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
-			__func__, bc);
+		return;
+	buf = list_entry(q->active.next,
+			struct cx23885_buffer, queue);
+
+	buf->vb.v4l2_buf.sequence = q->count++;
+	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+	dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index,
+			count, q->count);
+	list_del(&buf->queue);
+	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
 }
 
 int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
@@ -324,6 +119,12 @@
 		(unsigned int)norm,
 		v4l2_norm_to_name(norm));
 
+	if (dev->tvnorm != norm) {
+		if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
+		    vb2_is_busy(&dev->vb2_mpegq))
+			return -EBUSY;
+	}
+
 	dev->tvnorm = norm;
 
 	call_all(dev, video, s_std, norm);
@@ -345,79 +146,13 @@
 	*vfd = *template;
 	vfd->v4l2_dev = &dev->v4l2_dev;
 	vfd->release = video_device_release;
+	vfd->lock = &dev->lock;
 	snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
 		 cx23885_boards[dev->board].name, type);
 	video_set_drvdata(vfd, dev);
 	return vfd;
 }
 
-static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
-{
-	int i;
-
-	if (qctrl->id < V4L2_CID_BASE ||
-	    qctrl->id >= V4L2_CID_LASTP1)
-		return -EINVAL;
-	for (i = 0; i < CX23885_CTLS; i++)
-		if (cx23885_ctls[i].v.id == qctrl->id)
-			break;
-	if (i == CX23885_CTLS) {
-		*qctrl = no_ctl;
-		return 0;
-	}
-	*qctrl = cx23885_ctls[i].v;
-	return 0;
-}
-
-/* ------------------------------------------------------------------- */
-/* resource management                                                 */
-
-static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
-	unsigned int bit)
-{
-	dprintk(1, "%s()\n", __func__);
-	if (fh->resources & bit)
-		/* have it already allocated */
-		return 1;
-
-	/* is it free? */
-	mutex_lock(&dev->lock);
-	if (dev->resources & bit) {
-		/* no, someone else uses it */
-		mutex_unlock(&dev->lock);
-		return 0;
-	}
-	/* it's free, grab it */
-	fh->resources  |= bit;
-	dev->resources |= bit;
-	dprintk(1, "res: get %d\n", bit);
-	mutex_unlock(&dev->lock);
-	return 1;
-}
-
-static int res_check(struct cx23885_fh *fh, unsigned int bit)
-{
-	return fh->resources & bit;
-}
-
-static int res_locked(struct cx23885_dev *dev, unsigned int bit)
-{
-	return dev->resources & bit;
-}
-
-static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
-	unsigned int bits)
-{
-	BUG_ON((fh->resources & bits) != bits);
-	dprintk(1, "%s()\n", __func__);
-
-	mutex_lock(&dev->lock);
-	fh->resources  &= ~bits;
-	dev->resources &= ~bits;
-	dprintk(1, "res: put %d\n", bits);
-	mutex_unlock(&dev->lock);
-}
-
 int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data)
 {
 	/* 8 bit registers, 8 bit values */
@@ -567,7 +302,7 @@
 
 	/* reset counter */
 	cx_write(VID_A_GPCNT_CTL, 3);
-	q->count = 1;
+	q->count = 0;
 
 	/* enable irq */
 	cx23885_irq_add_enable(dev, 0x01);
@@ -580,496 +315,224 @@
 	return 0;
 }
 
-
-static int cx23885_restart_video_queue(struct cx23885_dev *dev,
-			       struct cx23885_dmaqueue *q)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+			   unsigned int *num_buffers, unsigned int *num_planes,
+			   unsigned int sizes[], void *alloc_ctxs[])
 {
-	struct cx23885_buffer *buf, *prev;
-	struct list_head *item;
-	dprintk(1, "%s()\n", __func__);
+	struct cx23885_dev *dev = q->drv_priv;
 
-	if (!list_empty(&q->active)) {
-		buf = list_entry(q->active.next, struct cx23885_buffer,
-			vb.queue);
-		dprintk(2, "restart_queue [%p/%d]: restart dma\n",
-			buf, buf->vb.i);
-		cx23885_start_video_dma(dev, q, buf);
-		list_for_each(item, &q->active) {
-			buf = list_entry(item, struct cx23885_buffer,
-				vb.queue);
-			buf->count    = q->count++;
-		}
-		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-		return 0;
-	}
-
-	prev = NULL;
-	for (;;) {
-		if (list_empty(&q->queued))
-			return 0;
-		buf = list_entry(q->queued.next, struct cx23885_buffer,
-			vb.queue);
-		if (NULL == prev) {
-			list_move_tail(&buf->vb.queue, &q->active);
-			cx23885_start_video_dma(dev, q, buf);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count    = q->count++;
-			mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-			dprintk(2, "[%p/%d] restart_queue - first active\n",
-				buf, buf->vb.i);
-
-		} else if (prev->vb.width  == buf->vb.width  &&
-			   prev->vb.height == buf->vb.height &&
-			   prev->fmt       == buf->fmt) {
-			list_move_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count    = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-			prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
-			dprintk(2, "[%p/%d] restart_queue - move to active\n",
-				buf, buf->vb.i);
-		} else {
-			return 0;
-		}
-		prev = buf;
-	}
-}
-
-static int buffer_setup(struct videobuf_queue *q, unsigned int *count,
-	unsigned int *size)
-{
-	struct cx23885_fh *fh = q->priv_data;
-
-	*size = fh->fmt->depth*fh->width*fh->height >> 3;
-	if (0 == *count)
-		*count = 32;
-	if (*size * *count > vid_limit * 1024 * 1024)
-		*count = (vid_limit * 1024 * 1024) / *size;
+	*num_planes = 1;
+	sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3;
 	return 0;
 }
 
-static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
-	       enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-	struct cx23885_fh *fh  = q->priv_data;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
 	struct cx23885_buffer *buf =
 		container_of(vb, struct cx23885_buffer, vb);
-	int rc, init_buffer = 0;
 	u32 line0_offset, line1_offset;
-	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+	struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
 	int field_tff;
+	int ret;
 
-	BUG_ON(NULL == fh->fmt);
-	if (fh->width  < 48 || fh->width  > norm_maxw(dev->tvnorm) ||
-	    fh->height < 32 || fh->height > norm_maxh(dev->tvnorm))
+	buf->bpl = (dev->width * dev->fmt->depth) >> 3;
+
+	if (vb2_plane_size(vb, 0) < dev->height * buf->bpl)
 		return -EINVAL;
-	buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
-	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
-		return -EINVAL;
+	vb2_set_plane_payload(vb, 0, dev->height * buf->bpl);
 
-	if (buf->fmt       != fh->fmt    ||
-	    buf->vb.width  != fh->width  ||
-	    buf->vb.height != fh->height ||
-	    buf->vb.field  != field) {
-		buf->fmt       = fh->fmt;
-		buf->vb.width  = fh->width;
-		buf->vb.height = fh->height;
-		buf->vb.field  = field;
-		init_buffer = 1;
-	}
+	ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+	if (!ret)
+		return -EIO;
 
-	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-		init_buffer = 1;
-		rc = videobuf_iolock(q, &buf->vb, NULL);
-		if (0 != rc)
-			goto fail;
-	}
+	switch (dev->field) {
+	case V4L2_FIELD_TOP:
+		cx23885_risc_buffer(dev->pci, &buf->risc,
+				sgt->sgl, 0, UNSET,
+				buf->bpl, 0, dev->height);
+		break;
+	case V4L2_FIELD_BOTTOM:
+		cx23885_risc_buffer(dev->pci, &buf->risc,
+				sgt->sgl, UNSET, 0,
+				buf->bpl, 0, dev->height);
+		break;
+	case V4L2_FIELD_INTERLACED:
+		if (dev->tvnorm & V4L2_STD_525_60)
+			/* NTSC or  */
+			field_tff = 1;
+		else
+			field_tff = 0;
 
-	if (init_buffer) {
-		buf->bpl = buf->vb.width * buf->fmt->depth >> 3;
-		switch (buf->vb.field) {
-		case V4L2_FIELD_TOP:
-			cx23885_risc_buffer(dev->pci, &buf->risc,
-					 dma->sglist, 0, UNSET,
-					 buf->bpl, 0, buf->vb.height);
-			break;
-		case V4L2_FIELD_BOTTOM:
-			cx23885_risc_buffer(dev->pci, &buf->risc,
-					 dma->sglist, UNSET, 0,
-					 buf->bpl, 0, buf->vb.height);
-			break;
-		case V4L2_FIELD_INTERLACED:
-			if (dev->tvnorm & V4L2_STD_NTSC)
-				/* NTSC or  */
-				field_tff = 1;
-			else
-				field_tff = 0;
+		if (cx23885_boards[dev->board].force_bff)
+			/* PAL / SECAM OR 888 in NTSC MODE */
+			field_tff = 0;
 
-			if (cx23885_boards[dev->board].force_bff)
-				/* PAL / SECAM OR 888 in NTSC MODE */
-				field_tff = 0;
-
-			if (field_tff) {
-				/* cx25840 transmits NTSC bottom field first */
-				dprintk(1, "%s() Creating TFF/NTSC risc\n",
+		if (field_tff) {
+			/* cx25840 transmits NTSC bottom field first */
+			dprintk(1, "%s() Creating TFF/NTSC risc\n",
 					__func__);
-				line0_offset = buf->bpl;
-				line1_offset = 0;
-			} else {
-				/* All other formats are top field first */
-				dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n",
+			line0_offset = buf->bpl;
+			line1_offset = 0;
+		} else {
+			/* All other formats are top field first */
+			dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n",
 					__func__);
-				line0_offset = 0;
-				line1_offset = buf->bpl;
-			}
-			cx23885_risc_buffer(dev->pci, &buf->risc,
-					dma->sglist, line0_offset,
-					line1_offset,
-					buf->bpl, buf->bpl,
-					buf->vb.height >> 1);
-			break;
-		case V4L2_FIELD_SEQ_TB:
-			cx23885_risc_buffer(dev->pci, &buf->risc,
-					 dma->sglist,
-					 0, buf->bpl * (buf->vb.height >> 1),
-					 buf->bpl, 0,
-					 buf->vb.height >> 1);
-			break;
-		case V4L2_FIELD_SEQ_BT:
-			cx23885_risc_buffer(dev->pci, &buf->risc,
-					 dma->sglist,
-					 buf->bpl * (buf->vb.height >> 1), 0,
-					 buf->bpl, 0,
-					 buf->vb.height >> 1);
-			break;
-		default:
-			BUG();
+			line0_offset = 0;
+			line1_offset = buf->bpl;
 		}
+		cx23885_risc_buffer(dev->pci, &buf->risc,
+				sgt->sgl, line0_offset,
+				line1_offset,
+				buf->bpl, buf->bpl,
+				dev->height >> 1);
+		break;
+	case V4L2_FIELD_SEQ_TB:
+		cx23885_risc_buffer(dev->pci, &buf->risc,
+				sgt->sgl,
+				0, buf->bpl * (dev->height >> 1),
+				buf->bpl, 0,
+				dev->height >> 1);
+		break;
+	case V4L2_FIELD_SEQ_BT:
+		cx23885_risc_buffer(dev->pci, &buf->risc,
+				sgt->sgl,
+				buf->bpl * (dev->height >> 1), 0,
+				buf->bpl, 0,
+				dev->height >> 1);
+		break;
+	default:
+		BUG();
 	}
-	dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
-		buf, buf->vb.i,
-		fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
+	dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
+		buf, buf->vb.v4l2_buf.index,
+		dev->width, dev->height, dev->fmt->depth, dev->fmt->name,
 		(unsigned long)buf->risc.dma);
-
-	buf->vb.state = VIDEOBUF_PREPARED;
 	return 0;
-
- fail:
-	cx23885_free_buffer(q, buf);
-	return rc;
 }
 
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
 {
+	struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+	struct cx23885_buffer *buf = container_of(vb,
+		struct cx23885_buffer, vb);
+	struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+
+	cx23885_free_buffer(vb->vb2_queue->drv_priv, buf);
+
+	dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+}
+
+/*
+ * The risc program for each buffer works as follows: it starts with a simple
+ * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
+ * the initial JUMP).
+ *
+ * This is the risc program of the first buffer to be queued if the active list
+ * is empty and it just keeps DMAing this buffer without generating any
+ * interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the code for that buffer
+ * will generate an interrupt which signals that the previous buffer has been
+ * DMAed successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
+static void buffer_queue(struct vb2_buffer *vb)
+{
+	struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
 	struct cx23885_buffer   *buf = container_of(vb,
 		struct cx23885_buffer, vb);
 	struct cx23885_buffer   *prev;
-	struct cx23885_fh       *fh   = vq->priv_data;
-	struct cx23885_dev      *dev  = fh->dev;
 	struct cx23885_dmaqueue *q    = &dev->vidq;
+	unsigned long flags;
 
-	/* add jump to stopper */
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
-	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+	/* add jump to start */
+	buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
 	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
 
-	if (!list_empty(&q->queued)) {
-		list_add_tail(&buf->vb.queue, &q->queued);
-		buf->vb.state = VIDEOBUF_QUEUED;
-		dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
-			buf, buf->vb.i);
-
-	} else if (list_empty(&q->active)) {
-		list_add_tail(&buf->vb.queue, &q->active);
-		cx23885_start_video_dma(dev, q, buf);
-		buf->vb.state = VIDEOBUF_ACTIVE;
-		buf->count    = q->count++;
-		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+	spin_lock_irqsave(&dev->slock, flags);
+	if (list_empty(&q->active)) {
+		list_add_tail(&buf->queue, &q->active);
 		dprintk(2, "[%p/%d] buffer_queue - first active\n",
-			buf, buf->vb.i);
-
+			buf, buf->vb.v4l2_buf.index);
 	} else {
+		buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
 		prev = list_entry(q->active.prev, struct cx23885_buffer,
-			vb.queue);
-		if (prev->vb.width  == buf->vb.width  &&
-		    prev->vb.height == buf->vb.height &&
-		    prev->fmt       == buf->fmt) {
-			list_add_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = VIDEOBUF_ACTIVE;
-			buf->count    = q->count++;
-			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-			/* 64 bit bits 63-32 */
-			prev->risc.jmp[2] = cpu_to_le32(0);
-			dprintk(2, "[%p/%d] buffer_queue - append to active\n",
-				buf, buf->vb.i);
-
-		} else {
-			list_add_tail(&buf->vb.queue, &q->queued);
-			buf->vb.state = VIDEOBUF_QUEUED;
-			dprintk(2, "[%p/%d] buffer_queue - first queued\n",
-				buf, buf->vb.i);
-		}
+			queue);
+		list_add_tail(&buf->queue, &q->active);
+		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+		dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+				buf, buf->vb.v4l2_buf.index);
 	}
+	spin_unlock_irqrestore(&dev->slock, flags);
 }
 
-static void buffer_release(struct videobuf_queue *q,
-	struct videobuf_buffer *vb)
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
 {
-	struct cx23885_buffer *buf = container_of(vb,
-		struct cx23885_buffer, vb);
+	struct cx23885_dev *dev = q->drv_priv;
+	struct cx23885_dmaqueue *dmaq = &dev->vidq;
+	struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+			struct cx23885_buffer, queue);
 
-	cx23885_free_buffer(q, buf);
+	cx23885_start_video_dma(dev, dmaq, buf);
+	return 0;
 }
 
-static struct videobuf_queue_ops cx23885_video_qops = {
-	.buf_setup    = buffer_setup,
+static void cx23885_stop_streaming(struct vb2_queue *q)
+{
+	struct cx23885_dev *dev = q->drv_priv;
+	struct cx23885_dmaqueue *dmaq = &dev->vidq;
+	unsigned long flags;
+
+	cx_clear(VID_A_DMA_CTL, 0x11);
+	spin_lock_irqsave(&dev->slock, flags);
+	while (!list_empty(&dmaq->active)) {
+		struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+			struct cx23885_buffer, queue);
+
+		list_del(&buf->queue);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+static struct vb2_ops cx23885_video_qops = {
+	.queue_setup    = queue_setup,
 	.buf_prepare  = buffer_prepare,
+	.buf_finish = buffer_finish,
 	.buf_queue    = buffer_queue,
-	.buf_release  = buffer_release,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+	.start_streaming = cx23885_start_streaming,
+	.stop_streaming = cx23885_stop_streaming,
 };
 
-static struct videobuf_queue *get_queue(struct cx23885_fh *fh)
-{
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		return &fh->vidq;
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		return &fh->vbiq;
-	default:
-		BUG();
-		return NULL;
-	}
-}
-
-static int get_resource(struct cx23885_fh *fh)
-{
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		return RESOURCE_VIDEO;
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		return RESOURCE_VBI;
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static int video_open(struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct cx23885_dev *dev = video_drvdata(file);
-	struct cx23885_fh *fh;
-	enum v4l2_buf_type type = 0;
-	int radio = 0;
-
-	switch (vdev->vfl_type) {
-	case VFL_TYPE_GRABBER:
-		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		break;
-	case VFL_TYPE_VBI:
-		type = V4L2_BUF_TYPE_VBI_CAPTURE;
-		break;
-	case VFL_TYPE_RADIO:
-		radio = 1;
-		break;
-	}
-
-	dprintk(1, "open dev=%s radio=%d type=%s\n",
-		video_device_node_name(vdev), radio, v4l2_type_names[type]);
-
-	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
-
-	file->private_data = fh;
-	fh->dev      = dev;
-	fh->radio    = radio;
-	fh->type     = type;
-	fh->width    = 320;
-	fh->height   = 240;
-	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
-	videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops,
-			    &dev->pci->dev, &dev->slock,
-			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			    V4L2_FIELD_INTERLACED,
-			    sizeof(struct cx23885_buffer),
-			    fh, NULL);
-
-	videobuf_queue_sg_init(&fh->vbiq, &cx23885_vbi_qops,
-		&dev->pci->dev, &dev->slock,
-		V4L2_BUF_TYPE_VBI_CAPTURE,
-		V4L2_FIELD_SEQ_TB,
-		sizeof(struct cx23885_buffer),
-		fh, NULL);
-
-
-	dprintk(1, "post videobuf_queue_init()\n");
-
-	return 0;
-}
-
-static ssize_t video_read(struct file *file, char __user *data,
-	size_t count, loff_t *ppos)
-{
-	struct cx23885_fh *fh = file->private_data;
-
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		if (res_locked(fh->dev, RESOURCE_VIDEO))
-			return -EBUSY;
-		return videobuf_read_one(&fh->vidq, data, count, ppos,
-					 file->f_flags & O_NONBLOCK);
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		if (!res_get(fh->dev, fh, RESOURCE_VBI))
-			return -EBUSY;
-		return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,
-					    file->f_flags & O_NONBLOCK);
-	default:
-		BUG();
-		return 0;
-	}
-}
-
-static unsigned int video_poll(struct file *file,
-	struct poll_table_struct *wait)
-{
-	struct cx23885_fh *fh = file->private_data;
-	struct cx23885_buffer *buf;
-	unsigned int rc = POLLERR;
-
-	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
-		if (!res_get(fh->dev, fh, RESOURCE_VBI))
-			return POLLERR;
-		return videobuf_poll_stream(file, &fh->vbiq, wait);
-	}
-
-	mutex_lock(&fh->vidq.vb_lock);
-	if (res_check(fh, RESOURCE_VIDEO)) {
-		/* streaming capture */
-		if (list_empty(&fh->vidq.stream))
-			goto done;
-		buf = list_entry(fh->vidq.stream.next,
-			struct cx23885_buffer, vb.stream);
-	} else {
-		/* read() capture */
-		buf = (struct cx23885_buffer *)fh->vidq.read_buf;
-		if (NULL == buf)
-			goto done;
-	}
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == VIDEOBUF_DONE ||
-	    buf->vb.state == VIDEOBUF_ERROR)
-		rc =  POLLIN|POLLRDNORM;
-	else
-		rc = 0;
-done:
-	mutex_unlock(&fh->vidq.vb_lock);
-	return rc;
-}
-
-static int video_release(struct file *file)
-{
-	struct cx23885_fh *fh = file->private_data;
-	struct cx23885_dev *dev = fh->dev;
-
-	/* turn off overlay */
-	if (res_check(fh, RESOURCE_OVERLAY)) {
-		/* FIXME */
-		res_free(dev, fh, RESOURCE_OVERLAY);
-	}
-
-	/* stop video capture */
-	if (res_check(fh, RESOURCE_VIDEO)) {
-		videobuf_queue_cancel(&fh->vidq);
-		res_free(dev, fh, RESOURCE_VIDEO);
-	}
-	if (fh->vidq.read_buf) {
-		buffer_release(&fh->vidq, fh->vidq.read_buf);
-		kfree(fh->vidq.read_buf);
-	}
-
-	/* stop vbi capture */
-	if (res_check(fh, RESOURCE_VBI)) {
-		if (fh->vbiq.streaming)
-			videobuf_streamoff(&fh->vbiq);
-		if (fh->vbiq.reading)
-			videobuf_read_stop(&fh->vbiq);
-		res_free(dev, fh, RESOURCE_VBI);
-	}
-
-	videobuf_mmap_free(&fh->vidq);
-	videobuf_mmap_free(&fh->vbiq);
-
-	file->private_data = NULL;
-	kfree(fh);
-
-	/* We are not putting the tuner to sleep here on exit, because
-	 * we want to use the mpeg encoder in another session to capture
-	 * tuner video. Closing this will result in no video to the encoder.
-	 */
-
-	return 0;
-}
-
-static int video_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct cx23885_fh *fh = file->private_data;
-
-	return videobuf_mmap_mapper(get_queue(fh), vma);
-}
-
-/* ------------------------------------------------------------------ */
-/* VIDEO CTRL IOCTLS                                                  */
-
-int cx23885_get_control(struct cx23885_dev *dev,
-	struct v4l2_control *ctl)
-{
-	dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
-	call_all(dev, core, g_ctrl, ctl);
-	return 0;
-}
-
-int cx23885_set_control(struct cx23885_dev *dev,
-	struct v4l2_control *ctl)
-{
-	dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__);
-	call_all(dev, core, s_ctrl, ctl);
-
-	return 0;
-}
-
-static void init_controls(struct cx23885_dev *dev)
-{
-	struct v4l2_control ctrl;
-	int i;
-
-	for (i = 0; i < CX23885_CTLS; i++) {
-		ctrl.id = cx23885_ctls[i].v.id;
-		ctrl.value = cx23885_ctls[i].v.default_value;
-
-		cx23885_set_control(dev, &ctrl);
-	}
-}
-
 /* ------------------------------------------------------------------ */
 /* VIDEO IOCTLS                                                       */
 
 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 	struct v4l2_format *f)
 {
-	struct cx23885_fh *fh   = priv;
+	struct cx23885_dev *dev = video_drvdata(file);
 
-	f->fmt.pix.width        = fh->width;
-	f->fmt.pix.height       = fh->height;
-	f->fmt.pix.field        = fh->vidq.field;
-	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+	f->fmt.pix.width        = dev->width;
+	f->fmt.pix.height       = dev->height;
+	f->fmt.pix.field        = dev->field;
+	f->fmt.pix.pixelformat  = dev->fmt->fourcc;
 	f->fmt.pix.bytesperline =
-		(f->fmt.pix.width * fh->fmt->depth) >> 3;
+		(f->fmt.pix.width * dev->fmt->depth) >> 3;
 	f->fmt.pix.sizeimage =
 		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	f->fmt.pix.colorspace   = V4L2_COLORSPACE_SMPTE170M;
 
 	return 0;
 }
@@ -1077,7 +540,7 @@
 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 	struct v4l2_format *f)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 	struct cx23885_fmt *fmt;
 	enum v4l2_field   field;
 	unsigned int      maxw, maxh;
@@ -1102,9 +565,12 @@
 		maxh = maxh / 2;
 		break;
 	case V4L2_FIELD_INTERLACED:
+	case V4L2_FIELD_SEQ_TB:
+	case V4L2_FIELD_SEQ_BT:
 		break;
 	default:
-		return -EINVAL;
+		field = V4L2_FIELD_INTERLACED;
+		break;
 	}
 
 	f->fmt.pix.field = field;
@@ -1114,6 +580,7 @@
 		(f->fmt.pix.width * fmt->depth) >> 3;
 	f->fmt.pix.sizeimage =
 		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 
 	return 0;
 }
@@ -1121,8 +588,7 @@
 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 	struct v4l2_format *f)
 {
-	struct cx23885_fh *fh = priv;
-	struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 	struct v4l2_mbus_framefmt mbus_fmt;
 	int err;
 
@@ -1131,34 +597,44 @@
 
 	if (0 != err)
 		return err;
-	fh->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
-	fh->width      = f->fmt.pix.width;
-	fh->height     = f->fmt.pix.height;
-	fh->vidq.field = f->fmt.pix.field;
+
+	if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
+	    vb2_is_busy(&dev->vb2_mpegq))
+		return -EBUSY;
+
+	dev->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
+	dev->width      = f->fmt.pix.width;
+	dev->height     = f->fmt.pix.height;
+	dev->field	= f->fmt.pix.field;
 	dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
-		fh->width, fh->height, fh->vidq.field);
+		dev->width, dev->height, dev->field);
 	v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
 	call_all(dev, video, s_mbus_fmt, &mbus_fmt);
 	v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
+	/* s_mbus_fmt overwrites f->fmt.pix.field, restore it */
+	f->fmt.pix.field = dev->field;
 	return 0;
 }
 
 static int vidioc_querycap(struct file *file, void  *priv,
 	struct v4l2_capability *cap)
 {
-	struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
+	struct video_device *vdev = video_devdata(file);
 
 	strcpy(cap->driver, "cx23885");
 	strlcpy(cap->card, cx23885_boards[dev->board].name,
 		sizeof(cap->card));
 	sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
-	cap->capabilities =
-		V4L2_CAP_VIDEO_CAPTURE |
-		V4L2_CAP_READWRITE     |
-		V4L2_CAP_STREAMING     |
-		V4L2_CAP_VBI_CAPTURE;
+	cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO;
 	if (dev->tuner_type != TUNER_ABSENT)
-		cap->capabilities |= V4L2_CAP_TUNER;
+		cap->device_caps |= V4L2_CAP_TUNER;
+	if (vdev->vfl_type == VFL_TYPE_VBI)
+		cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
+	else
+		cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+	cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE |
+		V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
@@ -1175,85 +651,9 @@
 	return 0;
 }
 
-static int vidioc_reqbufs(struct file *file, void *priv,
-	struct v4l2_requestbuffers *p)
-{
-	struct cx23885_fh *fh = priv;
-	return videobuf_reqbufs(get_queue(fh), p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
-	struct v4l2_buffer *p)
-{
-	struct cx23885_fh *fh = priv;
-	return videobuf_querybuf(get_queue(fh), p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv,
-	struct v4l2_buffer *p)
-{
-	struct cx23885_fh *fh = priv;
-	return videobuf_qbuf(get_queue(fh), p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv,
-	struct v4l2_buffer *p)
-{
-	struct cx23885_fh *fh = priv;
-	return videobuf_dqbuf(get_queue(fh), p,
-				file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_streamon(struct file *file, void *priv,
-	enum v4l2_buf_type i)
-{
-	struct cx23885_fh *fh = priv;
-	struct cx23885_dev *dev = fh->dev;
-	dprintk(1, "%s()\n", __func__);
-
-	if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
-		(fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
-		return -EINVAL;
-	if (unlikely(i != fh->type))
-		return -EINVAL;
-
-	if (unlikely(!res_get(dev, fh, get_resource(fh))))
-		return -EBUSY;
-
-	/* Don't start VBI streaming unless vida streaming
-	 * has already started.
-	 */
-	if ((fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) &&
-		((cx_read(VID_A_DMA_CTL) & 0x11) == 0))
-		return -EINVAL;
-
-	return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-	struct cx23885_fh *fh = priv;
-	struct cx23885_dev *dev = fh->dev;
-	int err, res;
-	dprintk(1, "%s()\n", __func__);
-
-	if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
-		(fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
-		return -EINVAL;
-	if (i != fh->type)
-		return -EINVAL;
-
-	res = get_resource(fh);
-	err = videobuf_streamoff(get_queue(fh));
-	if (err < 0)
-		return err;
-	res_free(dev, fh, res);
-	return 0;
-}
-
 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 	dprintk(1, "%s()\n", __func__);
 
 	*id = dev->tvnorm;
@@ -1262,14 +662,10 @@
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 	dprintk(1, "%s()\n", __func__);
 
-	mutex_lock(&dev->lock);
-	cx23885_set_tvnorm(dev, tvnorms);
-	mutex_unlock(&dev->lock);
-
-	return 0;
+	return cx23885_set_tvnorm(dev, tvnorms);
 }
 
 int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
@@ -1299,16 +695,16 @@
 	i->index = n;
 	i->type  = V4L2_INPUT_TYPE_CAMERA;
 	strcpy(i->name, iname[INPUT(n)->type]);
+	i->std = CX23885_NORMS;
 	if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) ||
 		(CX23885_VMUX_CABLE == INPUT(n)->type)) {
 		i->type = V4L2_INPUT_TYPE_TUNER;
-		i->std = CX23885_NORMS;
+		i->audioset = 4;
+	} else {
+		/* Two selectable audio inputs for non-tv inputs */
+		i->audioset = 3;
 	}
 
-	/* Two selectable audio inputs for non-tv inputs */
-	if (INPUT(n)->type != CX23885_VMUX_TELEVISION)
-		i->audioset = 0x3;
-
 	if (dev->input == n) {
 		/* enum'd input matches our configured input.
 		 * Ask the video decoder to process the call
@@ -1324,14 +720,14 @@
 static int vidioc_enum_input(struct file *file, void *priv,
 				struct v4l2_input *i)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 	dprintk(1, "%s()\n", __func__);
 	return cx23885_enum_input(dev, i);
 }
 
 int cx23885_get_input(struct file *file, void *priv, unsigned int *i)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	*i = dev->input;
 	dprintk(1, "%s() returns %d\n", __func__, *i);
@@ -1345,7 +741,7 @@
 
 int cx23885_set_input(struct file *file, void *priv, unsigned int i)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	dprintk(1, "%s(%d)\n", __func__, i);
 
@@ -1357,13 +753,11 @@
 	if (INPUT(i)->type == 0)
 		return -EINVAL;
 
-	mutex_lock(&dev->lock);
 	cx23885_video_mux(dev, i);
 
 	/* By default establish the default audio input for the card also */
 	/* Caller is free to use VIDIOC_S_AUDIO to override afterwards */
 	cx23885_audio_mux(dev, i);
-	mutex_unlock(&dev->lock);
 	return 0;
 }
 
@@ -1374,39 +768,32 @@
 
 static int vidioc_log_status(struct file *file, void *priv)
 {
-	struct cx23885_fh  *fh  = priv;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
-	printk(KERN_INFO
-		"%s/0: ============  START LOG STATUS  ============\n",
-		dev->name);
 	call_all(dev, core, log_status);
-	printk(KERN_INFO
-		"%s/0: =============  END LOG STATUS  =============\n",
-		dev->name);
 	return 0;
 }
 
 static int cx23885_query_audinput(struct file *file, void *priv,
 	struct v4l2_audio *i)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 	static const char *iname[] = {
 		[0] = "Baseband L/R 1",
 		[1] = "Baseband L/R 2",
+		[2] = "TV",
 	};
 	unsigned int n;
 	dprintk(1, "%s()\n", __func__);
 
 	n = i->index;
-	if (n >= 2)
+	if (n >= 3)
 		return -EINVAL;
 
 	memset(i, 0, sizeof(*i));
 	i->index = n;
 	strcpy(i->name, iname[n]);
-	i->capability  = V4L2_AUDCAP_STEREO;
-	i->mode  = V4L2_AUDMODE_AVL;
+	i->capability = V4L2_AUDCAP_STEREO;
 	return 0;
 
 }
@@ -1420,9 +807,13 @@
 static int vidioc_g_audinput(struct file *file, void *priv,
 	struct v4l2_audio *i)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
-	i->index = dev->audinput;
+	if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) ||
+		(CX23885_VMUX_CABLE == INPUT(dev->input)->type))
+		i->index = 2;
+	else
+		i->index = dev->audinput;
 	dprintk(1, "%s(input=%d)\n", __func__, i->index);
 
 	return cx23885_query_audinput(file, priv, i);
@@ -1431,8 +822,13 @@
 static int vidioc_s_audinput(struct file *file, void *priv,
 	const struct v4l2_audio *i)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-	if (i->index >= 2)
+	struct cx23885_dev *dev = video_drvdata(file);
+
+	if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) ||
+		(CX23885_VMUX_CABLE == INPUT(dev->input)->type)) {
+		return i->index != 2 ? -EINVAL : 0;
+	}
+	if (i->index > 1)
 		return -EINVAL;
 
 	dprintk(1, "%s(%d)\n", __func__, i->index);
@@ -1445,35 +841,10 @@
 	return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-				struct v4l2_queryctrl *qctrl)
-{
-	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
-	if (unlikely(qctrl->id == 0))
-		return -EINVAL;
-	return cx23885_ctrl_query(qctrl);
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctl)
-{
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
-	return cx23885_get_control(dev, ctl);
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctl)
-{
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
-	return cx23885_set_control(dev, ctl);
-}
-
 static int vidioc_g_tuner(struct file *file, void *priv,
 				struct v4l2_tuner *t)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	if (dev->tuner_type == TUNER_ABSENT)
 		return -EINVAL;
@@ -1489,7 +860,7 @@
 static int vidioc_s_tuner(struct file *file, void *priv,
 				const struct v4l2_tuner *t)
 {
-	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	if (dev->tuner_type == TUNER_ABSENT)
 		return -EINVAL;
@@ -1504,14 +875,12 @@
 static int vidioc_g_frequency(struct file *file, void *priv,
 				struct v4l2_frequency *f)
 {
-	struct cx23885_fh *fh = priv;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 
 	if (dev->tuner_type == TUNER_ABSENT)
 		return -EINVAL;
 
-	/* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
-	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+	f->type = V4L2_TUNER_ANALOG_TV;
 	f->frequency = dev->freq;
 
 	call_all(dev, tuner, g_frequency, f);
@@ -1521,20 +890,23 @@
 
 static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency *f)
 {
-	struct v4l2_control ctrl;
+	struct v4l2_ctrl *mute;
+	int old_mute_val = 1;
 
 	if (dev->tuner_type == TUNER_ABSENT)
 		return -EINVAL;
 	if (unlikely(f->tuner != 0))
 		return -EINVAL;
 
-	mutex_lock(&dev->lock);
 	dev->freq = f->frequency;
 
 	/* I need to mute audio here */
-	ctrl.id = V4L2_CID_AUDIO_MUTE;
-	ctrl.value = 1;
-	cx23885_set_control(dev, &ctrl);
+	mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE);
+	if (mute) {
+		old_mute_val = v4l2_ctrl_g_ctrl(mute);
+		if (!old_mute_val)
+			v4l2_ctrl_s_ctrl(mute, 1);
+	}
 
 	call_all(dev, tuner, s_frequency, f);
 
@@ -1542,10 +914,8 @@
 	msleep(100);
 
 	/* I need to unmute audio here */
-	ctrl.value = 0;
-	cx23885_set_control(dev, &ctrl);
-
-	mutex_unlock(&dev->lock);
+	if (old_mute_val == 0)
+		v4l2_ctrl_s_ctrl(mute, old_mute_val);
 
 	return 0;
 }
@@ -1553,8 +923,9 @@
 static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
 	const struct v4l2_frequency *f)
 {
-	struct v4l2_control ctrl;
-	struct videobuf_dvb_frontend *vfe;
+	struct v4l2_ctrl *mute;
+	int old_mute_val = 1;
+	struct vb2_dvb_frontend *vfe;
 	struct dvb_frontend *fe;
 
 	struct analog_parameters params = {
@@ -1564,21 +935,22 @@
 		.frequency = f->frequency
 	};
 
-	mutex_lock(&dev->lock);
 	dev->freq = f->frequency;
 
 	/* I need to mute audio here */
-	ctrl.id = V4L2_CID_AUDIO_MUTE;
-	ctrl.value = 1;
-	cx23885_set_control(dev, &ctrl);
+	mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE);
+	if (mute) {
+		old_mute_val = v4l2_ctrl_g_ctrl(mute);
+		if (!old_mute_val)
+			v4l2_ctrl_s_ctrl(mute, 1);
+	}
 
 	/* If HVR1850 */
 	dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__,
 		params.frequency, f->tuner, params.std);
 
-	vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1);
+	vfe = vb2_dvb_get_frontend(&dev->ts2.frontends, 1);
 	if (!vfe) {
-		mutex_unlock(&dev->lock);
 		return -EINVAL;
 	}
 
@@ -1600,10 +972,8 @@
 	msleep(100);
 
 	/* I need to unmute audio here */
-	ctrl.value = 0;
-	cx23885_set_control(dev, &ctrl);
-
-	mutex_unlock(&dev->lock);
+	if (old_mute_val == 0)
+		v4l2_ctrl_s_ctrl(mute, old_mute_val);
 
 	return 0;
 }
@@ -1611,8 +981,7 @@
 int cx23885_set_frequency(struct file *file, void *priv,
 	const struct v4l2_frequency *f)
 {
-	struct cx23885_fh *fh = priv;
-	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_dev *dev = video_drvdata(file);
 	int ret;
 
 	switch (dev->board) {
@@ -1636,28 +1005,6 @@
 
 /* ----------------------------------------------------------- */
 
-static void cx23885_vid_timeout(unsigned long data)
-{
-	struct cx23885_dev *dev = (struct cx23885_dev *)data;
-	struct cx23885_dmaqueue *q = &dev->vidq;
-	struct cx23885_buffer *buf;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->slock, flags);
-	while (!list_empty(&q->active)) {
-		buf = list_entry(q->active.next,
-			struct cx23885_buffer, vb.queue);
-		list_del(&buf->vb.queue);
-		buf->vb.state = VIDEOBUF_ERROR;
-		wake_up(&buf->vb.done);
-		printk(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n",
-			dev->name, buf, buf->vb.i,
-			(unsigned long)buf->risc.dma);
-	}
-	cx23885_restart_video_queue(dev, q);
-	spin_unlock_irqrestore(&dev->slock, flags);
-}
-
 int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
 {
 	u32 mask, count;
@@ -1702,13 +1049,6 @@
 		spin_unlock(&dev->slock);
 		handled++;
 	}
-	if (status & VID_BC_MSK_RISCI2) {
-		dprintk(2, "stopper video\n");
-		spin_lock(&dev->slock);
-		cx23885_restart_video_queue(dev, &dev->vidq);
-		spin_unlock(&dev->slock);
-		handled++;
-	}
 
 	/* Allow the VBI framework to process it's payload */
 	handled += cx23885_vbi_irq(dev, status);
@@ -1721,12 +1061,12 @@
 
 static const struct v4l2_file_operations video_fops = {
 	.owner	       = THIS_MODULE,
-	.open	       = video_open,
-	.release       = video_release,
-	.read	       = video_read,
-	.poll          = video_poll,
-	.mmap	       = video_mmap,
-	.ioctl	       = video_ioctl2,
+	.open           = v4l2_fh_open,
+	.release        = vb2_fop_release,
+	.read           = vb2_fop_read,
+	.poll		= vb2_fop_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap           = vb2_fop_mmap,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -1738,21 +1078,19 @@
 	.vidioc_g_fmt_vbi_cap     = cx23885_vbi_fmt,
 	.vidioc_try_fmt_vbi_cap   = cx23885_vbi_fmt,
 	.vidioc_s_fmt_vbi_cap     = cx23885_vbi_fmt,
-	.vidioc_reqbufs       = vidioc_reqbufs,
-	.vidioc_querybuf      = vidioc_querybuf,
-	.vidioc_qbuf          = vidioc_qbuf,
-	.vidioc_dqbuf         = vidioc_dqbuf,
+	.vidioc_reqbufs       = vb2_ioctl_reqbufs,
+	.vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
+	.vidioc_querybuf      = vb2_ioctl_querybuf,
+	.vidioc_qbuf          = vb2_ioctl_qbuf,
+	.vidioc_dqbuf         = vb2_ioctl_dqbuf,
+	.vidioc_streamon      = vb2_ioctl_streamon,
+	.vidioc_streamoff     = vb2_ioctl_streamoff,
 	.vidioc_s_std         = vidioc_s_std,
 	.vidioc_g_std         = vidioc_g_std,
 	.vidioc_enum_input    = vidioc_enum_input,
 	.vidioc_g_input       = vidioc_g_input,
 	.vidioc_s_input       = vidioc_s_input,
 	.vidioc_log_status    = vidioc_log_status,
-	.vidioc_queryctrl     = vidioc_queryctrl,
-	.vidioc_g_ctrl        = vidioc_g_ctrl,
-	.vidioc_s_ctrl        = vidioc_s_ctrl,
-	.vidioc_streamon      = vidioc_streamon,
-	.vidioc_streamoff     = vidioc_streamoff,
 	.vidioc_g_tuner       = vidioc_g_tuner,
 	.vidioc_s_tuner       = vidioc_s_tuner,
 	.vidioc_g_frequency   = vidioc_g_frequency,
@@ -1765,6 +1103,8 @@
 	.vidioc_enumaudio     = vidioc_enum_audinput,
 	.vidioc_g_audio       = vidioc_g_audinput,
 	.vidioc_s_audio       = vidioc_s_audinput,
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 static struct video_device cx23885_vbi_template;
@@ -1775,14 +1115,6 @@
 	.tvnorms              = CX23885_NORMS,
 };
 
-static const struct v4l2_file_operations radio_fops = {
-	.owner         = THIS_MODULE,
-	.open          = video_open,
-	.release       = video_release,
-	.ioctl         = video_ioctl2,
-};
-
-
 void cx23885_video_unregister(struct cx23885_dev *dev)
 {
 	dprintk(1, "%s()\n", __func__);
@@ -1794,7 +1126,6 @@
 		else
 			video_device_release(dev->vbi_dev);
 		dev->vbi_dev = NULL;
-		btcx_riscmem_free(dev->pci, &dev->vbiq.stopper);
 	}
 	if (dev->video_dev) {
 		if (video_is_registered(dev->video_dev))
@@ -1802,8 +1133,6 @@
 		else
 			video_device_release(dev->video_dev);
 		dev->video_dev = NULL;
-
-		btcx_riscmem_free(dev->pci, &dev->vidq.stopper);
 	}
 
 	if (dev->audio_dev)
@@ -1812,6 +1141,7 @@
 
 int cx23885_video_register(struct cx23885_dev *dev)
 {
+	struct vb2_queue *q;
 	int err;
 
 	dprintk(1, "%s()\n", __func__);
@@ -1822,24 +1152,16 @@
 	strcpy(cx23885_vbi_template.name, "cx23885-vbi");
 
 	dev->tvnorm = V4L2_STD_NTSC_M;
+	dev->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
+	dev->field = V4L2_FIELD_INTERLACED;
+	dev->width = 720;
+	dev->height = norm_maxh(dev->tvnorm);
 
 	/* init video dma queues */
 	INIT_LIST_HEAD(&dev->vidq.active);
-	INIT_LIST_HEAD(&dev->vidq.queued);
-	dev->vidq.timeout.function = cx23885_vid_timeout;
-	dev->vidq.timeout.data = (unsigned long)dev;
-	init_timer(&dev->vidq.timeout);
-	cx23885_risc_stopper(dev->pci, &dev->vidq.stopper,
-		VID_A_DMA_CTL, 0x11, 0x00);
 
 	/* init vbi dma queues */
 	INIT_LIST_HEAD(&dev->vbiq.active);
-	INIT_LIST_HEAD(&dev->vbiq.queued);
-	dev->vbiq.timeout.function = cx23885_vbi_timeout;
-	dev->vbiq.timeout.data = (unsigned long)dev;
-	init_timer(&dev->vbiq.timeout);
-	cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper,
-		VID_A_DMA_CTL, 0x22, 0x00);
 
 	cx23885_irq_add_enable(dev, 0x01);
 
@@ -1893,9 +1215,49 @@
 		}
 	}
 
+	/* initial device configuration */
+	mutex_lock(&dev->lock);
+	cx23885_set_tvnorm(dev, dev->tvnorm);
+	cx23885_video_mux(dev, 0);
+	cx23885_audio_mux(dev, 0);
+	mutex_unlock(&dev->lock);
+
+	q = &dev->vb2_vidq;
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+	q->gfp_flags = GFP_DMA32;
+	q->min_buffers_needed = 2;
+	q->drv_priv = dev;
+	q->buf_struct_size = sizeof(struct cx23885_buffer);
+	q->ops = &cx23885_video_qops;
+	q->mem_ops = &vb2_dma_sg_memops;
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	q->lock = &dev->lock;
+
+	err = vb2_queue_init(q);
+	if (err < 0)
+		goto fail_unreg;
+
+	q = &dev->vb2_vbiq;
+	q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+	q->gfp_flags = GFP_DMA32;
+	q->min_buffers_needed = 2;
+	q->drv_priv = dev;
+	q->buf_struct_size = sizeof(struct cx23885_buffer);
+	q->ops = &cx23885_vbi_qops;
+	q->mem_ops = &vb2_dma_sg_memops;
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	q->lock = &dev->lock;
+
+	err = vb2_queue_init(q);
+	if (err < 0)
+		goto fail_unreg;
+
 	/* register Video device */
 	dev->video_dev = cx23885_vdev_init(dev, dev->pci,
 		&cx23885_video_template, "video");
+	dev->video_dev->queue = &dev->vb2_vidq;
 	err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER,
 				    video_nr[dev->nr]);
 	if (err < 0) {
@@ -1909,6 +1271,7 @@
 	/* register VBI device */
 	dev->vbi_dev = cx23885_vdev_init(dev, dev->pci,
 		&cx23885_vbi_template, "vbi");
+	dev->vbi_dev->queue = &dev->vb2_vbiq;
 	err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
 				    vbi_nr[dev->nr]);
 	if (err < 0) {
@@ -1922,18 +1285,9 @@
 	/* Register ALSA audio device */
 	dev->audio_dev = cx23885_audio_register(dev);
 
-	/* initial device configuration */
-	mutex_lock(&dev->lock);
-	cx23885_set_tvnorm(dev, dev->tvnorm);
-	init_controls(dev);
-	cx23885_video_mux(dev, 0);
-	cx23885_audio_mux(dev, 0);
-	mutex_unlock(&dev->lock);
-
 	return 0;
 
 fail_unreg:
 	cx23885_video_unregister(dev);
 	return err;
 }
-
diff --git a/drivers/media/pci/cx23885/cx23885-video.h b/drivers/media/pci/cx23885/cx23885-video.h
index c961a2b..291e8f3 100644
--- a/drivers/media/pci/cx23885/cx23885-video.h
+++ b/drivers/media/pci/cx23885/cx23885-video.h
@@ -12,11 +12,6 @@
  *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #ifndef _CX23885_VIDEO_H_
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
index 0e086c0..6c35e61 100644
--- a/drivers/media/pci/cx23885/cx23885.h
+++ b/drivers/media/pci/cx23885/cx23885.h
@@ -13,10 +13,6 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/pci.h>
@@ -25,19 +21,20 @@
 #include <linux/slab.h>
 
 #include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
 #include <media/tuner.h>
 #include <media/tveeprom.h>
-#include <media/videobuf-dma-sg.h>
-#include <media/videobuf-dvb.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-dvb.h>
 #include <media/rc-core.h>
 
-#include "btcx-risc.h"
 #include "cx23885-reg.h"
 #include "media/cx2341x.h"
 
 #include <linux/mutex.h>
 
-#define CX23885_VERSION "0.0.3"
+#define CX23885_VERSION "0.0.4"
 
 #define UNSET (-1U)
 
@@ -46,9 +43,6 @@
 /* Max number of inputs by card */
 #define MAX_CX23885_INPUT 8
 #define INPUT(nr) (&cx23885_boards[dev->board].input[nr])
-#define RESOURCE_OVERLAY       1
-#define RESOURCE_VIDEO         2
-#define RESOURCE_VBI           4
 
 #define BUFFER_TIMEOUT     (HZ)  /* 0.5 seconds */
 
@@ -98,6 +92,7 @@
 #define CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200 42
 #define CX23885_BOARD_HAUPPAUGE_IMPACTVCBE     43
 #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2 44
+#define CX23885_BOARD_DVBSKY_T9580             45
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
@@ -131,14 +126,6 @@
 	u32   cxformat;
 };
 
-struct cx23885_ctrl {
-	struct v4l2_queryctrl v;
-	u32                   off;
-	u32                   reg;
-	u32                   mask;
-	u32                   shift;
-};
-
 struct cx23885_tvnorm {
 	char		*name;
 	v4l2_std_id	id;
@@ -146,30 +133,6 @@
 	u32		cxoformat;
 };
 
-struct cx23885_fh {
-	struct cx23885_dev         *dev;
-	enum v4l2_buf_type         type;
-	int                        radio;
-	u32                        resources;
-
-	/* video overlay */
-	struct v4l2_window         win;
-	struct v4l2_clip           *clips;
-	unsigned int               nclips;
-
-	/* video capture */
-	struct cx23885_fmt         *fmt;
-	unsigned int               width, height;
-
-	/* vbi capture */
-	struct videobuf_queue      vidq;
-	struct videobuf_queue      vbiq;
-
-	/* MPEG Encoder specifics ONLY */
-	struct videobuf_queue      mpegq;
-	atomic_t                   v4l_reading;
-};
-
 enum cx23885_itype {
 	CX23885_VMUX_COMPOSITE1 = 1,
 	CX23885_VMUX_COMPOSITE2,
@@ -189,14 +152,22 @@
 	CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO
 };
 
+struct cx23885_riscmem {
+	unsigned int   size;
+	__le32         *cpu;
+	__le32         *jmp;
+	dma_addr_t     dma;
+};
+
 /* buffer for one video frame */
 struct cx23885_buffer {
 	/* common v4l buffer stuff -- must be first */
-	struct videobuf_buffer vb;
+	struct vb2_buffer vb;
+	struct list_head queue;
 
 	/* cx23885 specific */
 	unsigned int           bpl;
-	struct btcx_riscmem    risc;
+	struct cx23885_riscmem risc;
 	struct cx23885_fmt     *fmt;
 	u32                    count;
 };
@@ -268,9 +239,6 @@
 
 struct cx23885_dmaqueue {
 	struct list_head       active;
-	struct list_head       queued;
-	struct timer_list      timeout;
-	struct btcx_riscmem    stopper;
 	u32                    count;
 };
 
@@ -280,7 +248,7 @@
 	int                        nr;
 	int                        sram_chno;
 
-	struct videobuf_dvb_frontends frontends;
+	struct vb2_dvb_frontends   frontends;
 
 	/* dma queues */
 	struct cx23885_dmaqueue    mpegq;
@@ -326,7 +294,12 @@
 	/* Workaround for a temp dvb_frontend that the tuner can attached to */
 	struct dvb_frontend analog_fe;
 
+	struct i2c_client *i2c_client_demod;
+	struct i2c_client *i2c_client_tuner;
+
 	int (*set_frontend)(struct dvb_frontend *fe);
+	int (*fe_set_voltage)(struct dvb_frontend *fe,
+				fe_sec_voltage_t voltage);
 };
 
 struct cx23885_kernel_ir {
@@ -339,8 +312,11 @@
 
 struct cx23885_audio_buffer {
 	unsigned int		bpl;
-	struct btcx_riscmem	risc;
-	struct videobuf_dmabuf	dma;
+	struct cx23885_riscmem	risc;
+	void			*vaddr;
+	struct scatterlist	*sglist;
+	int                     sglen;
+	int                     nr_pages;
 };
 
 struct cx23885_audio_dev {
@@ -358,8 +334,6 @@
 	unsigned int		period_size;
 	unsigned int		num_periods;
 
-	struct videobuf_dmabuf	*dma_risc;
-
 	struct cx23885_audio_buffer   *buf;
 
 	struct snd_pcm_substream *substream;
@@ -368,6 +342,7 @@
 struct cx23885_dev {
 	atomic_t                   refcount;
 	struct v4l2_device 	   v4l2_dev;
+	struct v4l2_ctrl_handler   ctrl_handler;
 
 	/* pci stuff */
 	struct pci_dev             *pci;
@@ -407,7 +382,6 @@
 	} bridge;
 
 	/* Analog video */
-	u32                        resources;
 	unsigned int               input;
 	unsigned int               audinput; /* Selectable audio input */
 	u32                        tvaudio;
@@ -417,7 +391,6 @@
 	unsigned int               tuner_bus;
 	unsigned int               radio_type;
 	unsigned char              radio_addr;
-	unsigned int               has_radio;
 	struct v4l2_subdev 	   *sd_cx25840;
 	struct work_struct	   cx25840_work;
 
@@ -435,17 +408,24 @@
 	u32                        freq;
 	struct video_device        *video_dev;
 	struct video_device        *vbi_dev;
-	struct video_device        *radio_dev;
+
+	/* video capture */
+	struct cx23885_fmt         *fmt;
+	unsigned int               width, height;
+	unsigned		   field;
 
 	struct cx23885_dmaqueue    vidq;
+	struct vb2_queue           vb2_vidq;
 	struct cx23885_dmaqueue    vbiq;
+	struct vb2_queue           vb2_vbiq;
+
 	spinlock_t                 slock;
 
 	/* MPEG Encoder ONLY settings */
 	u32                        cx23417_mailbox;
-	struct cx2341x_mpeg_params mpeg_params;
+	struct cx2341x_handler     cxhdl;
 	struct video_device        *v4l_device;
-	atomic_t                   v4l_reader_count;
+	struct vb2_queue           vb2_mpegq;
 	struct cx23885_tvnorm      encodernorm;
 
 	/* Analog raw audio */
@@ -521,26 +501,21 @@
 extern void cx23885_sram_channel_dump(struct cx23885_dev *dev,
 	struct sram_channel *ch);
 
-extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-	u32 reg, u32 mask, u32 value);
-
-extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+extern int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
 	struct scatterlist *sglist,
 	unsigned int top_offset, unsigned int bottom_offset,
 	unsigned int bpl, unsigned int padding, unsigned int lines);
 
 extern int cx23885_risc_vbibuffer(struct pci_dev *pci,
-	struct btcx_riscmem *risc, struct scatterlist *sglist,
+	struct cx23885_riscmem *risc, struct scatterlist *sglist,
 	unsigned int top_offset, unsigned int bottom_offset,
 	unsigned int bpl, unsigned int padding, unsigned int lines);
 
+int cx23885_start_dma(struct cx23885_tsport *port,
+			     struct cx23885_dmaqueue *q,
+			     struct cx23885_buffer   *buf);
 void cx23885_cancel_buffers(struct cx23885_tsport *port);
 
-extern int cx23885_restart_queue(struct cx23885_tsport *port,
-				struct cx23885_dmaqueue *q);
-
-extern void cx23885_wakeup(struct cx23885_tsport *port,
-			   struct cx23885_dmaqueue *q, u32 count);
 
 extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask);
 extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask);
@@ -574,13 +549,11 @@
 extern int cx23885_dvb_register(struct cx23885_tsport *port);
 extern int cx23885_dvb_unregister(struct cx23885_tsport *port);
 
-extern int cx23885_buf_prepare(struct videobuf_queue *q,
-			       struct cx23885_tsport *port,
-			       struct cx23885_buffer *buf,
-			       enum v4l2_field field);
+extern int cx23885_buf_prepare(struct cx23885_buffer *buf,
+			       struct cx23885_tsport *port);
 extern void cx23885_buf_queue(struct cx23885_tsport *port,
 			      struct cx23885_buffer *buf);
-extern void cx23885_free_buffer(struct videobuf_queue *q,
+extern void cx23885_free_buffer(struct cx23885_dev *dev,
 				struct cx23885_buffer *buf);
 
 /* ----------------------------------------------------------- */
@@ -595,8 +568,6 @@
 int cx23885_set_input(struct file *file, void *priv, unsigned int i);
 int cx23885_get_input(struct file *file, void *priv, unsigned int *i);
 int cx23885_set_frequency(struct file *file, void *priv, const struct v4l2_frequency *f);
-int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
-int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
 int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
 
 /* ----------------------------------------------------------- */
@@ -604,9 +575,7 @@
 extern int cx23885_vbi_fmt(struct file *file, void *priv,
 	struct v4l2_format *f);
 extern void cx23885_vbi_timeout(unsigned long data);
-extern struct videobuf_queue_ops cx23885_vbi_qops;
-extern int cx23885_restart_vbi_queue(struct cx23885_dev *dev,
-	struct cx23885_dmaqueue *q);
+extern struct vb2_ops cx23885_vbi_qops;
 extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status);
 
 /* cx23885-i2c.c                                                */
@@ -638,7 +607,7 @@
 extern void cx23885_audio_unregister(struct cx23885_dev *dev);
 extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask);
 extern int cx23885_risc_databuffer(struct pci_dev *pci,
-				   struct btcx_riscmem *risc,
+				   struct cx23885_riscmem *risc,
 				   struct scatterlist *sglist,
 				   unsigned int bpl,
 				   unsigned int lines,
@@ -649,15 +618,10 @@
 
 static inline unsigned int norm_maxw(v4l2_std_id norm)
 {
-	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+	return (norm & V4L2_STD_525_60) ? 720 : 768;
 }
 
 static inline unsigned int norm_maxh(v4l2_std_id norm)
 {
-	return (norm & V4L2_STD_625_50) ? 576 : 480;
-}
-
-static inline unsigned int norm_swidth(v4l2_std_id norm)
-{
-	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+	return (norm & V4L2_STD_525_60) ? 480 : 576;
 }
diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
index 54fa7f2..eda568b 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.c
+++ b/drivers/media/pci/cx23885/cx23888-ir.c
@@ -14,11 +14,6 @@
  *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #include <linux/kfifo.h>
@@ -263,7 +258,7 @@
 }
 
 /*
- * FIFO register pulse width count compuations
+ * FIFO register pulse width count computations
  */
 static u32 clock_divider_to_resolution(u16 divider)
 {
diff --git a/drivers/media/pci/cx23885/cx23888-ir.h b/drivers/media/pci/cx23885/cx23888-ir.h
index d2de41c..ff74a93 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.h
+++ b/drivers/media/pci/cx23885/cx23888-ir.h
@@ -14,11 +14,6 @@
  *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- *  02110-1301, USA.
  */
 
 #ifndef _CX23888_IR_H_
diff --git a/drivers/media/pci/cx23885/netup-eeprom.c b/drivers/media/pci/cx23885/netup-eeprom.c
index 98a48f5..b6542ee 100644
--- a/drivers/media/pci/cx23885/netup-eeprom.c
+++ b/drivers/media/pci/cx23885/netup-eeprom.c
@@ -17,10 +17,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #
diff --git a/drivers/media/pci/cx23885/netup-eeprom.h b/drivers/media/pci/cx23885/netup-eeprom.h
index 13926e1..90cac5b 100644
--- a/drivers/media/pci/cx23885/netup-eeprom.h
+++ b/drivers/media/pci/cx23885/netup-eeprom.h
@@ -16,10 +16,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef NETUP_EEPROM_H
diff --git a/drivers/media/pci/cx23885/netup-init.c b/drivers/media/pci/cx23885/netup-init.c
index 0044fef..76d9487 100644
--- a/drivers/media/pci/cx23885/netup-init.c
+++ b/drivers/media/pci/cx23885/netup-init.c
@@ -17,10 +17,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include "cx23885.h"
diff --git a/drivers/media/pci/cx23885/netup-init.h b/drivers/media/pci/cx23885/netup-init.h
index d26ae4b..daaa212 100644
--- a/drivers/media/pci/cx23885/netup-init.h
+++ b/drivers/media/pci/cx23885/netup-init.h
@@ -17,9 +17,5 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 extern void netup_initialize(struct cx23885_dev *dev);
diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c
index 1f43be0..a664997 100644
--- a/drivers/media/pci/cx25821/cx25821-video-upstream.c
+++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c
@@ -330,8 +330,9 @@
 
 	if (frame_size - curpos < count)
 		count = frame_size - curpos;
-	memcpy((char *)out->_data_buf_virt_addr + frame_offset + curpos,
-			data, count);
+	if (copy_from_user((__force char *)out->_data_buf_virt_addr + frame_offset + curpos,
+				data, count))
+		return -EFAULT;
 	curpos += count;
 	if (curpos == frame_size) {
 		out->_frame_count++;
diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
index e18a7ac..851754b 100644
--- a/drivers/media/pci/cx88/cx88-cards.c
+++ b/drivers/media/pci/cx88/cx88-cards.c
@@ -78,19 +78,19 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 0,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE2,
 			.vmux   = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE3,
 			.vmux   = 2,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE4,
 			.vmux   = 3,
-		}},
+		} },
 	},
 	[CX88_BOARD_HAUPPAUGE] = {
 		.name		= "Hauppauge WinTV 34xxx models",
@@ -99,23 +99,23 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0xff00,  // internal decoder
-		},{
+		}, {
 			.type   = CX88_VMUX_DEBUG,
 			.vmux   = 0,
 			.gpio0  = 0xff01,  // mono from tuner chip
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0xff02,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0xff02,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0xff01,
@@ -127,13 +127,13 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-		}},
+		} },
 	},
 	[CX88_BOARD_PIXELVIEW] = {
 		.name           = "PixelView",
@@ -141,17 +141,17 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0xff00,  // internal decoder
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-		}},
+		} },
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0xff10,
@@ -164,19 +164,19 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x03ff,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x03fe,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x03fe,
-		}},
+		} },
 	},
 	[CX88_BOARD_WINFAST2000XP_EXPERT] = {
 		.name           = "Leadtek Winfast 2000XP Expert",
@@ -185,28 +185,28 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0	= 0x00F5e700,
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x00F5e700,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0	= 0x00F5c700,
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x00F5c700,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0	= 0x00F5c700,
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x00F5c700,
 			.gpio3  = 0x02000000,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0	= 0x00F5d700,
@@ -222,19 +222,19 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio1  = 0xe09f,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio1  = 0xe05f,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio1  = 0xe05f,
-		}},
+		} },
 		.radio = {
 			.gpio1  = 0xe0df,
 			.type   = CX88_RADIO,
@@ -249,25 +249,25 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf	= TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x000040bf,
 			.gpio1  = 0x000080c0,
 			.gpio2  = 0x0000ff40,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x000040bf,
 			.gpio1  = 0x000080c0,
 			.gpio2  = 0x0000ff40,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x000040bf,
 			.gpio1  = 0x000080c0,
 			.gpio2  = 0x0000ff40,
-		}},
+		} },
 		.radio = {
 			 .type   = CX88_RADIO,
 			 .vmux   = 3,
@@ -283,14 +283,14 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0035e700,
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x0035e700,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
@@ -298,14 +298,14 @@
 			.gpio1  = 0x00003004,
 			.gpio2  = 0x0035c700,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0035c700,
 			.gpio1  = 0x0035c700,
 			.gpio2  = 0x02000000,
 			.gpio3  = 0x02000000,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x0035d700,
@@ -322,22 +322,22 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0000bde2,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x0000bde6,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0000bde6,
 			.audioroute = 1,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x0000bd62,
@@ -351,16 +351,16 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 0,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE2,
 			.vmux   = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-		}},
+		} },
 	},
 	[CX88_BOARD_PROLINK_PLAYTVPVR] = {
 		.name           = "Prolink PlayTV PVR",
@@ -369,19 +369,19 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf	= TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0xbff0,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0xbff3,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0xbff3,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0xbff0,
@@ -394,16 +394,16 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0000fde6,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
 			.audioroute = 1,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x0000fde2,
@@ -417,22 +417,22 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x00000fbf,
 			.gpio2  = 0x0000fc08,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00000fbf,
 			.gpio2  = 0x0000fc68,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00000fbf,
 			.gpio2  = 0x0000fc68,
-		}},
+		} },
 	},
 	[CX88_BOARD_KWORLD_DVB_T] = {
 		.name           = "KWorld/VStream XPert DVB-T",
@@ -440,17 +440,17 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
@@ -459,15 +459,15 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x000027df,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x000027df,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_KWORLD_LTV883] = {
@@ -476,23 +476,23 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x07f8,
-		},{
+		}, {
 			.type   = CX88_VMUX_DEBUG,
 			.vmux   = 0,
 			.gpio0  = 0x07f9,  // mono from tuner chip
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x000007fa,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x000007fa,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x000007f8,
@@ -521,23 +521,23 @@
 		    0 - normal RF
 		    1 - high RF
 		*/
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0	= 0x0f0d,
-		},{
+		}, {
 			.type   = CX88_VMUX_CABLE,
 			.vmux   = 0,
 			.gpio0	= 0x0f05,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0	= 0x0f00,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0	= 0x0f00,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_HAUPPAUGE_DVB_T1] = {
@@ -546,10 +546,10 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_CONEXANT_DVB_T1] = {
@@ -558,10 +558,10 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_PROVIDEO_PV259] = {
@@ -570,11 +570,11 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.audioroute = 1,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_BLACKBIRD,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
@@ -583,15 +583,15 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x000027df,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x000027df,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_DNTV_LIVE_DVB_T] = {
@@ -600,17 +600,17 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input		= {{
+		.input		= { {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00000700,
 			.gpio2  = 0x00000101,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00000700,
 			.gpio2  = 0x00000101,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_PCHDTV_HD3000] = {
@@ -632,19 +632,19 @@
 		 *
 		 * GPIO[16] = Remote control input
 		 */
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x00008484,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00008400,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00008400,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x00008404,
@@ -659,25 +659,25 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0xed1a,
 			.gpio2  = 0x00ff,
-		},{
+		}, {
 			.type   = CX88_VMUX_DEBUG,
 			.vmux   = 0,
 			.gpio0  = 0xff01,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0xff02,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0xed92,
 			.gpio2  = 0x00ff,
-		}},
+		} },
 		.radio = {
 			 .type   = CX88_RADIO,
 			 .gpio0  = 0xed96,
@@ -692,22 +692,22 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x00009d80,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00009d76,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00009d76,
 			.audioroute = 1,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x00009d00,
@@ -722,19 +722,19 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 1,
 			.gpio1  = 0x0000e03f,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 2,
 			.gpio1  = 0x0000e07f,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 3,
 			.gpio1  = 0x0000e07f,
-		}}
+		} }
 	},
 	[CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = {
 		.name           = "PixelView PlayTV Ultra Pro (Stereo)",
@@ -745,19 +745,19 @@
 		.radio_addr	= ADDR_UNSET,
 		/* Some variants use a tda9874 and so need the tvaudio module. */
 		.audio_chip     = CX88_AUDIO_TVAUDIO,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0xbf61,  /* internal decoder */
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0	= 0xbf63,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0	= 0xbf63,
-		}},
+		} },
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0xbf60,
@@ -770,19 +770,19 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x97ed,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x97e9,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x97e9,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_ADSTECH_DVB_T_PCI] = {
@@ -791,32 +791,32 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
 		.name           = "TerraTec Cinergy 1400 DVB-T",
 		.tuner_type     = TUNER_ABSENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 2,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
@@ -826,19 +826,19 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x87fd,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x87f9,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x87f9,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = {
@@ -848,22 +848,22 @@
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 0,
 			.gpio0  = 0x0000cd73,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 1,
 			.gpio0  = 0x0000cd73,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 3,
 			.gpio0  = 0x0000cdb3,
 			.audioroute = 1,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.vmux   = 2,
@@ -876,21 +876,21 @@
 		 /* Alexander Wold <awold@bigfoot.com> */
 		 .name           = "Kworld V-Stream Xpert DVD",
 		 .tuner_type     = UNSET,
-		 .input          = {{
+		 .input          = { {
 			 .type   = CX88_VMUX_COMPOSITE1,
 			 .vmux   = 1,
 			 .gpio0  = 0x03000000,
 			 .gpio1  = 0x01000000,
 			 .gpio2  = 0x02000000,
 			 .gpio3  = 0x00100000,
-		 },{
+		 }, {
 			 .type   = CX88_VMUX_SVIDEO,
 			 .vmux   = 2,
 			 .gpio0  = 0x03000000,
 			 .gpio1  = 0x01000000,
 			 .gpio2  = 0x02000000,
 			 .gpio3  = 0x00100000,
-		 }},
+		 } },
 	},
 	[CX88_BOARD_ATI_HDTVWONDER] = {
 		.name           = "ATI HDTV Wonder",
@@ -898,28 +898,28 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x00000ff7,
 			.gpio1  = 0x000000ff,
 			.gpio2  = 0x00000001,
 			.gpio3  = 0x00000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00000ffe,
 			.gpio1  = 0x000000ff,
 			.gpio2  = 0x00000001,
 			.gpio3  = 0x00000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00000ffe,
 			.gpio1  = 0x000000ff,
 			.gpio2  = 0x00000001,
 			.gpio3  = 0x00000000,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_WINFAST_DTV1000] = {
@@ -928,16 +928,16 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_AVERTV_303] = {
@@ -947,28 +947,28 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x00ff,
 			.gpio1  = 0xe09f,
 			.gpio2  = 0x0010,
 			.gpio3  = 0x0000,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00ff,
 			.gpio1  = 0xe05f,
 			.gpio2  = 0x0010,
 			.gpio3  = 0x0000,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00ff,
 			.gpio1  = 0xe05f,
 			.gpio2  = 0x0010,
 			.gpio3  = 0x0000,
-		}},
+		} },
 	},
 	[CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = {
 		.name		= "Hauppauge Nova-S-Plus DVB-S",
@@ -978,22 +978,22 @@
 		.radio_addr	= ADDR_UNSET,
 		.audio_chip	= CX88_AUDIO_WM8775,
 		.i2sinputcntl   = 2,
-		.input		= {{
+		.input		= { {
 			.type	= CX88_VMUX_DVB,
 			.vmux	= 0,
 			/* 2: Line-In */
 			.audioroute = 2,
-		},{
+		}, {
 			.type	= CX88_VMUX_COMPOSITE1,
 			.vmux	= 1,
 			/* 2: Line-In */
 			.audioroute = 2,
-		},{
+		}, {
 			.type	= CX88_VMUX_SVIDEO,
 			.vmux	= 2,
 			/* 2: Line-In */
 			.audioroute = 2,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = {
@@ -1002,10 +1002,10 @@
 		.radio_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input		= {{
+		.input		= { {
 			.type	= CX88_VMUX_DVB,
 			.vmux	= 0,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_KWORLD_DVBS_100] = {
@@ -1015,22 +1015,22 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.audio_chip = CX88_AUDIO_WM8775,
-		.input		= {{
+		.input		= { {
 			.type	= CX88_VMUX_DVB,
 			.vmux	= 0,
 			/* 2: Line-In */
 			.audioroute = 2,
-		},{
+		}, {
 			.type	= CX88_VMUX_COMPOSITE1,
 			.vmux	= 1,
 			/* 2: Line-In */
 			.audioroute = 2,
-		},{
+		}, {
 			.type	= CX88_VMUX_SVIDEO,
 			.vmux	= 2,
 			/* 2: Line-In */
 			.audioroute = 2,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_HAUPPAUGE_HVR1100] = {
@@ -1040,16 +1040,16 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input		= {{
+		.input		= { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-		},{
+		}, {
 			.type	= CX88_VMUX_COMPOSITE1,
 			.vmux	= 1,
-		},{
+		}, {
 			.type	= CX88_VMUX_SVIDEO,
 			.vmux	= 2,
-		}},
+		} },
 		/* fixme: Add radio support */
 		.mpeg           = CX88_MPEG_DVB,
 	},
@@ -1060,13 +1060,13 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input		= {{
+		.input		= { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-		},{
+		}, {
 			.type	= CX88_VMUX_COMPOSITE1,
 			.vmux	= 1,
-		}},
+		} },
 		/* fixme: Add radio support */
 		.mpeg           = CX88_MPEG_DVB,
 	},
@@ -1078,19 +1078,19 @@
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
 				  TDA9887_PORT2_ACTIVE,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0xf80808,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0	= 0xf80808,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0	= 0xf80808,
-		}},
+		} },
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0xf80808,
@@ -1106,17 +1106,17 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0700,
 			.gpio2  = 0x0101,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = {
@@ -1125,15 +1125,15 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x000067df,
-		 },{
+		 }, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x000067df,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
@@ -1142,22 +1142,22 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x3de2,
 			.gpio2  = 0x00ff,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x3de6,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x3de6,
 			.audioroute = 1,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x3de6,
@@ -1171,19 +1171,19 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0000a75f,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x0000a75b,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0000a75b,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_PCHDTV_HD5500] = {
@@ -1193,19 +1193,19 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x87fd,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x87f9,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x87f9,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_KWORLD_MCE200_DELUXE] = {
@@ -1217,11 +1217,11 @@
 		.tda9887_conf   = TDA9887_PRESENT,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0000BDE6
-		}},
+		} },
 		.mpeg           = CX88_MPEG_BLACKBIRD,
 	},
 	[CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
@@ -1233,11 +1233,11 @@
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
 				  TDA9887_PORT2_ACTIVE,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x5da6,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_BLACKBIRD,
 	},
 	[CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
@@ -1246,19 +1246,19 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0	= 0x0788,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0	= 0x078b,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0	= 0x078b,
-		}},
+		} },
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0x074a,
@@ -1271,7 +1271,7 @@
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x00017304,
@@ -1299,7 +1299,7 @@
 			.gpio1  = 0x0000b207,
 			.gpio2  = 0x0001d701,
 			.gpio3  = 0x02000000,
-		}},
+		} },
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0x00015702,
@@ -1316,35 +1316,35 @@
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x00017300,
 			.gpio1  = 0x00008207,
 			.gpio2	= 0x00000000,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x00018300,
 			.gpio1  = 0x0000f207,
 			.gpio2	= 0x00017304,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00018301,
 			.gpio1  = 0x0000f207,
 			.gpio2	= 0x00017304,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00018301,
 			.gpio1  = 0x0000f207,
 			.gpio2	= 0x00017304,
 			.gpio3  = 0x02000000,
-		}},
+		} },
 		.radio = {
 			 .type  = CX88_RADIO,
 			 .gpio0 = 0x00015702,
@@ -1360,13 +1360,13 @@
 		.radio_type    = UNSET,
 		.tuner_addr    = ADDR_UNSET,
 		.radio_addr    = ADDR_UNSET,
-		.input  = {{
+		.input  = { {
 			.type  = CX88_VMUX_DVB,
 			.vmux  = 0,
-		},{
+		}, {
 			.type  = CX88_VMUX_COMPOSITE1,
 			.vmux  = 1,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_HAUPPAUGE_HVR3000] = {
@@ -1377,25 +1377,25 @@
 		.radio_addr     = ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
 		.audio_chip     = CX88_AUDIO_WM8775,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x84bf,
 			/* 1: TV Audio / FM Mono */
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x84bf,
 			/* 2: Line-In */
 			.audioroute = 2,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x84bf,
 			/* 2: Line-In */
 			.audioroute = 2,
-		}},
+		} },
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0	= 0x84bf,
@@ -1411,19 +1411,19 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0709,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x070b,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x070b,
-		}},
+		} },
 	},
 	[CX88_BOARD_TE_DTV_250_OEM_SWANN] = {
 		.name           = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM",
@@ -1431,28 +1431,28 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x003fffff,
 			.gpio1  = 0x00e00000,
 			.gpio2  = 0x003fffff,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x003fffff,
 			.gpio1  = 0x00e00000,
 			.gpio2  = 0x003fffff,
 			.gpio3  = 0x02000000,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x003fffff,
 			.gpio1  = 0x00e00000,
 			.gpio2  = 0x003fffff,
 			.gpio3  = 0x02000000,
-		}},
+		} },
 	},
 	[CX88_BOARD_HAUPPAUGE_HVR1300] = {
 		.name		= "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder",
@@ -1465,25 +1465,25 @@
 		/*
 		 * gpio0 as reported by Mike Crash <mike AT mikecrash.com>
 		 */
-		.input		= {{
+		.input		= { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0	= 0xef88,
 			/* 1: TV Audio / FM Mono */
 			.audioroute = 1,
-		},{
+		}, {
 			.type	= CX88_VMUX_COMPOSITE1,
 			.vmux	= 1,
 			.gpio0	= 0xef88,
 			/* 2: Line-In */
 			.audioroute = 2,
-		},{
+		}, {
 			.type	= CX88_VMUX_SVIDEO,
 			.vmux	= 2,
 			.gpio0	= 0xef88,
 			/* 2: Line-In */
 			.audioroute = 2,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
 		.radio = {
 			.type   = CX88_RADIO,
@@ -1510,19 +1510,19 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DEBUG,
 			.vmux   = 3,
 			.gpio0  = 0x04ff,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x07fa,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x07fa,
-		}},
+		} },
 	},
 	[CX88_BOARD_PINNACLE_PCTV_HD_800i] = {
 		.name           = "Pinnacle PCTV HD 800i",
@@ -1530,24 +1530,24 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x04fb,
 			.gpio1  = 0x10ff,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x04fb,
 			.gpio1  = 0x10ef,
 			.audioroute = 1,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x04fb,
 			.gpio1  = 0x10ef,
 			.audioroute = 1,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = {
@@ -1557,7 +1557,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x000027df, /* Unconfirmed */
@@ -1815,19 +1815,19 @@
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x10df,
-		},{
+		}, {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x16d9,
-		},{
+		}, {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x16d9,
-		}},
+		} },
 		.mpeg           = CX88_MPEG_DVB,
 	},
 	[CX88_BOARD_PROLINK_PV_8000GT] = {
@@ -1967,7 +1967,7 @@
 		 * 3: Line-In Expansion
 		 * 4: FM Stereo
 		 */
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0xc4bf,
@@ -2001,7 +2001,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
 		} },
@@ -2013,7 +2013,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
 		} },
@@ -2025,7 +2025,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
 		} },
@@ -2037,7 +2037,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
 		} },
@@ -2049,7 +2049,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
 		} },
@@ -2061,7 +2061,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
 		} },
@@ -2073,7 +2073,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
 			.gpio0  = 0x8080,
@@ -2086,7 +2086,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
 		} },
@@ -2098,7 +2098,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
 		} },
@@ -2110,7 +2110,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
 		} },
@@ -2170,7 +2170,7 @@
 		 * 13: audio source (0=tuner audio,1=line in)
 		 * 14: FM (0=on,1=off ???)
 		 */
-		.input          = {{
+		.input          = { {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0400,       /* pin 2 = 0 */
@@ -2211,7 +2211,7 @@
 		 * 13: audio source (0=tuner audio,1=line in)
 		 * 14: FM (0=on,1=off ???)
 		 */
-		.input		= {{
+		.input		= { {
 			.type	= CX88_VMUX_TELEVISION,
 			.vmux	= 0,
 			.gpio0	= 0x0400,	/* pin 2 = 0 */
@@ -2229,7 +2229,7 @@
 			.gpio0	= 0x0400,	/* pin 2 = 0 */
 			.gpio1	= 0x6060,	/* pin 13 = 1, pin 14 = 1 */
 			.gpio2	= 0x0000,
-		}},
+		} },
 		.radio = {
 			.type	= CX88_RADIO,
 			.gpio0	= 0x0400,	/* pin 2 = 0 */
@@ -2252,7 +2252,7 @@
 		 *  14: 0: FM radio
 		 *  16: 0: RF input is cable
 		 */
-		.input		= {{
+		.input		= { {
 			.type	= CX88_VMUX_TELEVISION,
 			.vmux	= 0,
 			.gpio0	= 0x0403,
@@ -2280,7 +2280,7 @@
 			.gpio1	= 0xF0F7,
 			.gpio2	= 0x0101,
 			.gpio3	= 0x0000,
-		}},
+		} },
 		.radio = {
 			.type	= CX88_RADIO,
 			.gpio0	= 0x0403,
@@ -2308,7 +2308,7 @@
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.input          = {{
+		.input          = { {
 		       .type   = CX88_VMUX_DVB,
 		       .vmux   = 0,
 		} },
@@ -2324,19 +2324,19 @@
 		.subvendor = 0x0070,
 		.subdevice = 0x3400,
 		.card      = CX88_BOARD_HAUPPAUGE,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x3401,
 		.card      = CX88_BOARD_HAUPPAUGE,
-	},{
+	}, {
 		.subvendor = 0x14c7,
 		.subdevice = 0x0106,
 		.card      = CX88_BOARD_GDI,
-	},{
+	}, {
 		.subvendor = 0x14c7,
 		.subdevice = 0x0107, /* with mpeg encoder */
 		.card      = CX88_BOARD_GDI,
-	},{
+	}, {
 		.subvendor = PCI_VENDOR_ID_ATI,
 		.subdevice = 0x00f8,
 		.card      = CX88_BOARD_ATI_WONDER_PRO,
@@ -2348,176 +2348,176 @@
 		.subvendor = 0x107d,
 		.subdevice = 0x6611,
 		.card      = CX88_BOARD_WINFAST2000XP_EXPERT,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x6613,	/* NTSC */
 		.card      = CX88_BOARD_WINFAST2000XP_EXPERT,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x6620,
 		.card      = CX88_BOARD_WINFAST_DV2000,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x663b,
 		.card      = CX88_BOARD_LEADTEK_PVR2000,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x663c,
 		.card      = CX88_BOARD_LEADTEK_PVR2000,
-	},{
+	}, {
 		.subvendor = 0x1461,
 		.subdevice = 0x000b,
 		.card      = CX88_BOARD_AVERTV_STUDIO_303,
-	},{
+	}, {
 		.subvendor = 0x1462,
 		.subdevice = 0x8606,
 		.card      = CX88_BOARD_MSI_TVANYWHERE_MASTER,
-	},{
+	}, {
 		.subvendor = 0x10fc,
 		.subdevice = 0xd003,
 		.card      = CX88_BOARD_IODATA_GVVCP3PCI,
-	},{
+	}, {
 		.subvendor = 0x1043,
 		.subdevice = 0x4823,  /* with mpeg encoder */
 		.card      = CX88_BOARD_ASUS_PVR_416,
-	},{
+	}, {
 		.subvendor = 0x17de,
 		.subdevice = 0x08a6,
 		.card      = CX88_BOARD_KWORLD_DVB_T,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xd810,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xd820,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb00,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9002,
 		.card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-	},{
+	}, {
 		.subvendor = 0x14f1,
 		.subdevice = 0x0187,
 		.card      = CX88_BOARD_CONEXANT_DVB_T1,
-	},{
+	}, {
 		.subvendor = 0x1540,
 		.subdevice = 0x2580,
 		.card      = CX88_BOARD_PROVIDEO_PV259,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb10,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
-	},{
+	}, {
 		.subvendor = 0x1554,
 		.subdevice = 0x4811,
 		.card      = CX88_BOARD_PIXELVIEW,
-	},{
+	}, {
 		.subvendor = 0x7063,
 		.subdevice = 0x3000, /* HD-3000 card */
 		.card      = CX88_BOARD_PCHDTV_HD3000,
-	},{
+	}, {
 		.subvendor = 0x17de,
 		.subdevice = 0xa8a6,
 		.card      = CX88_BOARD_DNTV_LIVE_DVB_T,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x2801,
 		.card      = CX88_BOARD_HAUPPAUGE_ROSLYN,
-	},{
+	}, {
 		.subvendor = 0x14f1,
 		.subdevice = 0x0342,
 		.card      = CX88_BOARD_DIGITALLOGIC_MEC,
-	},{
+	}, {
 		.subvendor = 0x10fc,
 		.subdevice = 0xd035,
 		.card      = CX88_BOARD_IODATA_GVBCTV7E,
-	},{
+	}, {
 		.subvendor = 0x1421,
 		.subdevice = 0x0334,
 		.card      = CX88_BOARD_ADSTECH_DVB_T_PCI,
-	},{
+	}, {
 		.subvendor = 0x153b,
 		.subdevice = 0x1166,
 		.card      = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xd500,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD,
-	},{
+	}, {
 		.subvendor = 0x1461,
 		.subdevice = 0x8011,
 		.card      = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550,
-	},{
+	}, {
 		.subvendor = PCI_VENDOR_ID_ATI,
 		.subdevice = 0xa101,
 		.card      = CX88_BOARD_ATI_HDTVWONDER,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x665f,
 		.card      = CX88_BOARD_WINFAST_DTV1000,
-	},{
+	}, {
 		.subvendor = 0x1461,
 		.subdevice = 0x000a,
 		.card      = CX88_BOARD_AVERTV_303,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9200,
 		.card      = CX88_BOARD_HAUPPAUGE_NOVASE2_S1,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9201,
 		.card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9202,
 		.card      = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
-	},{
+	}, {
 		.subvendor = 0x17de,
 		.subdevice = 0x08b2,
 		.card      = CX88_BOARD_KWORLD_DVBS_100,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9400,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1100,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9402,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1100,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9800,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9802,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9001,
 		.card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-	},{
+	}, {
 		.subvendor = 0x1822,
 		.subdevice = 0x0025,
 		.card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
-	},{
+	}, {
 		.subvendor = 0x17de,
 		.subdevice = 0x08a1,
 		.card      = CX88_BOARD_KWORLD_DVB_T_CX22702,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb50,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb54,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
 		/* Re-branded DViCO: DigitalNow DVB-T Dual */
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb11,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
@@ -2530,55 +2530,55 @@
 		.subvendor = 0x17de,
 		.subdevice = 0x0840,
 		.card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
-	},{
+	}, {
 		.subvendor = 0x1421,
 		.subdevice = 0x0305,
 		.card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb40,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xdb44,
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
-	},{
+	}, {
 		.subvendor = 0x7063,
 		.subdevice = 0x5500,
 		.card      = CX88_BOARD_PCHDTV_HD5500,
-	},{
+	}, {
 		.subvendor = 0x17de,
 		.subdevice = 0x0841,
 		.card      = CX88_BOARD_KWORLD_MCE200_DELUXE,
-	},{
+	}, {
 		.subvendor = 0x1822,
 		.subdevice = 0x0019,
 		.card      = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
-	},{
+	}, {
 		.subvendor = 0x1554,
 		.subdevice = 0x4813,
 		.card      = CX88_BOARD_PIXELVIEW_PLAYTV_P7000,
-	},{
+	}, {
 		.subvendor = 0x14f1,
 		.subdevice = 0x0842,
 		.card      = CX88_BOARD_NPGTECH_REALTV_TOP10FM,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x665e,
 		.card      = CX88_BOARD_WINFAST_DTV2000H,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x6f2b,
 		.card      = CX88_BOARD_WINFAST_DTV2000H_J,
-	},{
+	}, {
 		.subvendor = 0x18ac,
 		.subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
 		.card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
-	},{
+	}, {
 		.subvendor = 0x14f1,
 		.subdevice = 0x0084,
 		.card      = CX88_BOARD_GENIATECH_DVBS,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x1404,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
@@ -2590,60 +2590,60 @@
 		.subvendor = 0x18ac,
 		.subdevice = 0xdccd,
 		.card      = CX88_BOARD_SAMSUNG_SMT_7020,
-	},{
+	}, {
 		.subvendor = 0x1461,
 		.subdevice = 0xc111, /* AverMedia M150-D */
 		/* This board is known to work with the ASUS PVR416 config */
 		.card      = CX88_BOARD_ASUS_PVR_416,
-	},{
+	}, {
 		.subvendor = 0xc180,
 		.subdevice = 0xc980,
 		.card      = CX88_BOARD_TE_DTV_250_OEM_SWANN,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9600,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1300,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9601,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1300,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9602,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR1300,
-	},{
+	}, {
 		.subvendor = 0x107d,
 		.subdevice = 0x6632,
 		.card      = CX88_BOARD_LEADTEK_PVR2000,
-	},{
+	}, {
 		.subvendor = 0x12ab,
 		.subdevice = 0x2300, /* Club3D Zap TV2100 */
 		.card      = CX88_BOARD_KWORLD_DVB_T_CX22702,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x9000,
 		.card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x1400,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x1401,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
-	},{
+	}, {
 		.subvendor = 0x0070,
 		.subdevice = 0x1402,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
-	},{
+	}, {
 		.subvendor = 0x1421,
 		.subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
 		.card      = CX88_BOARD_KWORLD_DVBS_100,
-	},{
+	}, {
 		.subvendor = 0x1421,
 		.subdevice = 0x0390,
 		.card      = CX88_BOARD_ADSTECH_PTV_390,
-	},{
+	}, {
 		.subvendor = 0x11bd,
 		.subdevice = 0x0051,
 		.card      = CX88_BOARD_PINNACLE_PCTV_HD_800i,
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index 08b9220..e46b732 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -696,7 +696,6 @@
 		return &fh->vbiq;
 	default:
 		BUG();
-		return NULL;
 	}
 }
 
@@ -711,7 +710,6 @@
 		return RESOURCE_VBI;
 	default:
 		BUG();
-		return 0;
 	}
 }
 
@@ -812,7 +810,6 @@
 					    file->f_flags & O_NONBLOCK);
 	default:
 		BUG();
-		return 0;
 	}
 }
 
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 76c1c53..ad8dfdd 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -149,7 +149,7 @@
 	return I2C_FUNC_SMBUS_EMUL;
 }
 
-struct i2c_algorithm ddb_i2c_algo = {
+static struct i2c_algorithm ddb_i2c_algo = {
 	.master_xfer   = ddb_i2c_master_xfer,
 	.functionality = ddb_i2c_functionality,
 };
@@ -266,7 +266,7 @@
 	for (i = 0; i < num; i++) {
 		if (vbuf[i]) {
 			pci_free_consistent(pdev, size, vbuf[i], pbuf[i]);
-			vbuf[i] = 0;
+			vbuf[i] = NULL;
 		}
 	}
 }
@@ -440,7 +440,7 @@
 }
 
 static ssize_t ddb_output_write(struct ddb_output *output,
-				const u8 *buf, size_t count)
+				const __user u8 *buf, size_t count)
 {
 	struct ddb *dev = output->port->dev;
 	u32 idx, off, stat = output->stat;
@@ -506,7 +506,7 @@
 	return 0;
 }
 
-static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
+static ssize_t ddb_input_read(struct ddb_input *input, __user u8 *buf, size_t count)
 {
 	struct ddb *dev = input->port->dev;
 	u32 left = count;
@@ -849,7 +849,7 @@
 		return ret;
 	input->attached = 4;
 
-	input->fe = 0;
+	input->fe = NULL;
 	switch (port->type) {
 	case DDB_TUNER_DVBS_ST:
 		if (demod_attach_stv0900(input, 0) < 0)
@@ -895,7 +895,7 @@
 /****************************************************************************/
 /****************************************************************************/
 
-static ssize_t ts_write(struct file *file, const char *buf,
+static ssize_t ts_write(struct file *file, const __user char *buf,
 			size_t count, loff_t *ppos)
 {
 	struct dvb_device *dvbdev = file->private_data;
@@ -920,7 +920,7 @@
 	return (left == count) ? -EAGAIN : (count - left);
 }
 
-static ssize_t ts_read(struct file *file, char *buf,
+static ssize_t ts_read(struct file *file, __user char *buf,
 		       size_t count, loff_t *ppos)
 {
 	struct dvb_device *dvbdev = file->private_data;
@@ -975,11 +975,9 @@
 	.open    = dvb_generic_open,
 	.release = dvb_generic_release,
 	.poll    = ts_poll,
-	.mmap    = 0,
 };
 
 static struct dvb_device dvbdev_ci = {
-	.priv    = 0,
 	.readers = -1,
 	.writers = -1,
 	.users   = -1,
@@ -1038,7 +1036,7 @@
 }
 
 
-struct cxd2099_cfg cxd_cfg = {
+static struct cxd2099_cfg cxd_cfg = {
 	.bitrate =  62000,
 	.adr     =  0x40,
 	.polarity = 1,
@@ -1127,7 +1125,7 @@
 				ddb_output_stop(port->output);
 				dvb_ca_en50221_release(port->en);
 				kfree(port->en);
-				port->en = 0;
+				port->en = NULL;
 				dvb_unregister_adapter(&port->output->adap);
 			}
 			break;
@@ -1413,9 +1411,9 @@
 #define DDB_MAGIC 'd'
 
 struct ddb_flashio {
-	__u8 *write_buf;
+	__user __u8 *write_buf;
 	__u32 write_len;
-	__u8 *read_buf;
+	__user __u8 *read_buf;
 	__u32 read_len;
 };
 
@@ -1439,7 +1437,7 @@
 static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct ddb *dev = file->private_data;
-	void *parg = (void *)arg;
+	__user void *parg = (__user void *)arg;
 	int res;
 
 	switch (cmd) {
@@ -1562,7 +1560,7 @@
 	ddb_device_destroy(dev);
 
 	ddb_unmap(dev);
-	pci_set_drvdata(pdev, 0);
+	pci_set_drvdata(pdev, NULL);
 	pci_disable_device(pdev);
 }
 
@@ -1641,7 +1639,7 @@
 fail:
 	printk(KERN_ERR "fail\n");
 	ddb_unmap(dev);
-	pci_set_drvdata(pdev, 0);
+	pci_set_drvdata(pdev, NULL);
 	pci_disable_device(pdev);
 	return -1;
 }
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index 8b1b41d..be87fbd 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -156,7 +156,7 @@
 
 struct ddb {
 	struct pci_dev        *pdev;
-	unsigned char         *regs;
+	unsigned char __iomem *regs;
 	struct ddb_port        port[DDB_MAX_PORT];
 	struct ddb_i2c         i2c[DDB_MAX_I2C];
 	struct ddb_input       input[DDB_MAX_INPUT];
@@ -173,12 +173,10 @@
 /****************************************************************************/
 
 #define ddbwritel(_val, _adr)        writel((_val), \
-				     (char *) (dev->regs+(_adr)))
-#define ddbreadl(_adr)               readl((char *) (dev->regs+(_adr)))
-#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *)	\
-				     (dev->regs+(_adr)), (_src), (_count))
-#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \
-				       (dev->regs+(_adr)), (_count))
+				     dev->regs+(_adr))
+#define ddbreadl(_adr)               readl(dev->regs+(_adr))
+#define ddbcpyto(_adr, _src, _count) memcpy_toio(dev->regs+(_adr), (_src), (_count))
+#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), dev->regs+(_adr), (_count))
 
 /****************************************************************************/
 
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index e8826c5..ed11716 100644
--- a/drivers/media/pci/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -614,7 +614,7 @@
 
 static void dm1105_set_dma_addr(struct dm1105_dev *dev)
 {
-	dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr));
+	dm_writel(DM1105_STADR, (__force u32)cpu_to_le32(dev->dma_addr));
 }
 
 static int dm1105_dma_map(struct dm1105_dev *dev)
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
index 7a9b98b..7bf9cbc 100644
--- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
+++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
@@ -81,7 +81,7 @@
 	int period_elapsed = 0;
 	int length;
 
-	dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zd\n", itvsc,
+	dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zu\n", itvsc,
 		pcm_data, num_bytes);
 
 	substream = itvsc->capture_pcm_substream;
diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c
index ed73edd..4b0e758 100644
--- a/drivers/media/pci/ivtv/ivtv-firmware.c
+++ b/drivers/media/pci/ivtv/ivtv-firmware.c
@@ -65,7 +65,7 @@
 			   the wrong file was sometimes loaded. So we check filesizes to
 			   see if at least the right-sized file was loaded. If not, then we
 			   retry. */
-			IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+			IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zu)\n", fn, size, fw->size);
 			release_firmware(fw);
 			retries--;
 			goto retry;
@@ -76,7 +76,7 @@
 			dst++;
 			src++;
 		}
-		IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
+		IVTV_INFO("Loaded %s firmware (%zu bytes)\n", fn, fw->size);
 		release_firmware(fw);
 		return size;
 	}
diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c
index 19a7c9b..ab6d5d2 100644
--- a/drivers/media/pci/ivtv/ivtv-irq.c
+++ b/drivers/media/pci/ivtv/ivtv-irq.c
@@ -192,11 +192,11 @@
 		if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
 		    s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
 			s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET);
-			write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET);
+			write_dec_sync(DMA_MAGIC_COOKIE, offset - IVTV_DECODER_OFFSET);
 		}
 		else {
 			s->pending_backup = read_enc(offset);
-			write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset);
+			write_enc_sync(DMA_MAGIC_COOKIE, offset);
 		}
 		s->pending_offset = offset;
 	}
@@ -275,13 +275,11 @@
 
 		if (x == 0 && ivtv_use_dma(s)) {
 			offset = s->dma_last_offset;
-			if (u32buf[offset / 4] != DMA_MAGIC_COOKIE)
+			if (le32_to_cpu(u32buf[offset / 4]) != DMA_MAGIC_COOKIE)
 			{
-				for (offset = 0; offset < 64; offset++) {
-					if (u32buf[offset] == DMA_MAGIC_COOKIE) {
+				for (offset = 0; offset < 64; offset++)
+					if (le32_to_cpu(u32buf[offset]) == DMA_MAGIC_COOKIE)
 						break;
-					}
-				}
 				offset *= 4;
 				if (offset == 256) {
 					IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name);
diff --git a/drivers/media/pci/mantis/hopper_vp3028.c b/drivers/media/pci/mantis/hopper_vp3028.c
index 68a29f8..1032db6 100644
--- a/drivers/media/pci/mantis/hopper_vp3028.c
+++ b/drivers/media/pci/mantis/hopper_vp3028.c
@@ -34,7 +34,7 @@
 #include "mantis_dvb.h"
 #include "hopper_vp3028.h"
 
-struct zl10353_config hopper_vp3028_config = {
+static struct zl10353_config hopper_vp3028_config = {
 	.demod_address	= 0x0f,
 };
 
diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h
index f2410cf..8ff448b 100644
--- a/drivers/media/pci/mantis/mantis_common.h
+++ b/drivers/media/pci/mantis/mantis_common.h
@@ -127,7 +127,7 @@
 	u32			last_block;
 	u8			*buf_cpu;
 	dma_addr_t		buf_dma;
-	u32			*risc_cpu;
+	__le32			*risc_cpu;
 	dma_addr_t		risc_dma;
 
 	struct tasklet_struct	tasklet;
diff --git a/drivers/media/pci/mantis/mantis_vp1033.c b/drivers/media/pci/mantis/mantis_vp1033.c
index 115003e..12a6adb 100644
--- a/drivers/media/pci/mantis/mantis_vp1033.c
+++ b/drivers/media/pci/mantis/mantis_vp1033.c
@@ -35,7 +35,7 @@
 #include "mantis_vp1033.h"
 #include "mantis_reg.h"
 
-u8 lgtdqcs001f_inittab[] = {
+static u8 lgtdqcs001f_inittab[] = {
 	0x01, 0x15,
 	0x02, 0x30,
 	0x03, 0x00,
@@ -150,7 +150,7 @@
 	return 0;
 }
 
-struct stv0299_config lgtdqcs001f_config = {
+static struct stv0299_config lgtdqcs001f_config = {
 	.demod_address		= 0x68,
 	.inittab		= lgtdqcs001f_inittab,
 	.mclk			= 88000000UL,
diff --git a/drivers/media/pci/mantis/mantis_vp1034.c b/drivers/media/pci/mantis/mantis_vp1034.c
index 430ae84..7c1bd16 100644
--- a/drivers/media/pci/mantis/mantis_vp1034.c
+++ b/drivers/media/pci/mantis/mantis_vp1034.c
@@ -36,7 +36,7 @@
 #include "mantis_vp1034.h"
 #include "mantis_reg.h"
 
-struct mb86a16_config vp1034_mb86a16_config = {
+static struct mb86a16_config vp1034_mb86a16_config = {
 	.demod_address	= 0x08,
 	.set_voltage	= vp1034_set_voltage,
 };
diff --git a/drivers/media/pci/mantis/mantis_vp1041.c b/drivers/media/pci/mantis/mantis_vp1041.c
index 07a2074..7082fcb 100644
--- a/drivers/media/pci/mantis/mantis_vp1041.c
+++ b/drivers/media/pci/mantis/mantis_vp1041.c
@@ -263,7 +263,7 @@
 	{ 0xffff			, 0xff },
 };
 
-struct stb0899_config vp1041_stb0899_config = {
+static struct stb0899_config vp1041_stb0899_config = {
 	.init_dev		= vp1041_stb0899_s1_init_1,
 	.init_s2_demod		= stb0899_s2_init_2,
 	.init_s1_demod		= vp1041_stb0899_s1_init_3,
@@ -300,7 +300,7 @@
 	.tuner_set_rfsiggain	= NULL,
 };
 
-struct stb6100_config vp1041_stb6100_config = {
+static struct stb6100_config vp1041_stb6100_config = {
 	.tuner_address	= 0x60,
 	.refclock	= 27000000,
 };
diff --git a/drivers/media/pci/mantis/mantis_vp2033.c b/drivers/media/pci/mantis/mantis_vp2033.c
index 1ca6837..8d48b5a 100644
--- a/drivers/media/pci/mantis/mantis_vp2033.c
+++ b/drivers/media/pci/mantis/mantis_vp2033.c
@@ -37,12 +37,12 @@
 #define MANTIS_MODEL_NAME	"VP-2033"
 #define MANTIS_DEV_TYPE		"DVB-C"
 
-struct tda1002x_config vp2033_tda1002x_cu1216_config = {
+static struct tda1002x_config vp2033_tda1002x_cu1216_config = {
 	.demod_address = 0x18 >> 1,
 	.invert = 1,
 };
 
-struct tda10023_config vp2033_tda10023_cu1216_config = {
+static struct tda10023_config vp2033_tda10023_cu1216_config = {
 	.demod_address = 0x18 >> 1,
 	.invert = 1,
 };
diff --git a/drivers/media/pci/mantis/mantis_vp2040.c b/drivers/media/pci/mantis/mantis_vp2040.c
index d480741..8dd17d7 100644
--- a/drivers/media/pci/mantis/mantis_vp2040.c
+++ b/drivers/media/pci/mantis/mantis_vp2040.c
@@ -37,12 +37,12 @@
 #define MANTIS_MODEL_NAME	"VP-2040"
 #define MANTIS_DEV_TYPE		"DVB-C"
 
-struct tda1002x_config vp2040_tda1002x_cu1216_config = {
+static struct tda1002x_config vp2040_tda1002x_cu1216_config = {
 	.demod_address	= 0x18 >> 1,
 	.invert		= 1,
 };
 
-struct tda10023_config vp2040_tda10023_cu1216_config = {
+static struct tda10023_config vp2040_tda10023_cu1216_config = {
 	.demod_address	= 0x18 >> 1,
 	.invert		= 1,
 };
diff --git a/drivers/media/pci/mantis/mantis_vp3030.c b/drivers/media/pci/mantis/mantis_vp3030.c
index c09308c..5c1dd92 100644
--- a/drivers/media/pci/mantis/mantis_vp3030.c
+++ b/drivers/media/pci/mantis/mantis_vp3030.c
@@ -35,11 +35,11 @@
 #include "mantis_dvb.h"
 #include "mantis_vp3030.h"
 
-struct zl10353_config mantis_vp3030_config = {
+static struct zl10353_config mantis_vp3030_config = {
 	.demod_address		= 0x0f,
 };
 
-struct tda665x_config env57h12d5_config = {
+static struct tda665x_config env57h12d5_config = {
 	.name			= "ENV57H12D5 (ET-50DT)",
 	.addr			= 0x60,
 	.frequency_min		=  47000000,
diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c
index a7ce7d1..ec33541 100644
--- a/drivers/media/pci/ngene/ngene-cards.c
+++ b/drivers/media/pci/ngene/ngene-cards.c
@@ -696,7 +696,7 @@
 	.demod_attach   = { NULL, demod_attach_lg330x },
 
 	/* Ensure these are NULL else the frame will call them (as funcs) */
-	.tuner_attach   = { 0, 0, 0, 0 },
+	.tuner_attach   = { NULL, NULL, NULL, NULL },
 	.fe_config      = { NULL, &aver_m780 },
 	.avf            = { 0 },
 
diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c
index 4930b55..e29bc3a 100644
--- a/drivers/media/pci/ngene/ngene-core.c
+++ b/drivers/media/pci/ngene/ngene-core.c
@@ -57,15 +57,13 @@
 
 #define dprintk	if (debug) printk
 
-#define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
-#define ngwritel(dat, adr)         writel((dat), (char *)(dev->iomem + (adr)))
-#define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
+#define ngwriteb(dat, adr)         writeb((dat), dev->iomem + (adr))
+#define ngwritel(dat, adr)         writel((dat), dev->iomem + (adr))
+#define ngwriteb(dat, adr)         writeb((dat), dev->iomem + (adr))
 #define ngreadl(adr)               readl(dev->iomem + (adr))
 #define ngreadb(adr)               readb(dev->iomem + (adr))
-#define ngcpyto(adr, src, count)   memcpy_toio((char *) \
-				   (dev->iomem + (adr)), (src), (count))
-#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \
-				   (dev->iomem + (adr)), (count))
+#define ngcpyto(adr, src, count)   memcpy_toio(dev->iomem + (adr), (src), (count))
+#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), dev->iomem + (adr), (count))
 
 /****************************************************************************/
 /* nGene interrupt handler **************************************************/
@@ -1592,7 +1590,7 @@
 
 	dvb_ca_en50221_release(ci->en);
 	kfree(ci->en);
-	ci->en = 0;
+	ci->en = NULL;
 }
 
 /***********************************/
diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c
index fcb16a6..59bb285 100644
--- a/drivers/media/pci/ngene/ngene-dvb.c
+++ b/drivers/media/pci/ngene/ngene-dvb.c
@@ -47,7 +47,7 @@
 /* COMMAND API interface ****************************************************/
 /****************************************************************************/
 
-static ssize_t ts_write(struct file *file, const char *buf,
+static ssize_t ts_write(struct file *file, const char __user *buf,
 			size_t count, loff_t *ppos)
 {
 	struct dvb_device *dvbdev = file->private_data;
@@ -59,12 +59,12 @@
 				     (&dev->tsout_rbuf) >= count) < 0)
 		return 0;
 
-	dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count);
+	dvb_ringbuffer_write_user(&dev->tsout_rbuf, buf, count);
 
 	return count;
 }
 
-static ssize_t ts_read(struct file *file, char *buf,
+static ssize_t ts_read(struct file *file, char __user *buf,
 		       size_t count, loff_t *ppos)
 {
 	struct dvb_device *dvbdev = file->private_data;
@@ -97,7 +97,6 @@
 };
 
 struct dvb_device ngene_dvbdev_ci = {
-	.priv    = 0,
 	.readers = -1,
 	.writers = -1,
 	.users   = -1,
diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h
index 22c39ff..51e2fbd 100644
--- a/drivers/media/pci/ngene/ngene.h
+++ b/drivers/media/pci/ngene/ngene.h
@@ -737,7 +737,7 @@
 struct ngene {
 	int                   nr;
 	struct pci_dev       *pci_dev;
-	unsigned char        *iomem;
+	unsigned char __iomem *iomem;
 
 	/*struct i2c_adapter  i2c_adapter;*/
 
diff --git a/drivers/media/pci/pt3/Kconfig b/drivers/media/pci/pt3/Kconfig
new file mode 100644
index 0000000..f62f306
--- /dev/null
+++ b/drivers/media/pci/pt3/Kconfig
@@ -0,0 +1,12 @@
+config DVB_PT3
+	depends on !BACKPORT_KERNEL_3_3
+	tristate "Earthsoft PT3 cards"
+	depends on m
+	depends on DVB_CORE && PCI && I2C
+	select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT
+	select MEDIA_TUNER_QM1D1C0042 if MEDIA_SUBDRV_AUTOSELECT
+	select MEDIA_TUNER_MXL301RF if MEDIA_SUBDRV_AUTOSELECT
+	help
+	  Support for Earthsoft PT3 PCIe cards.
+
+	  Say Y or M if you own such a device and want to use it.
diff --git a/drivers/media/pci/pt3/Makefile b/drivers/media/pci/pt3/Makefile
new file mode 100644
index 0000000..4c6b58a
--- /dev/null
+++ b/drivers/media/pci/pt3/Makefile
@@ -0,0 +1,8 @@
+
+earth-pt3-objs += pt3.o pt3_i2c.o pt3_dma.o
+
+obj-$(CPTCFG_DVB_PT3) += earth-pt3.o
+
+ccflags-y += -I$(backport_srctree)/drivers/media/dvb-core
+ccflags-y += -I$(backport_srctree)/drivers/media/dvb-frontends
+ccflags-y += -I$(backport_srctree)/drivers/media/tuners
diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c
new file mode 100644
index 0000000..1fdeac1
--- /dev/null
+++ b/drivers/media/pci/pt3/pt3.c
@@ -0,0 +1,876 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * 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/freezer.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
+#include "pt3.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static bool one_adapter;
+module_param(one_adapter, bool, 0444);
+MODULE_PARM_DESC(one_adapter, "Place FE's together under one adapter.");
+
+static int num_bufs = 4;
+module_param(num_bufs, int, 0444);
+MODULE_PARM_DESC(num_bufs, "Number of DMA buffer (188KiB) per FE.");
+
+
+static const struct i2c_algorithm pt3_i2c_algo = {
+	.master_xfer   = &pt3_i2c_master_xfer,
+	.functionality = &pt3_i2c_functionality,
+};
+
+static const struct pt3_adap_config adap_conf[PT3_NUM_FE] = {
+	{
+		.demod_info = {
+			I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x11),
+		},
+		.tuner_info = {
+			I2C_BOARD_INFO("qm1d1c0042", 0x63),
+		},
+		.tuner_cfg.qm1d1c0042 = {
+			.lpf = 1,
+		},
+		.init_freq = 1049480 - 300,
+	},
+	{
+		.demod_info = {
+			I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x10),
+		},
+		.tuner_info = {
+			I2C_BOARD_INFO("mxl301rf", 0x62),
+		},
+		.init_freq = 515142857,
+	},
+	{
+		.demod_info = {
+			I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x13),
+		},
+		.tuner_info = {
+			I2C_BOARD_INFO("qm1d1c0042", 0x60),
+		},
+		.tuner_cfg.qm1d1c0042 = {
+			.lpf = 1,
+		},
+		.init_freq = 1049480 + 300,
+	},
+	{
+		.demod_info = {
+			I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x12),
+		},
+		.tuner_info = {
+			I2C_BOARD_INFO("mxl301rf", 0x61),
+		},
+		.init_freq = 521142857,
+	},
+};
+
+
+struct reg_val {
+	u8 reg;
+	u8 val;
+};
+
+static int
+pt3_demod_write(struct pt3_adapter *adap, const struct reg_val *data, int num)
+{
+	struct i2c_msg msg;
+	int i, ret;
+
+	ret = 0;
+	msg.addr = adap->i2c_demod->addr;
+	msg.flags = 0;
+	msg.len = 2;
+	for (i = 0; i < num; i++) {
+		msg.buf = (u8 *)&data[i];
+		ret = i2c_transfer(adap->i2c_demod->adapter, &msg, 1);
+		if (ret == 0)
+			ret = -EREMOTE;
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static inline void pt3_lnb_ctrl(struct pt3_board *pt3, bool on)
+{
+	iowrite32((on ? 0x0f : 0x0c), pt3->regs[0] + REG_SYSTEM_W);
+}
+
+static inline struct pt3_adapter *pt3_find_adapter(struct dvb_frontend *fe)
+{
+	struct pt3_board *pt3;
+	int i;
+
+	if (one_adapter) {
+		pt3 = fe->dvb->priv;
+		for (i = 0; i < PT3_NUM_FE; i++)
+			if (pt3->adaps[i]->fe == fe)
+				return pt3->adaps[i];
+	}
+	return container_of(fe->dvb, struct pt3_adapter, dvb_adap);
+}
+
+/*
+ * all 4 tuners in PT3 are packaged in a can module (Sharp VA4M6JC2103).
+ * it seems that they share the power lines and Amp power line and
+ * adaps[3] controls those powers.
+ */
+static int
+pt3_set_tuner_power(struct pt3_board *pt3, bool tuner_on, bool amp_on)
+{
+	struct reg_val rv = { 0x1e, 0x99 };
+
+	if (tuner_on)
+		rv.val |= 0x40;
+	if (amp_on)
+		rv.val |= 0x04;
+	return pt3_demod_write(pt3->adaps[PT3_NUM_FE - 1], &rv, 1);
+}
+
+static int pt3_set_lna(struct dvb_frontend *fe)
+{
+	struct pt3_adapter *adap;
+	struct pt3_board *pt3;
+	u32 val;
+	int ret;
+
+	/* LNA is shared btw. 2 TERR-tuners */
+
+	adap = pt3_find_adapter(fe);
+	val = fe->dtv_property_cache.lna;
+	if (val == LNA_AUTO || val == adap->cur_lna)
+		return 0;
+
+	pt3 = adap->dvb_adap.priv;
+	if (mutex_lock_interruptible(&pt3->lock))
+		return -ERESTARTSYS;
+	if (val)
+		pt3->lna_on_cnt++;
+	else
+		pt3->lna_on_cnt--;
+
+	if (val && pt3->lna_on_cnt <= 1) {
+		pt3->lna_on_cnt = 1;
+		ret = pt3_set_tuner_power(pt3, true, true);
+	} else if (!val && pt3->lna_on_cnt <= 0) {
+		pt3->lna_on_cnt = 0;
+		ret = pt3_set_tuner_power(pt3, true, false);
+	} else
+		ret = 0;
+	mutex_unlock(&pt3->lock);
+	adap->cur_lna = (val != 0);
+	return ret;
+}
+
+static int pt3_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+	struct pt3_adapter *adap;
+	struct pt3_board *pt3;
+	bool on;
+
+	/* LNB power is shared btw. 2 SAT-tuners */
+
+	adap = pt3_find_adapter(fe);
+	on = (volt != SEC_VOLTAGE_OFF);
+	if (on == adap->cur_lnb)
+		return 0;
+	adap->cur_lnb = on;
+	pt3 = adap->dvb_adap.priv;
+	if (mutex_lock_interruptible(&pt3->lock))
+		return -ERESTARTSYS;
+	if (on)
+		pt3->lnb_on_cnt++;
+	else
+		pt3->lnb_on_cnt--;
+
+	if (on && pt3->lnb_on_cnt <= 1) {
+		pt3->lnb_on_cnt = 1;
+		pt3_lnb_ctrl(pt3, true);
+	} else if (!on && pt3->lnb_on_cnt <= 0) {
+		pt3->lnb_on_cnt = 0;
+		pt3_lnb_ctrl(pt3, false);
+	}
+	mutex_unlock(&pt3->lock);
+	return 0;
+}
+
+/* register values used in pt3_fe_init() */
+
+static const struct reg_val init0_sat[] = {
+	{ 0x03, 0x01 },
+	{ 0x1e, 0x10 },
+};
+static const struct reg_val init0_ter[] = {
+	{ 0x01, 0x40 },
+	{ 0x1c, 0x10 },
+};
+static const struct reg_val cfg_sat[] = {
+	{ 0x1c, 0x15 },
+	{ 0x1f, 0x04 },
+};
+static const struct reg_val cfg_ter[] = {
+	{ 0x1d, 0x01 },
+};
+
+/*
+ * pt3_fe_init: initialize demod sub modules and ISDB-T tuners all at once.
+ *
+ * As for demod IC (TC90522) and ISDB-T tuners (MxL301RF),
+ * the i2c sequences for init'ing them are not public and hidden in a ROM,
+ * and include the board specific configurations as well.
+ * They are stored in a lump and cannot be taken out / accessed separately,
+ * thus cannot be moved to the FE/tuner driver.
+ */
+static int pt3_fe_init(struct pt3_board *pt3)
+{
+	int i, ret;
+	struct dvb_frontend *fe;
+
+	pt3_i2c_reset(pt3);
+	ret = pt3_init_all_demods(pt3);
+	if (ret < 0) {
+		dev_warn(&pt3->pdev->dev, "Failed to init demod chips.");
+		return ret;
+	}
+
+	/* additional config? */
+	for (i = 0; i < PT3_NUM_FE; i++) {
+		fe = pt3->adaps[i]->fe;
+
+		if (fe->ops.delsys[0] == SYS_ISDBS)
+			ret = pt3_demod_write(pt3->adaps[i],
+					      init0_sat, ARRAY_SIZE(init0_sat));
+		else
+			ret = pt3_demod_write(pt3->adaps[i],
+					      init0_ter, ARRAY_SIZE(init0_ter));
+		if (ret < 0) {
+			dev_warn(&pt3->pdev->dev,
+				 "demod[%d] faild in init sequence0.", i);
+			return ret;
+		}
+		ret = fe->ops.init(fe);
+		if (ret < 0)
+			return ret;
+	}
+
+	usleep_range(2000, 4000);
+	ret = pt3_set_tuner_power(pt3, true, false);
+	if (ret < 0) {
+		dev_warn(&pt3->pdev->dev, "Failed to control tuner module.");
+		return ret;
+	}
+
+	/* output pin configuration */
+	for (i = 0; i < PT3_NUM_FE; i++) {
+		fe = pt3->adaps[i]->fe;
+		if (fe->ops.delsys[0] == SYS_ISDBS)
+			ret = pt3_demod_write(pt3->adaps[i],
+						cfg_sat, ARRAY_SIZE(cfg_sat));
+		else
+			ret = pt3_demod_write(pt3->adaps[i],
+						cfg_ter, ARRAY_SIZE(cfg_ter));
+		if (ret < 0) {
+			dev_warn(&pt3->pdev->dev,
+				 "demod[%d] faild in init sequence1.", i);
+			return ret;
+		}
+	}
+	usleep_range(4000, 6000);
+
+	for (i = 0; i < PT3_NUM_FE; i++) {
+		fe = pt3->adaps[i]->fe;
+		if (fe->ops.delsys[0] != SYS_ISDBS)
+			continue;
+		/* init and wake-up ISDB-S tuners */
+		ret = fe->ops.tuner_ops.init(fe);
+		if (ret < 0) {
+			dev_warn(&pt3->pdev->dev,
+				 "Failed to init SAT-tuner[%d].", i);
+			return ret;
+		}
+	}
+	ret = pt3_init_all_mxl301rf(pt3);
+	if (ret < 0) {
+		dev_warn(&pt3->pdev->dev, "Failed to init TERR-tuners.");
+		return ret;
+	}
+
+	ret = pt3_set_tuner_power(pt3, true, true);
+	if (ret < 0) {
+		dev_warn(&pt3->pdev->dev, "Failed to control tuner module.");
+		return ret;
+	}
+
+	/* Wake up all tuners and make an initial tuning,
+	 * in order to avoid interference among the tuners in the module,
+	 * according to the doc from the manufacturer.
+	 */
+	for (i = 0; i < PT3_NUM_FE; i++) {
+		fe = pt3->adaps[i]->fe;
+		ret = 0;
+		if (fe->ops.delsys[0] == SYS_ISDBT)
+			ret = fe->ops.tuner_ops.init(fe);
+		/* set only when called from pt3_probe(), not resume() */
+		if (ret == 0 && fe->dtv_property_cache.frequency == 0) {
+			fe->dtv_property_cache.frequency =
+						adap_conf[i].init_freq;
+			ret = fe->ops.tuner_ops.set_params(fe);
+		}
+		if (ret < 0) {
+			dev_warn(&pt3->pdev->dev,
+				 "Failed in initial tuning of tuner[%d].", i);
+			return ret;
+		}
+	}
+
+	/* and sleep again, waiting to be opened by users. */
+	for (i = 0; i < PT3_NUM_FE; i++) {
+		fe = pt3->adaps[i]->fe;
+		if (fe->ops.tuner_ops.sleep)
+			ret = fe->ops.tuner_ops.sleep(fe);
+		if (ret < 0)
+			break;
+		if (fe->ops.sleep)
+			ret = fe->ops.sleep(fe);
+		if (ret < 0)
+			break;
+		if (fe->ops.delsys[0] == SYS_ISDBS)
+			fe->ops.set_voltage = &pt3_set_voltage;
+		else
+			fe->ops.set_lna = &pt3_set_lna;
+	}
+	if (i < PT3_NUM_FE) {
+		dev_warn(&pt3->pdev->dev, "FE[%d] failed to standby.", i);
+		return ret;
+	}
+	return 0;
+}
+
+
+static int pt3_attach_fe(struct pt3_board *pt3, int i)
+{
+	struct i2c_board_info info;
+	struct tc90522_config cfg;
+	struct i2c_client *cl;
+	struct dvb_adapter *dvb_adap;
+	int ret;
+
+	info = adap_conf[i].demod_info;
+	cfg = adap_conf[i].demod_cfg;
+	cfg.tuner_i2c = NULL;
+	info.platform_data = &cfg;
+
+	ret = -ENODEV;
+	request_module("tc90522");
+	cl = i2c_new_device(&pt3->i2c_adap, &info);
+	if (!cl || !cl->dev.driver)
+		return -ENODEV;
+	pt3->adaps[i]->i2c_demod = cl;
+	if (!try_module_get(cl->dev.driver->owner))
+		goto err_demod_i2c_unregister_device;
+
+	if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, sizeof(cl->name))) {
+		struct qm1d1c0042_config tcfg;
+
+		tcfg = adap_conf[i].tuner_cfg.qm1d1c0042;
+		tcfg.fe = cfg.fe;
+		info = adap_conf[i].tuner_info;
+		info.platform_data = &tcfg;
+		request_module("qm1d1c0042");
+		cl = i2c_new_device(cfg.tuner_i2c, &info);
+	} else {
+		struct mxl301rf_config tcfg;
+
+		tcfg = adap_conf[i].tuner_cfg.mxl301rf;
+		tcfg.fe = cfg.fe;
+		info = adap_conf[i].tuner_info;
+		info.platform_data = &tcfg;
+		request_module("mxl301rf");
+		cl = i2c_new_device(cfg.tuner_i2c, &info);
+	}
+	if (!cl || !cl->dev.driver)
+		goto err_demod_module_put;
+	pt3->adaps[i]->i2c_tuner = cl;
+	if (!try_module_get(cl->dev.driver->owner))
+		goto err_tuner_i2c_unregister_device;
+
+	dvb_adap = &pt3->adaps[one_adapter ? 0 : i]->dvb_adap;
+	ret = dvb_register_frontend(dvb_adap, cfg.fe);
+	if (ret < 0)
+		goto err_tuner_module_put;
+	pt3->adaps[i]->fe = cfg.fe;
+	return 0;
+
+err_tuner_module_put:
+	module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner);
+err_tuner_i2c_unregister_device:
+	i2c_unregister_device(pt3->adaps[i]->i2c_tuner);
+err_demod_module_put:
+	module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner);
+err_demod_i2c_unregister_device:
+	i2c_unregister_device(pt3->adaps[i]->i2c_demod);
+
+	return ret;
+}
+
+
+static int pt3_fetch_thread(void *data)
+{
+	struct pt3_adapter *adap = data;
+	ktime_t delay;
+	bool was_frozen;
+
+#define PT3_INITIAL_BUF_DROPS 4
+#define PT3_FETCH_DELAY 10
+#define PT3_FETCH_DELAY_DELTA 2
+
+	pt3_init_dmabuf(adap);
+	adap->num_discard = PT3_INITIAL_BUF_DROPS;
+
+	dev_dbg(adap->dvb_adap.device,
+		"PT3: [%s] started.\n", adap->thread->comm);
+	set_freezable();
+	while (!kthread_freezable_should_stop(&was_frozen)) {
+		if (was_frozen)
+			adap->num_discard = PT3_INITIAL_BUF_DROPS;
+
+		pt3_proc_dma(adap);
+
+		delay = ktime_set(0, PT3_FETCH_DELAY * NSEC_PER_MSEC);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		freezable_schedule_hrtimeout_range(&delay,
+					PT3_FETCH_DELAY_DELTA * NSEC_PER_MSEC,
+					HRTIMER_MODE_REL);
+	}
+	dev_dbg(adap->dvb_adap.device,
+		"PT3: [%s] exited.\n", adap->thread->comm);
+	adap->thread = NULL;
+	return 0;
+}
+
+static int pt3_start_streaming(struct pt3_adapter *adap)
+{
+	struct task_struct *thread;
+
+	/* start fetching thread */
+	thread = kthread_run(pt3_fetch_thread, adap, "pt3-ad%i-dmx%i",
+				adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+	if (IS_ERR(thread)) {
+		int ret = PTR_ERR(thread);
+
+		dev_warn(adap->dvb_adap.device,
+			"PT3 (adap:%d, dmx:%d): failed to start kthread.\n",
+			adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+		return ret;
+	}
+	adap->thread = thread;
+
+	return pt3_start_dma(adap);
+}
+
+static int pt3_stop_streaming(struct pt3_adapter *adap)
+{
+	int ret;
+
+	ret = pt3_stop_dma(adap);
+	if (ret)
+		dev_warn(adap->dvb_adap.device,
+			"PT3: failed to stop streaming of adap:%d/FE:%d\n",
+			adap->dvb_adap.num, adap->fe->id);
+
+	/* kill the fetching thread */
+	ret = kthread_stop(adap->thread);
+	return ret;
+}
+
+static int pt3_start_feed(struct dvb_demux_feed *feed)
+{
+	struct pt3_adapter *adap;
+
+	if (signal_pending(current))
+		return -EINTR;
+
+	adap = container_of(feed->demux, struct pt3_adapter, demux);
+	adap->num_feeds++;
+	if (adap->thread)
+		return 0;
+	if (adap->num_feeds != 1) {
+		dev_warn(adap->dvb_adap.device,
+			"%s: unmatched start/stop_feed in adap:%i/dmx:%i.\n",
+			__func__, adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+		adap->num_feeds = 1;
+	}
+
+	return pt3_start_streaming(adap);
+
+}
+
+static int pt3_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct pt3_adapter *adap;
+
+	adap = container_of(feed->demux, struct pt3_adapter, demux);
+
+	adap->num_feeds--;
+	if (adap->num_feeds > 0 || !adap->thread)
+		return 0;
+	adap->num_feeds = 0;
+
+	return pt3_stop_streaming(adap);
+}
+
+
+static int pt3_alloc_adapter(struct pt3_board *pt3, int index)
+{
+	int ret;
+	struct pt3_adapter *adap;
+	struct dvb_adapter *da;
+
+	adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+	if (!adap) {
+		dev_err(&pt3->pdev->dev, "failed to alloc mem for adapter.\n");
+		return -ENOMEM;
+	}
+	pt3->adaps[index] = adap;
+	adap->adap_idx = index;
+
+	if (index == 0 || !one_adapter) {
+		ret = dvb_register_adapter(&adap->dvb_adap, "PT3 DVB",
+				THIS_MODULE, &pt3->pdev->dev, adapter_nr);
+		if (ret < 0) {
+			dev_err(&pt3->pdev->dev,
+				"failed to register adapter dev.\n");
+			goto err_mem;
+		}
+		da = &adap->dvb_adap;
+	} else
+		da = &pt3->adaps[0]->dvb_adap;
+
+	adap->dvb_adap.priv = pt3;
+	adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+	adap->demux.priv = adap;
+	adap->demux.feednum = 256;
+	adap->demux.filternum = 256;
+	adap->demux.start_feed = pt3_start_feed;
+	adap->demux.stop_feed = pt3_stop_feed;
+	ret = dvb_dmx_init(&adap->demux);
+	if (ret < 0) {
+		dev_err(&pt3->pdev->dev, "failed to init dmx dev.\n");
+		goto err_adap;
+	}
+
+	adap->dmxdev.filternum = 256;
+	adap->dmxdev.demux = &adap->demux.dmx;
+	ret = dvb_dmxdev_init(&adap->dmxdev, da);
+	if (ret < 0) {
+		dev_err(&pt3->pdev->dev, "failed to init dmxdev.\n");
+		goto err_demux;
+	}
+
+	ret = pt3_alloc_dmabuf(adap);
+	if (ret) {
+		dev_err(&pt3->pdev->dev, "failed to alloc DMA buffers.\n");
+		goto err_dmabuf;
+	}
+
+	return 0;
+
+err_dmabuf:
+	pt3_free_dmabuf(adap);
+	dvb_dmxdev_release(&adap->dmxdev);
+err_demux:
+	dvb_dmx_release(&adap->demux);
+err_adap:
+	if (index == 0 || !one_adapter)
+		dvb_unregister_adapter(da);
+err_mem:
+	kfree(adap);
+	pt3->adaps[index] = NULL;
+	return ret;
+}
+
+static void pt3_cleanup_adapter(struct pt3_board *pt3, int index)
+{
+	struct pt3_adapter *adap;
+	struct dmx_demux *dmx;
+
+	adap = pt3->adaps[index];
+	if (adap == NULL)
+		return;
+
+	/* stop demux kthread */
+	if (adap->thread)
+		pt3_stop_streaming(adap);
+
+	dmx = &adap->demux.dmx;
+	dmx->close(dmx);
+	if (adap->fe) {
+		adap->fe->callback = NULL;
+		if (adap->fe->frontend_priv)
+			dvb_unregister_frontend(adap->fe);
+		if (adap->i2c_tuner) {
+			module_put(adap->i2c_tuner->dev.driver->owner);
+			i2c_unregister_device(adap->i2c_tuner);
+		}
+		if (adap->i2c_demod) {
+			module_put(adap->i2c_demod->dev.driver->owner);
+			i2c_unregister_device(adap->i2c_demod);
+		}
+	}
+	pt3_free_dmabuf(adap);
+	dvb_dmxdev_release(&adap->dmxdev);
+	dvb_dmx_release(&adap->demux);
+	if (index == 0 || !one_adapter)
+		dvb_unregister_adapter(&adap->dvb_adap);
+	kfree(adap);
+	pt3->adaps[index] = NULL;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int pt3_suspend(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct pt3_board *pt3 = pci_get_drvdata(pdev);
+	int i;
+	struct pt3_adapter *adap;
+
+	for (i = 0; i < PT3_NUM_FE; i++) {
+		adap = pt3->adaps[i];
+		if (adap->num_feeds > 0)
+			pt3_stop_dma(adap);
+		dvb_frontend_suspend(adap->fe);
+		pt3_free_dmabuf(adap);
+	}
+
+	pt3_lnb_ctrl(pt3, false);
+	pt3_set_tuner_power(pt3, false, false);
+	return 0;
+}
+
+static int pt3_resume(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct pt3_board *pt3 = pci_get_drvdata(pdev);
+	int i, ret;
+	struct pt3_adapter *adap;
+
+	ret = pt3_fe_init(pt3);
+	if (ret)
+		return ret;
+
+	if (pt3->lna_on_cnt > 0)
+		pt3_set_tuner_power(pt3, true, true);
+	if (pt3->lnb_on_cnt > 0)
+		pt3_lnb_ctrl(pt3, true);
+
+	for (i = 0; i < PT3_NUM_FE; i++) {
+		adap = pt3->adaps[i];
+		dvb_frontend_resume(adap->fe);
+		ret = pt3_alloc_dmabuf(adap);
+		if (ret) {
+			dev_err(&pt3->pdev->dev, "failed to alloc DMA bufs.\n");
+			continue;
+		}
+		if (adap->num_feeds > 0)
+			pt3_start_dma(adap);
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
+
+static void pt3_remove(struct pci_dev *pdev)
+{
+	struct pt3_board *pt3;
+	int i;
+
+	pt3 = pci_get_drvdata(pdev);
+	for (i = PT3_NUM_FE - 1; i >= 0; i--)
+		pt3_cleanup_adapter(pt3, i);
+	i2c_del_adapter(&pt3->i2c_adap);
+	kfree(pt3->i2c_buf);
+	pci_iounmap(pt3->pdev, pt3->regs[0]);
+	pci_iounmap(pt3->pdev, pt3->regs[1]);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	kfree(pt3);
+}
+
+static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	u8 rev;
+	u32 ver;
+	int i, ret;
+	struct pt3_board *pt3;
+	struct i2c_adapter *i2c;
+
+	if (pci_read_config_byte(pdev, PCI_REVISION_ID, &rev) || rev != 1)
+		return -ENODEV;
+
+	ret = pci_enable_device(pdev);
+	if (ret < 0)
+		return -ENODEV;
+	pci_set_master(pdev);
+
+	ret = pci_request_regions(pdev, DRV_NAME);
+	if (ret < 0)
+		goto err_disable_device;
+
+	ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+	if (ret == 0)
+		dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+	else {
+		ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+		if (ret == 0)
+			dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+		else {
+			dev_err(&pdev->dev, "Failed to set DMA mask.\n");
+			goto err_release_regions;
+		}
+		dev_info(&pdev->dev, "Use 32bit DMA.\n");
+	}
+
+	pt3 = kzalloc(sizeof(*pt3), GFP_KERNEL);
+	if (!pt3) {
+		dev_err(&pdev->dev, "Failed to alloc mem for this dev.\n");
+		ret = -ENOMEM;
+		goto err_release_regions;
+	}
+	pci_set_drvdata(pdev, pt3);
+	pt3->pdev = pdev;
+	mutex_init(&pt3->lock);
+	pt3->regs[0] = pci_ioremap_bar(pdev, 0);
+	pt3->regs[1] = pci_ioremap_bar(pdev, 2);
+	if (pt3->regs[0] == NULL || pt3->regs[1] == NULL) {
+		dev_err(&pdev->dev, "Failed to ioremap.\n");
+		ret = -ENOMEM;
+		goto err_kfree;
+	}
+
+	ver = ioread32(pt3->regs[0] + REG_VERSION);
+	if ((ver >> 16) != 0x0301) {
+		dev_warn(&pdev->dev, "PT%d, I/F-ver.:%d not supported",
+			ver >> 24, (ver & 0x00ff0000) >> 16);
+		ret = -ENODEV;
+		goto err_iounmap;
+	}
+
+	pt3->num_bufs = clamp_val(num_bufs, MIN_DATA_BUFS, MAX_DATA_BUFS);
+
+	pt3->i2c_buf = kmalloc(sizeof(*pt3->i2c_buf), GFP_KERNEL);
+	if (pt3->i2c_buf == NULL) {
+		dev_err(&pdev->dev, "Failed to alloc mem for i2c.\n");
+		ret = -ENOMEM;
+		goto err_iounmap;
+	}
+	i2c = &pt3->i2c_adap;
+	i2c->owner = THIS_MODULE;
+	i2c->algo = &pt3_i2c_algo;
+	i2c->algo_data = NULL;
+	i2c->dev.parent = &pdev->dev;
+	strlcpy(i2c->name, DRV_NAME, sizeof(i2c->name));
+	i2c_set_adapdata(i2c, pt3);
+	ret = i2c_add_adapter(i2c);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to add i2c adapter.\n");
+		goto err_i2cbuf;
+	}
+
+	for (i = 0; i < PT3_NUM_FE; i++) {
+		ret = pt3_alloc_adapter(pt3, i);
+		if (ret < 0)
+			break;
+
+		ret = pt3_attach_fe(pt3, i);
+		if (ret < 0)
+			break;
+	}
+	if (i < PT3_NUM_FE) {
+		dev_err(&pdev->dev, "Failed to create FE%d.\n", i);
+		goto err_cleanup_adapters;
+	}
+
+	ret = pt3_fe_init(pt3);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to init frontends.\n");
+		i = PT3_NUM_FE - 1;
+		goto err_cleanup_adapters;
+	}
+
+	dev_info(&pdev->dev,
+		"successfully init'ed PT%d (fw:0x%02x, I/F:0x%02x).\n",
+		ver >> 24, (ver >> 8) & 0xff, (ver >> 16) & 0xff);
+	return 0;
+
+err_cleanup_adapters:
+	while (i >= 0)
+		pt3_cleanup_adapter(pt3, i--);
+	i2c_del_adapter(i2c);
+err_i2cbuf:
+	kfree(pt3->i2c_buf);
+err_iounmap:
+	if (pt3->regs[0])
+		pci_iounmap(pdev, pt3->regs[0]);
+	if (pt3->regs[1])
+		pci_iounmap(pdev, pt3->regs[1]);
+err_kfree:
+	kfree(pt3);
+err_release_regions:
+	pci_release_regions(pdev);
+err_disable_device:
+	pci_disable_device(pdev);
+	return ret;
+
+}
+
+static const struct pci_device_id pt3_id_table[] = {
+	{ PCI_DEVICE_SUB(0x1172, 0x4c15, 0xee8d, 0x0368) },
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, pt3_id_table);
+
+static SIMPLE_DEV_PM_OPS(pt3_pm_ops, pt3_suspend, pt3_resume);
+
+static struct pci_driver pt3_driver = {
+	.name		= DRV_NAME,
+	.probe		= pt3_probe,
+	.remove		= pt3_remove,
+	.id_table	= pt3_id_table,
+
+	.driver.pm	= &pt3_pm_ops,
+};
+
+module_pci_driver(pt3_driver);
+
+MODULE_DESCRIPTION("Earthsoft PT3 Driver");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/pt3/pt3.h b/drivers/media/pci/pt3/pt3.h
new file mode 100644
index 0000000..1b3f2ad
--- /dev/null
+++ b/drivers/media/pci/pt3/pt3.h
@@ -0,0 +1,186 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * 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.
+ */
+
+#ifndef PT3_H
+#define PT3_H
+
+#include <linux/atomic.h>
+#include <linux/types.h>
+
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dmxdev.h"
+
+#include "tc90522.h"
+#include "mxl301rf.h"
+#include "qm1d1c0042.h"
+
+#define DRV_NAME KBUILD_MODNAME
+
+#define PT3_NUM_FE 4
+
+/*
+ * register index of the FPGA chip
+ */
+#define REG_VERSION	0x00
+#define REG_BUS		0x04
+#define REG_SYSTEM_W	0x08
+#define REG_SYSTEM_R	0x0c
+#define REG_I2C_W	0x10
+#define REG_I2C_R	0x14
+#define REG_RAM_W	0x18
+#define REG_RAM_R	0x1c
+#define REG_DMA_BASE	0x40	/* regs for FE[i] = REG_DMA_BASE + 0x18 * i */
+#define OFST_DMA_DESC_L	0x00
+#define OFST_DMA_DESC_H	0x04
+#define OFST_DMA_CTL	0x08
+#define OFST_TS_CTL	0x0c
+#define OFST_STATUS	0x10
+#define OFST_TS_ERR	0x14
+
+/*
+ * internal buffer for I2C
+ */
+#define PT3_I2C_MAX 4091
+struct pt3_i2cbuf {
+	u8  data[PT3_I2C_MAX];
+	u8  tmp;
+	u32 num_cmds;
+};
+
+/*
+ * DMA things
+ */
+#define TS_PACKET_SZ  188
+/* DMA transfers must not cross 4GiB, so use one page / transfer */
+#define DATA_XFER_SZ   4096
+#define DATA_BUF_XFERS 47
+/* (num_bufs * DATA_BUF_SZ) % TS_PACKET_SZ must be 0 */
+#define DATA_BUF_SZ    (DATA_BUF_XFERS * DATA_XFER_SZ)
+#define MAX_DATA_BUFS  16
+#define MIN_DATA_BUFS   2
+
+#define DESCS_IN_PAGE (PAGE_SIZE / sizeof(struct xfer_desc))
+#define MAX_NUM_XFERS (MAX_DATA_BUFS * DATA_BUF_XFERS)
+#define MAX_DESC_BUFS DIV_ROUND_UP(MAX_NUM_XFERS, DESCS_IN_PAGE)
+
+/* DMA transfer description.
+ * device is passed a pointer to this struct, dma-reads it,
+ * and gets the DMA buffer ring for storing TS data.
+ */
+struct xfer_desc {
+	u32 addr_l; /* bus address of target data buffer */
+	u32 addr_h;
+	u32 size;
+	u32 next_l; /* bus adddress of the next xfer_desc */
+	u32 next_h;
+};
+
+/* A DMA mapping of a page containing xfer_desc's */
+struct xfer_desc_buffer {
+	dma_addr_t b_addr;
+	struct xfer_desc *descs; /* PAGE_SIZE (xfer_desc[DESCS_IN_PAGE]) */
+};
+
+/* A DMA mapping of a data buffer */
+struct dma_data_buffer {
+	dma_addr_t b_addr;
+	u8 *data; /* size: u8[PAGE_SIZE] */
+};
+
+/*
+ * device things
+ */
+struct pt3_adap_config {
+	struct i2c_board_info demod_info;
+	struct tc90522_config demod_cfg;
+
+	struct i2c_board_info tuner_info;
+	union tuner_config {
+		struct qm1d1c0042_config qm1d1c0042;
+		struct mxl301rf_config   mxl301rf;
+	} tuner_cfg;
+	u32 init_freq;
+};
+
+struct pt3_adapter {
+	struct dvb_adapter  dvb_adap;  /* dvb_adap.priv => struct pt3_board */
+	int adap_idx;
+
+	struct dvb_demux    demux;
+	struct dmxdev       dmxdev;
+	struct dvb_frontend *fe;
+	struct i2c_client   *i2c_demod;
+	struct i2c_client   *i2c_tuner;
+
+	/* data fetch thread */
+	struct task_struct *thread;
+	int num_feeds;
+
+	bool cur_lna;
+	bool cur_lnb; /* current LNB power status (on/off) */
+
+	/* items below are for DMA */
+	struct dma_data_buffer buffer[MAX_DATA_BUFS];
+	int buf_idx;
+	int buf_ofs;
+	int num_bufs;  /* == pt3_board->num_bufs */
+	int num_discard; /* how many access units to discard initially */
+
+	struct xfer_desc_buffer desc_buf[MAX_DESC_BUFS];
+	int num_desc_bufs;  /* == num_bufs * DATA_BUF_XFERS / DESCS_IN_PAGE */
+};
+
+
+struct pt3_board {
+	struct pci_dev *pdev;
+	void __iomem *regs[2];
+	/* regs[0]: registers, regs[1]: internal memory, used for I2C */
+
+	struct mutex lock;
+
+	/* LNB power shared among sat-FEs */
+	int lnb_on_cnt; /* LNB power on count */
+
+	/* LNA shared among terr-FEs */
+	int lna_on_cnt; /* booster enabled count */
+
+	int num_bufs;  /* number of DMA buffers allocated/mapped per FE */
+
+	struct i2c_adapter i2c_adap;
+	struct pt3_i2cbuf *i2c_buf;
+
+	struct pt3_adapter *adaps[PT3_NUM_FE];
+};
+
+
+/*
+ * prototypes
+ */
+extern int  pt3_alloc_dmabuf(struct pt3_adapter *adap);
+extern void pt3_init_dmabuf(struct pt3_adapter *adap);
+extern void pt3_free_dmabuf(struct pt3_adapter *adap);
+extern int  pt3_start_dma(struct pt3_adapter *adap);
+extern int  pt3_stop_dma(struct pt3_adapter *adap);
+extern int  pt3_proc_dma(struct pt3_adapter *adap);
+
+extern int  pt3_i2c_master_xfer(struct i2c_adapter *adap,
+				struct i2c_msg *msgs, int num);
+extern u32  pt3_i2c_functionality(struct i2c_adapter *adap);
+extern void pt3_i2c_reset(struct pt3_board *pt3);
+extern int  pt3_init_all_demods(struct pt3_board *pt3);
+extern int  pt3_init_all_mxl301rf(struct pt3_board *pt3);
+#endif /* PT3_H */
diff --git a/drivers/media/pci/pt3/pt3_dma.c b/drivers/media/pci/pt3/pt3_dma.c
new file mode 100644
index 0000000..f0ce904
--- /dev/null
+++ b/drivers/media/pci/pt3/pt3_dma.c
@@ -0,0 +1,225 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * 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/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include "pt3.h"
+
+#define PT3_ACCESS_UNIT (TS_PACKET_SZ * 128)
+#define PT3_BUF_CANARY  (0x74)
+
+static u32 get_dma_base(int idx)
+{
+	int i;
+
+	i = (idx == 1 || idx == 2) ? 3 - idx : idx;
+	return REG_DMA_BASE + 0x18 * i;
+}
+
+int pt3_stop_dma(struct pt3_adapter *adap)
+{
+	struct pt3_board *pt3 = adap->dvb_adap.priv;
+	u32 base;
+	u32 stat;
+	int retry;
+
+	base = get_dma_base(adap->adap_idx);
+	stat = ioread32(pt3->regs[0] + base + OFST_STATUS);
+	if (!(stat & 0x01))
+		return 0;
+
+	iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL);
+	for (retry = 0; retry < 5; retry++) {
+		stat = ioread32(pt3->regs[0] + base + OFST_STATUS);
+		if (!(stat & 0x01))
+			return 0;
+		msleep(50);
+	}
+	return -EIO;
+}
+
+int pt3_start_dma(struct pt3_adapter *adap)
+{
+	struct pt3_board *pt3 = adap->dvb_adap.priv;
+	u32 base = get_dma_base(adap->adap_idx);
+
+	iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL);
+	iowrite32(lower_32_bits(adap->desc_buf[0].b_addr),
+			pt3->regs[0] + base + OFST_DMA_DESC_L);
+	iowrite32(upper_32_bits(adap->desc_buf[0].b_addr),
+			pt3->regs[0] + base + OFST_DMA_DESC_H);
+	iowrite32(0x01, pt3->regs[0] + base + OFST_DMA_CTL);
+	return 0;
+}
+
+
+static u8 *next_unit(struct pt3_adapter *adap, int *idx, int *ofs)
+{
+	*ofs += PT3_ACCESS_UNIT;
+	if (*ofs >= DATA_BUF_SZ) {
+		*ofs -= DATA_BUF_SZ;
+		(*idx)++;
+		if (*idx == adap->num_bufs)
+			*idx = 0;
+	}
+	return &adap->buffer[*idx].data[*ofs];
+}
+
+int pt3_proc_dma(struct pt3_adapter *adap)
+{
+	int idx, ofs;
+
+	idx = adap->buf_idx;
+	ofs = adap->buf_ofs;
+
+	if (adap->buffer[idx].data[ofs] == PT3_BUF_CANARY)
+		return 0;
+
+	while (*next_unit(adap, &idx, &ofs) != PT3_BUF_CANARY) {
+		u8 *p;
+
+		p = &adap->buffer[adap->buf_idx].data[adap->buf_ofs];
+		if (adap->num_discard > 0)
+			adap->num_discard--;
+		else if (adap->buf_ofs + PT3_ACCESS_UNIT > DATA_BUF_SZ) {
+			dvb_dmx_swfilter_packets(&adap->demux, p,
+				(DATA_BUF_SZ - adap->buf_ofs) / TS_PACKET_SZ);
+			dvb_dmx_swfilter_packets(&adap->demux,
+				adap->buffer[idx].data, ofs / TS_PACKET_SZ);
+		} else
+			dvb_dmx_swfilter_packets(&adap->demux, p,
+				PT3_ACCESS_UNIT / TS_PACKET_SZ);
+
+		*p = PT3_BUF_CANARY;
+		adap->buf_idx = idx;
+		adap->buf_ofs = ofs;
+	}
+	return 0;
+}
+
+void pt3_init_dmabuf(struct pt3_adapter *adap)
+{
+	int idx, ofs;
+	u8 *p;
+
+	idx = 0;
+	ofs = 0;
+	p = adap->buffer[0].data;
+	/* mark the whole buffers as "not written yet" */
+	while (idx < adap->num_bufs) {
+		p[ofs] = PT3_BUF_CANARY;
+		ofs += PT3_ACCESS_UNIT;
+		if (ofs >= DATA_BUF_SZ) {
+			ofs -= DATA_BUF_SZ;
+			idx++;
+			p = adap->buffer[idx].data;
+		}
+	}
+	adap->buf_idx = 0;
+	adap->buf_ofs = 0;
+}
+
+void pt3_free_dmabuf(struct pt3_adapter *adap)
+{
+	struct pt3_board *pt3;
+	int i;
+
+	pt3 = adap->dvb_adap.priv;
+	for (i = 0; i < adap->num_bufs; i++)
+		dma_free_coherent(&pt3->pdev->dev, DATA_BUF_SZ,
+			adap->buffer[i].data, adap->buffer[i].b_addr);
+	adap->num_bufs = 0;
+
+	for (i = 0; i < adap->num_desc_bufs; i++)
+		dma_free_coherent(&pt3->pdev->dev, PAGE_SIZE,
+			adap->desc_buf[i].descs, adap->desc_buf[i].b_addr);
+	adap->num_desc_bufs = 0;
+}
+
+
+int pt3_alloc_dmabuf(struct pt3_adapter *adap)
+{
+	struct pt3_board *pt3;
+	void *p;
+	int i, j;
+	int idx, ofs;
+	int num_desc_bufs;
+	dma_addr_t data_addr, desc_addr;
+	struct xfer_desc *d;
+
+	pt3 = adap->dvb_adap.priv;
+	adap->num_bufs = 0;
+	adap->num_desc_bufs = 0;
+	for (i = 0; i < pt3->num_bufs; i++) {
+		p = dma_alloc_coherent(&pt3->pdev->dev, DATA_BUF_SZ,
+					&adap->buffer[i].b_addr, GFP_KERNEL);
+		if (p == NULL)
+			goto failed;
+		adap->buffer[i].data = p;
+		adap->num_bufs++;
+	}
+	pt3_init_dmabuf(adap);
+
+	/* build circular-linked pointers (xfer_desc) to the data buffers*/
+	idx = 0;
+	ofs = 0;
+	num_desc_bufs =
+		DIV_ROUND_UP(adap->num_bufs * DATA_BUF_XFERS, DESCS_IN_PAGE);
+	for (i = 0; i < num_desc_bufs; i++) {
+		p = dma_alloc_coherent(&pt3->pdev->dev, PAGE_SIZE,
+					&desc_addr, GFP_KERNEL);
+		if (p == NULL)
+			goto failed;
+		adap->num_desc_bufs++;
+		adap->desc_buf[i].descs = p;
+		adap->desc_buf[i].b_addr = desc_addr;
+
+		if (i > 0) {
+			d = &adap->desc_buf[i - 1].descs[DESCS_IN_PAGE - 1];
+			d->next_l = lower_32_bits(desc_addr);
+			d->next_h = upper_32_bits(desc_addr);
+		}
+		for (j = 0; j < DESCS_IN_PAGE; j++) {
+			data_addr = adap->buffer[idx].b_addr + ofs;
+			d = &adap->desc_buf[i].descs[j];
+			d->addr_l = lower_32_bits(data_addr);
+			d->addr_h = upper_32_bits(data_addr);
+			d->size = DATA_XFER_SZ;
+
+			desc_addr += sizeof(struct xfer_desc);
+			d->next_l = lower_32_bits(desc_addr);
+			d->next_h = upper_32_bits(desc_addr);
+
+			ofs += DATA_XFER_SZ;
+			if (ofs >= DATA_BUF_SZ) {
+				ofs -= DATA_BUF_SZ;
+				idx++;
+				if (idx >= adap->num_bufs) {
+					desc_addr = adap->desc_buf[0].b_addr;
+					d->next_l = lower_32_bits(desc_addr);
+					d->next_h = upper_32_bits(desc_addr);
+					return 0;
+				}
+			}
+		}
+	}
+	return 0;
+
+failed:
+	pt3_free_dmabuf(adap);
+	return -ENOMEM;
+}
diff --git a/drivers/media/pci/pt3/pt3_i2c.c b/drivers/media/pci/pt3/pt3_i2c.c
new file mode 100644
index 0000000..ec6a8a2
--- /dev/null
+++ b/drivers/media/pci/pt3/pt3_i2c.c
@@ -0,0 +1,240 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * 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/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+
+#include "pt3.h"
+
+#define PT3_I2C_BASE  2048
+#define PT3_CMD_ADDR_NORMAL 0
+#define PT3_CMD_ADDR_INIT_DEMOD  4096
+#define PT3_CMD_ADDR_INIT_TUNER  (4096 + 2042)
+
+/* masks for I2C status register */
+#define STAT_SEQ_RUNNING 0x1
+#define STAT_SEQ_ERROR   0x6
+#define STAT_NO_SEQ      0x8
+
+#define PT3_I2C_RUN   (1 << 16)
+#define PT3_I2C_RESET (1 << 17)
+
+enum ctl_cmd {
+	I_END,
+	I_ADDRESS,
+	I_CLOCK_L,
+	I_CLOCK_H,
+	I_DATA_L,
+	I_DATA_H,
+	I_RESET,
+	I_SLEEP,
+	I_DATA_L_NOP  = 0x08,
+	I_DATA_H_NOP  = 0x0c,
+	I_DATA_H_READ = 0x0d,
+	I_DATA_H_ACK0 = 0x0e,
+	I_DATA_H_ACK1 = 0x0f,
+};
+
+
+static void cmdbuf_add(struct pt3_i2cbuf *cbuf, enum ctl_cmd cmd)
+{
+	int buf_idx;
+
+	if ((cbuf->num_cmds % 2) == 0)
+		cbuf->tmp = cmd;
+	else {
+		cbuf->tmp |= cmd << 4;
+		buf_idx = cbuf->num_cmds / 2;
+		if (buf_idx < ARRAY_SIZE(cbuf->data))
+			cbuf->data[buf_idx] = cbuf->tmp;
+	}
+	cbuf->num_cmds++;
+}
+
+static void put_end(struct pt3_i2cbuf *cbuf)
+{
+	cmdbuf_add(cbuf, I_END);
+	if (cbuf->num_cmds % 2)
+		cmdbuf_add(cbuf, I_END);
+}
+
+static void put_start(struct pt3_i2cbuf *cbuf)
+{
+	cmdbuf_add(cbuf, I_DATA_H);
+	cmdbuf_add(cbuf, I_CLOCK_H);
+	cmdbuf_add(cbuf, I_DATA_L);
+	cmdbuf_add(cbuf, I_CLOCK_L);
+}
+
+static void put_byte_write(struct pt3_i2cbuf *cbuf, u8 val)
+{
+	u8 mask;
+
+	mask = 0x80;
+	for (mask = 0x80; mask > 0; mask >>= 1)
+		cmdbuf_add(cbuf, (val & mask) ? I_DATA_H_NOP : I_DATA_L_NOP);
+	cmdbuf_add(cbuf, I_DATA_H_ACK0);
+}
+
+static void put_byte_read(struct pt3_i2cbuf *cbuf, u32 size)
+{
+	int i, j;
+
+	for (i = 0; i < size; i++) {
+		for (j = 0; j < 8; j++)
+			cmdbuf_add(cbuf, I_DATA_H_READ);
+		cmdbuf_add(cbuf, (i == size - 1) ? I_DATA_H_NOP : I_DATA_L_NOP);
+	}
+}
+
+static void put_stop(struct pt3_i2cbuf *cbuf)
+{
+	cmdbuf_add(cbuf, I_DATA_L);
+	cmdbuf_add(cbuf, I_CLOCK_H);
+	cmdbuf_add(cbuf, I_DATA_H);
+}
+
+
+/* translates msgs to internal commands for bit-banging */
+static void translate(struct pt3_i2cbuf *cbuf, struct i2c_msg *msgs, int num)
+{
+	int i, j;
+	bool rd;
+
+	cbuf->num_cmds = 0;
+	for (i = 0; i < num; i++) {
+		rd = !!(msgs[i].flags & I2C_M_RD);
+		put_start(cbuf);
+		put_byte_write(cbuf, msgs[i].addr << 1 | rd);
+		if (rd)
+			put_byte_read(cbuf, msgs[i].len);
+		else
+			for (j = 0; j < msgs[i].len; j++)
+				put_byte_write(cbuf, msgs[i].buf[j]);
+	}
+	if (num > 0) {
+		put_stop(cbuf);
+		put_end(cbuf);
+	}
+}
+
+static int wait_i2c_result(struct pt3_board *pt3, u32 *result, int max_wait)
+{
+	int i;
+	u32 v;
+
+	for (i = 0; i < max_wait; i++) {
+		v = ioread32(pt3->regs[0] + REG_I2C_R);
+		if (!(v & STAT_SEQ_RUNNING))
+			break;
+		usleep_range(500, 750);
+	}
+	if (i >= max_wait)
+		return -EIO;
+	if (result)
+		*result = v;
+	return 0;
+}
+
+/* send [pre-]translated i2c msgs stored at addr */
+static int send_i2c_cmd(struct pt3_board *pt3, u32 addr)
+{
+	u32 ret;
+
+	/* make sure that previous transactions had finished */
+	if (wait_i2c_result(pt3, NULL, 50)) {
+		dev_warn(&pt3->pdev->dev, "(%s) prev. transaction stalled\n",
+				__func__);
+		return -EIO;
+	}
+
+	iowrite32(PT3_I2C_RUN | addr, pt3->regs[0] + REG_I2C_W);
+	usleep_range(200, 300);
+	/* wait for the current transaction to finish */
+	if (wait_i2c_result(pt3, &ret, 500) || (ret & STAT_SEQ_ERROR)) {
+		dev_warn(&pt3->pdev->dev, "(%s) failed.\n", __func__);
+		return -EIO;
+	}
+	return 0;
+}
+
+
+/* init commands for each demod are combined into one transaction
+ *  and hidden in ROM with the address PT3_CMD_ADDR_INIT_DEMOD.
+ */
+int  pt3_init_all_demods(struct pt3_board *pt3)
+{
+	ioread32(pt3->regs[0] + REG_I2C_R);
+	return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_DEMOD);
+}
+
+/* init commands for two ISDB-T tuners are hidden in ROM. */
+int  pt3_init_all_mxl301rf(struct pt3_board *pt3)
+{
+	usleep_range(1000, 2000);
+	return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_TUNER);
+}
+
+void pt3_i2c_reset(struct pt3_board *pt3)
+{
+	iowrite32(PT3_I2C_RESET, pt3->regs[0] + REG_I2C_W);
+}
+
+/*
+ * I2C algorithm
+ */
+int
+pt3_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct pt3_board *pt3;
+	struct pt3_i2cbuf *cbuf;
+	int i;
+	void __iomem *p;
+
+	pt3 = i2c_get_adapdata(adap);
+	cbuf = pt3->i2c_buf;
+
+	for (i = 0; i < num; i++)
+		if (msgs[i].flags & I2C_M_RECV_LEN) {
+			dev_warn(&pt3->pdev->dev,
+				"(%s) I2C_M_RECV_LEN not supported.\n",
+				__func__);
+			return -EINVAL;
+		}
+
+	translate(cbuf, msgs, num);
+	memcpy_toio(pt3->regs[1] + PT3_I2C_BASE + PT3_CMD_ADDR_NORMAL / 2,
+			cbuf->data, cbuf->num_cmds);
+
+	if (send_i2c_cmd(pt3, PT3_CMD_ADDR_NORMAL) < 0)
+		return -EIO;
+
+	p = pt3->regs[1] + PT3_I2C_BASE;
+	for (i = 0; i < num; i++)
+		if ((msgs[i].flags & I2C_M_RD) && msgs[i].len > 0) {
+			memcpy_fromio(msgs[i].buf, p, msgs[i].len);
+			p += msgs[i].len;
+		}
+
+	return num;
+}
+
+u32 pt3_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C;
+}
diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig
index 5e4a679..7064573 100644
--- a/drivers/media/pci/saa7134/Kconfig
+++ b/drivers/media/pci/saa7134/Kconfig
@@ -66,3 +66,12 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called saa7134-dvb.
+
+config VIDEO_SAA7134_GO7007
+	tristate "go7007 support for saa7134 based TV cards"
+	depends on m
+	depends on VIDEO_SAA7134
+	depends on VIDEO_GO7007
+	---help---
+	  Enables saa7134 driver support for boards with go7007
+	  MPEG encoder (WIS Voyager or compatible).
diff --git a/drivers/media/pci/saa7134/Makefile b/drivers/media/pci/saa7134/Makefile
index 373543c..7e85f15 100644
--- a/drivers/media/pci/saa7134/Makefile
+++ b/drivers/media/pci/saa7134/Makefile
@@ -5,6 +5,7 @@
 saa7134-$(CPTCFG_VIDEO_SAA7134_RC) += saa7134-input.o
 
 obj-$(CPTCFG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o
+obj-$(CPTCFG_VIDEO_SAA7134_GO7007) += saa7134-go7007.o
 
 obj-$(CPTCFG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
 
@@ -14,3 +15,4 @@
 ccflags-y += -I$(backport_srctree)/drivers/media/tuners
 ccflags-y += -I$(backport_srctree)/drivers/media/dvb-core
 ccflags-y += -I$(backport_srctree)/drivers/media/dvb-frontends
+ccflags-y += -I$(backport_srctree)/drivers/media/usb/go7007
diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
index 6e4bdb9..3ca0780 100644
--- a/drivers/media/pci/saa7134/saa7134-cards.c
+++ b/drivers/media/pci/saa7134/saa7134-cards.c
@@ -5827,6 +5827,29 @@
 			.gpio = 0x0000800,
 		},
 	},
+	[SAA7134_BOARD_WIS_VOYAGER] = {
+		.name           = "WIS Voyager or compatible",
+		.audio_clock    = 0x00200000,
+		.tuner_type	= TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.mpeg		= SAA7134_MPEG_GO7007,
+		.inputs		= { {
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		}, {
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		}, {
+			.name = name_svideo,
+			.vmux = 6,
+		.amux = LINE1,
+		} },
+	},
 
 };
 
@@ -7080,6 +7103,12 @@
 		.subdevice    = 0x2055, /* AverTV Satellite Hybrid+FM A706 */
 		.driver_data  = SAA7134_BOARD_AVERMEDIA_A706,
 	}, {
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1905, /* WIS */
+		.subdevice    = 0x7007,
+		.driver_data  = SAA7134_BOARD_WIS_VOYAGER,
+	}, {
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index 9ff03a6..236ed72 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -160,6 +160,8 @@
 		request_module("saa7134-empress");
 	if (card_is_dvb(dev))
 		request_module("saa7134-dvb");
+	if (card_is_go7007(dev))
+		request_module("saa7134-go7007");
 	if (alsa) {
 		if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130)
 			request_module("saa7134-alsa");
@@ -563,8 +565,12 @@
 			saa7134_irq_vbi_done(dev,status);
 
 		if ((report & SAA7134_IRQ_REPORT_DONE_RA2) &&
-		    card_has_mpeg(dev))
-			saa7134_irq_ts_done(dev,status);
+		    card_has_mpeg(dev)) {
+			if (dev->mops->irq_ts_done != NULL)
+				dev->mops->irq_ts_done(dev, status);
+			else
+				saa7134_irq_ts_done(dev, status);
+		}
 
 		if (report & SAA7134_IRQ_REPORT_GPIO16) {
 			switch (dev->has_remote) {
diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c
new file mode 100644
index 0000000..54e650b
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-go7007.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <asm/byteorder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+#include "go7007-priv.h"
+
+/*#define GO7007_HPI_DEBUG*/
+
+enum hpi_address {
+	HPI_ADDR_VIDEO_BUFFER = 0xe4,
+	HPI_ADDR_INIT_BUFFER = 0xea,
+	HPI_ADDR_INTR_RET_VALUE = 0xee,
+	HPI_ADDR_INTR_RET_DATA = 0xec,
+	HPI_ADDR_INTR_STATUS = 0xf4,
+	HPI_ADDR_INTR_WR_PARAM = 0xf6,
+	HPI_ADDR_INTR_WR_INDEX = 0xf8,
+};
+
+enum gpio_command {
+	GPIO_COMMAND_RESET = 0x00, /* 000b */
+	GPIO_COMMAND_REQ1  = 0x04, /* 001b */
+	GPIO_COMMAND_WRITE = 0x20, /* 010b */
+	GPIO_COMMAND_REQ2  = 0x24, /* 011b */
+	GPIO_COMMAND_READ  = 0x80, /* 100b */
+	GPIO_COMMAND_VIDEO = 0x84, /* 101b */
+	GPIO_COMMAND_IDLE  = 0xA0, /* 110b */
+	GPIO_COMMAND_ADDR  = 0xA4, /* 111b */
+};
+
+struct saa7134_go7007 {
+	struct v4l2_subdev sd;
+	struct saa7134_dev *dev;
+	u8 *top;
+	u8 *bottom;
+	dma_addr_t top_dma;
+	dma_addr_t bottom_dma;
+};
+
+static inline struct saa7134_go7007 *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct saa7134_go7007, sd);
+}
+
+static const struct go7007_board_info board_voyager = {
+	.flags		 = 0,
+	.sensor_flags	 = GO7007_SENSOR_656 |
+				GO7007_SENSOR_VALID_ENABLE |
+				GO7007_SENSOR_TV |
+				GO7007_SENSOR_VBI,
+	.audio_flags	= GO7007_AUDIO_I2S_MODE_1 |
+				GO7007_AUDIO_WORD_16,
+	.audio_rate	 = 48000,
+	.audio_bclk_div	 = 8,
+	.audio_main_div	 = 2,
+	.hpi_buffer_cap  = 7,
+	.num_inputs	 = 1,
+	.inputs		 = {
+		{
+			.name		= "SAA7134",
+		},
+	},
+};
+
+/********************* Driver for GPIO HPI interface *********************/
+
+static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data)
+{
+	saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+	/* Write HPI address */
+	saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+	/* Write low byte */
+	saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+	/* Write high byte */
+	saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+	return 0;
+}
+
+static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data)
+{
+	saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+	/* Write HPI address */
+	saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+	saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+	/* Read low byte */
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	*data = saa_readb(SAA7134_GPIO_GPSTATUS0);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+	/* Read high byte */
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	*data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8;
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+	return 0;
+}
+
+static int saa7134_go7007_interface_reset(struct go7007 *go)
+{
+	struct saa7134_go7007 *saa = go->hpi_context;
+	struct saa7134_dev *dev = saa->dev;
+	u16 intr_val, intr_data;
+	int count = 20;
+
+	saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */
+	saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4);
+	saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET);
+	msleep(1);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+	msleep(10);
+
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+	saa_readb(SAA7134_GPIO_GPSTATUS2);
+	/*pr_debug("status is %s\n", saa_readb(SAA7134_GPIO_GPSTATUS2) & 0x40 ? "OK" : "not OK"); */
+
+	/* enter command mode...(?) */
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+
+	do {
+		saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+		saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+		saa_readb(SAA7134_GPIO_GPSTATUS2);
+		/*pr_info("gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */
+	} while (--count > 0);
+
+	/* Wait for an interrupt to indicate successful hardware reset */
+	if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
+			(intr_val & ~0x1) != 0x55aa) {
+		pr_err("saa7134-go7007: unable to reset the GO7007\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data)
+{
+	struct saa7134_go7007 *saa = go->hpi_context;
+	struct saa7134_dev *dev = saa->dev;
+	int i;
+	u16 status_reg;
+
+#ifdef GO7007_HPI_DEBUG
+	pr_debug("saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data);
+#endif
+
+	for (i = 0; i < 100; ++i) {
+		gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+		if (!(status_reg & 0x0010))
+			break;
+		msleep(10);
+	}
+	if (i == 100) {
+		pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n",
+			status_reg);
+		return -1;
+	}
+	gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data);
+	gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr);
+
+	return 0;
+}
+
+static int saa7134_go7007_read_interrupt(struct go7007 *go)
+{
+	struct saa7134_go7007 *saa = go->hpi_context;
+	struct saa7134_dev *dev = saa->dev;
+
+	/* XXX we need to wait if there is no interrupt available */
+	go->interrupt_available = 1;
+	gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value);
+	gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data);
+#ifdef GO7007_HPI_DEBUG
+	pr_debug("saa7134-go7007: ReadInterrupt: %04x %04x\n",
+			go->interrupt_value, go->interrupt_data);
+#endif
+	return 0;
+}
+
+static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev,
+						unsigned long status)
+{
+	struct go7007 *go = video_get_drvdata(dev->empress_dev);
+	struct saa7134_go7007 *saa = go->hpi_context;
+
+	if (!vb2_is_streaming(&go->vidq))
+		return;
+	if (0 != (status & 0x000f0000))
+		pr_debug("saa7134-go7007: irq: lost %ld\n",
+				(status >> 16) & 0x0f);
+	if (status & 0x100000) {
+		dma_sync_single_for_cpu(&dev->pci->dev,
+					saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+		go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE);
+		saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma);
+	} else {
+		dma_sync_single_for_cpu(&dev->pci->dev,
+					saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+		go7007_parse_video_stream(go, saa->top, PAGE_SIZE);
+		saa_writel(SAA7134_RS_BA1(5), saa->top_dma);
+	}
+}
+
+static int saa7134_go7007_stream_start(struct go7007 *go)
+{
+	struct saa7134_go7007 *saa = go->hpi_context;
+	struct saa7134_dev *dev = saa->dev;
+
+	saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top),
+			0, PAGE_SIZE, DMA_FROM_DEVICE);
+	if (dma_mapping_error(&dev->pci->dev, saa->top_dma))
+		return -ENOMEM;
+	saa->bottom_dma = dma_map_page(&dev->pci->dev,
+			virt_to_page(saa->bottom),
+			0, PAGE_SIZE, DMA_FROM_DEVICE);
+	if (dma_mapping_error(&dev->pci->dev, saa->bottom_dma)) {
+		dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+				DMA_FROM_DEVICE);
+		return -ENOMEM;
+	}
+
+	saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000);
+	saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200);
+
+	/* Set HPI interface for video */
+	saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+	saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER);
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+	saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+	/* Enable TS interface */
+	saa_writeb(SAA7134_TS_PARALLEL, 0xe6);
+
+	/* Reset TS interface */
+	saa_setb(SAA7134_TS_SERIAL1, 0x01);
+	saa_clearb(SAA7134_TS_SERIAL1, 0x01);
+
+	/* Set up transfer block size */
+	saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1);
+	saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1);
+	saa_writeb(SAA7134_TS_DMA1, 0);
+	saa_writeb(SAA7134_TS_DMA2, 0);
+
+	/* Enable video streaming mode */
+	saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO);
+
+	saa_writel(SAA7134_RS_BA1(5), saa->top_dma);
+	saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma);
+	saa_writel(SAA7134_RS_PITCH(5), 128);
+	saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX);
+
+	/* Enable TS FIFO */
+	saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+	/* Enable DMA IRQ */
+	saa_setl(SAA7134_IRQ1,
+			SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+	return 0;
+}
+
+static int saa7134_go7007_stream_stop(struct go7007 *go)
+{
+	struct saa7134_go7007 *saa = go->hpi_context;
+	struct saa7134_dev *dev;
+
+	if (!saa)
+		return -EINVAL;
+	dev = saa->dev;
+	if (!dev)
+		return -EINVAL;
+
+	/* Shut down TS FIFO */
+	saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+	/* Disable DMA IRQ */
+	saa_clearl(SAA7134_IRQ1,
+			SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+	/* Disable TS interface */
+	saa_clearb(SAA7134_TS_PARALLEL, 0x80);
+
+	dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+			DMA_FROM_DEVICE);
+	dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE,
+			DMA_FROM_DEVICE);
+
+	return 0;
+}
+
+static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len)
+{
+	struct saa7134_go7007 *saa = go->hpi_context;
+	struct saa7134_dev *dev = saa->dev;
+	u16 status_reg;
+	int i;
+
+#ifdef GO7007_HPI_DEBUG
+	pr_debug("saa7134-go7007: DownloadBuffer sending %d bytes\n", len);
+#endif
+
+	while (len > 0) {
+		i = len > 64 ? 64 : len;
+		saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+		saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER);
+		saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+		saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+		while (i-- > 0) {
+			saa_writeb(SAA7134_GPIO_GPSTATUS0, *data);
+			saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+			saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+			++data;
+			--len;
+		}
+		for (i = 0; i < 100; ++i) {
+			gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+			if (!(status_reg & 0x0002))
+				break;
+		}
+		if (i == 100) {
+			pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n",
+			       status_reg);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
+	.interface_reset	= saa7134_go7007_interface_reset,
+	.write_interrupt	= saa7134_go7007_write_interrupt,
+	.read_interrupt		= saa7134_go7007_read_interrupt,
+	.stream_start		= saa7134_go7007_stream_start,
+	.stream_stop		= saa7134_go7007_stream_stop,
+	.send_firmware		= saa7134_go7007_send_firmware,
+};
+MODULE_FIRMWARE("go7007/go7007tv.bin");
+
+/* --------------------------------------------------------------------------*/
+
+static int saa7134_go7007_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+#if 0
+	struct saa7134_go7007 *saa = to_state(sd);
+	struct saa7134_dev *dev = saa->dev;
+
+	return saa7134_s_std_internal(dev, NULL, norm);
+#else
+	return 0;
+#endif
+}
+
+static const struct v4l2_subdev_video_ops saa7134_go7007_video_ops = {
+	.s_std = saa7134_go7007_s_std,
+};
+
+static const struct v4l2_subdev_ops saa7134_go7007_sd_ops = {
+	.video = &saa7134_go7007_video_ops,
+};
+
+/* --------------------------------------------------------------------------*/
+
+
+/********************* Add/remove functions *********************/
+
+static int saa7134_go7007_init(struct saa7134_dev *dev)
+{
+	struct go7007 *go;
+	struct saa7134_go7007 *saa;
+	struct v4l2_subdev *sd;
+
+	pr_debug("saa7134-go7007: probing new SAA713X board\n");
+
+	go = go7007_alloc(&board_voyager, &dev->pci->dev);
+	if (go == NULL)
+		return -ENOMEM;
+
+	saa = kzalloc(sizeof(struct saa7134_go7007), GFP_KERNEL);
+	if (saa == NULL) {
+		kfree(go);
+		return -ENOMEM;
+	}
+
+	go->board_id = GO7007_BOARDID_PCI_VOYAGER;
+	snprintf(go->bus_info, sizeof(go->bus_info), "PCI:%s", pci_name(dev->pci));
+	strlcpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name));
+	go->hpi_ops = &saa7134_go7007_hpi_ops;
+	go->hpi_context = saa;
+	saa->dev = dev;
+
+	/* Init the subdevice interface */
+	sd = &saa->sd;
+	v4l2_subdev_init(sd, &saa7134_go7007_sd_ops);
+	v4l2_set_subdevdata(sd, saa);
+	strncpy(sd->name, "saa7134-go7007", sizeof(sd->name));
+
+	/* Allocate a couple pages for receiving the compressed stream */
+	saa->top = (u8 *)get_zeroed_page(GFP_KERNEL);
+	if (!saa->top)
+		goto allocfail;
+	saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL);
+	if (!saa->bottom)
+		goto allocfail;
+
+	/* Boot the GO7007 */
+	if (go7007_boot_encoder(go, go->board_info->flags &
+					GO7007_BOARD_USE_ONBOARD_I2C) < 0)
+		goto allocfail;
+
+	/* Do any final GO7007 initialization, then register the
+	 * V4L2 and ALSA interfaces */
+	if (go7007_register_encoder(go, go->board_info->num_i2c_devs) < 0)
+		goto allocfail;
+
+	/* Register the subdevice interface with the go7007 device */
+	if (v4l2_device_register_subdev(&go->v4l2_dev, sd) < 0)
+		pr_info("saa7134-go7007: register subdev failed\n");
+
+	dev->empress_dev = &go->vdev;
+
+	go->status = STATUS_ONLINE;
+	return 0;
+
+allocfail:
+	if (saa->top)
+		free_page((unsigned long)saa->top);
+	if (saa->bottom)
+		free_page((unsigned long)saa->bottom);
+	kfree(saa);
+	kfree(go);
+	return -ENOMEM;
+}
+
+static int saa7134_go7007_fini(struct saa7134_dev *dev)
+{
+	struct go7007 *go;
+	struct saa7134_go7007 *saa;
+
+	if (NULL == dev->empress_dev)
+		return 0;
+
+	go = video_get_drvdata(dev->empress_dev);
+	if (go->audio_enabled)
+		go7007_snd_remove(go);
+
+	saa = go->hpi_context;
+	go->status = STATUS_SHUTDOWN;
+	free_page((unsigned long)saa->top);
+	free_page((unsigned long)saa->bottom);
+	v4l2_device_unregister_subdev(&saa->sd);
+	kfree(saa);
+	video_unregister_device(&go->vdev);
+
+	v4l2_device_put(&go->v4l2_dev);
+	dev->empress_dev = NULL;
+
+	return 0;
+}
+
+static struct saa7134_mpeg_ops saa7134_go7007_ops = {
+	.type          = SAA7134_MPEG_GO7007,
+	.init          = saa7134_go7007_init,
+	.fini          = saa7134_go7007_fini,
+	.irq_ts_done   = saa7134_go7007_irq_ts_done,
+};
+
+static int __init saa7134_go7007_mod_init(void)
+{
+	return saa7134_ts_register(&saa7134_go7007_ops);
+}
+
+static void __exit saa7134_go7007_mod_cleanup(void)
+{
+	saa7134_ts_unregister(&saa7134_go7007_ops);
+}
+
+module_init(saa7134_go7007_mod_init);
+module_exit(saa7134_go7007_mod_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c
index c06dbe1..4f0b101 100644
--- a/drivers/media/pci/saa7134/saa7134-vbi.c
+++ b/drivers/media/pci/saa7134/saa7134-vbi.c
@@ -43,7 +43,7 @@
 
 /* ------------------------------------------------------------------ */
 
-#define VBI_LINE_COUNT     16
+#define VBI_LINE_COUNT     17
 #define VBI_LINE_LENGTH  2048
 #define VBI_SCALE       0x200
 
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 4932d92..b0f279c 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -201,7 +201,7 @@
 		.video_v_start = 24,	\
 		.video_v_stop  = 311,	\
 		.vbi_v_start_0 = 7,	\
-		.vbi_v_stop_0  = 22,	\
+		.vbi_v_stop_0  = 23,	\
 		.vbi_v_start_1 = 319,   \
 		.src_timing    = 4
 
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index 67ef1c9..5e9cc30 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -338,6 +338,7 @@
 #define SAA7134_BOARD_ASUSTeK_PS3_100      190
 #define SAA7134_BOARD_HAWELL_HW_9004V1      191
 #define SAA7134_BOARD_AVERMEDIA_A706		192
+#define SAA7134_BOARD_WIS_VOYAGER           193
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
@@ -368,6 +369,7 @@
 	SAA7134_MPEG_UNUSED,
 	SAA7134_MPEG_EMPRESS,
 	SAA7134_MPEG_DVB,
+	SAA7134_MPEG_GO7007,
 };
 
 enum saa7134_mpeg_ts_type {
@@ -407,6 +409,7 @@
 #define card_has_radio(dev)   (NULL != saa7134_boards[dev->board].radio.name)
 #define card_is_empress(dev)  (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg)
 #define card_is_dvb(dev)      (SAA7134_MPEG_DVB     == saa7134_boards[dev->board].mpeg)
+#define card_is_go7007(dev)   (SAA7134_MPEG_GO7007  == saa7134_boards[dev->board].mpeg)
 #define card_has_mpeg(dev)    (SAA7134_MPEG_UNUSED  != saa7134_boards[dev->board].mpeg)
 #define card(dev)             (saa7134_boards[dev->board])
 #define card_in(dev,n)        (saa7134_boards[dev->board].inputs[n])
@@ -522,6 +525,8 @@
 	int                        (*init)(struct saa7134_dev *dev);
 	int                        (*fini)(struct saa7134_dev *dev);
 	void                       (*signal_change)(struct saa7134_dev *dev);
+	void                       (*irq_ts_done)(struct saa7134_dev *dev,
+						  unsigned long status);
 };
 
 /* global device status */
diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c
index e042963..4f3b1dd 100644
--- a/drivers/media/pci/saa7164/saa7164-api.c
+++ b/drivers/media/pci/saa7164/saa7164-api.c
@@ -680,7 +680,6 @@
 int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
 {
 	struct saa7164_dev *dev = port->dev;
-	int ret = 0;
 	u8 agc_disable;
 
 	dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std);
@@ -733,7 +732,7 @@
 	saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */
 	msleep(100);
 
-	return ret;
+	return 0;
 }
 
 /* Ensure the dif is in the correct state for the operating mode
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index 1bf0697..cc1be8a 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -52,7 +52,7 @@
 module_param_named(debug, saa_debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
 
-unsigned int fw_debug;
+static unsigned int fw_debug;
 module_param(fw_debug, int, 0644);
 MODULE_PARM_DESC(fw_debug, "Firmware debug level def:2");
 
@@ -72,7 +72,7 @@
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card, "card type");
 
-unsigned int print_histogram = 64;
+static unsigned int print_histogram = 64;
 module_param(print_histogram, int, 0644);
 MODULE_PARM_DESC(print_histogram, "print histogram values once");
 
@@ -80,7 +80,7 @@
 module_param(crc_checking, int, 0644);
 MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers");
 
-unsigned int guard_checking = 1;
+static unsigned int guard_checking = 1;
 module_param(guard_checking, int, 0644);
 MODULE_PARM_DESC(guard_checking,
 	"enable dma sanity checking for buffer overruns");
diff --git a/drivers/media/pci/solo6x10/Kconfig b/drivers/media/pci/solo6x10/Kconfig
index d9516ac..a6933d8 100644
--- a/drivers/media/pci/solo6x10/Kconfig
+++ b/drivers/media/pci/solo6x10/Kconfig
@@ -2,6 +2,7 @@
 	tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)"
 	depends on m
 	depends on PCI && VIDEO_DEV && SND && I2C
+	depends on HAS_DMA
 	depends on BITREVERSE
 	depends on FONT_SUPPORT
 	depends on FONT_8x16
diff --git a/drivers/media/pci/solo6x10/solo6x10-disp.c b/drivers/media/pci/solo6x10/solo6x10-disp.c
index 5ea9cac..11c98f0 100644
--- a/drivers/media/pci/solo6x10/solo6x10-disp.c
+++ b/drivers/media/pci/solo6x10/solo6x10-disp.c
@@ -172,7 +172,7 @@
 static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
 			       u16 val, int reg_size)
 {
-	u16 *buf;
+	__le16 *buf;
 	const int n = 64, size = n * sizeof(*buf);
 	int i, ret = 0;
 
@@ -211,7 +211,7 @@
 {
 	const unsigned size = sizeof(u16) * 64;
 	u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
-	u16 *buf;
+	__le16 *buf;
 	int x, y;
 	int ret = 0;
 
diff --git a/drivers/media/pci/solo6x10/solo6x10-eeprom.c b/drivers/media/pci/solo6x10/solo6x10-eeprom.c
index af40b3a..da25ce4 100644
--- a/drivers/media/pci/solo6x10/solo6x10-eeprom.c
+++ b/drivers/media/pci/solo6x10/solo6x10-eeprom.c
@@ -100,7 +100,7 @@
 	return retval;
 }
 
-unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc)
+__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc)
 {
 	int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
 	unsigned short retval = 0;
@@ -117,11 +117,11 @@
 
 	solo_eeprom_reg_write(solo_dev, ~EE_CS);
 
-	return retval;
+	return (__force __be16)retval;
 }
 
 int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
-		      unsigned short data)
+		      __be16 data)
 {
 	int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN);
 	unsigned int retval;
@@ -130,7 +130,7 @@
 	solo_eeprom_cmd(solo_dev, write_cmd);
 
 	for (i = 15; i >= 0; i--) {
-		unsigned int dataval = (data >> i) & 1;
+		unsigned int dataval = ((__force unsigned)data >> i) & 1;
 
 		solo_eeprom_reg_write(solo_dev, EE_ENB);
 		solo_eeprom_reg_write(solo_dev,
diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h
index c6154b0..72017b7 100644
--- a/drivers/media/pci/solo6x10/solo6x10.h
+++ b/drivers/media/pci/solo6x10/solo6x10.h
@@ -394,9 +394,9 @@
 
 /* EEPROM commands */
 unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en);
-unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc);
+__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc);
 int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
-		      unsigned short data);
+		      __be16 data);
 
 /* JPEG Qp functions */
 void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch,
diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig
index c892cbc..db259af 100644
--- a/drivers/media/pci/sta2x11/Kconfig
+++ b/drivers/media/pci/sta2x11/Kconfig
@@ -2,6 +2,7 @@
 	tristate "STA2X11 VIP Video For Linux"
 	depends on m
 	depends on STA2X11
+	depends on HAS_DMA
 	select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEOBUF2_DMA_CONTIG
 	depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 365bd21..22450f5 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -152,7 +152,7 @@
 	int tcount, bcount;
 	int overflow;
 
-	void *iomem;	/* I/O Memory */
+	void __iomem *iomem;	/* I/O Memory */
 	struct vip_config *config;
 };
 
diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig
index a90a2fa..893ddf1 100644
--- a/drivers/media/pci/ttpci/Kconfig
+++ b/drivers/media/pci/ttpci/Kconfig
@@ -1,9 +1,13 @@
+config DVB_AV7110_IR
+	bool
+
 config DVB_AV7110
 	tristate "AV7110 cards"
 	depends on m
 	depends on DVB_CORE && PCI && I2C
 	select TTPCI_EEPROM
 	select VIDEO_SAA7146_VV
+	select DVB_AV7110_IR if INPUT_EVDEV=y || INPUT_EVDEV=DVB_AV7110
 	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
 	select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT
 	select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile
index 0fe8f9c..ba7d1c3 100644
--- a/drivers/media/pci/ttpci/Makefile
+++ b/drivers/media/pci/ttpci/Makefile
@@ -5,7 +5,7 @@
 
 dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o
 
-ifdef CONFIG_INPUT_EVDEV
+ifdef CPTCFG_DVB_AV7110_IR
 dvb-ttpci-objs += av7110_ir.o
 endif
 
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index 6599b1b..45a2852 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -235,7 +235,7 @@
 
 	restart_feeds(av7110);
 
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CPTCFG_DVB_AV7110_IR)
 	av7110_check_ir_config(av7110, true);
 #endif
 }
@@ -268,7 +268,7 @@
 		if (!av7110->arm_ready)
 			continue;
 
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CPTCFG_DVB_AV7110_IR)
 		av7110_check_ir_config(av7110, false);
 #endif
 
@@ -2725,7 +2725,7 @@
 
 	mutex_init(&av7110->ioctl_mutex);
 
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CPTCFG_DVB_AV7110_IR)
 	av7110_ir_init(av7110);
 #endif
 	printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
@@ -2768,7 +2768,7 @@
 	struct av7110 *av7110 = saa->ext_priv;
 	dprintk(4, "%p\n", av7110);
 
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CPTCFG_DVB_AV7110_IR)
 	av7110_ir_exit(av7110);
 #endif
 	if (budgetpatch || av7110->full_ts) {
diff --git a/drivers/media/pci/tw68/Kconfig b/drivers/media/pci/tw68/Kconfig
new file mode 100644
index 0000000..61b3e24
--- /dev/null
+++ b/drivers/media/pci/tw68/Kconfig
@@ -0,0 +1,11 @@
+config VIDEO_TW68
+	tristate "Techwell tw68x Video For Linux"
+	depends on m
+	depends on VIDEO_DEV && PCI && VIDEO_V4L2
+	depends on I2C_ALGOBIT
+	select VIDEOBUF2_DMA_SG
+	---help---
+	  Support for Techwell tw68xx based frame grabber boards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tw68.
diff --git a/drivers/media/pci/tw68/Makefile b/drivers/media/pci/tw68/Makefile
new file mode 100644
index 0000000..677e3b7
--- /dev/null
+++ b/drivers/media/pci/tw68/Makefile
@@ -0,0 +1,3 @@
+tw68-objs := tw68-core.o tw68-video.o tw68-risc.o
+
+obj-$(CPTCFG_VIDEO_TW68) += tw68.o
diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c
new file mode 100644
index 0000000..a6fb48c
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68-core.c
@@ -0,0 +1,434 @@
+/*
+ *  tw68-core.c
+ *  Core functions for the Techwell 68xx driver
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) 2009  William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
+#include <linux/sound.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm.h>
+
+#include <media/v4l2-dev.h>
+#include "tw68.h"
+#include "tw68-reg.h"
+
+MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards");
+MODULE_AUTHOR("William M. Brack");
+MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
+MODULE_LICENSE("GPL");
+
+static unsigned int latency = UNSET;
+module_param(latency, int, 0444);
+MODULE_PARM_DESC(latency, "pci latency timer");
+
+static unsigned int video_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "video device number");
+
+static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
+
+static atomic_t tw68_instance = ATOMIC_INIT(0);
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * Please add any new PCI IDs to: http://pci-ids.ucw.cz.  This keeps
+ * the PCI ID database up to date.  Note that the entries must be
+ * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs.
+ */
+static const struct pci_device_id tw68_pci_tbl[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6800)},
+	{PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6801)},
+	{PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6804)},
+	{PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_1)},
+	{PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_2)},
+	{PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_3)},
+	{PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_4)},
+	{0,}
+};
+
+/* ------------------------------------------------------------------ */
+
+
+/*
+ * The device is given a "soft reset". According to the specifications,
+ * after this "all register content remain unchanged", so we also write
+ * to all specified registers manually as well (mostly to manufacturer's
+ * specified reset values)
+ */
+static int tw68_hw_init1(struct tw68_dev *dev)
+{
+	/* Assure all interrupts are disabled */
+	tw_writel(TW68_INTMASK, 0);		/* 020 */
+	/* Clear any pending interrupts */
+	tw_writel(TW68_INTSTAT, 0xffffffff);	/* 01C */
+	/* Stop risc processor, set default buffer level */
+	tw_writel(TW68_DMAC, 0x1600);
+
+	tw_writeb(TW68_ACNTL, 0x80);	/* 218	soft reset */
+	msleep(100);
+
+	tw_writeb(TW68_INFORM, 0x40);	/* 208	mux0, 27mhz xtal */
+	tw_writeb(TW68_OPFORM, 0x04);	/* 20C	analog line-lock */
+	tw_writeb(TW68_HSYNC, 0);	/* 210	color-killer high sens */
+	tw_writeb(TW68_ACNTL, 0x42);	/* 218	int vref #2, chroma adc off */
+
+	tw_writeb(TW68_CROP_HI, 0x02);	/* 21C	Hactive m.s. bits */
+	tw_writeb(TW68_VDELAY_LO, 0x12);/* 220	Mfg specified reset value */
+	tw_writeb(TW68_VACTIVE_LO, 0xf0);
+	tw_writeb(TW68_HDELAY_LO, 0x0f);
+	tw_writeb(TW68_HACTIVE_LO, 0xd0);
+
+	tw_writeb(TW68_CNTRL1, 0xcd);	/* 230	Wide Chroma BPF B/W
+					 *	Secam reduction, Adap comb for
+					 *	NTSC, Op Mode 1 */
+
+	tw_writeb(TW68_VSCALE_LO, 0);	/* 234 */
+	tw_writeb(TW68_SCALE_HI, 0x11);	/* 238 */
+	tw_writeb(TW68_HSCALE_LO, 0);	/* 23c */
+	tw_writeb(TW68_BRIGHT, 0);	/* 240 */
+	tw_writeb(TW68_CONTRAST, 0x5c);	/* 244 */
+	tw_writeb(TW68_SHARPNESS, 0x51);/* 248 */
+	tw_writeb(TW68_SAT_U, 0x80);	/* 24C */
+	tw_writeb(TW68_SAT_V, 0x80);	/* 250 */
+	tw_writeb(TW68_HUE, 0x00);	/* 254 */
+
+	/* TODO - Check that none of these are set by control defaults */
+	tw_writeb(TW68_SHARP2, 0x53);	/* 258	Mfg specified reset val */
+	tw_writeb(TW68_VSHARP, 0x80);	/* 25C	Sharpness Coring val 8 */
+	tw_writeb(TW68_CORING, 0x44);	/* 260	CTI and Vert Peak coring */
+	tw_writeb(TW68_CNTRL2, 0x00);	/* 268	No power saving enabled */
+	tw_writeb(TW68_SDT, 0x07);	/* 270	Enable shadow reg, auto-det */
+	tw_writeb(TW68_SDTR, 0x7f);	/* 274	All stds recog, don't start */
+	tw_writeb(TW68_CLMPG, 0x50);	/* 280	Clamp end at 40 sys clocks */
+	tw_writeb(TW68_IAGC, 0x22);	/* 284	Mfg specified reset val */
+	tw_writeb(TW68_AGCGAIN, 0xf0);	/* 288	AGC gain when loop disabled */
+	tw_writeb(TW68_PEAKWT, 0xd8);	/* 28C	White peak threshold */
+	tw_writeb(TW68_CLMPL, 0x3c);	/* 290	Y channel clamp level */
+/*	tw_writeb(TW68_SYNCT, 0x38);*/	/* 294	Sync amplitude */
+	tw_writeb(TW68_SYNCT, 0x30);	/* 294	Sync amplitude */
+	tw_writeb(TW68_MISSCNT, 0x44);	/* 298	Horiz sync, VCR detect sens */
+	tw_writeb(TW68_PCLAMP, 0x28);	/* 29C	Clamp pos from PLL sync */
+	/* Bit DETV of VCNTL1 helps sync multi cams/chip board */
+	tw_writeb(TW68_VCNTL1, 0x04);	/* 2A0 */
+	tw_writeb(TW68_VCNTL2, 0);	/* 2A4 */
+	tw_writeb(TW68_CKILL, 0x68);	/* 2A8	Mfg specified reset val */
+	tw_writeb(TW68_COMB, 0x44);	/* 2AC	Mfg specified reset val */
+	tw_writeb(TW68_LDLY, 0x30);	/* 2B0	Max positive luma delay */
+	tw_writeb(TW68_MISC1, 0x14);	/* 2B4	Mfg specified reset val */
+	tw_writeb(TW68_LOOP, 0xa5);	/* 2B8	Mfg specified reset val */
+	tw_writeb(TW68_MISC2, 0xe0);	/* 2BC	Enable colour killer */
+	tw_writeb(TW68_MVSN, 0);	/* 2C0 */
+	tw_writeb(TW68_CLMD, 0x05);	/* 2CC	slice level auto, clamp med. */
+	tw_writeb(TW68_IDCNTL, 0);	/* 2D0	Writing zero to this register
+					 *	selects NTSC ID detection,
+					 *	but doesn't change the
+					 *	sensitivity (which has a reset
+					 *	value of 1E).  Since we are
+					 *	not doing auto-detection, it
+					 *	has no real effect */
+	tw_writeb(TW68_CLCNTL1, 0);	/* 2D4 */
+	tw_writel(TW68_VBIC, 0x03);	/* 010 */
+	tw_writel(TW68_CAP_CTL, 0x03);	/* 040	Enable both even & odd flds */
+	tw_writel(TW68_DMAC, 0x2000);	/* patch set had 0x2080 */
+	tw_writel(TW68_TESTREG, 0);	/* 02C */
+
+	/*
+	 * Some common boards, especially inexpensive single-chip models,
+	 * use the GPIO bits 0-3 to control an on-board video-output mux.
+	 * For these boards, we need to set up the GPIO register into
+	 * "normal" mode, set bits 0-3 as output, and then set those bits
+	 * zero.
+	 *
+	 * Eventually, it would be nice if we could identify these boards
+	 * uniquely, and only do this initialisation if the board has been
+	 * identify.  For the moment, however, it shouldn't hurt anything
+	 * to do these steps.
+	 */
+	tw_writel(TW68_GPIOC, 0);	/* Set the GPIO to "normal", no ints */
+	tw_writel(TW68_GPOE, 0x0f);	/* Set bits 0-3 to "output" */
+	tw_writel(TW68_GPDATA, 0);	/* Set all bits to low state */
+
+	/* Initialize the device control structures */
+	mutex_init(&dev->lock);
+	spin_lock_init(&dev->slock);
+
+	/* Initialize any subsystems */
+	tw68_video_init1(dev);
+	return 0;
+}
+
+static irqreturn_t tw68_irq(int irq, void *dev_id)
+{
+	struct tw68_dev *dev = dev_id;
+	u32 status, orig;
+	int loop;
+
+	status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask;
+	/* Check if anything to do */
+	if (0 == status)
+		return IRQ_NONE;	/* Nope - return */
+	for (loop = 0; loop < 10; loop++) {
+		if (status & dev->board_virqmask)	/* video interrupt */
+			tw68_irq_video_done(dev, status);
+		status = tw_readl(TW68_INTSTAT) & dev->pci_irqmask;
+		if (0 == status)
+			return IRQ_HANDLED;
+	}
+	dev_dbg(&dev->pci->dev, "%s: **** INTERRUPT NOT HANDLED - clearing mask (orig 0x%08x, cur 0x%08x)",
+			dev->name, orig, tw_readl(TW68_INTSTAT));
+	dev_dbg(&dev->pci->dev, "%s: pci_irqmask 0x%08x; board_virqmask 0x%08x ****\n",
+			dev->name, dev->pci_irqmask, dev->board_virqmask);
+	tw_clearl(TW68_INTMASK, dev->pci_irqmask);
+	return IRQ_HANDLED;
+}
+
+static int tw68_initdev(struct pci_dev *pci_dev,
+				     const struct pci_device_id *pci_id)
+{
+	struct tw68_dev *dev;
+	int vidnr = -1;
+	int err;
+
+	dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev), GFP_KERNEL);
+	if (NULL == dev)
+		return -ENOMEM;
+
+	dev->instance = v4l2_device_set_name(&dev->v4l2_dev, "tw68",
+						&tw68_instance);
+
+	err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
+	if (err)
+		return err;
+
+	/* pci init */
+	dev->pci = pci_dev;
+	if (pci_enable_device(pci_dev)) {
+		err = -EIO;
+		goto fail1;
+	}
+
+	dev->name = dev->v4l2_dev.name;
+
+	if (UNSET != latency) {
+		pr_info("%s: setting pci latency timer to %d\n",
+		       dev->name, latency);
+		pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
+	}
+
+	/* print pci info */
+	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+	pr_info("%s: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n",
+		dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+		dev->pci_lat, (u64)pci_resource_start(pci_dev, 0));
+	pci_set_master(pci_dev);
+	if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) {
+		pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
+		err = -EIO;
+		goto fail1;
+	}
+
+	switch (pci_id->device) {
+	case PCI_DEVICE_ID_6800:	/* TW6800 */
+		dev->vdecoder = TW6800;
+		dev->board_virqmask = TW68_VID_INTS;
+		break;
+	case PCI_DEVICE_ID_6801:	/* Video decoder for TW6802 */
+		dev->vdecoder = TW6801;
+		dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
+		break;
+	case PCI_DEVICE_ID_6804:	/* Video decoder for TW6804 */
+		dev->vdecoder = TW6804;
+		dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
+		break;
+	default:
+		dev->vdecoder = TWXXXX;	/* To be announced */
+		dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
+		break;
+	}
+
+	/* get mmio */
+	if (!request_mem_region(pci_resource_start(pci_dev, 0),
+				pci_resource_len(pci_dev, 0),
+				dev->name)) {
+		err = -EBUSY;
+		pr_err("%s: can't get MMIO memory @ 0x%llx\n",
+			dev->name,
+			(unsigned long long)pci_resource_start(pci_dev, 0));
+		goto fail1;
+	}
+	dev->lmmio = ioremap(pci_resource_start(pci_dev, 0),
+			     pci_resource_len(pci_dev, 0));
+	dev->bmmio = (__u8 __iomem *)dev->lmmio;
+	if (NULL == dev->lmmio) {
+		err = -EIO;
+		pr_err("%s: can't ioremap() MMIO memory\n",
+		       dev->name);
+		goto fail2;
+	}
+	/* initialize hardware #1 */
+	/* Then do any initialisation wanted before interrupts are on */
+	tw68_hw_init1(dev);
+
+	/* get irq */
+	err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq,
+			  IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+	if (err < 0) {
+		pr_err("%s: can't get IRQ %d\n",
+		       dev->name, pci_dev->irq);
+		goto fail3;
+	}
+
+	/*
+	 *  Now do remainder of initialisation, first for
+	 *  things unique for this card, then for general board
+	 */
+	if (dev->instance < TW68_MAXBOARDS)
+		vidnr = video_nr[dev->instance];
+	/* initialise video function first */
+	err = tw68_video_init2(dev, vidnr);
+	if (err < 0) {
+		pr_err("%s: can't register video device\n",
+		       dev->name);
+		goto fail4;
+	}
+	tw_setl(TW68_INTMASK, dev->pci_irqmask);
+
+	pr_info("%s: registered device %s\n",
+	       dev->name, video_device_node_name(&dev->vdev));
+
+	return 0;
+
+fail4:
+	video_unregister_device(&dev->vdev);
+fail3:
+	iounmap(dev->lmmio);
+fail2:
+	release_mem_region(pci_resource_start(pci_dev, 0),
+			   pci_resource_len(pci_dev, 0));
+fail1:
+	v4l2_device_unregister(&dev->v4l2_dev);
+	return err;
+}
+
+static void tw68_finidev(struct pci_dev *pci_dev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+	struct tw68_dev *dev =
+		container_of(v4l2_dev, struct tw68_dev, v4l2_dev);
+
+	/* shutdown subsystems */
+	tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
+	tw_writel(TW68_INTMASK, 0);
+
+	/* unregister */
+	video_unregister_device(&dev->vdev);
+	v4l2_ctrl_handler_free(&dev->hdl);
+
+	/* release resources */
+	iounmap(dev->lmmio);
+	release_mem_region(pci_resource_start(pci_dev, 0),
+			   pci_resource_len(pci_dev, 0));
+
+	v4l2_device_unregister(&dev->v4l2_dev);
+}
+
+#ifdef CONFIG_PM
+
+static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+	struct tw68_dev *dev = container_of(v4l2_dev,
+				struct tw68_dev, v4l2_dev);
+
+	tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
+	dev->pci_irqmask &= ~TW68_VID_INTS;
+	tw_writel(TW68_INTMASK, 0);
+
+	synchronize_irq(pci_dev->irq);
+
+	pci_save_state(pci_dev);
+	pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+	vb2_discard_done(&dev->vidq);
+
+	return 0;
+}
+
+static int tw68_resume(struct pci_dev *pci_dev)
+{
+	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+	struct tw68_dev *dev = container_of(v4l2_dev,
+					    struct tw68_dev, v4l2_dev);
+	struct tw68_buf *buf;
+	unsigned long flags;
+
+	pci_set_power_state(pci_dev, PCI_D0);
+	pci_restore_state(pci_dev);
+
+	/* Do things that are done in tw68_initdev ,
+		except of initializing memory structures.*/
+
+	msleep(100);
+
+	tw68_set_tvnorm_hw(dev);
+
+	/*resume unfinished buffer(s)*/
+	spin_lock_irqsave(&dev->slock, flags);
+	buf = container_of(dev->active.next, struct tw68_buf, list);
+
+	tw68_video_start_dma(dev, buf);
+
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+
+static struct pci_driver tw68_pci_driver = {
+	.name	  = "tw68",
+	.id_table = tw68_pci_tbl,
+	.probe	  = tw68_initdev,
+	.remove	  = tw68_finidev,
+#ifdef CONFIG_PM
+	.suspend  = tw68_suspend,
+	.resume   = tw68_resume
+#endif
+};
+
+module_pci_driver(tw68_pci_driver);
diff --git a/drivers/media/pci/tw68/tw68-reg.h b/drivers/media/pci/tw68/tw68-reg.h
new file mode 100644
index 0000000..f60b3a8
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68-reg.h
@@ -0,0 +1,195 @@
+/*
+ *  tw68-reg.h - TW68xx register offsets
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+*/
+
+#ifndef _TW68_REG_H_
+#define _TW68_REG_H_
+
+/* ---------------------------------------------------------------------- */
+#define	TW68_DMAC		0x000
+#define	TW68_DMAP_SA		0x004
+#define	TW68_DMAP_EXE		0x008
+#define	TW68_DMAP_PP		0x00c
+#define	TW68_VBIC		0x010
+#define	TW68_SBUSC		0x014
+#define	TW68_SBUSSD		0x018
+#define	TW68_INTSTAT		0x01C
+#define	TW68_INTMASK		0x020
+#define	TW68_GPIOC		0x024
+#define	TW68_GPOE		0x028
+#define	TW68_TESTREG		0x02C
+#define	TW68_SBUSRD		0x030
+#define	TW68_SBUS_TRIG		0x034
+#define	TW68_CAP_CTL		0x040
+#define	TW68_SUBSYS		0x054
+#define	TW68_I2C_RST		0x064
+#define	TW68_VBIINST		0x06C
+/* define bits in FIFO and DMAP Control reg */
+#define	TW68_DMAP_EN		(1 << 0)
+#define	TW68_FIFO_EN		(1 << 1)
+/* define the Interrupt Status Register bits */
+#define	TW68_SBDONE		(1 << 0)
+#define	TW68_DMAPI		(1 << 1)
+#define	TW68_GPINT		(1 << 2)
+#define	TW68_FFOF		(1 << 3)
+#define	TW68_FDMIS		(1 << 4)
+#define	TW68_DMAPERR		(1 << 5)
+#define	TW68_PABORT		(1 << 6)
+#define	TW68_SBDONE2		(1 << 12)
+#define	TW68_SBERR2		(1 << 13)
+#define	TW68_PPERR		(1 << 14)
+#define	TW68_FFERR		(1 << 15)
+#define	TW68_DET50		(1 << 16)
+#define	TW68_FLOCK		(1 << 17)
+#define	TW68_CCVALID		(1 << 18)
+#define	TW68_VLOCK		(1 << 19)
+#define	TW68_FIELD		(1 << 20)
+#define	TW68_SLOCK		(1 << 21)
+#define	TW68_HLOCK		(1 << 22)
+#define	TW68_VDLOSS		(1 << 23)
+#define	TW68_SBERR		(1 << 24)
+/* define the i2c control register bits */
+#define	TW68_SBMODE		(0)
+#define	TW68_WREN		(1)
+#define	TW68_SSCLK		(6)
+#define	TW68_SSDAT		(7)
+#define	TW68_SBCLK		(8)
+#define	TW68_WDLEN		(16)
+#define	TW68_RDLEN		(20)
+#define	TW68_SBRW		(24)
+#define	TW68_SBDEV		(25)
+
+#define	TW68_SBMODE_B		(1 << TW68_SBMODE)
+#define	TW68_WREN_B		(1 << TW68_WREN)
+#define	TW68_SSCLK_B		(1 << TW68_SSCLK)
+#define	TW68_SSDAT_B		(1 << TW68_SSDAT)
+#define	TW68_SBRW_B		(1 << TW68_SBRW)
+
+#define	TW68_GPDATA		0x100
+#define	TW68_STATUS1		0x204
+#define	TW68_INFORM		0x208
+#define	TW68_OPFORM		0x20C
+#define	TW68_HSYNC		0x210
+#define	TW68_ACNTL		0x218
+#define	TW68_CROP_HI		0x21C
+#define	TW68_VDELAY_LO		0x220
+#define	TW68_VACTIVE_LO		0x224
+#define	TW68_HDELAY_LO		0x228
+#define	TW68_HACTIVE_LO		0x22C
+#define	TW68_CNTRL1		0x230
+#define	TW68_VSCALE_LO		0x234
+#define	TW68_SCALE_HI		0x238
+#define	TW68_HSCALE_LO		0x23C
+#define	TW68_BRIGHT		0x240
+#define	TW68_CONTRAST		0x244
+#define	TW68_SHARPNESS		0x248
+#define	TW68_SAT_U		0x24C
+#define	TW68_SAT_V		0x250
+#define	TW68_HUE		0x254
+#define	TW68_SHARP2		0x258
+#define	TW68_VSHARP		0x25C
+#define	TW68_CORING		0x260
+#define	TW68_VBICNTL		0x264
+#define	TW68_CNTRL2		0x268
+#define	TW68_CC_DATA		0x26C
+#define	TW68_SDT		0x270
+#define	TW68_SDTR		0x274
+#define	TW68_RESERV2		0x278
+#define	TW68_RESERV3		0x27C
+#define	TW68_CLMPG		0x280
+#define	TW68_IAGC		0x284
+#define	TW68_AGCGAIN		0x288
+#define	TW68_PEAKWT		0x28C
+#define	TW68_CLMPL		0x290
+#define	TW68_SYNCT		0x294
+#define	TW68_MISSCNT		0x298
+#define	TW68_PCLAMP		0x29C
+#define	TW68_VCNTL1		0x2A0
+#define	TW68_VCNTL2		0x2A4
+#define	TW68_CKILL		0x2A8
+#define	TW68_COMB		0x2AC
+#define	TW68_LDLY		0x2B0
+#define	TW68_MISC1		0x2B4
+#define	TW68_LOOP		0x2B8
+#define	TW68_MISC2		0x2BC
+#define	TW68_MVSN		0x2C0
+#define	TW68_STATUS2		0x2C4
+#define	TW68_HFREF		0x2C8
+#define	TW68_CLMD		0x2CC
+#define	TW68_IDCNTL		0x2D0
+#define	TW68_CLCNTL1		0x2D4
+
+/* Audio */
+#define	TW68_ACKI1		0x300
+#define	TW68_ACKI2		0x304
+#define	TW68_ACKI3		0x308
+#define	TW68_ACKN1		0x30C
+#define	TW68_ACKN2		0x310
+#define	TW68_ACKN3		0x314
+#define	TW68_SDIV		0x318
+#define	TW68_LRDIV		0x31C
+#define	TW68_ACCNTL		0x320
+
+#define	TW68_VSCTL		0x3B8
+#define	TW68_CHROMAGVAL		0x3BC
+
+#define	TW68_F2CROP_HI		0x3DC
+#define	TW68_F2VDELAY_LO	0x3E0
+#define	TW68_F2VACTIVE_LO	0x3E4
+#define	TW68_F2HDELAY_LO	0x3E8
+#define	TW68_F2HACTIVE_LO	0x3EC
+#define	TW68_F2CNT		0x3F0
+#define	TW68_F2VSCALE_LO	0x3F4
+#define	TW68_F2SCALE_HI		0x3F8
+#define	TW68_F2HSCALE_LO	0x3FC
+
+#define	RISC_INT_BIT		0x08000000
+#define	RISC_SYNCO		0xC0000000
+#define	RISC_SYNCE		0xD0000000
+#define	RISC_JUMP		0xB0000000
+#define	RISC_LINESTART		0x90000000
+#define	RISC_INLINE		0xA0000000
+
+#define VideoFormatNTSC		 0
+#define VideoFormatNTSCJapan	 0
+#define VideoFormatPALBDGHI	 1
+#define VideoFormatSECAM	 2
+#define VideoFormatNTSC443	 3
+#define VideoFormatPALM		 4
+#define VideoFormatPALN		 5
+#define VideoFormatPALNC	 5
+#define VideoFormatPAL60	 6
+#define VideoFormatAuto		 7
+
+#define ColorFormatRGB32	 0x00
+#define ColorFormatRGB24	 0x10
+#define ColorFormatRGB16	 0x20
+#define ColorFormatRGB15	 0x30
+#define ColorFormatYUY2		 0x40
+#define ColorFormatBSWAP         0x04
+#define ColorFormatWSWAP         0x08
+#define ColorFormatGamma         0x80
+#endif
diff --git a/drivers/media/pci/tw68/tw68-risc.c b/drivers/media/pci/tw68/tw68-risc.c
new file mode 100644
index 0000000..7439db2
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68-risc.c
@@ -0,0 +1,230 @@
+/*
+ *  tw68_risc.c
+ *  Part of the device driver for Techwell 68xx based cards
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) 2009  William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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 "tw68.h"
+
+/**
+ *  @rp		pointer to current risc program position
+ *  @sglist	pointer to "scatter-gather list" of buffer pointers
+ *  @offset	offset to target memory buffer
+ *  @sync_line	0 -> no sync, 1 -> odd sync, 2 -> even sync
+ *  @bpl	number of bytes per scan line
+ *  @padding	number of bytes of padding to add
+ *  @lines	number of lines in field
+ *  @jump	insert a jump at the start
+ */
+static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist,
+			    unsigned int offset, u32 sync_line,
+			    unsigned int bpl, unsigned int padding,
+			    unsigned int lines, bool jump)
+{
+	struct scatterlist *sg;
+	unsigned int line, todo, done;
+
+	if (jump) {
+		*(rp++) = cpu_to_le32(RISC_JUMP);
+		*(rp++) = 0;
+	}
+
+	/* sync instruction */
+	if (sync_line == 1)
+		*(rp++) = cpu_to_le32(RISC_SYNCO);
+	else
+		*(rp++) = cpu_to_le32(RISC_SYNCE);
+	*(rp++) = 0;
+
+	/* scan lines */
+	sg = sglist;
+	for (line = 0; line < lines; line++) {
+		/* calculate next starting position */
+		while (offset && offset >= sg_dma_len(sg)) {
+			offset -= sg_dma_len(sg);
+			sg = sg_next(sg);
+		}
+		if (bpl <= sg_dma_len(sg) - offset) {
+			/* fits into current chunk */
+			*(rp++) = cpu_to_le32(RISC_LINESTART |
+					      /* (offset<<12) |*/  bpl);
+			*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
+			offset += bpl;
+		} else {
+			/*
+			 * scanline needs to be split.  Put the start in
+			 * whatever memory remains using RISC_LINESTART,
+			 * then the remainder into following addresses
+			 * given by the scatter-gather list.
+			 */
+			todo = bpl;	/* one full line to be done */
+			/* first fragment */
+			done = (sg_dma_len(sg) - offset);
+			*(rp++) = cpu_to_le32(RISC_LINESTART |
+						(7 << 24) |
+						done);
+			*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
+			todo -= done;
+			sg = sg_next(sg);
+			/* succeeding fragments have no offset */
+			while (todo > sg_dma_len(sg)) {
+				*(rp++) = cpu_to_le32(RISC_INLINE |
+						(done << 12) |
+						sg_dma_len(sg));
+				*(rp++) = cpu_to_le32(sg_dma_address(sg));
+				todo -= sg_dma_len(sg);
+				sg = sg_next(sg);
+				done += sg_dma_len(sg);
+			}
+			if (todo) {
+				/* final chunk - offset 0, count 'todo' */
+				*(rp++) = cpu_to_le32(RISC_INLINE |
+							(done << 12) |
+							todo);
+				*(rp++) = cpu_to_le32(sg_dma_address(sg));
+			}
+			offset = todo;
+		}
+		offset += padding;
+	}
+
+	return rp;
+}
+
+/**
+ * tw68_risc_buffer
+ *
+ *	This routine is called by tw68-video.  It allocates
+ *	memory for the dma controller "program" and then fills in that
+ *	memory with the appropriate "instructions".
+ *
+ *	@pci_dev	structure with info about the pci
+ *			slot which our device is in.
+ *	@risc		structure with info about the memory
+ *			used for our controller program.
+ *	@sglist		scatter-gather list entry
+ *	@top_offset	offset within the risc program area for the
+ *			first odd frame line
+ *	@bottom_offset	offset within the risc program area for the
+ *			first even frame line
+ *	@bpl		number of data bytes per scan line
+ *	@padding	number of extra bytes to add at end of line
+ *	@lines		number of scan lines
+ */
+int tw68_risc_buffer(struct pci_dev *pci,
+			struct tw68_buf *buf,
+			struct scatterlist *sglist,
+			unsigned int top_offset,
+			unsigned int bottom_offset,
+			unsigned int bpl,
+			unsigned int padding,
+			unsigned int lines)
+{
+	u32 instructions, fields;
+	__le32 *rp;
+
+	fields = 0;
+	if (UNSET != top_offset)
+		fields++;
+	if (UNSET != bottom_offset)
+		fields++;
+	/*
+	 * estimate risc mem: worst case is one write per page border +
+	 * one write per scan line + syncs + 2 jumps (all 2 dwords).
+	 * Padding can cause next bpl to start close to a page border.
+	 * First DMA region may be smaller than PAGE_SIZE
+	 */
+	instructions  = fields * (1 + (((bpl + padding) * lines) /
+			 PAGE_SIZE) + lines) + 4;
+	buf->size = instructions * 8;
+	buf->cpu = pci_alloc_consistent(pci, buf->size, &buf->dma);
+	if (buf->cpu == NULL)
+		return -ENOMEM;
+
+	/* write risc instructions */
+	rp = buf->cpu;
+	if (UNSET != top_offset)	/* generates SYNCO */
+		rp = tw68_risc_field(rp, sglist, top_offset, 1,
+				     bpl, padding, lines, true);
+	if (UNSET != bottom_offset)	/* generates SYNCE */
+		rp = tw68_risc_field(rp, sglist, bottom_offset, 2,
+				     bpl, padding, lines, top_offset == UNSET);
+
+	/* save pointer to jmp instruction address */
+	buf->jmp = rp;
+	buf->cpu[1] = cpu_to_le32(buf->dma + 8);
+	/* assure risc buffer hasn't overflowed */
+	BUG_ON((buf->jmp - buf->cpu + 2) * sizeof(buf->cpu[0]) > buf->size);
+	return 0;
+}
+
+#if 0
+/* ------------------------------------------------------------------ */
+/* debug helper code                                                  */
+
+static void tw68_risc_decode(u32 risc, u32 addr)
+{
+#define	RISC_OP(reg)	(((reg) >> 28) & 7)
+	static struct instr_details {
+		char *name;
+		u8 has_data_type;
+		u8 has_byte_info;
+		u8 has_addr;
+	} instr[8] = {
+		[RISC_OP(RISC_SYNCO)]	  = {"syncOdd", 0, 0, 0},
+		[RISC_OP(RISC_SYNCE)]	  = {"syncEven", 0, 0, 0},
+		[RISC_OP(RISC_JUMP)]	  = {"jump", 0, 0, 1},
+		[RISC_OP(RISC_LINESTART)] = {"lineStart", 1, 1, 1},
+		[RISC_OP(RISC_INLINE)]	  = {"inline", 1, 1, 1},
+	};
+	u32 p;
+
+	p = RISC_OP(risc);
+	if (!(risc & 0x80000000) || !instr[p].name) {
+		pr_debug("0x%08x [ INVALID ]\n", risc);
+		return;
+	}
+	pr_debug("0x%08x %-9s IRQ=%d",
+		risc, instr[p].name, (risc >> 27) & 1);
+	if (instr[p].has_data_type)
+		pr_debug(" Type=%d", (risc >> 24) & 7);
+	if (instr[p].has_byte_info)
+		pr_debug(" Start=0x%03x Count=%03u",
+			(risc >> 12) & 0xfff, risc & 0xfff);
+	if (instr[p].has_addr)
+		pr_debug(" StartAddr=0x%08x", addr);
+	pr_debug("\n");
+}
+
+void tw68_risc_program_dump(struct tw68_core *core, struct tw68_buf *buf)
+{
+	const __le32 *addr;
+
+	pr_debug("%s: risc_program_dump: risc=%p, buf->cpu=0x%p, buf->jmp=0x%p\n",
+		  core->name, buf, buf->cpu, buf->jmp);
+	for (addr = buf->cpu; addr <= buf->jmp; addr += 2)
+		tw68_risc_decode(*addr, *(addr+1));
+}
+#endif
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c
new file mode 100644
index 0000000..25f0cc8
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68-video.c
@@ -0,0 +1,1051 @@
+/*
+ *  tw68 functions to handle video data
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) 2009  William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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/module.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "tw68.h"
+#include "tw68-reg.h"
+
+/* ------------------------------------------------------------------ */
+/* data structs for video                                             */
+/*
+ * FIXME -
+ * Note that the saa7134 has formats, e.g. YUV420, which are classified
+ * as "planar".  These affect overlay mode, and are flagged with a field
+ * ".planar" in the format.  Do we need to implement this in this driver?
+ */
+static const struct tw68_format formats[] = {
+	{
+		.name		= "15 bpp RGB, le",
+		.fourcc		= V4L2_PIX_FMT_RGB555,
+		.depth		= 16,
+		.twformat	= ColorFormatRGB15,
+	}, {
+		.name		= "15 bpp RGB, be",
+		.fourcc		= V4L2_PIX_FMT_RGB555X,
+		.depth		= 16,
+		.twformat	= ColorFormatRGB15 | ColorFormatBSWAP,
+	}, {
+		.name		= "16 bpp RGB, le",
+		.fourcc		= V4L2_PIX_FMT_RGB565,
+		.depth		= 16,
+		.twformat	= ColorFormatRGB16,
+	}, {
+		.name		= "16 bpp RGB, be",
+		.fourcc		= V4L2_PIX_FMT_RGB565X,
+		.depth		= 16,
+		.twformat	= ColorFormatRGB16 | ColorFormatBSWAP,
+	}, {
+		.name		= "24 bpp RGB, le",
+		.fourcc		= V4L2_PIX_FMT_BGR24,
+		.depth		= 24,
+		.twformat	= ColorFormatRGB24,
+	}, {
+		.name		= "24 bpp RGB, be",
+		.fourcc		= V4L2_PIX_FMT_RGB24,
+		.depth		= 24,
+		.twformat	= ColorFormatRGB24 | ColorFormatBSWAP,
+	}, {
+		.name		= "32 bpp RGB, le",
+		.fourcc		= V4L2_PIX_FMT_BGR32,
+		.depth		= 32,
+		.twformat	= ColorFormatRGB32,
+	}, {
+		.name		= "32 bpp RGB, be",
+		.fourcc		= V4L2_PIX_FMT_RGB32,
+		.depth		= 32,
+		.twformat	= ColorFormatRGB32 | ColorFormatBSWAP |
+				  ColorFormatWSWAP,
+	}, {
+		.name		= "4:2:2 packed, YUYV",
+		.fourcc		= V4L2_PIX_FMT_YUYV,
+		.depth		= 16,
+		.twformat	= ColorFormatYUY2,
+	}, {
+		.name		= "4:2:2 packed, UYVY",
+		.fourcc		= V4L2_PIX_FMT_UYVY,
+		.depth		= 16,
+		.twformat	= ColorFormatYUY2 | ColorFormatBSWAP,
+	}
+};
+#define FORMATS ARRAY_SIZE(formats)
+
+#define NORM_625_50			\
+		.h_delay	= 3,	\
+		.h_delay0	= 133,	\
+		.h_start	= 0,	\
+		.h_stop		= 719,	\
+		.v_delay	= 24,	\
+		.vbi_v_start_0	= 7,	\
+		.vbi_v_stop_0	= 22,	\
+		.video_v_start	= 24,	\
+		.video_v_stop	= 311,	\
+		.vbi_v_start_1	= 319
+
+#define NORM_525_60			\
+		.h_delay	= 8,	\
+		.h_delay0	= 138,	\
+		.h_start	= 0,	\
+		.h_stop		= 719,	\
+		.v_delay	= 22,	\
+		.vbi_v_start_0	= 10,	\
+		.vbi_v_stop_0	= 21,	\
+		.video_v_start	= 22,	\
+		.video_v_stop	= 262,	\
+		.vbi_v_start_1	= 273
+
+/*
+ * The following table is searched by tw68_s_std, first for a specific
+ * match, then for an entry which contains the desired id.  The table
+ * entries should therefore be ordered in ascending order of specificity.
+ */
+static const struct tw68_tvnorm tvnorms[] = {
+	{
+		.name		= "PAL", /* autodetect */
+		.id		= V4L2_STD_PAL,
+		NORM_625_50,
+
+		.sync_control	= 0x18,
+		.luma_control	= 0x40,
+		.chroma_ctrl1	= 0x81,
+		.chroma_gain	= 0x2a,
+		.chroma_ctrl2	= 0x06,
+		.vgate_misc	= 0x1c,
+		.format		= VideoFormatPALBDGHI,
+	}, {
+		.name		= "NTSC",
+		.id		= V4L2_STD_NTSC,
+		NORM_525_60,
+
+		.sync_control	= 0x59,
+		.luma_control	= 0x40,
+		.chroma_ctrl1	= 0x89,
+		.chroma_gain	= 0x2a,
+		.chroma_ctrl2	= 0x0e,
+		.vgate_misc	= 0x18,
+		.format		= VideoFormatNTSC,
+	}, {
+		.name		= "SECAM",
+		.id		= V4L2_STD_SECAM,
+		NORM_625_50,
+
+		.sync_control	= 0x18,
+		.luma_control	= 0x1b,
+		.chroma_ctrl1	= 0xd1,
+		.chroma_gain	= 0x80,
+		.chroma_ctrl2	= 0x00,
+		.vgate_misc	= 0x1c,
+		.format		= VideoFormatSECAM,
+	}, {
+		.name		= "PAL-M",
+		.id		= V4L2_STD_PAL_M,
+		NORM_525_60,
+
+		.sync_control	= 0x59,
+		.luma_control	= 0x40,
+		.chroma_ctrl1	= 0xb9,
+		.chroma_gain	= 0x2a,
+		.chroma_ctrl2	= 0x0e,
+		.vgate_misc	= 0x18,
+		.format		= VideoFormatPALM,
+	}, {
+		.name		= "PAL-Nc",
+		.id		= V4L2_STD_PAL_Nc,
+		NORM_625_50,
+
+		.sync_control	= 0x18,
+		.luma_control	= 0x40,
+		.chroma_ctrl1	= 0xa1,
+		.chroma_gain	= 0x2a,
+		.chroma_ctrl2	= 0x06,
+		.vgate_misc	= 0x1c,
+		.format		= VideoFormatPALNC,
+	}, {
+		.name		= "PAL-60",
+		.id		= V4L2_STD_PAL_60,
+		.h_delay	= 186,
+		.h_start	= 0,
+		.h_stop		= 719,
+		.v_delay	= 26,
+		.video_v_start	= 23,
+		.video_v_stop	= 262,
+		.vbi_v_start_0	= 10,
+		.vbi_v_stop_0	= 21,
+		.vbi_v_start_1	= 273,
+
+		.sync_control	= 0x18,
+		.luma_control	= 0x40,
+		.chroma_ctrl1	= 0x81,
+		.chroma_gain	= 0x2a,
+		.chroma_ctrl2	= 0x06,
+		.vgate_misc	= 0x1c,
+		.format		= VideoFormatPAL60,
+	}
+};
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+static const struct tw68_format *format_by_fourcc(unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < FORMATS; i++)
+		if (formats[i].fourcc == fourcc)
+			return formats+i;
+	return NULL;
+}
+
+
+/* ------------------------------------------------------------------ */
+/*
+ * Note that the cropping rectangles are described in terms of a single
+ * frame, i.e. line positions are only 1/2 the interlaced equivalent
+ */
+static void set_tvnorm(struct tw68_dev *dev, const struct tw68_tvnorm *norm)
+{
+	if (norm != dev->tvnorm) {
+		dev->width = 720;
+		dev->height = (norm->id & V4L2_STD_525_60) ? 480 : 576;
+		dev->tvnorm = norm;
+		tw68_set_tvnorm_hw(dev);
+	}
+}
+
+/*
+ * tw68_set_scale
+ *
+ * Scaling and Cropping for video decoding
+ *
+ * We are working with 3 values for horizontal and vertical - scale,
+ * delay and active.
+ *
+ * HACTIVE represent the actual number of pixels in the "usable" image,
+ * before scaling.  HDELAY represents the number of pixels skipped
+ * between the start of the horizontal sync and the start of the image.
+ * HSCALE is calculated using the formula
+ *	HSCALE = (HACTIVE / (#pixels desired)) * 256
+ *
+ * The vertical registers are similar, except based upon the total number
+ * of lines in the image, and the first line of the image (i.e. ignoring
+ * vertical sync and VBI).
+ *
+ * Note that the number of bytes reaching the FIFO (and hence needing
+ * to be processed by the DMAP program) is completely dependent upon
+ * these values, especially HSCALE.
+ *
+ * Parameters:
+ *	@dev		pointer to the device structure, needed for
+ *			getting current norm (as well as debug print)
+ *	@width		actual image width (from user buffer)
+ *	@height		actual image height
+ *	@field		indicates Top, Bottom or Interlaced
+ */
+static int tw68_set_scale(struct tw68_dev *dev, unsigned int width,
+			  unsigned int height, enum v4l2_field field)
+{
+	const struct tw68_tvnorm *norm = dev->tvnorm;
+	/* set individually for debugging clarity */
+	int hactive, hdelay, hscale;
+	int vactive, vdelay, vscale;
+	int comb;
+
+	if (V4L2_FIELD_HAS_BOTH(field))	/* if field is interlaced */
+		height /= 2;		/* we must set for 1-frame */
+
+	pr_debug("%s: width=%d, height=%d, both=%d\n"
+		 "  tvnorm h_delay=%d, h_start=%d, h_stop=%d, "
+		 "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__,
+		width, height, V4L2_FIELD_HAS_BOTH(field),
+		norm->h_delay, norm->h_start, norm->h_stop,
+		norm->v_delay, norm->video_v_start,
+		norm->video_v_stop);
+
+	switch (dev->vdecoder) {
+	case TW6800:
+		hdelay = norm->h_delay0;
+		break;
+	default:
+		hdelay = norm->h_delay;
+		break;
+	}
+
+	hdelay += norm->h_start;
+	hactive = norm->h_stop - norm->h_start + 1;
+
+	hscale = (hactive * 256) / (width);
+
+	vdelay = norm->v_delay;
+	vactive = ((norm->id & V4L2_STD_525_60) ? 524 : 624) / 2 - norm->video_v_start;
+	vscale = (vactive * 256) / height;
+
+	pr_debug("%s: %dx%d [%s%s,%s]\n", __func__,
+		width, height,
+		V4L2_FIELD_HAS_TOP(field)    ? "T" : "",
+		V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
+		v4l2_norm_to_name(dev->tvnorm->id));
+	pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; "
+		"vactive=%d, vdelay=%d, vscale=%d\n", __func__,
+		hactive, hdelay, hscale, vactive, vdelay, vscale);
+
+	comb =	((vdelay & 0x300)  >> 2) |
+		((vactive & 0x300) >> 4) |
+		((hdelay & 0x300)  >> 6) |
+		((hactive & 0x300) >> 8);
+	pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, "
+		"VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n",
+		__func__, comb, vdelay, vactive, hdelay, hactive);
+	tw_writeb(TW68_CROP_HI, comb);
+	tw_writeb(TW68_VDELAY_LO, vdelay & 0xff);
+	tw_writeb(TW68_VACTIVE_LO, vactive & 0xff);
+	tw_writeb(TW68_HDELAY_LO, hdelay & 0xff);
+	tw_writeb(TW68_HACTIVE_LO, hactive & 0xff);
+
+	comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8);
+	pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, "
+		"HSCALE_LO=%02x\n", __func__, comb, vscale, hscale);
+	tw_writeb(TW68_SCALE_HI, comb);
+	tw_writeb(TW68_VSCALE_LO, vscale);
+	tw_writeb(TW68_HSCALE_LO, hscale);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf)
+{
+	/* Set cropping and scaling */
+	tw68_set_scale(dev, dev->width, dev->height, dev->field);
+	/*
+	 *  Set start address for RISC program.  Note that if the DMAP
+	 *  processor is currently running, it must be stopped before
+	 *  a new address can be set.
+	 */
+	tw_clearl(TW68_DMAC, TW68_DMAP_EN);
+	tw_writel(TW68_DMAP_SA, buf->dma);
+	/* Clear any pending interrupts */
+	tw_writel(TW68_INTSTAT, dev->board_virqmask);
+	/* Enable the risc engine and the fifo */
+	tw_andorl(TW68_DMAC, 0xff, dev->fmt->twformat |
+		ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN);
+	dev->pci_irqmask |= dev->board_virqmask;
+	tw_setl(TW68_INTMASK, dev->pci_irqmask);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+/* calc max # of buffers from size (must not exceed the 4MB virtual
+ * address space per DMA channel) */
+static int tw68_buffer_count(unsigned int size, unsigned int count)
+{
+	unsigned int maxcount;
+
+	maxcount = (4 * 1024 * 1024) / roundup(size, PAGE_SIZE);
+	if (count > maxcount)
+		count = maxcount;
+	return count;
+}
+
+/* ------------------------------------------------------------- */
+/* vb2 queue operations                                          */
+
+static int tw68_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+			   unsigned int *num_buffers, unsigned int *num_planes,
+			   unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct tw68_dev *dev = vb2_get_drv_priv(q);
+	unsigned tot_bufs = q->num_buffers + *num_buffers;
+
+	sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3;
+	/*
+	 * We allow create_bufs, but only if the sizeimage is the same as the
+	 * current sizeimage. The tw68_buffer_count calculation becomes quite
+	 * difficult otherwise.
+	 */
+	if (fmt && fmt->fmt.pix.sizeimage < sizes[0])
+		return -EINVAL;
+	*num_planes = 1;
+	if (tot_bufs < 2)
+		tot_bufs = 2;
+	tot_bufs = tw68_buffer_count(sizes[0], tot_bufs);
+	*num_buffers = tot_bufs - q->num_buffers;
+
+	return 0;
+}
+
+/*
+ * The risc program for each buffers works as follows: it starts with a simple
+ * 'JUMP to addr + 8', which is effectively a NOP. Then the program to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 8 (skipping
+ * the initial JUMP).
+ *
+ * This is the program of the first buffer to be queued if the active list is
+ * empty and it just keeps DMAing this buffer without generating any interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the program generates an
+ * interrupt as well which signals that the previous buffer has been DMAed
+ * successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
+static void tw68_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct tw68_dev *dev = vb2_get_drv_priv(vq);
+	struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
+	struct tw68_buf *prev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->slock, flags);
+
+	/* append a 'JUMP to start of buffer' to the buffer risc program */
+	buf->jmp[0] = cpu_to_le32(RISC_JUMP);
+	buf->jmp[1] = cpu_to_le32(buf->dma + 8);
+
+	if (!list_empty(&dev->active)) {
+		prev = list_entry(dev->active.prev, struct tw68_buf, list);
+		buf->cpu[0] |= cpu_to_le32(RISC_INT_BIT);
+		prev->jmp[1] = cpu_to_le32(buf->dma);
+	}
+	list_add_tail(&buf->list, &dev->active);
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+/*
+ * buffer_prepare
+ *
+ * Set the ancilliary information into the buffer structure.  This
+ * includes generating the necessary risc program if it hasn't already
+ * been done for the current buffer format.
+ * The structure fh contains the details of the format requested by the
+ * user - type, width, height and #fields.  This is compared with the
+ * last format set for the current buffer.  If they differ, the risc
+ * code (which controls the filling of the buffer) is (re-)generated.
+ */
+static int tw68_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct tw68_dev *dev = vb2_get_drv_priv(vq);
+	struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
+	struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);
+	unsigned size, bpl;
+	int rc;
+
+	size = (dev->width * dev->height * dev->fmt->depth) >> 3;
+	if (vb2_plane_size(vb, 0) < size)
+		return -EINVAL;
+	vb2_set_plane_payload(vb, 0, size);
+
+	rc = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+	if (!rc)
+		return -EIO;
+
+	bpl = (dev->width * dev->fmt->depth) >> 3;
+	switch (dev->field) {
+	case V4L2_FIELD_TOP:
+		tw68_risc_buffer(dev->pci, buf, dma->sgl,
+				 0, UNSET, bpl, 0, dev->height);
+		break;
+	case V4L2_FIELD_BOTTOM:
+		tw68_risc_buffer(dev->pci, buf, dma->sgl,
+				 UNSET, 0, bpl, 0, dev->height);
+		break;
+	case V4L2_FIELD_SEQ_TB:
+		tw68_risc_buffer(dev->pci, buf, dma->sgl,
+				 0, bpl * (dev->height >> 1),
+				 bpl, 0, dev->height >> 1);
+		break;
+	case V4L2_FIELD_SEQ_BT:
+		tw68_risc_buffer(dev->pci, buf, dma->sgl,
+				 bpl * (dev->height >> 1), 0,
+				 bpl, 0, dev->height >> 1);
+		break;
+	case V4L2_FIELD_INTERLACED:
+	default:
+		tw68_risc_buffer(dev->pci, buf, dma->sgl,
+				 0, bpl, bpl, bpl, dev->height >> 1);
+		break;
+	}
+	return 0;
+}
+
+static void tw68_buf_finish(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct tw68_dev *dev = vb2_get_drv_priv(vq);
+	struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);
+	struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
+
+	dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+
+	pci_free_consistent(dev->pci, buf->size, buf->cpu, buf->dma);
+}
+
+static int tw68_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct tw68_dev *dev = vb2_get_drv_priv(q);
+	struct tw68_buf *buf =
+		container_of(dev->active.next, struct tw68_buf, list);
+
+	dev->seqnr = 0;
+	tw68_video_start_dma(dev, buf);
+	return 0;
+}
+
+static void tw68_stop_streaming(struct vb2_queue *q)
+{
+	struct tw68_dev *dev = vb2_get_drv_priv(q);
+
+	/* Stop risc & fifo */
+	tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
+	while (!list_empty(&dev->active)) {
+		struct tw68_buf *buf =
+			container_of(dev->active.next, struct tw68_buf, list);
+
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+}
+
+static struct vb2_ops tw68_video_qops = {
+	.queue_setup	= tw68_queue_setup,
+	.buf_queue	= tw68_buf_queue,
+	.buf_prepare	= tw68_buf_prepare,
+	.buf_finish	= tw68_buf_finish,
+	.start_streaming = tw68_start_streaming,
+	.stop_streaming = tw68_stop_streaming,
+	.wait_prepare	= vb2_ops_wait_prepare,
+	.wait_finish	= vb2_ops_wait_finish,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int tw68_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct tw68_dev *dev =
+		container_of(ctrl->handler, struct tw68_dev, hdl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		tw_writeb(TW68_BRIGHT, ctrl->val);
+		break;
+	case V4L2_CID_HUE:
+		tw_writeb(TW68_HUE, ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		tw_writeb(TW68_CONTRAST, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		tw_writeb(TW68_SAT_U, ctrl->val);
+		tw_writeb(TW68_SAT_V, ctrl->val);
+		break;
+	case V4L2_CID_COLOR_KILLER:
+		if (ctrl->val)
+			tw_andorb(TW68_MISC2, 0xe0, 0xe0);
+		else
+			tw_andorb(TW68_MISC2, 0xe0, 0x00);
+		break;
+	case V4L2_CID_CHROMA_AGC:
+		if (ctrl->val)
+			tw_andorb(TW68_LOOP, 0x30, 0x20);
+		else
+			tw_andorb(TW68_LOOP, 0x30, 0x00);
+		break;
+	}
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * Note that this routine returns what is stored in the fh structure, and
+ * does not interrogate any of the device registers.
+ */
+static int tw68_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct tw68_dev *dev = video_drvdata(file);
+
+	f->fmt.pix.width        = dev->width;
+	f->fmt.pix.height       = dev->height;
+	f->fmt.pix.field        = dev->field;
+	f->fmt.pix.pixelformat  = dev->fmt->fourcc;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * (dev->fmt->depth)) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	f->fmt.pix.colorspace	= V4L2_COLORSPACE_SMPTE170M;
+	f->fmt.pix.priv = 0;
+	return 0;
+}
+
+static int tw68_try_fmt_vid_cap(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	struct tw68_dev *dev = video_drvdata(file);
+	const struct tw68_format *fmt;
+	enum v4l2_field field;
+	unsigned int maxh;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+
+	field = f->fmt.pix.field;
+	maxh  = (dev->tvnorm->id & V4L2_STD_525_60) ? 480 : 576;
+
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		break;
+	case V4L2_FIELD_INTERLACED:
+	case V4L2_FIELD_SEQ_BT:
+	case V4L2_FIELD_SEQ_TB:
+		maxh = maxh * 2;
+		break;
+	default:
+		field = (f->fmt.pix.height > maxh / 2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_BOTTOM;
+		break;
+	}
+
+	f->fmt.pix.field = field;
+	if (f->fmt.pix.width  < 48)
+		f->fmt.pix.width  = 48;
+	if (f->fmt.pix.height < 32)
+		f->fmt.pix.height = 32;
+	if (f->fmt.pix.width > 720)
+		f->fmt.pix.width = 720;
+	if (f->fmt.pix.height > maxh)
+		f->fmt.pix.height = maxh;
+	f->fmt.pix.width &= ~0x03;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * (fmt->depth)) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	return 0;
+}
+
+/*
+ * Note that tw68_s_fmt_vid_cap sets the information into the fh structure,
+ * and it will be used for all future new buffers.  However, there could be
+ * some number of buffers on the "active" chain which will be filled before
+ * the change takes place.
+ */
+static int tw68_s_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct tw68_dev *dev = video_drvdata(file);
+	int err;
+
+	err = tw68_try_fmt_vid_cap(file, priv, f);
+	if (0 != err)
+		return err;
+
+	dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	dev->width = f->fmt.pix.width;
+	dev->height = f->fmt.pix.height;
+	dev->field = f->fmt.pix.field;
+	return 0;
+}
+
+static int tw68_enum_input(struct file *file, void *priv,
+					struct v4l2_input *i)
+{
+	struct tw68_dev *dev = video_drvdata(file);
+	unsigned int n;
+
+	n = i->index;
+	if (n >= TW68_INPUT_MAX)
+		return -EINVAL;
+	i->index = n;
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+	snprintf(i->name, sizeof(i->name), "Composite %d", n);
+
+	/* If the query is for the current input, get live data */
+	if (n == dev->input) {
+		int v1 = tw_readb(TW68_STATUS1);
+		int v2 = tw_readb(TW68_MVSN);
+
+		if (0 != (v1 & (1 << 7)))
+			i->status |= V4L2_IN_ST_NO_SYNC;
+		if (0 != (v1 & (1 << 6)))
+			i->status |= V4L2_IN_ST_NO_H_LOCK;
+		if (0 != (v1 & (1 << 2)))
+			i->status |= V4L2_IN_ST_NO_SIGNAL;
+		if (0 != (v1 & 1 << 1))
+			i->status |= V4L2_IN_ST_NO_COLOR;
+		if (0 != (v2 & (1 << 2)))
+			i->status |= V4L2_IN_ST_MACROVISION;
+	}
+	i->std = video_devdata(file)->tvnorms;
+	return 0;
+}
+
+static int tw68_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct tw68_dev *dev = video_drvdata(file);
+
+	*i = dev->input;
+	return 0;
+}
+
+static int tw68_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct tw68_dev *dev = video_drvdata(file);
+
+	if (i >= TW68_INPUT_MAX)
+		return -EINVAL;
+	dev->input = i;
+	tw_andorb(TW68_INFORM, 0x03 << 2, dev->input << 2);
+	return 0;
+}
+
+static int tw68_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct tw68_dev *dev = video_drvdata(file);
+
+	strcpy(cap->driver, "tw68");
+	strlcpy(cap->card, "Techwell Capture Card",
+		sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+	cap->device_caps =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_READWRITE |
+		V4L2_CAP_STREAMING;
+
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int tw68_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+	struct tw68_dev *dev = video_drvdata(file);
+	unsigned int i;
+
+	if (vb2_is_busy(&dev->vidq))
+		return -EBUSY;
+
+	/* Look for match on complete norm id (may have mult bits) */
+	for (i = 0; i < TVNORMS; i++) {
+		if (id == tvnorms[i].id)
+			break;
+	}
+
+	/* If no exact match, look for norm which contains this one */
+	if (i == TVNORMS) {
+		for (i = 0; i < TVNORMS; i++)
+			if (id & tvnorms[i].id)
+				break;
+	}
+	/* If still not matched, give up */
+	if (i == TVNORMS)
+		return -EINVAL;
+
+	set_tvnorm(dev, &tvnorms[i]);	/* do the actual setting */
+	return 0;
+}
+
+static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct tw68_dev *dev = video_drvdata(file);
+
+	*id = dev->tvnorm->id;
+	return 0;
+}
+
+static int tw68_enum_fmt_vid_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (f->index >= FORMATS)
+		return -EINVAL;
+
+	strlcpy(f->description, formats[f->index].name,
+		sizeof(f->description));
+
+	f->pixelformat = formats[f->index].fourcc;
+
+	return 0;
+}
+
+/*
+ * Used strictly for internal development and debugging, this routine
+ * prints out the current register contents for the tw68xx device.
+ */
+static void tw68_dump_regs(struct tw68_dev *dev)
+{
+	unsigned char line[80];
+	int i, j, k;
+	unsigned char *cptr;
+
+	pr_info("Full dump of TW68 registers:\n");
+	/* First we do the PCI regs, 8 4-byte regs per line */
+	for (i = 0; i < 0x100; i += 32) {
+		cptr = line;
+		cptr += sprintf(cptr, "%03x  ", i);
+		/* j steps through the next 4 words */
+		for (j = i; j < i + 16; j += 4)
+			cptr += sprintf(cptr, "%08x ", tw_readl(j));
+		*cptr++ = ' ';
+		for (; j < i + 32; j += 4)
+			cptr += sprintf(cptr, "%08x ", tw_readl(j));
+		*cptr++ = '\n';
+		*cptr = 0;
+		pr_info("%s", line);
+	}
+	/* Next the control regs, which are single-byte, address mod 4 */
+	while (i < 0x400) {
+		cptr = line;
+		cptr += sprintf(cptr, "%03x ", i);
+		/* Print out 4 groups of 4 bytes */
+		for (j = 0; j < 4; j++) {
+			for (k = 0; k < 4; k++) {
+				cptr += sprintf(cptr, "%02x ",
+					tw_readb(i));
+				i += 4;
+			}
+			*cptr++ = ' ';
+		}
+		*cptr++ = '\n';
+		*cptr = 0;
+		pr_info("%s", line);
+	}
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+	struct tw68_dev *dev = video_drvdata(file);
+
+	tw68_dump_regs(dev);
+	return v4l2_ctrl_log_status(file, priv);
+}
+
+#ifdef CPTCFG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+			      struct v4l2_dbg_register *reg)
+{
+	struct tw68_dev *dev = video_drvdata(file);
+
+	if (reg->size == 1)
+		reg->val = tw_readb(reg->reg);
+	else
+		reg->val = tw_readl(reg->reg);
+	return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+				const struct v4l2_dbg_register *reg)
+{
+	struct tw68_dev *dev = video_drvdata(file);
+
+	if (reg->size == 1)
+		tw_writeb(reg->reg, reg->val);
+	else
+		tw_writel(reg->reg & 0xffff, reg->val);
+	return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops tw68_ctrl_ops = {
+	.s_ctrl = tw68_s_ctrl,
+};
+
+static const struct v4l2_file_operations video_fops = {
+	.owner			= THIS_MODULE,
+	.open			= v4l2_fh_open,
+	.release		= vb2_fop_release,
+	.read			= vb2_fop_read,
+	.poll			= vb2_fop_poll,
+	.mmap			= vb2_fop_mmap,
+	.unlocked_ioctl		= video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+	.vidioc_querycap		= tw68_querycap,
+	.vidioc_enum_fmt_vid_cap	= tw68_enum_fmt_vid_cap,
+	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
+	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
+	.vidioc_querybuf		= vb2_ioctl_querybuf,
+	.vidioc_qbuf			= vb2_ioctl_qbuf,
+	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
+	.vidioc_s_std			= tw68_s_std,
+	.vidioc_g_std			= tw68_g_std,
+	.vidioc_enum_input		= tw68_enum_input,
+	.vidioc_g_input			= tw68_g_input,
+	.vidioc_s_input			= tw68_s_input,
+	.vidioc_streamon		= vb2_ioctl_streamon,
+	.vidioc_streamoff		= vb2_ioctl_streamoff,
+	.vidioc_g_fmt_vid_cap		= tw68_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap		= tw68_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap		= tw68_s_fmt_vid_cap,
+	.vidioc_log_status		= vidioc_log_status,
+	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
+#ifdef CPTCFG_VIDEO_ADV_DEBUG
+	.vidioc_g_register              = vidioc_g_register,
+	.vidioc_s_register              = vidioc_s_register,
+#endif
+};
+
+static struct video_device tw68_video_template = {
+	.name			= "tw68_video",
+	.fops			= &video_fops,
+	.ioctl_ops		= &video_ioctl_ops,
+	.release		= video_device_release_empty,
+	.tvnorms		= TW68_NORMS,
+};
+
+/* ------------------------------------------------------------------ */
+/* exported stuff                                                     */
+void tw68_set_tvnorm_hw(struct tw68_dev *dev)
+{
+	tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format);
+}
+
+int tw68_video_init1(struct tw68_dev *dev)
+{
+	struct v4l2_ctrl_handler *hdl = &dev->hdl;
+
+	v4l2_ctrl_handler_init(hdl, 6);
+	v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, -128, 127, 1, 20);
+	v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 100);
+	v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 128);
+	/* NTSC only */
+	v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+			V4L2_CID_HUE, -128, 127, 1, 0);
+	v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+			V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+			V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);
+	if (hdl->error) {
+		v4l2_ctrl_handler_free(hdl);
+		return hdl->error;
+	}
+	dev->v4l2_dev.ctrl_handler = hdl;
+	v4l2_ctrl_handler_setup(hdl);
+	return 0;
+}
+
+int tw68_video_init2(struct tw68_dev *dev, int video_nr)
+{
+	int ret;
+
+	set_tvnorm(dev, &tvnorms[0]);
+
+	dev->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+	dev->width    = 720;
+	dev->height   = 576;
+	dev->field    = V4L2_FIELD_INTERLACED;
+
+	INIT_LIST_HEAD(&dev->active);
+	dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF;
+	dev->vidq.ops = &tw68_video_qops;
+	dev->vidq.mem_ops = &vb2_dma_sg_memops;
+	dev->vidq.drv_priv = dev;
+	dev->vidq.gfp_flags = __GFP_DMA32;
+	dev->vidq.buf_struct_size = sizeof(struct tw68_buf);
+	dev->vidq.lock = &dev->lock;
+	dev->vidq.min_buffers_needed = 2;
+	ret = vb2_queue_init(&dev->vidq);
+	if (ret)
+		return ret;
+	dev->vdev = tw68_video_template;
+	dev->vdev.v4l2_dev = &dev->v4l2_dev;
+	dev->vdev.lock = &dev->lock;
+	dev->vdev.queue = &dev->vidq;
+	video_set_drvdata(&dev->vdev, dev);
+	return video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr);
+}
+
+/*
+ * tw68_irq_video_done
+ */
+void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status)
+{
+	__u32 reg;
+
+	/* reset interrupts handled by this routine */
+	tw_writel(TW68_INTSTAT, status);
+	/*
+	 * Check most likely first
+	 *
+	 * DMAPI shows we have reached the end of the risc code
+	 * for the current buffer.
+	 */
+	if (status & TW68_DMAPI) {
+		struct tw68_buf *buf;
+
+		spin_lock(&dev->slock);
+		buf = list_entry(dev->active.next, struct tw68_buf, list);
+		list_del(&buf->list);
+		spin_unlock(&dev->slock);
+		v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+		buf->vb.v4l2_buf.field = dev->field;
+		buf->vb.v4l2_buf.sequence = dev->seqnr++;
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+		status &= ~(TW68_DMAPI);
+		if (0 == status)
+			return;
+	}
+	if (status & (TW68_VLOCK | TW68_HLOCK))
+		dev_dbg(&dev->pci->dev, "Lost sync\n");
+	if (status & TW68_PABORT)
+		dev_err(&dev->pci->dev, "PABORT interrupt\n");
+	if (status & TW68_DMAPERR)
+		dev_err(&dev->pci->dev, "DMAPERR interrupt\n");
+	/*
+	 * On TW6800, FDMIS is apparently generated if video input is switched
+	 * during operation.  Therefore, it is not enabled for that chip.
+	 */
+	if (status & TW68_FDMIS)
+		dev_dbg(&dev->pci->dev, "FDMIS interrupt\n");
+	if (status & TW68_FFOF) {
+		/* probably a logic error */
+		reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN;
+		tw_clearl(TW68_DMAC, TW68_FIFO_EN);
+		dev_dbg(&dev->pci->dev, "FFOF interrupt\n");
+		tw_setl(TW68_DMAC, reg);
+	}
+	if (status & TW68_FFERR)
+		dev_dbg(&dev->pci->dev, "FFERR interrupt\n");
+}
diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h
new file mode 100644
index 0000000..2c8abe2
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68.h
@@ -0,0 +1,231 @@
+/*
+ *  tw68 driver common header file
+ *
+ *  Much of this code is derived from the cx88 and sa7134 drivers, which
+ *  were in turn derived from the bt87x driver.  The original work was by
+ *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
+ *  acknowledged.  Full credit goes to them - any problems within this code
+ *  are mine.
+ *
+ *  Copyright (C) 2009  William M. Brack
+ *
+ *  Refactored and updated to the latest v4l core frameworks:
+ *
+ *  Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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/version.h>
+#include <linux/pci.h>
+#include <linux/videodev2.h>
+#include <linux/notifier.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "tw68-reg.h"
+
+#define	UNSET	(-1U)
+
+/* system vendor and device ID's */
+#define	PCI_VENDOR_ID_TECHWELL	0x1797
+#define	PCI_DEVICE_ID_6800	0x6800
+#define	PCI_DEVICE_ID_6801	0x6801
+#define	PCI_DEVICE_ID_AUDIO2	0x6802
+#define	PCI_DEVICE_ID_TS3	0x6803
+#define	PCI_DEVICE_ID_6804	0x6804
+#define	PCI_DEVICE_ID_AUDIO5	0x6805
+#define	PCI_DEVICE_ID_TS6	0x6806
+
+/* tw6816 based cards */
+#define	PCI_DEVICE_ID_6816_1   0x6810
+#define	PCI_DEVICE_ID_6816_2   0x6811
+#define	PCI_DEVICE_ID_6816_3   0x6812
+#define	PCI_DEVICE_ID_6816_4   0x6813
+
+#define TW68_NORMS ( \
+	V4L2_STD_NTSC    | V4L2_STD_PAL       | V4L2_STD_SECAM    | \
+	V4L2_STD_PAL_M   | V4L2_STD_PAL_Nc    | V4L2_STD_PAL_60)
+
+#define	TW68_VID_INTS	(TW68_FFERR | TW68_PABORT | TW68_DMAPERR | \
+			 TW68_FFOF   | TW68_DMAPI)
+/* TW6800 chips have trouble with these, so we don't set them for that chip */
+#define	TW68_VID_INTSX	(TW68_FDMIS | TW68_HLOCK | TW68_VLOCK)
+
+#define	TW68_I2C_INTS	(TW68_SBERR | TW68_SBDONE | TW68_SBERR2  | \
+			 TW68_SBDONE2)
+
+enum tw68_decoder_type {
+	TW6800,
+	TW6801,
+	TW6804,
+	TWXXXX,
+};
+
+/* ----------------------------------------------------------- */
+/* static data                                                 */
+
+struct tw68_tvnorm {
+	char		*name;
+	v4l2_std_id	id;
+
+	/* video decoder */
+	u32	sync_control;
+	u32	luma_control;
+	u32	chroma_ctrl1;
+	u32	chroma_gain;
+	u32	chroma_ctrl2;
+	u32	vgate_misc;
+
+	/* video scaler */
+	u32	h_delay;
+	u32	h_delay0;	/* for TW6800 */
+	u32	h_start;
+	u32	h_stop;
+	u32	v_delay;
+	u32	video_v_start;
+	u32	video_v_stop;
+	u32	vbi_v_start_0;
+	u32	vbi_v_stop_0;
+	u32	vbi_v_start_1;
+
+	/* Techwell specific */
+	u32	format;
+};
+
+struct tw68_format {
+	char	*name;
+	u32	fourcc;
+	u32	depth;
+	u32	twformat;
+};
+
+/* ----------------------------------------------------------- */
+/* card configuration					  */
+
+#define TW68_BOARD_NOAUTO		UNSET
+#define TW68_BOARD_UNKNOWN		0
+#define	TW68_BOARD_GENERIC_6802		1
+
+#define	TW68_MAXBOARDS			16
+#define	TW68_INPUT_MAX			4
+
+/* ----------------------------------------------------------- */
+/* device / file handle status                                 */
+
+#define	BUFFER_TIMEOUT	msecs_to_jiffies(500)	/* 0.5 seconds */
+
+struct tw68_dev;	/* forward delclaration */
+
+/* buffer for one video/vbi/ts frame */
+struct tw68_buf {
+	struct vb2_buffer vb;
+	struct list_head list;
+
+	unsigned int   size;
+	__le32         *cpu;
+	__le32         *jmp;
+	dma_addr_t     dma;
+};
+
+struct tw68_fmt {
+	char			*name;
+	u32			fourcc;	/* v4l2 format id */
+	int			depth;
+	int			flags;
+	u32			twformat;
+};
+
+/* global device status */
+struct tw68_dev {
+	struct mutex		lock;
+	spinlock_t		slock;
+	u16			instance;
+	struct v4l2_device	v4l2_dev;
+
+	/* various device info */
+	enum tw68_decoder_type	vdecoder;
+	struct video_device	vdev;
+	struct v4l2_ctrl_handler hdl;
+
+	/* pci i/o */
+	char			*name;
+	struct pci_dev		*pci;
+	unsigned char		pci_rev, pci_lat;
+	u32			__iomem *lmmio;
+	u8			__iomem *bmmio;
+	u32			pci_irqmask;
+	/* The irq mask to be used will depend upon the chip type */
+	u32			board_virqmask;
+
+	/* video capture */
+	const struct tw68_format *fmt;
+	unsigned		width, height;
+	unsigned		seqnr;
+	unsigned		field;
+	struct vb2_queue	vidq;
+	struct list_head	active;
+
+	/* various v4l controls */
+	const struct tw68_tvnorm *tvnorm;	/* video */
+
+	int			input;
+};
+
+/* ----------------------------------------------------------- */
+
+#define tw_readl(reg)		readl(dev->lmmio + ((reg) >> 2))
+#define	tw_readb(reg)		readb(dev->bmmio + (reg))
+#define tw_writel(reg, value)	writel((value), dev->lmmio + ((reg) >> 2))
+#define	tw_writeb(reg, value)	writeb((value), dev->bmmio + (reg))
+
+#define tw_andorl(reg, mask, value) \
+		writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
+		((value) & (mask)), dev->lmmio+((reg)>>2))
+#define	tw_andorb(reg, mask, value) \
+		writeb((readb(dev->bmmio + (reg)) & ~(mask)) |\
+		((value) & (mask)), dev->bmmio+(reg))
+#define tw_setl(reg, bit)	tw_andorl((reg), (bit), (bit))
+#define	tw_setb(reg, bit)	tw_andorb((reg), (bit), (bit))
+#define	tw_clearl(reg, bit)	\
+		writel((readl(dev->lmmio + ((reg) >> 2)) & ~(bit)), \
+		dev->lmmio + ((reg) >> 2))
+#define	tw_clearb(reg, bit)	\
+		writeb((readb(dev->bmmio+(reg)) & ~(bit)), \
+		dev->bmmio + (reg))
+
+#define tw_wait(us) { udelay(us); }
+
+/* ----------------------------------------------------------- */
+/* tw68-video.c                                                */
+
+void tw68_set_tvnorm_hw(struct tw68_dev *dev);
+
+int tw68_video_init1(struct tw68_dev *dev);
+int tw68_video_init2(struct tw68_dev *dev, int video_nr);
+void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status);
+int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf);
+
+/* ----------------------------------------------------------- */
+/* tw68-risc.c                                                 */
+
+int tw68_risc_buffer(struct pci_dev *pci, struct tw68_buf *buf,
+	struct scatterlist *sglist, unsigned int top_offset,
+	unsigned int bottom_offset, unsigned int bpl,
+	unsigned int padding, unsigned int lines);
diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c
index bf34b93..b6801e0 100644
--- a/drivers/media/pci/zoran/zoran_device.c
+++ b/drivers/media/pci/zoran/zoran_device.c
@@ -682,7 +682,7 @@
 	switch (zr->card.type) {
 	case LML33:
 	case LML33R10:
-		if (lml33dpath == 0)
+		if (!lml33dpath)
 			GPIO(zr, 5, val);
 		else
 			GPIO(zr, 5, 1);
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 3f85861..56ec66e 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -61,7 +61,8 @@
 	depends on !BACKPORT_KERNEL_3_4
 	tristate "Support for timberdale Video In/LogiWIN"
 	depends on m
-	depends on MFD_TIMBERDALE && VIDEO_V4L2 && I2C && DMADEVICES
+	depends on VIDEO_V4L2 && I2C && DMADEVICES
+	depends on MFD_TIMBERDALE || COMPILE_TEST
 	depends on DMA_ENGINE
 	depends on TIMB_DMA
 	select VIDEO_ADV7180
@@ -81,7 +82,8 @@
 config VIDEO_M32R_AR
 	tristate "AR devices"
 	depends on m
-	depends on M32R && VIDEO_V4L2
+	depends on VIDEO_V4L2
+	depends on M32R || COMPILE_TEST
 	---help---
 	  This is a video4linux driver for the Renesas AR (Artificial Retina)
 	  camera module.
@@ -103,6 +105,7 @@
 	tristate "OMAP 3 Camera support"
 	depends on m
 	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3
+	depends on HAS_DMA
 	depends on ARM_DMA_USE_IOMMU
 	depends on OMAP_IOMMU
 	select VIDEOBUF2_DMA_CONTIG
@@ -119,7 +122,9 @@
 	tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver"
 	depends on m
 	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
-	depends on (ARCH_S3C64XX || PLAT_S3C24XX) && PM_RUNTIME
+	depends on PM_RUNTIME
+	depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	---help---
 	  This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera
@@ -151,6 +156,7 @@
 	tristate "Chips&Media Coda multi-standard codec IP"
 	depends on m
 	depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MXC
+	depends on HAS_DMA
 	depends on SRAM
 	select VIDEOBUF2_DMA_CONTIG
 	select V4L2_MEM2MEM_DEV
@@ -164,6 +170,7 @@
 	tristate "Deinterlace support"
 	depends on m
 	depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	select V4L2_MEM2MEM_DEV
 	help
@@ -172,7 +179,9 @@
 config VIDEO_SAMSUNG_S5P_G2D
 	tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver"
 	depends on m
-	depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS)
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	select V4L2_MEM2MEM_DEV
 	default n
@@ -183,7 +192,9 @@
 config VIDEO_SAMSUNG_S5P_JPEG
 	tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver"
 	depends on m
-	depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS)
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	select V4L2_MEM2MEM_DEV
 	---help---
@@ -193,7 +204,9 @@
 config VIDEO_SAMSUNG_S5P_MFC
 	tristate "Samsung S5P MFC Video Codec"
 	depends on m
-	depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS)
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	default n
 	help
@@ -202,7 +215,9 @@
 config VIDEO_MX2_EMMAPRP
 	tristate "MX2 eMMa-PrP support"
 	depends on m
-	depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on SOC_IMX27 || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	select V4L2_MEM2MEM_DEV
 	help
@@ -213,7 +228,9 @@
 config VIDEO_SAMSUNG_EXYNOS_GSC
 	tristate "Samsung Exynos G-Scaler driver"
 	depends on m
-	depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_EXYNOS5
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on ARCH_EXYNOS5 || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	select V4L2_MEM2MEM_DEV
 	help
@@ -223,6 +240,7 @@
 	tristate "SuperH VEU mem2mem video processing driver"
 	depends on m
 	depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	select V4L2_MEM2MEM_DEV
 	help
@@ -234,6 +252,7 @@
 	tristate "Renesas VSP1 Video Processing Engine"
 	depends on m
 	depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA
+	depends on ARCH_SHMOBILE || COMPILE_TEST
 	select VIDEOBUF2_DMA_CONTIG
 	---help---
 	  This is a V4L2 driver for the Renesas VSP1 video processing engine.
@@ -244,7 +263,9 @@
 config VIDEO_TI_VPE
 	tristate "TI VPE (Video Processing Engine) driver"
 	depends on m
-	depends on VIDEO_DEV && VIDEO_V4L2 && SOC_DRA7XX
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on SOC_DRA7XX || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	select V4L2_MEM2MEM_DEV
 	default n
@@ -265,20 +286,8 @@
 	depends on MEDIA_CAMERA_SUPPORT
 
 if V4L_TEST_DRIVERS
-config VIDEO_VIVI
-	tristate "Virtual Video Driver"
-	depends on m
-	depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
-	depends on FONT_SUPPORT
-	depends on FONT_8x16
-	select VIDEOBUF2_VMALLOC
-	default n
-	---help---
-	  Enables a virtual video driver. This device shows a color bar
-	  and a timestamp, as a real device would generate by using V4L2
-	  api.
-	  Say Y here if you want to test video apps or debug V4L devices.
-	  In doubt, say N.
+
+source "drivers/media/platform/vivid/Kconfig"
 
 config VIDEO_MEM2MEM_TESTDEV
 	tristate "Virtual test device for mem2mem framework"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index a0f28f8..140e3e5 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -15,14 +15,14 @@
 obj-$(CPTCFG_VIDEO_OMAP3)	+= omap3isp/
 
 obj-$(CPTCFG_VIDEO_VIU) += fsl-viu.o
-obj-$(CPTCFG_VIDEO_VIVI) += vivi.o
 
+obj-$(CPTCFG_VIDEO_VIVID)		+= vivid/
 obj-$(CPTCFG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
 
 obj-$(CPTCFG_VIDEO_TI_VPE)		+= ti-vpe/
 
 obj-$(CPTCFG_VIDEO_MX2_EMMAPRP)		+= mx2_emmaprp.o
-obj-$(CPTCFG_VIDEO_CODA) 		+= coda.o
+obj-$(CPTCFG_VIDEO_CODA) 		+= coda/
 
 obj-$(CPTCFG_VIDEO_SH_VEU)		+= sh_veu.o
 
@@ -47,8 +47,6 @@
 
 obj-$(CPTCFG_VIDEO_RENESAS_VSP1)	+= vsp1/
 
-obj-y	+= davinci/
-
-obj-$(CONFIG_ARCH_OMAP)	+= omap/
+obj-y	+= omap/
 
 ccflags-y += -I$(backport_srctree)/drivers/media/i2c
diff --git a/drivers/media/platform/blackfin/Kconfig b/drivers/media/platform/blackfin/Kconfig
index 2e7619b..aea07ec 100644
--- a/drivers/media/platform/blackfin/Kconfig
+++ b/drivers/media/platform/blackfin/Kconfig
@@ -2,6 +2,7 @@
 	tristate "Blackfin Video Capture Driver"
 	depends on m
 	depends on VIDEO_V4L2 && BLACKFIN && I2C
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	help
 	  V4L2 bridge driver for Blackfin video capture device.
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
deleted file mode 100644
index 3a6d1d2..0000000
--- a/drivers/media/platform/coda.c
+++ /dev/null
@@ -1,3933 +0,0 @@
-/*
- * Coda multi-standard codec IP
- *
- * Copyright (C) 2012 Vista Silicon S.L.
- *    Javier Martin, <javier.martin@vista-silicon.com>
- *    Xavier Duret
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/clk.h>
-#include <linux/debugfs.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/genalloc.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/kfifo.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/of.h>
-#include <linux/platform_data/coda.h>
-#include <linux/reset.h>
-
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/videobuf2-core.h>
-#include <media/videobuf2-dma-contig.h>
-
-#include "coda.h"
-
-#define CODA_NAME		"coda"
-
-#define CODADX6_MAX_INSTANCES	4
-
-#define CODA_PARA_BUF_SIZE	(10 * 1024)
-#define CODA_ISRAM_SIZE	(2048 * 2)
-
-#define CODA7_PS_BUF_SIZE	0x28000
-#define CODA9_PS_SAVE_SIZE	(512 * 1024)
-
-#define CODA_MAX_FRAMEBUFFERS	8
-
-#define CODA_MAX_FRAME_SIZE	0x100000
-#define FMO_SLICE_SAVE_BUF_SIZE         (32)
-#define CODA_DEFAULT_GAMMA		4096
-#define CODA9_DEFAULT_GAMMA		24576	/* 0.75 * 32768 */
-
-#define MIN_W 176
-#define MIN_H 144
-
-#define S_ALIGN		1 /* multiple of 2 */
-#define W_ALIGN		1 /* multiple of 2 */
-#define H_ALIGN		1 /* multiple of 2 */
-
-#define fh_to_ctx(__fh)	container_of(__fh, struct coda_ctx, fh)
-
-static int coda_debug;
-module_param(coda_debug, int, 0644);
-MODULE_PARM_DESC(coda_debug, "Debug level (0-1)");
-
-enum {
-	V4L2_M2M_SRC = 0,
-	V4L2_M2M_DST = 1,
-};
-
-enum coda_inst_type {
-	CODA_INST_ENCODER,
-	CODA_INST_DECODER,
-};
-
-enum coda_product {
-	CODA_DX6 = 0xf001,
-	CODA_7541 = 0xf012,
-	CODA_960 = 0xf020,
-};
-
-struct coda_fmt {
-	char *name;
-	u32 fourcc;
-};
-
-struct coda_codec {
-	u32 mode;
-	u32 src_fourcc;
-	u32 dst_fourcc;
-	u32 max_w;
-	u32 max_h;
-};
-
-struct coda_devtype {
-	char			*firmware;
-	enum coda_product	product;
-	struct coda_codec	*codecs;
-	unsigned int		num_codecs;
-	size_t			workbuf_size;
-	size_t			tempbuf_size;
-	size_t			iram_size;
-};
-
-/* Per-queue, driver-specific private data */
-struct coda_q_data {
-	unsigned int		width;
-	unsigned int		height;
-	unsigned int		bytesperline;
-	unsigned int		sizeimage;
-	unsigned int		fourcc;
-	struct v4l2_rect	rect;
-};
-
-struct coda_aux_buf {
-	void			*vaddr;
-	dma_addr_t		paddr;
-	u32			size;
-	struct debugfs_blob_wrapper blob;
-	struct dentry		*dentry;
-};
-
-struct coda_dev {
-	struct v4l2_device	v4l2_dev;
-	struct video_device	vfd;
-	struct platform_device	*plat_dev;
-	const struct coda_devtype *devtype;
-
-	void __iomem		*regs_base;
-	struct clk		*clk_per;
-	struct clk		*clk_ahb;
-	struct reset_control	*rstc;
-
-	struct coda_aux_buf	codebuf;
-	struct coda_aux_buf	tempbuf;
-	struct coda_aux_buf	workbuf;
-	struct gen_pool		*iram_pool;
-	struct coda_aux_buf	iram;
-
-	spinlock_t		irqlock;
-	struct mutex		dev_mutex;
-	struct mutex		coda_mutex;
-	struct workqueue_struct	*workqueue;
-	struct v4l2_m2m_dev	*m2m_dev;
-	struct vb2_alloc_ctx	*alloc_ctx;
-	struct list_head	instances;
-	unsigned long		instance_mask;
-	struct dentry		*debugfs_root;
-};
-
-struct coda_params {
-	u8			rot_mode;
-	u8			h264_intra_qp;
-	u8			h264_inter_qp;
-	u8			h264_min_qp;
-	u8			h264_max_qp;
-	u8			h264_deblk_enabled;
-	u8			h264_deblk_alpha;
-	u8			h264_deblk_beta;
-	u8			mpeg4_intra_qp;
-	u8			mpeg4_inter_qp;
-	u8			gop_size;
-	int			intra_refresh;
-	int			codec_mode;
-	int			codec_mode_aux;
-	enum v4l2_mpeg_video_multi_slice_mode slice_mode;
-	u32			framerate;
-	u16			bitrate;
-	u32			slice_max_bits;
-	u32			slice_max_mb;
-};
-
-struct coda_iram_info {
-	u32		axi_sram_use;
-	phys_addr_t	buf_bit_use;
-	phys_addr_t	buf_ip_ac_dc_use;
-	phys_addr_t	buf_dbk_y_use;
-	phys_addr_t	buf_dbk_c_use;
-	phys_addr_t	buf_ovl_use;
-	phys_addr_t	buf_btp_use;
-	phys_addr_t	search_ram_paddr;
-	int		search_ram_size;
-	int		remaining;
-	phys_addr_t	next_paddr;
-};
-
-struct gdi_tiled_map {
-	int xy2ca_map[16];
-	int xy2ba_map[16];
-	int xy2ra_map[16];
-	int rbc2axi_map[32];
-	int xy2rbc_config;
-	int map_type;
-#define GDI_LINEAR_FRAME_MAP 0
-};
-
-struct coda_timestamp {
-	struct list_head	list;
-	u32			sequence;
-	struct v4l2_timecode	timecode;
-	struct timeval		timestamp;
-};
-
-struct coda_ctx {
-	struct coda_dev			*dev;
-	struct mutex			buffer_mutex;
-	struct list_head		list;
-	struct work_struct		pic_run_work;
-	struct work_struct		seq_end_work;
-	struct completion		completion;
-	int				aborting;
-	int				initialized;
-	int				streamon_out;
-	int				streamon_cap;
-	u32				isequence;
-	u32				qsequence;
-	u32				osequence;
-	u32				sequence_offset;
-	struct coda_q_data		q_data[2];
-	enum coda_inst_type		inst_type;
-	struct coda_codec		*codec;
-	enum v4l2_colorspace		colorspace;
-	struct coda_params		params;
-	struct v4l2_ctrl_handler	ctrls;
-	struct v4l2_fh			fh;
-	int				gopcounter;
-	int				runcounter;
-	char				vpu_header[3][64];
-	int				vpu_header_size[3];
-	struct kfifo			bitstream_fifo;
-	struct mutex			bitstream_mutex;
-	struct coda_aux_buf		bitstream;
-	bool				hold;
-	struct coda_aux_buf		parabuf;
-	struct coda_aux_buf		psbuf;
-	struct coda_aux_buf		slicebuf;
-	struct coda_aux_buf		internal_frames[CODA_MAX_FRAMEBUFFERS];
-	u32				frame_types[CODA_MAX_FRAMEBUFFERS];
-	struct coda_timestamp		frame_timestamps[CODA_MAX_FRAMEBUFFERS];
-	u32				frame_errors[CODA_MAX_FRAMEBUFFERS];
-	struct list_head		timestamp_list;
-	struct coda_aux_buf		workbuf;
-	int				num_internal_frames;
-	int				idx;
-	int				reg_idx;
-	struct coda_iram_info		iram_info;
-	struct gdi_tiled_map		tiled_map;
-	u32				bit_stream_param;
-	u32				frm_dis_flg;
-	u32				frame_mem_ctrl;
-	int				display_idx;
-	struct dentry			*debugfs_entry;
-};
-
-static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff,
-			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 };
-static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 };
-
-static inline void coda_write(struct coda_dev *dev, u32 data, u32 reg)
-{
-	v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-		 "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
-	writel(data, dev->regs_base + reg);
-}
-
-static inline unsigned int coda_read(struct coda_dev *dev, u32 reg)
-{
-	u32 data;
-	data = readl(dev->regs_base + reg);
-	v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-		 "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
-	return data;
-}
-
-static inline unsigned long coda_isbusy(struct coda_dev *dev)
-{
-	return coda_read(dev, CODA_REG_BIT_BUSY);
-}
-
-static inline int coda_is_initialized(struct coda_dev *dev)
-{
-	return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0);
-}
-
-static int coda_wait_timeout(struct coda_dev *dev)
-{
-	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-
-	while (coda_isbusy(dev)) {
-		if (time_after(jiffies, timeout))
-			return -ETIMEDOUT;
-	}
-	return 0;
-}
-
-static void coda_command_async(struct coda_ctx *ctx, int cmd)
-{
-	struct coda_dev *dev = ctx->dev;
-
-	if (dev->devtype->product == CODA_960 ||
-	    dev->devtype->product == CODA_7541) {
-		/* Restore context related registers to CODA */
-		coda_write(dev, ctx->bit_stream_param,
-				CODA_REG_BIT_BIT_STREAM_PARAM);
-		coda_write(dev, ctx->frm_dis_flg,
-				CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
-		coda_write(dev, ctx->frame_mem_ctrl,
-				CODA_REG_BIT_FRAME_MEM_CTRL);
-		coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
-	}
-
-	if (dev->devtype->product == CODA_960) {
-		coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR);
-		coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
-	}
-
-	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
-
-	coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
-	coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
-	coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD);
-
-	coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
-}
-
-static int coda_command_sync(struct coda_ctx *ctx, int cmd)
-{
-	struct coda_dev *dev = ctx->dev;
-
-	coda_command_async(ctx, cmd);
-	return coda_wait_timeout(dev);
-}
-
-static int coda_hw_reset(struct coda_ctx *ctx)
-{
-	struct coda_dev *dev = ctx->dev;
-	unsigned long timeout;
-	unsigned int idx;
-	int ret;
-
-	if (!dev->rstc)
-		return -ENOENT;
-
-	idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX);
-
-	timeout = jiffies + msecs_to_jiffies(100);
-	coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL);
-	while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) {
-		if (time_after(jiffies, timeout))
-			return -ETIME;
-		cpu_relax();
-	}
-
-	ret = reset_control_reset(dev->rstc);
-	if (ret < 0)
-		return ret;
-
-	coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL);
-	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
-	coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
-	ret = coda_wait_timeout(dev);
-	coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX);
-
-	return ret;
-}
-
-static struct coda_q_data *get_q_data(struct coda_ctx *ctx,
-					 enum v4l2_buf_type type)
-{
-	switch (type) {
-	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-		return &(ctx->q_data[V4L2_M2M_SRC]);
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		return &(ctx->q_data[V4L2_M2M_DST]);
-	default:
-		return NULL;
-	}
-}
-
-/*
- * Array of all formats supported by any version of Coda:
- */
-static struct coda_fmt coda_formats[] = {
-	{
-		.name = "YUV 4:2:0 Planar, YCbCr",
-		.fourcc = V4L2_PIX_FMT_YUV420,
-	},
-	{
-		.name = "YUV 4:2:0 Planar, YCrCb",
-		.fourcc = V4L2_PIX_FMT_YVU420,
-	},
-	{
-		.name = "H264 Encoded Stream",
-		.fourcc = V4L2_PIX_FMT_H264,
-	},
-	{
-		.name = "MPEG4 Encoded Stream",
-		.fourcc = V4L2_PIX_FMT_MPEG4,
-	},
-};
-
-#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \
-	{ mode, src_fourcc, dst_fourcc, max_w, max_h }
-
-/*
- * Arrays of codecs supported by each given version of Coda:
- *  i.MX27 -> codadx6
- *  i.MX5x -> coda7
- *  i.MX6  -> coda960
- * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants
- */
-static struct coda_codec codadx6_codecs[] = {
-	CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,  720, 576),
-	CODA_CODEC(CODADX6_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576),
-};
-
-static struct coda_codec coda7_codecs[] = {
-	CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1280, 720),
-	CODA_CODEC(CODA7_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1280, 720),
-	CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1080),
-	CODA_CODEC(CODA7_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1080),
-};
-
-static struct coda_codec coda9_codecs[] = {
-	CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1920, 1080),
-	CODA_CODEC(CODA9_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1920, 1080),
-	CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1080),
-	CODA_CODEC(CODA9_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1080),
-};
-
-static bool coda_format_is_yuv(u32 fourcc)
-{
-	switch (fourcc) {
-	case V4L2_PIX_FMT_YUV420:
-	case V4L2_PIX_FMT_YVU420:
-		return true;
-	default:
-		return false;
-	}
-}
-
-/*
- * Normalize all supported YUV 4:2:0 formats to the value used in the codec
- * tables.
- */
-static u32 coda_format_normalize_yuv(u32 fourcc)
-{
-	return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc;
-}
-
-static struct coda_codec *coda_find_codec(struct coda_dev *dev, int src_fourcc,
-					  int dst_fourcc)
-{
-	struct coda_codec *codecs = dev->devtype->codecs;
-	int num_codecs = dev->devtype->num_codecs;
-	int k;
-
-	src_fourcc = coda_format_normalize_yuv(src_fourcc);
-	dst_fourcc = coda_format_normalize_yuv(dst_fourcc);
-	if (src_fourcc == dst_fourcc)
-		return NULL;
-
-	for (k = 0; k < num_codecs; k++) {
-		if (codecs[k].src_fourcc == src_fourcc &&
-		    codecs[k].dst_fourcc == dst_fourcc)
-			break;
-	}
-
-	if (k == num_codecs)
-		return NULL;
-
-	return &codecs[k];
-}
-
-static void coda_get_max_dimensions(struct coda_dev *dev,
-				    struct coda_codec *codec,
-				    int *max_w, int *max_h)
-{
-	struct coda_codec *codecs = dev->devtype->codecs;
-	int num_codecs = dev->devtype->num_codecs;
-	unsigned int w, h;
-	int k;
-
-	if (codec) {
-		w = codec->max_w;
-		h = codec->max_h;
-	} else {
-		for (k = 0, w = 0, h = 0; k < num_codecs; k++) {
-			w = max(w, codecs[k].max_w);
-			h = max(h, codecs[k].max_h);
-		}
-	}
-
-	if (max_w)
-		*max_w = w;
-	if (max_h)
-		*max_h = h;
-}
-
-static char *coda_product_name(int product)
-{
-	static char buf[9];
-
-	switch (product) {
-	case CODA_DX6:
-		return "CodaDx6";
-	case CODA_7541:
-		return "CODA7541";
-	case CODA_960:
-		return "CODA960";
-	default:
-		snprintf(buf, sizeof(buf), "(0x%04x)", product);
-		return buf;
-	}
-}
-
-/*
- * V4L2 ioctl() operations.
- */
-static int coda_querycap(struct file *file, void *priv,
-			 struct v4l2_capability *cap)
-{
-	struct coda_ctx *ctx = fh_to_ctx(priv);
-
-	strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
-	strlcpy(cap->card, coda_product_name(ctx->dev->devtype->product),
-		sizeof(cap->card));
-	strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info));
-	/*
-	 * This is only a mem-to-mem video device. The capture and output
-	 * device capability flags are left only for backward compatibility
-	 * and are scheduled for removal.
-	 */
-	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
-			   V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
-	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
-	return 0;
-}
-
-static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
-			enum v4l2_buf_type type, int src_fourcc)
-{
-	struct coda_ctx *ctx = fh_to_ctx(priv);
-	struct coda_codec *codecs = ctx->dev->devtype->codecs;
-	struct coda_fmt *formats = coda_formats;
-	struct coda_fmt *fmt;
-	int num_codecs = ctx->dev->devtype->num_codecs;
-	int num_formats = ARRAY_SIZE(coda_formats);
-	int i, k, num = 0;
-
-	for (i = 0; i < num_formats; i++) {
-		/* Both uncompressed formats are always supported */
-		if (coda_format_is_yuv(formats[i].fourcc) &&
-		    !coda_format_is_yuv(src_fourcc)) {
-			if (num == f->index)
-				break;
-			++num;
-			continue;
-		}
-		/* Compressed formats may be supported, check the codec list */
-		for (k = 0; k < num_codecs; k++) {
-			/* if src_fourcc is set, only consider matching codecs */
-			if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-			    formats[i].fourcc == codecs[k].dst_fourcc &&
-			    (!src_fourcc || src_fourcc == codecs[k].src_fourcc))
-				break;
-			if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-			    formats[i].fourcc == codecs[k].src_fourcc)
-				break;
-		}
-		if (k < num_codecs) {
-			if (num == f->index)
-				break;
-			++num;
-		}
-	}
-
-	if (i < num_formats) {
-		fmt = &formats[i];
-		strlcpy(f->description, fmt->name, sizeof(f->description));
-		f->pixelformat = fmt->fourcc;
-		if (!coda_format_is_yuv(fmt->fourcc))
-			f->flags |= V4L2_FMT_FLAG_COMPRESSED;
-		return 0;
-	}
-
-	/* Format not found */
-	return -EINVAL;
-}
-
-static int coda_enum_fmt_vid_cap(struct file *file, void *priv,
-				 struct v4l2_fmtdesc *f)
-{
-	struct coda_ctx *ctx = fh_to_ctx(priv);
-	struct vb2_queue *src_vq;
-	struct coda_q_data *q_data_src;
-
-	/* If the source format is already fixed, only list matching formats */
-	src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-	if (vb2_is_streaming(src_vq)) {
-		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-
-		return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE,
-				q_data_src->fourcc);
-	}
-
-	return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0);
-}
-
-static int coda_enum_fmt_vid_out(struct file *file, void *priv,
-				 struct v4l2_fmtdesc *f)
-{
-	return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0);
-}
-
-static int coda_g_fmt(struct file *file, void *priv,
-		      struct v4l2_format *f)
-{
-	struct coda_q_data *q_data;
-	struct coda_ctx *ctx = fh_to_ctx(priv);
-
-	q_data = get_q_data(ctx, f->type);
-	if (!q_data)
-		return -EINVAL;
-
-	f->fmt.pix.field	= V4L2_FIELD_NONE;
-	f->fmt.pix.pixelformat	= q_data->fourcc;
-	f->fmt.pix.width	= q_data->width;
-	f->fmt.pix.height	= q_data->height;
-	f->fmt.pix.bytesperline = q_data->bytesperline;
-
-	f->fmt.pix.sizeimage	= q_data->sizeimage;
-	f->fmt.pix.colorspace	= ctx->colorspace;
-
-	return 0;
-}
-
-static int coda_try_fmt(struct coda_ctx *ctx, struct coda_codec *codec,
-			struct v4l2_format *f)
-{
-	struct coda_dev *dev = ctx->dev;
-	struct coda_q_data *q_data;
-	unsigned int max_w, max_h;
-	enum v4l2_field field;
-
-	field = f->fmt.pix.field;
-	if (field == V4L2_FIELD_ANY)
-		field = V4L2_FIELD_NONE;
-	else if (V4L2_FIELD_NONE != field)
-		return -EINVAL;
-
-	/* V4L2 specification suggests the driver corrects the format struct
-	 * if any of the dimensions is unsupported */
-	f->fmt.pix.field = field;
-
-	coda_get_max_dimensions(dev, codec, &max_w, &max_h);
-	v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w, W_ALIGN,
-			      &f->fmt.pix.height, MIN_H, max_h, H_ALIGN,
-			      S_ALIGN);
-
-	switch (f->fmt.pix.pixelformat) {
-	case V4L2_PIX_FMT_YUV420:
-	case V4L2_PIX_FMT_YVU420:
-	case V4L2_PIX_FMT_H264:
-	case V4L2_PIX_FMT_MPEG4:
-	case V4L2_PIX_FMT_JPEG:
-		break;
-	default:
-		q_data = get_q_data(ctx, f->type);
-		if (!q_data)
-			return -EINVAL;
-		f->fmt.pix.pixelformat = q_data->fourcc;
-	}
-
-	switch (f->fmt.pix.pixelformat) {
-	case V4L2_PIX_FMT_YUV420:
-	case V4L2_PIX_FMT_YVU420:
-		/* Frame stride must be multiple of 8, but 16 for h.264 */
-		f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
-		f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
-					f->fmt.pix.height * 3 / 2;
-		break;
-	case V4L2_PIX_FMT_H264:
-	case V4L2_PIX_FMT_MPEG4:
-	case V4L2_PIX_FMT_JPEG:
-		f->fmt.pix.bytesperline = 0;
-		f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
-		break;
-	default:
-		BUG();
-	}
-
-	return 0;
-}
-
-static int coda_try_fmt_vid_cap(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct coda_ctx *ctx = fh_to_ctx(priv);
-	struct coda_codec *codec;
-	struct vb2_queue *src_vq;
-	int ret;
-
-	/*
-	 * If the source format is already fixed, try to find a codec that
-	 * converts to the given destination format
-	 */
-	src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-	if (vb2_is_streaming(src_vq)) {
-		struct coda_q_data *q_data_src;
-
-		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-		codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
-					f->fmt.pix.pixelformat);
-		if (!codec)
-			return -EINVAL;
-	} else {
-		/* Otherwise determine codec by encoded format, if possible */
-		codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
-					f->fmt.pix.pixelformat);
-	}
-
-	f->fmt.pix.colorspace = ctx->colorspace;
-
-	ret = coda_try_fmt(ctx, codec, f);
-	if (ret < 0)
-		return ret;
-
-	/* The h.264 decoder only returns complete 16x16 macroblocks */
-	if (codec && codec->src_fourcc == V4L2_PIX_FMT_H264) {
-		f->fmt.pix.width = f->fmt.pix.width;
-		f->fmt.pix.height = round_up(f->fmt.pix.height, 16);
-		f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
-		f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
-				       f->fmt.pix.height * 3 / 2;
-	}
-
-	return 0;
-}
-
-static int coda_try_fmt_vid_out(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct coda_ctx *ctx = fh_to_ctx(priv);
-	struct coda_codec *codec;
-
-	/* Determine codec by encoded format, returns NULL if raw or invalid */
-	codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat,
-				V4L2_PIX_FMT_YUV420);
-
-	if (!f->fmt.pix.colorspace)
-		f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
-
-	return coda_try_fmt(ctx, codec, f);
-}
-
-static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
-{
-	struct coda_q_data *q_data;
-	struct vb2_queue *vq;
-
-	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
-	if (!vq)
-		return -EINVAL;
-
-	q_data = get_q_data(ctx, f->type);
-	if (!q_data)
-		return -EINVAL;
-
-	if (vb2_is_busy(vq)) {
-		v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
-		return -EBUSY;
-	}
-
-	q_data->fourcc = f->fmt.pix.pixelformat;
-	q_data->width = f->fmt.pix.width;
-	q_data->height = f->fmt.pix.height;
-	q_data->bytesperline = f->fmt.pix.bytesperline;
-	q_data->sizeimage = f->fmt.pix.sizeimage;
-	q_data->rect.left = 0;
-	q_data->rect.top = 0;
-	q_data->rect.width = f->fmt.pix.width;
-	q_data->rect.height = f->fmt.pix.height;
-
-	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-		"Setting format for type %d, wxh: %dx%d, fmt: %d\n",
-		f->type, q_data->width, q_data->height, q_data->fourcc);
-
-	return 0;
-}
-
-static int coda_s_fmt_vid_cap(struct file *file, void *priv,
-			      struct v4l2_format *f)
-{
-	struct coda_ctx *ctx = fh_to_ctx(priv);
-	int ret;
-
-	ret = coda_try_fmt_vid_cap(file, priv, f);
-	if (ret)
-		return ret;
-
-	return coda_s_fmt(ctx, f);
-}
-
-static int coda_s_fmt_vid_out(struct file *file, void *priv,
-			      struct v4l2_format *f)
-{
-	struct coda_ctx *ctx = fh_to_ctx(priv);
-	int ret;
-
-	ret = coda_try_fmt_vid_out(file, priv, f);
-	if (ret)
-		return ret;
-
-	ret = coda_s_fmt(ctx, f);
-	if (ret)
-		ctx->colorspace = f->fmt.pix.colorspace;
-
-	return ret;
-}
-
-static int coda_qbuf(struct file *file, void *priv,
-		     struct v4l2_buffer *buf)
-{
-	struct coda_ctx *ctx = fh_to_ctx(priv);
-
-	return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf);
-}
-
-static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
-				      struct v4l2_buffer *buf)
-{
-	struct vb2_queue *src_vq;
-
-	src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-
-	return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) &&
-		(buf->sequence == (ctx->qsequence - 1)));
-}
-
-static int coda_dqbuf(struct file *file, void *priv,
-		      struct v4l2_buffer *buf)
-{
-	struct coda_ctx *ctx = fh_to_ctx(priv);
-	int ret;
-
-	ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf);
-
-	/* If this is the last capture buffer, emit an end-of-stream event */
-	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-	    coda_buf_is_end_of_stream(ctx, buf)) {
-		const struct v4l2_event eos_event = {
-			.type = V4L2_EVENT_EOS
-		};
-
-		v4l2_event_queue_fh(&ctx->fh, &eos_event);
-	}
-
-	return ret;
-}
-
-static int coda_g_selection(struct file *file, void *fh,
-			    struct v4l2_selection *s)
-{
-	struct coda_ctx *ctx = fh_to_ctx(fh);
-	struct coda_q_data *q_data;
-	struct v4l2_rect r, *rsel;
-
-	q_data = get_q_data(ctx, s->type);
-	if (!q_data)
-		return -EINVAL;
-
-	r.left = 0;
-	r.top = 0;
-	r.width = q_data->width;
-	r.height = q_data->height;
-	rsel = &q_data->rect;
-
-	switch (s->target) {
-	case V4L2_SEL_TGT_CROP_DEFAULT:
-	case V4L2_SEL_TGT_CROP_BOUNDS:
-		rsel = &r;
-		/* fallthrough */
-	case V4L2_SEL_TGT_CROP:
-		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-			return -EINVAL;
-		break;
-	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
-	case V4L2_SEL_TGT_COMPOSE_PADDED:
-		rsel = &r;
-		/* fallthrough */
-	case V4L2_SEL_TGT_COMPOSE:
-	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
-		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	s->r = *rsel;
-
-	return 0;
-}
-
-static int coda_try_decoder_cmd(struct file *file, void *fh,
-				struct v4l2_decoder_cmd *dc)
-{
-	if (dc->cmd != V4L2_DEC_CMD_STOP)
-		return -EINVAL;
-
-	if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
-		return -EINVAL;
-
-	if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
-		return -EINVAL;
-
-	return 0;
-}
-
-static int coda_decoder_cmd(struct file *file, void *fh,
-			    struct v4l2_decoder_cmd *dc)
-{
-	struct coda_ctx *ctx = fh_to_ctx(fh);
-	struct coda_dev *dev = ctx->dev;
-	int ret;
-
-	ret = coda_try_decoder_cmd(file, fh, dc);
-	if (ret < 0)
-		return ret;
-
-	/* Ignore decoder stop command silently in encoder context */
-	if (ctx->inst_type != CODA_INST_DECODER)
-		return 0;
-
-	/* Set the strem-end flag on this context */
-	ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
-
-	if ((dev->devtype->product == CODA_960) &&
-	    coda_isbusy(dev) &&
-	    (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
-		/* If this context is currently running, update the hardware flag */
-		coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM);
-	}
-	ctx->hold = false;
-	v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
-
-	return 0;
-}
-
-static int coda_subscribe_event(struct v4l2_fh *fh,
-				const struct v4l2_event_subscription *sub)
-{
-	switch (sub->type) {
-	case V4L2_EVENT_EOS:
-		return v4l2_event_subscribe(fh, sub, 0, NULL);
-	default:
-		return v4l2_ctrl_subscribe_event(fh, sub);
-	}
-}
-
-static const struct v4l2_ioctl_ops coda_ioctl_ops = {
-	.vidioc_querycap	= coda_querycap,
-
-	.vidioc_enum_fmt_vid_cap = coda_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap	= coda_g_fmt,
-	.vidioc_try_fmt_vid_cap	= coda_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap	= coda_s_fmt_vid_cap,
-
-	.vidioc_enum_fmt_vid_out = coda_enum_fmt_vid_out,
-	.vidioc_g_fmt_vid_out	= coda_g_fmt,
-	.vidioc_try_fmt_vid_out	= coda_try_fmt_vid_out,
-	.vidioc_s_fmt_vid_out	= coda_s_fmt_vid_out,
-
-	.vidioc_reqbufs		= v4l2_m2m_ioctl_reqbufs,
-	.vidioc_querybuf	= v4l2_m2m_ioctl_querybuf,
-
-	.vidioc_qbuf		= coda_qbuf,
-	.vidioc_expbuf		= v4l2_m2m_ioctl_expbuf,
-	.vidioc_dqbuf		= coda_dqbuf,
-	.vidioc_create_bufs	= v4l2_m2m_ioctl_create_bufs,
-
-	.vidioc_streamon	= v4l2_m2m_ioctl_streamon,
-	.vidioc_streamoff	= v4l2_m2m_ioctl_streamoff,
-
-	.vidioc_g_selection	= coda_g_selection,
-
-	.vidioc_try_decoder_cmd	= coda_try_decoder_cmd,
-	.vidioc_decoder_cmd	= coda_decoder_cmd,
-
-	.vidioc_subscribe_event = coda_subscribe_event,
-	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static int coda_start_decoding(struct coda_ctx *ctx);
-
-static inline int coda_get_bitstream_payload(struct coda_ctx *ctx)
-{
-	return kfifo_len(&ctx->bitstream_fifo);
-}
-
-static void coda_kfifo_sync_from_device(struct coda_ctx *ctx)
-{
-	struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
-	struct coda_dev *dev = ctx->dev;
-	u32 rd_ptr;
-
-	rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
-	kfifo->out = (kfifo->in & ~kfifo->mask) |
-		      (rd_ptr - ctx->bitstream.paddr);
-	if (kfifo->out > kfifo->in)
-		kfifo->out -= kfifo->mask + 1;
-}
-
-static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx)
-{
-	struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
-	struct coda_dev *dev = ctx->dev;
-	u32 rd_ptr, wr_ptr;
-
-	rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask);
-	coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
-	wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
-	coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
-}
-
-static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx)
-{
-	struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
-	struct coda_dev *dev = ctx->dev;
-	u32 wr_ptr;
-
-	wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
-	coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
-}
-
-static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf)
-{
-	u32 src_size = vb2_get_plane_payload(src_buf, 0);
-	u32 n;
-
-	n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size);
-	if (n < src_size)
-		return -ENOSPC;
-
-	dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr,
-				   ctx->bitstream.size, DMA_TO_DEVICE);
-
-	src_buf->v4l2_buf.sequence = ctx->qsequence++;
-
-	return 0;
-}
-
-static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
-				     struct vb2_buffer *src_buf)
-{
-	int ret;
-
-	if (coda_get_bitstream_payload(ctx) +
-	    vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size)
-		return false;
-
-	if (vb2_plane_vaddr(src_buf, 0) == NULL) {
-		v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n");
-		return true;
-	}
-
-	ret = coda_bitstream_queue(ctx, src_buf);
-	if (ret < 0) {
-		v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n");
-		return false;
-	}
-	/* Sync read pointer to device */
-	if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
-		coda_kfifo_sync_to_device_write(ctx);
-
-	ctx->hold = false;
-
-	return true;
-}
-
-static void coda_fill_bitstream(struct coda_ctx *ctx)
-{
-	struct vb2_buffer *src_buf;
-	struct coda_timestamp *ts;
-
-	while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
-		src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
-
-		if (coda_bitstream_try_queue(ctx, src_buf)) {
-			/*
-			 * Source buffer is queued in the bitstream ringbuffer;
-			 * queue the timestamp and mark source buffer as done
-			 */
-			src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
-
-			ts = kmalloc(sizeof(*ts), GFP_KERNEL);
-			if (ts) {
-				ts->sequence = src_buf->v4l2_buf.sequence;
-				ts->timecode = src_buf->v4l2_buf.timecode;
-				ts->timestamp = src_buf->v4l2_buf.timestamp;
-				list_add_tail(&ts->list, &ctx->timestamp_list);
-			}
-
-			v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
-		} else {
-			break;
-		}
-	}
-}
-
-static void coda_set_gdi_regs(struct coda_ctx *ctx)
-{
-	struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
-	struct coda_dev *dev = ctx->dev;
-	int i;
-
-	for (i = 0; i < 16; i++)
-		coda_write(dev, tiled_map->xy2ca_map[i],
-				CODA9_GDI_XY2_CAS_0 + 4 * i);
-	for (i = 0; i < 4; i++)
-		coda_write(dev, tiled_map->xy2ba_map[i],
-				CODA9_GDI_XY2_BA_0 + 4 * i);
-	for (i = 0; i < 16; i++)
-		coda_write(dev, tiled_map->xy2ra_map[i],
-				CODA9_GDI_XY2_RAS_0 + 4 * i);
-	coda_write(dev, tiled_map->xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG);
-	for (i = 0; i < 32; i++)
-		coda_write(dev, tiled_map->rbc2axi_map[i],
-				CODA9_GDI_RBC2_AXI_0 + 4 * i);
-}
-
-/*
- * Mem-to-mem operations.
- */
-static int coda_prepare_decode(struct coda_ctx *ctx)
-{
-	struct vb2_buffer *dst_buf;
-	struct coda_dev *dev = ctx->dev;
-	struct coda_q_data *q_data_dst;
-	u32 stridey, height;
-	u32 picture_y, picture_cb, picture_cr;
-
-	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-
-	if (ctx->params.rot_mode & CODA_ROT_90) {
-		stridey = q_data_dst->height;
-		height = q_data_dst->width;
-	} else {
-		stridey = q_data_dst->width;
-		height = q_data_dst->height;
-	}
-
-	/* Try to copy source buffer contents into the bitstream ringbuffer */
-	mutex_lock(&ctx->bitstream_mutex);
-	coda_fill_bitstream(ctx);
-	mutex_unlock(&ctx->bitstream_mutex);
-
-	if (coda_get_bitstream_payload(ctx) < 512 &&
-	    (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
-		v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-			 "bitstream payload: %d, skipping\n",
-			 coda_get_bitstream_payload(ctx));
-		v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
-		return -EAGAIN;
-	}
-
-	/* Run coda_start_decoding (again) if not yet initialized */
-	if (!ctx->initialized) {
-		int ret = coda_start_decoding(ctx);
-		if (ret < 0) {
-			v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
-			v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
-			return -EAGAIN;
-		} else {
-			ctx->initialized = 1;
-		}
-	}
-
-	if (dev->devtype->product == CODA_960)
-		coda_set_gdi_regs(ctx);
-
-	/* Set rotator output */
-	picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
-	if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) {
-		/* Switch Cr and Cb for YVU420 format */
-		picture_cr = picture_y + stridey * height;
-		picture_cb = picture_cr + stridey / 2 * height / 2;
-	} else {
-		picture_cb = picture_y + stridey * height;
-		picture_cr = picture_cb + stridey / 2 * height / 2;
-	}
-
-	if (dev->devtype->product == CODA_960) {
-		/*
-		 * The CODA960 seems to have an internal list of buffers with
-		 * 64 entries that includes the registered frame buffers as
-		 * well as the rotator buffer output.
-		 * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames.
-		 */
-		coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index,
-				CODA9_CMD_DEC_PIC_ROT_INDEX);
-		coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y);
-		coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB);
-		coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR);
-		coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE);
-	} else {
-		coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y);
-		coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB);
-		coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR);
-		coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE);
-	}
-	coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
-			CODA_CMD_DEC_PIC_ROT_MODE);
-
-	switch (dev->devtype->product) {
-	case CODA_DX6:
-		/* TBD */
-	case CODA_7541:
-		coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION);
-		break;
-	case CODA_960:
-		coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); /* 'hardcode to use interrupt disable mode'? */
-		break;
-	}
-
-	coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM);
-
-	coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START);
-	coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE);
-
-	return 0;
-}
-
-static void coda_prepare_encode(struct coda_ctx *ctx)
-{
-	struct coda_q_data *q_data_src, *q_data_dst;
-	struct vb2_buffer *src_buf, *dst_buf;
-	struct coda_dev *dev = ctx->dev;
-	int force_ipicture;
-	int quant_param = 0;
-	u32 picture_y, picture_cb, picture_cr;
-	u32 pic_stream_buffer_addr, pic_stream_buffer_size;
-	u32 dst_fourcc;
-
-	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
-	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-	dst_fourcc = q_data_dst->fourcc;
-
-	src_buf->v4l2_buf.sequence = ctx->osequence;
-	dst_buf->v4l2_buf.sequence = ctx->osequence;
-	ctx->osequence++;
-
-	/*
-	 * Workaround coda firmware BUG that only marks the first
-	 * frame as IDR. This is a problem for some decoders that can't
-	 * recover when a frame is lost.
-	 */
-	if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) {
-		src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
-		src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
-	} else {
-		src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
-		src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
-	}
-
-	if (dev->devtype->product == CODA_960)
-		coda_set_gdi_regs(ctx);
-
-	/*
-	 * Copy headers at the beginning of the first frame for H.264 only.
-	 * In MPEG4 they are already copied by the coda.
-	 */
-	if (src_buf->v4l2_buf.sequence == 0) {
-		pic_stream_buffer_addr =
-			vb2_dma_contig_plane_dma_addr(dst_buf, 0) +
-			ctx->vpu_header_size[0] +
-			ctx->vpu_header_size[1] +
-			ctx->vpu_header_size[2];
-		pic_stream_buffer_size = CODA_MAX_FRAME_SIZE -
-			ctx->vpu_header_size[0] -
-			ctx->vpu_header_size[1] -
-			ctx->vpu_header_size[2];
-		memcpy(vb2_plane_vaddr(dst_buf, 0),
-		       &ctx->vpu_header[0][0], ctx->vpu_header_size[0]);
-		memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0],
-		       &ctx->vpu_header[1][0], ctx->vpu_header_size[1]);
-		memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] +
-			ctx->vpu_header_size[1], &ctx->vpu_header[2][0],
-			ctx->vpu_header_size[2]);
-	} else {
-		pic_stream_buffer_addr =
-			vb2_dma_contig_plane_dma_addr(dst_buf, 0);
-		pic_stream_buffer_size = CODA_MAX_FRAME_SIZE;
-	}
-
-	if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
-		force_ipicture = 1;
-		switch (dst_fourcc) {
-		case V4L2_PIX_FMT_H264:
-			quant_param = ctx->params.h264_intra_qp;
-			break;
-		case V4L2_PIX_FMT_MPEG4:
-			quant_param = ctx->params.mpeg4_intra_qp;
-			break;
-		default:
-			v4l2_warn(&ctx->dev->v4l2_dev,
-				"cannot set intra qp, fmt not supported\n");
-			break;
-		}
-	} else {
-		force_ipicture = 0;
-		switch (dst_fourcc) {
-		case V4L2_PIX_FMT_H264:
-			quant_param = ctx->params.h264_inter_qp;
-			break;
-		case V4L2_PIX_FMT_MPEG4:
-			quant_param = ctx->params.mpeg4_inter_qp;
-			break;
-		default:
-			v4l2_warn(&ctx->dev->v4l2_dev,
-				"cannot set inter qp, fmt not supported\n");
-			break;
-		}
-	}
-
-	/* submit */
-	coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_ENC_PIC_ROT_MODE);
-	coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
-
-
-	picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0);
-	switch (q_data_src->fourcc) {
-	case V4L2_PIX_FMT_YVU420:
-		/* Switch Cb and Cr for YVU420 format */
-		picture_cr = picture_y + q_data_src->bytesperline *
-				q_data_src->height;
-		picture_cb = picture_cr + q_data_src->bytesperline / 2 *
-				q_data_src->height / 2;
-		break;
-	case V4L2_PIX_FMT_YUV420:
-	default:
-		picture_cb = picture_y + q_data_src->bytesperline *
-				q_data_src->height;
-		picture_cr = picture_cb + q_data_src->bytesperline / 2 *
-				q_data_src->height / 2;
-		break;
-	}
-
-	if (dev->devtype->product == CODA_960) {
-		coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX);
-		coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE);
-		coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC);
-
-		coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y);
-		coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB);
-		coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR);
-	} else {
-		coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
-		coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
-		coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR);
-	}
-	coda_write(dev, force_ipicture << 1 & 0x2,
-		   CODA_CMD_ENC_PIC_OPTION);
-
-	coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
-	coda_write(dev, pic_stream_buffer_size / 1024,
-		   CODA_CMD_ENC_PIC_BB_SIZE);
-
-	if (!ctx->streamon_out) {
-		/* After streamoff on the output side, set the stream end flag */
-		ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
-		coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM);
-	}
-}
-
-static void coda_device_run(void *m2m_priv)
-{
-	struct coda_ctx *ctx = m2m_priv;
-	struct coda_dev *dev = ctx->dev;
-
-	queue_work(dev->workqueue, &ctx->pic_run_work);
-}
-
-static void coda_free_framebuffers(struct coda_ctx *ctx);
-static void coda_free_context_buffers(struct coda_ctx *ctx);
-
-static void coda_seq_end_work(struct work_struct *work)
-{
-	struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work);
-	struct coda_dev *dev = ctx->dev;
-
-	mutex_lock(&ctx->buffer_mutex);
-	mutex_lock(&dev->coda_mutex);
-
-	v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-		 "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__);
-	if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
-		v4l2_err(&dev->v4l2_dev,
-			 "CODA_COMMAND_SEQ_END failed\n");
-	}
-
-	kfifo_init(&ctx->bitstream_fifo,
-		ctx->bitstream.vaddr, ctx->bitstream.size);
-
-	coda_free_framebuffers(ctx);
-	coda_free_context_buffers(ctx);
-
-	mutex_unlock(&dev->coda_mutex);
-	mutex_unlock(&ctx->buffer_mutex);
-}
-
-static void coda_finish_decode(struct coda_ctx *ctx);
-static void coda_finish_encode(struct coda_ctx *ctx);
-
-static void coda_pic_run_work(struct work_struct *work)
-{
-	struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work);
-	struct coda_dev *dev = ctx->dev;
-	int ret;
-
-	mutex_lock(&ctx->buffer_mutex);
-	mutex_lock(&dev->coda_mutex);
-
-	if (ctx->inst_type == CODA_INST_DECODER) {
-		ret = coda_prepare_decode(ctx);
-		if (ret < 0) {
-			mutex_unlock(&dev->coda_mutex);
-			mutex_unlock(&ctx->buffer_mutex);
-			/* job_finish scheduled by prepare_decode */
-			return;
-		}
-	} else {
-		coda_prepare_encode(ctx);
-	}
-
-	if (dev->devtype->product != CODA_DX6)
-		coda_write(dev, ctx->iram_info.axi_sram_use,
-				CODA7_REG_BIT_AXI_SRAM_USE);
-
-	if (ctx->inst_type == CODA_INST_DECODER)
-		coda_kfifo_sync_to_device_full(ctx);
-	coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
-
-	if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) {
-		dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n");
-
-		ctx->hold = true;
-
-		coda_hw_reset(ctx);
-	} else if (!ctx->aborting) {
-		if (ctx->inst_type == CODA_INST_DECODER)
-			coda_finish_decode(ctx);
-		else
-			coda_finish_encode(ctx);
-	}
-
-	if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out))
-		queue_work(dev->workqueue, &ctx->seq_end_work);
-
-	mutex_unlock(&dev->coda_mutex);
-	mutex_unlock(&ctx->buffer_mutex);
-
-	v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
-}
-
-static int coda_job_ready(void *m2m_priv)
-{
-	struct coda_ctx *ctx = m2m_priv;
-
-	/*
-	 * For both 'P' and 'key' frame cases 1 picture
-	 * and 1 frame are needed. In the decoder case,
-	 * the compressed frame can be in the bitstream.
-	 */
-	if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
-	    ctx->inst_type != CODA_INST_DECODER) {
-		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-			 "not ready: not enough video buffers.\n");
-		return 0;
-	}
-
-	if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
-		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-			 "not ready: not enough video capture buffers.\n");
-		return 0;
-	}
-
-	if (ctx->hold ||
-	    ((ctx->inst_type == CODA_INST_DECODER) &&
-	     (coda_get_bitstream_payload(ctx) < 512) &&
-	     !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
-		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-			 "%d: not ready: not enough bitstream data.\n",
-			 ctx->idx);
-		return 0;
-	}
-
-	if (ctx->aborting) {
-		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-			 "not ready: aborting\n");
-		return 0;
-	}
-
-	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-			"job ready\n");
-	return 1;
-}
-
-static void coda_job_abort(void *priv)
-{
-	struct coda_ctx *ctx = priv;
-
-	ctx->aborting = 1;
-
-	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-		 "Aborting task\n");
-}
-
-static void coda_lock(void *m2m_priv)
-{
-	struct coda_ctx *ctx = m2m_priv;
-	struct coda_dev *pcdev = ctx->dev;
-	mutex_lock(&pcdev->dev_mutex);
-}
-
-static void coda_unlock(void *m2m_priv)
-{
-	struct coda_ctx *ctx = m2m_priv;
-	struct coda_dev *pcdev = ctx->dev;
-	mutex_unlock(&pcdev->dev_mutex);
-}
-
-static struct v4l2_m2m_ops coda_m2m_ops = {
-	.device_run	= coda_device_run,
-	.job_ready	= coda_job_ready,
-	.job_abort	= coda_job_abort,
-	.lock		= coda_lock,
-	.unlock		= coda_unlock,
-};
-
-static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type)
-{
-	struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
-	int luma_map, chro_map, i;
-
-	memset(tiled_map, 0, sizeof(*tiled_map));
-
-	luma_map = 64;
-	chro_map = 64;
-	tiled_map->map_type = tiled_map_type;
-	for (i = 0; i < 16; i++)
-		tiled_map->xy2ca_map[i] = luma_map << 8 | chro_map;
-	for (i = 0; i < 4; i++)
-		tiled_map->xy2ba_map[i] = luma_map << 8 | chro_map;
-	for (i = 0; i < 16; i++)
-		tiled_map->xy2ra_map[i] = luma_map << 8 | chro_map;
-
-	if (tiled_map_type == GDI_LINEAR_FRAME_MAP) {
-		tiled_map->xy2rbc_config = 0;
-	} else {
-		dev_err(&ctx->dev->plat_dev->dev, "invalid map type: %d\n",
-			tiled_map_type);
-		return;
-	}
-}
-
-static void set_default_params(struct coda_ctx *ctx)
-{
-	int max_w;
-	int max_h;
-
-	ctx->codec = &ctx->dev->devtype->codecs[0];
-	max_w = ctx->codec->max_w;
-	max_h = ctx->codec->max_h;
-
-	ctx->params.codec_mode = CODA_MODE_INVALID;
-	ctx->colorspace = V4L2_COLORSPACE_REC709;
-	ctx->params.framerate = 30;
-	ctx->aborting = 0;
-
-	/* Default formats for output and input queues */
-	ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc;
-	ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc;
-	ctx->q_data[V4L2_M2M_SRC].width = max_w;
-	ctx->q_data[V4L2_M2M_SRC].height = max_h;
-	ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w;
-	ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
-	ctx->q_data[V4L2_M2M_DST].width = max_w;
-	ctx->q_data[V4L2_M2M_DST].height = max_h;
-	ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
-	ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
-	ctx->q_data[V4L2_M2M_SRC].rect.width = max_w;
-	ctx->q_data[V4L2_M2M_SRC].rect.height = max_h;
-	ctx->q_data[V4L2_M2M_DST].rect.width = max_w;
-	ctx->q_data[V4L2_M2M_DST].rect.height = max_h;
-
-	if (ctx->dev->devtype->product == CODA_960)
-		coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP);
-}
-
-/*
- * Queue operations
- */
-static int coda_queue_setup(struct vb2_queue *vq,
-				const struct v4l2_format *fmt,
-				unsigned int *nbuffers, unsigned int *nplanes,
-				unsigned int sizes[], void *alloc_ctxs[])
-{
-	struct coda_ctx *ctx = vb2_get_drv_priv(vq);
-	struct coda_q_data *q_data;
-	unsigned int size;
-
-	q_data = get_q_data(ctx, vq->type);
-	size = q_data->sizeimage;
-
-	*nplanes = 1;
-	sizes[0] = size;
-
-	alloc_ctxs[0] = ctx->dev->alloc_ctx;
-
-	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-		 "get %d buffer(s) of size %d each.\n", *nbuffers, size);
-
-	return 0;
-}
-
-static int coda_buf_prepare(struct vb2_buffer *vb)
-{
-	struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-	struct coda_q_data *q_data;
-
-	q_data = get_q_data(ctx, vb->vb2_queue->type);
-
-	if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
-		v4l2_warn(&ctx->dev->v4l2_dev,
-			  "%s data will not fit into plane (%lu < %lu)\n",
-			  __func__, vb2_plane_size(vb, 0),
-			  (long)q_data->sizeimage);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static void coda_buf_queue(struct vb2_buffer *vb)
-{
-	struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-	struct coda_dev *dev = ctx->dev;
-	struct coda_q_data *q_data;
-
-	q_data = get_q_data(ctx, vb->vb2_queue->type);
-
-	/*
-	 * In the decoder case, immediately try to copy the buffer into the
-	 * bitstream ringbuffer and mark it as ready to be dequeued.
-	 */
-	if (q_data->fourcc == V4L2_PIX_FMT_H264 &&
-	    vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-		/*
-		 * For backwards compatibility, queuing an empty buffer marks
-		 * the stream end
-		 */
-		if (vb2_get_plane_payload(vb, 0) == 0) {
-			ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
-			if ((dev->devtype->product == CODA_960) &&
-			    coda_isbusy(dev) &&
-			    (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
-				/* if this decoder instance is running, set the stream end flag */
-				coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM);
-			}
-		}
-		mutex_lock(&ctx->bitstream_mutex);
-		v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
-		coda_fill_bitstream(ctx);
-		mutex_unlock(&ctx->bitstream_mutex);
-	} else {
-		v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
-	}
-}
-
-static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
-{
-	struct coda_dev *dev = ctx->dev;
-	u32 *p = ctx->parabuf.vaddr;
-
-	if (dev->devtype->product == CODA_DX6)
-		p[index] = value;
-	else
-		p[index ^ 1] = value;
-}
-
-static int coda_alloc_aux_buf(struct coda_dev *dev,
-			      struct coda_aux_buf *buf, size_t size,
-			      const char *name, struct dentry *parent)
-{
-	buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr,
-					GFP_KERNEL);
-	if (!buf->vaddr)
-		return -ENOMEM;
-
-	buf->size = size;
-
-	if (name && parent) {
-		buf->blob.data = buf->vaddr;
-		buf->blob.size = size;
-		buf->dentry = debugfs_create_blob(name, 0644, parent, &buf->blob);
-		if (!buf->dentry)
-			dev_warn(&dev->plat_dev->dev,
-				 "failed to create debugfs entry %s\n", name);
-	}
-
-	return 0;
-}
-
-static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
-					 struct coda_aux_buf *buf, size_t size,
-					 const char *name)
-{
-	return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry);
-}
-
-static void coda_free_aux_buf(struct coda_dev *dev,
-			      struct coda_aux_buf *buf)
-{
-	if (buf->vaddr) {
-		dma_free_coherent(&dev->plat_dev->dev, buf->size,
-				  buf->vaddr, buf->paddr);
-		buf->vaddr = NULL;
-		buf->size = 0;
-	}
-	debugfs_remove(buf->dentry);
-}
-
-static void coda_free_framebuffers(struct coda_ctx *ctx)
-{
-	int i;
-
-	for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++)
-		coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]);
-}
-
-static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc)
-{
-	struct coda_dev *dev = ctx->dev;
-	int width, height;
-	dma_addr_t paddr;
-	int ysize;
-	int ret;
-	int i;
-
-	if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
-	     ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) {
-		width = round_up(q_data->width, 16);
-		height = round_up(q_data->height, 16);
-	} else {
-		width = round_up(q_data->width, 8);
-		height = q_data->height;
-	}
-	ysize = width * height;
-
-	/* Allocate frame buffers */
-	for (i = 0; i < ctx->num_internal_frames; i++) {
-		size_t size;
-		char *name;
-
-		size = ysize + ysize / 2;
-		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
-		    dev->devtype->product != CODA_DX6)
-			size += ysize / 4;
-		name = kasprintf(GFP_KERNEL, "fb%d", i);
-		ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i],
-					     size, name);
-		kfree(name);
-		if (ret < 0) {
-			coda_free_framebuffers(ctx);
-			return ret;
-		}
-	}
-
-	/* Register frame buffers in the parameter buffer */
-	for (i = 0; i < ctx->num_internal_frames; i++) {
-		paddr = ctx->internal_frames[i].paddr;
-		coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */
-		coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */
-		coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */
-
-		/* mvcol buffer for h.264 */
-		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
-		    dev->devtype->product != CODA_DX6)
-			coda_parabuf_write(ctx, 96 + i,
-					   ctx->internal_frames[i].paddr +
-					   ysize + ysize/4 + ysize/4);
-	}
-
-	/* mvcol buffer for mpeg4 */
-	if ((dev->devtype->product != CODA_DX6) &&
-	    (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4))
-		coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr +
-					    ysize + ysize/4 + ysize/4);
-
-	return 0;
-}
-
-static int coda_h264_padding(int size, char *p)
-{
-	int nal_size;
-	int diff;
-
-	diff = size - (size & ~0x7);
-	if (diff == 0)
-		return 0;
-
-	nal_size = coda_filler_size[diff];
-	memcpy(p, coda_filler_nal, nal_size);
-
-	/* Add rbsp stop bit and trailing at the end */
-	*(p + nal_size - 1) = 0x80;
-
-	return nal_size;
-}
-
-static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size)
-{
-	phys_addr_t ret;
-
-	size = round_up(size, 1024);
-	if (size > iram->remaining)
-		return 0;
-	iram->remaining -= size;
-
-	ret = iram->next_paddr;
-	iram->next_paddr += size;
-
-	return ret;
-}
-
-static void coda_setup_iram(struct coda_ctx *ctx)
-{
-	struct coda_iram_info *iram_info = &ctx->iram_info;
-	struct coda_dev *dev = ctx->dev;
-	int mb_width;
-	int dbk_bits;
-	int bit_bits;
-	int ip_bits;
-
-	memset(iram_info, 0, sizeof(*iram_info));
-	iram_info->next_paddr = dev->iram.paddr;
-	iram_info->remaining = dev->iram.size;
-
-	switch (dev->devtype->product) {
-	case CODA_7541:
-		dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE;
-		bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
-		ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
-		break;
-	case CODA_960:
-		dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE;
-		bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
-		ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
-		break;
-	default: /* CODA_DX6 */
-		return;
-	}
-
-	if (ctx->inst_type == CODA_INST_ENCODER) {
-		struct coda_q_data *q_data_src;
-
-		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-		mb_width = DIV_ROUND_UP(q_data_src->width, 16);
-
-		/* Prioritize in case IRAM is too small for everything */
-		if (dev->devtype->product == CODA_7541) {
-			iram_info->search_ram_size = round_up(mb_width * 16 *
-							      36 + 2048, 1024);
-			iram_info->search_ram_paddr = coda_iram_alloc(iram_info,
-							iram_info->search_ram_size);
-			if (!iram_info->search_ram_paddr) {
-				pr_err("IRAM is smaller than the search ram size\n");
-				goto out;
-			}
-			iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE |
-						   CODA7_USE_ME_ENABLE;
-		}
-
-		/* Only H.264BP and H.263P3 are considered */
-		iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 64 * mb_width);
-		iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 64 * mb_width);
-		if (!iram_info->buf_dbk_c_use)
-			goto out;
-		iram_info->axi_sram_use |= dbk_bits;
-
-		iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width);
-		if (!iram_info->buf_bit_use)
-			goto out;
-		iram_info->axi_sram_use |= bit_bits;
-
-		iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width);
-		if (!iram_info->buf_ip_ac_dc_use)
-			goto out;
-		iram_info->axi_sram_use |= ip_bits;
-
-		/* OVL and BTP disabled for encoder */
-	} else if (ctx->inst_type == CODA_INST_DECODER) {
-		struct coda_q_data *q_data_dst;
-
-		q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-		mb_width = DIV_ROUND_UP(q_data_dst->width, 16);
-
-		iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 128 * mb_width);
-		iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 128 * mb_width);
-		if (!iram_info->buf_dbk_c_use)
-			goto out;
-		iram_info->axi_sram_use |= dbk_bits;
-
-		iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width);
-		if (!iram_info->buf_bit_use)
-			goto out;
-		iram_info->axi_sram_use |= bit_bits;
-
-		iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width);
-		if (!iram_info->buf_ip_ac_dc_use)
-			goto out;
-		iram_info->axi_sram_use |= ip_bits;
-
-		/* OVL and BTP unused as there is no VC1 support yet */
-	}
-
-out:
-	if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE))
-		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-			 "IRAM smaller than needed\n");
-
-	if (dev->devtype->product == CODA_7541) {
-		/* TODO - Enabling these causes picture errors on CODA7541 */
-		if (ctx->inst_type == CODA_INST_DECODER) {
-			/* fw 1.4.50 */
-			iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
-						     CODA7_USE_IP_ENABLE);
-		} else {
-			/* fw 13.4.29 */
-			iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
-						     CODA7_USE_HOST_DBK_ENABLE |
-						     CODA7_USE_IP_ENABLE |
-						     CODA7_USE_DBK_ENABLE);
-		}
-	}
-}
-
-static void coda_free_context_buffers(struct coda_ctx *ctx)
-{
-	struct coda_dev *dev = ctx->dev;
-
-	coda_free_aux_buf(dev, &ctx->slicebuf);
-	coda_free_aux_buf(dev, &ctx->psbuf);
-	if (dev->devtype->product != CODA_DX6)
-		coda_free_aux_buf(dev, &ctx->workbuf);
-}
-
-static int coda_alloc_context_buffers(struct coda_ctx *ctx,
-				      struct coda_q_data *q_data)
-{
-	struct coda_dev *dev = ctx->dev;
-	size_t size;
-	int ret;
-
-	if (dev->devtype->product == CODA_DX6)
-		return 0;
-
-	if (ctx->psbuf.vaddr) {
-		v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n");
-		return -EBUSY;
-	}
-	if (ctx->slicebuf.vaddr) {
-		v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n");
-		return -EBUSY;
-	}
-	if (ctx->workbuf.vaddr) {
-		v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
-		ret = -EBUSY;
-		return -ENOMEM;
-	}
-
-	if (q_data->fourcc == V4L2_PIX_FMT_H264) {
-		/* worst case slice size */
-		size = (DIV_ROUND_UP(q_data->width, 16) *
-			DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512;
-		ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf");
-		if (ret < 0) {
-			v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer",
-				 ctx->slicebuf.size);
-			return ret;
-		}
-	}
-
-	if (dev->devtype->product == CODA_7541) {
-		ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf");
-		if (ret < 0) {
-			v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer");
-			goto err;
-		}
-	}
-
-	size = dev->devtype->workbuf_size;
-	if (dev->devtype->product == CODA_960 &&
-	    q_data->fourcc == V4L2_PIX_FMT_H264)
-		size += CODA9_PS_SAVE_SIZE;
-	ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf");
-	if (ret < 0) {
-		v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer",
-			 ctx->workbuf.size);
-		goto err;
-	}
-
-	return 0;
-
-err:
-	coda_free_context_buffers(ctx);
-	return ret;
-}
-
-static int coda_start_decoding(struct coda_ctx *ctx)
-{
-	struct coda_q_data *q_data_src, *q_data_dst;
-	u32 bitstream_buf, bitstream_size;
-	struct coda_dev *dev = ctx->dev;
-	int width, height;
-	u32 src_fourcc;
-	u32 val;
-	int ret;
-
-	/* Start decoding */
-	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-	bitstream_buf = ctx->bitstream.paddr;
-	bitstream_size = ctx->bitstream.size;
-	src_fourcc = q_data_src->fourcc;
-
-	coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
-
-	/* Update coda bitstream read and write pointers from kfifo */
-	coda_kfifo_sync_to_device_full(ctx);
-
-	ctx->display_idx = -1;
-	ctx->frm_dis_flg = 0;
-	coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
-
-	coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE,
-			CODA_REG_BIT_BIT_STREAM_PARAM);
-
-	coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START);
-	coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE);
-	val = 0;
-	if ((dev->devtype->product == CODA_7541) ||
-	    (dev->devtype->product == CODA_960))
-		val |= CODA_REORDER_ENABLE;
-	coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
-
-	ctx->params.codec_mode = ctx->codec->mode;
-	if (dev->devtype->product == CODA_960 &&
-	    src_fourcc == V4L2_PIX_FMT_MPEG4)
-		ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4;
-	else
-		ctx->params.codec_mode_aux = 0;
-	if (src_fourcc == V4L2_PIX_FMT_H264) {
-		if (dev->devtype->product == CODA_7541) {
-			coda_write(dev, ctx->psbuf.paddr,
-					CODA_CMD_DEC_SEQ_PS_BB_START);
-			coda_write(dev, (CODA7_PS_BUF_SIZE / 1024),
-					CODA_CMD_DEC_SEQ_PS_BB_SIZE);
-		}
-		if (dev->devtype->product == CODA_960) {
-			coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN);
-			coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE);
-		}
-	}
-	if (dev->devtype->product != CODA_960) {
-		coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE);
-	}
-
-	if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
-		v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
-		coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
-		return -ETIMEDOUT;
-	}
-
-	/* Update kfifo out pointer from coda bitstream read pointer */
-	coda_kfifo_sync_from_device(ctx);
-
-	coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
-
-	if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) {
-		v4l2_err(&dev->v4l2_dev,
-			"CODA_COMMAND_SEQ_INIT failed, error code = %d\n",
-			coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON));
-		return -EAGAIN;
-	}
-
-	val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE);
-	if (dev->devtype->product == CODA_DX6) {
-		width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK;
-		height = val & CODADX6_PICHEIGHT_MASK;
-	} else {
-		width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK;
-		height = val & CODA7_PICHEIGHT_MASK;
-	}
-
-	if (width > q_data_dst->width || height > q_data_dst->height) {
-		v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n",
-			 width, height, q_data_dst->width, q_data_dst->height);
-		return -EINVAL;
-	}
-
-	width = round_up(width, 16);
-	height = round_up(height, 16);
-
-	v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n",
-		 __func__, ctx->idx, width, height);
-
-	ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED);
-	if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) {
-		v4l2_err(&dev->v4l2_dev,
-			 "not enough framebuffers to decode (%d < %d)\n",
-			 CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames);
-		return -EINVAL;
-	}
-
-	if (src_fourcc == V4L2_PIX_FMT_H264) {
-		u32 left_right;
-		u32 top_bottom;
-
-		left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT);
-		top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM);
-
-		q_data_dst->rect.left = (left_right >> 10) & 0x3ff;
-		q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff;
-		q_data_dst->rect.width = width - q_data_dst->rect.left -
-					 (left_right & 0x3ff);
-		q_data_dst->rect.height = height - q_data_dst->rect.top -
-					  (top_bottom & 0x3ff);
-	}
-
-	ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
-	if (ret < 0)
-		return ret;
-
-	/* Tell the decoder how many frame buffers we allocated. */
-	coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
-	coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE);
-
-	if (dev->devtype->product != CODA_DX6) {
-		/* Set secondary AXI IRAM */
-		coda_setup_iram(ctx);
-
-		coda_write(dev, ctx->iram_info.buf_bit_use,
-				CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
-		coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
-				CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
-		coda_write(dev, ctx->iram_info.buf_dbk_y_use,
-				CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
-		coda_write(dev, ctx->iram_info.buf_dbk_c_use,
-				CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
-		coda_write(dev, ctx->iram_info.buf_ovl_use,
-				CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
-		if (dev->devtype->product == CODA_960)
-			coda_write(dev, ctx->iram_info.buf_btp_use,
-					CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
-	}
-
-	if (dev->devtype->product == CODA_960) {
-		coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY);
-
-		coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE);
-		coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET |
-				32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
-				8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET |
-				8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET,
-				CODA9_CMD_SET_FRAME_CACHE_CONFIG);
-	}
-
-	if (src_fourcc == V4L2_PIX_FMT_H264) {
-		coda_write(dev, ctx->slicebuf.paddr,
-				CODA_CMD_SET_FRAME_SLICE_BB_START);
-		coda_write(dev, ctx->slicebuf.size / 1024,
-				CODA_CMD_SET_FRAME_SLICE_BB_SIZE);
-	}
-
-	if (dev->devtype->product == CODA_7541) {
-		int max_mb_x = 1920 / 16;
-		int max_mb_y = 1088 / 16;
-		int max_mb_num = max_mb_x * max_mb_y;
-
-		coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
-				CODA7_CMD_SET_FRAME_MAX_DEC_SIZE);
-	} else if (dev->devtype->product == CODA_960) {
-		int max_mb_x = 1920 / 16;
-		int max_mb_y = 1088 / 16;
-		int max_mb_num = max_mb_x * max_mb_y;
-
-		coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
-				CODA9_CMD_SET_FRAME_MAX_DEC_SIZE);
-	}
-
-	if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
-		v4l2_err(&ctx->dev->v4l2_dev,
-			 "CODA_COMMAND_SET_FRAME_BUF timeout\n");
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
-static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
-			      int header_code, u8 *header, int *size)
-{
-	struct coda_dev *dev = ctx->dev;
-	size_t bufsize;
-	int ret;
-	int i;
-
-	if (dev->devtype->product == CODA_960)
-		memset(vb2_plane_vaddr(buf, 0), 0, 64);
-
-	coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0),
-		   CODA_CMD_ENC_HEADER_BB_START);
-	bufsize = vb2_plane_size(buf, 0);
-	if (dev->devtype->product == CODA_960)
-		bufsize /= 1024;
-	coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE);
-	coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE);
-	ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER);
-	if (ret < 0) {
-		v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
-		return ret;
-	}
-
-	if (dev->devtype->product == CODA_960) {
-		for (i = 63; i > 0; i--)
-			if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0)
-				break;
-		*size = i + 1;
-	} else {
-		*size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
-			coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
-	}
-	memcpy(header, vb2_plane_vaddr(buf, 0), *size);
-
-	return 0;
-}
-
-static int coda_start_encoding(struct coda_ctx *ctx);
-
-static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
-{
-	struct coda_ctx *ctx = vb2_get_drv_priv(q);
-	struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev;
-	struct coda_dev *dev = ctx->dev;
-	struct coda_q_data *q_data_src, *q_data_dst;
-	u32 dst_fourcc;
-	int ret = 0;
-
-	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-		if (q_data_src->fourcc == V4L2_PIX_FMT_H264) {
-			if (coda_get_bitstream_payload(ctx) < 512)
-				return -EINVAL;
-		} else {
-			if (count < 1)
-				return -EINVAL;
-		}
-
-		ctx->streamon_out = 1;
-
-		if (coda_format_is_yuv(q_data_src->fourcc))
-			ctx->inst_type = CODA_INST_ENCODER;
-		else
-			ctx->inst_type = CODA_INST_DECODER;
-	} else {
-		if (count < 1)
-			return -EINVAL;
-
-		ctx->streamon_cap = 1;
-	}
-
-	/* Don't start the coda unless both queues are on */
-	if (!(ctx->streamon_out & ctx->streamon_cap))
-		return 0;
-
-	/* Allow decoder device_run with no new buffers queued */
-	if (ctx->inst_type == CODA_INST_DECODER)
-		v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
-
-	ctx->gopcounter = ctx->params.gop_size - 1;
-	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-	dst_fourcc = q_data_dst->fourcc;
-
-	ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
-				     q_data_dst->fourcc);
-	if (!ctx->codec) {
-		v4l2_err(v4l2_dev, "couldn't tell instance type.\n");
-		return -EINVAL;
-	}
-
-	/* Allocate per-instance buffers */
-	ret = coda_alloc_context_buffers(ctx, q_data_src);
-	if (ret < 0)
-		return ret;
-
-	if (ctx->inst_type == CODA_INST_DECODER) {
-		mutex_lock(&dev->coda_mutex);
-		ret = coda_start_decoding(ctx);
-		mutex_unlock(&dev->coda_mutex);
-		if (ret == -EAGAIN)
-			return 0;
-		else if (ret < 0)
-			return ret;
-	} else {
-		ret = coda_start_encoding(ctx);
-	}
-
-	ctx->initialized = 1;
-	return ret;
-}
-
-static int coda_start_encoding(struct coda_ctx *ctx)
-{
-	struct coda_dev *dev = ctx->dev;
-	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
-	struct coda_q_data *q_data_src, *q_data_dst;
-	u32 bitstream_buf, bitstream_size;
-	struct vb2_buffer *buf;
-	int gamma, ret, value;
-	u32 dst_fourcc;
-
-	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-	dst_fourcc = q_data_dst->fourcc;
-
-	buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-	bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
-	bitstream_size = q_data_dst->sizeimage;
-
-	if (!coda_is_initialized(dev)) {
-		v4l2_err(v4l2_dev, "coda is not initialized.\n");
-		return -EFAULT;
-	}
-
-	mutex_lock(&dev->coda_mutex);
-
-	coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
-	coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
-	coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
-	switch (dev->devtype->product) {
-	case CODA_DX6:
-		coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
-			CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
-		break;
-	case CODA_960:
-		coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
-		/* fallthrough */
-	case CODA_7541:
-		coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
-			CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
-		break;
-	}
-
-	value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL);
-	value &= ~(1 << 2 | 0x7 << 9);
-	ctx->frame_mem_ctrl = value;
-	coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL);
-
-	if (dev->devtype->product == CODA_DX6) {
-		/* Configure the coda */
-		coda_write(dev, dev->iram.paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR);
-	}
-
-	/* Could set rotation here if needed */
-	switch (dev->devtype->product) {
-	case CODA_DX6:
-		value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET;
-		value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
-		break;
-	case CODA_7541:
-		if (dst_fourcc == V4L2_PIX_FMT_H264) {
-			value = (round_up(q_data_src->width, 16) &
-				 CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
-			value |= (round_up(q_data_src->height, 16) &
-				  CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
-			break;
-		}
-		/* fallthrough */
-	case CODA_960:
-		value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
-		value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
-	}
-	coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
-	coda_write(dev, ctx->params.framerate,
-		   CODA_CMD_ENC_SEQ_SRC_F_RATE);
-
-	ctx->params.codec_mode = ctx->codec->mode;
-	switch (dst_fourcc) {
-	case V4L2_PIX_FMT_MPEG4:
-		if (dev->devtype->product == CODA_960)
-			coda_write(dev, CODA9_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
-		else
-			coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
-		coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
-		break;
-	case V4L2_PIX_FMT_H264:
-		if (dev->devtype->product == CODA_960)
-			coda_write(dev, CODA9_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
-		else
-			coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
-		if (ctx->params.h264_deblk_enabled) {
-			value = ((ctx->params.h264_deblk_alpha &
-				  CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
-				 CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
-				((ctx->params.h264_deblk_beta &
-				  CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
-				 CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET);
-		} else {
-			value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET;
-		}
-		coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
-		break;
-	default:
-		v4l2_err(v4l2_dev,
-			 "dst format (0x%08x) invalid.\n", dst_fourcc);
-		ret = -EINVAL;
-		goto out;
-	}
-
-	switch (ctx->params.slice_mode) {
-	case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
-		value = 0;
-		break;
-	case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
-		value  = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET;
-		value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET;
-		value |=  1 & CODA_SLICING_MODE_MASK;
-		break;
-	case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
-		value  = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET;
-		value |= (0 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET;
-		value |=  1 & CODA_SLICING_MODE_MASK;
-		break;
-	}
-	coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
-	value = ctx->params.gop_size & CODA_GOP_SIZE_MASK;
-	coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
-
-	if (ctx->params.bitrate) {
-		/* Rate control enabled */
-		value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET;
-		value |=  1 & CODA_RATECONTROL_ENABLE_MASK;
-		if (dev->devtype->product == CODA_960)
-			value |= BIT(31); /* disable autoskip */
-	} else {
-		value = 0;
-	}
-	coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA);
-
-	coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE);
-	coda_write(dev, ctx->params.intra_refresh,
-		   CODA_CMD_ENC_SEQ_INTRA_REFRESH);
-
-	coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START);
-	coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE);
-
-
-	value = 0;
-	if (dev->devtype->product == CODA_960)
-		gamma = CODA9_DEFAULT_GAMMA;
-	else
-		gamma = CODA_DEFAULT_GAMMA;
-	if (gamma > 0) {
-		coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET,
-			   CODA_CMD_ENC_SEQ_RC_GAMMA);
-	}
-
-	if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) {
-		coda_write(dev,
-			   ctx->params.h264_min_qp << CODA_QPMIN_OFFSET |
-			   ctx->params.h264_max_qp << CODA_QPMAX_OFFSET,
-			   CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX);
-	}
-	if (dev->devtype->product == CODA_960) {
-		if (ctx->params.h264_max_qp)
-			value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET;
-		if (CODA_DEFAULT_GAMMA > 0)
-			value |= 1 << CODA9_OPTION_GAMMA_OFFSET;
-	} else {
-		if (CODA_DEFAULT_GAMMA > 0) {
-			if (dev->devtype->product == CODA_DX6)
-				value |= 1 << CODADX6_OPTION_GAMMA_OFFSET;
-			else
-				value |= 1 << CODA7_OPTION_GAMMA_OFFSET;
-		}
-		if (ctx->params.h264_min_qp)
-			value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET;
-		if (ctx->params.h264_max_qp)
-			value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET;
-	}
-	coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
-
-	coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE);
-
-	coda_setup_iram(ctx);
-
-	if (dst_fourcc == V4L2_PIX_FMT_H264) {
-		switch (dev->devtype->product) {
-		case CODA_DX6:
-			value = FMO_SLICE_SAVE_BUF_SIZE << 7;
-			coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO);
-			break;
-		case CODA_7541:
-			coda_write(dev, ctx->iram_info.search_ram_paddr,
-					CODA7_CMD_ENC_SEQ_SEARCH_BASE);
-			coda_write(dev, ctx->iram_info.search_ram_size,
-					CODA7_CMD_ENC_SEQ_SEARCH_SIZE);
-			break;
-		case CODA_960:
-			coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION);
-			coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT);
-		}
-	}
-
-	ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT);
-	if (ret < 0) {
-		v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
-		goto out;
-	}
-
-	if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) {
-		v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n");
-		ret = -EFAULT;
-		goto out;
-	}
-
-	if (dev->devtype->product == CODA_960)
-		ctx->num_internal_frames = 4;
-	else
-		ctx->num_internal_frames = 2;
-	ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
-	if (ret < 0) {
-		v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
-		goto out;
-	}
-
-	coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
-	coda_write(dev, q_data_src->bytesperline,
-			CODA_CMD_SET_FRAME_BUF_STRIDE);
-	if (dev->devtype->product == CODA_7541) {
-		coda_write(dev, q_data_src->bytesperline,
-				CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
-	}
-	if (dev->devtype->product != CODA_DX6) {
-		coda_write(dev, ctx->iram_info.buf_bit_use,
-				CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
-		coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
-				CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
-		coda_write(dev, ctx->iram_info.buf_dbk_y_use,
-				CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
-		coda_write(dev, ctx->iram_info.buf_dbk_c_use,
-				CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
-		coda_write(dev, ctx->iram_info.buf_ovl_use,
-				CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
-		if (dev->devtype->product == CODA_960) {
-			coda_write(dev, ctx->iram_info.buf_btp_use,
-					CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
-
-			/* FIXME */
-			coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A);
-			coda_write(dev, ctx->internal_frames[3].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B);
-		}
-	}
-
-	ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF);
-	if (ret < 0) {
-		v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
-		goto out;
-	}
-
-	/* Save stream headers */
-	buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-	switch (dst_fourcc) {
-	case V4L2_PIX_FMT_H264:
-		/*
-		 * Get SPS in the first frame and copy it to an
-		 * intermediate buffer.
-		 */
-		ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS,
-					 &ctx->vpu_header[0][0],
-					 &ctx->vpu_header_size[0]);
-		if (ret < 0)
-			goto out;
-
-		/*
-		 * Get PPS in the first frame and copy it to an
-		 * intermediate buffer.
-		 */
-		ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS,
-					 &ctx->vpu_header[1][0],
-					 &ctx->vpu_header_size[1]);
-		if (ret < 0)
-			goto out;
-
-		/*
-		 * Length of H.264 headers is variable and thus it might not be
-		 * aligned for the coda to append the encoded frame. In that is
-		 * the case a filler NAL must be added to header 2.
-		 */
-		ctx->vpu_header_size[2] = coda_h264_padding(
-					(ctx->vpu_header_size[0] +
-					 ctx->vpu_header_size[1]),
-					 ctx->vpu_header[2]);
-		break;
-	case V4L2_PIX_FMT_MPEG4:
-		/*
-		 * Get VOS in the first frame and copy it to an
-		 * intermediate buffer
-		 */
-		ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS,
-					 &ctx->vpu_header[0][0],
-					 &ctx->vpu_header_size[0]);
-		if (ret < 0)
-			goto out;
-
-		ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS,
-					 &ctx->vpu_header[1][0],
-					 &ctx->vpu_header_size[1]);
-		if (ret < 0)
-			goto out;
-
-		ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL,
-					 &ctx->vpu_header[2][0],
-					 &ctx->vpu_header_size[2]);
-		if (ret < 0)
-			goto out;
-		break;
-	default:
-		/* No more formats need to save headers at the moment */
-		break;
-	}
-
-out:
-	mutex_unlock(&dev->coda_mutex);
-	return ret;
-}
-
-static void coda_stop_streaming(struct vb2_queue *q)
-{
-	struct coda_ctx *ctx = vb2_get_drv_priv(q);
-	struct coda_dev *dev = ctx->dev;
-
-	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-		v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-			 "%s: output\n", __func__);
-		ctx->streamon_out = 0;
-
-		if (ctx->inst_type == CODA_INST_DECODER &&
-		    coda_isbusy(dev) && ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX)) {
-			/* if this decoder instance is running, set the stream end flag */
-			if (dev->devtype->product == CODA_960) {
-				u32 val = coda_read(dev, CODA_REG_BIT_BIT_STREAM_PARAM);
-
-				val |= CODA_BIT_STREAM_END_FLAG;
-				coda_write(dev, val, CODA_REG_BIT_BIT_STREAM_PARAM);
-				ctx->bit_stream_param = val;
-			}
-		}
-		ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
-
-		ctx->isequence = 0;
-	} else {
-		v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-			 "%s: capture\n", __func__);
-		ctx->streamon_cap = 0;
-
-		ctx->osequence = 0;
-		ctx->sequence_offset = 0;
-	}
-
-	if (!ctx->streamon_out && !ctx->streamon_cap) {
-		struct coda_timestamp *ts;
-
-		while (!list_empty(&ctx->timestamp_list)) {
-			ts = list_first_entry(&ctx->timestamp_list,
-					      struct coda_timestamp, list);
-			list_del(&ts->list);
-			kfree(ts);
-		}
-		kfifo_init(&ctx->bitstream_fifo,
-			ctx->bitstream.vaddr, ctx->bitstream.size);
-		ctx->runcounter = 0;
-	}
-}
-
-static struct vb2_ops coda_qops = {
-	.queue_setup		= coda_queue_setup,
-	.buf_prepare		= coda_buf_prepare,
-	.buf_queue		= coda_buf_queue,
-	.start_streaming	= coda_start_streaming,
-	.stop_streaming		= coda_stop_streaming,
-	.wait_prepare		= vb2_ops_wait_prepare,
-	.wait_finish		= vb2_ops_wait_finish,
-};
-
-static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct coda_ctx *ctx =
-			container_of(ctrl->handler, struct coda_ctx, ctrls);
-
-	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-		 "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
-
-	switch (ctrl->id) {
-	case V4L2_CID_HFLIP:
-		if (ctrl->val)
-			ctx->params.rot_mode |= CODA_MIR_HOR;
-		else
-			ctx->params.rot_mode &= ~CODA_MIR_HOR;
-		break;
-	case V4L2_CID_VFLIP:
-		if (ctrl->val)
-			ctx->params.rot_mode |= CODA_MIR_VER;
-		else
-			ctx->params.rot_mode &= ~CODA_MIR_VER;
-		break;
-	case V4L2_CID_MPEG_VIDEO_BITRATE:
-		ctx->params.bitrate = ctrl->val / 1000;
-		break;
-	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-		ctx->params.gop_size = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
-		ctx->params.h264_intra_qp = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
-		ctx->params.h264_inter_qp = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
-		ctx->params.h264_min_qp = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
-		ctx->params.h264_max_qp = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
-		ctx->params.h264_deblk_alpha = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
-		ctx->params.h264_deblk_beta = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
-		ctx->params.h264_deblk_enabled = (ctrl->val ==
-				V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
-		break;
-	case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
-		ctx->params.mpeg4_intra_qp = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
-		ctx->params.mpeg4_inter_qp = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
-		ctx->params.slice_mode = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
-		ctx->params.slice_max_mb = ctrl->val;
-		break;
-	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
-		ctx->params.slice_max_bits = ctrl->val * 8;
-		break;
-	case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
-		break;
-	case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
-		ctx->params.intra_refresh = ctrl->val;
-		break;
-	default:
-		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-			"Invalid control, id=%d, val=%d\n",
-			ctrl->id, ctrl->val);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static struct v4l2_ctrl_ops coda_ctrl_ops = {
-	.s_ctrl = coda_s_ctrl,
-};
-
-static int coda_ctrls_setup(struct coda_ctx *ctx)
-{
-	v4l2_ctrl_handler_init(&ctx->ctrls, 9);
-
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_HFLIP, 0, 1, 1, 0);
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_VFLIP, 0, 1, 1, 0);
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25);
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25);
-	if (ctx->dev->devtype->product != CODA_960) {
-		v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-			V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12);
-	}
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51);
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0);
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0);
-	v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
-		V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0,
-		V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2);
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2);
-	v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
-		V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0,
-		V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1);
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, 500);
-	v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_HEADER_MODE,
-		V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
-		(1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE),
-		V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
-	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
-		V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 1920 * 1088 / 256, 1, 0);
-
-	if (ctx->ctrls.error) {
-		v4l2_err(&ctx->dev->v4l2_dev, "control initialization error (%d)",
-			ctx->ctrls.error);
-		return -EINVAL;
-	}
-
-	return v4l2_ctrl_handler_setup(&ctx->ctrls);
-}
-
-static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
-		      struct vb2_queue *dst_vq)
-{
-	struct coda_ctx *ctx = priv;
-	int ret;
-
-	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-	src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
-	src_vq->drv_priv = ctx;
-	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
-	src_vq->ops = &coda_qops;
-	src_vq->mem_ops = &vb2_dma_contig_memops;
-	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-	src_vq->lock = &ctx->dev->dev_mutex;
-
-	ret = vb2_queue_init(src_vq);
-	if (ret)
-		return ret;
-
-	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
-	dst_vq->drv_priv = ctx;
-	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
-	dst_vq->ops = &coda_qops;
-	dst_vq->mem_ops = &vb2_dma_contig_memops;
-	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-	dst_vq->lock = &ctx->dev->dev_mutex;
-
-	return vb2_queue_init(dst_vq);
-}
-
-static int coda_next_free_instance(struct coda_dev *dev)
-{
-	int idx = ffz(dev->instance_mask);
-
-	if ((idx < 0) ||
-	    (dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES))
-		return -EBUSY;
-
-	return idx;
-}
-
-static int coda_open(struct file *file)
-{
-	struct coda_dev *dev = video_drvdata(file);
-	struct coda_ctx *ctx = NULL;
-	char *name;
-	int ret;
-	int idx;
-
-	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
-	if (!ctx)
-		return -ENOMEM;
-
-	idx = coda_next_free_instance(dev);
-	if (idx < 0) {
-		ret = idx;
-		goto err_coda_max;
-	}
-	set_bit(idx, &dev->instance_mask);
-
-	name = kasprintf(GFP_KERNEL, "context%d", idx);
-	ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root);
-	kfree(name);
-
-	init_completion(&ctx->completion);
-	INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
-	INIT_WORK(&ctx->seq_end_work, coda_seq_end_work);
-	v4l2_fh_init(&ctx->fh, video_devdata(file));
-	file->private_data = &ctx->fh;
-	v4l2_fh_add(&ctx->fh);
-	ctx->dev = dev;
-	ctx->idx = idx;
-	switch (dev->devtype->product) {
-	case CODA_7541:
-	case CODA_960:
-		ctx->reg_idx = 0;
-		break;
-	default:
-		ctx->reg_idx = idx;
-	}
-
-	/* Power up and upload firmware if necessary */
-	ret = pm_runtime_get_sync(&dev->plat_dev->dev);
-	if (ret < 0) {
-		v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret);
-		goto err_pm_get;
-	}
-
-	ret = clk_prepare_enable(dev->clk_per);
-	if (ret)
-		goto err_clk_per;
-
-	ret = clk_prepare_enable(dev->clk_ahb);
-	if (ret)
-		goto err_clk_ahb;
-
-	set_default_params(ctx);
-	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
-					 &coda_queue_init);
-	if (IS_ERR(ctx->fh.m2m_ctx)) {
-		ret = PTR_ERR(ctx->fh.m2m_ctx);
-
-		v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n",
-			 __func__, ret);
-		goto err_ctx_init;
-	}
-
-	ret = coda_ctrls_setup(ctx);
-	if (ret) {
-		v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n");
-		goto err_ctrls_setup;
-	}
-
-	ctx->fh.ctrl_handler = &ctx->ctrls;
-
-	ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE,
-				     "parabuf");
-	if (ret < 0) {
-		v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
-		goto err_dma_alloc;
-	}
-
-	ctx->bitstream.size = CODA_MAX_FRAME_SIZE;
-	ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev,
-			ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL);
-	if (!ctx->bitstream.vaddr) {
-		v4l2_err(&dev->v4l2_dev, "failed to allocate bitstream ringbuffer");
-		ret = -ENOMEM;
-		goto err_dma_writecombine;
-	}
-	kfifo_init(&ctx->bitstream_fifo,
-		ctx->bitstream.vaddr, ctx->bitstream.size);
-	mutex_init(&ctx->bitstream_mutex);
-	mutex_init(&ctx->buffer_mutex);
-	INIT_LIST_HEAD(&ctx->timestamp_list);
-
-	coda_lock(ctx);
-	list_add(&ctx->list, &dev->instances);
-	coda_unlock(ctx);
-
-	v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n",
-		 ctx->idx, ctx);
-
-	return 0;
-
-err_dma_writecombine:
-	coda_free_context_buffers(ctx);
-	if (ctx->dev->devtype->product == CODA_DX6)
-		coda_free_aux_buf(dev, &ctx->workbuf);
-	coda_free_aux_buf(dev, &ctx->parabuf);
-err_dma_alloc:
-	v4l2_ctrl_handler_free(&ctx->ctrls);
-err_ctrls_setup:
-	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
-err_ctx_init:
-	clk_disable_unprepare(dev->clk_ahb);
-err_clk_ahb:
-	clk_disable_unprepare(dev->clk_per);
-err_clk_per:
-	pm_runtime_put_sync(&dev->plat_dev->dev);
-err_pm_get:
-	v4l2_fh_del(&ctx->fh);
-	v4l2_fh_exit(&ctx->fh);
-	clear_bit(ctx->idx, &dev->instance_mask);
-err_coda_max:
-	kfree(ctx);
-	return ret;
-}
-
-static int coda_release(struct file *file)
-{
-	struct coda_dev *dev = video_drvdata(file);
-	struct coda_ctx *ctx = fh_to_ctx(file->private_data);
-
-	v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
-		 ctx);
-
-	debugfs_remove_recursive(ctx->debugfs_entry);
-
-	/* If this instance is running, call .job_abort and wait for it to end */
-	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
-
-	/* In case the instance was not running, we still need to call SEQ_END */
-	if (ctx->initialized) {
-		queue_work(dev->workqueue, &ctx->seq_end_work);
-		flush_work(&ctx->seq_end_work);
-	}
-
-	coda_free_framebuffers(ctx);
-
-	coda_lock(ctx);
-	list_del(&ctx->list);
-	coda_unlock(ctx);
-
-	dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
-		ctx->bitstream.vaddr, ctx->bitstream.paddr);
-	coda_free_context_buffers(ctx);
-	if (ctx->dev->devtype->product == CODA_DX6)
-		coda_free_aux_buf(dev, &ctx->workbuf);
-
-	coda_free_aux_buf(dev, &ctx->parabuf);
-	v4l2_ctrl_handler_free(&ctx->ctrls);
-	clk_disable_unprepare(dev->clk_ahb);
-	clk_disable_unprepare(dev->clk_per);
-	pm_runtime_put_sync(&dev->plat_dev->dev);
-	v4l2_fh_del(&ctx->fh);
-	v4l2_fh_exit(&ctx->fh);
-	clear_bit(ctx->idx, &dev->instance_mask);
-	kfree(ctx);
-
-	return 0;
-}
-
-static const struct v4l2_file_operations coda_fops = {
-	.owner		= THIS_MODULE,
-	.open		= coda_open,
-	.release	= coda_release,
-	.poll		= v4l2_m2m_fop_poll,
-	.unlocked_ioctl	= video_ioctl2,
-	.mmap		= v4l2_m2m_fop_mmap,
-};
-
-static void coda_finish_decode(struct coda_ctx *ctx)
-{
-	struct coda_dev *dev = ctx->dev;
-	struct coda_q_data *q_data_src;
-	struct coda_q_data *q_data_dst;
-	struct vb2_buffer *dst_buf;
-	struct coda_timestamp *ts;
-	int width, height;
-	int decoded_idx;
-	int display_idx;
-	u32 src_fourcc;
-	int success;
-	u32 err_mb;
-	u32 val;
-
-	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-
-	/* Update kfifo out pointer from coda bitstream read pointer */
-	coda_kfifo_sync_from_device(ctx);
-
-	/*
-	 * in stream-end mode, the read pointer can overshoot the write pointer
-	 * by up to 512 bytes
-	 */
-	if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
-		if (coda_get_bitstream_payload(ctx) >= 0x100000 - 512)
-			kfifo_init(&ctx->bitstream_fifo,
-				ctx->bitstream.vaddr, ctx->bitstream.size);
-	}
-
-	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-	src_fourcc = q_data_src->fourcc;
-
-	val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS);
-	if (val != 1)
-		pr_err("DEC_PIC_SUCCESS = %d\n", val);
-
-	success = val & 0x1;
-	if (!success)
-		v4l2_err(&dev->v4l2_dev, "decode failed\n");
-
-	if (src_fourcc == V4L2_PIX_FMT_H264) {
-		if (val & (1 << 3))
-			v4l2_err(&dev->v4l2_dev,
-				 "insufficient PS buffer space (%d bytes)\n",
-				 ctx->psbuf.size);
-		if (val & (1 << 2))
-			v4l2_err(&dev->v4l2_dev,
-				 "insufficient slice buffer space (%d bytes)\n",
-				 ctx->slicebuf.size);
-	}
-
-	val = coda_read(dev, CODA_RET_DEC_PIC_SIZE);
-	width = (val >> 16) & 0xffff;
-	height = val & 0xffff;
-
-	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-
-	/* frame crop information */
-	if (src_fourcc == V4L2_PIX_FMT_H264) {
-		u32 left_right;
-		u32 top_bottom;
-
-		left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT);
-		top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM);
-
-		if (left_right == 0xffffffff && top_bottom == 0xffffffff) {
-			/* Keep current crop information */
-		} else {
-			struct v4l2_rect *rect = &q_data_dst->rect;
-
-			rect->left = left_right >> 16 & 0xffff;
-			rect->top = top_bottom >> 16 & 0xffff;
-			rect->width = width - rect->left -
-				      (left_right & 0xffff);
-			rect->height = height - rect->top -
-				       (top_bottom & 0xffff);
-		}
-	} else {
-		/* no cropping */
-	}
-
-	err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB);
-	if (err_mb > 0)
-		v4l2_err(&dev->v4l2_dev,
-			 "errors in %d macroblocks\n", err_mb);
-
-	if (dev->devtype->product == CODA_7541) {
-		val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
-		if (val == 0) {
-			/* not enough bitstream data */
-			v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-				 "prescan failed: %d\n", val);
-			ctx->hold = true;
-			return;
-		}
-	}
-
-	ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
-
-	/*
-	 * The previous display frame was copied out by the rotator,
-	 * now it can be overwritten again
-	 */
-	if (ctx->display_idx >= 0 &&
-	    ctx->display_idx < ctx->num_internal_frames) {
-		ctx->frm_dis_flg &= ~(1 << ctx->display_idx);
-		coda_write(dev, ctx->frm_dis_flg,
-				CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
-	}
-
-	/*
-	 * The index of the last decoded frame, not necessarily in
-	 * display order, and the index of the next display frame.
-	 * The latter could have been decoded in a previous run.
-	 */
-	decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX);
-	display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX);
-
-	if (decoded_idx == -1) {
-		/* no frame was decoded, but we might have a display frame */
-		if (display_idx >= 0 && display_idx < ctx->num_internal_frames)
-			ctx->sequence_offset++;
-		else if (ctx->display_idx < 0)
-			ctx->hold = true;
-	} else if (decoded_idx == -2) {
-		/* no frame was decoded, we still return the remaining buffers */
-	} else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
-		v4l2_err(&dev->v4l2_dev,
-			 "decoded frame index out of range: %d\n", decoded_idx);
-	} else {
-		ts = list_first_entry(&ctx->timestamp_list,
-				      struct coda_timestamp, list);
-		list_del(&ts->list);
-		val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
-		val -= ctx->sequence_offset;
-		if (val != (ts->sequence & 0xffff)) {
-			v4l2_err(&dev->v4l2_dev,
-				 "sequence number mismatch (%d(%d) != %d)\n",
-				 val, ctx->sequence_offset, ts->sequence);
-		}
-		ctx->frame_timestamps[decoded_idx] = *ts;
-		kfree(ts);
-
-		val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7;
-		if (val == 0)
-			ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME;
-		else if (val == 1)
-			ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME;
-		else
-			ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME;
-
-		ctx->frame_errors[decoded_idx] = err_mb;
-	}
-
-	if (display_idx == -1) {
-		/*
-		 * no more frames to be decoded, but there could still
-		 * be rotator output to dequeue
-		 */
-		ctx->hold = true;
-	} else if (display_idx == -3) {
-		/* possibly prescan failure */
-	} else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) {
-		v4l2_err(&dev->v4l2_dev,
-			 "presentation frame index out of range: %d\n",
-			 display_idx);
-	}
-
-	/* If a frame was copied out, return it */
-	if (ctx->display_idx >= 0 &&
-	    ctx->display_idx < ctx->num_internal_frames) {
-		dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-		dst_buf->v4l2_buf.sequence = ctx->osequence++;
-
-		dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
-					     V4L2_BUF_FLAG_PFRAME |
-					     V4L2_BUF_FLAG_BFRAME);
-		dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx];
-		ts = &ctx->frame_timestamps[ctx->display_idx];
-		dst_buf->v4l2_buf.timecode = ts->timecode;
-		dst_buf->v4l2_buf.timestamp = ts->timestamp;
-
-		vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2);
-
-		v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ?
-				  VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
-
-		v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-			"job finished: decoding frame (%d) (%s)\n",
-			dst_buf->v4l2_buf.sequence,
-			(dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
-			"KEYFRAME" : "PFRAME");
-	} else {
-		v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-			"job finished: no frame decoded\n");
-	}
-
-	/* The rotator will copy the current display frame next time */
-	ctx->display_idx = display_idx;
-}
-
-static void coda_finish_encode(struct coda_ctx *ctx)
-{
-	struct vb2_buffer *src_buf, *dst_buf;
-	struct coda_dev *dev = ctx->dev;
-	u32 wr_ptr, start_ptr;
-
-	src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
-	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-
-	/* Get results from the coda */
-	start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
-	wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
-
-	/* Calculate bytesused field */
-	if (dst_buf->v4l2_buf.sequence == 0) {
-		vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr +
-					ctx->vpu_header_size[0] +
-					ctx->vpu_header_size[1] +
-					ctx->vpu_header_size[2]);
-	} else {
-		vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr);
-	}
-
-	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n",
-		 wr_ptr - start_ptr);
-
-	coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
-	coda_read(dev, CODA_RET_ENC_PIC_FLAG);
-
-	if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) {
-		dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
-		dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
-	} else {
-		dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
-		dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
-	}
-
-	dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
-	dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-	dst_buf->v4l2_buf.flags |=
-		src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-	dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
-
-	v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
-
-	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-	v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
-
-	ctx->gopcounter--;
-	if (ctx->gopcounter < 0)
-		ctx->gopcounter = ctx->params.gop_size - 1;
-
-	v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
-		"job finished: encoding frame (%d) (%s)\n",
-		dst_buf->v4l2_buf.sequence,
-		(dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
-		"KEYFRAME" : "PFRAME");
-}
-
-static irqreturn_t coda_irq_handler(int irq, void *data)
-{
-	struct coda_dev *dev = data;
-	struct coda_ctx *ctx;
-
-	/* read status register to attend the IRQ */
-	coda_read(dev, CODA_REG_BIT_INT_STATUS);
-	coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
-		      CODA_REG_BIT_INT_CLEAR);
-
-	ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
-	if (ctx == NULL) {
-		v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n");
-		mutex_unlock(&dev->coda_mutex);
-		return IRQ_HANDLED;
-	}
-
-	if (ctx->aborting) {
-		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-			 "task has been aborted\n");
-	}
-
-	if (coda_isbusy(ctx->dev)) {
-		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-			 "coda is still busy!!!!\n");
-		return IRQ_NONE;
-	}
-
-	complete(&ctx->completion);
-
-	return IRQ_HANDLED;
-}
-
-static u32 coda_supported_firmwares[] = {
-	CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
-	CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
-	CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5),
-};
-
-static bool coda_firmware_supported(u32 vernum)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++)
-		if (vernum == coda_supported_firmwares[i])
-			return true;
-	return false;
-}
-
-static int coda_hw_init(struct coda_dev *dev)
-{
-	u32 data;
-	u16 *p;
-	int i, ret;
-
-	ret = clk_prepare_enable(dev->clk_per);
-	if (ret)
-		goto err_clk_per;
-
-	ret = clk_prepare_enable(dev->clk_ahb);
-	if (ret)
-		goto err_clk_ahb;
-
-	if (dev->rstc)
-		reset_control_reset(dev->rstc);
-
-	/*
-	 * Copy the first CODA_ISRAM_SIZE in the internal SRAM.
-	 * The 16-bit chars in the code buffer are in memory access
-	 * order, re-sort them to CODA order for register download.
-	 * Data in this SRAM survives a reboot.
-	 */
-	p = (u16 *)dev->codebuf.vaddr;
-	if (dev->devtype->product == CODA_DX6) {
-		for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++)  {
-			data = CODA_DOWN_ADDRESS_SET(i) |
-				CODA_DOWN_DATA_SET(p[i ^ 1]);
-			coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
-		}
-	} else {
-		for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) {
-			data = CODA_DOWN_ADDRESS_SET(i) |
-				CODA_DOWN_DATA_SET(p[round_down(i, 4) +
-							3 - (i % 4)]);
-			coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
-		}
-	}
-
-	/* Clear registers */
-	for (i = 0; i < 64; i++)
-		coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4);
-
-	/* Tell the BIT where to find everything it needs */
-	if (dev->devtype->product == CODA_960 ||
-	    dev->devtype->product == CODA_7541) {
-		coda_write(dev, dev->tempbuf.paddr,
-				CODA_REG_BIT_TEMP_BUF_ADDR);
-		coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
-	} else {
-		coda_write(dev, dev->workbuf.paddr,
-			      CODA_REG_BIT_WORK_BUF_ADDR);
-	}
-	coda_write(dev, dev->codebuf.paddr,
-		      CODA_REG_BIT_CODE_BUF_ADDR);
-	coda_write(dev, 0, CODA_REG_BIT_CODE_RUN);
-
-	/* Set default values */
-	switch (dev->devtype->product) {
-	case CODA_DX6:
-		coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
-		break;
-	default:
-		coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
-	}
-	if (dev->devtype->product == CODA_960)
-		coda_write(dev, 1 << 12, CODA_REG_BIT_FRAME_MEM_CTRL);
-	else
-		coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL);
-
-	if (dev->devtype->product != CODA_DX6)
-		coda_write(dev, 0, CODA7_REG_BIT_AXI_SRAM_USE);
-
-	coda_write(dev, CODA_INT_INTERRUPT_ENABLE,
-		      CODA_REG_BIT_INT_ENABLE);
-
-	/* Reset VPU and start processor */
-	data = coda_read(dev, CODA_REG_BIT_CODE_RESET);
-	data |= CODA_REG_RESET_ENABLE;
-	coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
-	udelay(10);
-	data &= ~CODA_REG_RESET_ENABLE;
-	coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
-	coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
-
-	clk_disable_unprepare(dev->clk_ahb);
-	clk_disable_unprepare(dev->clk_per);
-
-	return 0;
-
-err_clk_ahb:
-	clk_disable_unprepare(dev->clk_per);
-err_clk_per:
-	return ret;
-}
-
-static int coda_check_firmware(struct coda_dev *dev)
-{
-	u16 product, major, minor, release;
-	u32 data;
-	int ret;
-
-	ret = clk_prepare_enable(dev->clk_per);
-	if (ret)
-		goto err_clk_per;
-
-	ret = clk_prepare_enable(dev->clk_ahb);
-	if (ret)
-		goto err_clk_ahb;
-
-	coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM);
-	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
-	coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX);
-	coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD);
-	coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND);
-	if (coda_wait_timeout(dev)) {
-		v4l2_err(&dev->v4l2_dev, "firmware get command error\n");
-		ret = -EIO;
-		goto err_run_cmd;
-	}
-
-	if (dev->devtype->product == CODA_960) {
-		data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV);
-		v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n",
-			  data);
-	}
-
-	/* Check we are compatible with the loaded firmware */
-	data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM);
-	product = CODA_FIRMWARE_PRODUCT(data);
-	major = CODA_FIRMWARE_MAJOR(data);
-	minor = CODA_FIRMWARE_MINOR(data);
-	release = CODA_FIRMWARE_RELEASE(data);
-
-	clk_disable_unprepare(dev->clk_per);
-	clk_disable_unprepare(dev->clk_ahb);
-
-	if (product != dev->devtype->product) {
-		v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s,"
-			 " Version: %u.%u.%u\n",
-			 coda_product_name(dev->devtype->product),
-			 coda_product_name(product), major, minor, release);
-		return -EINVAL;
-	}
-
-	v4l2_info(&dev->v4l2_dev, "Initialized %s.\n",
-		  coda_product_name(product));
-
-	if (coda_firmware_supported(data)) {
-		v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n",
-			  major, minor, release);
-	} else {
-		v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: "
-			  "%u.%u.%u\n", major, minor, release);
-	}
-
-	return 0;
-
-err_run_cmd:
-	clk_disable_unprepare(dev->clk_ahb);
-err_clk_ahb:
-	clk_disable_unprepare(dev->clk_per);
-err_clk_per:
-	return ret;
-}
-
-static void coda_fw_callback(const struct firmware *fw, void *context)
-{
-	struct coda_dev *dev = context;
-	struct platform_device *pdev = dev->plat_dev;
-	int ret;
-
-	if (!fw) {
-		v4l2_err(&dev->v4l2_dev, "firmware request failed\n");
-		return;
-	}
-
-	/* allocate auxiliary per-device code buffer for the BIT processor */
-	ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf",
-				 dev->debugfs_root);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "failed to allocate code buffer\n");
-		return;
-	}
-
-	/* Copy the whole firmware image to the code buffer */
-	memcpy(dev->codebuf.vaddr, fw->data, fw->size);
-	release_firmware(fw);
-
-	if (pm_runtime_enabled(&pdev->dev) && pdev->dev.pm_domain) {
-		/*
-		 * Enabling power temporarily will cause coda_hw_init to be
-		 * called via coda_runtime_resume by the pm domain.
-		 */
-		ret = pm_runtime_get_sync(&dev->plat_dev->dev);
-		if (ret < 0) {
-			v4l2_err(&dev->v4l2_dev, "failed to power on: %d\n",
-				 ret);
-			return;
-		}
-
-		ret = coda_check_firmware(dev);
-		if (ret < 0)
-			return;
-
-		pm_runtime_put_sync(&dev->plat_dev->dev);
-	} else {
-		/*
-		 * If runtime pm is disabled or pm_domain is not set,
-		 * initialize once manually.
-		 */
-		ret = coda_hw_init(dev);
-		if (ret < 0) {
-			v4l2_err(&dev->v4l2_dev, "HW initialization failed\n");
-			return;
-		}
-
-		ret = coda_check_firmware(dev);
-		if (ret < 0)
-			return;
-	}
-
-	dev->vfd.fops	= &coda_fops,
-	dev->vfd.ioctl_ops	= &coda_ioctl_ops;
-	dev->vfd.release	= video_device_release_empty,
-	dev->vfd.lock	= &dev->dev_mutex;
-	dev->vfd.v4l2_dev	= &dev->v4l2_dev;
-	dev->vfd.vfl_dir	= VFL_DIR_M2M;
-	snprintf(dev->vfd.name, sizeof(dev->vfd.name), "%s", CODA_NAME);
-	video_set_drvdata(&dev->vfd, dev);
-
-	dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
-	if (IS_ERR(dev->alloc_ctx)) {
-		v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n");
-		return;
-	}
-
-	dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops);
-	if (IS_ERR(dev->m2m_dev)) {
-		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
-		goto rel_ctx;
-	}
-
-	ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, 0);
-	if (ret) {
-		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
-		goto rel_m2m;
-	}
-	v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video%d\n",
-		  dev->vfd.num);
-
-	return;
-
-rel_m2m:
-	v4l2_m2m_release(dev->m2m_dev);
-rel_ctx:
-	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
-}
-
-static int coda_firmware_request(struct coda_dev *dev)
-{
-	char *fw = dev->devtype->firmware;
-
-	dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
-		coda_product_name(dev->devtype->product));
-
-	return request_firmware_nowait(THIS_MODULE, true,
-		fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback);
-}
-
-enum coda_platform {
-	CODA_IMX27,
-	CODA_IMX53,
-	CODA_IMX6Q,
-	CODA_IMX6DL,
-};
-
-static const struct coda_devtype coda_devdata[] = {
-	[CODA_IMX27] = {
-		.firmware     = "v4l-codadx6-imx27.bin",
-		.product      = CODA_DX6,
-		.codecs       = codadx6_codecs,
-		.num_codecs   = ARRAY_SIZE(codadx6_codecs),
-		.workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024,
-		.iram_size    = 0xb000,
-	},
-	[CODA_IMX53] = {
-		.firmware     = "v4l-coda7541-imx53.bin",
-		.product      = CODA_7541,
-		.codecs       = coda7_codecs,
-		.num_codecs   = ARRAY_SIZE(coda7_codecs),
-		.workbuf_size = 128 * 1024,
-		.tempbuf_size = 304 * 1024,
-		.iram_size    = 0x14000,
-	},
-	[CODA_IMX6Q] = {
-		.firmware     = "v4l-coda960-imx6q.bin",
-		.product      = CODA_960,
-		.codecs       = coda9_codecs,
-		.num_codecs   = ARRAY_SIZE(coda9_codecs),
-		.workbuf_size = 80 * 1024,
-		.tempbuf_size = 204 * 1024,
-		.iram_size    = 0x21000,
-	},
-	[CODA_IMX6DL] = {
-		.firmware     = "v4l-coda960-imx6dl.bin",
-		.product      = CODA_960,
-		.codecs       = coda9_codecs,
-		.num_codecs   = ARRAY_SIZE(coda9_codecs),
-		.workbuf_size = 80 * 1024,
-		.tempbuf_size = 204 * 1024,
-		.iram_size    = 0x20000,
-	},
-};
-
-static struct platform_device_id coda_platform_ids[] = {
-	{ .name = "coda-imx27", .driver_data = CODA_IMX27 },
-	{ .name = "coda-imx53", .driver_data = CODA_IMX53 },
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, coda_platform_ids);
-
-#ifdef CONFIG_OF
-static const struct of_device_id coda_dt_ids[] = {
-	{ .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] },
-	{ .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] },
-	{ .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] },
-	{ .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] },
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, coda_dt_ids);
-#endif
-
-static int coda_probe(struct platform_device *pdev)
-{
-	const struct of_device_id *of_id =
-			of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev);
-	const struct platform_device_id *pdev_id;
-	struct coda_platform_data *pdata = pdev->dev.platform_data;
-	struct device_node *np = pdev->dev.of_node;
-	struct gen_pool *pool;
-	struct coda_dev *dev;
-	struct resource *res;
-	int ret, irq;
-
-	dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL);
-	if (!dev) {
-		dev_err(&pdev->dev, "Not enough memory for %s\n",
-			CODA_NAME);
-		return -ENOMEM;
-	}
-
-	spin_lock_init(&dev->irqlock);
-	INIT_LIST_HEAD(&dev->instances);
-
-	dev->plat_dev = pdev;
-	dev->clk_per = devm_clk_get(&pdev->dev, "per");
-	if (IS_ERR(dev->clk_per)) {
-		dev_err(&pdev->dev, "Could not get per clock\n");
-		return PTR_ERR(dev->clk_per);
-	}
-
-	dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
-	if (IS_ERR(dev->clk_ahb)) {
-		dev_err(&pdev->dev, "Could not get ahb clock\n");
-		return PTR_ERR(dev->clk_ahb);
-	}
-
-	/* Get  memory for physical registers */
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(dev->regs_base))
-		return PTR_ERR(dev->regs_base);
-
-	/* IRQ */
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(&pdev->dev, "failed to get irq resource\n");
-		return irq;
-	}
-
-	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
-			IRQF_ONESHOT, dev_name(&pdev->dev), dev);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
-		return ret;
-	}
-
-	dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL);
-	if (IS_ERR(dev->rstc)) {
-		ret = PTR_ERR(dev->rstc);
-		if (ret == -ENOENT || ret == -ENOSYS) {
-			dev->rstc = NULL;
-		} else {
-			dev_err(&pdev->dev, "failed get reset control: %d\n", ret);
-			return ret;
-		}
-	}
-
-	/* Get IRAM pool from device tree or platform data */
-	pool = of_get_named_gen_pool(np, "iram", 0);
-	if (!pool && pdata)
-		pool = dev_get_gen_pool(pdata->iram_dev);
-	if (!pool) {
-		dev_err(&pdev->dev, "iram pool not available\n");
-		return -ENOMEM;
-	}
-	dev->iram_pool = pool;
-
-	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-	if (ret)
-		return ret;
-
-	mutex_init(&dev->dev_mutex);
-	mutex_init(&dev->coda_mutex);
-
-	pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
-
-	if (of_id) {
-		dev->devtype = of_id->data;
-	} else if (pdev_id) {
-		dev->devtype = &coda_devdata[pdev_id->driver_data];
-	} else {
-		v4l2_device_unregister(&dev->v4l2_dev);
-		return -EINVAL;
-	}
-
-	dev->debugfs_root = debugfs_create_dir("coda", NULL);
-	if (!dev->debugfs_root)
-		dev_warn(&pdev->dev, "failed to create debugfs root\n");
-
-	/* allocate auxiliary per-device buffers for the BIT processor */
-	if (dev->devtype->product == CODA_DX6) {
-		ret = coda_alloc_aux_buf(dev, &dev->workbuf,
-					 dev->devtype->workbuf_size, "workbuf",
-					 dev->debugfs_root);
-		if (ret < 0) {
-			dev_err(&pdev->dev, "failed to allocate work buffer\n");
-			v4l2_device_unregister(&dev->v4l2_dev);
-			return ret;
-		}
-	}
-
-	if (dev->devtype->tempbuf_size) {
-		ret = coda_alloc_aux_buf(dev, &dev->tempbuf,
-					 dev->devtype->tempbuf_size, "tempbuf",
-					 dev->debugfs_root);
-		if (ret < 0) {
-			dev_err(&pdev->dev, "failed to allocate temp buffer\n");
-			v4l2_device_unregister(&dev->v4l2_dev);
-			return ret;
-		}
-	}
-
-	dev->iram.size = dev->devtype->iram_size;
-	dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size,
-					     &dev->iram.paddr);
-	if (!dev->iram.vaddr) {
-		dev_err(&pdev->dev, "unable to alloc iram\n");
-		return -ENOMEM;
-	}
-
-	dev->iram.blob.data = dev->iram.vaddr;
-	dev->iram.blob.size = dev->iram.size;
-	dev->iram.dentry = debugfs_create_blob("iram", 0644, dev->debugfs_root,
-					       &dev->iram.blob);
-
-	dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
-	if (!dev->workqueue) {
-		dev_err(&pdev->dev, "unable to alloc workqueue\n");
-		return -ENOMEM;
-	}
-
-	platform_set_drvdata(pdev, dev);
-
-	pm_runtime_enable(&pdev->dev);
-
-	return coda_firmware_request(dev);
-}
-
-static int coda_remove(struct platform_device *pdev)
-{
-	struct coda_dev *dev = platform_get_drvdata(pdev);
-
-	video_unregister_device(&dev->vfd);
-	if (dev->m2m_dev)
-		v4l2_m2m_release(dev->m2m_dev);
-	pm_runtime_disable(&pdev->dev);
-	if (dev->alloc_ctx)
-		vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
-	v4l2_device_unregister(&dev->v4l2_dev);
-	destroy_workqueue(dev->workqueue);
-	if (dev->iram.vaddr)
-		gen_pool_free(dev->iram_pool, (unsigned long)dev->iram.vaddr,
-			      dev->iram.size);
-	coda_free_aux_buf(dev, &dev->codebuf);
-	coda_free_aux_buf(dev, &dev->tempbuf);
-	coda_free_aux_buf(dev, &dev->workbuf);
-	debugfs_remove_recursive(dev->debugfs_root);
-	return 0;
-}
-
-#ifdef CONFIG_PM_RUNTIME
-static int coda_runtime_resume(struct device *dev)
-{
-	struct coda_dev *cdev = dev_get_drvdata(dev);
-	int ret = 0;
-
-	if (dev->pm_domain) {
-		ret = coda_hw_init(cdev);
-		if (ret)
-			v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n");
-	}
-
-	return ret;
-}
-#endif
-
-static const struct dev_pm_ops coda_pm_ops = {
-	SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL)
-};
-
-static struct platform_driver coda_driver = {
-	.probe	= coda_probe,
-	.remove	= coda_remove,
-	.driver	= {
-		.name	= CODA_NAME,
-		.owner	= THIS_MODULE,
-		.of_match_table = of_match_ptr(coda_dt_ids),
-		.pm	= &coda_pm_ops,
-	},
-	.id_table = coda_platform_ids,
-};
-
-module_platform_driver(coda_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
-MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver");
diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile
new file mode 100644
index 0000000..fb7529f
--- /dev/null
+++ b/drivers/media/platform/coda/Makefile
@@ -0,0 +1,3 @@
+coda-objs := coda-common.o coda-bit.o coda-h264.o
+
+obj-$(CPTCFG_VIDEO_CODA) += coda.o
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
new file mode 100644
index 0000000..9b8ea8b
--- /dev/null
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -0,0 +1,1861 @@
+/*
+ * Coda multi-standard codec IP - BIT processor functions
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/irqreturn.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "coda.h"
+
+#define CODA7_PS_BUF_SIZE	0x28000
+#define CODA9_PS_SAVE_SIZE	(512 * 1024)
+
+#define CODA_DEFAULT_GAMMA	4096
+#define CODA9_DEFAULT_GAMMA	24576	/* 0.75 * 32768 */
+
+static inline int coda_is_initialized(struct coda_dev *dev)
+{
+	return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0;
+}
+
+static inline unsigned long coda_isbusy(struct coda_dev *dev)
+{
+	return coda_read(dev, CODA_REG_BIT_BUSY);
+}
+
+static int coda_wait_timeout(struct coda_dev *dev)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+	while (coda_isbusy(dev)) {
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static void coda_command_async(struct coda_ctx *ctx, int cmd)
+{
+	struct coda_dev *dev = ctx->dev;
+
+	if (dev->devtype->product == CODA_960 ||
+	    dev->devtype->product == CODA_7541) {
+		/* Restore context related registers to CODA */
+		coda_write(dev, ctx->bit_stream_param,
+				CODA_REG_BIT_BIT_STREAM_PARAM);
+		coda_write(dev, ctx->frm_dis_flg,
+				CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+		coda_write(dev, ctx->frame_mem_ctrl,
+				CODA_REG_BIT_FRAME_MEM_CTRL);
+		coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
+	}
+
+	if (dev->devtype->product == CODA_960) {
+		coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR);
+		coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
+	}
+
+	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+
+	coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
+	coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
+	coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD);
+
+	coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
+}
+
+static int coda_command_sync(struct coda_ctx *ctx, int cmd)
+{
+	struct coda_dev *dev = ctx->dev;
+
+	coda_command_async(ctx, cmd);
+	return coda_wait_timeout(dev);
+}
+
+int coda_hw_reset(struct coda_ctx *ctx)
+{
+	struct coda_dev *dev = ctx->dev;
+	unsigned long timeout;
+	unsigned int idx;
+	int ret;
+
+	if (!dev->rstc)
+		return -ENOENT;
+
+	idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX);
+
+	if (dev->devtype->product == CODA_960) {
+		timeout = jiffies + msecs_to_jiffies(100);
+		coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL);
+		while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) {
+			if (time_after(jiffies, timeout))
+				return -ETIME;
+			cpu_relax();
+		}
+	}
+
+	ret = reset_control_reset(dev->rstc);
+	if (ret < 0)
+		return ret;
+
+	if (dev->devtype->product == CODA_960)
+		coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL);
+	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+	coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
+	ret = coda_wait_timeout(dev);
+	coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX);
+
+	return ret;
+}
+
+static void coda_kfifo_sync_from_device(struct coda_ctx *ctx)
+{
+	struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
+	struct coda_dev *dev = ctx->dev;
+	u32 rd_ptr;
+
+	rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+	kfifo->out = (kfifo->in & ~kfifo->mask) |
+		      (rd_ptr - ctx->bitstream.paddr);
+	if (kfifo->out > kfifo->in)
+		kfifo->out -= kfifo->mask + 1;
+}
+
+static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx)
+{
+	struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
+	struct coda_dev *dev = ctx->dev;
+	u32 rd_ptr, wr_ptr;
+
+	rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask);
+	coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+	wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
+	coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+}
+
+static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx)
+{
+	struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo;
+	struct coda_dev *dev = ctx->dev;
+	u32 wr_ptr;
+
+	wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask);
+	coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+}
+
+static int coda_bitstream_queue(struct coda_ctx *ctx,
+				struct vb2_buffer *src_buf)
+{
+	u32 src_size = vb2_get_plane_payload(src_buf, 0);
+	u32 n;
+
+	n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0),
+		     src_size);
+	if (n < src_size)
+		return -ENOSPC;
+
+	dma_sync_single_for_device(&ctx->dev->plat_dev->dev,
+				   ctx->bitstream.paddr, ctx->bitstream.size,
+				   DMA_TO_DEVICE);
+
+	src_buf->v4l2_buf.sequence = ctx->qsequence++;
+
+	return 0;
+}
+
+static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
+				     struct vb2_buffer *src_buf)
+{
+	int ret;
+
+	if (coda_get_bitstream_payload(ctx) +
+	    vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size)
+		return false;
+
+	if (vb2_plane_vaddr(src_buf, 0) == NULL) {
+		v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n");
+		return true;
+	}
+
+	ret = coda_bitstream_queue(ctx, src_buf);
+	if (ret < 0) {
+		v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n");
+		return false;
+	}
+	/* Sync read pointer to device */
+	if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
+		coda_kfifo_sync_to_device_write(ctx);
+
+	ctx->hold = false;
+
+	return true;
+}
+
+void coda_fill_bitstream(struct coda_ctx *ctx)
+{
+	struct vb2_buffer *src_buf;
+	struct coda_timestamp *ts;
+
+	while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
+		src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+
+		if (coda_bitstream_try_queue(ctx, src_buf)) {
+			/*
+			 * Source buffer is queued in the bitstream ringbuffer;
+			 * queue the timestamp and mark source buffer as done
+			 */
+			src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+
+			ts = kmalloc(sizeof(*ts), GFP_KERNEL);
+			if (ts) {
+				ts->sequence = src_buf->v4l2_buf.sequence;
+				ts->timecode = src_buf->v4l2_buf.timecode;
+				ts->timestamp = src_buf->v4l2_buf.timestamp;
+				list_add_tail(&ts->list, &ctx->timestamp_list);
+			}
+
+			v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+		} else {
+			break;
+		}
+	}
+}
+
+void coda_bit_stream_end_flag(struct coda_ctx *ctx)
+{
+	struct coda_dev *dev = ctx->dev;
+
+	ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+
+	/* If this context is currently running, update the hardware flag */
+	if ((dev->devtype->product == CODA_960) &&
+	    coda_isbusy(dev) &&
+	    (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
+		coda_write(dev, ctx->bit_stream_param,
+			   CODA_REG_BIT_BIT_STREAM_PARAM);
+	}
+}
+
+static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
+{
+	struct coda_dev *dev = ctx->dev;
+	u32 *p = ctx->parabuf.vaddr;
+
+	if (dev->devtype->product == CODA_DX6)
+		p[index] = value;
+	else
+		p[index ^ 1] = value;
+}
+
+static void coda_free_framebuffers(struct coda_ctx *ctx)
+{
+	int i;
+
+	for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++)
+		coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]);
+}
+
+static int coda_alloc_framebuffers(struct coda_ctx *ctx,
+				   struct coda_q_data *q_data, u32 fourcc)
+{
+	struct coda_dev *dev = ctx->dev;
+	int width, height;
+	dma_addr_t paddr;
+	int ysize;
+	int ret;
+	int i;
+
+	if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
+	     ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) {
+		width = round_up(q_data->width, 16);
+		height = round_up(q_data->height, 16);
+	} else {
+		width = round_up(q_data->width, 8);
+		height = q_data->height;
+	}
+	ysize = width * height;
+
+	/* Allocate frame buffers */
+	for (i = 0; i < ctx->num_internal_frames; i++) {
+		size_t size;
+		char *name;
+
+		size = ysize + ysize / 2;
+		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
+		    dev->devtype->product != CODA_DX6)
+			size += ysize / 4;
+		name = kasprintf(GFP_KERNEL, "fb%d", i);
+		ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i],
+					     size, name);
+		kfree(name);
+		if (ret < 0) {
+			coda_free_framebuffers(ctx);
+			return ret;
+		}
+	}
+
+	/* Register frame buffers in the parameter buffer */
+	for (i = 0; i < ctx->num_internal_frames; i++) {
+		paddr = ctx->internal_frames[i].paddr;
+		/* Start addresses of Y, Cb, Cr planes */
+		coda_parabuf_write(ctx, i * 3 + 0, paddr);
+		coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize);
+		coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize / 4);
+
+		/* mvcol buffer for h.264 */
+		if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
+		    dev->devtype->product != CODA_DX6)
+			coda_parabuf_write(ctx, 96 + i,
+					   ctx->internal_frames[i].paddr +
+					   ysize + ysize/4 + ysize/4);
+	}
+
+	/* mvcol buffer for mpeg4 */
+	if ((dev->devtype->product != CODA_DX6) &&
+	    (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4))
+		coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr +
+					    ysize + ysize/4 + ysize/4);
+
+	return 0;
+}
+
+static void coda_free_context_buffers(struct coda_ctx *ctx)
+{
+	struct coda_dev *dev = ctx->dev;
+
+	coda_free_aux_buf(dev, &ctx->slicebuf);
+	coda_free_aux_buf(dev, &ctx->psbuf);
+	if (dev->devtype->product != CODA_DX6)
+		coda_free_aux_buf(dev, &ctx->workbuf);
+}
+
+static int coda_alloc_context_buffers(struct coda_ctx *ctx,
+				      struct coda_q_data *q_data)
+{
+	struct coda_dev *dev = ctx->dev;
+	size_t size;
+	int ret;
+
+	if (dev->devtype->product == CODA_DX6)
+		return 0;
+
+	if (ctx->psbuf.vaddr) {
+		v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n");
+		return -EBUSY;
+	}
+	if (ctx->slicebuf.vaddr) {
+		v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n");
+		return -EBUSY;
+	}
+	if (ctx->workbuf.vaddr) {
+		v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
+		ret = -EBUSY;
+		return -ENOMEM;
+	}
+
+	if (q_data->fourcc == V4L2_PIX_FMT_H264) {
+		/* worst case slice size */
+		size = (DIV_ROUND_UP(q_data->width, 16) *
+			DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512;
+		ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size,
+					     "slicebuf");
+		if (ret < 0) {
+			v4l2_err(&dev->v4l2_dev,
+				 "failed to allocate %d byte slice buffer",
+				 ctx->slicebuf.size);
+			return ret;
+		}
+	}
+
+	if (dev->devtype->product == CODA_7541) {
+		ret = coda_alloc_context_buf(ctx, &ctx->psbuf,
+					     CODA7_PS_BUF_SIZE, "psbuf");
+		if (ret < 0) {
+			v4l2_err(&dev->v4l2_dev,
+				 "failed to allocate psmem buffer");
+			goto err;
+		}
+	}
+
+	size = dev->devtype->workbuf_size;
+	if (dev->devtype->product == CODA_960 &&
+	    q_data->fourcc == V4L2_PIX_FMT_H264)
+		size += CODA9_PS_SAVE_SIZE;
+	ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf");
+	if (ret < 0) {
+		v4l2_err(&dev->v4l2_dev,
+			 "failed to allocate %d byte context buffer",
+			 ctx->workbuf.size);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	coda_free_context_buffers(ctx);
+	return ret;
+}
+
+static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
+			      int header_code, u8 *header, int *size)
+{
+	struct coda_dev *dev = ctx->dev;
+	size_t bufsize;
+	int ret;
+	int i;
+
+	if (dev->devtype->product == CODA_960)
+		memset(vb2_plane_vaddr(buf, 0), 0, 64);
+
+	coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0),
+		   CODA_CMD_ENC_HEADER_BB_START);
+	bufsize = vb2_plane_size(buf, 0);
+	if (dev->devtype->product == CODA_960)
+		bufsize /= 1024;
+	coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE);
+	coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE);
+	ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER);
+	if (ret < 0) {
+		v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+		return ret;
+	}
+
+	if (dev->devtype->product == CODA_960) {
+		for (i = 63; i > 0; i--)
+			if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0)
+				break;
+		*size = i + 1;
+	} else {
+		*size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
+			coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+	}
+	memcpy(header, vb2_plane_vaddr(buf, 0), *size);
+
+	return 0;
+}
+
+static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size)
+{
+	phys_addr_t ret;
+
+	size = round_up(size, 1024);
+	if (size > iram->remaining)
+		return 0;
+	iram->remaining -= size;
+
+	ret = iram->next_paddr;
+	iram->next_paddr += size;
+
+	return ret;
+}
+
+static void coda_setup_iram(struct coda_ctx *ctx)
+{
+	struct coda_iram_info *iram_info = &ctx->iram_info;
+	struct coda_dev *dev = ctx->dev;
+	int w64, w128;
+	int mb_width;
+	int dbk_bits;
+	int bit_bits;
+	int ip_bits;
+
+	memset(iram_info, 0, sizeof(*iram_info));
+	iram_info->next_paddr = dev->iram.paddr;
+	iram_info->remaining = dev->iram.size;
+
+	if (!dev->iram.vaddr)
+		return;
+
+	switch (dev->devtype->product) {
+	case CODA_7541:
+		dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE;
+		bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
+		ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
+		break;
+	case CODA_960:
+		dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE;
+		bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
+		ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
+		break;
+	default: /* CODA_DX6 */
+		return;
+	}
+
+	if (ctx->inst_type == CODA_INST_ENCODER) {
+		struct coda_q_data *q_data_src;
+
+		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+		mb_width = DIV_ROUND_UP(q_data_src->width, 16);
+		w128 = mb_width * 128;
+		w64 = mb_width * 64;
+
+		/* Prioritize in case IRAM is too small for everything */
+		if (dev->devtype->product == CODA_7541) {
+			iram_info->search_ram_size = round_up(mb_width * 16 *
+							      36 + 2048, 1024);
+			iram_info->search_ram_paddr = coda_iram_alloc(iram_info,
+						iram_info->search_ram_size);
+			if (!iram_info->search_ram_paddr) {
+				pr_err("IRAM is smaller than the search ram size\n");
+				goto out;
+			}
+			iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE |
+						   CODA7_USE_ME_ENABLE;
+		}
+
+		/* Only H.264BP and H.263P3 are considered */
+		iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64);
+		iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64);
+		if (!iram_info->buf_dbk_c_use)
+			goto out;
+		iram_info->axi_sram_use |= dbk_bits;
+
+		iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128);
+		if (!iram_info->buf_bit_use)
+			goto out;
+		iram_info->axi_sram_use |= bit_bits;
+
+		iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128);
+		if (!iram_info->buf_ip_ac_dc_use)
+			goto out;
+		iram_info->axi_sram_use |= ip_bits;
+
+		/* OVL and BTP disabled for encoder */
+	} else if (ctx->inst_type == CODA_INST_DECODER) {
+		struct coda_q_data *q_data_dst;
+
+		q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+		mb_width = DIV_ROUND_UP(q_data_dst->width, 16);
+		w128 = mb_width * 128;
+
+		iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128);
+		iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128);
+		if (!iram_info->buf_dbk_c_use)
+			goto out;
+		iram_info->axi_sram_use |= dbk_bits;
+
+		iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128);
+		if (!iram_info->buf_bit_use)
+			goto out;
+		iram_info->axi_sram_use |= bit_bits;
+
+		iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128);
+		if (!iram_info->buf_ip_ac_dc_use)
+			goto out;
+		iram_info->axi_sram_use |= ip_bits;
+
+		/* OVL and BTP unused as there is no VC1 support yet */
+	}
+
+out:
+	if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE))
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "IRAM smaller than needed\n");
+
+	if (dev->devtype->product == CODA_7541) {
+		/* TODO - Enabling these causes picture errors on CODA7541 */
+		if (ctx->inst_type == CODA_INST_DECODER) {
+			/* fw 1.4.50 */
+			iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
+						     CODA7_USE_IP_ENABLE);
+		} else {
+			/* fw 13.4.29 */
+			iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE |
+						     CODA7_USE_HOST_DBK_ENABLE |
+						     CODA7_USE_IP_ENABLE |
+						     CODA7_USE_DBK_ENABLE);
+		}
+	}
+}
+
+static u32 coda_supported_firmwares[] = {
+	CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
+	CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
+	CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5),
+};
+
+static bool coda_firmware_supported(u32 vernum)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++)
+		if (vernum == coda_supported_firmwares[i])
+			return true;
+	return false;
+}
+
+int coda_check_firmware(struct coda_dev *dev)
+{
+	u16 product, major, minor, release;
+	u32 data;
+	int ret;
+
+	ret = clk_prepare_enable(dev->clk_per);
+	if (ret)
+		goto err_clk_per;
+
+	ret = clk_prepare_enable(dev->clk_ahb);
+	if (ret)
+		goto err_clk_ahb;
+
+	coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM);
+	coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+	coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX);
+	coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD);
+	coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND);
+	if (coda_wait_timeout(dev)) {
+		v4l2_err(&dev->v4l2_dev, "firmware get command error\n");
+		ret = -EIO;
+		goto err_run_cmd;
+	}
+
+	if (dev->devtype->product == CODA_960) {
+		data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV);
+		v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n",
+			  data);
+	}
+
+	/* Check we are compatible with the loaded firmware */
+	data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM);
+	product = CODA_FIRMWARE_PRODUCT(data);
+	major = CODA_FIRMWARE_MAJOR(data);
+	minor = CODA_FIRMWARE_MINOR(data);
+	release = CODA_FIRMWARE_RELEASE(data);
+
+	clk_disable_unprepare(dev->clk_per);
+	clk_disable_unprepare(dev->clk_ahb);
+
+	if (product != dev->devtype->product) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Wrong firmware. Hw: %s, Fw: %s, Version: %u.%u.%u\n",
+			 coda_product_name(dev->devtype->product),
+			 coda_product_name(product), major, minor, release);
+		return -EINVAL;
+	}
+
+	v4l2_info(&dev->v4l2_dev, "Initialized %s.\n",
+		  coda_product_name(product));
+
+	if (coda_firmware_supported(data)) {
+		v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n",
+			  major, minor, release);
+	} else {
+		v4l2_warn(&dev->v4l2_dev,
+			  "Unsupported firmware version: %u.%u.%u\n",
+			  major, minor, release);
+	}
+
+	return 0;
+
+err_run_cmd:
+	clk_disable_unprepare(dev->clk_ahb);
+err_clk_ahb:
+	clk_disable_unprepare(dev->clk_per);
+err_clk_per:
+	return ret;
+}
+
+/*
+ * Encoder context operations
+ */
+
+static int coda_start_encoding(struct coda_ctx *ctx)
+{
+	struct coda_dev *dev = ctx->dev;
+	struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+	struct coda_q_data *q_data_src, *q_data_dst;
+	u32 bitstream_buf, bitstream_size;
+	struct vb2_buffer *buf;
+	int gamma, ret, value;
+	u32 dst_fourcc;
+
+	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	dst_fourcc = q_data_dst->fourcc;
+
+	/* Allocate per-instance buffers */
+	ret = coda_alloc_context_buffers(ctx, q_data_src);
+	if (ret < 0)
+		return ret;
+
+	buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+	bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
+	bitstream_size = q_data_dst->sizeimage;
+
+	if (!coda_is_initialized(dev)) {
+		v4l2_err(v4l2_dev, "coda is not initialized.\n");
+		return -EFAULT;
+	}
+
+	mutex_lock(&dev->coda_mutex);
+
+	coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
+	coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
+	coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+	switch (dev->devtype->product) {
+	case CODA_DX6:
+		coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
+			CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+		break;
+	case CODA_960:
+		coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
+		/* fallthrough */
+	case CODA_7541:
+		coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
+			CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+		break;
+	}
+
+	value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL);
+	value &= ~(1 << 2 | 0x7 << 9);
+	ctx->frame_mem_ctrl = value;
+	coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL);
+
+	if (dev->devtype->product == CODA_DX6) {
+		/* Configure the coda */
+		coda_write(dev, dev->iram.paddr,
+			   CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR);
+	}
+
+	/* Could set rotation here if needed */
+	switch (dev->devtype->product) {
+	case CODA_DX6:
+		value = (q_data_src->width & CODADX6_PICWIDTH_MASK)
+			<< CODADX6_PICWIDTH_OFFSET;
+		value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK)
+			 << CODA_PICHEIGHT_OFFSET;
+		break;
+	case CODA_7541:
+		if (dst_fourcc == V4L2_PIX_FMT_H264) {
+			value = (round_up(q_data_src->width, 16) &
+				 CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
+			value |= (round_up(q_data_src->height, 16) &
+				 CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
+			break;
+		}
+		/* fallthrough */
+	case CODA_960:
+		value = (q_data_src->width & CODA7_PICWIDTH_MASK)
+			<< CODA7_PICWIDTH_OFFSET;
+		value |= (q_data_src->height & CODA7_PICHEIGHT_MASK)
+			 << CODA_PICHEIGHT_OFFSET;
+	}
+	coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
+	coda_write(dev, ctx->params.framerate,
+		   CODA_CMD_ENC_SEQ_SRC_F_RATE);
+
+	ctx->params.codec_mode = ctx->codec->mode;
+	switch (dst_fourcc) {
+	case V4L2_PIX_FMT_MPEG4:
+		if (dev->devtype->product == CODA_960)
+			coda_write(dev, CODA9_STD_MPEG4,
+				   CODA_CMD_ENC_SEQ_COD_STD);
+		else
+			coda_write(dev, CODA_STD_MPEG4,
+				   CODA_CMD_ENC_SEQ_COD_STD);
+		coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
+		break;
+	case V4L2_PIX_FMT_H264:
+		if (dev->devtype->product == CODA_960)
+			coda_write(dev, CODA9_STD_H264,
+				   CODA_CMD_ENC_SEQ_COD_STD);
+		else
+			coda_write(dev, CODA_STD_H264,
+				   CODA_CMD_ENC_SEQ_COD_STD);
+		if (ctx->params.h264_deblk_enabled) {
+			value = ((ctx->params.h264_deblk_alpha &
+				  CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
+				 CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
+				((ctx->params.h264_deblk_beta &
+				  CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
+				 CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET);
+		} else {
+			value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET;
+		}
+		coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
+		break;
+	default:
+		v4l2_err(v4l2_dev,
+			 "dst format (0x%08x) invalid.\n", dst_fourcc);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	switch (ctx->params.slice_mode) {
+	case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+		value = 0;
+		break;
+	case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+		value  = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK)
+			 << CODA_SLICING_SIZE_OFFSET;
+		value |= (1 & CODA_SLICING_UNIT_MASK)
+			 << CODA_SLICING_UNIT_OFFSET;
+		value |=  1 & CODA_SLICING_MODE_MASK;
+		break;
+	case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+		value  = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK)
+			 << CODA_SLICING_SIZE_OFFSET;
+		value |= (0 & CODA_SLICING_UNIT_MASK)
+			 << CODA_SLICING_UNIT_OFFSET;
+		value |=  1 & CODA_SLICING_MODE_MASK;
+		break;
+	}
+	coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
+	value = ctx->params.gop_size & CODA_GOP_SIZE_MASK;
+	coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
+
+	if (ctx->params.bitrate) {
+		/* Rate control enabled */
+		value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK)
+			<< CODA_RATECONTROL_BITRATE_OFFSET;
+		value |=  1 & CODA_RATECONTROL_ENABLE_MASK;
+		if (dev->devtype->product == CODA_960)
+			value |= BIT(31); /* disable autoskip */
+	} else {
+		value = 0;
+	}
+	coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA);
+
+	coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE);
+	coda_write(dev, ctx->params.intra_refresh,
+		   CODA_CMD_ENC_SEQ_INTRA_REFRESH);
+
+	coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START);
+	coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE);
+
+
+	value = 0;
+	if (dev->devtype->product == CODA_960)
+		gamma = CODA9_DEFAULT_GAMMA;
+	else
+		gamma = CODA_DEFAULT_GAMMA;
+	if (gamma > 0) {
+		coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET,
+			   CODA_CMD_ENC_SEQ_RC_GAMMA);
+	}
+
+	if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) {
+		coda_write(dev,
+			   ctx->params.h264_min_qp << CODA_QPMIN_OFFSET |
+			   ctx->params.h264_max_qp << CODA_QPMAX_OFFSET,
+			   CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX);
+	}
+	if (dev->devtype->product == CODA_960) {
+		if (ctx->params.h264_max_qp)
+			value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET;
+		if (CODA_DEFAULT_GAMMA > 0)
+			value |= 1 << CODA9_OPTION_GAMMA_OFFSET;
+	} else {
+		if (CODA_DEFAULT_GAMMA > 0) {
+			if (dev->devtype->product == CODA_DX6)
+				value |= 1 << CODADX6_OPTION_GAMMA_OFFSET;
+			else
+				value |= 1 << CODA7_OPTION_GAMMA_OFFSET;
+		}
+		if (ctx->params.h264_min_qp)
+			value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET;
+		if (ctx->params.h264_max_qp)
+			value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET;
+	}
+	coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
+
+	coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE);
+
+	coda_setup_iram(ctx);
+
+	if (dst_fourcc == V4L2_PIX_FMT_H264) {
+		switch (dev->devtype->product) {
+		case CODA_DX6:
+			value = FMO_SLICE_SAVE_BUF_SIZE << 7;
+			coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO);
+			break;
+		case CODA_7541:
+			coda_write(dev, ctx->iram_info.search_ram_paddr,
+					CODA7_CMD_ENC_SEQ_SEARCH_BASE);
+			coda_write(dev, ctx->iram_info.search_ram_size,
+					CODA7_CMD_ENC_SEQ_SEARCH_SIZE);
+			break;
+		case CODA_960:
+			coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION);
+			coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT);
+		}
+	}
+
+	ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT);
+	if (ret < 0) {
+		v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
+		goto out;
+	}
+
+	if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) {
+		v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n");
+		ret = -EFAULT;
+		goto out;
+	}
+
+	if (dev->devtype->product == CODA_960)
+		ctx->num_internal_frames = 4;
+	else
+		ctx->num_internal_frames = 2;
+	ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
+	if (ret < 0) {
+		v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
+		goto out;
+	}
+
+	coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
+	coda_write(dev, q_data_src->bytesperline,
+			CODA_CMD_SET_FRAME_BUF_STRIDE);
+	if (dev->devtype->product == CODA_7541) {
+		coda_write(dev, q_data_src->bytesperline,
+				CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
+	}
+	if (dev->devtype->product != CODA_DX6) {
+		coda_write(dev, ctx->iram_info.buf_bit_use,
+				CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
+		coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
+				CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
+		coda_write(dev, ctx->iram_info.buf_dbk_y_use,
+				CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
+		coda_write(dev, ctx->iram_info.buf_dbk_c_use,
+				CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
+		coda_write(dev, ctx->iram_info.buf_ovl_use,
+				CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
+		if (dev->devtype->product == CODA_960) {
+			coda_write(dev, ctx->iram_info.buf_btp_use,
+					CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
+
+			/* FIXME */
+			coda_write(dev, ctx->internal_frames[2].paddr,
+				   CODA9_CMD_SET_FRAME_SUBSAMP_A);
+			coda_write(dev, ctx->internal_frames[3].paddr,
+				   CODA9_CMD_SET_FRAME_SUBSAMP_B);
+		}
+	}
+
+	ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF);
+	if (ret < 0) {
+		v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
+		goto out;
+	}
+
+	/* Save stream headers */
+	buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+	switch (dst_fourcc) {
+	case V4L2_PIX_FMT_H264:
+		/*
+		 * Get SPS in the first frame and copy it to an
+		 * intermediate buffer.
+		 */
+		ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS,
+					 &ctx->vpu_header[0][0],
+					 &ctx->vpu_header_size[0]);
+		if (ret < 0)
+			goto out;
+
+		/*
+		 * Get PPS in the first frame and copy it to an
+		 * intermediate buffer.
+		 */
+		ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS,
+					 &ctx->vpu_header[1][0],
+					 &ctx->vpu_header_size[1]);
+		if (ret < 0)
+			goto out;
+
+		/*
+		 * Length of H.264 headers is variable and thus it might not be
+		 * aligned for the coda to append the encoded frame. In that is
+		 * the case a filler NAL must be added to header 2.
+		 */
+		ctx->vpu_header_size[2] = coda_h264_padding(
+					(ctx->vpu_header_size[0] +
+					 ctx->vpu_header_size[1]),
+					 ctx->vpu_header[2]);
+		break;
+	case V4L2_PIX_FMT_MPEG4:
+		/*
+		 * Get VOS in the first frame and copy it to an
+		 * intermediate buffer
+		 */
+		ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS,
+					 &ctx->vpu_header[0][0],
+					 &ctx->vpu_header_size[0]);
+		if (ret < 0)
+			goto out;
+
+		ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS,
+					 &ctx->vpu_header[1][0],
+					 &ctx->vpu_header_size[1]);
+		if (ret < 0)
+			goto out;
+
+		ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL,
+					 &ctx->vpu_header[2][0],
+					 &ctx->vpu_header_size[2]);
+		if (ret < 0)
+			goto out;
+		break;
+	default:
+		/* No more formats need to save headers at the moment */
+		break;
+	}
+
+out:
+	mutex_unlock(&dev->coda_mutex);
+	return ret;
+}
+
+static int coda_prepare_encode(struct coda_ctx *ctx)
+{
+	struct coda_q_data *q_data_src, *q_data_dst;
+	struct vb2_buffer *src_buf, *dst_buf;
+	struct coda_dev *dev = ctx->dev;
+	int force_ipicture;
+	int quant_param = 0;
+	u32 picture_y, picture_cb, picture_cr;
+	u32 pic_stream_buffer_addr, pic_stream_buffer_size;
+	u32 dst_fourcc;
+
+	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	dst_fourcc = q_data_dst->fourcc;
+
+	src_buf->v4l2_buf.sequence = ctx->osequence;
+	dst_buf->v4l2_buf.sequence = ctx->osequence;
+	ctx->osequence++;
+
+	/*
+	 * Workaround coda firmware BUG that only marks the first
+	 * frame as IDR. This is a problem for some decoders that can't
+	 * recover when a frame is lost.
+	 */
+	if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) {
+		src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+		src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+	} else {
+		src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+		src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+	}
+
+	if (dev->devtype->product == CODA_960)
+		coda_set_gdi_regs(ctx);
+
+	/*
+	 * Copy headers at the beginning of the first frame for H.264 only.
+	 * In MPEG4 they are already copied by the coda.
+	 */
+	if (src_buf->v4l2_buf.sequence == 0) {
+		pic_stream_buffer_addr =
+			vb2_dma_contig_plane_dma_addr(dst_buf, 0) +
+			ctx->vpu_header_size[0] +
+			ctx->vpu_header_size[1] +
+			ctx->vpu_header_size[2];
+		pic_stream_buffer_size = CODA_MAX_FRAME_SIZE -
+			ctx->vpu_header_size[0] -
+			ctx->vpu_header_size[1] -
+			ctx->vpu_header_size[2];
+		memcpy(vb2_plane_vaddr(dst_buf, 0),
+		       &ctx->vpu_header[0][0], ctx->vpu_header_size[0]);
+		memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0],
+		       &ctx->vpu_header[1][0], ctx->vpu_header_size[1]);
+		memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] +
+			ctx->vpu_header_size[1], &ctx->vpu_header[2][0],
+			ctx->vpu_header_size[2]);
+	} else {
+		pic_stream_buffer_addr =
+			vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+		pic_stream_buffer_size = CODA_MAX_FRAME_SIZE;
+	}
+
+	if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
+		force_ipicture = 1;
+		switch (dst_fourcc) {
+		case V4L2_PIX_FMT_H264:
+			quant_param = ctx->params.h264_intra_qp;
+			break;
+		case V4L2_PIX_FMT_MPEG4:
+			quant_param = ctx->params.mpeg4_intra_qp;
+			break;
+		default:
+			v4l2_warn(&ctx->dev->v4l2_dev,
+				"cannot set intra qp, fmt not supported\n");
+			break;
+		}
+	} else {
+		force_ipicture = 0;
+		switch (dst_fourcc) {
+		case V4L2_PIX_FMT_H264:
+			quant_param = ctx->params.h264_inter_qp;
+			break;
+		case V4L2_PIX_FMT_MPEG4:
+			quant_param = ctx->params.mpeg4_inter_qp;
+			break;
+		default:
+			v4l2_warn(&ctx->dev->v4l2_dev,
+				"cannot set inter qp, fmt not supported\n");
+			break;
+		}
+	}
+
+	/* submit */
+	coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
+		   CODA_CMD_ENC_PIC_ROT_MODE);
+	coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
+
+
+	picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+	switch (q_data_src->fourcc) {
+	case V4L2_PIX_FMT_YVU420:
+		/* Switch Cb and Cr for YVU420 format */
+		picture_cr = picture_y + q_data_src->bytesperline *
+				q_data_src->height;
+		picture_cb = picture_cr + q_data_src->bytesperline / 2 *
+				q_data_src->height / 2;
+		break;
+	case V4L2_PIX_FMT_YUV420:
+	default:
+		picture_cb = picture_y + q_data_src->bytesperline *
+				q_data_src->height;
+		picture_cr = picture_cb + q_data_src->bytesperline / 2 *
+				q_data_src->height / 2;
+		break;
+	}
+
+	if (dev->devtype->product == CODA_960) {
+		coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX);
+		coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE);
+		coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC);
+
+		coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y);
+		coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB);
+		coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR);
+	} else {
+		coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
+		coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
+		coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR);
+	}
+	coda_write(dev, force_ipicture << 1 & 0x2,
+		   CODA_CMD_ENC_PIC_OPTION);
+
+	coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
+	coda_write(dev, pic_stream_buffer_size / 1024,
+		   CODA_CMD_ENC_PIC_BB_SIZE);
+
+	if (!ctx->streamon_out) {
+		/* After streamoff on the output side, set stream end flag */
+		ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+		coda_write(dev, ctx->bit_stream_param,
+			   CODA_REG_BIT_BIT_STREAM_PARAM);
+	}
+
+	if (dev->devtype->product != CODA_DX6)
+		coda_write(dev, ctx->iram_info.axi_sram_use,
+				CODA7_REG_BIT_AXI_SRAM_USE);
+
+	coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
+
+	return 0;
+}
+
+static void coda_finish_encode(struct coda_ctx *ctx)
+{
+	struct vb2_buffer *src_buf, *dst_buf;
+	struct coda_dev *dev = ctx->dev;
+	u32 wr_ptr, start_ptr;
+
+	src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+	/* Get results from the coda */
+	start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
+	wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
+
+	/* Calculate bytesused field */
+	if (dst_buf->v4l2_buf.sequence == 0) {
+		vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr +
+					ctx->vpu_header_size[0] +
+					ctx->vpu_header_size[1] +
+					ctx->vpu_header_size[2]);
+	} else {
+		vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr);
+	}
+
+	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n",
+		 wr_ptr - start_ptr);
+
+	coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
+	coda_read(dev, CODA_RET_ENC_PIC_FLAG);
+
+	if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) {
+		dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+		dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+	} else {
+		dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+		dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+	}
+
+	dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
+	dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+	dst_buf->v4l2_buf.flags |=
+		src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+	dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
+
+	v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+
+	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+	v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+
+	ctx->gopcounter--;
+	if (ctx->gopcounter < 0)
+		ctx->gopcounter = ctx->params.gop_size - 1;
+
+	v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+		"job finished: encoding frame (%d) (%s)\n",
+		dst_buf->v4l2_buf.sequence,
+		(dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
+		"KEYFRAME" : "PFRAME");
+}
+
+static void coda_seq_end_work(struct work_struct *work)
+{
+	struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work);
+	struct coda_dev *dev = ctx->dev;
+
+	mutex_lock(&ctx->buffer_mutex);
+	mutex_lock(&dev->coda_mutex);
+
+	v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+		 "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx,
+		 __func__);
+	if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
+		v4l2_err(&dev->v4l2_dev,
+			 "CODA_COMMAND_SEQ_END failed\n");
+	}
+
+	kfifo_init(&ctx->bitstream_fifo,
+		ctx->bitstream.vaddr, ctx->bitstream.size);
+
+	coda_free_framebuffers(ctx);
+	coda_free_context_buffers(ctx);
+
+	mutex_unlock(&dev->coda_mutex);
+	mutex_unlock(&ctx->buffer_mutex);
+}
+
+static void coda_bit_release(struct coda_ctx *ctx)
+{
+	coda_free_framebuffers(ctx);
+	coda_free_context_buffers(ctx);
+}
+
+const struct coda_context_ops coda_bit_encode_ops = {
+	.queue_init = coda_encoder_queue_init,
+	.start_streaming = coda_start_encoding,
+	.prepare_run = coda_prepare_encode,
+	.finish_run = coda_finish_encode,
+	.seq_end_work = coda_seq_end_work,
+	.release = coda_bit_release,
+};
+
+/*
+ * Decoder context operations
+ */
+
+static int __coda_start_decoding(struct coda_ctx *ctx)
+{
+	struct coda_q_data *q_data_src, *q_data_dst;
+	u32 bitstream_buf, bitstream_size;
+	struct coda_dev *dev = ctx->dev;
+	int width, height;
+	u32 src_fourcc;
+	u32 val;
+	int ret;
+
+	/* Start decoding */
+	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	bitstream_buf = ctx->bitstream.paddr;
+	bitstream_size = ctx->bitstream.size;
+	src_fourcc = q_data_src->fourcc;
+
+	/* Allocate per-instance buffers */
+	ret = coda_alloc_context_buffers(ctx, q_data_src);
+	if (ret < 0)
+		return ret;
+
+	coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
+
+	/* Update coda bitstream read and write pointers from kfifo */
+	coda_kfifo_sync_to_device_full(ctx);
+
+	ctx->display_idx = -1;
+	ctx->frm_dis_flg = 0;
+	coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+
+	coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE,
+			CODA_REG_BIT_BIT_STREAM_PARAM);
+
+	coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START);
+	coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE);
+	val = 0;
+	if ((dev->devtype->product == CODA_7541) ||
+	    (dev->devtype->product == CODA_960))
+		val |= CODA_REORDER_ENABLE;
+	coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
+
+	ctx->params.codec_mode = ctx->codec->mode;
+	if (dev->devtype->product == CODA_960 &&
+	    src_fourcc == V4L2_PIX_FMT_MPEG4)
+		ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4;
+	else
+		ctx->params.codec_mode_aux = 0;
+	if (src_fourcc == V4L2_PIX_FMT_H264) {
+		if (dev->devtype->product == CODA_7541) {
+			coda_write(dev, ctx->psbuf.paddr,
+					CODA_CMD_DEC_SEQ_PS_BB_START);
+			coda_write(dev, (CODA7_PS_BUF_SIZE / 1024),
+					CODA_CMD_DEC_SEQ_PS_BB_SIZE);
+		}
+		if (dev->devtype->product == CODA_960) {
+			coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN);
+			coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE);
+		}
+	}
+	if (dev->devtype->product != CODA_960)
+		coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE);
+
+	if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
+		v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
+		coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
+		return -ETIMEDOUT;
+	}
+
+	/* Update kfifo out pointer from coda bitstream read pointer */
+	coda_kfifo_sync_from_device(ctx);
+
+	coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
+
+	if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) {
+		v4l2_err(&dev->v4l2_dev,
+			"CODA_COMMAND_SEQ_INIT failed, error code = %d\n",
+			coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON));
+		return -EAGAIN;
+	}
+
+	val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE);
+	if (dev->devtype->product == CODA_DX6) {
+		width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK;
+		height = val & CODADX6_PICHEIGHT_MASK;
+	} else {
+		width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK;
+		height = val & CODA7_PICHEIGHT_MASK;
+	}
+
+	if (width > q_data_dst->width || height > q_data_dst->height) {
+		v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n",
+			 width, height, q_data_dst->width, q_data_dst->height);
+		return -EINVAL;
+	}
+
+	width = round_up(width, 16);
+	height = round_up(height, 16);
+
+	v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n",
+		 __func__, ctx->idx, width, height);
+
+	ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED);
+	if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) {
+		v4l2_err(&dev->v4l2_dev,
+			 "not enough framebuffers to decode (%d < %d)\n",
+			 CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames);
+		return -EINVAL;
+	}
+
+	if (src_fourcc == V4L2_PIX_FMT_H264) {
+		u32 left_right;
+		u32 top_bottom;
+
+		left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT);
+		top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM);
+
+		q_data_dst->rect.left = (left_right >> 10) & 0x3ff;
+		q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff;
+		q_data_dst->rect.width = width - q_data_dst->rect.left -
+					 (left_right & 0x3ff);
+		q_data_dst->rect.height = height - q_data_dst->rect.top -
+					  (top_bottom & 0x3ff);
+	}
+
+	ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
+	if (ret < 0) {
+		v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n");
+		return ret;
+	}
+
+	/* Tell the decoder how many frame buffers we allocated. */
+	coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
+	coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE);
+
+	if (dev->devtype->product != CODA_DX6) {
+		/* Set secondary AXI IRAM */
+		coda_setup_iram(ctx);
+
+		coda_write(dev, ctx->iram_info.buf_bit_use,
+				CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
+		coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
+				CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
+		coda_write(dev, ctx->iram_info.buf_dbk_y_use,
+				CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
+		coda_write(dev, ctx->iram_info.buf_dbk_c_use,
+				CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
+		coda_write(dev, ctx->iram_info.buf_ovl_use,
+				CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
+		if (dev->devtype->product == CODA_960)
+			coda_write(dev, ctx->iram_info.buf_btp_use,
+					CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
+	}
+
+	if (dev->devtype->product == CODA_960) {
+		coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY);
+
+		coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE);
+		coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET |
+				32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
+				8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET |
+				8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET,
+				CODA9_CMD_SET_FRAME_CACHE_CONFIG);
+	}
+
+	if (src_fourcc == V4L2_PIX_FMT_H264) {
+		coda_write(dev, ctx->slicebuf.paddr,
+				CODA_CMD_SET_FRAME_SLICE_BB_START);
+		coda_write(dev, ctx->slicebuf.size / 1024,
+				CODA_CMD_SET_FRAME_SLICE_BB_SIZE);
+	}
+
+	if (dev->devtype->product == CODA_7541) {
+		int max_mb_x = 1920 / 16;
+		int max_mb_y = 1088 / 16;
+		int max_mb_num = max_mb_x * max_mb_y;
+
+		coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
+				CODA7_CMD_SET_FRAME_MAX_DEC_SIZE);
+	} else if (dev->devtype->product == CODA_960) {
+		int max_mb_x = 1920 / 16;
+		int max_mb_y = 1088 / 16;
+		int max_mb_num = max_mb_x * max_mb_y;
+
+		coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
+				CODA9_CMD_SET_FRAME_MAX_DEC_SIZE);
+	}
+
+	if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
+		v4l2_err(&ctx->dev->v4l2_dev,
+			 "CODA_COMMAND_SET_FRAME_BUF timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int coda_start_decoding(struct coda_ctx *ctx)
+{
+	struct coda_dev *dev = ctx->dev;
+	int ret;
+
+	mutex_lock(&dev->coda_mutex);
+	ret = __coda_start_decoding(ctx);
+	mutex_unlock(&dev->coda_mutex);
+
+	return ret;
+}
+
+static int coda_prepare_decode(struct coda_ctx *ctx)
+{
+	struct vb2_buffer *dst_buf;
+	struct coda_dev *dev = ctx->dev;
+	struct coda_q_data *q_data_dst;
+	u32 stridey, height;
+	u32 picture_y, picture_cb, picture_cr;
+
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+	if (ctx->params.rot_mode & CODA_ROT_90) {
+		stridey = q_data_dst->height;
+		height = q_data_dst->width;
+	} else {
+		stridey = q_data_dst->width;
+		height = q_data_dst->height;
+	}
+
+	/* Try to copy source buffer contents into the bitstream ringbuffer */
+	mutex_lock(&ctx->bitstream_mutex);
+	coda_fill_bitstream(ctx);
+	mutex_unlock(&ctx->bitstream_mutex);
+
+	if (coda_get_bitstream_payload(ctx) < 512 &&
+	    (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
+		v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+			 "bitstream payload: %d, skipping\n",
+			 coda_get_bitstream_payload(ctx));
+		v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+		return -EAGAIN;
+	}
+
+	/* Run coda_start_decoding (again) if not yet initialized */
+	if (!ctx->initialized) {
+		int ret = __coda_start_decoding(ctx);
+
+		if (ret < 0) {
+			v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
+			v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+			return -EAGAIN;
+		} else {
+			ctx->initialized = 1;
+		}
+	}
+
+	if (dev->devtype->product == CODA_960)
+		coda_set_gdi_regs(ctx);
+
+	/* Set rotator output */
+	picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+	if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) {
+		/* Switch Cr and Cb for YVU420 format */
+		picture_cr = picture_y + stridey * height;
+		picture_cb = picture_cr + stridey / 2 * height / 2;
+	} else {
+		picture_cb = picture_y + stridey * height;
+		picture_cr = picture_cb + stridey / 2 * height / 2;
+	}
+
+	if (dev->devtype->product == CODA_960) {
+		/*
+		 * The CODA960 seems to have an internal list of buffers with
+		 * 64 entries that includes the registered frame buffers as
+		 * well as the rotator buffer output.
+		 * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames.
+		 */
+		coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index,
+				CODA9_CMD_DEC_PIC_ROT_INDEX);
+		coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y);
+		coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB);
+		coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR);
+		coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE);
+	} else {
+		coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y);
+		coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB);
+		coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR);
+		coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE);
+	}
+	coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
+			CODA_CMD_DEC_PIC_ROT_MODE);
+
+	switch (dev->devtype->product) {
+	case CODA_DX6:
+		/* TBD */
+	case CODA_7541:
+		coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION);
+		break;
+	case CODA_960:
+		/* 'hardcode to use interrupt disable mode'? */
+		coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION);
+		break;
+	}
+
+	coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM);
+
+	coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START);
+	coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE);
+
+	if (dev->devtype->product != CODA_DX6)
+		coda_write(dev, ctx->iram_info.axi_sram_use,
+				CODA7_REG_BIT_AXI_SRAM_USE);
+
+	coda_kfifo_sync_to_device_full(ctx);
+
+	coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
+
+	return 0;
+}
+
+static void coda_finish_decode(struct coda_ctx *ctx)
+{
+	struct coda_dev *dev = ctx->dev;
+	struct coda_q_data *q_data_src;
+	struct coda_q_data *q_data_dst;
+	struct vb2_buffer *dst_buf;
+	struct coda_timestamp *ts;
+	int width, height;
+	int decoded_idx;
+	int display_idx;
+	u32 src_fourcc;
+	int success;
+	u32 err_mb;
+	u32 val;
+
+	/* Update kfifo out pointer from coda bitstream read pointer */
+	coda_kfifo_sync_from_device(ctx);
+
+	/*
+	 * in stream-end mode, the read pointer can overshoot the write pointer
+	 * by up to 512 bytes
+	 */
+	if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
+		if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512)
+			kfifo_init(&ctx->bitstream_fifo,
+				ctx->bitstream.vaddr, ctx->bitstream.size);
+	}
+
+	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	src_fourcc = q_data_src->fourcc;
+
+	val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS);
+	if (val != 1)
+		pr_err("DEC_PIC_SUCCESS = %d\n", val);
+
+	success = val & 0x1;
+	if (!success)
+		v4l2_err(&dev->v4l2_dev, "decode failed\n");
+
+	if (src_fourcc == V4L2_PIX_FMT_H264) {
+		if (val & (1 << 3))
+			v4l2_err(&dev->v4l2_dev,
+				 "insufficient PS buffer space (%d bytes)\n",
+				 ctx->psbuf.size);
+		if (val & (1 << 2))
+			v4l2_err(&dev->v4l2_dev,
+				 "insufficient slice buffer space (%d bytes)\n",
+				 ctx->slicebuf.size);
+	}
+
+	val = coda_read(dev, CODA_RET_DEC_PIC_SIZE);
+	width = (val >> 16) & 0xffff;
+	height = val & 0xffff;
+
+	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+	/* frame crop information */
+	if (src_fourcc == V4L2_PIX_FMT_H264) {
+		u32 left_right;
+		u32 top_bottom;
+
+		left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT);
+		top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM);
+
+		if (left_right == 0xffffffff && top_bottom == 0xffffffff) {
+			/* Keep current crop information */
+		} else {
+			struct v4l2_rect *rect = &q_data_dst->rect;
+
+			rect->left = left_right >> 16 & 0xffff;
+			rect->top = top_bottom >> 16 & 0xffff;
+			rect->width = width - rect->left -
+				      (left_right & 0xffff);
+			rect->height = height - rect->top -
+				       (top_bottom & 0xffff);
+		}
+	} else {
+		/* no cropping */
+	}
+
+	err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB);
+	if (err_mb > 0)
+		v4l2_err(&dev->v4l2_dev,
+			 "errors in %d macroblocks\n", err_mb);
+
+	if (dev->devtype->product == CODA_7541) {
+		val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
+		if (val == 0) {
+			/* not enough bitstream data */
+			v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+				 "prescan failed: %d\n", val);
+			ctx->hold = true;
+			return;
+		}
+	}
+
+	ctx->frm_dis_flg = coda_read(dev,
+				     CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+
+	/*
+	 * The previous display frame was copied out by the rotator,
+	 * now it can be overwritten again
+	 */
+	if (ctx->display_idx >= 0 &&
+	    ctx->display_idx < ctx->num_internal_frames) {
+		ctx->frm_dis_flg &= ~(1 << ctx->display_idx);
+		coda_write(dev, ctx->frm_dis_flg,
+				CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+	}
+
+	/*
+	 * The index of the last decoded frame, not necessarily in
+	 * display order, and the index of the next display frame.
+	 * The latter could have been decoded in a previous run.
+	 */
+	decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX);
+	display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX);
+
+	if (decoded_idx == -1) {
+		/* no frame was decoded, but we might have a display frame */
+		if (display_idx >= 0 && display_idx < ctx->num_internal_frames)
+			ctx->sequence_offset++;
+		else if (ctx->display_idx < 0)
+			ctx->hold = true;
+	} else if (decoded_idx == -2) {
+		/* no frame was decoded, we still return remaining buffers */
+	} else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
+		v4l2_err(&dev->v4l2_dev,
+			 "decoded frame index out of range: %d\n", decoded_idx);
+	} else {
+		val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
+		val -= ctx->sequence_offset;
+		mutex_lock(&ctx->bitstream_mutex);
+		if (!list_empty(&ctx->timestamp_list)) {
+			ts = list_first_entry(&ctx->timestamp_list,
+					      struct coda_timestamp, list);
+			list_del(&ts->list);
+			if (val != (ts->sequence & 0xffff)) {
+				v4l2_err(&dev->v4l2_dev,
+					 "sequence number mismatch (%d(%d) != %d)\n",
+					 val, ctx->sequence_offset,
+					 ts->sequence);
+			}
+			ctx->frame_timestamps[decoded_idx] = *ts;
+			kfree(ts);
+		} else {
+			v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n");
+			memset(&ctx->frame_timestamps[decoded_idx], 0,
+			       sizeof(struct coda_timestamp));
+			ctx->frame_timestamps[decoded_idx].sequence = val;
+		}
+		mutex_unlock(&ctx->bitstream_mutex);
+
+		val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7;
+		if (val == 0)
+			ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME;
+		else if (val == 1)
+			ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME;
+		else
+			ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME;
+
+		ctx->frame_errors[decoded_idx] = err_mb;
+	}
+
+	if (display_idx == -1) {
+		/*
+		 * no more frames to be decoded, but there could still
+		 * be rotator output to dequeue
+		 */
+		ctx->hold = true;
+	} else if (display_idx == -3) {
+		/* possibly prescan failure */
+	} else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) {
+		v4l2_err(&dev->v4l2_dev,
+			 "presentation frame index out of range: %d\n",
+			 display_idx);
+	}
+
+	/* If a frame was copied out, return it */
+	if (ctx->display_idx >= 0 &&
+	    ctx->display_idx < ctx->num_internal_frames) {
+		dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+		dst_buf->v4l2_buf.sequence = ctx->osequence++;
+
+		dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
+					     V4L2_BUF_FLAG_PFRAME |
+					     V4L2_BUF_FLAG_BFRAME);
+		dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx];
+		ts = &ctx->frame_timestamps[ctx->display_idx];
+		dst_buf->v4l2_buf.timecode = ts->timecode;
+		dst_buf->v4l2_buf.timestamp = ts->timestamp;
+
+		vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2);
+
+		v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ?
+				  VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+		v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+			"job finished: decoding frame (%d) (%s)\n",
+			dst_buf->v4l2_buf.sequence,
+			(dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
+			"KEYFRAME" : "PFRAME");
+	} else {
+		v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+			"job finished: no frame decoded\n");
+	}
+
+	/* The rotator will copy the current display frame next time */
+	ctx->display_idx = display_idx;
+}
+
+const struct coda_context_ops coda_bit_decode_ops = {
+	.queue_init = coda_decoder_queue_init,
+	.start_streaming = coda_start_decoding,
+	.prepare_run = coda_prepare_decode,
+	.finish_run = coda_finish_decode,
+	.seq_end_work = coda_seq_end_work,
+	.release = coda_bit_release,
+};
+
+irqreturn_t coda_irq_handler(int irq, void *data)
+{
+	struct coda_dev *dev = data;
+	struct coda_ctx *ctx;
+
+	/* read status register to attend the IRQ */
+	coda_read(dev, CODA_REG_BIT_INT_STATUS);
+	coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
+		      CODA_REG_BIT_INT_CLEAR);
+
+	ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+	if (ctx == NULL) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Instance released before the end of transaction\n");
+		mutex_unlock(&dev->coda_mutex);
+		return IRQ_HANDLED;
+	}
+
+	if (ctx->aborting) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "task has been aborted\n");
+	}
+
+	if (coda_isbusy(ctx->dev)) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "coda is still busy!!!!\n");
+		return IRQ_NONE;
+	}
+
+	complete(&ctx->completion);
+
+	return IRQ_HANDLED;
+}
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
new file mode 100644
index 0000000..ced4760
--- /dev/null
+++ b/drivers/media/platform/coda/coda-common.c
@@ -0,0 +1,2052 @@
+/*
+ * Coda multi-standard codec IP
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/genalloc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kfifo.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/of.h>
+#include <linux/platform_data/coda.h>
+#include <linux/reset.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "coda.h"
+
+#define CODA_NAME		"coda"
+
+#define CODADX6_MAX_INSTANCES	4
+
+#define CODA_PARA_BUF_SIZE	(10 * 1024)
+#define CODA_ISRAM_SIZE	(2048 * 2)
+
+#define MIN_W 176
+#define MIN_H 144
+
+#define S_ALIGN		1 /* multiple of 2 */
+#define W_ALIGN		1 /* multiple of 2 */
+#define H_ALIGN		1 /* multiple of 2 */
+
+#define fh_to_ctx(__fh)	container_of(__fh, struct coda_ctx, fh)
+
+int coda_debug;
+module_param(coda_debug, int, 0644);
+MODULE_PARM_DESC(coda_debug, "Debug level (0-2)");
+
+struct coda_fmt {
+	char *name;
+	u32 fourcc;
+};
+
+void coda_write(struct coda_dev *dev, u32 data, u32 reg)
+{
+	v4l2_dbg(2, coda_debug, &dev->v4l2_dev,
+		 "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
+	writel(data, dev->regs_base + reg);
+}
+
+unsigned int coda_read(struct coda_dev *dev, u32 reg)
+{
+	u32 data;
+
+	data = readl(dev->regs_base + reg);
+	v4l2_dbg(2, coda_debug, &dev->v4l2_dev,
+		 "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
+	return data;
+}
+
+/*
+ * Array of all formats supported by any version of Coda:
+ */
+static const struct coda_fmt coda_formats[] = {
+	{
+		.name = "YUV 4:2:0 Planar, YCbCr",
+		.fourcc = V4L2_PIX_FMT_YUV420,
+	},
+	{
+		.name = "YUV 4:2:0 Planar, YCrCb",
+		.fourcc = V4L2_PIX_FMT_YVU420,
+	},
+	{
+		.name = "H264 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_H264,
+	},
+	{
+		.name = "MPEG4 Encoded Stream",
+		.fourcc = V4L2_PIX_FMT_MPEG4,
+	},
+};
+
+#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \
+	{ mode, src_fourcc, dst_fourcc, max_w, max_h }
+
+/*
+ * Arrays of codecs supported by each given version of Coda:
+ *  i.MX27 -> codadx6
+ *  i.MX5x -> coda7
+ *  i.MX6  -> coda960
+ * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants
+ */
+static const struct coda_codec codadx6_codecs[] = {
+	CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,  720, 576),
+	CODA_CODEC(CODADX6_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576),
+};
+
+static const struct coda_codec coda7_codecs[] = {
+	CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1280, 720),
+	CODA_CODEC(CODA7_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1280, 720),
+	CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1088),
+	CODA_CODEC(CODA7_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1088),
+};
+
+static const struct coda_codec coda9_codecs[] = {
+	CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264,   1920, 1088),
+	CODA_CODEC(CODA9_MODE_ENCODE_MP4,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4,  1920, 1088),
+	CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264,   V4L2_PIX_FMT_YUV420, 1920, 1088),
+	CODA_CODEC(CODA9_MODE_DECODE_MP4,  V4L2_PIX_FMT_MPEG4,  V4L2_PIX_FMT_YUV420, 1920, 1088),
+};
+
+static bool coda_format_is_yuv(u32 fourcc)
+{
+	switch (fourcc) {
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_YVU420:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/*
+ * Normalize all supported YUV 4:2:0 formats to the value used in the codec
+ * tables.
+ */
+static u32 coda_format_normalize_yuv(u32 fourcc)
+{
+	return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc;
+}
+
+static const struct coda_codec *coda_find_codec(struct coda_dev *dev,
+						int src_fourcc, int dst_fourcc)
+{
+	const struct coda_codec *codecs = dev->devtype->codecs;
+	int num_codecs = dev->devtype->num_codecs;
+	int k;
+
+	src_fourcc = coda_format_normalize_yuv(src_fourcc);
+	dst_fourcc = coda_format_normalize_yuv(dst_fourcc);
+	if (src_fourcc == dst_fourcc)
+		return NULL;
+
+	for (k = 0; k < num_codecs; k++) {
+		if (codecs[k].src_fourcc == src_fourcc &&
+		    codecs[k].dst_fourcc == dst_fourcc)
+			break;
+	}
+
+	if (k == num_codecs)
+		return NULL;
+
+	return &codecs[k];
+}
+
+static void coda_get_max_dimensions(struct coda_dev *dev,
+				    const struct coda_codec *codec,
+				    int *max_w, int *max_h)
+{
+	const struct coda_codec *codecs = dev->devtype->codecs;
+	int num_codecs = dev->devtype->num_codecs;
+	unsigned int w, h;
+	int k;
+
+	if (codec) {
+		w = codec->max_w;
+		h = codec->max_h;
+	} else {
+		for (k = 0, w = 0, h = 0; k < num_codecs; k++) {
+			w = max(w, codecs[k].max_w);
+			h = max(h, codecs[k].max_h);
+		}
+	}
+
+	if (max_w)
+		*max_w = w;
+	if (max_h)
+		*max_h = h;
+}
+
+const char *coda_product_name(int product)
+{
+	static char buf[9];
+
+	switch (product) {
+	case CODA_DX6:
+		return "CodaDx6";
+	case CODA_7541:
+		return "CODA7541";
+	case CODA_960:
+		return "CODA960";
+	default:
+		snprintf(buf, sizeof(buf), "(0x%04x)", product);
+		return buf;
+	}
+}
+
+/*
+ * V4L2 ioctl() operations.
+ */
+static int coda_querycap(struct file *file, void *priv,
+			 struct v4l2_capability *cap)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+
+	strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, coda_product_name(ctx->dev->devtype->product),
+		sizeof(cap->card));
+	strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info));
+	cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+	return 0;
+}
+
+static int coda_enum_fmt(struct file *file, void *priv,
+			 struct v4l2_fmtdesc *f)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+	const struct coda_codec *codecs = ctx->dev->devtype->codecs;
+	const struct coda_fmt *formats = coda_formats;
+	const struct coda_fmt *fmt;
+	int num_codecs = ctx->dev->devtype->num_codecs;
+	int num_formats = ARRAY_SIZE(coda_formats);
+	int i, k, num = 0;
+	bool yuv;
+
+	if (ctx->inst_type == CODA_INST_ENCODER)
+		yuv = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	else
+		yuv = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+	for (i = 0; i < num_formats; i++) {
+		/* Skip either raw or compressed formats */
+		if (yuv != coda_format_is_yuv(formats[i].fourcc))
+			continue;
+		/* All uncompressed formats are always supported */
+		if (yuv) {
+			if (num == f->index)
+				break;
+			++num;
+			continue;
+		}
+		/* Compressed formats may be supported, check the codec list */
+		for (k = 0; k < num_codecs; k++) {
+			if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+			    formats[i].fourcc == codecs[k].dst_fourcc)
+				break;
+			if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+			    formats[i].fourcc == codecs[k].src_fourcc)
+				break;
+		}
+		if (k < num_codecs) {
+			if (num == f->index)
+				break;
+			++num;
+		}
+	}
+
+	if (i < num_formats) {
+		fmt = &formats[i];
+		strlcpy(f->description, fmt->name, sizeof(f->description));
+		f->pixelformat = fmt->fourcc;
+		if (!yuv)
+			f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+		return 0;
+	}
+
+	/* Format not found */
+	return -EINVAL;
+}
+
+static int coda_g_fmt(struct file *file, void *priv,
+		      struct v4l2_format *f)
+{
+	struct coda_q_data *q_data;
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+
+	q_data = get_q_data(ctx, f->type);
+	if (!q_data)
+		return -EINVAL;
+
+	f->fmt.pix.field	= V4L2_FIELD_NONE;
+	f->fmt.pix.pixelformat	= q_data->fourcc;
+	f->fmt.pix.width	= q_data->width;
+	f->fmt.pix.height	= q_data->height;
+	f->fmt.pix.bytesperline = q_data->bytesperline;
+
+	f->fmt.pix.sizeimage	= q_data->sizeimage;
+	f->fmt.pix.colorspace	= ctx->colorspace;
+
+	return 0;
+}
+
+static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
+			struct v4l2_format *f)
+{
+	struct coda_dev *dev = ctx->dev;
+	struct coda_q_data *q_data;
+	unsigned int max_w, max_h;
+	enum v4l2_field field;
+
+	field = f->fmt.pix.field;
+	if (field == V4L2_FIELD_ANY)
+		field = V4L2_FIELD_NONE;
+	else if (V4L2_FIELD_NONE != field)
+		return -EINVAL;
+
+	/* V4L2 specification suggests the driver corrects the format struct
+	 * if any of the dimensions is unsupported */
+	f->fmt.pix.field = field;
+
+	coda_get_max_dimensions(dev, codec, &max_w, &max_h);
+	v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w, W_ALIGN,
+			      &f->fmt.pix.height, MIN_H, max_h, H_ALIGN,
+			      S_ALIGN);
+
+	switch (f->fmt.pix.pixelformat) {
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_YVU420:
+	case V4L2_PIX_FMT_H264:
+	case V4L2_PIX_FMT_MPEG4:
+	case V4L2_PIX_FMT_JPEG:
+		break;
+	default:
+		q_data = get_q_data(ctx, f->type);
+		if (!q_data)
+			return -EINVAL;
+		f->fmt.pix.pixelformat = q_data->fourcc;
+	}
+
+	switch (f->fmt.pix.pixelformat) {
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_YVU420:
+		/* Frame stride must be multiple of 8, but 16 for h.264 */
+		f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
+		f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+					f->fmt.pix.height * 3 / 2;
+		break;
+	case V4L2_PIX_FMT_H264:
+	case V4L2_PIX_FMT_MPEG4:
+	case V4L2_PIX_FMT_JPEG:
+		f->fmt.pix.bytesperline = 0;
+		f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
+		break;
+	default:
+		BUG();
+	}
+
+	return 0;
+}
+
+static int coda_try_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+	const struct coda_codec *codec = NULL;
+	struct vb2_queue *src_vq;
+	int ret;
+
+	/*
+	 * If the source format is already fixed, try to find a codec that
+	 * converts to the given destination format
+	 */
+	src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	if (vb2_is_streaming(src_vq)) {
+		struct coda_q_data *q_data_src;
+
+		q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+		codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
+					f->fmt.pix.pixelformat);
+		if (!codec)
+			return -EINVAL;
+
+		f->fmt.pix.width = q_data_src->width;
+		f->fmt.pix.height = q_data_src->height;
+	} else {
+		/* Otherwise determine codec by encoded format, if possible */
+		codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
+					f->fmt.pix.pixelformat);
+	}
+
+	f->fmt.pix.colorspace = ctx->colorspace;
+
+	ret = coda_try_fmt(ctx, codec, f);
+	if (ret < 0)
+		return ret;
+
+	/* The h.264 decoder only returns complete 16x16 macroblocks */
+	if (codec && codec->src_fourcc == V4L2_PIX_FMT_H264) {
+		f->fmt.pix.width = f->fmt.pix.width;
+		f->fmt.pix.height = round_up(f->fmt.pix.height, 16);
+		f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
+		f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+				       f->fmt.pix.height * 3 / 2;
+	}
+
+	return 0;
+}
+
+static int coda_try_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+	const struct coda_codec *codec = NULL;
+
+	/* Determine codec by encoded format, returns NULL if raw or invalid */
+	if (ctx->inst_type == CODA_INST_DECODER) {
+		codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat,
+					V4L2_PIX_FMT_YUV420);
+		if (!codec)
+			codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264,
+						V4L2_PIX_FMT_YUV420);
+		if (!codec)
+			return -EINVAL;
+	}
+
+	if (!f->fmt.pix.colorspace)
+		f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+	return coda_try_fmt(ctx, codec, f);
+}
+
+static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
+{
+	struct coda_q_data *q_data;
+	struct vb2_queue *vq;
+
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+
+	q_data = get_q_data(ctx, f->type);
+	if (!q_data)
+		return -EINVAL;
+
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+		return -EBUSY;
+	}
+
+	q_data->fourcc = f->fmt.pix.pixelformat;
+	q_data->width = f->fmt.pix.width;
+	q_data->height = f->fmt.pix.height;
+	q_data->bytesperline = f->fmt.pix.bytesperline;
+	q_data->sizeimage = f->fmt.pix.sizeimage;
+	q_data->rect.left = 0;
+	q_data->rect.top = 0;
+	q_data->rect.width = f->fmt.pix.width;
+	q_data->rect.height = f->fmt.pix.height;
+
+	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+		"Setting format for type %d, wxh: %dx%d, fmt: %d\n",
+		f->type, q_data->width, q_data->height, q_data->fourcc);
+
+	return 0;
+}
+
+static int coda_s_fmt_vid_cap(struct file *file, void *priv,
+			      struct v4l2_format *f)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+	int ret;
+
+	ret = coda_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	return coda_s_fmt(ctx, f);
+}
+
+static int coda_s_fmt_vid_out(struct file *file, void *priv,
+			      struct v4l2_format *f)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+	struct v4l2_format f_cap;
+	int ret;
+
+	ret = coda_try_fmt_vid_out(file, priv, f);
+	if (ret)
+		return ret;
+
+	ret = coda_s_fmt(ctx, f);
+	if (ret)
+		return ret;
+
+	ctx->colorspace = f->fmt.pix.colorspace;
+
+	f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	coda_g_fmt(file, priv, &f_cap);
+	f_cap.fmt.pix.width = f->fmt.pix.width;
+	f_cap.fmt.pix.height = f->fmt.pix.height;
+
+	ret = coda_try_fmt_vid_cap(file, priv, &f_cap);
+	if (ret)
+		return ret;
+
+	return coda_s_fmt(ctx, &f_cap);
+}
+
+static int coda_qbuf(struct file *file, void *priv,
+		     struct v4l2_buffer *buf)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+
+	return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf);
+}
+
+static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
+				      struct v4l2_buffer *buf)
+{
+	struct vb2_queue *src_vq;
+
+	src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+	return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) &&
+		(buf->sequence == (ctx->qsequence - 1)));
+}
+
+static int coda_dqbuf(struct file *file, void *priv,
+		      struct v4l2_buffer *buf)
+{
+	struct coda_ctx *ctx = fh_to_ctx(priv);
+	int ret;
+
+	ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf);
+
+	/* If this is the last capture buffer, emit an end-of-stream event */
+	if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    coda_buf_is_end_of_stream(ctx, buf)) {
+		const struct v4l2_event eos_event = {
+			.type = V4L2_EVENT_EOS
+		};
+
+		v4l2_event_queue_fh(&ctx->fh, &eos_event);
+	}
+
+	return ret;
+}
+
+static int coda_g_selection(struct file *file, void *fh,
+			    struct v4l2_selection *s)
+{
+	struct coda_ctx *ctx = fh_to_ctx(fh);
+	struct coda_q_data *q_data;
+	struct v4l2_rect r, *rsel;
+
+	q_data = get_q_data(ctx, s->type);
+	if (!q_data)
+		return -EINVAL;
+
+	r.left = 0;
+	r.top = 0;
+	r.width = q_data->width;
+	r.height = q_data->height;
+	rsel = &q_data->rect;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		rsel = &r;
+		/* fallthrough */
+	case V4L2_SEL_TGT_CROP:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_PADDED:
+		rsel = &r;
+		/* fallthrough */
+	case V4L2_SEL_TGT_COMPOSE:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	s->r = *rsel;
+
+	return 0;
+}
+
+static int coda_try_decoder_cmd(struct file *file, void *fh,
+				struct v4l2_decoder_cmd *dc)
+{
+	if (dc->cmd != V4L2_DEC_CMD_STOP)
+		return -EINVAL;
+
+	if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
+		return -EINVAL;
+
+	if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int coda_decoder_cmd(struct file *file, void *fh,
+			    struct v4l2_decoder_cmd *dc)
+{
+	struct coda_ctx *ctx = fh_to_ctx(fh);
+	int ret;
+
+	ret = coda_try_decoder_cmd(file, fh, dc);
+	if (ret < 0)
+		return ret;
+
+	/* Ignore decoder stop command silently in encoder context */
+	if (ctx->inst_type != CODA_INST_DECODER)
+		return 0;
+
+	/* Set the stream-end flag on this context */
+	coda_bit_stream_end_flag(ctx);
+	ctx->hold = false;
+	v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
+
+	return 0;
+}
+
+static int coda_subscribe_event(struct v4l2_fh *fh,
+				const struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_EOS:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	default:
+		return v4l2_ctrl_subscribe_event(fh, sub);
+	}
+}
+
+static const struct v4l2_ioctl_ops coda_ioctl_ops = {
+	.vidioc_querycap	= coda_querycap,
+
+	.vidioc_enum_fmt_vid_cap = coda_enum_fmt,
+	.vidioc_g_fmt_vid_cap	= coda_g_fmt,
+	.vidioc_try_fmt_vid_cap	= coda_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap	= coda_s_fmt_vid_cap,
+
+	.vidioc_enum_fmt_vid_out = coda_enum_fmt,
+	.vidioc_g_fmt_vid_out	= coda_g_fmt,
+	.vidioc_try_fmt_vid_out	= coda_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out	= coda_s_fmt_vid_out,
+
+	.vidioc_reqbufs		= v4l2_m2m_ioctl_reqbufs,
+	.vidioc_querybuf	= v4l2_m2m_ioctl_querybuf,
+
+	.vidioc_qbuf		= coda_qbuf,
+	.vidioc_expbuf		= v4l2_m2m_ioctl_expbuf,
+	.vidioc_dqbuf		= coda_dqbuf,
+	.vidioc_create_bufs	= v4l2_m2m_ioctl_create_bufs,
+
+	.vidioc_streamon	= v4l2_m2m_ioctl_streamon,
+	.vidioc_streamoff	= v4l2_m2m_ioctl_streamoff,
+
+	.vidioc_g_selection	= coda_g_selection,
+
+	.vidioc_try_decoder_cmd	= coda_try_decoder_cmd,
+	.vidioc_decoder_cmd	= coda_decoder_cmd,
+
+	.vidioc_subscribe_event = coda_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+void coda_set_gdi_regs(struct coda_ctx *ctx)
+{
+	struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
+	struct coda_dev *dev = ctx->dev;
+	int i;
+
+	for (i = 0; i < 16; i++)
+		coda_write(dev, tiled_map->xy2ca_map[i],
+				CODA9_GDI_XY2_CAS_0 + 4 * i);
+	for (i = 0; i < 4; i++)
+		coda_write(dev, tiled_map->xy2ba_map[i],
+				CODA9_GDI_XY2_BA_0 + 4 * i);
+	for (i = 0; i < 16; i++)
+		coda_write(dev, tiled_map->xy2ra_map[i],
+				CODA9_GDI_XY2_RAS_0 + 4 * i);
+	coda_write(dev, tiled_map->xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG);
+	for (i = 0; i < 32; i++)
+		coda_write(dev, tiled_map->rbc2axi_map[i],
+				CODA9_GDI_RBC2_AXI_0 + 4 * i);
+}
+
+/*
+ * Mem-to-mem operations.
+ */
+
+static void coda_device_run(void *m2m_priv)
+{
+	struct coda_ctx *ctx = m2m_priv;
+	struct coda_dev *dev = ctx->dev;
+
+	queue_work(dev->workqueue, &ctx->pic_run_work);
+}
+
+static void coda_pic_run_work(struct work_struct *work)
+{
+	struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work);
+	struct coda_dev *dev = ctx->dev;
+	int ret;
+
+	mutex_lock(&ctx->buffer_mutex);
+	mutex_lock(&dev->coda_mutex);
+
+	ret = ctx->ops->prepare_run(ctx);
+	if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) {
+		mutex_unlock(&dev->coda_mutex);
+		mutex_unlock(&ctx->buffer_mutex);
+		/* job_finish scheduled by prepare_decode */
+		return;
+	}
+
+	if (!wait_for_completion_timeout(&ctx->completion,
+					 msecs_to_jiffies(1000))) {
+		dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n");
+
+		ctx->hold = true;
+
+		coda_hw_reset(ctx);
+	} else if (!ctx->aborting) {
+		ctx->ops->finish_run(ctx);
+	}
+
+	if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out))
+		queue_work(dev->workqueue, &ctx->seq_end_work);
+
+	mutex_unlock(&dev->coda_mutex);
+	mutex_unlock(&ctx->buffer_mutex);
+
+	v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static int coda_job_ready(void *m2m_priv)
+{
+	struct coda_ctx *ctx = m2m_priv;
+
+	/*
+	 * For both 'P' and 'key' frame cases 1 picture
+	 * and 1 frame are needed. In the decoder case,
+	 * the compressed frame can be in the bitstream.
+	 */
+	if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
+	    ctx->inst_type != CODA_INST_DECODER) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "not ready: not enough video buffers.\n");
+		return 0;
+	}
+
+	if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "not ready: not enough video capture buffers.\n");
+		return 0;
+	}
+
+	if (ctx->hold ||
+	    ((ctx->inst_type == CODA_INST_DECODER) &&
+	     (coda_get_bitstream_payload(ctx) < 512) &&
+	     !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "%d: not ready: not enough bitstream data.\n",
+			 ctx->idx);
+		return 0;
+	}
+
+	if (ctx->aborting) {
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			 "not ready: aborting\n");
+		return 0;
+	}
+
+	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			"job ready\n");
+	return 1;
+}
+
+static void coda_job_abort(void *priv)
+{
+	struct coda_ctx *ctx = priv;
+
+	ctx->aborting = 1;
+
+	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+		 "Aborting task\n");
+}
+
+static void coda_lock(void *m2m_priv)
+{
+	struct coda_ctx *ctx = m2m_priv;
+	struct coda_dev *pcdev = ctx->dev;
+
+	mutex_lock(&pcdev->dev_mutex);
+}
+
+static void coda_unlock(void *m2m_priv)
+{
+	struct coda_ctx *ctx = m2m_priv;
+	struct coda_dev *pcdev = ctx->dev;
+
+	mutex_unlock(&pcdev->dev_mutex);
+}
+
+static const struct v4l2_m2m_ops coda_m2m_ops = {
+	.device_run	= coda_device_run,
+	.job_ready	= coda_job_ready,
+	.job_abort	= coda_job_abort,
+	.lock		= coda_lock,
+	.unlock		= coda_unlock,
+};
+
+static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type)
+{
+	struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
+	int luma_map, chro_map, i;
+
+	memset(tiled_map, 0, sizeof(*tiled_map));
+
+	luma_map = 64;
+	chro_map = 64;
+	tiled_map->map_type = tiled_map_type;
+	for (i = 0; i < 16; i++)
+		tiled_map->xy2ca_map[i] = luma_map << 8 | chro_map;
+	for (i = 0; i < 4; i++)
+		tiled_map->xy2ba_map[i] = luma_map << 8 | chro_map;
+	for (i = 0; i < 16; i++)
+		tiled_map->xy2ra_map[i] = luma_map << 8 | chro_map;
+
+	if (tiled_map_type == GDI_LINEAR_FRAME_MAP) {
+		tiled_map->xy2rbc_config = 0;
+	} else {
+		dev_err(&ctx->dev->plat_dev->dev, "invalid map type: %d\n",
+			tiled_map_type);
+		return;
+	}
+}
+
+static void set_default_params(struct coda_ctx *ctx)
+{
+	u32 src_fourcc, dst_fourcc;
+	int max_w;
+	int max_h;
+
+	if (ctx->inst_type == CODA_INST_ENCODER) {
+		src_fourcc = V4L2_PIX_FMT_YUV420;
+		dst_fourcc = V4L2_PIX_FMT_H264;
+	} else {
+		src_fourcc = V4L2_PIX_FMT_H264;
+		dst_fourcc = V4L2_PIX_FMT_YUV420;
+	}
+	ctx->codec = coda_find_codec(ctx->dev, src_fourcc, dst_fourcc);
+	max_w = ctx->codec->max_w;
+	max_h = ctx->codec->max_h;
+
+	ctx->params.codec_mode = ctx->codec->mode;
+	ctx->colorspace = V4L2_COLORSPACE_REC709;
+	ctx->params.framerate = 30;
+	ctx->aborting = 0;
+
+	/* Default formats for output and input queues */
+	ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc;
+	ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc;
+	ctx->q_data[V4L2_M2M_SRC].width = max_w;
+	ctx->q_data[V4L2_M2M_SRC].height = max_h;
+	ctx->q_data[V4L2_M2M_DST].width = max_w;
+	ctx->q_data[V4L2_M2M_DST].height = max_h;
+	if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) {
+		ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w;
+		ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
+		ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
+		ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
+	} else {
+		ctx->q_data[V4L2_M2M_SRC].bytesperline = 0;
+		ctx->q_data[V4L2_M2M_SRC].sizeimage = CODA_MAX_FRAME_SIZE;
+		ctx->q_data[V4L2_M2M_DST].bytesperline = max_w;
+		ctx->q_data[V4L2_M2M_DST].sizeimage = (max_w * max_h * 3) / 2;
+	}
+	ctx->q_data[V4L2_M2M_SRC].rect.width = max_w;
+	ctx->q_data[V4L2_M2M_SRC].rect.height = max_h;
+	ctx->q_data[V4L2_M2M_DST].rect.width = max_w;
+	ctx->q_data[V4L2_M2M_DST].rect.height = max_h;
+
+	if (ctx->dev->devtype->product == CODA_960)
+		coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP);
+}
+
+/*
+ * Queue operations
+ */
+static int coda_queue_setup(struct vb2_queue *vq,
+				const struct v4l2_format *fmt,
+				unsigned int *nbuffers, unsigned int *nplanes,
+				unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct coda_ctx *ctx = vb2_get_drv_priv(vq);
+	struct coda_q_data *q_data;
+	unsigned int size;
+
+	q_data = get_q_data(ctx, vq->type);
+	size = q_data->sizeimage;
+
+	*nplanes = 1;
+	sizes[0] = size;
+
+	alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+		 "get %d buffer(s) of size %d each.\n", *nbuffers, size);
+
+	return 0;
+}
+
+static int coda_buf_prepare(struct vb2_buffer *vb)
+{
+	struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct coda_q_data *q_data;
+
+	q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+	if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+		v4l2_warn(&ctx->dev->v4l2_dev,
+			  "%s data will not fit into plane (%lu < %lu)\n",
+			  __func__, vb2_plane_size(vb, 0),
+			  (long)q_data->sizeimage);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void coda_buf_queue(struct vb2_buffer *vb)
+{
+	struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct coda_q_data *q_data;
+
+	q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+	/*
+	 * In the decoder case, immediately try to copy the buffer into the
+	 * bitstream ringbuffer and mark it as ready to be dequeued.
+	 */
+	if (q_data->fourcc == V4L2_PIX_FMT_H264 &&
+	    vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		/*
+		 * For backwards compatibility, queuing an empty buffer marks
+		 * the stream end
+		 */
+		if (vb2_get_plane_payload(vb, 0) == 0)
+			coda_bit_stream_end_flag(ctx);
+		mutex_lock(&ctx->bitstream_mutex);
+		v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
+		if (vb2_is_streaming(vb->vb2_queue))
+			coda_fill_bitstream(ctx);
+		mutex_unlock(&ctx->bitstream_mutex);
+	} else {
+		v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
+	}
+}
+
+int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
+		       size_t size, const char *name, struct dentry *parent)
+{
+	buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr,
+					GFP_KERNEL);
+	if (!buf->vaddr) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Failed to allocate %s buffer of size %u\n",
+			 name, size);
+		return -ENOMEM;
+	}
+
+	buf->size = size;
+
+	if (name && parent) {
+		buf->blob.data = buf->vaddr;
+		buf->blob.size = size;
+		buf->dentry = debugfs_create_blob(name, 0644, parent,
+						  &buf->blob);
+		if (!buf->dentry)
+			dev_warn(&dev->plat_dev->dev,
+				 "failed to create debugfs entry %s\n", name);
+	}
+
+	return 0;
+}
+
+void coda_free_aux_buf(struct coda_dev *dev,
+		       struct coda_aux_buf *buf)
+{
+	if (buf->vaddr) {
+		dma_free_coherent(&dev->plat_dev->dev, buf->size,
+				  buf->vaddr, buf->paddr);
+		buf->vaddr = NULL;
+		buf->size = 0;
+	}
+	debugfs_remove(buf->dentry);
+}
+
+static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct coda_ctx *ctx = vb2_get_drv_priv(q);
+	struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev;
+	struct coda_q_data *q_data_src, *q_data_dst;
+	struct vb2_buffer *buf;
+	u32 dst_fourcc;
+	int ret = 0;
+
+	q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		if (q_data_src->fourcc == V4L2_PIX_FMT_H264) {
+			/* copy the buffers that where queued before streamon */
+			mutex_lock(&ctx->bitstream_mutex);
+			coda_fill_bitstream(ctx);
+			mutex_unlock(&ctx->bitstream_mutex);
+
+			if (coda_get_bitstream_payload(ctx) < 512) {
+				ret = -EINVAL;
+				goto err;
+			}
+		} else {
+			if (count < 1) {
+				ret = -EINVAL;
+				goto err;
+			}
+		}
+
+		ctx->streamon_out = 1;
+	} else {
+		if (count < 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		ctx->streamon_cap = 1;
+	}
+
+	/* Don't start the coda unless both queues are on */
+	if (!(ctx->streamon_out & ctx->streamon_cap))
+		return 0;
+
+	/* Allow decoder device_run with no new buffers queued */
+	if (ctx->inst_type == CODA_INST_DECODER)
+		v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
+
+	ctx->gopcounter = ctx->params.gop_size - 1;
+	q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	dst_fourcc = q_data_dst->fourcc;
+
+	ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
+				     q_data_dst->fourcc);
+	if (!ctx->codec) {
+		v4l2_err(v4l2_dev, "couldn't tell instance type.\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = ctx->ops->start_streaming(ctx);
+	if (ctx->inst_type == CODA_INST_DECODER) {
+		if (ret == -EAGAIN)
+			return 0;
+		else if (ret < 0)
+			goto err;
+	}
+
+	ctx->initialized = 1;
+	return ret;
+
+err:
+	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+			v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED);
+	} else {
+		while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx)))
+			v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED);
+	}
+	return ret;
+}
+
+static void coda_stop_streaming(struct vb2_queue *q)
+{
+	struct coda_ctx *ctx = vb2_get_drv_priv(q);
+	struct coda_dev *dev = ctx->dev;
+	struct vb2_buffer *buf;
+
+	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+			 "%s: output\n", __func__);
+		ctx->streamon_out = 0;
+
+		coda_bit_stream_end_flag(ctx);
+
+		ctx->isequence = 0;
+
+		while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+			v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+	} else {
+		v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+			 "%s: capture\n", __func__);
+		ctx->streamon_cap = 0;
+
+		ctx->osequence = 0;
+		ctx->sequence_offset = 0;
+
+		while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx)))
+			v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+	}
+
+	if (!ctx->streamon_out && !ctx->streamon_cap) {
+		struct coda_timestamp *ts;
+
+		mutex_lock(&ctx->bitstream_mutex);
+		while (!list_empty(&ctx->timestamp_list)) {
+			ts = list_first_entry(&ctx->timestamp_list,
+					      struct coda_timestamp, list);
+			list_del(&ts->list);
+			kfree(ts);
+		}
+		mutex_unlock(&ctx->bitstream_mutex);
+		kfifo_init(&ctx->bitstream_fifo,
+			ctx->bitstream.vaddr, ctx->bitstream.size);
+		ctx->runcounter = 0;
+	}
+}
+
+static const struct vb2_ops coda_qops = {
+	.queue_setup		= coda_queue_setup,
+	.buf_prepare		= coda_buf_prepare,
+	.buf_queue		= coda_buf_queue,
+	.start_streaming	= coda_start_streaming,
+	.stop_streaming		= coda_stop_streaming,
+	.wait_prepare		= vb2_ops_wait_prepare,
+	.wait_finish		= vb2_ops_wait_finish,
+};
+
+static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct coda_ctx *ctx =
+			container_of(ctrl->handler, struct coda_ctx, ctrls);
+
+	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+		 "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
+
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		if (ctrl->val)
+			ctx->params.rot_mode |= CODA_MIR_HOR;
+		else
+			ctx->params.rot_mode &= ~CODA_MIR_HOR;
+		break;
+	case V4L2_CID_VFLIP:
+		if (ctrl->val)
+			ctx->params.rot_mode |= CODA_MIR_VER;
+		else
+			ctx->params.rot_mode &= ~CODA_MIR_VER;
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		ctx->params.bitrate = ctrl->val / 1000;
+		break;
+	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+		ctx->params.gop_size = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+		ctx->params.h264_intra_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+		ctx->params.h264_inter_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+		ctx->params.h264_min_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+		ctx->params.h264_max_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+		ctx->params.h264_deblk_alpha = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+		ctx->params.h264_deblk_beta = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+		ctx->params.h264_deblk_enabled = (ctrl->val ==
+				V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+		ctx->params.mpeg4_intra_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+		ctx->params.mpeg4_inter_qp = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+		ctx->params.slice_mode = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+		ctx->params.slice_max_mb = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+		ctx->params.slice_max_bits = ctrl->val * 8;
+		break;
+	case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+		break;
+	case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+		ctx->params.intra_refresh = ctrl->val;
+		break;
+	default:
+		v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+			"Invalid control, id=%d, val=%d\n",
+			ctrl->id, ctrl->val);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops coda_ctrl_ops = {
+	.s_ctrl = coda_s_ctrl,
+};
+
+static int coda_ctrls_setup(struct coda_ctx *ctx)
+{
+	v4l2_ctrl_handler_init(&ctx->ctrls, 9);
+
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25);
+	if (ctx->dev->devtype->product != CODA_960) {
+		v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+			V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12);
+	}
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0);
+	v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+		V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0,
+		V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2);
+	v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+		V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0,
+		V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1,
+		500);
+	v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+		V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+		(1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE),
+		V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
+	v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+		V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0,
+		1920 * 1088 / 256, 1, 0);
+
+	if (ctx->ctrls.error) {
+		v4l2_err(&ctx->dev->v4l2_dev,
+			"control initialization error (%d)",
+			ctx->ctrls.error);
+		return -EINVAL;
+	}
+
+	return v4l2_ctrl_handler_setup(&ctx->ctrls);
+}
+
+static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq)
+{
+	vq->drv_priv = ctx;
+	vq->ops = &coda_qops;
+	vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	vq->lock = &ctx->dev->dev_mutex;
+
+	return vb2_queue_init(vq);
+}
+
+int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq,
+			    struct vb2_queue *dst_vq)
+{
+	int ret;
+
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+
+	ret = coda_queue_init(priv, src_vq);
+	if (ret)
+		return ret;
+
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+	return coda_queue_init(priv, dst_vq);
+}
+
+int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
+			    struct vb2_queue *dst_vq)
+{
+	int ret;
+
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+
+	ret = coda_queue_init(priv, src_vq);
+	if (ret)
+		return ret;
+
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+	return coda_queue_init(priv, dst_vq);
+}
+
+static int coda_next_free_instance(struct coda_dev *dev)
+{
+	int idx = ffz(dev->instance_mask);
+
+	if ((idx < 0) ||
+	    (dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES))
+		return -EBUSY;
+
+	return idx;
+}
+
+static int coda_open(struct file *file, enum coda_inst_type inst_type,
+		     const struct coda_context_ops *ctx_ops)
+{
+	struct coda_dev *dev = video_drvdata(file);
+	struct coda_ctx *ctx = NULL;
+	char *name;
+	int ret;
+	int idx;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	idx = coda_next_free_instance(dev);
+	if (idx < 0) {
+		ret = idx;
+		goto err_coda_max;
+	}
+	set_bit(idx, &dev->instance_mask);
+
+	name = kasprintf(GFP_KERNEL, "context%d", idx);
+	ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root);
+	kfree(name);
+
+	ctx->inst_type = inst_type;
+	ctx->ops = ctx_ops;
+	init_completion(&ctx->completion);
+	INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
+	INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work);
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+	ctx->dev = dev;
+	ctx->idx = idx;
+	switch (dev->devtype->product) {
+	case CODA_7541:
+	case CODA_960:
+		ctx->reg_idx = 0;
+		break;
+	default:
+		ctx->reg_idx = idx;
+	}
+
+	/* Power up and upload firmware if necessary */
+	ret = pm_runtime_get_sync(&dev->plat_dev->dev);
+	if (ret < 0) {
+		v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret);
+		goto err_pm_get;
+	}
+
+	ret = clk_prepare_enable(dev->clk_per);
+	if (ret)
+		goto err_clk_per;
+
+	ret = clk_prepare_enable(dev->clk_ahb);
+	if (ret)
+		goto err_clk_ahb;
+
+	set_default_params(ctx);
+	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+					    ctx->ops->queue_init);
+	if (IS_ERR(ctx->fh.m2m_ctx)) {
+		ret = PTR_ERR(ctx->fh.m2m_ctx);
+
+		v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n",
+			 __func__, ret);
+		goto err_ctx_init;
+	}
+
+	ret = coda_ctrls_setup(ctx);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n");
+		goto err_ctrls_setup;
+	}
+
+	ctx->fh.ctrl_handler = &ctx->ctrls;
+
+	ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE,
+				     "parabuf");
+	if (ret < 0) {
+		v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
+		goto err_dma_alloc;
+	}
+
+	ctx->bitstream.size = CODA_MAX_FRAME_SIZE;
+	ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev,
+			ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL);
+	if (!ctx->bitstream.vaddr) {
+		v4l2_err(&dev->v4l2_dev,
+			 "failed to allocate bitstream ringbuffer");
+		ret = -ENOMEM;
+		goto err_dma_writecombine;
+	}
+	kfifo_init(&ctx->bitstream_fifo,
+		ctx->bitstream.vaddr, ctx->bitstream.size);
+	mutex_init(&ctx->bitstream_mutex);
+	mutex_init(&ctx->buffer_mutex);
+	INIT_LIST_HEAD(&ctx->timestamp_list);
+
+	coda_lock(ctx);
+	list_add(&ctx->list, &dev->instances);
+	coda_unlock(ctx);
+
+	v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n",
+		 ctx->idx, ctx);
+
+	return 0;
+
+err_dma_writecombine:
+	if (ctx->dev->devtype->product == CODA_DX6)
+		coda_free_aux_buf(dev, &ctx->workbuf);
+	coda_free_aux_buf(dev, &ctx->parabuf);
+err_dma_alloc:
+	v4l2_ctrl_handler_free(&ctx->ctrls);
+err_ctrls_setup:
+	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+err_ctx_init:
+	clk_disable_unprepare(dev->clk_ahb);
+err_clk_ahb:
+	clk_disable_unprepare(dev->clk_per);
+err_clk_per:
+	pm_runtime_put_sync(&dev->plat_dev->dev);
+err_pm_get:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	clear_bit(ctx->idx, &dev->instance_mask);
+err_coda_max:
+	kfree(ctx);
+	return ret;
+}
+
+static int coda_encoder_open(struct file *file)
+{
+	return coda_open(file, CODA_INST_ENCODER, &coda_bit_encode_ops);
+}
+
+static int coda_decoder_open(struct file *file)
+{
+	return coda_open(file, CODA_INST_DECODER, &coda_bit_decode_ops);
+}
+
+static int coda_release(struct file *file)
+{
+	struct coda_dev *dev = video_drvdata(file);
+	struct coda_ctx *ctx = fh_to_ctx(file->private_data);
+
+	v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
+		 ctx);
+
+	debugfs_remove_recursive(ctx->debugfs_entry);
+
+	/* If this instance is running, call .job_abort and wait for it to end */
+	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+	/* In case the instance was not running, we still need to call SEQ_END */
+	if (ctx->initialized) {
+		queue_work(dev->workqueue, &ctx->seq_end_work);
+		flush_work(&ctx->seq_end_work);
+	}
+
+	coda_lock(ctx);
+	list_del(&ctx->list);
+	coda_unlock(ctx);
+
+	dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
+		ctx->bitstream.vaddr, ctx->bitstream.paddr);
+	if (ctx->dev->devtype->product == CODA_DX6)
+		coda_free_aux_buf(dev, &ctx->workbuf);
+
+	coda_free_aux_buf(dev, &ctx->parabuf);
+	v4l2_ctrl_handler_free(&ctx->ctrls);
+	clk_disable_unprepare(dev->clk_ahb);
+	clk_disable_unprepare(dev->clk_per);
+	pm_runtime_put_sync(&dev->plat_dev->dev);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	clear_bit(ctx->idx, &dev->instance_mask);
+	if (ctx->ops->release)
+		ctx->ops->release(ctx);
+	kfree(ctx);
+
+	return 0;
+}
+
+static const struct v4l2_file_operations coda_encoder_fops = {
+	.owner		= THIS_MODULE,
+	.open		= coda_encoder_open,
+	.release	= coda_release,
+	.poll		= v4l2_m2m_fop_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= v4l2_m2m_fop_mmap,
+};
+
+static const struct v4l2_file_operations coda_decoder_fops = {
+	.owner		= THIS_MODULE,
+	.open		= coda_decoder_open,
+	.release	= coda_release,
+	.poll		= v4l2_m2m_fop_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= v4l2_m2m_fop_mmap,
+};
+
+static int coda_hw_init(struct coda_dev *dev)
+{
+	u32 data;
+	u16 *p;
+	int i, ret;
+
+	ret = clk_prepare_enable(dev->clk_per);
+	if (ret)
+		goto err_clk_per;
+
+	ret = clk_prepare_enable(dev->clk_ahb);
+	if (ret)
+		goto err_clk_ahb;
+
+	if (dev->rstc)
+		reset_control_reset(dev->rstc);
+
+	/*
+	 * Copy the first CODA_ISRAM_SIZE in the internal SRAM.
+	 * The 16-bit chars in the code buffer are in memory access
+	 * order, re-sort them to CODA order for register download.
+	 * Data in this SRAM survives a reboot.
+	 */
+	p = (u16 *)dev->codebuf.vaddr;
+	if (dev->devtype->product == CODA_DX6) {
+		for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++)  {
+			data = CODA_DOWN_ADDRESS_SET(i) |
+				CODA_DOWN_DATA_SET(p[i ^ 1]);
+			coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
+		}
+	} else {
+		for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) {
+			data = CODA_DOWN_ADDRESS_SET(i) |
+				CODA_DOWN_DATA_SET(p[round_down(i, 4) +
+							3 - (i % 4)]);
+			coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
+		}
+	}
+
+	/* Clear registers */
+	for (i = 0; i < 64; i++)
+		coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4);
+
+	/* Tell the BIT where to find everything it needs */
+	if (dev->devtype->product == CODA_960 ||
+	    dev->devtype->product == CODA_7541) {
+		coda_write(dev, dev->tempbuf.paddr,
+				CODA_REG_BIT_TEMP_BUF_ADDR);
+		coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
+	} else {
+		coda_write(dev, dev->workbuf.paddr,
+			      CODA_REG_BIT_WORK_BUF_ADDR);
+	}
+	coda_write(dev, dev->codebuf.paddr,
+		      CODA_REG_BIT_CODE_BUF_ADDR);
+	coda_write(dev, 0, CODA_REG_BIT_CODE_RUN);
+
+	/* Set default values */
+	switch (dev->devtype->product) {
+	case CODA_DX6:
+		coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH,
+			   CODA_REG_BIT_STREAM_CTRL);
+		break;
+	default:
+		coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH,
+			   CODA_REG_BIT_STREAM_CTRL);
+	}
+	if (dev->devtype->product == CODA_960)
+		coda_write(dev, 1 << 12, CODA_REG_BIT_FRAME_MEM_CTRL);
+	else
+		coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL);
+
+	if (dev->devtype->product != CODA_DX6)
+		coda_write(dev, 0, CODA7_REG_BIT_AXI_SRAM_USE);
+
+	coda_write(dev, CODA_INT_INTERRUPT_ENABLE,
+		      CODA_REG_BIT_INT_ENABLE);
+
+	/* Reset VPU and start processor */
+	data = coda_read(dev, CODA_REG_BIT_CODE_RESET);
+	data |= CODA_REG_RESET_ENABLE;
+	coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
+	udelay(10);
+	data &= ~CODA_REG_RESET_ENABLE;
+	coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
+	coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
+
+	clk_disable_unprepare(dev->clk_ahb);
+	clk_disable_unprepare(dev->clk_per);
+
+	return 0;
+
+err_clk_ahb:
+	clk_disable_unprepare(dev->clk_per);
+err_clk_per:
+	return ret;
+}
+
+static int coda_register_device(struct coda_dev *dev, struct video_device *vfd)
+{
+	vfd->release	= video_device_release_empty,
+	vfd->lock	= &dev->dev_mutex;
+	vfd->v4l2_dev	= &dev->v4l2_dev;
+	vfd->vfl_dir	= VFL_DIR_M2M;
+	video_set_drvdata(vfd, dev);
+
+	/* Not applicable, use the selection API instead */
+	v4l2_disable_ioctl(vfd, VIDIOC_CROPCAP);
+	v4l2_disable_ioctl(vfd, VIDIOC_G_CROP);
+	v4l2_disable_ioctl(vfd, VIDIOC_S_CROP);
+
+	return video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+}
+
+static void coda_fw_callback(const struct firmware *fw, void *context)
+{
+	struct coda_dev *dev = context;
+	struct platform_device *pdev = dev->plat_dev;
+	int ret;
+
+	if (!fw) {
+		v4l2_err(&dev->v4l2_dev, "firmware request failed\n");
+		goto put_pm;
+	}
+
+	/* allocate auxiliary per-device code buffer for the BIT processor */
+	ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf",
+				 dev->debugfs_root);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to allocate code buffer\n");
+		goto put_pm;
+	}
+
+	/* Copy the whole firmware image to the code buffer */
+	memcpy(dev->codebuf.vaddr, fw->data, fw->size);
+	release_firmware(fw);
+
+	ret = coda_hw_init(dev);
+	if (ret < 0) {
+		v4l2_err(&dev->v4l2_dev, "HW initialization failed\n");
+		goto put_pm;
+	}
+
+	ret = coda_check_firmware(dev);
+	if (ret < 0)
+		goto put_pm;
+
+	dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+	if (IS_ERR(dev->alloc_ctx)) {
+		v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n");
+		goto put_pm;
+	}
+
+	dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops);
+	if (IS_ERR(dev->m2m_dev)) {
+		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+		goto rel_ctx;
+	}
+
+	dev->vfd[0].fops      = &coda_encoder_fops,
+	dev->vfd[0].ioctl_ops = &coda_ioctl_ops;
+	snprintf(dev->vfd[0].name, sizeof(dev->vfd[0].name), "coda-encoder");
+	ret = coda_register_device(dev, &dev->vfd[0]);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Failed to register encoder video device\n");
+		goto rel_m2m;
+	}
+
+	dev->vfd[1].fops      = &coda_decoder_fops,
+	dev->vfd[1].ioctl_ops = &coda_ioctl_ops;
+	snprintf(dev->vfd[1].name, sizeof(dev->vfd[1].name), "coda-decoder");
+	ret = coda_register_device(dev, &dev->vfd[1]);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Failed to register decoder video device\n");
+		goto rel_m2m;
+	}
+
+	v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n",
+		  dev->vfd[0].num, dev->vfd[1].num);
+
+	pm_runtime_put_sync(&pdev->dev);
+	return;
+
+rel_m2m:
+	v4l2_m2m_release(dev->m2m_dev);
+rel_ctx:
+	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+put_pm:
+	pm_runtime_put_sync(&pdev->dev);
+}
+
+static int coda_firmware_request(struct coda_dev *dev)
+{
+	char *fw = dev->devtype->firmware;
+
+	dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
+		coda_product_name(dev->devtype->product));
+
+	return request_firmware_nowait(THIS_MODULE, true,
+		fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback);
+}
+
+enum coda_platform {
+	CODA_IMX27,
+	CODA_IMX53,
+	CODA_IMX6Q,
+	CODA_IMX6DL,
+};
+
+static const struct coda_devtype coda_devdata[] = {
+	[CODA_IMX27] = {
+		.firmware     = "v4l-codadx6-imx27.bin",
+		.product      = CODA_DX6,
+		.codecs       = codadx6_codecs,
+		.num_codecs   = ARRAY_SIZE(codadx6_codecs),
+		.workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024,
+		.iram_size    = 0xb000,
+	},
+	[CODA_IMX53] = {
+		.firmware     = "v4l-coda7541-imx53.bin",
+		.product      = CODA_7541,
+		.codecs       = coda7_codecs,
+		.num_codecs   = ARRAY_SIZE(coda7_codecs),
+		.workbuf_size = 128 * 1024,
+		.tempbuf_size = 304 * 1024,
+		.iram_size    = 0x14000,
+	},
+	[CODA_IMX6Q] = {
+		.firmware     = "v4l-coda960-imx6q.bin",
+		.product      = CODA_960,
+		.codecs       = coda9_codecs,
+		.num_codecs   = ARRAY_SIZE(coda9_codecs),
+		.workbuf_size = 80 * 1024,
+		.tempbuf_size = 204 * 1024,
+		.iram_size    = 0x21000,
+	},
+	[CODA_IMX6DL] = {
+		.firmware     = "v4l-coda960-imx6dl.bin",
+		.product      = CODA_960,
+		.codecs       = coda9_codecs,
+		.num_codecs   = ARRAY_SIZE(coda9_codecs),
+		.workbuf_size = 80 * 1024,
+		.tempbuf_size = 204 * 1024,
+		.iram_size    = 0x20000,
+	},
+};
+
+static struct platform_device_id coda_platform_ids[] = {
+	{ .name = "coda-imx27", .driver_data = CODA_IMX27 },
+	{ .name = "coda-imx53", .driver_data = CODA_IMX53 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, coda_platform_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id coda_dt_ids[] = {
+	{ .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] },
+	{ .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] },
+	{ .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] },
+	{ .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, coda_dt_ids);
+#endif
+
+static int coda_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id =
+			of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev);
+	const struct platform_device_id *pdev_id;
+	struct coda_platform_data *pdata = pdev->dev.platform_data;
+	struct device_node *np = pdev->dev.of_node;
+	struct gen_pool *pool;
+	struct coda_dev *dev;
+	struct resource *res;
+	int ret, irq;
+
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		dev_err(&pdev->dev, "Not enough memory for %s\n",
+			CODA_NAME);
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&dev->irqlock);
+	INIT_LIST_HEAD(&dev->instances);
+
+	dev->plat_dev = pdev;
+	dev->clk_per = devm_clk_get(&pdev->dev, "per");
+	if (IS_ERR(dev->clk_per)) {
+		dev_err(&pdev->dev, "Could not get per clock\n");
+		return PTR_ERR(dev->clk_per);
+	}
+
+	dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
+	if (IS_ERR(dev->clk_ahb)) {
+		dev_err(&pdev->dev, "Could not get ahb clock\n");
+		return PTR_ERR(dev->clk_ahb);
+	}
+
+	/* Get  memory for physical registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dev->regs_base))
+		return PTR_ERR(dev->regs_base);
+
+	/* IRQ */
+	irq = platform_get_irq_byname(pdev, "bit");
+	if (irq < 0)
+		irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "failed to get irq resource\n");
+		return irq;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
+			IRQF_ONESHOT, dev_name(&pdev->dev), dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+		return ret;
+	}
+
+	dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL);
+	if (IS_ERR(dev->rstc)) {
+		ret = PTR_ERR(dev->rstc);
+		if (ret == -ENOENT || ret == -ENOSYS) {
+			dev->rstc = NULL;
+		} else {
+			dev_err(&pdev->dev, "failed get reset control: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	/* Get IRAM pool from device tree or platform data */
+	pool = of_get_named_gen_pool(np, "iram", 0);
+	if (!pool && pdata)
+		pool = dev_get_gen_pool(pdata->iram_dev);
+	if (!pool) {
+		dev_err(&pdev->dev, "iram pool not available\n");
+		return -ENOMEM;
+	}
+	dev->iram_pool = pool;
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret)
+		return ret;
+
+	mutex_init(&dev->dev_mutex);
+	mutex_init(&dev->coda_mutex);
+
+	pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
+
+	if (of_id) {
+		dev->devtype = of_id->data;
+	} else if (pdev_id) {
+		dev->devtype = &coda_devdata[pdev_id->driver_data];
+	} else {
+		v4l2_device_unregister(&dev->v4l2_dev);
+		return -EINVAL;
+	}
+
+	dev->debugfs_root = debugfs_create_dir("coda", NULL);
+	if (!dev->debugfs_root)
+		dev_warn(&pdev->dev, "failed to create debugfs root\n");
+
+	/* allocate auxiliary per-device buffers for the BIT processor */
+	if (dev->devtype->product == CODA_DX6) {
+		ret = coda_alloc_aux_buf(dev, &dev->workbuf,
+					 dev->devtype->workbuf_size, "workbuf",
+					 dev->debugfs_root);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to allocate work buffer\n");
+			v4l2_device_unregister(&dev->v4l2_dev);
+			return ret;
+		}
+	}
+
+	if (dev->devtype->tempbuf_size) {
+		ret = coda_alloc_aux_buf(dev, &dev->tempbuf,
+					 dev->devtype->tempbuf_size, "tempbuf",
+					 dev->debugfs_root);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to allocate temp buffer\n");
+			v4l2_device_unregister(&dev->v4l2_dev);
+			return ret;
+		}
+	}
+
+	dev->iram.size = dev->devtype->iram_size;
+	dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size,
+					     &dev->iram.paddr);
+	if (!dev->iram.vaddr) {
+		dev_warn(&pdev->dev, "unable to alloc iram\n");
+	} else {
+		dev->iram.blob.data = dev->iram.vaddr;
+		dev->iram.blob.size = dev->iram.size;
+		dev->iram.dentry = debugfs_create_blob("iram", 0644,
+						       dev->debugfs_root,
+						       &dev->iram.blob);
+	}
+
+	dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+	if (!dev->workqueue) {
+		dev_err(&pdev->dev, "unable to alloc workqueue\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	/*
+	 * Start activated so we can directly call coda_hw_init in
+	 * coda_fw_callback regardless of whether CONFIG_PM_RUNTIME is
+	 * enabled or whether the device is associated with a PM domain.
+	 */
+	pm_runtime_get_noresume(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	return coda_firmware_request(dev);
+}
+
+static int coda_remove(struct platform_device *pdev)
+{
+	struct coda_dev *dev = platform_get_drvdata(pdev);
+
+	video_unregister_device(&dev->vfd[0]);
+	video_unregister_device(&dev->vfd[1]);
+	if (dev->m2m_dev)
+		v4l2_m2m_release(dev->m2m_dev);
+	pm_runtime_disable(&pdev->dev);
+	if (dev->alloc_ctx)
+		vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	destroy_workqueue(dev->workqueue);
+	if (dev->iram.vaddr)
+		gen_pool_free(dev->iram_pool, (unsigned long)dev->iram.vaddr,
+			      dev->iram.size);
+	coda_free_aux_buf(dev, &dev->codebuf);
+	coda_free_aux_buf(dev, &dev->tempbuf);
+	coda_free_aux_buf(dev, &dev->workbuf);
+	debugfs_remove_recursive(dev->debugfs_root);
+	return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int coda_runtime_resume(struct device *dev)
+{
+	struct coda_dev *cdev = dev_get_drvdata(dev);
+	int ret = 0;
+
+	if (dev->pm_domain && cdev->codebuf.vaddr) {
+		ret = coda_hw_init(cdev);
+		if (ret)
+			v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n");
+	}
+
+	return ret;
+}
+#endif
+
+static const struct dev_pm_ops coda_pm_ops = {
+	SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL)
+};
+
+static struct platform_driver coda_driver = {
+	.probe	= coda_probe,
+	.remove	= coda_remove,
+	.driver	= {
+		.name	= CODA_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(coda_dt_ids),
+		.pm	= &coda_pm_ops,
+	},
+	.id_table = coda_platform_ids,
+};
+
+module_platform_driver(coda_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
+MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver");
diff --git a/drivers/media/platform/coda/coda-h264.c b/drivers/media/platform/coda/coda-h264.c
new file mode 100644
index 0000000..456773a
--- /dev/null
+++ b/drivers/media/platform/coda/coda-h264.c
@@ -0,0 +1,37 @@
+/*
+ * Coda multi-standard codec IP - H.264 helper functions
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff,
+			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 };
+static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 };
+
+int coda_h264_padding(int size, char *p)
+{
+	int nal_size;
+	int diff;
+
+	diff = size - (size & ~0x7);
+	if (diff == 0)
+		return 0;
+
+	nal_size = coda_filler_size[diff];
+	memcpy(p, coda_filler_nal, nal_size);
+
+	/* Add rbsp stop bit and trailing at the end */
+	*(p + nal_size - 1) = 0x80;
+
+	return nal_size;
+}
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
new file mode 100644
index 0000000..bbc18c0
--- /dev/null
+++ b/drivers/media/platform/coda/coda.h
@@ -0,0 +1,287 @@
+/*
+ * Coda multi-standard codec IP
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <linux/kfifo.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-core.h>
+
+#include "coda_regs.h"
+
+#define CODA_MAX_FRAMEBUFFERS	8
+#define CODA_MAX_FRAME_SIZE	0x100000
+#define FMO_SLICE_SAVE_BUF_SIZE	(32)
+
+enum {
+	V4L2_M2M_SRC = 0,
+	V4L2_M2M_DST = 1,
+};
+
+enum coda_inst_type {
+	CODA_INST_ENCODER,
+	CODA_INST_DECODER,
+};
+
+enum coda_product {
+	CODA_DX6 = 0xf001,
+	CODA_7541 = 0xf012,
+	CODA_960 = 0xf020,
+};
+
+struct coda_devtype {
+	char			*firmware;
+	enum coda_product	product;
+	const struct coda_codec	*codecs;
+	unsigned int		num_codecs;
+	size_t			workbuf_size;
+	size_t			tempbuf_size;
+	size_t			iram_size;
+};
+
+struct coda_aux_buf {
+	void			*vaddr;
+	dma_addr_t		paddr;
+	u32			size;
+	struct debugfs_blob_wrapper blob;
+	struct dentry		*dentry;
+};
+
+struct coda_dev {
+	struct v4l2_device	v4l2_dev;
+	struct video_device	vfd[2];
+	struct platform_device	*plat_dev;
+	const struct coda_devtype *devtype;
+
+	void __iomem		*regs_base;
+	struct clk		*clk_per;
+	struct clk		*clk_ahb;
+	struct reset_control	*rstc;
+
+	struct coda_aux_buf	codebuf;
+	struct coda_aux_buf	tempbuf;
+	struct coda_aux_buf	workbuf;
+	struct gen_pool		*iram_pool;
+	struct coda_aux_buf	iram;
+
+	spinlock_t		irqlock;
+	struct mutex		dev_mutex;
+	struct mutex		coda_mutex;
+	struct workqueue_struct	*workqueue;
+	struct v4l2_m2m_dev	*m2m_dev;
+	struct vb2_alloc_ctx	*alloc_ctx;
+	struct list_head	instances;
+	unsigned long		instance_mask;
+	struct dentry		*debugfs_root;
+};
+
+struct coda_codec {
+	u32 mode;
+	u32 src_fourcc;
+	u32 dst_fourcc;
+	u32 max_w;
+	u32 max_h;
+};
+
+struct coda_huff_tab;
+
+struct coda_params {
+	u8			rot_mode;
+	u8			h264_intra_qp;
+	u8			h264_inter_qp;
+	u8			h264_min_qp;
+	u8			h264_max_qp;
+	u8			h264_deblk_enabled;
+	u8			h264_deblk_alpha;
+	u8			h264_deblk_beta;
+	u8			mpeg4_intra_qp;
+	u8			mpeg4_inter_qp;
+	u8			gop_size;
+	int			intra_refresh;
+	int			codec_mode;
+	int			codec_mode_aux;
+	enum v4l2_mpeg_video_multi_slice_mode slice_mode;
+	u32			framerate;
+	u16			bitrate;
+	u32			slice_max_bits;
+	u32			slice_max_mb;
+};
+
+struct coda_timestamp {
+	struct list_head	list;
+	u32			sequence;
+	struct v4l2_timecode	timecode;
+	struct timeval		timestamp;
+};
+
+/* Per-queue, driver-specific private data */
+struct coda_q_data {
+	unsigned int		width;
+	unsigned int		height;
+	unsigned int		bytesperline;
+	unsigned int		sizeimage;
+	unsigned int		fourcc;
+	struct v4l2_rect	rect;
+};
+
+struct coda_iram_info {
+	u32		axi_sram_use;
+	phys_addr_t	buf_bit_use;
+	phys_addr_t	buf_ip_ac_dc_use;
+	phys_addr_t	buf_dbk_y_use;
+	phys_addr_t	buf_dbk_c_use;
+	phys_addr_t	buf_ovl_use;
+	phys_addr_t	buf_btp_use;
+	phys_addr_t	search_ram_paddr;
+	int		search_ram_size;
+	int		remaining;
+	phys_addr_t	next_paddr;
+};
+
+struct gdi_tiled_map {
+	int xy2ca_map[16];
+	int xy2ba_map[16];
+	int xy2ra_map[16];
+	int rbc2axi_map[32];
+	int xy2rbc_config;
+	int map_type;
+#define GDI_LINEAR_FRAME_MAP 0
+};
+
+struct coda_ctx;
+
+struct coda_context_ops {
+	int (*queue_init)(void *priv, struct vb2_queue *src_vq,
+			  struct vb2_queue *dst_vq);
+	int (*start_streaming)(struct coda_ctx *ctx);
+	int (*prepare_run)(struct coda_ctx *ctx);
+	void (*finish_run)(struct coda_ctx *ctx);
+	void (*seq_end_work)(struct work_struct *work);
+	void (*release)(struct coda_ctx *ctx);
+};
+
+struct coda_ctx {
+	struct coda_dev			*dev;
+	struct mutex			buffer_mutex;
+	struct list_head		list;
+	struct work_struct		pic_run_work;
+	struct work_struct		seq_end_work;
+	struct completion		completion;
+	const struct coda_context_ops	*ops;
+	int				aborting;
+	int				initialized;
+	int				streamon_out;
+	int				streamon_cap;
+	u32				isequence;
+	u32				qsequence;
+	u32				osequence;
+	u32				sequence_offset;
+	struct coda_q_data		q_data[2];
+	enum coda_inst_type		inst_type;
+	const struct coda_codec		*codec;
+	enum v4l2_colorspace		colorspace;
+	struct coda_params		params;
+	struct v4l2_ctrl_handler	ctrls;
+	struct v4l2_fh			fh;
+	int				gopcounter;
+	int				runcounter;
+	char				vpu_header[3][64];
+	int				vpu_header_size[3];
+	struct kfifo			bitstream_fifo;
+	struct mutex			bitstream_mutex;
+	struct coda_aux_buf		bitstream;
+	bool				hold;
+	struct coda_aux_buf		parabuf;
+	struct coda_aux_buf		psbuf;
+	struct coda_aux_buf		slicebuf;
+	struct coda_aux_buf		internal_frames[CODA_MAX_FRAMEBUFFERS];
+	u32				frame_types[CODA_MAX_FRAMEBUFFERS];
+	struct coda_timestamp		frame_timestamps[CODA_MAX_FRAMEBUFFERS];
+	u32				frame_errors[CODA_MAX_FRAMEBUFFERS];
+	struct list_head		timestamp_list;
+	struct coda_aux_buf		workbuf;
+	int				num_internal_frames;
+	int				idx;
+	int				reg_idx;
+	struct coda_iram_info		iram_info;
+	struct gdi_tiled_map		tiled_map;
+	u32				bit_stream_param;
+	u32				frm_dis_flg;
+	u32				frame_mem_ctrl;
+	int				display_idx;
+	struct dentry			*debugfs_entry;
+};
+
+extern int coda_debug;
+
+void coda_write(struct coda_dev *dev, u32 data, u32 reg);
+unsigned int coda_read(struct coda_dev *dev, u32 reg);
+
+int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
+		       size_t size, const char *name, struct dentry *parent);
+void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf);
+
+static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
+					 struct coda_aux_buf *buf, size_t size,
+					 const char *name)
+{
+	return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry);
+}
+
+int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq,
+			    struct vb2_queue *dst_vq);
+int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
+			    struct vb2_queue *dst_vq);
+
+int coda_hw_reset(struct coda_ctx *ctx);
+
+void coda_fill_bitstream(struct coda_ctx *ctx);
+
+void coda_set_gdi_regs(struct coda_ctx *ctx);
+
+static inline struct coda_q_data *get_q_data(struct coda_ctx *ctx,
+					     enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &(ctx->q_data[V4L2_M2M_SRC]);
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &(ctx->q_data[V4L2_M2M_DST]);
+	default:
+		return NULL;
+	}
+}
+
+const char *coda_product_name(int product);
+
+int coda_check_firmware(struct coda_dev *dev);
+
+static inline int coda_get_bitstream_payload(struct coda_ctx *ctx)
+{
+	return kfifo_len(&ctx->bitstream_fifo);
+}
+
+void coda_bit_stream_end_flag(struct coda_ctx *ctx);
+
+int coda_h264_padding(int size, char *p);
+
+extern const struct coda_context_ops coda_bit_encode_ops;
+extern const struct coda_context_ops coda_bit_decode_ops;
+
+irqreturn_t coda_irq_handler(int irq, void *data);
diff --git a/drivers/media/platform/coda.h b/drivers/media/platform/coda/coda_regs.h
similarity index 100%
rename from drivers/media/platform/coda.h
rename to drivers/media/platform/coda/coda_regs.h
diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig
index 45d598a..6434baf 100644
--- a/drivers/media/platform/davinci/Kconfig
+++ b/drivers/media/platform/davinci/Kconfig
@@ -1,7 +1,9 @@
 config VIDEO_DAVINCI_VPIF_DISPLAY
 	tristate "TI DaVinci VPIF V4L2-Display driver"
 	depends on m
-	depends on VIDEO_DEV && ARCH_DAVINCI
+	depends on VIDEO_DEV
+	depends on ARCH_DAVINCI || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT
@@ -16,7 +18,9 @@
 config VIDEO_DAVINCI_VPIF_CAPTURE
 	tristate "TI DaVinci VPIF video capture driver"
 	depends on m
-	depends on VIDEO_DEV && ARCH_DAVINCI
+	depends on VIDEO_DEV
+	depends on ARCH_DAVINCI || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	help
 	  Enables Davinci VPIF module used for capture devices.
@@ -29,7 +33,9 @@
 config VIDEO_DM6446_CCDC
 	tristate "TI DM6446 CCDC video capture driver"
 	depends on m
-	depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
+	depends on VIDEO_V4L2
+	depends on ARCH_DAVINCI || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF_DMA_CONTIG
 	help
 	   Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
@@ -44,7 +50,9 @@
 config VIDEO_DM355_CCDC
 	tristate "TI DM355 CCDC video capture driver"
 	depends on m
-	depends on VIDEO_V4L2 && ARCH_DAVINCI
+	depends on VIDEO_V4L2
+	depends on ARCH_DAVINCI || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF_DMA_CONTIG
 	help
 	   Enables DM355 CCD hw module. DM355 CCDC hw interfaces
@@ -60,6 +68,7 @@
 	tristate "TI DM365 ISIF video capture driver"
 	depends on m
 	depends on VIDEO_V4L2 && ARCH_DAVINCI
+	depends on HAS_DMA
 	select VIDEOBUF_DMA_CONTIG
 	help
 	   Enables ISIF hw module. This is the hardware module for
@@ -73,6 +82,7 @@
 	tristate "TI DaVinci VPBE V4L2-Display driver"
 	depends on m
 	depends on ARCH_DAVINCI
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	help
 	    Enables Davinci VPBE module used for display devices.
diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c
index 05f8fb7..3f44deb 100644
--- a/drivers/media/platform/davinci/dm355_ccdc.c
+++ b/drivers/media/platform/davinci/dm355_ccdc.c
@@ -460,7 +460,7 @@
  * ccdc_write_dfc_entry()
  * write an entry in the dfc table.
  */
-int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
+static int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
 {
 /* TODO This is to be re-visited and adjusted */
 #define DFC_WRITE_WAIT_COUNT	1000
diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c
index 07e98df..62a0ebb 100644
--- a/drivers/media/platform/davinci/dm644x_ccdc.c
+++ b/drivers/media/platform/davinci/dm644x_ccdc.c
@@ -130,9 +130,9 @@
  * This function will configure the window size
  * to be capture in CCDC reg
  */
-void ccdc_setwin(struct v4l2_rect *image_win,
-		enum ccdc_frmfmt frm_fmt,
-		int ppc)
+static void ccdc_setwin(struct v4l2_rect *image_win,
+			enum ccdc_frmfmt frm_fmt,
+			int ppc)
 {
 	int horz_start, horz_nr_pixels;
 	int vert_start, vert_nr_lines;
@@ -291,7 +291,7 @@
 		dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed");
 		return -EFAULT;
 	}
-	config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr;
+	config_params->fault_pxl.fpc_table_addr = (unsigned long)fpc_physaddr;
 	return 0;
 }
 
@@ -370,7 +370,7 @@
  * ccdc_config_ycbcr()
  * This function will configure CCDC for YCbCr video capture
  */
-void ccdc_config_ycbcr(void)
+static void ccdc_config_ycbcr(void)
 {
 	struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
 	u32 syn_mode;
@@ -506,7 +506,7 @@
 
 	/* Configure Fault pixel if needed */
 	regw(fpc->fpc_table_addr, CCDC_FPC_ADDR);
-	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n",
+	dev_dbg(ccdc_cfg.dev, "\nWriting 0x%lx to FPC_ADDR...\n",
 		       (fpc->fpc_table_addr));
 	/* Write the FPC params with FPC disable */
 	val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK;
@@ -523,7 +523,7 @@
  * ccdc_config_raw()
  * This function will configure CCDC for Raw capture mode
  */
-void ccdc_config_raw(void)
+static void ccdc_config_raw(void)
 {
 	struct ccdc_params_raw *params = &ccdc_cfg.bayer;
 	struct ccdc_config_params_raw *config_params =
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index ea7661a..de55f47 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -125,7 +125,7 @@
 /* ccdc configuration */
 static struct ccdc_config *ccdc_cfg;
 
-const struct vpfe_standard vpfe_standards[] = {
+static const struct vpfe_standard vpfe_standards[] = {
 	{V4L2_STD_525_60, 720, 480, {11, 10}, 1},
 	{V4L2_STD_625_50, 720, 576, {54, 59}, 1},
 };
@@ -442,11 +442,10 @@
 		return ret;
 
 	/* Update the values of sizeimage and bytesperline */
-	if (!ret) {
-		pix->bytesperline = ccdc_dev->hw_ops.get_line_length();
-		pix->sizeimage = pix->bytesperline * pix->height;
-	}
-	return ret;
+	pix->bytesperline = ccdc_dev->hw_ops.get_line_length();
+	pix->sizeimage = pix->bytesperline * pix->height;
+
+	return 0;
 }
 
 static int vpfe_initialize_device(struct vpfe_device *vpfe_dev)
@@ -943,12 +942,11 @@
 				struct v4l2_format *fmt)
 {
 	struct vpfe_device *vpfe_dev = video_drvdata(file);
-	int ret = 0;
 
 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n");
 	/* Fill in the information about format */
 	*fmt = vpfe_dev->fmt;
-	return ret;
+	return 0;
 }
 
 static int vpfe_enum_fmt_vid_cap(struct file *file, void  *priv,
@@ -1914,7 +1912,7 @@
 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
 		"trying to register vpfe device.\n");
 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
-		"video_dev=%x\n", (int)&vpfe_dev->video_dev);
+		"video_dev=%p\n", &vpfe_dev->video_dev);
 	vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	ret = video_register_device(vpfe_dev->video_dev,
 				    VFL_TYPE_GRABBER, -1);
diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c
index cd08e52..3dad5bd 100644
--- a/drivers/media/platform/davinci/vpif.c
+++ b/drivers/media/platform/davinci/vpif.c
@@ -38,6 +38,7 @@
 #define VPIF_CH3_MAX_MODES	2
 
 spinlock_t vpif_lock;
+EXPORT_SYMBOL_GPL(vpif_lock);
 
 void __iomem *vpif_base;
 EXPORT_SYMBOL_GPL(vpif_base);
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index b054b7e..3ccb26f 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -213,8 +213,6 @@
 	/* Remove buffer from the buffer queue */
 	list_del(&common->cur_frm->list);
 	spin_unlock_irqrestore(&common->irqlock, flags);
-	/* Mark state of the current frame to active */
-	common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
 
 	addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
 
@@ -350,7 +348,6 @@
 	/* Remove that buffer from the buffer queue */
 	list_del(&common->next_frm->list);
 	spin_unlock(&common->irqlock);
-	common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
 	addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
 
 	/* Set top and bottom field addresses in VPIF registers */
@@ -373,7 +370,6 @@
 	struct vpif_device *dev = &vpif_obj;
 	struct common_obj *common;
 	struct channel_obj *ch;
-	enum v4l2_field field;
 	int channel_id = 0;
 	int fid = -1, i;
 
@@ -383,8 +379,6 @@
 
 	ch = dev->dev[channel_id];
 
-	field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
-
 	for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) {
 		common = &ch->common[i];
 		/* skip If streaming is not started in this channel */
@@ -533,7 +527,7 @@
  */
 static void vpif_calculate_offsets(struct channel_obj *ch)
 {
-	unsigned int hpitch, vpitch, sizeimage;
+	unsigned int hpitch, sizeimage;
 	struct video_obj *vid_ch = &(ch->video);
 	struct vpif_params *vpifparams = &ch->vpifparams;
 	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
@@ -552,7 +546,6 @@
 	sizeimage = common->fmt.fmt.pix.sizeimage;
 
 	hpitch = common->fmt.fmt.pix.bytesperline;
-	vpitch = sizeimage / (hpitch * 2);
 
 	if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
 	    (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
@@ -1603,7 +1596,7 @@
 		ch = vpif_obj.dev[i];
 		common = &ch->common[VPIF_VIDEO_INDEX];
 
-		if (!vb2_is_streaming(&common->buffer_queue))
+		if (!vb2_start_streaming_called(&common->buffer_queue))
 			continue;
 
 		mutex_lock(&common->lock);
@@ -1637,7 +1630,7 @@
 		ch = vpif_obj.dev[i];
 		common = &ch->common[VPIF_VIDEO_INDEX];
 
-		if (!vb2_is_streaming(&common->buffer_queue))
+		if (!vb2_start_streaming_called(&common->buffer_queue))
 			continue;
 
 		mutex_lock(&common->lock);
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index a03ec73..8d6ced5 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -196,8 +196,6 @@
 
 	list_del(&common->cur_frm->list);
 	spin_unlock_irqrestore(&common->irqlock, flags);
-	/* Mark state of the current frame to active */
-	common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
 
 	addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
 	common->set_addr((addr + common->ytop_off),
@@ -306,8 +304,6 @@
 	/* Remove that buffer from the buffer queue */
 	list_del(&common->next_frm->list);
 	spin_unlock(&common->irqlock);
-	/* Mark status of the buffer as active */
-	common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
 
 	/* Set top and bottom field addrs in VPIF registers */
 	addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
@@ -360,7 +356,6 @@
 	struct vpif_device *dev = &vpif_obj;
 	struct channel_obj *ch;
 	struct common_obj *common;
-	enum v4l2_field field;
 	int fid = -1, i;
 	int channel_id = 0;
 
@@ -369,7 +364,6 @@
 		return IRQ_NONE;
 
 	ch = dev->dev[channel_id];
-	field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field;
 	for (i = 0; i < VPIF_NUMOBJECTS; i++) {
 		common = &ch->common[i];
 		/* If streaming is started in this channel */
@@ -502,7 +496,7 @@
 	struct vpif_params *vpifparams = &ch->vpifparams;
 	enum v4l2_field field = common->fmt.fmt.pix.field;
 	struct video_obj *vid_ch = &ch->video;
-	unsigned int hpitch, vpitch, sizeimage;
+	unsigned int hpitch, sizeimage;
 
 	if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) {
 		if (ch->vpifparams.std_info.frm_fmt)
@@ -516,7 +510,6 @@
 	sizeimage = common->fmt.fmt.pix.sizeimage;
 
 	hpitch = common->fmt.fmt.pix.bytesperline;
-	vpitch = sizeimage / (hpitch * 2);
 	if ((V4L2_FIELD_NONE == vid_ch->buf_field) ||
 	    (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) {
 		common->ytop_off = 0;
@@ -813,17 +806,14 @@
 {
 	struct vpif_display_chan_config *chan_cfg =
 		&vpif_cfg->chan_config[ch->channel_id];
-	struct vpif_subdev_info *subdev_info = NULL;
 	struct v4l2_subdev *sd = NULL;
 	u32 input = 0, output = 0;
 	int sd_index;
 	int ret;
 
 	sd_index = vpif_output_to_subdev(vpif_cfg, chan_cfg, index);
-	if (sd_index >= 0) {
+	if (sd_index >= 0)
 		sd = vpif_obj.sd[sd_index];
-		subdev_info = &vpif_cfg->subdevinfo[sd_index];
-	}
 
 	if (sd) {
 		input = chan_cfg->outputs[index].input_route;
@@ -1210,8 +1200,8 @@
 		INIT_LIST_HEAD(&common->dma_queue);
 
 		/* register video device */
-		vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
-			 (int)ch, (int)&ch->video_dev);
+		vpif_dbg(1, debug, "channel=%p,channel->video_dev=%p\n",
+			 ch, &ch->video_dev);
 
 		/* Initialize the video_device structure */
 		vdev = ch->video_dev;
@@ -1410,7 +1400,7 @@
 		ch = vpif_obj.dev[i];
 		common = &ch->common[VPIF_VIDEO_INDEX];
 
-		if (!vb2_is_streaming(&common->buffer_queue))
+		if (!vb2_start_streaming_called(&common->buffer_queue))
 			continue;
 
 		mutex_lock(&common->lock);
@@ -1442,7 +1432,7 @@
 		ch = vpif_obj.dev[i];
 		common = &ch->common[VPIF_VIDEO_INDEX];
 
-		if (!vb2_is_streaming(&common->buffer_queue))
+		if (!vb2_start_streaming_called(&common->buffer_queue))
 			continue;
 
 		mutex_lock(&common->lock);
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 9d0cc04..b4c9f1d 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -852,8 +852,8 @@
 		(frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
 		swap(addr->cb, addr->cr);
 
-	pr_debug("ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
-		addr->y, addr->cb, addr->cr, ret);
+	pr_debug("ADDR: y= %pad  cb= %pad cr= %pad ret= %d",
+		&addr->y, &addr->cb, &addr->cr, ret);
 
 	return ret;
 }
@@ -1086,7 +1086,7 @@
 	else
 		gsc->id = pdev->id;
 
-	if (gsc->id < 0 || gsc->id >= drv_data->num_entities) {
+	if (gsc->id >= drv_data->num_entities) {
 		dev_err(dev, "Invalid platform device id: %d\n", gsc->id);
 		return -EINVAL;
 	}
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index e434f1f..74e1de6 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -362,7 +362,6 @@
 {
 	struct gsc_ctx *ctx = fh_to_ctx(fh);
 	struct gsc_dev *gsc = ctx->gsc_dev;
-	struct gsc_frame *frame;
 	u32 max_cnt;
 
 	max_cnt = (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
@@ -376,8 +375,6 @@
 			gsc_ctx_state_lock_clear(GSC_DST_FMT, ctx);
 	}
 
-	frame = ctx_get_frame(ctx, reqbufs->type);
-
 	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
 }
 
diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.c b/drivers/media/platform/exynos-gsc/gsc-regs.c
index e22d147..ce12a11 100644
--- a/drivers/media/platform/exynos-gsc/gsc-regs.c
+++ b/drivers/media/platform/exynos-gsc/gsc-regs.c
@@ -90,8 +90,8 @@
 void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,
 				int index)
 {
-	pr_debug("src_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", index,
-			addr->y, addr->cb, addr->cr);
+	pr_debug("src_buf[%d]: %pad, cb: %pad, cr: %pad", index,
+			&addr->y, &addr->cb, &addr->cr);
 	writel(addr->y, dev->regs + GSC_IN_BASE_ADDR_Y(index));
 	writel(addr->cb, dev->regs + GSC_IN_BASE_ADDR_CB(index));
 	writel(addr->cr, dev->regs + GSC_IN_BASE_ADDR_CR(index));
@@ -101,8 +101,8 @@
 void gsc_hw_set_output_addr(struct gsc_dev *dev,
 			     struct gsc_addr *addr, int index)
 {
-	pr_debug("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
-			index, addr->y, addr->cb, addr->cr);
+	pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad",
+			index, &addr->y, &addr->cb, &addr->cr);
 	writel(addr->y, dev->regs + GSC_OUT_BASE_ADDR_Y(index));
 	writel(addr->cb, dev->regs + GSC_OUT_BASE_ADDR_CB(index));
 	writel(addr->cr, dev->regs + GSC_OUT_BASE_ADDR_CR(index));
diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig
index d7eadb7..8b0a506 100644
--- a/drivers/media/platform/exynos4-is/Kconfig
+++ b/drivers/media/platform/exynos4-is/Kconfig
@@ -2,7 +2,7 @@
 config VIDEO_SAMSUNG_EXYNOS4_IS
 	bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver"
 	depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
-	depends on (PLAT_S5P || ARCH_EXYNOS)
+	depends on (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST)
 	depends on OF && COMMON_CLK
 	help
 	  Say Y here to enable camera host interface devices for
@@ -18,6 +18,7 @@
 	tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver"
 	depends on m
 	depends on I2C
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	select V4L2_MEM2MEM_DEV
 	depends on MFD_SYSCON
@@ -47,6 +48,7 @@
 	tristate "EXYNOS FIMC-LITE camera interface driver"
 	depends on m
 	depends on I2C
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	select VIDEO_EXYNOS4_IS_COMMON
 	help
@@ -60,6 +62,7 @@
 config VIDEO_EXYNOS4_FIMC_IS
 	tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver"
 	depends on m
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	depends on OF
 	depends on FW_LOADER
diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.c b/drivers/media/platform/exynos4-is/fimc-is-errno.c
index e8519e1..e050e63 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-errno.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-errno.c
@@ -15,7 +15,7 @@
 
 #include "fimc-is-errno.h"
 
-const char * const fimc_is_param_strerr(unsigned int error)
+const char *fimc_is_param_strerr(unsigned int error)
 {
 	switch (error) {
 	case ERROR_COMMON_CMD:
@@ -146,7 +146,7 @@
 	}
 }
 
-const char * const fimc_is_strerr(unsigned int error)
+const char *fimc_is_strerr(unsigned int error)
 {
 	error &= ~IS_ERROR_TIME_OUT_FLAG;
 
diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.h b/drivers/media/platform/exynos4-is/fimc-is-errno.h
index 3de6f6d..ef981e7 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-errno.h
+++ b/drivers/media/platform/exynos4-is/fimc-is-errno.h
@@ -242,7 +242,7 @@
 	ERROR_SCALER_FLIP				= 521,
 };
 
-const char * const fimc_is_strerr(unsigned int error);
-const char * const fimc_is_param_strerr(unsigned int error);
+const char *fimc_is_strerr(unsigned int error);
+const char *fimc_is_param_strerr(unsigned int error);
 
 #endif /* FIMC_IS_ERR_H_ */
diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c
index bf1465d..72b9b43 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-param.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-param.c
@@ -667,7 +667,6 @@
 void fimc_is_set_initial_params(struct fimc_is *is)
 {
 	struct global_param *global;
-	struct sensor_param *sensor;
 	struct isp_param *isp;
 	struct drc_param *drc;
 	struct fd_param *fd;
@@ -676,7 +675,6 @@
 
 	index = is->config_index;
 	global = &is->config[index].global;
-	sensor = &is->config[index].sensor;
 	isp = &is->config[index].isp;
 	drc = &is->config[index].drc;
 	fd = &is->config[index].fd;
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index 5476dce..22162b2 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -388,7 +388,7 @@
 	mutex_lock(&is->lock);
 
 	if (fw->size < FIMC_IS_FW_SIZE_MIN || fw->size > FIMC_IS_FW_SIZE_MAX) {
-		dev_err(dev, "wrong firmware size: %d\n", fw->size);
+		dev_err(dev, "wrong firmware size: %zu\n", fw->size);
 		goto done;
 	}
 
@@ -416,7 +416,7 @@
 
 	dev_info(dev, "loaded firmware: %s, rev. %s\n",
 		 is->fw.info, is->fw.version);
-	dev_dbg(dev, "FW size: %d, paddr: %#x\n", fw->size, is->memory.paddr);
+	dev_dbg(dev, "FW size: %zu, paddr: %pad\n", fw->size, &is->memory.paddr);
 
 	is->is_shared_region->chip_id = 0xe4412;
 	is->is_shared_region->chip_rev_no = 1;
@@ -693,9 +693,9 @@
 		return -EIO;
 	}
 
-	pr_debug("shared region: %#x, parameter region: %#x\n",
-		 is->memory.paddr + FIMC_IS_SHARED_REGION_OFFSET,
-		 is->is_dma_p_region);
+	pr_debug("shared region: %pad, parameter region: %pad\n",
+		 &is->memory.paddr + FIMC_IS_SHARED_REGION_OFFSET,
+		 &is->is_dma_p_region);
 
 	is->setfile.sub_index = 0;
 
diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c
index 93f9cf2..76b6b4d 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp-video.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c
@@ -219,9 +219,9 @@
 							ivb->dma_addr[i];
 
 			isp_dbg(2, &video->ve.vdev,
-				"dma_buf %d (%d/%d/%d) addr: %#x\n",
-				buf_index, ivb->index, i, vb->v4l2_buf.index,
-				ivb->dma_addr[i]);
+				"dma_buf %pad (%d/%d/%d) addr: %pad\n",
+				&buf_index, ivb->index, i, vb->v4l2_buf.index,
+				&ivb->dma_addr[i]);
 		}
 
 		if (++video->buf_count < video->reqbufs_count)
@@ -313,7 +313,6 @@
 	struct fimc_is_video *ivc = &isp->video_capture;
 	struct media_entity *entity = &ivc->ve.vdev.entity;
 	struct media_device *mdev = entity->parent;
-	int ret = 0;
 
 	mutex_lock(&isp->video_lock);
 
@@ -335,7 +334,7 @@
 	pm_runtime_put(&isp->pdev->dev);
 	mutex_unlock(&isp->video_lock);
 
-	return ret;
+	return 0;
 }
 
 static const struct v4l2_file_operations isp_video_fops = {
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 344718d..54c49d5 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -1098,8 +1098,10 @@
 	if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) {
 		if (!(flags & MEDIA_LNK_FL_ENABLED))
 			ret = __fimc_md_modify_pipelines(sink, false);
+#if 0
 		else
-			; /* TODO: Link state change validation */
+			/* TODO: Link state change validation */
+#endif
 	/* After link activation */
 	} else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
 		   (link->flags & MEDIA_LNK_FL_ENABLED)) {
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index ae54ef5..db6fd14 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -25,6 +25,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/videodev2.h>
@@ -752,7 +753,7 @@
 	v4l2_of_parse_endpoint(node, &endpoint);
 
 	state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0;
-	if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES)
+	if (state->index >= CSIS_MAX_ENTITIES)
 		return -ENXIO;
 
 	/* Get MIPI CSI-2 bus configration from the endpoint node. */
diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig
index 72f3ef8..9c2e8f4 100644
--- a/drivers/media/platform/marvell-ccic/Kconfig
+++ b/drivers/media/platform/marvell-ccic/Kconfig
@@ -2,6 +2,7 @@
 	tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support"
 	depends on m
 	depends on PCI && I2C && VIDEO_V4L2
+	depends on HAS_DMA
 	select VIDEO_OV7670
 	select VIDEOBUF2_VMALLOC
 	select VIDEOBUF2_DMA_CONTIG
@@ -14,6 +15,7 @@
 	tristate "Marvell Armada 610 integrated camera controller support"
 	depends on m
 	depends on ARCH_MMP && I2C && VIDEO_V4L2
+	depends on HAS_DMA
 	select VIDEO_OV7670
 	depends on I2C_GPIO
 	select VIDEOBUF2_DMA_SG
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index 7e7d6e5..6895e12 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -67,7 +67,7 @@
 		"parameters require larger buffers, an attempt to reallocate "
 		"will be made.");
 #else /* MCAM_MODE_VMALLOC */
-static const bool alloc_bufs_at_read = 0;
+static const bool alloc_bufs_at_read;
 static const int n_dma_bufs = 3;  /* Used by S/G_PARM */
 #endif /* MCAM_MODE_VMALLOC */
 
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index fa8f7ca..4971ff2 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -27,7 +27,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf2-dma-contig.h>
-#include <asm/sizes.h>
+#include <linux/sizes.h>
 
 #define EMMAPRP_MODULE_NAME "mem2mem-emmaprp"
 
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
index f44d044..f0bc674 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -4,7 +4,7 @@
 config VIDEO_OMAP2_VOUT
 	tristate "OMAP2/OMAP3 V4L2-Display driver"
 	depends on m
-	depends on ARCH_OMAP2 || ARCH_OMAP3
+	depends on ARCH_OMAP2 || ARCH_OMAP3 || (COMPILE_TEST && HAS_MMU)
 	select VIDEOBUF_GEN
 	select VIDEOBUF_DMA_CONTIG
 	select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index 2d177fa..64ab6fb 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -369,7 +369,7 @@
 {
 	int ret = 0;
 	struct omap_overlay_info info;
-	int cropheight, cropwidth, pixheight, pixwidth;
+	int cropheight, cropwidth, pixwidth;
 
 	if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 &&
 			(outw != vout->pix.width || outh != vout->pix.height)) {
@@ -389,12 +389,10 @@
 	if (is_rotation_90_or_270(vout)) {
 		cropheight = vout->crop.width;
 		cropwidth = vout->crop.height;
-		pixheight = vout->pix.width;
 		pixwidth = vout->pix.height;
 	} else {
 		cropheight = vout->crop.height;
 		cropwidth = vout->crop.width;
-		pixheight = vout->pix.height;
 		pixwidth = vout->pix.width;
 	}
 
@@ -991,7 +989,7 @@
 		mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
 			DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2;
 		omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
-		vout->streaming = 0;
+		vout->streaming = false;
 
 		videobuf_streamoff(q);
 		videobuf_queue_cancel(q);
@@ -1451,12 +1449,10 @@
 	}
 	case V4L2_CID_VFLIP:
 	{
-		struct omap_overlay *ovl;
 		struct omapvideo_info *ovid;
 		unsigned int  mirror = a->value;
 
 		ovid = &vout->vid_info;
-		ovl = ovid->overlays[0];
 
 		mutex_lock(&vout->lock);
 		if (mirror && ovid->rotation_type == VOUT_ROT_NONE) {
@@ -1489,7 +1485,7 @@
 	struct omap_vout_device *vout = fh;
 	struct videobuf_queue *q = &vout->vbq;
 
-	if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0))
+	if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
 		return -EINVAL;
 	/* if memory is not mmp or userptr
 	   return error */
@@ -1648,7 +1644,7 @@
 	vout->field_id = 0;
 
 	/* set flag here. Next QBUF will start DMA */
-	vout->streaming = 1;
+	vout->streaming = true;
 
 	vout->first_int = 1;
 
@@ -1708,7 +1704,7 @@
 	if (!vout->streaming)
 		return -EINVAL;
 
-	vout->streaming = 0;
+	vout->streaming = false;
 	mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
 		| DISPC_IRQ_VSYNC2;
 
@@ -1916,7 +1912,7 @@
 	control[0].id = V4L2_CID_ROTATE;
 	control[0].value = 0;
 	vout->rotation = 0;
-	vout->mirror = 0;
+	vout->mirror = false;
 	vout->control[2].id = V4L2_CID_HFLIP;
 	vout->control[2].value = 0;
 	if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c
index 62e7e57..aa39306 100644
--- a/drivers/media/platform/omap/omap_vout_vrfb.c
+++ b/drivers/media/platform/omap/omap_vout_vrfb.c
@@ -148,7 +148,7 @@
 			ret =  -ENOMEM;
 			goto release_vrfb_ctx;
 		}
-		vout->vrfb_static_allocation = 1;
+		vout->vrfb_static_allocation = true;
 	}
 	return 0;
 
@@ -336,7 +336,7 @@
 		offset = vout->vrfb_context[0].yoffset *
 			vout->vrfb_context[0].bytespp;
 		temp_ps = ps / vr_ps;
-		if (mirroring == 0) {
+		if (!mirroring) {
 			*cropped_offset = offset + line_length *
 				temp_ps * cleft + crop->top * temp_ps;
 		} else {
@@ -350,7 +350,7 @@
 			vout->vrfb_context[0].bytespp) +
 			(vout->vrfb_context[0].xoffset *
 			vout->vrfb_context[0].bytespp));
-		if (mirroring == 0) {
+		if (!mirroring) {
 			*cropped_offset = offset + (line_length * ps * ctop) +
 				(cleft / vr_ps) * ps;
 
@@ -364,7 +364,7 @@
 		offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset *
 			vout->vrfb_context[0].bytespp;
 		temp_ps = ps / vr_ps;
-		if (mirroring == 0) {
+		if (!mirroring) {
 			*cropped_offset = offset + line_length *
 			    temp_ps * crop->left + ctop * ps;
 		} else {
@@ -375,7 +375,7 @@
 		}
 		break;
 	case dss_rotation_0_degree:
-		if (mirroring == 0) {
+		if (!mirroring) {
 			*cropped_offset = (line_length * ps) *
 				crop->top + (crop->left / vr_ps) * ps;
 		} else {
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.h b/drivers/media/platform/omap/omap_vout_vrfb.h
index 993d685..ce06cb1 100644
--- a/drivers/media/platform/omap/omap_vout_vrfb.h
+++ b/drivers/media/platform/omap/omap_vout_vrfb.h
@@ -23,18 +23,18 @@
 			struct videobuf_buffer *vb);
 void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout);
 #else
-void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }
-int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
+static inline void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { };
+static inline int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
 			u32 static_vrfb_allocation)
-		{ return 0; }
-void omap_vout_release_vrfb(struct omap_vout_device *vout) { }
-int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+		{ return 0; };
+static inline void omap_vout_release_vrfb(struct omap_vout_device *vout) { };
+static inline int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
 			unsigned int *count, unsigned int startindex)
-		{ return 0; }
-int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
+		{ return 0; };
+static inline int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
 			struct videobuf_buffer *vb)
-		{ return 0; }
-void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { }
+		{ return 0; };
+static inline void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { };
 #endif
 
 #endif
diff --git a/drivers/media/platform/omap3isp/cfa_coef_table.h b/drivers/media/platform/omap3isp/cfa_coef_table.h
index c84df07..e75b0eb 100644
--- a/drivers/media/platform/omap3isp/cfa_coef_table.h
+++ b/drivers/media/platform/omap3isp/cfa_coef_table.h
@@ -11,16 +11,6 @@
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 { 244, 0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
diff --git a/drivers/media/platform/omap3isp/gamma_table.h b/drivers/media/platform/omap3isp/gamma_table.h
index 78deebf..3b50707 100644
--- a/drivers/media/platform/omap3isp/gamma_table.h
+++ b/drivers/media/platform/omap3isp/gamma_table.h
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
   0,   0,   1,   2,   3,   3,   4,   5,   6,   8,  10,  12,  14,  16,  18,  20,
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 2c7aa67..72265e5 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -40,16 +40,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <asm/cacheflush.h>
@@ -999,16 +989,14 @@
 					 video, s_stream, 0);
 		}
 
-		v4l2_subdev_call(subdev, video, s_stream, 0);
+		ret = v4l2_subdev_call(subdev, video, s_stream, 0);
 
 		if (subdev == &isp->isp_res.subdev)
-			ret = isp_pipeline_wait(isp, isp_pipeline_wait_resizer);
+			ret |= isp_pipeline_wait(isp, isp_pipeline_wait_resizer);
 		else if (subdev == &isp->isp_prev.subdev)
-			ret = isp_pipeline_wait(isp, isp_pipeline_wait_preview);
+			ret |= isp_pipeline_wait(isp, isp_pipeline_wait_preview);
 		else if (subdev == &isp->isp_ccdc.subdev)
-			ret = isp_pipeline_wait(isp, isp_pipeline_wait_ccdc);
-		else
-			ret = 0;
+			ret |= isp_pipeline_wait(isp, isp_pipeline_wait_ccdc);
 
 		/* Handle stop failures. An entity that fails to stop can
 		 * usually just be restarted. Flag the stop failure nonetheless
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
index 2c314ee..cfdfc87 100644
--- a/drivers/media/platform/omap3isp/isp.h
+++ b/drivers/media/platform/omap3isp/isp.h
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_CORE_H
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 9f727d2..81a9dc0 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/module.h>
@@ -491,14 +481,13 @@
 static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc)
 {
 	unsigned long flags;
+	int ret;
 
 	spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
-	if (ccdc->lsc.active) {
-		spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
-		return 1;
-	}
+	ret = ccdc->lsc.active != NULL;
 	spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
-	return 0;
+
+	return ret;
 }
 
 static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc)
@@ -818,29 +807,48 @@
 	struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
 	struct isp_device *isp = to_isp_device(ccdc);
 	const struct isp_format_info *info;
+	struct v4l2_mbus_framefmt *format;
 	unsigned long l3_ick = pipe->l3_ick;
 	unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8;
 	unsigned int div = 0;
-	u32 fmtcfg_vp;
+	u32 fmtcfg = ISPCCDC_FMTCFG_VPEN;
 
-	fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG)
-		  & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK);
+	format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
+
+	if (!format->code) {
+		/* Disable the video port when the input format isn't supported.
+		 * This is indicated by a pixel code set to 0.
+		 */
+		isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
+		return;
+	}
+
+	isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
+		       (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);
+	isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
+		       ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);
+
+	isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
+		       (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
 
 	info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code);
 
 	switch (info->width) {
 	case 8:
 	case 10:
-		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
+		fmtcfg |= ISPCCDC_FMTCFG_VPIN_9_0;
 		break;
 	case 11:
-		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
+		fmtcfg |= ISPCCDC_FMTCFG_VPIN_10_1;
 		break;
 	case 12:
-		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
+		fmtcfg |= ISPCCDC_FMTCFG_VPIN_11_2;
 		break;
 	case 13:
-		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
+		fmtcfg |= ISPCCDC_FMTCFG_VPIN_12_3;
 		break;
 	}
 
@@ -850,75 +858,59 @@
 		div = l3_ick / pipe->external_rate;
 
 	div = clamp(div, 2U, max_div);
-	fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
+	fmtcfg |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
 
-	isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
-}
-
-/*
- * ccdc_enable_vp - Enable Video Port.
- * @ccdc: Pointer to ISP CCDC device.
- * @enable: 0 Disables VP, 1 Enables VP
- *
- * This is needed for outputting image to Preview, H3A and HIST ISP submodules.
- */
-static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable)
-{
-	struct isp_device *isp = to_isp_device(ccdc);
-
-	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
-			ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0);
+	isp_reg_writel(isp, fmtcfg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
 }
 
 /*
  * ccdc_config_outlineoffset - Configure memory saving output line offset
  * @ccdc: Pointer to ISP CCDC device.
- * @offset: Address offset to start a new line. Must be twice the
- *          Output width and aligned on 32 byte boundary
- * @oddeven: Specifies the odd/even line pattern to be chosen to store the
- *           output.
- * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
+ * @bpl: Number of bytes per line when stored in memory.
+ * @field: Field order when storing interlaced formats in memory.
  *
- * - Configures the output line offset when stored in memory
- * - Sets the odd/even line pattern to store the output
- *    (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
- * - Configures the number of even and odd line fields in case of rearranging
- * the lines.
+ * Configure the offsets for the line output control:
+ *
+ * - The horizontal line offset is defined as the number of bytes between the
+ *   start of two consecutive lines in memory. Set it to the given bytes per
+ *   line value.
+ *
+ * - The field offset value is defined as the number of lines to offset the
+ *   start of the field identified by FID = 1. Set it to one.
+ *
+ * - The line offset values are defined as the number of lines (as defined by
+ *   the horizontal line offset) between the start of two consecutive lines for
+ *   all combinations of odd/even lines in odd/even fields. When interleaving
+ *   fields set them all to two lines, and to one line otherwise.
  */
 static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc,
-					u32 offset, u8 oddeven, u8 numlines)
+				      unsigned int bpl,
+				      enum v4l2_field field)
 {
 	struct isp_device *isp = to_isp_device(ccdc);
+	u32 sdofst = 0;
 
-	isp_reg_writel(isp, offset & 0xffff,
-		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF);
+	isp_reg_writel(isp, bpl & 0xffff, OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_HSIZE_OFF);
 
-	isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-		    ISPCCDC_SDOFST_FINV);
+	switch (field) {
+	case V4L2_FIELD_INTERLACED_TB:
+	case V4L2_FIELD_INTERLACED_BT:
+		/* When interleaving fields in memory offset field one by one
+		 * line and set the line offset to two lines.
+		 */
+		sdofst |= (1 << ISPCCDC_SDOFST_LOFST0_SHIFT)
+		       |  (1 << ISPCCDC_SDOFST_LOFST1_SHIFT)
+		       |  (1 << ISPCCDC_SDOFST_LOFST2_SHIFT)
+		       |  (1 << ISPCCDC_SDOFST_LOFST3_SHIFT);
+		break;
 
-	isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-		    ISPCCDC_SDOFST_FOFST_4L);
-
-	switch (oddeven) {
-	case EVENEVEN:
-		isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-			    (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
-		break;
-	case ODDEVEN:
-		isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-			    (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
-		break;
-	case EVENODD:
-		isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-			    (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
-		break;
-	case ODDODD:
-		isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-			    (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
-		break;
 	default:
+		/* In all other cases set the line offsets to one line. */
 		break;
 	}
+
+	isp_reg_writel(isp, sdofst, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST);
 }
 
 /*
@@ -981,10 +973,16 @@
 
 	if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
 	    format->code == V4L2_MBUS_FMT_UYVY8_2X8) {
-		/* The bridge is enabled for YUV8 formats. Configure the input
-		 * mode accordingly.
+		/* According to the OMAP3 TRM the input mode only affects SYNC
+		 * mode, enabling BT.656 mode should take precedence. However,
+		 * in practice setting the input mode to YCbCr data on 8 bits
+		 * seems to be required in BT.656 mode. In SYNC mode set it to
+		 * YCbCr on 16 bits as the bridge is enabled in that case.
 		 */
-		syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16;
+		if (ccdc->bt656)
+			syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR8;
+		else
+			syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16;
 	}
 
 	switch (data_size) {
@@ -1008,9 +1006,15 @@
 	if (pdata && pdata->hs_pol)
 		syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
 
-	if (pdata && pdata->vs_pol)
+	/* The polarity of the vertical sync signal output by the BT.656
+	 * decoder is not documented and seems to be active low.
+	 */
+	if ((pdata && pdata->vs_pol) || ccdc->bt656)
 		syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
 
+	if (pdata && pdata->fld_pol)
+		syn_mode |= ISPCCDC_SYN_MODE_FLDPOL;
+
 	isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
 
 	/* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The
@@ -1023,8 +1027,16 @@
 		isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
 			    ISPCCDC_CFG_Y8POS);
 
-	isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
-		    ISPCCDC_REC656IF_R656ON);
+	/* Enable or disable BT.656 mode, including error correction for the
+	 * synchronization codes.
+	 */
+	if (ccdc->bt656)
+		isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
+			    ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH);
+	else
+		isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
+			    ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH);
+
 }
 
 /* CCDC formats descriptions */
@@ -1115,17 +1127,33 @@
 	unsigned long flags;
 	unsigned int bridge;
 	unsigned int shift;
+	unsigned int nph;
+	unsigned int sph;
 	u32 syn_mode;
 	u32 ccdc_pattern;
 
+	ccdc->bt656 = false;
+	ccdc->fields = 0;
+
 	pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]);
 	sensor = media_entity_to_v4l2_subdev(pad->entity);
-	if (ccdc->input == CCDC_INPUT_PARALLEL)
+	if (ccdc->input == CCDC_INPUT_PARALLEL) {
+		struct v4l2_mbus_config cfg;
+		int ret;
+
+		ret = v4l2_subdev_call(sensor, video, g_mbus_config, &cfg);
+		if (!ret)
+			ccdc->bt656 = cfg.type == V4L2_MBUS_BT656;
+
 		pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
 			->bus.parallel;
+	}
+
+	/* CCDC_PAD_SINK */
+	format = &ccdc->formats[CCDC_PAD_SINK];
 
 	/* Compute the lane shifter shift value and enable the bridge when the
-	 * input format is YUV.
+	 * input format is a non-BT.656 YUV variant.
 	 */
 	fmt_src.pad = pad->index;
 	fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
@@ -1134,12 +1162,13 @@
 		depth_in = fmt_info->width;
 	}
 
-	fmt_info = omap3isp_video_format_info
-		(isp->isp_ccdc.formats[CCDC_PAD_SINK].code);
+	fmt_info = omap3isp_video_format_info(format->code);
 	depth_out = fmt_info->width;
 	shift = depth_in - depth_out;
 
-	if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8)
+	if (ccdc->bt656)
+		bridge = ISPCTRL_PAR_BRIDGE_DISABLE;
+	else if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8)
 		bridge = ISPCTRL_PAR_BRIDGE_LENDIAN;
 	else if (fmt_info->code == V4L2_MBUS_FMT_UYVY8_2X8)
 		bridge = ISPCTRL_PAR_BRIDGE_BENDIAN;
@@ -1148,6 +1177,7 @@
 
 	omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge);
 
+	/* Configure the sync interface. */
 	ccdc_config_sync_if(ccdc, pdata, depth_out);
 
 	syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
@@ -1167,9 +1197,6 @@
 	else
 		syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
 
-	/* CCDC_PAD_SINK */
-	format = &ccdc->formats[CCDC_PAD_SINK];
-
 	/* Mosaic filter */
 	switch (format->code) {
 	case V4L2_MBUS_FMT_SRGGB10_1X10:
@@ -1202,16 +1229,40 @@
 	format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
 	crop = &ccdc->crop;
 
-	isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
-		       ((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
+	/* The horizontal coordinates are expressed in pixel clock cycles. We
+	 * need two cycles per pixel in BT.656 mode, and one cycle per pixel in
+	 * SYNC mode regardless of the format as the bridge is enabled for YUV
+	 * formats in that case.
+	 */
+	if (ccdc->bt656) {
+		sph = crop->left * 2;
+		nph = crop->width * 2 - 1;
+	} else {
+		sph = crop->left;
+		nph = crop->width - 1;
+	}
+
+	isp_reg_writel(isp, (sph << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
+		       (nph << ISPCCDC_HORZ_INFO_NPH_SHIFT),
 		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
-	isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT,
+	isp_reg_writel(isp, (crop->top << ISPCCDC_VERT_START_SLV0_SHIFT) |
+		       (crop->top << ISPCCDC_VERT_START_SLV1_SHIFT),
 		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
 	isp_reg_writel(isp, (crop->height - 1)
 			<< ISPCCDC_VERT_LINES_NLV_SHIFT,
 		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);
 
-	ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0);
+	ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value,
+				  format->field);
+
+	/* When interleaving fields enable processing of the field input signal.
+	 * This will cause the line output control module to apply the field
+	 * offset to field 1.
+	 */
+	if (ccdc->formats[CCDC_PAD_SINK].field == V4L2_FIELD_ALTERNATE &&
+	    (format->field == V4L2_FIELD_INTERLACED_TB ||
+	     format->field == V4L2_FIELD_INTERLACED_BT))
+		syn_mode |= ISPCCDC_SYN_MODE_FLDMODE;
 
 	/* The CCDC outputs data in UYVY order by default. Swap bytes to get
 	 * YUYV.
@@ -1223,8 +1274,11 @@
 		isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
 			    ISPCCDC_CFG_BSWD);
 
-	/* Use PACK8 mode for 1byte per pixel formats. */
-	if (omap3isp_video_format_info(format->code)->width <= 8)
+	/* Use PACK8 mode for 1byte per pixel formats. Check for BT.656 mode
+	 * explicitly as the driver reports 1X16 instead of 2X8 at the OF pad
+	 * for simplicity.
+	 */
+	if (omap3isp_video_format_info(format->code)->width <= 8 || ccdc->bt656)
 		syn_mode |= ISPCCDC_SYN_MODE_PACK8;
 	else
 		syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;
@@ -1232,18 +1286,7 @@
 	isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
 
 	/* CCDC_PAD_SOURCE_VP */
-	format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
-
-	isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
-		       (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
-		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);
-	isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
-		       ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
-		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);
-
-	isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
-		       (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
-		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
+	ccdc_config_vp(ccdc);
 
 	/* Lens shading correction. */
 	spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
@@ -1277,6 +1320,8 @@
 
 	isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
 			ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
+
+	ccdc->running = enable;
 }
 
 static int ccdc_disable(struct isp_ccdc_device *ccdc)
@@ -1287,6 +1332,8 @@
 	spin_lock_irqsave(&ccdc->lock, flags);
 	if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS)
 		ccdc->stopping = CCDC_STOP_REQUEST;
+	if (!ccdc->running)
+		ccdc->stopping = CCDC_STOP_FINISHED;
 	spin_unlock_irqrestore(&ccdc->lock, flags);
 
 	ret = wait_event_timeout(ccdc->wait,
@@ -1369,14 +1416,14 @@
 	return -EBUSY;
 }
 
-/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence
+/* ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence
  * @ccdc: Pointer to ISP CCDC device.
  * @event: Pointing which event trigger handler
  *
  * Return 1 when the event and stopping request combination is satisfied,
  * zero otherwise.
  */
-static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
+static int ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
 {
 	int rval = 0;
 
@@ -1458,7 +1505,7 @@
 	if (ccdc->lsc.state == LSC_STATE_STOPPING)
 		ccdc->lsc.state = LSC_STATE_STOPPED;
 
-	if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))
+	if (ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))
 		goto done;
 
 	if (ccdc->lsc.state != LSC_STATE_RECONFIG)
@@ -1486,12 +1533,59 @@
 	spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
 }
 
+/*
+ * Check whether the CCDC has captured all fields necessary to complete the
+ * buffer.
+ */
+static bool ccdc_has_all_fields(struct isp_ccdc_device *ccdc)
+{
+	struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+	struct isp_device *isp = to_isp_device(ccdc);
+	enum v4l2_field of_field = ccdc->formats[CCDC_PAD_SOURCE_OF].field;
+	enum v4l2_field field;
+
+	/* When the input is progressive fields don't matter. */
+	if (of_field == V4L2_FIELD_NONE)
+		return true;
+
+	/* Read the current field identifier. */
+	field = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE)
+	      & ISPCCDC_SYN_MODE_FLDSTAT
+	      ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;
+
+	/* When capturing fields in alternate order just store the current field
+	 * identifier in the pipeline.
+	 */
+	if (of_field == V4L2_FIELD_ALTERNATE) {
+		pipe->field = field;
+		return true;
+	}
+
+	/* The format is interlaced. Make sure we've captured both fields. */
+	ccdc->fields |= field == V4L2_FIELD_BOTTOM
+		      ? CCDC_FIELD_BOTTOM : CCDC_FIELD_TOP;
+
+	if (ccdc->fields != CCDC_FIELD_BOTH)
+		return false;
+
+	/* Verify that the field just captured corresponds to the last field
+	 * needed based on the desired field order.
+	 */
+	if ((of_field == V4L2_FIELD_INTERLACED_TB && field == V4L2_FIELD_TOP) ||
+	    (of_field == V4L2_FIELD_INTERLACED_BT && field == V4L2_FIELD_BOTTOM))
+		return false;
+
+	/* The buffer can be completed, reset the fields for the next buffer. */
+	ccdc->fields = 0;
+
+	return true;
+}
+
 static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
 {
 	struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
 	struct isp_device *isp = to_isp_device(ccdc);
 	struct isp_buffer *buffer;
-	int restart = 0;
 
 	/* The CCDC generates VD0 interrupts even when disabled (the datasheet
 	 * doesn't explicitly state if that's supposed to happen or not, so it
@@ -1500,30 +1594,31 @@
 	 * would thus not be enough, we need to handle the situation explicitly.
 	 */
 	if (list_empty(&ccdc->video_out.dmaqueue))
-		goto done;
+		return 0;
 
 	/* We're in continuous mode, and memory writes were disabled due to a
 	 * buffer underrun. Reenable them now that we have a buffer. The buffer
 	 * address has been set in ccdc_video_queue.
 	 */
 	if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) {
-		restart = 1;
 		ccdc->underrun = 0;
-		goto done;
+		return 1;
 	}
 
+	/* Wait for the CCDC to become idle. */
 	if (ccdc_sbl_wait_idle(ccdc, 1000)) {
 		dev_info(isp->dev, "CCDC won't become idle!\n");
 		isp->crashed |= 1U << ccdc->subdev.entity.id;
 		omap3isp_pipeline_cancel_stream(pipe);
-		goto done;
+		return 0;
 	}
 
+	if (!ccdc_has_all_fields(ccdc))
+		return 1;
+
 	buffer = omap3isp_video_buffer_next(&ccdc->video_out);
-	if (buffer != NULL) {
+	if (buffer != NULL)
 		ccdc_set_outaddr(ccdc, buffer->dma);
-		restart = 1;
-	}
 
 	pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
 
@@ -1532,8 +1627,7 @@
 		omap3isp_pipeline_set_stream(pipe,
 					ISP_PIPELINE_STREAM_SINGLESHOT);
 
-done:
-	return restart;
+	return buffer != NULL;
 }
 
 /*
@@ -1547,11 +1641,38 @@
 	unsigned long flags;
 	int restart = 0;
 
+	/* In BT.656 mode the CCDC doesn't generate an HS/VS interrupt. We thus
+	 * need to increment the frame counter here.
+	 */
+	if (ccdc->bt656) {
+		struct isp_pipeline *pipe =
+			to_isp_pipeline(&ccdc->subdev.entity);
+
+		atomic_inc(&pipe->frame_number);
+	}
+
+	/* Emulate a VD1 interrupt for BT.656 mode, as we can't stop the CCDC in
+	 * the VD1 interrupt handler in that mode without risking a CCDC stall
+	 * if a short frame is received.
+	 */
+	if (ccdc->bt656) {
+		spin_lock_irqsave(&ccdc->lock, flags);
+		if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
+		    ccdc->output & CCDC_OUTPUT_MEMORY) {
+			if (ccdc->lsc.state != LSC_STATE_STOPPED)
+				__ccdc_lsc_enable(ccdc, 0);
+			__ccdc_enable(ccdc, 0);
+		}
+		ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1);
+		spin_unlock_irqrestore(&ccdc->lock, flags);
+	}
+
 	if (ccdc->output & CCDC_OUTPUT_MEMORY)
 		restart = ccdc_isr_buffer(ccdc);
 
 	spin_lock_irqsave(&ccdc->lock, flags);
-	if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
+
+	if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
 		spin_unlock_irqrestore(&ccdc->lock, flags);
 		return;
 	}
@@ -1572,6 +1693,18 @@
 {
 	unsigned long flags;
 
+	/* In BT.656 mode the synchronization signals are generated by the CCDC
+	 * from the embedded sync codes. The VD0 and VD1 interrupts are thus
+	 * only triggered when the CCDC is enabled, unlike external sync mode
+	 * where the line counter runs even when the CCDC is stopped. We can't
+	 * disable the CCDC at VD1 time, as no VD0 interrupt would be generated
+	 * for a short frame, which would result in the CCDC being stopped and
+	 * no VD interrupt generated anymore. The CCDC is stopped from the VD0
+	 * interrupt handler instead for BT.656.
+	 */
+	if (ccdc->bt656)
+		return;
+
 	spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
 
 	/*
@@ -1601,7 +1734,7 @@
 		break;
 	}
 
-	if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))
+	if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))
 		goto done;
 
 	if (ccdc->lsc.request == NULL)
@@ -1656,6 +1789,8 @@
 static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
 {
 	struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc;
+	unsigned long flags;
+	bool restart = false;
 
 	if (!(ccdc->output & CCDC_OUTPUT_MEMORY))
 		return -ENODEV;
@@ -1664,9 +1799,20 @@
 
 	/* We now have a buffer queued on the output, restart the pipeline
 	 * on the next CCDC interrupt if running in continuous mode (or when
-	 * starting the stream).
+	 * starting the stream) in external sync mode, or immediately in BT.656
+	 * sync mode as no CCDC interrupt is generated when the CCDC is stopped
+	 * in that case.
 	 */
-	ccdc->underrun = 1;
+	spin_lock_irqsave(&ccdc->lock, flags);
+	if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && !ccdc->running &&
+	    ccdc->bt656)
+		restart = true;
+	else
+		ccdc->underrun = 1;
+	spin_unlock_irqrestore(&ccdc->lock, flags);
+
+	if (restart)
+		ccdc_enable(ccdc);
 
 	return 0;
 }
@@ -1753,11 +1899,6 @@
 
 		ccdc_configure(ccdc);
 
-		/* TODO: Don't configure the video port if all of its output
-		 * links are inactive.
-		 */
-		ccdc_config_vp(ccdc);
-		ccdc_enable_vp(ccdc, 1);
 		ccdc_print_status(ccdc);
 	}
 
@@ -1830,6 +1971,7 @@
 	unsigned int width = fmt->width;
 	unsigned int height = fmt->height;
 	struct v4l2_rect *crop;
+	enum v4l2_field field;
 	unsigned int i;
 
 	switch (pad) {
@@ -1846,14 +1988,24 @@
 		/* Clamp the input size. */
 		fmt->width = clamp_t(u32, width, 32, 4096);
 		fmt->height = clamp_t(u32, height, 32, 4096);
+
+		/* Default to progressive field order. */
+		if (fmt->field == V4L2_FIELD_ANY)
+			fmt->field = V4L2_FIELD_NONE;
+
 		break;
 
 	case CCDC_PAD_SOURCE_OF:
 		pixelcode = fmt->code;
+		field = fmt->field;
 		*fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
 
-		/* YUV formats are converted from 2X8 to 1X16 by the bridge and
-		 * can be byte-swapped.
+		/* In SYNC mode the bridge converts YUV formats from 2X8 to
+		 * 1X16. In BT.656 no such conversion occurs. As we don't know
+		 * at this point whether the source will use SYNC or BT.656 mode
+		 * let's pretend the conversion always occurs. The CCDC will be
+		 * configured to pack bytes in BT.656, hiding the inaccuracy.
+		 * In all cases bytes can be swapped.
 		 */
 		if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
 		    fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) {
@@ -1874,6 +2026,17 @@
 		crop = __ccdc_get_crop(ccdc, fh, which);
 		fmt->width = crop->width;
 		fmt->height = crop->height;
+
+		/* When input format is interlaced with alternating fields the
+		 * CCDC can interleave the fields.
+		 */
+		if (fmt->field == V4L2_FIELD_ALTERNATE &&
+		    (field == V4L2_FIELD_INTERLACED_TB ||
+		     field == V4L2_FIELD_INTERLACED_BT)) {
+			fmt->field = field;
+			fmt->height *= 2;
+		}
+
 		break;
 
 	case CCDC_PAD_SOURCE_VP:
@@ -1901,7 +2064,6 @@
 	 * stored on 2 bytes.
 	 */
 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
-	fmt->field = V4L2_FIELD_NONE;
 }
 
 /*
diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h
index f650616..3440a70 100644
--- a/drivers/media/platform/omap3isp/ispccdc.h
+++ b/drivers/media/platform/omap3isp/ispccdc.h
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_CCDC_H
@@ -103,6 +93,10 @@
 #define CCDC_PAD_SOURCE_VP		2
 #define CCDC_PADS_NUM			3
 
+#define CCDC_FIELD_TOP			1
+#define CCDC_FIELD_BOTTOM		2
+#define CCDC_FIELD_BOTH			3
+
 /*
  * struct isp_ccdc_device - Structure for the CCDC module to store its own
  *			    information
@@ -123,11 +117,14 @@
  * @lsc: Lens shading compensation configuration
  * @update: Bitmask of controls to update during the next interrupt
  * @shadow_update: Controls update in progress by userspace
+ * @bt656: Whether the input interface uses BT.656 synchronization
+ * @fields: The fields (CCDC_FIELD_*) stored in the current buffer
  * @underrun: A buffer underrun occurred and a new buffer has been queued
  * @state: Streaming state
  * @lock: Serializes shadow_update with interrupt handler
  * @wait: Wait queue used to stop the module
  * @stopping: Stopping state
+ * @running: Is the CCDC hardware running
  * @ioctl_lock: Serializes ioctl calls and LSC requests freeing
  */
 struct isp_ccdc_device {
@@ -151,11 +148,15 @@
 	unsigned int update;
 	unsigned int shadow_update;
 
+	bool bt656;
+	unsigned int fields;
+
 	unsigned int underrun:1;
 	enum isp_pipeline_stream_state state;
 	spinlock_t lock;
 	wait_queue_head_t wait;
 	unsigned int stopping;
+	bool running;
 	struct mutex ioctl_lock;
 };
 
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index f3801db..9cb49b3 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/delay.h>
diff --git a/drivers/media/platform/omap3isp/ispccp2.h b/drivers/media/platform/omap3isp/ispccp2.h
index 76d65f4..4662bff 100644
--- a/drivers/media/platform/omap3isp/ispccp2.h
+++ b/drivers/media/platform/omap3isp/ispccp2.h
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_CCP2_H
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
index 5a2e47e..6530b25 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 #include <linux/delay.h>
 #include <media/v4l2-common.h>
diff --git a/drivers/media/platform/omap3isp/ispcsi2.h b/drivers/media/platform/omap3isp/ispcsi2.h
index c57729b..453ed62 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.h
+++ b/drivers/media/platform/omap3isp/ispcsi2.h
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_CSI2_H
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c
index c09de32..e033f22 100644
--- a/drivers/media/platform/omap3isp/ispcsiphy.c
+++ b/drivers/media/platform/omap3isp/ispcsiphy.c
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/delay.h>
diff --git a/drivers/media/platform/omap3isp/ispcsiphy.h b/drivers/media/platform/omap3isp/ispcsiphy.h
index 14551fd..e17c88b 100644
--- a/drivers/media/platform/omap3isp/ispcsiphy.h
+++ b/drivers/media/platform/omap3isp/ispcsiphy.h
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_CSI_PHY_H
diff --git a/drivers/media/platform/omap3isp/isph3a.h b/drivers/media/platform/omap3isp/isph3a.h
index fb09fd4..e5b28d0 100644
--- a/drivers/media/platform/omap3isp/isph3a.h
+++ b/drivers/media/platform/omap3isp/isph3a.h
@@ -13,16 +13,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_H3A_H
diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c
index d6811ce..b208c54 100644
--- a/drivers/media/platform/omap3isp/isph3a_aewb.c
+++ b/drivers/media/platform/omap3isp/isph3a_aewb.c
@@ -13,16 +13,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/slab.h>
diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c
index 6fc960c..8a83e19 100644
--- a/drivers/media/platform/omap3isp/isph3a_af.c
+++ b/drivers/media/platform/omap3isp/isph3a_af.c
@@ -13,16 +13,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 /* Linux specific include files */
diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c
index 06a5f81..ce822c3 100644
--- a/drivers/media/platform/omap3isp/isphist.c
+++ b/drivers/media/platform/omap3isp/isphist.c
@@ -13,16 +13,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/delay.h>
diff --git a/drivers/media/platform/omap3isp/isphist.h b/drivers/media/platform/omap3isp/isphist.h
index 0b2a38e..3b54155 100644
--- a/drivers/media/platform/omap3isp/isphist.h
+++ b/drivers/media/platform/omap3isp/isphist.h
@@ -13,16 +13,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_HIST_H
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
index 720809b..605f57e 100644
--- a/drivers/media/platform/omap3isp/isppreview.c
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/device.h>
diff --git a/drivers/media/platform/omap3isp/isppreview.h b/drivers/media/platform/omap3isp/isppreview.h
index f669234..16fdc03 100644
--- a/drivers/media/platform/omap3isp/isppreview.h
+++ b/drivers/media/platform/omap3isp/isppreview.h
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_PREVIEW_H
diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h
index b7d90e6..b5ea8da 100644
--- a/drivers/media/platform/omap3isp/ispreg.h
+++ b/drivers/media/platform/omap3isp/ispreg.h
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_REG_H
@@ -740,17 +730,13 @@
 
 #define ISPCCDC_HSIZE_OFF_SHIFT			0
 
-#define ISPCCDC_SDOFST_FINV			(1 << 14)
-#define ISPCCDC_SDOFST_FOFST_1L			0
-#define ISPCCDC_SDOFST_FOFST_4L			(3 << 12)
+#define ISPCCDC_SDOFST_FIINV			(1 << 14)
+#define ISPCCDC_SDOFST_FOFST_SHIFT		12
+#define ISPCCDC_SDOFST_FOFST_MASK		(3 << 12)
 #define ISPCCDC_SDOFST_LOFST3_SHIFT		0
 #define ISPCCDC_SDOFST_LOFST2_SHIFT		3
 #define ISPCCDC_SDOFST_LOFST1_SHIFT		6
 #define ISPCCDC_SDOFST_LOFST0_SHIFT		9
-#define EVENEVEN				1
-#define ODDEVEN					2
-#define EVENODD					3
-#define ODDODD					4
 
 #define ISPCCDC_CLAMP_OBGAIN_SHIFT		0
 #define ISPCCDC_CLAMP_OBST_SHIFT		10
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c
index 6f077c2..05d1ace 100644
--- a/drivers/media/platform/omap3isp/ispresizer.c
+++ b/drivers/media/platform/omap3isp/ispresizer.c
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/device.h>
@@ -239,7 +229,7 @@
 			      u32 v_phase)
 {
 	struct isp_device *isp = to_isp_device(res);
-	u32 rgval = 0;
+	u32 rgval;
 
 	rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
 	      ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
@@ -275,7 +265,7 @@
 			     struct resizer_luma_yenh *luma)
 {
 	struct isp_device *isp = to_isp_device(res);
-	u32 rgval = 0;
+	u32 rgval;
 
 	rgval  = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT)
 		  & ISPRSZ_YENH_ALGO_MASK;
@@ -322,7 +312,7 @@
 {
 	struct isp_device *isp = to_isp_device(res);
 	const u16 *h_filter, *v_filter;
-	u32 rgval = 0;
+	u32 rgval;
 
 	rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
 			      ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
@@ -365,9 +355,8 @@
 				    u32 width, u32 height)
 {
 	struct isp_device *isp = to_isp_device(res);
-	u32 rgval = 0;
+	u32 rgval;
 
-	dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height);
 	rgval  = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
 		 & ISPRSZ_OUT_SIZE_HORZ_MASK;
 	rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
@@ -409,7 +398,7 @@
 static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
 {
 	struct isp_device *isp = to_isp_device(res);
-	u32 rgval = 0;
+	u32 rgval;
 
 	rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT)
 		& ISPRSZ_IN_START_HORZ_ST_MASK;
@@ -429,9 +418,7 @@
 				   u32 width, u32 height)
 {
 	struct isp_device *isp = to_isp_device(res);
-	u32 rgval = 0;
-
-	dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height);
+	u32 rgval;
 
 	rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT)
 		& ISPRSZ_IN_SIZE_HORZ_MASK;
@@ -1075,10 +1062,13 @@
 void omap3isp_resizer_isr(struct isp_res_device *res)
 {
 	struct v4l2_mbus_framefmt *informat, *outformat;
+	unsigned long flags;
 
 	if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
 		return;
 
+	spin_lock_irqsave(&res->lock, flags);
+
 	if (res->applycrop) {
 		outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
 					      V4L2_SUBDEV_FORMAT_ACTIVE);
@@ -1088,6 +1078,8 @@
 		res->applycrop = 0;
 	}
 
+	spin_unlock_irqrestore(&res->lock, flags);
+
 	resizer_isr_buffer(res);
 }
 
@@ -1290,8 +1282,10 @@
 {
 	struct isp_res_device *res = v4l2_get_subdevdata(sd);
 	struct isp_device *isp = to_isp_device(res);
-	struct v4l2_mbus_framefmt *format_sink, *format_source;
+	const struct v4l2_mbus_framefmt *format_sink;
+	struct v4l2_mbus_framefmt format_source;
 	struct resizer_ratio ratio;
+	unsigned long flags;
 
 	if (sel->target != V4L2_SEL_TGT_CROP ||
 	    sel->pad != RESZ_PAD_SINK)
@@ -1299,16 +1293,14 @@
 
 	format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
 					   sel->which);
-	format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
-					     sel->which);
+	format_source = *__resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+					      sel->which);
 
-	dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
-		sel->r.left, sel->r.top, sel->r.width, sel->r.height,
-		sel->which);
-
-	dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
+	dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
+		__func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act",
 		format_sink->width, format_sink->height,
-		format_source->width, format_source->height);
+		sel->r.left, sel->r.top, sel->r.width, sel->r.height,
+		format_source.width, format_source.height);
 
 	/* Clamp the crop rectangle to the bounds, and then mangle it further to
 	 * fulfill the TRM equations. Store the clamped but otherwise unmangled
@@ -1318,23 +1310,39 @@
 	 * smaller input crop rectangle every time the output size is set if we
 	 * stored the mangled rectangle.
 	 */
-	resizer_try_crop(format_sink, format_source, &sel->r);
+	resizer_try_crop(format_sink, &format_source, &sel->r);
 	*__resizer_get_crop(res, fh, sel->which) = sel->r;
-	resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+	resizer_calc_ratios(res, &sel->r, &format_source, &ratio);
 
-	if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
+	dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n",
+		__func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act",
+		format_sink->width, format_sink->height,
+		sel->r.left, sel->r.top, sel->r.width, sel->r.height,
+		format_source.width, format_source.height);
+
+	if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+		*__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) =
+			format_source;
 		return 0;
+	}
+
+	/* Update the source format, resizing ratios and crop rectangle. If
+	 * streaming is on the IRQ handler will reprogram the resizer after the
+	 * current frame. We thus we need to protect against race conditions.
+	 */
+	spin_lock_irqsave(&res->lock, flags);
+
+	*__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) =
+		format_source;
 
 	res->ratio = ratio;
 	res->crop.active = sel->r;
 
-	/*
-	 * set_selection can be called while streaming is on. In this case the
-	 * crop values will be set in the next IRQ.
-	 */
 	if (res->state != ISP_PIPELINE_STREAM_STOPPED)
 		res->applycrop = 1;
 
+	spin_unlock_irqrestore(&res->lock, flags);
+
 	return 0;
 }
 
@@ -1781,6 +1789,8 @@
 
 	init_waitqueue_head(&res->wait);
 	atomic_set(&res->stopping, 0);
+	spin_lock_init(&res->lock);
+
 	return resizer_init_entities(res);
 }
 
diff --git a/drivers/media/platform/omap3isp/ispresizer.h b/drivers/media/platform/omap3isp/ispresizer.h
index 9b01e90..5414542 100644
--- a/drivers/media/platform/omap3isp/ispresizer.h
+++ b/drivers/media/platform/omap3isp/ispresizer.h
@@ -12,21 +12,12 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_RESIZER_H
 #define OMAP3_ISP_RESIZER_H
 
+#include <linux/spinlock.h>
 #include <linux/types.h>
 
 /*
@@ -96,6 +87,7 @@
 
 /*
  * struct isp_res_device - OMAP3 ISP resizer module
+ * @lock: Protects formats and crop rectangles between set_selection and IRQ
  * @crop.request: Crop rectangle requested by the user
  * @crop.active: Active crop rectangle (based on hardware requirements)
  */
@@ -116,6 +108,7 @@
 	enum isp_pipeline_stream_state state;
 	wait_queue_head_t wait;
 	atomic_t stopping;
+	spinlock_t lock;
 
 	struct {
 		struct v4l2_rect request;
diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
index e6cbc1e..a94e834 100644
--- a/drivers/media/platform/omap3isp/ispstat.c
+++ b/drivers/media/platform/omap3isp/ispstat.c
@@ -13,16 +13,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/dma-mapping.h>
diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h
index 58d6ac7..b32b296 100644
--- a/drivers/media/platform/omap3isp/ispstat.h
+++ b/drivers/media/platform/omap3isp/ispstat.h
@@ -13,16 +13,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_STAT_H
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index e36bac2..bc38c88 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -11,16 +11,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <asm/cacheflush.h>
@@ -319,10 +309,11 @@
 	    vfh->format.fmt.pix.height != format.fmt.pix.height ||
 	    vfh->format.fmt.pix.width != format.fmt.pix.width ||
 	    vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline ||
-	    vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage)
+	    vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage ||
+	    vfh->format.fmt.pix.field != format.fmt.pix.field)
 		return -EINVAL;
 
-	return ret;
+	return 0;
 }
 
 /* -----------------------------------------------------------------------------
@@ -491,6 +482,11 @@
 	else
 		buf->vb.v4l2_buf.sequence = atomic_read(&pipe->frame_number);
 
+	if (pipe->field != V4L2_FIELD_NONE)
+		buf->vb.v4l2_buf.sequence /= 2;
+
+	buf->vb.v4l2_buf.field = pipe->field;
+
 	/* Report pipeline errors to userspace on the capture device side. */
 	if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) {
 		state = VB2_BUF_STATE_ERROR;
@@ -641,7 +637,40 @@
 	if (format->type != video->type)
 		return -EINVAL;
 
-	mutex_lock(&video->mutex);
+	/* Replace unsupported field orders with sane defaults. */
+	switch (format->fmt.pix.field) {
+	case V4L2_FIELD_NONE:
+		/* Progressive is supported everywhere. */
+		break;
+	case V4L2_FIELD_ALTERNATE:
+		/* ALTERNATE is not supported on output nodes. */
+		if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			format->fmt.pix.field = V4L2_FIELD_NONE;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		/* The ISP has no concept of video standard, select the
+		 * top-bottom order when the unqualified interlaced order is
+		 * requested.
+		 */
+		format->fmt.pix.field = V4L2_FIELD_INTERLACED_TB;
+		/* Fall-through */
+	case V4L2_FIELD_INTERLACED_TB:
+	case V4L2_FIELD_INTERLACED_BT:
+		/* Interlaced orders are only supported at the CCDC output. */
+		if (video != &video->isp->isp_ccdc.video_out)
+			format->fmt.pix.field = V4L2_FIELD_NONE;
+		break;
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+	case V4L2_FIELD_SEQ_TB:
+	case V4L2_FIELD_SEQ_BT:
+	default:
+		/* All other field orders are currently unsupported, default to
+		 * progressive.
+		 */
+		format->fmt.pix.field = V4L2_FIELD_NONE;
+		break;
+	}
 
 	/* Fill the bytesperline and sizeimage fields by converting to media bus
 	 * format and back to pixel format.
@@ -649,9 +678,10 @@
 	isp_video_pix_to_mbus(&format->fmt.pix, &fmt);
 	isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
 
+	mutex_lock(&video->mutex);
 	vfh->format = *format;
-
 	mutex_unlock(&video->mutex);
+
 	return 0;
 }
 
@@ -1039,6 +1069,7 @@
 	video->queue = &vfh->queue;
 	INIT_LIST_HEAD(&video->dmaqueue);
 	atomic_set(&pipe->frame_number, -1);
+	pipe->field = vfh->format.fmt.pix.field;
 
 	mutex_lock(&video->queue_lock);
 	ret = vb2_streamon(&vfh->queue, type);
diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h
index 7d2e821..0b7efed 100644
--- a/drivers/media/platform/omap3isp/ispvideo.h
+++ b/drivers/media/platform/omap3isp/ispvideo.h
@@ -11,16 +11,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef OMAP3_ISP_VIDEO_H
@@ -88,6 +78,7 @@
 
 /*
  * struct isp_pipeline - An ISP hardware pipeline
+ * @field: The field being processed by the pipeline
  * @error: A hardware error occurred during capture
  * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
  */
@@ -101,6 +92,7 @@
 	u32 entities;
 	unsigned long l3_ick;
 	unsigned int max_rate;
+	enum v4l2_field field;
 	atomic_t frame_number;
 	bool do_propagation; /* of frame number */
 	bool error;
diff --git a/drivers/media/platform/omap3isp/luma_enhance_table.h b/drivers/media/platform/omap3isp/luma_enhance_table.h
index 098b45e..81c5b15 100644
--- a/drivers/media/platform/omap3isp/luma_enhance_table.h
+++ b/drivers/media/platform/omap3isp/luma_enhance_table.h
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
diff --git a/drivers/media/platform/omap3isp/noise_filter_table.h b/drivers/media/platform/omap3isp/noise_filter_table.h
index d50451a..5073f98 100644
--- a/drivers/media/platform/omap3isp/noise_filter_table.h
+++ b/drivers/media/platform/omap3isp/noise_filter_table.h
@@ -12,16 +12,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index f336413..4f81b4c 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -280,8 +280,8 @@
 		return -EINVAL;
 	}
 
-	pr_debug("DMA address: y: %#x  cb: %#x cr: %#x\n",
-		 paddr->y, paddr->cb, paddr->cr);
+	pr_debug("DMA address: y: %pad  cb: %pad cr: %pad\n",
+		 &paddr->y, &paddr->cb, &paddr->cr);
 
 	return 0;
 }
diff --git a/drivers/media/platform/s3c-camif/camif-regs.c b/drivers/media/platform/s3c-camif/camif-regs.c
index ebf5b18..6e0c998 100644
--- a/drivers/media/platform/s3c-camif/camif-regs.c
+++ b/drivers/media/platform/s3c-camif/camif-regs.c
@@ -214,8 +214,8 @@
 								paddr->cr);
 	}
 
-	pr_debug("dst_buf[%d]: %#X, cb: %#X, cr: %#X\n",
-		 i, paddr->y, paddr->cb, paddr->cr);
+	pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad\n",
+		 i, &paddr->y, &paddr->cb, &paddr->cr);
 }
 
 static void camif_hw_set_out_dma_size(struct camif_vp *vp)
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
index 357af1e..d79e214 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -490,14 +490,13 @@
 {
 	struct g2d_ctx *ctx = prv;
 	struct g2d_dev *dev = ctx->dev;
-	int ret;
 
 	if (dev->curr == NULL) /* No job currently running */
 		return;
 
-	ret = wait_event_timeout(dev->irq_queue,
-		dev->curr == NULL,
-		msecs_to_jiffies(G2D_TIMEOUT));
+	wait_event_timeout(dev->irq_queue,
+			   dev->curr == NULL,
+			   msecs_to_jiffies(G2D_TIMEOUT));
 }
 
 static void device_run(void *prv)
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index e66acbc..e525a7c 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -729,7 +729,7 @@
 			     ARRAY_SIZE(qtbl_chrominance[quality]));
 }
 
-void exynos4_jpeg_set_huff_tbl(void __iomem *base)
+static void exynos4_jpeg_set_huff_tbl(void __iomem *base)
 {
 	exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
 							ARRAY_SIZE(hdctbl0));
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c
index d26e1f8..e8c2cad 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c
@@ -233,6 +233,7 @@
 	writel(reg, regs + EXYNOS3250_JPGX);
 }
 
+#if 0	/* Currently unused */
 unsigned int exynos3250_jpeg_get_y(void __iomem *regs)
 {
 	return readl(regs + EXYNOS3250_JPGY);
@@ -242,6 +243,7 @@
 {
 	return readl(regs + EXYNOS3250_JPGX);
 }
+#endif
 
 void exynos3250_jpeg_interrupts_enable(void __iomem *regs)
 {
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c
index da8d6a1..ab6d6f4 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c
@@ -23,7 +23,7 @@
 	reg = readl(base + EXYNOS4_JPEG_CNTL_REG);
 	writel(reg & ~EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG);
 
-	ndelay(100000);
+	udelay(100);
 
 	writel(reg | EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG);
 }
@@ -151,9 +151,6 @@
 
 void exynos4_jpeg_set_interrupt(void __iomem *base)
 {
-	unsigned int reg;
-
-	reg = readl(base + EXYNOS4_INT_EN_REG) & ~EXYNOS4_INT_EN_MASK;
 	writel(EXYNOS4_INT_EN_ALL, base + EXYNOS4_INT_EN_REG);
 }
 
@@ -185,7 +182,7 @@
 		writel(reg | EXYNOS4_HUF_TBL_EN,
 					base + EXYNOS4_JPEG_CNTL_REG);
 	else
-		writel(reg | ~EXYNOS4_HUF_TBL_EN,
+		writel(reg & ~EXYNOS4_HUF_TBL_EN,
 					base + EXYNOS4_JPEG_CNTL_REG);
 }
 
@@ -196,9 +193,9 @@
 	reg = readl(base + EXYNOS4_JPEG_CNTL_REG) & ~(EXYNOS4_SYS_INT_EN);
 
 	if (value == 1)
-		writel(EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
+		writel(reg | EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
 	else
-		writel(~EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
+		writel(reg & ~EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
 }
 
 void exynos4_jpeg_set_stream_buf_address(void __iomem *base,
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
index 52407d7..e3b8e67 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
@@ -324,11 +324,9 @@
 
 void s5p_jpeg_clear_int(void __iomem *regs)
 {
-	unsigned long reg;
-
-	reg = readl(regs + S5P_JPGINTST);
+	readl(regs + S5P_JPGINTST);
 	writel(S5P_INT_RELEASE, regs + S5P_JPGCOM);
-	reg = readl(regs + S5P_JPGOPR);
+	readl(regs + S5P_JPGOPR);
 }
 
 unsigned int s5p_jpeg_compressed_size(void __iomem *regs)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index d35b041..165bc86 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -37,8 +37,8 @@
 #define S5P_MFC_DEC_NAME	"s5p-mfc-dec"
 #define S5P_MFC_ENC_NAME	"s5p-mfc-enc"
 
-int debug;
-module_param(debug, int, S_IRUGO | S_IWUSR);
+int mfc_debug_level;
+module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages");
 
 /* Helper functions for interrupt processing */
@@ -150,10 +150,10 @@
 		if (!ctx)
 			continue;
 		ctx->state = MFCINST_ERROR;
-		s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
-				&ctx->vq_dst);
-		s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
-				&ctx->vq_src);
+		s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+						&ctx->dst_queue, &ctx->vq_dst);
+		s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+						&ctx->src_queue, &ctx->vq_src);
 		clear_work_bit(ctx);
 		wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0);
 	}
@@ -264,7 +264,12 @@
 	unsigned int frame_type;
 
 	dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev);
-	frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_disp_frame_type, ctx);
+	if (IS_MFCV6_PLUS(dev))
+		frame_type = s5p_mfc_hw_call(dev->mfc_ops,
+			get_disp_frame_type, ctx);
+	else
+		frame_type = s5p_mfc_hw_call(dev->mfc_ops,
+			get_dec_frame_type, dev);
 
 	/* If frame is same as previous then skip and do not dequeue */
 	if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) {
@@ -327,12 +332,12 @@
 	if (res_change == S5P_FIMV_RES_INCREASE ||
 		res_change == S5P_FIMV_RES_DECREASE) {
 		ctx->state = MFCINST_RES_CHANGE_INIT;
-		s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+		s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
 		wake_up_ctx(ctx, reason, err);
 		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
 			BUG();
 		s5p_mfc_clock_off();
-		s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+		s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 		return;
 	}
 	if (ctx->dpb_flush_flag)
@@ -400,7 +405,7 @@
 	if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
 				    || ctx->dst_queue_cnt < ctx->pb_count)
 		clear_work_bit(ctx);
-	s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
 	wake_up_ctx(ctx, reason, err);
 	if (test_and_clear_bit(0, &dev->hw_lock) == 0)
 		BUG();
@@ -409,7 +414,7 @@
 	if (test_bit(0, &dev->enter_suspend))
 		wake_up_dev(dev, reason, err);
 	else
-		s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+		s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 }
 
 /* Error handling for interrupt */
@@ -435,10 +440,10 @@
 			ctx->state = MFCINST_ERROR;
 			/* Mark all dst buffers as having an error */
 			spin_lock_irqsave(&dev->irqlock, flags);
-			s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue,
+			s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
 						&ctx->dst_queue, &ctx->vq_dst);
 			/* Mark all src buffers as having an error */
-			s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue,
+			s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
 						&ctx->src_queue, &ctx->vq_src);
 			spin_unlock_irqrestore(&dev->irqlock, flags);
 			wake_up_ctx(ctx, reason, err);
@@ -452,7 +457,7 @@
 	}
 	if (test_and_clear_bit(0, &dev->hw_lock) == 0)
 		BUG();
-	s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
 	s5p_mfc_clock_off();
 	wake_up_dev(dev, reason, err);
 	return;
@@ -476,7 +481,7 @@
 		ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height,
 				dev);
 
-		s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx);
+		s5p_mfc_hw_call_void(dev->mfc_ops, dec_calc_dpb_size, ctx);
 
 		ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count,
 				dev);
@@ -503,12 +508,12 @@
 			ctx->head_processed = 1;
 		}
 	}
-	s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
 	clear_work_bit(ctx);
 	if (test_and_clear_bit(0, &dev->hw_lock) == 0)
 		BUG();
 	s5p_mfc_clock_off();
-	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 	wake_up_ctx(ctx, reason, err);
 }
 
@@ -523,7 +528,7 @@
 	if (ctx == NULL)
 		return;
 	dev = ctx->dev;
-	s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
 	ctx->int_type = reason;
 	ctx->int_err = err;
 	ctx->int_cond = 1;
@@ -550,7 +555,7 @@
 		s5p_mfc_clock_off();
 
 		wake_up(&ctx->queue);
-		s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+		s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 	} else {
 		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
 			BUG();
@@ -591,7 +596,7 @@
 
 	s5p_mfc_clock_off();
 	wake_up(&ctx->queue);
-	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 }
 
 /* Interrupt processing */
@@ -628,12 +633,12 @@
 		if (ctx->c_ops->post_frame_start) {
 			if (ctx->c_ops->post_frame_start(ctx))
 				mfc_err("post_frame_start() failed\n");
-			s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+			s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
 			wake_up_ctx(ctx, reason, err);
 			if (test_and_clear_bit(0, &dev->hw_lock) == 0)
 				BUG();
 			s5p_mfc_clock_off();
-			s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+			s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 		} else {
 			s5p_mfc_handle_frame(ctx, reason, err);
 		}
@@ -663,7 +668,7 @@
 	case S5P_MFC_R2H_CMD_WAKEUP_RET:
 		if (ctx)
 			clear_work_bit(ctx);
-		s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+		s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
 		wake_up_dev(dev, reason, err);
 		clear_bit(0, &dev->hw_lock);
 		clear_bit(0, &dev->enter_suspend);
@@ -685,12 +690,12 @@
 
 	default:
 		mfc_debug(2, "Unknown int reason\n");
-		s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+		s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
 	}
 	mfc_debug_leave();
 	return IRQ_HANDLED;
 irq_cleanup_hw:
-	s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
 	ctx->int_type = reason;
 	ctx->int_err = err;
 	ctx->int_cond = 1;
@@ -699,7 +704,7 @@
 
 	s5p_mfc_clock_off();
 
-	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 	mfc_debug(2, "Exit via irq_cleanup_hw\n");
 	return IRQ_HANDLED;
 }
@@ -1311,11 +1316,9 @@
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
-	int pre_power;
 
 	if (!m_dev->alloc_ctx)
 		return 0;
-	pre_power = atomic_read(&m_dev->pm.power);
 	atomic_set(&m_dev->pm.power, 1);
 	return 0;
 }
@@ -1328,20 +1331,20 @@
 			   NULL)
 };
 
-struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = {
+static struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = {
 	.h264_ctx	= MFC_H264_CTX_BUF_SIZE,
 	.non_h264_ctx	= MFC_CTX_BUF_SIZE,
 	.dsc		= DESC_BUF_SIZE,
 	.shm		= SHARED_BUF_SIZE,
 };
 
-struct s5p_mfc_buf_size buf_size_v5 = {
+static struct s5p_mfc_buf_size buf_size_v5 = {
 	.fw	= MAX_FW_SIZE,
 	.cpb	= MAX_CPB_SIZE,
 	.priv	= &mfc_buf_size_v5,
 };
 
-struct s5p_mfc_buf_align mfc_buf_align_v5 = {
+static struct s5p_mfc_buf_align mfc_buf_align_v5 = {
 	.base = MFC_BASE_ALIGN_ORDER,
 };
 
@@ -1354,7 +1357,7 @@
 	.fw_name[0]	= "s5p-mfc.fw",
 };
 
-struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = {
+static struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = {
 	.dev_ctx	= MFC_CTX_BUF_SIZE_V6,
 	.h264_dec_ctx	= MFC_H264_DEC_CTX_BUF_SIZE_V6,
 	.other_dec_ctx	= MFC_OTHER_DEC_CTX_BUF_SIZE_V6,
@@ -1362,13 +1365,13 @@
 	.other_enc_ctx	= MFC_OTHER_ENC_CTX_BUF_SIZE_V6,
 };
 
-struct s5p_mfc_buf_size buf_size_v6 = {
+static struct s5p_mfc_buf_size buf_size_v6 = {
 	.fw	= MAX_FW_SIZE_V6,
 	.cpb	= MAX_CPB_SIZE_V6,
 	.priv	= &mfc_buf_size_v6,
 };
 
-struct s5p_mfc_buf_align mfc_buf_align_v6 = {
+static struct s5p_mfc_buf_align mfc_buf_align_v6 = {
 	.base = 0,
 };
 
@@ -1386,7 +1389,7 @@
 	.fw_name[1]     = "s5p-mfc-v6-v2.fw",
 };
 
-struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = {
+static struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = {
 	.dev_ctx	= MFC_CTX_BUF_SIZE_V7,
 	.h264_dec_ctx	= MFC_H264_DEC_CTX_BUF_SIZE_V7,
 	.other_dec_ctx	= MFC_OTHER_DEC_CTX_BUF_SIZE_V7,
@@ -1394,13 +1397,13 @@
 	.other_enc_ctx	= MFC_OTHER_ENC_CTX_BUF_SIZE_V7,
 };
 
-struct s5p_mfc_buf_size buf_size_v7 = {
+static struct s5p_mfc_buf_size buf_size_v7 = {
 	.fw	= MAX_FW_SIZE_V7,
 	.cpb	= MAX_CPB_SIZE_V7,
 	.priv	= &mfc_buf_size_v7,
 };
 
-struct s5p_mfc_buf_align mfc_buf_align_v7 = {
+static struct s5p_mfc_buf_align mfc_buf_align_v7 = {
 	.base = 0,
 };
 
@@ -1413,7 +1416,7 @@
 	.fw_name[0]     = "s5p-mfc-v7.fw",
 };
 
-struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = {
+static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = {
 	.dev_ctx	= MFC_CTX_BUF_SIZE_V8,
 	.h264_dec_ctx	= MFC_H264_DEC_CTX_BUF_SIZE_V8,
 	.other_dec_ctx	= MFC_OTHER_DEC_CTX_BUF_SIZE_V8,
@@ -1421,13 +1424,13 @@
 	.other_enc_ctx	= MFC_OTHER_ENC_CTX_BUF_SIZE_V8,
 };
 
-struct s5p_mfc_buf_size buf_size_v8 = {
+static struct s5p_mfc_buf_size buf_size_v8 = {
 	.fw	= MAX_FW_SIZE_V8,
 	.cpb	= MAX_CPB_SIZE_V8,
 	.priv	= &mfc_buf_size_v8,
 };
 
-struct s5p_mfc_buf_align mfc_buf_align_v8 = {
+static struct s5p_mfc_buf_align mfc_buf_align_v8 = {
 	.base = 0,
 };
 
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c
index 9a6efd6..8c4739c 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c
@@ -14,6 +14,7 @@
 #include "s5p_mfc_cmd.h"
 #include "s5p_mfc_common.h"
 #include "s5p_mfc_debug.h"
+#include "s5p_mfc_cmd_v5.h"
 
 /* This function is used to send a command to the MFC */
 static int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd,
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
index ec1a594..f176096 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
@@ -16,6 +16,7 @@
 #include "s5p_mfc_debug.h"
 #include "s5p_mfc_intr.h"
 #include "s5p_mfc_opr.h"
+#include "s5p_mfc_cmd_v6.h"
 
 static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd,
 				struct s5p_mfc_cmd_args *args)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
index 01816ff..3e41ca1 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
@@ -698,6 +698,12 @@
 #define s5p_mfc_hw_call(f, op, args...) \
 	((f && f->op) ? f->op(args) : -ENODEV)
 
+#define s5p_mfc_hw_call_void(f, op, args...) \
+do { \
+	if (f && f->op) \
+		f->op(args); \
+} while (0)
+
 #define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh)
 #define ctrl_to_ctx(__ctrl) \
 	container_of((__ctrl)->handler, struct s5p_mfc_ctx, ctrl_handler)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
index ca9f789..0c885a8 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
@@ -21,6 +21,7 @@
 #include "s5p_mfc_intr.h"
 #include "s5p_mfc_opr.h"
 #include "s5p_mfc_pm.h"
+#include "s5p_mfc_ctrl.h"
 
 /* Allocate memory for firmware */
 int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
@@ -188,12 +189,12 @@
 {
 	if (IS_MFCV6_PLUS(dev)) {
 		mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6);
-		mfc_debug(2, "Base Address : %08x\n", dev->bank1);
+		mfc_debug(2, "Base Address : %pad\n", &dev->bank1);
 	} else {
 		mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A);
 		mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B);
-		mfc_debug(2, "Bank1: %08x, Bank2: %08x\n",
-				dev->bank1, dev->bank2);
+		mfc_debug(2, "Bank1: %pad, Bank2: %pad\n",
+				&dev->bank1, &dev->bank2);
 	}
 }
 
@@ -257,9 +258,9 @@
 		s5p_mfc_clock_off();
 		return ret;
 	}
-	mfc_debug(2, "Ok, now will write a command to init the system\n");
+	mfc_debug(2, "Ok, now will wait for completion of hardware init\n");
 	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) {
-		mfc_err("Failed to load firmware\n");
+		mfc_err("Failed to init hardware\n");
 		s5p_mfc_reset(dev);
 		s5p_mfc_clock_off();
 		return -EIO;
@@ -293,7 +294,7 @@
 	s5p_mfc_clock_on();
 
 	s5p_mfc_reset(dev);
-	s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, release_dev_context_buffer, dev);
 
 	s5p_mfc_clock_off();
 }
@@ -396,7 +397,7 @@
 
 	set_work_bit_irqsave(ctx);
 	s5p_mfc_clean_ctx_int_flags(ctx);
-	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 	if (s5p_mfc_wait_for_done_ctx(ctx,
 		S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
 		/* Error or timeout */
@@ -410,9 +411,9 @@
 
 err_free_desc_buf:
 	if (ctx->type == MFCINST_DECODER)
-		s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
+		s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx);
 err_free_inst_buf:
-	s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
+	s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx);
 err:
 	return ret;
 }
@@ -422,17 +423,17 @@
 	ctx->state = MFCINST_RETURN_INST;
 	set_work_bit_irqsave(ctx);
 	s5p_mfc_clean_ctx_int_flags(ctx);
-	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 	/* Wait until instance is returned or timeout occurred */
 	if (s5p_mfc_wait_for_done_ctx(ctx,
 				S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0))
 		mfc_err("Err returning instance\n");
 
 	/* Free resources */
-	s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
-	s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
+	s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx);
+	s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx);
 	if (ctx->type == MFCINST_DECODER)
-		s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
+		s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx);
 
 	ctx->inst_no = MFC_NO_INSTANCE_SET;
 	ctx->state = MFCINST_FREE;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
index 8e608f5..5936923 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
@@ -1,5 +1,5 @@
 /*
- * drivers/media/platform/samsung/mfc5/s5p_mfc_debug.h
+ * drivers/media/platform/s5p-mfc/s5p_mfc_debug.h
  *
  * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
  * This file contains debug macros
@@ -18,11 +18,11 @@
 #define DEBUG
 
 #ifdef DEBUG
-extern int debug;
+extern int mfc_debug_level;
 
 #define mfc_debug(level, fmt, args...)				\
 	do {							\
-		if (debug >= level)				\
+		if (mfc_debug_level >= level)			\
 			printk(KERN_DEBUG "%s:%d: " fmt,	\
 				__func__, __LINE__, ##args);	\
 	} while (0)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 9103258..a98fe02 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -283,17 +283,13 @@
 
 /* Enumerate format */
 static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
-							bool mplane, bool out)
+							bool out)
 {
 	struct s5p_mfc_dev *dev = video_drvdata(file);
 	struct s5p_mfc_fmt *fmt;
 	int i, j = 0;
 
 	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
-		if (mplane && formats[i].num_planes == 1)
-			continue;
-		else if (!mplane && formats[i].num_planes > 1)
-			continue;
 		if (out && formats[i].type != MFC_FMT_DEC)
 			continue;
 		else if (!out && formats[i].type != MFC_FMT_RAW)
@@ -313,28 +309,16 @@
 	return 0;
 }
 
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
-							struct v4l2_fmtdesc *f)
-{
-	return vidioc_enum_fmt(file, f, false, false);
-}
-
 static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
 							struct v4l2_fmtdesc *f)
 {
-	return vidioc_enum_fmt(file, f, true, false);
-}
-
-static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
-							struct v4l2_fmtdesc *f)
-{
-	return vidioc_enum_fmt(file, f, false, true);
+	return vidioc_enum_fmt(file, f, false);
 }
 
 static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv,
 							struct v4l2_fmtdesc *f)
 {
-	return vidioc_enum_fmt(file, f, true, true);
+	return vidioc_enum_fmt(file, f, true);
 }
 
 /* Get format */
@@ -543,7 +527,7 @@
 		ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
 		if (ret)
 			goto out;
-		s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
+		s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx);
 		ctx->dst_bufs_cnt = 0;
 	} else if (ctx->capture_state == QUEUE_FREE) {
 		WARN_ON(ctx->dst_bufs_cnt != 0);
@@ -571,7 +555,7 @@
 
 		if (s5p_mfc_ctx_ready(ctx))
 			set_work_bit_irqsave(ctx);
-		s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+		s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 		s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET,
 					  0);
 	} else {
@@ -823,8 +807,8 @@
 	return 0;
 }
 
-int vidioc_decoder_cmd(struct file *file, void *priv,
-						struct v4l2_decoder_cmd *cmd)
+static int vidioc_decoder_cmd(struct file *file, void *priv,
+			      struct v4l2_decoder_cmd *cmd)
 {
 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
 	struct s5p_mfc_dev *dev = ctx->dev;
@@ -846,7 +830,7 @@
 			if (s5p_mfc_ctx_ready(ctx))
 				set_work_bit_irqsave(ctx);
 			spin_unlock_irqrestore(&dev->irqlock, flags);
-			s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+			s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 		} else {
 			mfc_err("EOS: marking last buffer of stream");
 			buf = list_entry(ctx->src_queue.prev,
@@ -881,9 +865,7 @@
 /* v4l2_ioctl_ops */
 static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
 	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
 	.vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
-	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
 	.vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
 	.vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
 	.vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
@@ -990,7 +972,7 @@
 	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		if (ctx->capture_state == QUEUE_BUFS_MMAPED)
 			return 0;
-		for (i = 0; i <= ctx->src_fmt->num_planes ; i++) {
+		for (i = 0; i < ctx->dst_fmt->num_planes; i++) {
 			if (IS_ERR_OR_NULL(ERR_PTR(
 					vb2_dma_contig_plane_dma_addr(vb, i)))) {
 				mfc_err("Plane mem not allocated\n");
@@ -1044,7 +1026,7 @@
 	/* If context is ready then dev = work->data;schedule it to run */
 	if (s5p_mfc_ctx_ready(ctx))
 		set_work_bit_irqsave(ctx);
-	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 	return 0;
 }
 
@@ -1065,8 +1047,8 @@
 	}
 	if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		spin_lock_irqsave(&dev->irqlock, flags);
-		s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
-				&ctx->vq_dst);
+		s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+						&ctx->dst_queue, &ctx->vq_dst);
 		INIT_LIST_HEAD(&ctx->dst_queue);
 		ctx->dst_queue_cnt = 0;
 		ctx->dpb_flush_flag = 1;
@@ -1076,7 +1058,7 @@
 			ctx->state = MFCINST_FLUSH;
 			set_work_bit_irqsave(ctx);
 			s5p_mfc_clean_ctx_int_flags(ctx);
-			s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+			s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 			if (s5p_mfc_wait_for_done_ctx(ctx,
 				S5P_MFC_R2H_CMD_DPB_FLUSH_RET, 0))
 				mfc_err("Err flushing buffers\n");
@@ -1084,8 +1066,8 @@
 	}
 	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		spin_lock_irqsave(&dev->irqlock, flags);
-		s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
-				&ctx->vq_src);
+		s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+						&ctx->src_queue, &ctx->vq_src);
 		INIT_LIST_HEAD(&ctx->src_queue);
 		ctx->src_queue_cnt = 0;
 		spin_unlock_irqrestore(&dev->irqlock, flags);
@@ -1124,7 +1106,7 @@
 	}
 	if (s5p_mfc_ctx_ready(ctx))
 		set_work_bit_irqsave(ctx);
-	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 }
 
 static struct vb2_ops s5p_mfc_dec_qops = {
@@ -1220,7 +1202,7 @@
 	else
 		f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT;
 	ctx->dst_fmt = find_format(&f, MFC_FMT_RAW);
-	mfc_debug(2, "Default src_fmt is %x, dest_fmt is %x\n",
-			(unsigned int)ctx->src_fmt, (unsigned int)ctx->dst_fmt);
+	mfc_debug(2, "Default src_fmt is %p, dest_fmt is %p\n",
+			ctx->src_fmt, ctx->dst_fmt);
 }
 
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index d26b248..a904a1c 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -739,14 +739,11 @@
 static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx)
 {
 	struct s5p_mfc_buf *mb_entry;
-	unsigned long mb_y_addr, mb_c_addr;
 
 	/* move buffers in ref queue to src queue */
 	while (!list_empty(&ctx->ref_queue)) {
 		mb_entry = list_entry((&ctx->ref_queue)->next,
 						struct s5p_mfc_buf, list);
-		mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
-		mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1);
 		list_del(&mb_entry->list);
 		ctx->ref_queue_cnt--;
 		list_add_tail(&mb_entry->list, &ctx->src_queue);
@@ -770,7 +767,7 @@
 	dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
 	dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
 	dst_size = vb2_plane_size(dst_mb->b, 0);
-	s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
+	s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
 			dst_size);
 	spin_unlock_irqrestore(&dev->irqlock, flags);
 	return 0;
@@ -803,7 +800,7 @@
 		ctx->state = MFCINST_RUNNING;
 		if (s5p_mfc_ctx_ready(ctx))
 			set_work_bit_irqsave(ctx);
-		s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+		s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 	} else {
 		enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops,
 				get_enc_dpb_count, dev);
@@ -828,15 +825,15 @@
 	src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
 	src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0);
 	src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1);
-	s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx, src_y_addr,
-			src_c_addr);
+	s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_frame_buffer, ctx,
+							src_y_addr, src_c_addr);
 	spin_unlock_irqrestore(&dev->irqlock, flags);
 
 	spin_lock_irqsave(&dev->irqlock, flags);
 	dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
 	dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0);
 	dst_size = vb2_plane_size(dst_mb->b, 0);
-	s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
+	s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
 			dst_size);
 	spin_unlock_irqrestore(&dev->irqlock, flags);
 
@@ -861,7 +858,7 @@
 		  mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
 	spin_lock_irqsave(&dev->irqlock, flags);
 	if (slice_type >= 0) {
-		s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx,
+		s5p_mfc_hw_call_void(dev->mfc_ops, get_enc_frame_buffer, ctx,
 				&enc_y_addr, &enc_c_addr);
 		list_for_each_entry(mb_entry, &ctx->src_queue, list) {
 			mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0);
@@ -954,17 +951,13 @@
 }
 
 static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
-							bool mplane, bool out)
+							bool out)
 {
 	struct s5p_mfc_dev *dev = video_drvdata(file);
 	struct s5p_mfc_fmt *fmt;
 	int i, j = 0;
 
 	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
-		if (mplane && formats[i].num_planes == 1)
-			continue;
-		else if (!mplane && formats[i].num_planes > 1)
-			continue;
 		if (out && formats[i].type != MFC_FMT_RAW)
 			continue;
 		else if (!out && formats[i].type != MFC_FMT_ENC)
@@ -984,28 +977,16 @@
 	return -EINVAL;
 }
 
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
-				   struct v4l2_fmtdesc *f)
-{
-	return vidioc_enum_fmt(file, f, false, false);
-}
-
 static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
 					  struct v4l2_fmtdesc *f)
 {
-	return vidioc_enum_fmt(file, f, true, false);
-}
-
-static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
-				   struct v4l2_fmtdesc *f)
-{
-	return vidioc_enum_fmt(file, f, false, true);
+	return vidioc_enum_fmt(file, f, false);
 }
 
 static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
 					  struct v4l2_fmtdesc *f)
 {
-	return vidioc_enum_fmt(file, f, true, true);
+	return vidioc_enum_fmt(file, f, true);
 }
 
 static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
@@ -1127,7 +1108,7 @@
 			pix_fmt_mp->width, pix_fmt_mp->height,
 			ctx->img_width, ctx->img_height);
 
-		s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx);
+		s5p_mfc_hw_call_void(dev->mfc_ops, enc_calc_src_size, ctx);
 		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
 		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
 		pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
@@ -1681,8 +1662,8 @@
 	return 0;
 }
 
-int vidioc_encoder_cmd(struct file *file, void *priv,
-						struct v4l2_encoder_cmd *cmd)
+static int vidioc_encoder_cmd(struct file *file, void *priv,
+			      struct v4l2_encoder_cmd *cmd)
 {
 	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
 	struct s5p_mfc_dev *dev = ctx->dev;
@@ -1704,7 +1685,7 @@
 			if (s5p_mfc_ctx_ready(ctx))
 				set_work_bit_irqsave(ctx);
 			spin_unlock_irqrestore(&dev->irqlock, flags);
-			s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+			s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 		} else {
 			mfc_debug(2, "EOS: marking last buffer of stream\n");
 			buf = list_entry(ctx->src_queue.prev,
@@ -1736,9 +1717,7 @@
 
 static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
 	.vidioc_querycap = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
 	.vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
-	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
 	.vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
 	.vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
 	.vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
@@ -1771,13 +1750,13 @@
 		return -EINVAL;
 	}
 	for (i = 0; i < fmt->num_planes; i++) {
-		if (!vb2_dma_contig_plane_dma_addr(vb, i)) {
+		dma_addr_t dma = vb2_dma_contig_plane_dma_addr(vb, i);
+		if (!dma) {
 			mfc_err("failed to get plane cookie\n");
 			return -EINVAL;
 		}
-		mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx\n",
-			  vb->v4l2_buf.index, i,
-			  vb2_dma_contig_plane_dma_addr(vb, i));
+		mfc_debug(2, "index: %d, plane[%d] cookie: %pad\n",
+			  vb->v4l2_buf.index, i, &dma);
 	}
 	return 0;
 }
@@ -1897,7 +1876,7 @@
 		ret = check_vb_with_fmt(ctx->dst_fmt, vb);
 		if (ret < 0)
 			return ret;
-		mfc_debug(2, "plane size: %ld, dst size: %d\n",
+		mfc_debug(2, "plane size: %ld, dst size: %zu\n",
 			vb2_plane_size(vb, 0), ctx->enc_dst_buf_size);
 		if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) {
 			mfc_err("plane size is too small for capture\n");
@@ -1948,7 +1927,7 @@
 	/* If context is ready then dev = work->data;schedule it to run */
 	if (s5p_mfc_ctx_ready(ctx))
 		set_work_bit_irqsave(ctx);
-	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 
 	return 0;
 }
@@ -1969,14 +1948,14 @@
 	ctx->state = MFCINST_FINISHED;
 	spin_lock_irqsave(&dev->irqlock, flags);
 	if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-		s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
-				&ctx->vq_dst);
+		s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
+						&ctx->dst_queue, &ctx->vq_dst);
 		INIT_LIST_HEAD(&ctx->dst_queue);
 		ctx->dst_queue_cnt = 0;
 	}
 	if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		cleanup_ref_queue(ctx);
-		s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
+		s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
 				&ctx->vq_src);
 		INIT_LIST_HEAD(&ctx->src_queue);
 		ctx->src_queue_cnt = 0;
@@ -2017,7 +1996,7 @@
 	}
 	if (s5p_mfc_ctx_ready(ctx))
 		set_work_bit_irqsave(ctx);
-	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+	s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
 }
 
 static struct vb2_ops s5p_mfc_enc_qops = {
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
index c9a2274..00a1d8b 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
@@ -41,7 +41,7 @@
 					struct s5p_mfc_priv_buf *b)
 {
 
-	mfc_debug(3, "Allocating priv: %d\n", b->size);
+	mfc_debug(3, "Allocating priv: %zu\n", b->size);
 
 	b->virt = dma_alloc_coherent(dev, b->size, &b->dma, GFP_KERNEL);
 
@@ -50,7 +50,7 @@
 		return -ENOMEM;
 	}
 
-	mfc_debug(3, "Allocated addr %p %08x\n", b->virt, b->dma);
+	mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma);
 	return 0;
 }
 
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
index 7a7ad32..de2b8c6 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
@@ -20,254 +20,254 @@
 struct s5p_mfc_regs {
 
 	/* codec common registers */
-	void *risc_on;
-	void *risc2host_int;
-	void *host2risc_int;
-	void *risc_base_address;
-	void *mfc_reset;
-	void *host2risc_command;
-	void *risc2host_command;
-	void *mfc_bus_reset_ctrl;
-	void *firmware_version;
-	void *instance_id;
-	void *codec_type;
-	void *context_mem_addr;
-	void *context_mem_size;
-	void *pixel_format;
-	void *metadata_enable;
-	void *mfc_version;
-	void *dbg_info_enable;
-	void *dbg_buffer_addr;
-	void *dbg_buffer_size;
-	void *hed_control;
-	void *mfc_timeout_value;
-	void *hed_shared_mem_addr;
-	void *dis_shared_mem_addr;/* only v7 */
-	void *ret_instance_id;
-	void *error_code;
-	void *dbg_buffer_output_size;
-	void *metadata_status;
-	void *metadata_addr_mb_info;
-	void *metadata_size_mb_info;
-	void *dbg_info_stage_counter;
+	volatile void __iomem *risc_on;
+	volatile void __iomem *risc2host_int;
+	volatile void __iomem *host2risc_int;
+	volatile void __iomem *risc_base_address;
+	volatile void __iomem *mfc_reset;
+	volatile void __iomem *host2risc_command;
+	volatile void __iomem *risc2host_command;
+	volatile void __iomem *mfc_bus_reset_ctrl;
+	volatile void __iomem *firmware_version;
+	volatile void __iomem *instance_id;
+	volatile void __iomem *codec_type;
+	volatile void __iomem *context_mem_addr;
+	volatile void __iomem *context_mem_size;
+	volatile void __iomem *pixel_format;
+	volatile void __iomem *metadata_enable;
+	volatile void __iomem *mfc_version;
+	volatile void __iomem *dbg_info_enable;
+	volatile void __iomem *dbg_buffer_addr;
+	volatile void __iomem *dbg_buffer_size;
+	volatile void __iomem *hed_control;
+	volatile void __iomem *mfc_timeout_value;
+	volatile void __iomem *hed_shared_mem_addr;
+	volatile void __iomem *dis_shared_mem_addr;/* only v7 */
+	volatile void __iomem *ret_instance_id;
+	volatile void __iomem *error_code;
+	volatile void __iomem *dbg_buffer_output_size;
+	volatile void __iomem *metadata_status;
+	volatile void __iomem *metadata_addr_mb_info;
+	volatile void __iomem *metadata_size_mb_info;
+	volatile void __iomem *dbg_info_stage_counter;
 
 	/* decoder registers */
-	void *d_crc_ctrl;
-	void *d_dec_options;
-	void *d_display_delay;
-	void *d_set_frame_width;
-	void *d_set_frame_height;
-	void *d_sei_enable;
-	void *d_min_num_dpb;
-	void *d_min_first_plane_dpb_size;
-	void *d_min_second_plane_dpb_size;
-	void *d_min_third_plane_dpb_size;/* only v8 */
-	void *d_min_num_mv;
-	void *d_mvc_num_views;
-	void *d_min_num_dis;/* only v7 */
-	void *d_min_first_dis_size;/* only v7 */
-	void *d_min_second_dis_size;/* only v7 */
-	void *d_min_third_dis_size;/* only v7 */
-	void *d_post_filter_luma_dpb0;/*  v7 and v8 */
-	void *d_post_filter_luma_dpb1;/* v7 and v8 */
-	void *d_post_filter_luma_dpb2;/* only v7 */
-	void *d_post_filter_chroma_dpb0;/* v7 and v8 */
-	void *d_post_filter_chroma_dpb1;/* v7 and v8 */
-	void *d_post_filter_chroma_dpb2;/* only v7 */
-	void *d_num_dpb;
-	void *d_num_mv;
-	void *d_init_buffer_options;
-	void *d_first_plane_dpb_stride_size;/* only v8 */
-	void *d_second_plane_dpb_stride_size;/* only v8 */
-	void *d_third_plane_dpb_stride_size;/* only v8 */
-	void *d_first_plane_dpb_size;
-	void *d_second_plane_dpb_size;
-	void *d_third_plane_dpb_size;/* only v8 */
-	void *d_mv_buffer_size;
-	void *d_first_plane_dpb;
-	void *d_second_plane_dpb;
-	void *d_third_plane_dpb;
-	void *d_mv_buffer;
-	void *d_scratch_buffer_addr;
-	void *d_scratch_buffer_size;
-	void *d_metadata_buffer_addr;
-	void *d_metadata_buffer_size;
-	void *d_nal_start_options;/* v7 and v8 */
-	void *d_cpb_buffer_addr;
-	void *d_cpb_buffer_size;
-	void *d_available_dpb_flag_upper;
-	void *d_available_dpb_flag_lower;
-	void *d_cpb_buffer_offset;
-	void *d_slice_if_enable;
-	void *d_picture_tag;
-	void *d_stream_data_size;
-	void *d_dynamic_dpb_flag_upper;/* v7 and v8 */
-	void *d_dynamic_dpb_flag_lower;/* v7 and v8 */
-	void *d_display_frame_width;
-	void *d_display_frame_height;
-	void *d_display_status;
-	void *d_display_first_plane_addr;
-	void *d_display_second_plane_addr;
-	void *d_display_third_plane_addr;/* only v8 */
-	void *d_display_frame_type;
-	void *d_display_crop_info1;
-	void *d_display_crop_info2;
-	void *d_display_picture_profile;
-	void *d_display_luma_crc;/* v7 and v8 */
-	void *d_display_chroma0_crc;/* v7 and v8 */
-	void *d_display_chroma1_crc;/* only v8 */
-	void *d_display_luma_crc_top;/* only v6 */
-	void *d_display_chroma_crc_top;/* only v6 */
-	void *d_display_luma_crc_bot;/* only v6 */
-	void *d_display_chroma_crc_bot;/* only v6 */
-	void *d_display_aspect_ratio;
-	void *d_display_extended_ar;
-	void *d_decoded_frame_width;
-	void *d_decoded_frame_height;
-	void *d_decoded_status;
-	void *d_decoded_first_plane_addr;
-	void *d_decoded_second_plane_addr;
-	void *d_decoded_third_plane_addr;/* only v8 */
-	void *d_decoded_frame_type;
-	void *d_decoded_crop_info1;
-	void *d_decoded_crop_info2;
-	void *d_decoded_picture_profile;
-	void *d_decoded_nal_size;
-	void *d_decoded_luma_crc;
-	void *d_decoded_chroma0_crc;
-	void *d_decoded_chroma1_crc;/* only v8 */
-	void *d_ret_picture_tag_top;
-	void *d_ret_picture_tag_bot;
-	void *d_ret_picture_time_top;
-	void *d_ret_picture_time_bot;
-	void *d_chroma_format;
-	void *d_vc1_info;/* v7 and v8 */
-	void *d_mpeg4_info;
-	void *d_h264_info;
-	void *d_metadata_addr_concealed_mb;
-	void *d_metadata_size_concealed_mb;
-	void *d_metadata_addr_vc1_param;
-	void *d_metadata_size_vc1_param;
-	void *d_metadata_addr_sei_nal;
-	void *d_metadata_size_sei_nal;
-	void *d_metadata_addr_vui;
-	void *d_metadata_size_vui;
-	void *d_metadata_addr_mvcvui;/* v7 and v8 */
-	void *d_metadata_size_mvcvui;/* v7 and v8 */
-	void *d_mvc_view_id;
-	void *d_frame_pack_sei_avail;
-	void *d_frame_pack_arrgment_id;
-	void *d_frame_pack_sei_info;
-	void *d_frame_pack_grid_pos;
-	void *d_display_recovery_sei_info;/* v7 and v8 */
-	void *d_decoded_recovery_sei_info;/* v7 and v8 */
-	void *d_display_first_addr;/* only v7 */
-	void *d_display_second_addr;/* only v7 */
-	void *d_display_third_addr;/* only v7 */
-	void *d_decoded_first_addr;/* only v7 */
-	void *d_decoded_second_addr;/* only v7 */
-	void *d_decoded_third_addr;/* only v7 */
-	void *d_used_dpb_flag_upper;/* v7 and v8 */
-	void *d_used_dpb_flag_lower;/* v7 and v8 */
+	volatile void __iomem *d_crc_ctrl;
+	volatile void __iomem *d_dec_options;
+	volatile void __iomem *d_display_delay;
+	volatile void __iomem *d_set_frame_width;
+	volatile void __iomem *d_set_frame_height;
+	volatile void __iomem *d_sei_enable;
+	volatile void __iomem *d_min_num_dpb;
+	volatile void __iomem *d_min_first_plane_dpb_size;
+	volatile void __iomem *d_min_second_plane_dpb_size;
+	volatile void __iomem *d_min_third_plane_dpb_size;/* only v8 */
+	volatile void __iomem *d_min_num_mv;
+	volatile void __iomem *d_mvc_num_views;
+	volatile void __iomem *d_min_num_dis;/* only v7 */
+	volatile void __iomem *d_min_first_dis_size;/* only v7 */
+	volatile void __iomem *d_min_second_dis_size;/* only v7 */
+	volatile void __iomem *d_min_third_dis_size;/* only v7 */
+	volatile void __iomem *d_post_filter_luma_dpb0;/*  v7 and v8 */
+	volatile void __iomem *d_post_filter_luma_dpb1;/* v7 and v8 */
+	volatile void __iomem *d_post_filter_luma_dpb2;/* only v7 */
+	volatile void __iomem *d_post_filter_chroma_dpb0;/* v7 and v8 */
+	volatile void __iomem *d_post_filter_chroma_dpb1;/* v7 and v8 */
+	volatile void __iomem *d_post_filter_chroma_dpb2;/* only v7 */
+	volatile void __iomem *d_num_dpb;
+	volatile void __iomem *d_num_mv;
+	volatile void __iomem *d_init_buffer_options;
+	volatile void __iomem *d_first_plane_dpb_stride_size;/* only v8 */
+	volatile void __iomem *d_second_plane_dpb_stride_size;/* only v8 */
+	volatile void __iomem *d_third_plane_dpb_stride_size;/* only v8 */
+	volatile void __iomem *d_first_plane_dpb_size;
+	volatile void __iomem *d_second_plane_dpb_size;
+	volatile void __iomem *d_third_plane_dpb_size;/* only v8 */
+	volatile void __iomem *d_mv_buffer_size;
+	volatile void __iomem *d_first_plane_dpb;
+	volatile void __iomem *d_second_plane_dpb;
+	volatile void __iomem *d_third_plane_dpb;
+	volatile void __iomem *d_mv_buffer;
+	volatile void __iomem *d_scratch_buffer_addr;
+	volatile void __iomem *d_scratch_buffer_size;
+	volatile void __iomem *d_metadata_buffer_addr;
+	volatile void __iomem *d_metadata_buffer_size;
+	volatile void __iomem *d_nal_start_options;/* v7 and v8 */
+	volatile void __iomem *d_cpb_buffer_addr;
+	volatile void __iomem *d_cpb_buffer_size;
+	volatile void __iomem *d_available_dpb_flag_upper;
+	volatile void __iomem *d_available_dpb_flag_lower;
+	volatile void __iomem *d_cpb_buffer_offset;
+	volatile void __iomem *d_slice_if_enable;
+	volatile void __iomem *d_picture_tag;
+	volatile void __iomem *d_stream_data_size;
+	volatile void __iomem *d_dynamic_dpb_flag_upper;/* v7 and v8 */
+	volatile void __iomem *d_dynamic_dpb_flag_lower;/* v7 and v8 */
+	volatile void __iomem *d_display_frame_width;
+	volatile void __iomem *d_display_frame_height;
+	volatile void __iomem *d_display_status;
+	volatile void __iomem *d_display_first_plane_addr;
+	volatile void __iomem *d_display_second_plane_addr;
+	volatile void __iomem *d_display_third_plane_addr;/* only v8 */
+	volatile void __iomem *d_display_frame_type;
+	volatile void __iomem *d_display_crop_info1;
+	volatile void __iomem *d_display_crop_info2;
+	volatile void __iomem *d_display_picture_profile;
+	volatile void __iomem *d_display_luma_crc;/* v7 and v8 */
+	volatile void __iomem *d_display_chroma0_crc;/* v7 and v8 */
+	volatile void __iomem *d_display_chroma1_crc;/* only v8 */
+	volatile void __iomem *d_display_luma_crc_top;/* only v6 */
+	volatile void __iomem *d_display_chroma_crc_top;/* only v6 */
+	volatile void __iomem *d_display_luma_crc_bot;/* only v6 */
+	volatile void __iomem *d_display_chroma_crc_bot;/* only v6 */
+	volatile void __iomem *d_display_aspect_ratio;
+	volatile void __iomem *d_display_extended_ar;
+	volatile void __iomem *d_decoded_frame_width;
+	volatile void __iomem *d_decoded_frame_height;
+	volatile void __iomem *d_decoded_status;
+	volatile void __iomem *d_decoded_first_plane_addr;
+	volatile void __iomem *d_decoded_second_plane_addr;
+	volatile void __iomem *d_decoded_third_plane_addr;/* only v8 */
+	volatile void __iomem *d_decoded_frame_type;
+	volatile void __iomem *d_decoded_crop_info1;
+	volatile void __iomem *d_decoded_crop_info2;
+	volatile void __iomem *d_decoded_picture_profile;
+	volatile void __iomem *d_decoded_nal_size;
+	volatile void __iomem *d_decoded_luma_crc;
+	volatile void __iomem *d_decoded_chroma0_crc;
+	volatile void __iomem *d_decoded_chroma1_crc;/* only v8 */
+	volatile void __iomem *d_ret_picture_tag_top;
+	volatile void __iomem *d_ret_picture_tag_bot;
+	volatile void __iomem *d_ret_picture_time_top;
+	volatile void __iomem *d_ret_picture_time_bot;
+	volatile void __iomem *d_chroma_format;
+	volatile void __iomem *d_vc1_info;/* v7 and v8 */
+	volatile void __iomem *d_mpeg4_info;
+	volatile void __iomem *d_h264_info;
+	volatile void __iomem *d_metadata_addr_concealed_mb;
+	volatile void __iomem *d_metadata_size_concealed_mb;
+	volatile void __iomem *d_metadata_addr_vc1_param;
+	volatile void __iomem *d_metadata_size_vc1_param;
+	volatile void __iomem *d_metadata_addr_sei_nal;
+	volatile void __iomem *d_metadata_size_sei_nal;
+	volatile void __iomem *d_metadata_addr_vui;
+	volatile void __iomem *d_metadata_size_vui;
+	volatile void __iomem *d_metadata_addr_mvcvui;/* v7 and v8 */
+	volatile void __iomem *d_metadata_size_mvcvui;/* v7 and v8 */
+	volatile void __iomem *d_mvc_view_id;
+	volatile void __iomem *d_frame_pack_sei_avail;
+	volatile void __iomem *d_frame_pack_arrgment_id;
+	volatile void __iomem *d_frame_pack_sei_info;
+	volatile void __iomem *d_frame_pack_grid_pos;
+	volatile void __iomem *d_display_recovery_sei_info;/* v7 and v8 */
+	volatile void __iomem *d_decoded_recovery_sei_info;/* v7 and v8 */
+	volatile void __iomem *d_display_first_addr;/* only v7 */
+	volatile void __iomem *d_display_second_addr;/* only v7 */
+	volatile void __iomem *d_display_third_addr;/* only v7 */
+	volatile void __iomem *d_decoded_first_addr;/* only v7 */
+	volatile void __iomem *d_decoded_second_addr;/* only v7 */
+	volatile void __iomem *d_decoded_third_addr;/* only v7 */
+	volatile void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */
+	volatile void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */
 
 	/* encoder registers */
-	void *e_frame_width;
-	void *e_frame_height;
-	void *e_cropped_frame_width;
-	void *e_cropped_frame_height;
-	void *e_frame_crop_offset;
-	void *e_enc_options;
-	void *e_picture_profile;
-	void *e_vbv_buffer_size;
-	void *e_vbv_init_delay;
-	void *e_fixed_picture_qp;
-	void *e_rc_config;
-	void *e_rc_qp_bound;
-	void *e_rc_qp_bound_pb;/* v7 and v8 */
-	void *e_rc_mode;
-	void *e_mb_rc_config;
-	void *e_padding_ctrl;
-	void *e_air_threshold;
-	void *e_mv_hor_range;
-	void *e_mv_ver_range;
-	void *e_num_dpb;
-	void *e_luma_dpb;
-	void *e_chroma_dpb;
-	void *e_me_buffer;
-	void *e_scratch_buffer_addr;
-	void *e_scratch_buffer_size;
-	void *e_tmv_buffer0;
-	void *e_tmv_buffer1;
-	void *e_ir_buffer_addr;/* v7 and v8 */
-	void *e_source_first_plane_addr;
-	void *e_source_second_plane_addr;
-	void *e_source_third_plane_addr;/* v7 and v8 */
-	void *e_source_first_plane_stride;/* v7 and v8 */
-	void *e_source_second_plane_stride;/* v7 and v8 */
-	void *e_source_third_plane_stride;/* v7 and v8 */
-	void *e_stream_buffer_addr;
-	void *e_stream_buffer_size;
-	void *e_roi_buffer_addr;
-	void *e_param_change;
-	void *e_ir_size;
-	void *e_gop_config;
-	void *e_mslice_mode;
-	void *e_mslice_size_mb;
-	void *e_mslice_size_bits;
-	void *e_frame_insertion;
-	void *e_rc_frame_rate;
-	void *e_rc_bit_rate;
-	void *e_rc_roi_ctrl;
-	void *e_picture_tag;
-	void *e_bit_count_enable;
-	void *e_max_bit_count;
-	void *e_min_bit_count;
-	void *e_metadata_buffer_addr;
-	void *e_metadata_buffer_size;
-	void *e_encoded_source_first_plane_addr;
-	void *e_encoded_source_second_plane_addr;
-	void *e_encoded_source_third_plane_addr;/* v7 and v8 */
-	void *e_stream_size;
-	void *e_slice_type;
-	void *e_picture_count;
-	void *e_ret_picture_tag;
-	void *e_stream_buffer_write_pointer; /*  only v6 */
-	void *e_recon_luma_dpb_addr;
-	void *e_recon_chroma_dpb_addr;
-	void *e_metadata_addr_enc_slice;
-	void *e_metadata_size_enc_slice;
-	void *e_mpeg4_options;
-	void *e_mpeg4_hec_period;
-	void *e_aspect_ratio;
-	void *e_extended_sar;
-	void *e_h264_options;
-	void *e_h264_options_2;/* v7 and v8 */
-	void *e_h264_lf_alpha_offset;
-	void *e_h264_lf_beta_offset;
-	void *e_h264_i_period;
-	void *e_h264_fmo_slice_grp_map_type;
-	void *e_h264_fmo_num_slice_grp_minus1;
-	void *e_h264_fmo_slice_grp_change_dir;
-	void *e_h264_fmo_slice_grp_change_rate_minus1;
-	void *e_h264_fmo_run_length_minus1_0;
-	void *e_h264_aso_slice_order_0;
-	void *e_h264_chroma_qp_offset;
-	void *e_h264_num_t_layer;
-	void *e_h264_hierarchical_qp_layer0;
-	void *e_h264_frame_packing_sei_info;
-	void *e_h264_nal_control;/* v7 and v8 */
-	void *e_mvc_frame_qp_view1;
-	void *e_mvc_rc_bit_rate_view1;
-	void *e_mvc_rc_qbound_view1;
-	void *e_mvc_rc_mode_view1;
-	void *e_mvc_inter_view_prediction_on;
-	void *e_vp8_options;/* v7 and v8 */
-	void *e_vp8_filter_options;/* v7 and v8 */
-	void *e_vp8_golden_frame_option;/* v7 and v8 */
-	void *e_vp8_num_t_layer;/* v7 and v8 */
-	void *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
-	void *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
-	void *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
+	volatile void __iomem *e_frame_width;
+	volatile void __iomem *e_frame_height;
+	volatile void __iomem *e_cropped_frame_width;
+	volatile void __iomem *e_cropped_frame_height;
+	volatile void __iomem *e_frame_crop_offset;
+	volatile void __iomem *e_enc_options;
+	volatile void __iomem *e_picture_profile;
+	volatile void __iomem *e_vbv_buffer_size;
+	volatile void __iomem *e_vbv_init_delay;
+	volatile void __iomem *e_fixed_picture_qp;
+	volatile void __iomem *e_rc_config;
+	volatile void __iomem *e_rc_qp_bound;
+	volatile void __iomem *e_rc_qp_bound_pb;/* v7 and v8 */
+	volatile void __iomem *e_rc_mode;
+	volatile void __iomem *e_mb_rc_config;
+	volatile void __iomem *e_padding_ctrl;
+	volatile void __iomem *e_air_threshold;
+	volatile void __iomem *e_mv_hor_range;
+	volatile void __iomem *e_mv_ver_range;
+	volatile void __iomem *e_num_dpb;
+	volatile void __iomem *e_luma_dpb;
+	volatile void __iomem *e_chroma_dpb;
+	volatile void __iomem *e_me_buffer;
+	volatile void __iomem *e_scratch_buffer_addr;
+	volatile void __iomem *e_scratch_buffer_size;
+	volatile void __iomem *e_tmv_buffer0;
+	volatile void __iomem *e_tmv_buffer1;
+	volatile void __iomem *e_ir_buffer_addr;/* v7 and v8 */
+	volatile void __iomem *e_source_first_plane_addr;
+	volatile void __iomem *e_source_second_plane_addr;
+	volatile void __iomem *e_source_third_plane_addr;/* v7 and v8 */
+	volatile void __iomem *e_source_first_plane_stride;/* v7 and v8 */
+	volatile void __iomem *e_source_second_plane_stride;/* v7 and v8 */
+	volatile void __iomem *e_source_third_plane_stride;/* v7 and v8 */
+	volatile void __iomem *e_stream_buffer_addr;
+	volatile void __iomem *e_stream_buffer_size;
+	volatile void __iomem *e_roi_buffer_addr;
+	volatile void __iomem *e_param_change;
+	volatile void __iomem *e_ir_size;
+	volatile void __iomem *e_gop_config;
+	volatile void __iomem *e_mslice_mode;
+	volatile void __iomem *e_mslice_size_mb;
+	volatile void __iomem *e_mslice_size_bits;
+	volatile void __iomem *e_frame_insertion;
+	volatile void __iomem *e_rc_frame_rate;
+	volatile void __iomem *e_rc_bit_rate;
+	volatile void __iomem *e_rc_roi_ctrl;
+	volatile void __iomem *e_picture_tag;
+	volatile void __iomem *e_bit_count_enable;
+	volatile void __iomem *e_max_bit_count;
+	volatile void __iomem *e_min_bit_count;
+	volatile void __iomem *e_metadata_buffer_addr;
+	volatile void __iomem *e_metadata_buffer_size;
+	volatile void __iomem *e_encoded_source_first_plane_addr;
+	volatile void __iomem *e_encoded_source_second_plane_addr;
+	volatile void __iomem *e_encoded_source_third_plane_addr;/* v7 and v8 */
+	volatile void __iomem *e_stream_size;
+	volatile void __iomem *e_slice_type;
+	volatile void __iomem *e_picture_count;
+	volatile void __iomem *e_ret_picture_tag;
+	volatile void __iomem *e_stream_buffer_write_pointer; /*  only v6 */
+	volatile void __iomem *e_recon_luma_dpb_addr;
+	volatile void __iomem *e_recon_chroma_dpb_addr;
+	volatile void __iomem *e_metadata_addr_enc_slice;
+	volatile void __iomem *e_metadata_size_enc_slice;
+	volatile void __iomem *e_mpeg4_options;
+	volatile void __iomem *e_mpeg4_hec_period;
+	volatile void __iomem *e_aspect_ratio;
+	volatile void __iomem *e_extended_sar;
+	volatile void __iomem *e_h264_options;
+	volatile void __iomem *e_h264_options_2;/* v7 and v8 */
+	volatile void __iomem *e_h264_lf_alpha_offset;
+	volatile void __iomem *e_h264_lf_beta_offset;
+	volatile void __iomem *e_h264_i_period;
+	volatile void __iomem *e_h264_fmo_slice_grp_map_type;
+	volatile void __iomem *e_h264_fmo_num_slice_grp_minus1;
+	volatile void __iomem *e_h264_fmo_slice_grp_change_dir;
+	volatile void __iomem *e_h264_fmo_slice_grp_change_rate_minus1;
+	volatile void __iomem *e_h264_fmo_run_length_minus1_0;
+	volatile void __iomem *e_h264_aso_slice_order_0;
+	volatile void __iomem *e_h264_chroma_qp_offset;
+	volatile void __iomem *e_h264_num_t_layer;
+	volatile void __iomem *e_h264_hierarchical_qp_layer0;
+	volatile void __iomem *e_h264_frame_packing_sei_info;
+	volatile void __iomem *e_h264_nal_control;/* v7 and v8 */
+	volatile void __iomem *e_mvc_frame_qp_view1;
+	volatile void __iomem *e_mvc_rc_bit_rate_view1;
+	volatile void __iomem *e_mvc_rc_qbound_view1;
+	volatile void __iomem *e_mvc_rc_mode_view1;
+	volatile void __iomem *e_mvc_inter_view_prediction_on;
+	volatile void __iomem *e_vp8_options;/* v7 and v8 */
+	volatile void __iomem *e_vp8_filter_options;/* v7 and v8 */
+	volatile void __iomem *e_vp8_golden_frame_option;/* v7 and v8 */
+	volatile void __iomem *e_vp8_num_t_layer;/* v7 and v8 */
+	volatile void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
+	volatile void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
+	volatile void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
 };
 
 struct s5p_mfc_hw_ops {
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
index 58ec7bb..7cf0796 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
@@ -228,6 +228,7 @@
 	ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, &ctx->shm);
 	if (ret) {
 		mfc_err("Failed to allocate shared memory buffer\n");
+		s5p_mfc_release_priv_buf(dev->mem_dev_l, &ctx->ctx);
 		return ret;
 	}
 
@@ -262,7 +263,7 @@
 static void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data,
 			unsigned int ofs)
 {
-	writel(data, (ctx->shm.virt + ofs));
+	writel(data, (volatile void __iomem *)(ctx->shm.virt + ofs));
 	wmb();
 }
 
@@ -270,7 +271,7 @@
 				unsigned int ofs)
 {
 	rmb();
-	return readl(ctx->shm.virt + ofs);
+	return readl((volatile void __iomem *)(ctx->shm.virt + ofs));
 }
 
 static void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx)
@@ -377,7 +378,7 @@
 /* Set decoding frame buffer */
 static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx)
 {
-	unsigned int frame_size, i;
+	unsigned int frame_size_lu, i;
 	unsigned int frame_size_ch, frame_size_mv;
 	struct s5p_mfc_dev *dev = ctx->dev;
 	unsigned int dpb;
@@ -465,23 +466,23 @@
 			ctx->codec_mode);
 		return -EINVAL;
 	}
-	frame_size = ctx->luma_size;
+	frame_size_lu = ctx->luma_size;
 	frame_size_ch = ctx->chroma_size;
 	frame_size_mv = ctx->mv_size;
-	mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch,
+	mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size_lu, frame_size_ch,
 								frame_size_mv);
 	for (i = 0; i < ctx->total_dpb_count; i++) {
 		/* Bank2 */
-		mfc_debug(2, "Luma %d: %x\n", i,
+		mfc_debug(2, "Luma %d: %zx\n", i,
 					ctx->dst_bufs[i].cookie.raw.luma);
 		mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma),
 						S5P_FIMV_DEC_LUMA_ADR + i * 4);
-		mfc_debug(2, "\tChroma %d: %x\n", i,
+		mfc_debug(2, "\tChroma %d: %zx\n", i,
 					ctx->dst_bufs[i].cookie.raw.chroma);
 		mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma),
 					       S5P_FIMV_DEC_CHROMA_ADR + i * 4);
 		if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) {
-			mfc_debug(2, "\tBuf2: %x, size: %d\n",
+			mfc_debug(2, "\tBuf2: %zx, size: %d\n",
 							buf_addr2, buf_size2);
 			mfc_write(dev, OFFSETB(buf_addr2),
 						S5P_FIMV_H264_MV_ADR + i * 4);
@@ -489,14 +490,14 @@
 			buf_size2 -= frame_size_mv;
 		}
 	}
-	mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1);
+	mfc_debug(2, "Buf1: %zu, buf_size1: %d\n", buf_addr1, buf_size1);
 	mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n",
 			buf_size1,  buf_size2, ctx->total_dpb_count);
 	if (buf_size1 < 0 || buf_size2 < 0) {
 		mfc_debug(2, "Not enough memory has been allocated\n");
 		return -ENOMEM;
 	}
-	s5p_mfc_write_info_v5(ctx, frame_size, ALLOC_LUMA_DPB_SIZE);
+	s5p_mfc_write_info_v5(ctx, frame_size_lu, ALLOC_LUMA_DPB_SIZE);
 	s5p_mfc_write_info_v5(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE);
 	if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC)
 		s5p_mfc_write_info_v5(ctx, frame_size_mv, ALLOC_MV_SIZE);
@@ -566,7 +567,7 @@
 		enc_ref_c_size = ALIGN(guard_width * guard_height,
 				       S5P_FIMV_NV12MT_SALIGN);
 	}
-	mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2);
+	mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", buf_size1, buf_size2);
 	switch (ctx->codec_mode) {
 	case S5P_MFC_CODEC_H264_ENC:
 		for (i = 0; i < 2; i++) {
@@ -605,7 +606,7 @@
 					S5P_FIMV_H264_NBOR_INFO_ADR);
 		buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE;
 		buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE;
-		mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+		mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n",
 			buf_size1, buf_size2);
 		break;
 	case S5P_MFC_CODEC_MPEG4_ENC:
@@ -636,7 +637,7 @@
 						S5P_FIMV_MPEG4_ACDC_COEF_ADR);
 		buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
 		buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
-		mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+		mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n",
 			buf_size1, buf_size2);
 		break;
 	case S5P_MFC_CODEC_H263_ENC:
@@ -662,7 +663,7 @@
 		mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR);
 		buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
 		buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
-		mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+		mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n",
 			buf_size1, buf_size2);
 		break;
 	default:
@@ -1186,7 +1187,6 @@
 	struct s5p_mfc_dev *dev = ctx->dev;
 	struct s5p_mfc_buf *temp_vb;
 	unsigned long flags;
-	unsigned int index;
 
 	if (ctx->state == MFCINST_FINISHING) {
 		last_frame = MFC_DEC_LAST_FRAME;
@@ -1211,7 +1211,6 @@
 		vb2_dma_contig_plane_dma_addr(temp_vb->b, 0),
 		ctx->consumed_stream, temp_vb->b->v4l2_planes[0].bytesused);
 	spin_unlock_irqrestore(&dev->irqlock, flags);
-	index = temp_vb->b->v4l2_buf.index;
 	dev->curr_ctx = ctx->num;
 	s5p_mfc_clean_ctx_int_flags(ctx);
 	if (temp_vb->b->v4l2_planes[0].bytesused == 0) {
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index c1c12f8..8798b14 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -43,11 +43,6 @@
 	} while (0)
 #endif /* S5P_MFC_DEBUG_REGWRITE */
 
-#define READL(reg) \
-	(WARN_ON_ONCE(!(reg)) ? 0 : readl(reg))
-#define WRITEL(data, reg) \
-	(WARN_ON_ONCE(!(reg)) ? 0 : writel((data), (reg)))
-
 #define IS_MFCV6_V2(dev) (!IS_MFCV7_PLUS(dev) && dev->fw_ver == MFC_FW_V2)
 
 /* Allocate temporary buffers for decoding */
@@ -105,7 +100,7 @@
 						mb_width, mb_height),
 						S5P_FIMV_ME_BUFFER_ALIGN_V6);
 
-		mfc_debug(2, "recon luma size: %d chroma size: %d\n",
+		mfc_debug(2, "recon luma size: %zu chroma size: %zu\n",
 			  ctx->luma_dpb_size, ctx->chroma_dpb_size);
 	} else {
 		return -EINVAL;
@@ -416,10 +411,10 @@
 	mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x,\n"
 		"buf_size: 0x%08x (%d)\n",
 		ctx->inst_no, buf_addr, strm_size, strm_size);
-	WRITEL(strm_size, mfc_regs->d_stream_data_size);
-	WRITEL(buf_addr, mfc_regs->d_cpb_buffer_addr);
-	WRITEL(buf_size->cpb, mfc_regs->d_cpb_buffer_size);
-	WRITEL(start_num_byte, mfc_regs->d_cpb_buffer_offset);
+	writel(strm_size, mfc_regs->d_stream_data_size);
+	writel(buf_addr, mfc_regs->d_cpb_buffer_addr);
+	writel(buf_size->cpb, mfc_regs->d_cpb_buffer_size);
+	writel(start_num_byte, mfc_regs->d_cpb_buffer_offset);
 
 	mfc_debug_leave();
 	return 0;
@@ -443,17 +438,17 @@
 	mfc_debug(2, "Total DPB COUNT: %d\n", ctx->total_dpb_count);
 	mfc_debug(2, "Setting display delay to %d\n", ctx->display_delay);
 
-	WRITEL(ctx->total_dpb_count, mfc_regs->d_num_dpb);
-	WRITEL(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
-	WRITEL(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
+	writel(ctx->total_dpb_count, mfc_regs->d_num_dpb);
+	writel(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
+	writel(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
 
-	WRITEL(buf_addr1, mfc_regs->d_scratch_buffer_addr);
-	WRITEL(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
+	writel(buf_addr1, mfc_regs->d_scratch_buffer_addr);
+	writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
 
 	if (IS_MFCV8(dev)) {
-		WRITEL(ctx->img_width,
+		writel(ctx->img_width,
 			mfc_regs->d_first_plane_dpb_stride_size);
-		WRITEL(ctx->img_width,
+		writel(ctx->img_width,
 			mfc_regs->d_second_plane_dpb_stride_size);
 	}
 
@@ -462,8 +457,8 @@
 
 	if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
 			ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){
-		WRITEL(ctx->mv_size, mfc_regs->d_mv_buffer_size);
-		WRITEL(ctx->mv_count, mfc_regs->d_num_mv);
+		writel(ctx->mv_size, mfc_regs->d_mv_buffer_size);
+		writel(ctx->mv_count, mfc_regs->d_num_mv);
 	}
 
 	frame_size = ctx->luma_size;
@@ -474,13 +469,13 @@
 
 	for (i = 0; i < ctx->total_dpb_count; i++) {
 		/* Bank2 */
-		mfc_debug(2, "Luma %d: %x\n", i,
+		mfc_debug(2, "Luma %d: %zx\n", i,
 					ctx->dst_bufs[i].cookie.raw.luma);
-		WRITEL(ctx->dst_bufs[i].cookie.raw.luma,
+		writel(ctx->dst_bufs[i].cookie.raw.luma,
 				mfc_regs->d_first_plane_dpb + i * 4);
-		mfc_debug(2, "\tChroma %d: %x\n", i,
+		mfc_debug(2, "\tChroma %d: %zx\n", i,
 					ctx->dst_bufs[i].cookie.raw.chroma);
-		WRITEL(ctx->dst_bufs[i].cookie.raw.chroma,
+		writel(ctx->dst_bufs[i].cookie.raw.chroma,
 				mfc_regs->d_second_plane_dpb + i * 4);
 	}
 	if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
@@ -492,23 +487,23 @@
 			align_gap = buf_addr1 - align_gap;
 			buf_size1 -= align_gap;
 
-			mfc_debug(2, "\tBuf1: %x, size: %d\n",
+			mfc_debug(2, "\tBuf1: %zx, size: %d\n",
 					buf_addr1, buf_size1);
-			WRITEL(buf_addr1, mfc_regs->d_mv_buffer + i * 4);
+			writel(buf_addr1, mfc_regs->d_mv_buffer + i * 4);
 			buf_addr1 += frame_size_mv;
 			buf_size1 -= frame_size_mv;
 		}
 	}
 
-	mfc_debug(2, "Buf1: %u, buf_size1: %d (frames %d)\n",
+	mfc_debug(2, "Buf1: %zu, buf_size1: %d (frames %d)\n",
 			buf_addr1, buf_size1, ctx->total_dpb_count);
 	if (buf_size1 < 0) {
 		mfc_debug(2, "Not enough memory has been allocated.\n");
 		return -ENOMEM;
 	}
 
-	WRITEL(ctx->inst_no, mfc_regs->instance_id);
-	s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+	writel(ctx->inst_no, mfc_regs->instance_id);
+	s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
 			S5P_FIMV_CH_INIT_BUFS_V6, NULL);
 
 	mfc_debug(2, "After setting buffers.\n");
@@ -522,8 +517,8 @@
 	struct s5p_mfc_dev *dev = ctx->dev;
 	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
 
-	WRITEL(addr, mfc_regs->e_stream_buffer_addr); /* 16B align */
-	WRITEL(size, mfc_regs->e_stream_buffer_size);
+	writel(addr, mfc_regs->e_stream_buffer_addr); /* 16B align */
+	writel(size, mfc_regs->e_stream_buffer_size);
 
 	mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%d\n",
 		  addr, size);
@@ -537,8 +532,8 @@
 	struct s5p_mfc_dev *dev = ctx->dev;
 	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
 
-	WRITEL(y_addr, mfc_regs->e_source_first_plane_addr);
-	WRITEL(c_addr, mfc_regs->e_source_second_plane_addr);
+	writel(y_addr, mfc_regs->e_source_first_plane_addr);
+	writel(c_addr, mfc_regs->e_source_second_plane_addr);
 
 	mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr);
 	mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr);
@@ -551,11 +546,11 @@
 	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
 	unsigned long enc_recon_y_addr, enc_recon_c_addr;
 
-	*y_addr = READL(mfc_regs->e_encoded_source_first_plane_addr);
-	*c_addr = READL(mfc_regs->e_encoded_source_second_plane_addr);
+	*y_addr = readl(mfc_regs->e_encoded_source_first_plane_addr);
+	*c_addr = readl(mfc_regs->e_encoded_source_second_plane_addr);
 
-	enc_recon_y_addr = READL(mfc_regs->e_recon_luma_dpb_addr);
-	enc_recon_c_addr = READL(mfc_regs->e_recon_chroma_dpb_addr);
+	enc_recon_y_addr = readl(mfc_regs->e_recon_luma_dpb_addr);
+	enc_recon_c_addr = readl(mfc_regs->e_recon_chroma_dpb_addr);
 
 	mfc_debug(2, "recon y addr: 0x%08lx\n", enc_recon_y_addr);
 	mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr);
@@ -577,36 +572,36 @@
 	mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1);
 
 	for (i = 0; i < ctx->pb_count; i++) {
-		WRITEL(buf_addr1, mfc_regs->e_luma_dpb + (4 * i));
+		writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i));
 		buf_addr1 += ctx->luma_dpb_size;
-		WRITEL(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i));
+		writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i));
 		buf_addr1 += ctx->chroma_dpb_size;
-		WRITEL(buf_addr1, mfc_regs->e_me_buffer + (4 * i));
+		writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i));
 		buf_addr1 += ctx->me_buffer_size;
 		buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size +
 			ctx->me_buffer_size);
 	}
 
-	WRITEL(buf_addr1, mfc_regs->e_scratch_buffer_addr);
-	WRITEL(ctx->scratch_buf_size, mfc_regs->e_scratch_buffer_size);
+	writel(buf_addr1, mfc_regs->e_scratch_buffer_addr);
+	writel(ctx->scratch_buf_size, mfc_regs->e_scratch_buffer_size);
 	buf_addr1 += ctx->scratch_buf_size;
 	buf_size1 -= ctx->scratch_buf_size;
 
-	WRITEL(buf_addr1, mfc_regs->e_tmv_buffer0);
+	writel(buf_addr1, mfc_regs->e_tmv_buffer0);
 	buf_addr1 += ctx->tmv_buffer_size >> 1;
-	WRITEL(buf_addr1, mfc_regs->e_tmv_buffer1);
+	writel(buf_addr1, mfc_regs->e_tmv_buffer1);
 	buf_addr1 += ctx->tmv_buffer_size >> 1;
 	buf_size1 -= ctx->tmv_buffer_size;
 
-	mfc_debug(2, "Buf1: %u, buf_size1: %d (ref frames %d)\n",
+	mfc_debug(2, "Buf1: %zu, buf_size1: %d (ref frames %d)\n",
 			buf_addr1, buf_size1, ctx->pb_count);
 	if (buf_size1 < 0) {
 		mfc_debug(2, "Not enough memory has been allocated.\n");
 		return -ENOMEM;
 	}
 
-	WRITEL(ctx->inst_no, mfc_regs->instance_id);
-	s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+	writel(ctx->inst_no, mfc_regs->instance_id);
+	s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
 			S5P_FIMV_CH_INIT_BUFS_V6, NULL);
 
 	mfc_debug_leave();
@@ -621,15 +616,15 @@
 
 	/* multi-slice control */
 	/* multi-slice MB number or bit size */
-	WRITEL(ctx->slice_mode, mfc_regs->e_mslice_mode);
+	writel(ctx->slice_mode, mfc_regs->e_mslice_mode);
 	if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
-		WRITEL(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb);
+		writel(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb);
 	} else if (ctx->slice_mode ==
 			V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
-		WRITEL(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits);
+		writel(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits);
 	} else {
-		WRITEL(0x0, mfc_regs->e_mslice_size_mb);
-		WRITEL(0x0, mfc_regs->e_mslice_size_bits);
+		writel(0x0, mfc_regs->e_mslice_size_mb);
+		writel(0x0, mfc_regs->e_mslice_size_bits);
 	}
 
 	return 0;
@@ -645,21 +640,21 @@
 	mfc_debug_enter();
 
 	/* width */
-	WRITEL(ctx->img_width, mfc_regs->e_frame_width); /* 16 align */
+	writel(ctx->img_width, mfc_regs->e_frame_width); /* 16 align */
 	/* height */
-	WRITEL(ctx->img_height, mfc_regs->e_frame_height); /* 16 align */
+	writel(ctx->img_height, mfc_regs->e_frame_height); /* 16 align */
 
 	/* cropped width */
-	WRITEL(ctx->img_width, mfc_regs->e_cropped_frame_width);
+	writel(ctx->img_width, mfc_regs->e_cropped_frame_width);
 	/* cropped height */
-	WRITEL(ctx->img_height, mfc_regs->e_cropped_frame_height);
+	writel(ctx->img_height, mfc_regs->e_cropped_frame_height);
 	/* cropped offset */
-	WRITEL(0x0, mfc_regs->e_frame_crop_offset);
+	writel(0x0, mfc_regs->e_frame_crop_offset);
 
 	/* pictype : IDR period */
 	reg = 0;
 	reg |= p->gop_size & 0xFFFF;
-	WRITEL(reg, mfc_regs->e_gop_config);
+	writel(reg, mfc_regs->e_gop_config);
 
 	/* multi-slice control */
 	/* multi-slice MB number or bit size */
@@ -667,65 +662,65 @@
 	reg = 0;
 	if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
 		reg |= (0x1 << 3);
-		WRITEL(reg, mfc_regs->e_enc_options);
+		writel(reg, mfc_regs->e_enc_options);
 		ctx->slice_size.mb = p->slice_mb;
 	} else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
 		reg |= (0x1 << 3);
-		WRITEL(reg, mfc_regs->e_enc_options);
+		writel(reg, mfc_regs->e_enc_options);
 		ctx->slice_size.bits = p->slice_bit;
 	} else {
 		reg &= ~(0x1 << 3);
-		WRITEL(reg, mfc_regs->e_enc_options);
+		writel(reg, mfc_regs->e_enc_options);
 	}
 
 	s5p_mfc_set_slice_mode(ctx);
 
 	/* cyclic intra refresh */
-	WRITEL(p->intra_refresh_mb, mfc_regs->e_ir_size);
-	reg = READL(mfc_regs->e_enc_options);
+	writel(p->intra_refresh_mb, mfc_regs->e_ir_size);
+	reg = readl(mfc_regs->e_enc_options);
 	if (p->intra_refresh_mb == 0)
 		reg &= ~(0x1 << 4);
 	else
 		reg |= (0x1 << 4);
-	WRITEL(reg, mfc_regs->e_enc_options);
+	writel(reg, mfc_regs->e_enc_options);
 
 	/* 'NON_REFERENCE_STORE_ENABLE' for debugging */
-	reg = READL(mfc_regs->e_enc_options);
+	reg = readl(mfc_regs->e_enc_options);
 	reg &= ~(0x1 << 9);
-	WRITEL(reg, mfc_regs->e_enc_options);
+	writel(reg, mfc_regs->e_enc_options);
 
 	/* memory structure cur. frame */
 	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) {
 		/* 0: Linear, 1: 2D tiled*/
-		reg = READL(mfc_regs->e_enc_options);
+		reg = readl(mfc_regs->e_enc_options);
 		reg &= ~(0x1 << 7);
-		WRITEL(reg, mfc_regs->e_enc_options);
+		writel(reg, mfc_regs->e_enc_options);
 		/* 0: NV12(CbCr), 1: NV21(CrCb) */
-		WRITEL(0x0, mfc_regs->pixel_format);
+		writel(0x0, mfc_regs->pixel_format);
 	} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M) {
 		/* 0: Linear, 1: 2D tiled*/
-		reg = READL(mfc_regs->e_enc_options);
+		reg = readl(mfc_regs->e_enc_options);
 		reg &= ~(0x1 << 7);
-		WRITEL(reg, mfc_regs->e_enc_options);
+		writel(reg, mfc_regs->e_enc_options);
 		/* 0: NV12(CbCr), 1: NV21(CrCb) */
-		WRITEL(0x1, mfc_regs->pixel_format);
+		writel(0x1, mfc_regs->pixel_format);
 	} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) {
 		/* 0: Linear, 1: 2D tiled*/
-		reg = READL(mfc_regs->e_enc_options);
+		reg = readl(mfc_regs->e_enc_options);
 		reg |= (0x1 << 7);
-		WRITEL(reg, mfc_regs->e_enc_options);
+		writel(reg, mfc_regs->e_enc_options);
 		/* 0: NV12(CbCr), 1: NV21(CrCb) */
-		WRITEL(0x0, mfc_regs->pixel_format);
+		writel(0x0, mfc_regs->pixel_format);
 	}
 
 	/* memory structure recon. frame */
 	/* 0: Linear, 1: 2D tiled */
-	reg = READL(mfc_regs->e_enc_options);
+	reg = readl(mfc_regs->e_enc_options);
 	reg |= (0x1 << 8);
-	WRITEL(reg, mfc_regs->e_enc_options);
+	writel(reg, mfc_regs->e_enc_options);
 
 	/* padding control & value */
-	WRITEL(0x0, mfc_regs->e_padding_ctrl);
+	writel(0x0, mfc_regs->e_padding_ctrl);
 	if (p->pad) {
 		reg = 0;
 		/** enable */
@@ -736,64 +731,64 @@
 		reg |= ((p->pad_cb & 0xFF) << 8);
 		/** y value */
 		reg |= p->pad_luma & 0xFF;
-		WRITEL(reg, mfc_regs->e_padding_ctrl);
+		writel(reg, mfc_regs->e_padding_ctrl);
 	}
 
 	/* rate control config. */
 	reg = 0;
 	/* frame-level rate control */
 	reg |= ((p->rc_frame & 0x1) << 9);
-	WRITEL(reg, mfc_regs->e_rc_config);
+	writel(reg, mfc_regs->e_rc_config);
 
 	/* bit rate */
 	if (p->rc_frame)
-		WRITEL(p->rc_bitrate,
+		writel(p->rc_bitrate,
 			mfc_regs->e_rc_bit_rate);
 	else
-		WRITEL(1, mfc_regs->e_rc_bit_rate);
+		writel(1, mfc_regs->e_rc_bit_rate);
 
 	/* reaction coefficient */
 	if (p->rc_frame) {
 		if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */
-			WRITEL(1, mfc_regs->e_rc_mode);
+			writel(1, mfc_regs->e_rc_mode);
 		else					  /* loose CBR */
-			WRITEL(2, mfc_regs->e_rc_mode);
+			writel(2, mfc_regs->e_rc_mode);
 	}
 
 	/* seq header ctrl */
-	reg = READL(mfc_regs->e_enc_options);
+	reg = readl(mfc_regs->e_enc_options);
 	reg &= ~(0x1 << 2);
 	reg |= ((p->seq_hdr_mode & 0x1) << 2);
 
 	/* frame skip mode */
 	reg &= ~(0x3);
 	reg |= (p->frame_skip_mode & 0x3);
-	WRITEL(reg, mfc_regs->e_enc_options);
+	writel(reg, mfc_regs->e_enc_options);
 
 	/* 'DROP_CONTROL_ENABLE', disable */
-	reg = READL(mfc_regs->e_rc_config);
+	reg = readl(mfc_regs->e_rc_config);
 	reg &= ~(0x1 << 10);
-	WRITEL(reg, mfc_regs->e_rc_config);
+	writel(reg, mfc_regs->e_rc_config);
 
 	/* setting for MV range [16, 256] */
 	reg = (p->mv_h_range & S5P_FIMV_E_MV_RANGE_V6_MASK);
-	WRITEL(reg, mfc_regs->e_mv_hor_range);
+	writel(reg, mfc_regs->e_mv_hor_range);
 
 	reg = (p->mv_v_range & S5P_FIMV_E_MV_RANGE_V6_MASK);
-	WRITEL(reg, mfc_regs->e_mv_ver_range);
+	writel(reg, mfc_regs->e_mv_ver_range);
 
-	WRITEL(0x0, mfc_regs->e_frame_insertion);
-	WRITEL(0x0, mfc_regs->e_roi_buffer_addr);
-	WRITEL(0x0, mfc_regs->e_param_change);
-	WRITEL(0x0, mfc_regs->e_rc_roi_ctrl);
-	WRITEL(0x0, mfc_regs->e_picture_tag);
+	writel(0x0, mfc_regs->e_frame_insertion);
+	writel(0x0, mfc_regs->e_roi_buffer_addr);
+	writel(0x0, mfc_regs->e_param_change);
+	writel(0x0, mfc_regs->e_rc_roi_ctrl);
+	writel(0x0, mfc_regs->e_picture_tag);
 
-	WRITEL(0x0, mfc_regs->e_bit_count_enable);
-	WRITEL(0x0, mfc_regs->e_max_bit_count);
-	WRITEL(0x0, mfc_regs->e_min_bit_count);
+	writel(0x0, mfc_regs->e_bit_count_enable);
+	writel(0x0, mfc_regs->e_max_bit_count);
+	writel(0x0, mfc_regs->e_min_bit_count);
 
-	WRITEL(0x0, mfc_regs->e_metadata_buffer_addr);
-	WRITEL(0x0, mfc_regs->e_metadata_buffer_size);
+	writel(0x0, mfc_regs->e_metadata_buffer_addr);
+	writel(0x0, mfc_regs->e_metadata_buffer_size);
 
 	mfc_debug_leave();
 
@@ -814,10 +809,10 @@
 	s5p_mfc_set_enc_params(ctx);
 
 	/* pictype : number of B */
-	reg = READL(mfc_regs->e_gop_config);
+	reg = readl(mfc_regs->e_gop_config);
 	reg &= ~(0x3 << 16);
 	reg |= ((p->num_b_frame & 0x3) << 16);
-	WRITEL(reg, mfc_regs->e_gop_config);
+	writel(reg, mfc_regs->e_gop_config);
 
 	/* profile & level */
 	reg = 0;
@@ -825,19 +820,19 @@
 	reg |= ((p_h264->level & 0xFF) << 8);
 	/** profile - 0 ~ 3 */
 	reg |= p_h264->profile & 0x3F;
-	WRITEL(reg, mfc_regs->e_picture_profile);
+	writel(reg, mfc_regs->e_picture_profile);
 
 	/* rate control config. */
-	reg = READL(mfc_regs->e_rc_config);
+	reg = readl(mfc_regs->e_rc_config);
 	/** macroblock level rate control */
 	reg &= ~(0x1 << 8);
 	reg |= ((p->rc_mb & 0x1) << 8);
-	WRITEL(reg, mfc_regs->e_rc_config);
+	writel(reg, mfc_regs->e_rc_config);
 
 	/** frame QP */
 	reg &= ~(0x3F);
 	reg |= p_h264->rc_frame_qp & 0x3F;
-	WRITEL(reg, mfc_regs->e_rc_config);
+	writel(reg, mfc_regs->e_rc_config);
 
 	/* max & min value of QP */
 	reg = 0;
@@ -845,16 +840,16 @@
 	reg |= ((p_h264->rc_max_qp & 0x3F) << 8);
 	/** min QP */
 	reg |= p_h264->rc_min_qp & 0x3F;
-	WRITEL(reg, mfc_regs->e_rc_qp_bound);
+	writel(reg, mfc_regs->e_rc_qp_bound);
 
 	/* other QPs */
-	WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
+	writel(0x0, mfc_regs->e_fixed_picture_qp);
 	if (!p->rc_frame && !p->rc_mb) {
 		reg = 0;
 		reg |= ((p_h264->rc_b_frame_qp & 0x3F) << 16);
 		reg |= ((p_h264->rc_p_frame_qp & 0x3F) << 8);
 		reg |= p_h264->rc_frame_qp & 0x3F;
-		WRITEL(reg, mfc_regs->e_fixed_picture_qp);
+		writel(reg, mfc_regs->e_fixed_picture_qp);
 	}
 
 	/* frame rate */
@@ -862,38 +857,38 @@
 		reg = 0;
 		reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
 		reg |= p->rc_framerate_denom & 0xFFFF;
-		WRITEL(reg, mfc_regs->e_rc_frame_rate);
+		writel(reg, mfc_regs->e_rc_frame_rate);
 	}
 
 	/* vbv buffer size */
 	if (p->frame_skip_mode ==
 			V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
-		WRITEL(p_h264->cpb_size & 0xFFFF,
+		writel(p_h264->cpb_size & 0xFFFF,
 				mfc_regs->e_vbv_buffer_size);
 
 		if (p->rc_frame)
-			WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
+			writel(p->vbv_delay, mfc_regs->e_vbv_init_delay);
 	}
 
 	/* interlace */
 	reg = 0;
 	reg |= ((p_h264->interlace & 0x1) << 3);
-	WRITEL(reg, mfc_regs->e_h264_options);
+	writel(reg, mfc_regs->e_h264_options);
 
 	/* height */
 	if (p_h264->interlace) {
-		WRITEL(ctx->img_height >> 1,
+		writel(ctx->img_height >> 1,
 				mfc_regs->e_frame_height); /* 32 align */
 		/* cropped height */
-		WRITEL(ctx->img_height >> 1,
+		writel(ctx->img_height >> 1,
 				mfc_regs->e_cropped_frame_height);
 	}
 
 	/* loop filter ctrl */
-	reg = READL(mfc_regs->e_h264_options);
+	reg = readl(mfc_regs->e_h264_options);
 	reg &= ~(0x3 << 1);
 	reg |= ((p_h264->loop_filter_mode & 0x3) << 1);
-	WRITEL(reg, mfc_regs->e_h264_options);
+	writel(reg, mfc_regs->e_h264_options);
 
 	/* loopfilter alpha offset */
 	if (p_h264->loop_filter_alpha < 0) {
@@ -903,7 +898,7 @@
 		reg = 0x00;
 		reg |= (p_h264->loop_filter_alpha & 0xF);
 	}
-	WRITEL(reg, mfc_regs->e_h264_lf_alpha_offset);
+	writel(reg, mfc_regs->e_h264_lf_alpha_offset);
 
 	/* loopfilter beta offset */
 	if (p_h264->loop_filter_beta < 0) {
@@ -913,28 +908,28 @@
 		reg = 0x00;
 		reg |= (p_h264->loop_filter_beta & 0xF);
 	}
-	WRITEL(reg, mfc_regs->e_h264_lf_beta_offset);
+	writel(reg, mfc_regs->e_h264_lf_beta_offset);
 
 	/* entropy coding mode */
-	reg = READL(mfc_regs->e_h264_options);
+	reg = readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1);
 	reg |= p_h264->entropy_mode & 0x1;
-	WRITEL(reg, mfc_regs->e_h264_options);
+	writel(reg, mfc_regs->e_h264_options);
 
 	/* number of ref. picture */
-	reg = READL(mfc_regs->e_h264_options);
+	reg = readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 7);
 	reg |= (((p_h264->num_ref_pic_4p - 1) & 0x1) << 7);
-	WRITEL(reg, mfc_regs->e_h264_options);
+	writel(reg, mfc_regs->e_h264_options);
 
 	/* 8x8 transform enable */
-	reg = READL(mfc_regs->e_h264_options);
+	reg = readl(mfc_regs->e_h264_options);
 	reg &= ~(0x3 << 12);
 	reg |= ((p_h264->_8x8_transform & 0x3) << 12);
-	WRITEL(reg, mfc_regs->e_h264_options);
+	writel(reg, mfc_regs->e_h264_options);
 
 	/* macroblock adaptive scaling features */
-	WRITEL(0x0, mfc_regs->e_mb_rc_config);
+	writel(0x0, mfc_regs->e_mb_rc_config);
 	if (p->rc_mb) {
 		reg = 0;
 		/** dark region */
@@ -945,95 +940,95 @@
 		reg |= ((p_h264->rc_mb_static & 0x1) << 1);
 		/** high activity region */
 		reg |= p_h264->rc_mb_activity & 0x1;
-		WRITEL(reg, mfc_regs->e_mb_rc_config);
+		writel(reg, mfc_regs->e_mb_rc_config);
 	}
 
 	/* aspect ratio VUI */
-	READL(mfc_regs->e_h264_options);
+	readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 5);
 	reg |= ((p_h264->vui_sar & 0x1) << 5);
-	WRITEL(reg, mfc_regs->e_h264_options);
+	writel(reg, mfc_regs->e_h264_options);
 
-	WRITEL(0x0, mfc_regs->e_aspect_ratio);
-	WRITEL(0x0, mfc_regs->e_extended_sar);
+	writel(0x0, mfc_regs->e_aspect_ratio);
+	writel(0x0, mfc_regs->e_extended_sar);
 	if (p_h264->vui_sar) {
 		/* aspect ration IDC */
 		reg = 0;
 		reg |= p_h264->vui_sar_idc & 0xFF;
-		WRITEL(reg, mfc_regs->e_aspect_ratio);
+		writel(reg, mfc_regs->e_aspect_ratio);
 		if (p_h264->vui_sar_idc == 0xFF) {
 			/* extended SAR */
 			reg = 0;
 			reg |= (p_h264->vui_ext_sar_width & 0xFFFF) << 16;
 			reg |= p_h264->vui_ext_sar_height & 0xFFFF;
-			WRITEL(reg, mfc_regs->e_extended_sar);
+			writel(reg, mfc_regs->e_extended_sar);
 		}
 	}
 
 	/* intra picture period for H.264 open GOP */
 	/* control */
-	READL(mfc_regs->e_h264_options);
+	readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 4);
 	reg |= ((p_h264->open_gop & 0x1) << 4);
-	WRITEL(reg, mfc_regs->e_h264_options);
+	writel(reg, mfc_regs->e_h264_options);
 
 	/* value */
-	WRITEL(0x0, mfc_regs->e_h264_i_period);
+	writel(0x0, mfc_regs->e_h264_i_period);
 	if (p_h264->open_gop) {
 		reg = 0;
 		reg |= p_h264->open_gop_size & 0xFFFF;
-		WRITEL(reg, mfc_regs->e_h264_i_period);
+		writel(reg, mfc_regs->e_h264_i_period);
 	}
 
 	/* 'WEIGHTED_BI_PREDICTION' for B is disable */
-	READL(mfc_regs->e_h264_options);
+	readl(mfc_regs->e_h264_options);
 	reg &= ~(0x3 << 9);
-	WRITEL(reg, mfc_regs->e_h264_options);
+	writel(reg, mfc_regs->e_h264_options);
 
 	/* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */
-	READL(mfc_regs->e_h264_options);
+	readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 14);
-	WRITEL(reg, mfc_regs->e_h264_options);
+	writel(reg, mfc_regs->e_h264_options);
 
 	/* ASO */
-	READL(mfc_regs->e_h264_options);
+	readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 6);
 	reg |= ((p_h264->aso & 0x1) << 6);
-	WRITEL(reg, mfc_regs->e_h264_options);
+	writel(reg, mfc_regs->e_h264_options);
 
 	/* hier qp enable */
-	READL(mfc_regs->e_h264_options);
+	readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 8);
 	reg |= ((p_h264->open_gop & 0x1) << 8);
-	WRITEL(reg, mfc_regs->e_h264_options);
+	writel(reg, mfc_regs->e_h264_options);
 	reg = 0;
 	if (p_h264->hier_qp && p_h264->hier_qp_layer) {
 		reg |= (p_h264->hier_qp_type & 0x1) << 0x3;
 		reg |= p_h264->hier_qp_layer & 0x7;
-		WRITEL(reg, mfc_regs->e_h264_num_t_layer);
+		writel(reg, mfc_regs->e_h264_num_t_layer);
 		/* QP value for each layer */
 		for (i = 0; i < p_h264->hier_qp_layer &&
 				i < ARRAY_SIZE(p_h264->hier_qp_layer_qp); i++) {
-			WRITEL(p_h264->hier_qp_layer_qp[i],
+			writel(p_h264->hier_qp_layer_qp[i],
 				mfc_regs->e_h264_hierarchical_qp_layer0
 				+ i * 4);
 		}
 	}
 	/* number of coding layer should be zero when hierarchical is disable */
-	WRITEL(reg, mfc_regs->e_h264_num_t_layer);
+	writel(reg, mfc_regs->e_h264_num_t_layer);
 
 	/* frame packing SEI generation */
-	READL(mfc_regs->e_h264_options);
+	readl(mfc_regs->e_h264_options);
 	reg &= ~(0x1 << 25);
 	reg |= ((p_h264->sei_frame_packing & 0x1) << 25);
-	WRITEL(reg, mfc_regs->e_h264_options);
+	writel(reg, mfc_regs->e_h264_options);
 	if (p_h264->sei_frame_packing) {
 		reg = 0;
 		/** current frame0 flag */
 		reg |= ((p_h264->sei_fp_curr_frame_0 & 0x1) << 2);
 		/** arrangement type */
 		reg |= p_h264->sei_fp_arrangement_type & 0x3;
-		WRITEL(reg, mfc_regs->e_h264_frame_packing_sei_info);
+		writel(reg, mfc_regs->e_h264_frame_packing_sei_info);
 	}
 
 	if (p_h264->fmo) {
@@ -1042,7 +1037,7 @@
 			if (p_h264->fmo_slice_grp > 4)
 				p_h264->fmo_slice_grp = 4;
 			for (i = 0; i < (p_h264->fmo_slice_grp & 0xF); i++)
-				WRITEL(p_h264->fmo_run_len[i] - 1,
+				writel(p_h264->fmo_run_len[i] - 1,
 					mfc_regs->e_h264_fmo_run_length_minus1_0
 					+ i * 4);
 			break;
@@ -1054,10 +1049,10 @@
 		case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN:
 			if (p_h264->fmo_slice_grp > 2)
 				p_h264->fmo_slice_grp = 2;
-			WRITEL(p_h264->fmo_chg_dir & 0x1,
+			writel(p_h264->fmo_chg_dir & 0x1,
 				mfc_regs->e_h264_fmo_slice_grp_change_dir);
 			/* the valid range is 0 ~ number of macroblocks -1 */
-			WRITEL(p_h264->fmo_chg_rate,
+			writel(p_h264->fmo_chg_rate,
 			mfc_regs->e_h264_fmo_slice_grp_change_rate_minus1);
 			break;
 		default:
@@ -1068,12 +1063,12 @@
 			break;
 		}
 
-		WRITEL(p_h264->fmo_map_type,
+		writel(p_h264->fmo_map_type,
 				mfc_regs->e_h264_fmo_slice_grp_map_type);
-		WRITEL(p_h264->fmo_slice_grp - 1,
+		writel(p_h264->fmo_slice_grp - 1,
 				mfc_regs->e_h264_fmo_num_slice_grp_minus1);
 	} else {
-		WRITEL(0, mfc_regs->e_h264_fmo_num_slice_grp_minus1);
+		writel(0, mfc_regs->e_h264_fmo_num_slice_grp_minus1);
 	}
 
 	mfc_debug_leave();
@@ -1094,10 +1089,10 @@
 	s5p_mfc_set_enc_params(ctx);
 
 	/* pictype : number of B */
-	reg = READL(mfc_regs->e_gop_config);
+	reg = readl(mfc_regs->e_gop_config);
 	reg &= ~(0x3 << 16);
 	reg |= ((p->num_b_frame & 0x3) << 16);
-	WRITEL(reg, mfc_regs->e_gop_config);
+	writel(reg, mfc_regs->e_gop_config);
 
 	/* profile & level */
 	reg = 0;
@@ -1105,19 +1100,19 @@
 	reg |= ((p_mpeg4->level & 0xFF) << 8);
 	/** profile - 0 ~ 1 */
 	reg |= p_mpeg4->profile & 0x3F;
-	WRITEL(reg, mfc_regs->e_picture_profile);
+	writel(reg, mfc_regs->e_picture_profile);
 
 	/* rate control config. */
-	reg = READL(mfc_regs->e_rc_config);
+	reg = readl(mfc_regs->e_rc_config);
 	/** macroblock level rate control */
 	reg &= ~(0x1 << 8);
 	reg |= ((p->rc_mb & 0x1) << 8);
-	WRITEL(reg, mfc_regs->e_rc_config);
+	writel(reg, mfc_regs->e_rc_config);
 
 	/** frame QP */
 	reg &= ~(0x3F);
 	reg |= p_mpeg4->rc_frame_qp & 0x3F;
-	WRITEL(reg, mfc_regs->e_rc_config);
+	writel(reg, mfc_regs->e_rc_config);
 
 	/* max & min value of QP */
 	reg = 0;
@@ -1125,16 +1120,16 @@
 	reg |= ((p_mpeg4->rc_max_qp & 0x3F) << 8);
 	/** min QP */
 	reg |= p_mpeg4->rc_min_qp & 0x3F;
-	WRITEL(reg, mfc_regs->e_rc_qp_bound);
+	writel(reg, mfc_regs->e_rc_qp_bound);
 
 	/* other QPs */
-	WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
+	writel(0x0, mfc_regs->e_fixed_picture_qp);
 	if (!p->rc_frame && !p->rc_mb) {
 		reg = 0;
 		reg |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 16);
 		reg |= ((p_mpeg4->rc_p_frame_qp & 0x3F) << 8);
 		reg |= p_mpeg4->rc_frame_qp & 0x3F;
-		WRITEL(reg, mfc_regs->e_fixed_picture_qp);
+		writel(reg, mfc_regs->e_fixed_picture_qp);
 	}
 
 	/* frame rate */
@@ -1142,21 +1137,21 @@
 		reg = 0;
 		reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
 		reg |= p->rc_framerate_denom & 0xFFFF;
-		WRITEL(reg, mfc_regs->e_rc_frame_rate);
+		writel(reg, mfc_regs->e_rc_frame_rate);
 	}
 
 	/* vbv buffer size */
 	if (p->frame_skip_mode ==
 			V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
-		WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
+		writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
 
 		if (p->rc_frame)
-			WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
+			writel(p->vbv_delay, mfc_regs->e_vbv_init_delay);
 	}
 
 	/* Disable HEC */
-	WRITEL(0x0, mfc_regs->e_mpeg4_options);
-	WRITEL(0x0, mfc_regs->e_mpeg4_hec_period);
+	writel(0x0, mfc_regs->e_mpeg4_options);
+	writel(0x0, mfc_regs->e_mpeg4_hec_period);
 
 	mfc_debug_leave();
 
@@ -1179,19 +1174,19 @@
 	reg = 0;
 	/** profile */
 	reg |= (0x1 << 4);
-	WRITEL(reg, mfc_regs->e_picture_profile);
+	writel(reg, mfc_regs->e_picture_profile);
 
 	/* rate control config. */
-	reg = READL(mfc_regs->e_rc_config);
+	reg = readl(mfc_regs->e_rc_config);
 	/** macroblock level rate control */
 	reg &= ~(0x1 << 8);
 	reg |= ((p->rc_mb & 0x1) << 8);
-	WRITEL(reg, mfc_regs->e_rc_config);
+	writel(reg, mfc_regs->e_rc_config);
 
 	/** frame QP */
 	reg &= ~(0x3F);
 	reg |= p_h263->rc_frame_qp & 0x3F;
-	WRITEL(reg, mfc_regs->e_rc_config);
+	writel(reg, mfc_regs->e_rc_config);
 
 	/* max & min value of QP */
 	reg = 0;
@@ -1199,16 +1194,16 @@
 	reg |= ((p_h263->rc_max_qp & 0x3F) << 8);
 	/** min QP */
 	reg |= p_h263->rc_min_qp & 0x3F;
-	WRITEL(reg, mfc_regs->e_rc_qp_bound);
+	writel(reg, mfc_regs->e_rc_qp_bound);
 
 	/* other QPs */
-	WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
+	writel(0x0, mfc_regs->e_fixed_picture_qp);
 	if (!p->rc_frame && !p->rc_mb) {
 		reg = 0;
 		reg |= ((p_h263->rc_b_frame_qp & 0x3F) << 16);
 		reg |= ((p_h263->rc_p_frame_qp & 0x3F) << 8);
 		reg |= p_h263->rc_frame_qp & 0x3F;
-		WRITEL(reg, mfc_regs->e_fixed_picture_qp);
+		writel(reg, mfc_regs->e_fixed_picture_qp);
 	}
 
 	/* frame rate */
@@ -1216,16 +1211,16 @@
 		reg = 0;
 		reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
 		reg |= p->rc_framerate_denom & 0xFFFF;
-		WRITEL(reg, mfc_regs->e_rc_frame_rate);
+		writel(reg, mfc_regs->e_rc_frame_rate);
 	}
 
 	/* vbv buffer size */
 	if (p->frame_skip_mode ==
 			V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
-		WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
+		writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
 
 		if (p->rc_frame)
-			WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
+			writel(p->vbv_delay, mfc_regs->e_vbv_init_delay);
 	}
 
 	mfc_debug_leave();
@@ -1247,57 +1242,57 @@
 	s5p_mfc_set_enc_params(ctx);
 
 	/* pictype : number of B */
-	reg = READL(mfc_regs->e_gop_config);
+	reg = readl(mfc_regs->e_gop_config);
 	reg &= ~(0x3 << 16);
 	reg |= ((p->num_b_frame & 0x3) << 16);
-	WRITEL(reg, mfc_regs->e_gop_config);
+	writel(reg, mfc_regs->e_gop_config);
 
 	/* profile - 0 ~ 3 */
 	reg = p_vp8->profile & 0x3;
-	WRITEL(reg, mfc_regs->e_picture_profile);
+	writel(reg, mfc_regs->e_picture_profile);
 
 	/* rate control config. */
-	reg = READL(mfc_regs->e_rc_config);
+	reg = readl(mfc_regs->e_rc_config);
 	/** macroblock level rate control */
 	reg &= ~(0x1 << 8);
 	reg |= ((p->rc_mb & 0x1) << 8);
-	WRITEL(reg, mfc_regs->e_rc_config);
+	writel(reg, mfc_regs->e_rc_config);
 
 	/* frame rate */
 	if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
 		reg = 0;
 		reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
 		reg |= p->rc_framerate_denom & 0xFFFF;
-		WRITEL(reg, mfc_regs->e_rc_frame_rate);
+		writel(reg, mfc_regs->e_rc_frame_rate);
 	}
 
 	/* frame QP */
 	reg &= ~(0x7F);
 	reg |= p_vp8->rc_frame_qp & 0x7F;
-	WRITEL(reg, mfc_regs->e_rc_config);
+	writel(reg, mfc_regs->e_rc_config);
 
 	/* other QPs */
-	WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
+	writel(0x0, mfc_regs->e_fixed_picture_qp);
 	if (!p->rc_frame && !p->rc_mb) {
 		reg = 0;
 		reg |= ((p_vp8->rc_p_frame_qp & 0x7F) << 8);
 		reg |= p_vp8->rc_frame_qp & 0x7F;
-		WRITEL(reg, mfc_regs->e_fixed_picture_qp);
+		writel(reg, mfc_regs->e_fixed_picture_qp);
 	}
 
 	/* max QP */
 	reg = ((p_vp8->rc_max_qp & 0x7F) << 8);
 	/* min QP */
 	reg |= p_vp8->rc_min_qp & 0x7F;
-	WRITEL(reg, mfc_regs->e_rc_qp_bound);
+	writel(reg, mfc_regs->e_rc_qp_bound);
 
 	/* vbv buffer size */
 	if (p->frame_skip_mode ==
 			V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
-		WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
+		writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
 
 		if (p->rc_frame)
-			WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
+			writel(p->vbv_delay, mfc_regs->e_vbv_init_delay);
 	}
 
 	/* VP8 specific params */
@@ -1319,7 +1314,7 @@
 	}
 	reg |= (val & 0xF) << 3;
 	reg |= (p_vp8->num_ref & 0x2);
-	WRITEL(reg, mfc_regs->e_vp8_options);
+	writel(reg, mfc_regs->e_vp8_options);
 
 	mfc_debug_leave();
 
@@ -1338,9 +1333,9 @@
 	mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no,
 			S5P_FIMV_CH_SEQ_HEADER_V6);
 	mfc_debug(2, "BUFs: %08x %08x %08x\n",
-		  READL(mfc_regs->d_cpb_buffer_addr),
-		  READL(mfc_regs->d_cpb_buffer_addr),
-		  READL(mfc_regs->d_cpb_buffer_addr));
+		  readl(mfc_regs->d_cpb_buffer_addr),
+		  readl(mfc_regs->d_cpb_buffer_addr),
+		  readl(mfc_regs->d_cpb_buffer_addr));
 
 	/* FMO_ASO_CTRL - 0: Enable, 1: Disable */
 	reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6);
@@ -1351,11 +1346,11 @@
 	 * set to negative value. */
 	if (ctx->display_delay >= 0) {
 		reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6);
-		WRITEL(ctx->display_delay, mfc_regs->d_display_delay);
+		writel(ctx->display_delay, mfc_regs->d_display_delay);
 	}
 
 	if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev)) {
-		WRITEL(reg, mfc_regs->d_dec_options);
+		writel(reg, mfc_regs->d_dec_options);
 		reg = 0;
 	}
 
@@ -1370,22 +1365,22 @@
 		reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6);
 
 	if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev))
-		WRITEL(reg, mfc_regs->d_init_buffer_options);
+		writel(reg, mfc_regs->d_init_buffer_options);
 	else
-		WRITEL(reg, mfc_regs->d_dec_options);
+		writel(reg, mfc_regs->d_dec_options);
 
 	/* 0: NV12(CbCr), 1: NV21(CrCb) */
 	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
-		WRITEL(0x1, mfc_regs->pixel_format);
+		writel(0x1, mfc_regs->pixel_format);
 	else
-		WRITEL(0x0, mfc_regs->pixel_format);
+		writel(0x0, mfc_regs->pixel_format);
 
 
 	/* sei parse */
-	WRITEL(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable);
+	writel(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable);
 
-	WRITEL(ctx->inst_no, mfc_regs->instance_id);
-	s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+	writel(ctx->inst_no, mfc_regs->instance_id);
+	s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
 			S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
 
 	mfc_debug_leave();
@@ -1400,8 +1395,8 @@
 	if (flush) {
 		dev->curr_ctx = ctx->num;
 		s5p_mfc_clean_ctx_int_flags(ctx);
-		WRITEL(ctx->inst_no, mfc_regs->instance_id);
-		s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+		writel(ctx->inst_no, mfc_regs->instance_id);
+		s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
 				S5P_FIMV_H2R_CMD_FLUSH_V6, NULL);
 	}
 }
@@ -1413,19 +1408,19 @@
 	struct s5p_mfc_dev *dev = ctx->dev;
 	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
 
-	WRITEL(ctx->dec_dst_flag, mfc_regs->d_available_dpb_flag_lower);
-	WRITEL(ctx->slice_interface & 0x1, mfc_regs->d_slice_if_enable);
+	writel(ctx->dec_dst_flag, mfc_regs->d_available_dpb_flag_lower);
+	writel(ctx->slice_interface & 0x1, mfc_regs->d_slice_if_enable);
 
-	WRITEL(ctx->inst_no, mfc_regs->instance_id);
+	writel(ctx->inst_no, mfc_regs->instance_id);
 	/* Issue different commands to instance basing on whether it
 	 * is the last frame or not. */
 	switch (last_frame) {
 	case 0:
-		s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+		s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
 				S5P_FIMV_CH_FRAME_START_V6, NULL);
 		break;
 	case 1:
-		s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+		s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
 				S5P_FIMV_CH_LAST_FRAME_V6, NULL);
 		break;
 	default:
@@ -1458,12 +1453,12 @@
 
 	/* Set stride lengths for v7 & above */
 	if (IS_MFCV7_PLUS(dev)) {
-		WRITEL(ctx->img_width, mfc_regs->e_source_first_plane_stride);
-		WRITEL(ctx->img_width, mfc_regs->e_source_second_plane_stride);
+		writel(ctx->img_width, mfc_regs->e_source_first_plane_stride);
+		writel(ctx->img_width, mfc_regs->e_source_second_plane_stride);
 	}
 
-	WRITEL(ctx->inst_no, mfc_regs->instance_id);
-	s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+	writel(ctx->inst_no, mfc_regs->instance_id);
+	s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
 			S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
 
 	return 0;
@@ -1479,7 +1474,7 @@
 
 	if (p_h264->aso) {
 		for (i = 0; i < ARRAY_SIZE(p_h264->aso_slice_order); i++) {
-			WRITEL(p_h264->aso_slice_order[i],
+			writel(p_h264->aso_slice_order[i],
 				mfc_regs->e_h264_aso_slice_order_0 + i * 4);
 		}
 	}
@@ -1501,8 +1496,8 @@
 
 	s5p_mfc_set_slice_mode(ctx);
 
-	WRITEL(ctx->inst_no, mfc_regs->instance_id);
-	s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
+	writel(ctx->inst_no, mfc_regs->instance_id);
+	s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
 			S5P_FIMV_CH_FRAME_START_V6, NULL);
 
 	mfc_debug(2, "--\n");
@@ -1877,15 +1872,15 @@
 static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev)
 {
 	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
-	WRITEL(0, mfc_regs->risc2host_command);
-	WRITEL(0, mfc_regs->risc2host_int);
+	writel(0, mfc_regs->risc2host_command);
+	writel(0, mfc_regs->risc2host_int);
 }
 
 static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data,
 		unsigned int ofs)
 {
 	s5p_mfc_clock_on();
-	WRITEL(data, (void *)ofs);
+	writel(data, (volatile void __iomem *)((unsigned long)ofs));
 	s5p_mfc_clock_off();
 }
 
@@ -1895,7 +1890,7 @@
 	int ret;
 
 	s5p_mfc_clock_on();
-	ret = READL((void *)ofs);
+	ret = readl((volatile void __iomem *)((unsigned long)ofs));
 	s5p_mfc_clock_off();
 
 	return ret;
@@ -1903,51 +1898,51 @@
 
 static int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->d_display_first_plane_addr);
+	return readl(dev->mfc_regs->d_display_first_plane_addr);
 }
 
 static int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->d_decoded_first_plane_addr);
+	return readl(dev->mfc_regs->d_decoded_first_plane_addr);
 }
 
 static int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->d_display_status);
+	return readl(dev->mfc_regs->d_display_status);
 }
 
 static int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->d_decoded_status);
+	return readl(dev->mfc_regs->d_decoded_status);
 }
 
 static int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->d_decoded_frame_type) &
+	return readl(dev->mfc_regs->d_decoded_frame_type) &
 		S5P_FIMV_DECODE_FRAME_MASK_V6;
 }
 
 static int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx)
 {
 	struct s5p_mfc_dev *dev = ctx->dev;
-	return READL(dev->mfc_regs->d_display_frame_type) &
+	return readl(dev->mfc_regs->d_display_frame_type) &
 		S5P_FIMV_DECODE_FRAME_MASK_V6;
 }
 
 static int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->d_decoded_nal_size);
+	return readl(dev->mfc_regs->d_decoded_nal_size);
 }
 
 static int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->risc2host_command) &
+	return readl(dev->mfc_regs->risc2host_command) &
 		S5P_FIMV_RISC2HOST_CMD_MASK;
 }
 
 static int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->error_code);
+	return readl(dev->mfc_regs->error_code);
 }
 
 static int s5p_mfc_err_dec_v6(unsigned int err)
@@ -1962,87 +1957,87 @@
 
 static int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->d_display_frame_width);
+	return readl(dev->mfc_regs->d_display_frame_width);
 }
 
 static int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->d_display_frame_height);
+	return readl(dev->mfc_regs->d_display_frame_height);
 }
 
 static int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->d_min_num_dpb);
+	return readl(dev->mfc_regs->d_min_num_dpb);
 }
 
 static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->d_min_num_mv);
+	return readl(dev->mfc_regs->d_min_num_mv);
 }
 
 static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->ret_instance_id);
+	return readl(dev->mfc_regs->ret_instance_id);
 }
 
 static int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->e_num_dpb);
+	return readl(dev->mfc_regs->e_num_dpb);
 }
 
 static int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->e_stream_size);
+	return readl(dev->mfc_regs->e_stream_size);
 }
 
 static int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->e_slice_type);
+	return readl(dev->mfc_regs->e_slice_type);
 }
 
 static int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->e_picture_count);
+	return readl(dev->mfc_regs->e_picture_count);
 }
 
 static int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx)
 {
 	struct s5p_mfc_dev *dev = ctx->dev;
-	return READL(dev->mfc_regs->d_frame_pack_sei_avail);
+	return readl(dev->mfc_regs->d_frame_pack_sei_avail);
 }
 
 static int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->d_mvc_num_views);
+	return readl(dev->mfc_regs->d_mvc_num_views);
 }
 
 static int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev)
 {
-	return READL(dev->mfc_regs->d_mvc_view_id);
+	return readl(dev->mfc_regs->d_mvc_view_id);
 }
 
 static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx)
 {
 	return s5p_mfc_read_info_v6(ctx,
-		(unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_top);
+		(__force unsigned long) ctx->dev->mfc_regs->d_ret_picture_tag_top);
 }
 
 static unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx)
 {
 	return s5p_mfc_read_info_v6(ctx,
-		(unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_bot);
+		(__force unsigned long) ctx->dev->mfc_regs->d_ret_picture_tag_bot);
 }
 
 static unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx)
 {
 	return s5p_mfc_read_info_v6(ctx,
-		(unsigned int) ctx->dev->mfc_regs->d_display_crop_info1);
+		(__force unsigned long) ctx->dev->mfc_regs->d_display_crop_info1);
 }
 
 static unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx)
 {
 	return s5p_mfc_read_info_v6(ctx,
-		(unsigned int) ctx->dev->mfc_regs->d_display_crop_info2);
+		(__force unsigned long) ctx->dev->mfc_regs->d_display_crop_info2);
 }
 
 static struct s5p_mfc_regs mfc_regs;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
index b6a8be9..826c489 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
@@ -21,7 +21,7 @@
 #include "s5p_mfc_pm.h"
 
 #define MFC_GATE_CLK_NAME	"mfc"
-#define MFC_SCLK_NAME		"sclk-mfc"
+#define MFC_SCLK_NAME		"sclk_mfc"
 #define MFC_SCLK_RATE		(200 * 1000000)
 
 #define CLK_DEBUG
diff --git a/drivers/media/platform/s5p-tv/Kconfig b/drivers/media/platform/s5p-tv/Kconfig
index aea3ea8..c22aac6 100644
--- a/drivers/media/platform/s5p-tv/Kconfig
+++ b/drivers/media/platform/s5p-tv/Kconfig
@@ -8,7 +8,8 @@
 
 config VIDEO_SAMSUNG_S5P_TV
 	bool "Samsung TV driver for S5P platform"
-	depends on (PLAT_S5P || ARCH_EXYNOS) && PM_RUNTIME
+	depends on PM_RUNTIME
+	depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
 	default n
 	---help---
 	  Say Y here to enable selecting the TV output devices for
@@ -75,6 +76,7 @@
 	depends on m
 	depends on VIDEO_DEV && VIDEO_V4L2
 	depends on VIDEO_SAMSUNG_S5P_TV
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	help
 	  Say Y here if you want support for the Mixer in Samsung S5P SoCs.
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c
index 90ed30a..1434ba4 100644
--- a/drivers/media/platform/s5p-tv/hdmi_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmi_drv.c
@@ -615,7 +615,7 @@
 	else
 		ret = pm_runtime_put_sync(hdev->dev);
 	/* only values < 0 indicate errors */
-	return IS_ERR_VALUE(ret) ? ret : 0;
+	return ret < 0 ? ret : 0;
 }
 
 static int hdmi_s_dv_timings(struct v4l2_subdev *sd,
diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c
index 5a7c379..72cf892 100644
--- a/drivers/media/platform/s5p-tv/sdo_drv.c
+++ b/drivers/media/platform/s5p-tv/sdo_drv.c
@@ -190,7 +190,7 @@
 		ret = pm_runtime_put_sync(dev);
 
 	/* only values < 0 indicate errors */
-	return IS_ERR_VALUE(ret) ? ret : 0;
+	return ret < 0 ? ret : 0;
 }
 
 static int sdo_streamon(struct sdo_device *sdev)
diff --git a/drivers/media/platform/s5p-tv/sii9234_drv.c b/drivers/media/platform/s5p-tv/sii9234_drv.c
index 3dd762e..db8c17b 100644
--- a/drivers/media/platform/s5p-tv/sii9234_drv.c
+++ b/drivers/media/platform/s5p-tv/sii9234_drv.c
@@ -289,7 +289,7 @@
 	else
 		ret = pm_runtime_put(&ctx->client->dev);
 	/* only values < 0 indicate errors */
-	return IS_ERR_VALUE(ret) ? ret : 0;
+	return ret < 0 ? ret : 0;
 }
 
 static int sii9234_s_stream(struct v4l2_subdev *sd, int enable)
diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c
index 8dc279d..be3b3bc 100644
--- a/drivers/media/platform/sh_veu.c
+++ b/drivers/media/platform/sh_veu.c
@@ -26,6 +26,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-mem2mem.h>
+#include <media/v4l2-image-sizes.h>
 #include <media/videobuf2-dma-contig.h>
 
 #define VEU_STR 0x00 /* start register */
@@ -135,9 +136,6 @@
 	SH_VEU_FMT_RGB24,
 };
 
-#define VGA_WIDTH	640
-#define VGA_HEIGHT	480
-
 #define DEFAULT_IN_WIDTH	VGA_WIDTH
 #define DEFAULT_IN_HEIGHT	VGA_HEIGHT
 #define DEFAULT_IN_FMTIDX	SH_VEU_FMT_NV12
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig
index 6642012..aebae21 100644
--- a/drivers/media/platform/soc_camera/Kconfig
+++ b/drivers/media/platform/soc_camera/Kconfig
@@ -1,5 +1,6 @@
 config SOC_CAMERA
 	depends on !BACKPORT_KERNEL_3_4
+	depends on !BACKPORT_KERNEL_3_5
 	tristate "SoC camera support"
 	depends on m
 	depends on VIDEO_V4L2 && HAS_DMA && I2C
@@ -25,6 +26,8 @@
 	tristate "i.MX3x Camera Sensor Interface driver"
 	depends on m
 	depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
+	depends on MX3_IPU || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	---help---
 	  This is a v4l2 driver for the i.MX3x Camera Sensor Interface
@@ -42,6 +45,7 @@
 	depends on m
 	depends on VIDEO_DEV && SOC_CAMERA
 	depends on ARCH_SHMOBILE || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	select SOC_CAMERA_SCALE_CROP
 	---help---
@@ -60,6 +64,7 @@
 	depends on m
 	depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
 	depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	select SOC_CAMERA_SCALE_CROP
 	---help---
@@ -68,7 +73,9 @@
 config VIDEO_OMAP1
 	tristate "OMAP1 Camera Interface driver"
 	depends on m
-	depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA
+	depends on VIDEO_DEV && SOC_CAMERA
+	depends on ARCH_OMAP1
+	depends on HAS_DMA
 	select VIDEOBUF_DMA_CONTIG
 	select VIDEOBUF_DMA_SG
 	---help---
@@ -77,7 +84,9 @@
 config VIDEO_MX2
 	tristate "i.MX27 Camera Sensor Interface driver"
 	depends on m
-	depends on VIDEO_DEV && SOC_CAMERA && SOC_IMX27
+	depends on VIDEO_DEV && SOC_CAMERA
+	depends on SOC_IMX27 || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	---help---
 	  This is a v4l2 driver for the i.MX27 Camera Sensor Interface
@@ -85,7 +94,9 @@
 config VIDEO_ATMEL_ISI
 	tristate "ATMEL Image Sensor Interface (ISI) support"
 	depends on m
-	depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91
+	depends on VIDEO_DEV && SOC_CAMERA
+	depends on ARCH_AT91 || COMPILE_TEST
+	depends on HAS_DMA
 	select VIDEOBUF2_DMA_CONTIG
 	---help---
 	  This module makes the ATMEL Image Sensor Interface available
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index 3408b04..c5291b0 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -54,7 +54,7 @@
 struct isi_dma_desc {
 	struct list_head list;
 	struct fbd *p_fbd;
-	u32 fbd_phys;
+	dma_addr_t fbd_phys;
 };
 
 /* Frame buffer data */
@@ -75,7 +75,7 @@
 
 	/* Allocate descriptors for dma buffer use */
 	struct fbd			*p_fb_descriptors;
-	u32				fb_descriptors_phys;
+	dma_addr_t			fb_descriptors_phys;
 	struct				list_head dma_desc_head;
 	struct isi_dma_desc		dma_desc[MAX_BUFFER_NUM];
 
@@ -169,7 +169,7 @@
 		isi->active = list_entry(isi->video_buffer_list.next,
 					struct frame_buffer, list);
 		isi_writel(isi, ISI_DMA_C_DSCR,
-			isi->active->p_dma_desc->fbd_phys);
+			(u32)isi->active->p_dma_desc->fbd_phys);
 		isi_writel(isi, ISI_DMA_C_CTRL,
 			ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
 		isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
@@ -346,7 +346,7 @@
 		return;
 	}
 
-	isi_writel(isi, ISI_DMA_C_DSCR, buffer->p_dma_desc->fbd_phys);
+	isi_writel(isi, ISI_DMA_C_DSCR, (u32)buffer->p_dma_desc->fbd_phys);
 	isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
 	isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
 
@@ -384,7 +384,6 @@
 	struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
 	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 	struct atmel_isi *isi = ici->priv;
-	u32 sr = 0;
 	int ret;
 
 	/* Reset ISI */
@@ -394,11 +393,11 @@
 		return ret;
 	}
 	/* Disable all interrupts */
-	isi_writel(isi, ISI_INTDIS, ~0UL);
+	isi_writel(isi, ISI_INTDIS, (u32)~0UL);
 
 	spin_lock_irq(&isi->lock);
 	/* Clear any pending interrupt */
-	sr = isi_readl(isi, ISI_STATUS);
+	isi_readl(isi, ISI_STATUS);
 
 	if (count)
 		start_dma(isi, isi->active);
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c
index b40bc2e..2347612 100644
--- a/drivers/media/platform/soc_camera/mx2_camera.c
+++ b/drivers/media/platform/soc_camera/mx2_camera.c
@@ -809,10 +809,9 @@
 
 static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
 {
-	u32 cntl;
 	int count = 0;
 
-	cntl = readl(pcdev->base_emma + PRP_CNTL);
+	readl(pcdev->base_emma + PRP_CNTL);
 	writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
 	while (count++ < 100) {
 		if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST))
@@ -1003,7 +1002,7 @@
 			      struct v4l2_mbus_framefmt *mf_in,
 			      struct v4l2_pix_format *pix_out, bool apply)
 {
-	int num, den;
+	unsigned int num, den;
 	unsigned long m;
 	int i, dir;
 
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c
index 83315df..7696a87 100644
--- a/drivers/media/platform/soc_camera/mx3_camera.c
+++ b/drivers/media/platform/soc_camera/mx3_camera.c
@@ -415,10 +415,8 @@
 	struct mx3_camera_buffer *buf, *tmp;
 	unsigned long flags;
 
-	if (ichan) {
-		struct dma_chan *chan = &ichan->dma_chan;
-		chan->device->device_control(chan, DMA_PAUSE, 0);
-	}
+	if (ichan)
+		dmaengine_pause(&ichan->dma_chan);
 
 	spin_lock_irqsave(&mx3_cam->lock, flags);
 
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index 64dc80c..66178fc 100644
--- a/drivers/media/platform/soc_camera/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
@@ -1694,7 +1694,7 @@
 		break;
 	default:
 		break;
-	};
+	}
 
 	if (ep.bus.parallel.flags & V4L2_MBUS_MASTER)
 		pcdev->platform_flags |= PXA_CAMERA_MASTER;
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index 85d579f..20defcb 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -981,7 +981,7 @@
 
 		if (shift == 3) {
 			dev_err(dev,
-				"Failed to configure the client below %ux%x\n",
+				"Failed to configure the client below %ux%u\n",
 				mf.width, mf.height);
 			return -EIO;
 		}
@@ -1502,7 +1502,7 @@
 	} else {
 		priv->ici.nr = of_alias_get_id(pdev->dev.of_node, "vin");
 		priv->chip = (enum chip_id)match->data;
-	};
+	}
 
 	spin_lock_init(&priv->lock);
 	INIT_LIST_HEAD(&priv->capture);
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index f4308fe..8e61b97 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -437,6 +437,22 @@
 		return vb2_prepare_buf(&icd->vb2_vidq, b);
 }
 
+static int soc_camera_expbuf(struct file *file, void *priv,
+			     struct v4l2_exportbuffer *p)
+{
+	struct soc_camera_device *icd = file->private_data;
+	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
+	if (icd->streamer != file)
+		return -EBUSY;
+
+	/* videobuf2 only */
+	if (ici->ops->init_videobuf)
+		return -EINVAL;
+	else
+		return vb2_expbuf(&icd->vb2_vidq, p);
+}
+
 /* Always entered with .host_lock held */
 static int soc_camera_init_user_formats(struct soc_camera_device *icd)
 {
@@ -1347,13 +1363,11 @@
 		return -ENODEV;
 	}
 
-	ssdd = kzalloc(sizeof(*ssdd), GFP_KERNEL);
+	ssdd = kmemdup(&sdesc->subdev_desc, sizeof(*ssdd), GFP_KERNEL);
 	if (!ssdd) {
 		ret = -ENOMEM;
 		goto ealloc;
 	}
-
-	memcpy(ssdd, &sdesc->subdev_desc, sizeof(*ssdd));
 	/*
 	 * In synchronous case we request regulators ourselves in
 	 * soc_camera_pdrv_probe(), make sure the subdevice driver doesn't try
@@ -2085,6 +2099,7 @@
 	.vidioc_dqbuf		 = soc_camera_dqbuf,
 	.vidioc_create_bufs	 = soc_camera_create_bufs,
 	.vidioc_prepare_buf	 = soc_camera_prepare_buf,
+	.vidioc_expbuf		 = soc_camera_expbuf,
 	.vidioc_streamon	 = soc_camera_streamon,
 	.vidioc_streamoff	 = soc_camera_streamoff,
 	.vidioc_cropcap		 = soc_camera_cropcap,
diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c
index a51a013..3e2e3a3 100644
--- a/drivers/media/platform/ti-vpe/vpdma.c
+++ b/drivers/media/platform/ti-vpe/vpdma.c
@@ -329,7 +329,7 @@
 	if (!buf->addr)
 		return -ENOMEM;
 
-	WARN_ON((u32) buf->addr & VPDMA_DESC_ALIGN);
+	WARN_ON(((unsigned long)buf->addr & VPDMA_DESC_ALIGN) != 0);
 
 	return 0;
 }
@@ -584,7 +584,7 @@
 		pr_debug("word1: line_length = %d, xfer_height = %d\n",
 			dtd_get_line_length(dtd), dtd_get_xfer_height(dtd));
 
-	pr_debug("word2: start_addr = 0x%08x\n", dtd->start_addr);
+	pr_debug("word2: start_addr = %pad\n", &dtd->start_addr);
 
 	pr_debug("word3: pkt_type = %d, mode = %d, dir = %d, chan = %d, "
 		"pri = %d, next_chan = %d\n", dtd_get_pkt_type(dtd),
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
index 972f43f..9a081c2 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -31,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/log2.h>
+#include <linux/sizes.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
@@ -138,12 +139,12 @@
  * default expert DEI register values, unlikely to be modified.
  */
 static const struct vpe_dei_regs dei_regs = {
-	0x020C0804u,
-	0x0118100Fu,
-	0x08040200u,
-	0x1010100Cu,
-	0x10101010u,
-	0x10101010u,
+	.mdt_spacial_freq_thr_reg = 0x020C0804u,
+	.edi_config_reg = 0x0118100Fu,
+	.edi_lut_reg0 = 0x08040200u,
+	.edi_lut_reg1 = 0x1010100Cu,
+	.edi_lut_reg2 = 0x10101010u,
+	.edi_lut_reg3 = 0x10101010u,
 };
 
 /*
@@ -834,10 +835,10 @@
 					VPDMA_STRIDE_ALIGN);
 		mv_buf_size = bytes_per_line * s_q_data->height;
 
-		ctx->deinterlacing = 1;
+		ctx->deinterlacing = true;
 		src_h <<= 1;
 	} else {
-		ctx->deinterlacing = 0;
+		ctx->deinterlacing = false;
 		mv_buf_size = 0;
 	}
 
@@ -2343,8 +2344,7 @@
 
 static int vpe_remove(struct platform_device *pdev)
 {
-	struct vpe_dev *dev =
-		(struct vpe_dev *) platform_get_drvdata(pdev);
+	struct vpe_dev *dev = platform_get_drvdata(pdev);
 
 	v4l2_info(&dev->v4l2_dev, "Removing " VPE_MODULE_NAME);
 
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c
index b4f9d03..ae6870c 100644
--- a/drivers/media/platform/via-camera.c
+++ b/drivers/media/platform/via-camera.c
@@ -18,6 +18,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-image-sizes.h>
 #include <media/ov7670.h>
 #include <media/videobuf-dma-sg.h>
 #include <linux/delay.h>
@@ -49,14 +50,6 @@
 		"to force-enable the camera.");
 
 /*
- * Basic window sizes.
- */
-#define VGA_WIDTH	640
-#define VGA_HEIGHT	480
-#define QCIF_WIDTH	176
-#define	QCIF_HEIGHT	144
-
-/*
  * The structure describing our camera.
  */
 enum viacam_opstate { S_IDLE = 0, S_RUNNING = 1 };
@@ -89,7 +82,7 @@
 	 * live in frame buffer memory, so we don't call them "DMA".
 	 */
 	unsigned int cb_offsets[3];	/* offsets into fb mem */
-	u8 *cb_addrs[3];		/* Kernel-space addresses */
+	u8 __iomem *cb_addrs[3];		/* Kernel-space addresses */
 	int n_cap_bufs;			/* How many are we using? */
 	int next_buf;
 	struct videobuf_queue vb_queue;
@@ -1283,7 +1276,7 @@
 			VIACAM_SERIAL_CREG, &cbyte);
 	if ((cbyte & VIACAM_SERIAL_BIT) == 0)
 		return false; /* Not enabled */
-	if (override_serial == 0) {
+	if (!override_serial) {
 		printk(KERN_NOTICE "Via camera: serial port is enabled, " \
 				"refusing to load.\n");
 		printk(KERN_NOTICE "Specify override_serial=1 to force " \
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
deleted file mode 100644
index 8033371..0000000
--- a/drivers/media/platform/vivi.c
+++ /dev/null
@@ -1,1542 +0,0 @@
-/*
- * Virtual Video driver - This code emulates a real video device with v4l2 api
- *
- * Copyright (c) 2006 by:
- *      Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
- *      Ted Walther <ted--a.t--enumera.com>
- *      John Sokol <sokol--a.t--videotechnology.com>
- *      http://v4l.videotechnology.com/
- *
- *      Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski
- *      Copyright (c) 2010 Samsung Electronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the BSD Licence, GNU General Public License
- * as published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version
- */
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/font.h>
-#include <linux/mutex.h>
-#include <linux/videodev2.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <media/videobuf2-vmalloc.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-common.h>
-
-#define VIVI_MODULE_NAME "vivi"
-
-/* Maximum allowed frame rate
- *
- * Vivi will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range.
- *
- * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that
- * might hit application errors when they manipulate these values.
- *
- * Besides, for tpf < 1ms image-generation logic should be changed, to avoid
- * producing frames with equal content.
- */
-#define FPS_MAX 1000
-
-#define MAX_WIDTH 1920
-#define MAX_HEIGHT 1200
-
-#define VIVI_VERSION "0.8.1"
-
-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION(VIVI_VERSION);
-
-static unsigned video_nr = -1;
-module_param(video_nr, uint, 0644);
-MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
-
-static unsigned n_devs = 1;
-module_param(n_devs, uint, 0644);
-MODULE_PARM_DESC(n_devs, "number of video devices to create");
-
-static unsigned debug;
-module_param(debug, uint, 0644);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-/* Global font descriptor */
-static const u8 *font8x16;
-
-/* timeperframe: min/max and default */
-static const struct v4l2_fract
-	tpf_min     = {.numerator = 1,		.denominator = FPS_MAX},
-	tpf_max     = {.numerator = FPS_MAX,	.denominator = 1},
-	tpf_default = {.numerator = 1001,	.denominator = 30000};	/* NTSC */
-
-#define dprintk(dev, level, fmt, arg...) \
-	v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
-
-/* ------------------------------------------------------------------
-	Basic structures
-   ------------------------------------------------------------------*/
-
-struct vivi_fmt {
-	const char *name;
-	u32   fourcc;          /* v4l2 format id */
-	u8    depth;
-	bool  is_yuv;
-};
-
-static const struct vivi_fmt formats[] = {
-	{
-		.name     = "4:2:2, packed, YUYV",
-		.fourcc   = V4L2_PIX_FMT_YUYV,
-		.depth    = 16,
-		.is_yuv   = true,
-	},
-	{
-		.name     = "4:2:2, packed, UYVY",
-		.fourcc   = V4L2_PIX_FMT_UYVY,
-		.depth    = 16,
-		.is_yuv   = true,
-	},
-	{
-		.name     = "4:2:2, packed, YVYU",
-		.fourcc   = V4L2_PIX_FMT_YVYU,
-		.depth    = 16,
-		.is_yuv   = true,
-	},
-	{
-		.name     = "4:2:2, packed, VYUY",
-		.fourcc   = V4L2_PIX_FMT_VYUY,
-		.depth    = 16,
-		.is_yuv   = true,
-	},
-	{
-		.name     = "RGB565 (LE)",
-		.fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
-		.depth    = 16,
-	},
-	{
-		.name     = "RGB565 (BE)",
-		.fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
-		.depth    = 16,
-	},
-	{
-		.name     = "RGB555 (LE)",
-		.fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
-		.depth    = 16,
-	},
-	{
-		.name     = "RGB555 (BE)",
-		.fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
-		.depth    = 16,
-	},
-	{
-		.name     = "RGB24 (LE)",
-		.fourcc   = V4L2_PIX_FMT_RGB24, /* rgb */
-		.depth    = 24,
-	},
-	{
-		.name     = "RGB24 (BE)",
-		.fourcc   = V4L2_PIX_FMT_BGR24, /* bgr */
-		.depth    = 24,
-	},
-	{
-		.name     = "RGB32 (LE)",
-		.fourcc   = V4L2_PIX_FMT_RGB32, /* argb */
-		.depth    = 32,
-	},
-	{
-		.name     = "RGB32 (BE)",
-		.fourcc   = V4L2_PIX_FMT_BGR32, /* bgra */
-		.depth    = 32,
-	},
-};
-
-static const struct vivi_fmt *__get_format(u32 pixelformat)
-{
-	const struct vivi_fmt *fmt;
-	unsigned int k;
-
-	for (k = 0; k < ARRAY_SIZE(formats); k++) {
-		fmt = &formats[k];
-		if (fmt->fourcc == pixelformat)
-			break;
-	}
-
-	if (k == ARRAY_SIZE(formats))
-		return NULL;
-
-	return &formats[k];
-}
-
-static const struct vivi_fmt *get_format(struct v4l2_format *f)
-{
-	return __get_format(f->fmt.pix.pixelformat);
-}
-
-/* buffer for one video frame */
-struct vivi_buffer {
-	/* common v4l buffer stuff -- must be first */
-	struct vb2_buffer	vb;
-	struct list_head	list;
-};
-
-struct vivi_dmaqueue {
-	struct list_head       active;
-
-	/* thread for generating video stream*/
-	struct task_struct         *kthread;
-	wait_queue_head_t          wq;
-	/* Counters to control fps rate */
-	int                        frame;
-	int                        ini_jiffies;
-};
-
-static LIST_HEAD(vivi_devlist);
-
-struct vivi_dev {
-	struct list_head           vivi_devlist;
-	struct v4l2_device 	   v4l2_dev;
-	struct v4l2_ctrl_handler   ctrl_handler;
-	struct video_device	   vdev;
-
-	/* controls */
-	struct v4l2_ctrl	   *brightness;
-	struct v4l2_ctrl	   *contrast;
-	struct v4l2_ctrl	   *saturation;
-	struct v4l2_ctrl	   *hue;
-	struct {
-		/* autogain/gain cluster */
-		struct v4l2_ctrl	   *autogain;
-		struct v4l2_ctrl	   *gain;
-	};
-	struct v4l2_ctrl	   *volume;
-	struct v4l2_ctrl	   *alpha;
-	struct v4l2_ctrl	   *button;
-	struct v4l2_ctrl	   *boolean;
-	struct v4l2_ctrl	   *int32;
-	struct v4l2_ctrl	   *int64;
-	struct v4l2_ctrl	   *menu;
-	struct v4l2_ctrl	   *string;
-	struct v4l2_ctrl	   *bitmask;
-	struct v4l2_ctrl	   *int_menu;
-
-	spinlock_t                 slock;
-	struct mutex		   mutex;
-
-	struct vivi_dmaqueue       vidq;
-
-	/* Several counters */
-	unsigned 		   ms;
-	unsigned long              jiffies;
-	unsigned		   button_pressed;
-
-	int			   mv_count;	/* Controls bars movement */
-
-	/* Input Number */
-	int			   input;
-
-	/* video capture */
-	const struct vivi_fmt      *fmt;
-	struct v4l2_fract          timeperframe;
-	unsigned int               width, height;
-	struct vb2_queue	   vb_vidq;
-	unsigned int		   seq_count;
-
-	u8			   bars[9][3];
-	u8			   line[MAX_WIDTH * 8] __attribute__((__aligned__(4)));
-	unsigned int		   pixelsize;
-	u8			   alpha_component;
-	u32			   textfg, textbg;
-};
-
-/* ------------------------------------------------------------------
-	DMA and thread functions
-   ------------------------------------------------------------------*/
-
-/* Bars and Colors should match positions */
-
-enum colors {
-	WHITE,
-	AMBER,
-	CYAN,
-	GREEN,
-	MAGENTA,
-	RED,
-	BLUE,
-	BLACK,
-	TEXT_BLACK,
-};
-
-/* R   G   B */
-#define COLOR_WHITE	{204, 204, 204}
-#define COLOR_AMBER	{208, 208,   0}
-#define COLOR_CYAN	{  0, 206, 206}
-#define	COLOR_GREEN	{  0, 239,   0}
-#define COLOR_MAGENTA	{239,   0, 239}
-#define COLOR_RED	{205,   0,   0}
-#define COLOR_BLUE	{  0,   0, 255}
-#define COLOR_BLACK	{  0,   0,   0}
-
-struct bar_std {
-	u8 bar[9][3];
-};
-
-/* Maximum number of bars are 10 - otherwise, the input print code
-   should be modified */
-static const struct bar_std bars[] = {
-	{	/* Standard ITU-R color bar sequence */
-		{ COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN,
-		  COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK }
-	}, {
-		{ COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE,
-		  COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK }
-	}, {
-		{ COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE,
-		  COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK }
-	}, {
-		{ COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE,
-		  COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK }
-	},
-};
-
-#define NUM_INPUTS ARRAY_SIZE(bars)
-
-#define TO_Y(r, g, b) \
-	(((16829 * r + 33039 * g + 6416 * b  + 32768) >> 16) + 16)
-/* RGB to  V(Cr) Color transform */
-#define TO_V(r, g, b) \
-	(((28784 * r - 24103 * g - 4681 * b  + 32768) >> 16) + 128)
-/* RGB to  U(Cb) Color transform */
-#define TO_U(r, g, b) \
-	(((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
-
-/* precalculate color bar values to speed up rendering */
-static void precalculate_bars(struct vivi_dev *dev)
-{
-	u8 r, g, b;
-	int k, is_yuv;
-
-	for (k = 0; k < 9; k++) {
-		r = bars[dev->input].bar[k][0];
-		g = bars[dev->input].bar[k][1];
-		b = bars[dev->input].bar[k][2];
-		is_yuv = dev->fmt->is_yuv;
-
-		switch (dev->fmt->fourcc) {
-		case V4L2_PIX_FMT_RGB565:
-		case V4L2_PIX_FMT_RGB565X:
-			r >>= 3;
-			g >>= 2;
-			b >>= 3;
-			break;
-		case V4L2_PIX_FMT_RGB555:
-		case V4L2_PIX_FMT_RGB555X:
-			r >>= 3;
-			g >>= 3;
-			b >>= 3;
-			break;
-		case V4L2_PIX_FMT_YUYV:
-		case V4L2_PIX_FMT_UYVY:
-		case V4L2_PIX_FMT_YVYU:
-		case V4L2_PIX_FMT_VYUY:
-		case V4L2_PIX_FMT_RGB24:
-		case V4L2_PIX_FMT_BGR24:
-		case V4L2_PIX_FMT_RGB32:
-		case V4L2_PIX_FMT_BGR32:
-			break;
-		}
-
-		if (is_yuv) {
-			dev->bars[k][0] = TO_Y(r, g, b);	/* Luma */
-			dev->bars[k][1] = TO_U(r, g, b);	/* Cb */
-			dev->bars[k][2] = TO_V(r, g, b);	/* Cr */
-		} else {
-			dev->bars[k][0] = r;
-			dev->bars[k][1] = g;
-			dev->bars[k][2] = b;
-		}
-	}
-}
-
-/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
-static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd)
-{
-	u8 r_y, g_u, b_v;
-	u8 alpha = dev->alpha_component;
-	int color;
-	u8 *p;
-
-	r_y = dev->bars[colorpos][0]; /* R or precalculated Y */
-	g_u = dev->bars[colorpos][1]; /* G or precalculated U */
-	b_v = dev->bars[colorpos][2]; /* B or precalculated V */
-
-	for (color = 0; color < dev->pixelsize; color++) {
-		p = buf + color;
-
-		switch (dev->fmt->fourcc) {
-		case V4L2_PIX_FMT_YUYV:
-			switch (color) {
-			case 0:
-				*p = r_y;
-				break;
-			case 1:
-				*p = odd ? b_v : g_u;
-				break;
-			}
-			break;
-		case V4L2_PIX_FMT_UYVY:
-			switch (color) {
-			case 0:
-				*p = odd ? b_v : g_u;
-				break;
-			case 1:
-				*p = r_y;
-				break;
-			}
-			break;
-		case V4L2_PIX_FMT_YVYU:
-			switch (color) {
-			case 0:
-				*p = r_y;
-				break;
-			case 1:
-				*p = odd ? g_u : b_v;
-				break;
-			}
-			break;
-		case V4L2_PIX_FMT_VYUY:
-			switch (color) {
-			case 0:
-				*p = odd ? g_u : b_v;
-				break;
-			case 1:
-				*p = r_y;
-				break;
-			}
-			break;
-		case V4L2_PIX_FMT_RGB565:
-			switch (color) {
-			case 0:
-				*p = (g_u << 5) | b_v;
-				break;
-			case 1:
-				*p = (r_y << 3) | (g_u >> 3);
-				break;
-			}
-			break;
-		case V4L2_PIX_FMT_RGB565X:
-			switch (color) {
-			case 0:
-				*p = (r_y << 3) | (g_u >> 3);
-				break;
-			case 1:
-				*p = (g_u << 5) | b_v;
-				break;
-			}
-			break;
-		case V4L2_PIX_FMT_RGB555:
-			switch (color) {
-			case 0:
-				*p = (g_u << 5) | b_v;
-				break;
-			case 1:
-				*p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
-				break;
-			}
-			break;
-		case V4L2_PIX_FMT_RGB555X:
-			switch (color) {
-			case 0:
-				*p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
-				break;
-			case 1:
-				*p = (g_u << 5) | b_v;
-				break;
-			}
-			break;
-		case V4L2_PIX_FMT_RGB24:
-			switch (color) {
-			case 0:
-				*p = r_y;
-				break;
-			case 1:
-				*p = g_u;
-				break;
-			case 2:
-				*p = b_v;
-				break;
-			}
-			break;
-		case V4L2_PIX_FMT_BGR24:
-			switch (color) {
-			case 0:
-				*p = b_v;
-				break;
-			case 1:
-				*p = g_u;
-				break;
-			case 2:
-				*p = r_y;
-				break;
-			}
-			break;
-		case V4L2_PIX_FMT_RGB32:
-			switch (color) {
-			case 0:
-				*p = alpha;
-				break;
-			case 1:
-				*p = r_y;
-				break;
-			case 2:
-				*p = g_u;
-				break;
-			case 3:
-				*p = b_v;
-				break;
-			}
-			break;
-		case V4L2_PIX_FMT_BGR32:
-			switch (color) {
-			case 0:
-				*p = b_v;
-				break;
-			case 1:
-				*p = g_u;
-				break;
-			case 2:
-				*p = r_y;
-				break;
-			case 3:
-				*p = alpha;
-				break;
-			}
-			break;
-		}
-	}
-}
-
-static void precalculate_line(struct vivi_dev *dev)
-{
-	unsigned pixsize  = dev->pixelsize;
-	unsigned pixsize2 = 2*pixsize;
-	int colorpos;
-	u8 *pos;
-
-	for (colorpos = 0; colorpos < 16; ++colorpos) {
-		u8 pix[8];
-		int wstart =  colorpos    * dev->width / 8;
-		int wend   = (colorpos+1) * dev->width / 8;
-		int w;
-
-		gen_twopix(dev, &pix[0],        colorpos % 8, 0);
-		gen_twopix(dev, &pix[pixsize],  colorpos % 8, 1);
-
-		for (w = wstart/2*2, pos = dev->line + w*pixsize; w < wend; w += 2, pos += pixsize2)
-			memcpy(pos, pix, pixsize2);
-	}
-}
-
-/* need this to do rgb24 rendering */
-typedef struct { u16 __; u8 _; } __attribute__((packed)) x24;
-
-static void gen_text(struct vivi_dev *dev, char *basep,
-					int y, int x, char *text)
-{
-	int line;
-	unsigned int width = dev->width;
-
-	/* Checks if it is possible to show string */
-	if (y + 16 >= dev->height || x + strlen(text) * 8 >= width)
-		return;
-
-	/* Print stream time */
-#define PRINTSTR(PIXTYPE) do {	\
-	PIXTYPE fg;	\
-	PIXTYPE bg;	\
-	memcpy(&fg, &dev->textfg, sizeof(PIXTYPE));	\
-	memcpy(&bg, &dev->textbg, sizeof(PIXTYPE));	\
-	\
-	for (line = 0; line < 16; line++) {	\
-		PIXTYPE *pos = (PIXTYPE *)( basep + ((y + line) * width + x) * sizeof(PIXTYPE) );	\
-		u8 *s;	\
-	\
-		for (s = text; *s; s++) {	\
-			u8 chr = font8x16[*s * 16 + line];	\
-	\
-			pos[0] = (chr & (0x01 << 7) ? fg : bg);	\
-			pos[1] = (chr & (0x01 << 6) ? fg : bg);	\
-			pos[2] = (chr & (0x01 << 5) ? fg : bg);	\
-			pos[3] = (chr & (0x01 << 4) ? fg : bg);	\
-			pos[4] = (chr & (0x01 << 3) ? fg : bg);	\
-			pos[5] = (chr & (0x01 << 2) ? fg : bg);	\
-			pos[6] = (chr & (0x01 << 1) ? fg : bg);	\
-			pos[7] = (chr & (0x01 << 0) ? fg : bg);	\
-	\
-			pos += 8;	\
-		}	\
-	}	\
-} while (0)
-
-	switch (dev->pixelsize) {
-	case 2:
-		PRINTSTR(u16); break;
-	case 4:
-		PRINTSTR(u32); break;
-	case 3:
-		PRINTSTR(x24); break;
-	}
-}
-
-static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
-{
-	int stride = dev->width * dev->pixelsize;
-	int hmax = dev->height;
-	void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
-	unsigned ms;
-	char str[100];
-	int h, line = 1;
-	u8 *linestart;
-	s32 gain;
-
-	if (!vbuf)
-		return;
-
-	linestart = dev->line + (dev->mv_count % dev->width) * dev->pixelsize;
-
-	for (h = 0; h < hmax; h++)
-		memcpy(vbuf + h * stride, linestart, stride);
-
-	/* Updates stream time */
-
-	gen_twopix(dev, (u8 *)&dev->textbg, TEXT_BLACK, /*odd=*/ 0);
-	gen_twopix(dev, (u8 *)&dev->textfg, WHITE, /*odd=*/ 0);
-
-	dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);
-	dev->jiffies = jiffies;
-	ms = dev->ms;
-	snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ",
-			(ms / (60 * 60 * 1000)) % 24,
-			(ms / (60 * 1000)) % 60,
-			(ms / 1000) % 60,
-			ms % 1000);
-	gen_text(dev, vbuf, line++ * 16, 16, str);
-	snprintf(str, sizeof(str), " %dx%d, input %d ",
-			dev->width, dev->height, dev->input);
-	gen_text(dev, vbuf, line++ * 16, 16, str);
-
-	gain = v4l2_ctrl_g_ctrl(dev->gain);
-	mutex_lock(dev->ctrl_handler.lock);
-	snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
-			dev->brightness->cur.val,
-			dev->contrast->cur.val,
-			dev->saturation->cur.val,
-			dev->hue->cur.val);
-	gen_text(dev, vbuf, line++ * 16, 16, str);
-	snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ",
-			dev->autogain->cur.val, gain, dev->volume->cur.val,
-			dev->alpha->cur.val);
-	gen_text(dev, vbuf, line++ * 16, 16, str);
-	snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
-			dev->int32->cur.val,
-			*dev->int64->p_cur.p_s64,
-			dev->bitmask->cur.val);
-	gen_text(dev, vbuf, line++ * 16, 16, str);
-	snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
-			dev->boolean->cur.val,
-			dev->menu->qmenu[dev->menu->cur.val],
-			dev->string->p_cur.p_char);
-	gen_text(dev, vbuf, line++ * 16, 16, str);
-	snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
-			dev->int_menu->qmenu_int[dev->int_menu->cur.val],
-			dev->int_menu->cur.val);
-	gen_text(dev, vbuf, line++ * 16, 16, str);
-	mutex_unlock(dev->ctrl_handler.lock);
-	if (dev->button_pressed) {
-		dev->button_pressed--;
-		snprintf(str, sizeof(str), " button pressed!");
-		gen_text(dev, vbuf, line++ * 16, 16, str);
-	}
-
-	dev->mv_count += 2;
-
-	buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
-	buf->vb.v4l2_buf.sequence = dev->seq_count++;
-	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
-}
-
-static void vivi_thread_tick(struct vivi_dev *dev)
-{
-	struct vivi_dmaqueue *dma_q = &dev->vidq;
-	struct vivi_buffer *buf;
-	unsigned long flags = 0;
-
-	dprintk(dev, 1, "Thread tick\n");
-
-	spin_lock_irqsave(&dev->slock, flags);
-	if (list_empty(&dma_q->active)) {
-		dprintk(dev, 1, "No active queue to serve\n");
-		spin_unlock_irqrestore(&dev->slock, flags);
-		return;
-	}
-
-	buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
-	list_del(&buf->list);
-	spin_unlock_irqrestore(&dev->slock, flags);
-
-	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
-
-	/* Fill buffer */
-	vivi_fillbuff(dev, buf);
-	dprintk(dev, 1, "filled buffer %p\n", buf);
-
-	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
-	dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
-}
-
-#define frames_to_ms(dev, frames)				\
-	((frames * dev->timeperframe.numerator * 1000) / dev->timeperframe.denominator)
-
-static void vivi_sleep(struct vivi_dev *dev)
-{
-	struct vivi_dmaqueue *dma_q = &dev->vidq;
-	int timeout;
-	DECLARE_WAITQUEUE(wait, current);
-
-	dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
-		(unsigned long)dma_q);
-
-	add_wait_queue(&dma_q->wq, &wait);
-	if (kthread_should_stop())
-		goto stop_task;
-
-	/* Calculate time to wake up */
-	timeout = msecs_to_jiffies(frames_to_ms(dev, 1));
-
-	vivi_thread_tick(dev);
-
-	schedule_timeout_interruptible(timeout);
-
-stop_task:
-	remove_wait_queue(&dma_q->wq, &wait);
-	try_to_freeze();
-}
-
-static int vivi_thread(void *data)
-{
-	struct vivi_dev *dev = data;
-
-	dprintk(dev, 1, "thread started\n");
-
-	set_freezable();
-
-	for (;;) {
-		vivi_sleep(dev);
-
-		if (kthread_should_stop())
-			break;
-	}
-	dprintk(dev, 1, "thread: exit\n");
-	return 0;
-}
-
-static int vivi_start_generating(struct vivi_dev *dev)
-{
-	struct vivi_dmaqueue *dma_q = &dev->vidq;
-
-	dprintk(dev, 1, "%s\n", __func__);
-
-	/* Resets frame counters */
-	dev->ms = 0;
-	dev->mv_count = 0;
-	dev->jiffies = jiffies;
-
-	dma_q->frame = 0;
-	dma_q->ini_jiffies = jiffies;
-	dma_q->kthread = kthread_run(vivi_thread, dev, "%s",
-				     dev->v4l2_dev.name);
-
-	if (IS_ERR(dma_q->kthread)) {
-		v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-		return PTR_ERR(dma_q->kthread);
-	}
-	/* Wakes thread */
-	wake_up_interruptible(&dma_q->wq);
-
-	dprintk(dev, 1, "returning from %s\n", __func__);
-	return 0;
-}
-
-static void vivi_stop_generating(struct vivi_dev *dev)
-{
-	struct vivi_dmaqueue *dma_q = &dev->vidq;
-
-	dprintk(dev, 1, "%s\n", __func__);
-
-	/* shutdown control thread */
-	if (dma_q->kthread) {
-		kthread_stop(dma_q->kthread);
-		dma_q->kthread = NULL;
-	}
-
-	/*
-	 * Typical driver might need to wait here until dma engine stops.
-	 * In this case we can abort imiedetly, so it's just a noop.
-	 */
-
-	/* Release all active buffers */
-	while (!list_empty(&dma_q->active)) {
-		struct vivi_buffer *buf;
-		buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
-		list_del(&buf->list);
-		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
-		dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
-	}
-}
-/* ------------------------------------------------------------------
-	Videobuf operations
-   ------------------------------------------------------------------*/
-static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
-				unsigned int *nbuffers, unsigned int *nplanes,
-				unsigned int sizes[], void *alloc_ctxs[])
-{
-	struct vivi_dev *dev = vb2_get_drv_priv(vq);
-	unsigned long size;
-
-	size = dev->width * dev->height * dev->pixelsize;
-	if (fmt) {
-		if (fmt->fmt.pix.sizeimage < size)
-			return -EINVAL;
-		size = fmt->fmt.pix.sizeimage;
-		/* check against insane over 8K resolution buffers */
-		if (size > 7680 * 4320 * dev->pixelsize)
-			return -EINVAL;
-	}
-
-	*nplanes = 1;
-
-	sizes[0] = size;
-
-	/*
-	 * videobuf2-vmalloc allocator is context-less so no need to set
-	 * alloc_ctxs array.
-	 */
-
-	dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__,
-		*nbuffers, size);
-
-	return 0;
-}
-
-static int buffer_prepare(struct vb2_buffer *vb)
-{
-	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
-	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
-	unsigned long size;
-
-	dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
-
-	BUG_ON(NULL == dev->fmt);
-
-	/*
-	 * Theses properties only change when queue is idle, see s_fmt.
-	 * The below checks should not be performed here, on each
-	 * buffer_prepare (i.e. on each qbuf). Most of the code in this function
-	 * should thus be moved to buffer_init and s_fmt.
-	 */
-	if (dev->width  < 48 || dev->width  > MAX_WIDTH ||
-	    dev->height < 32 || dev->height > MAX_HEIGHT)
-		return -EINVAL;
-
-	size = dev->width * dev->height * dev->pixelsize;
-	if (vb2_plane_size(vb, 0) < size) {
-		dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
-				__func__, vb2_plane_size(vb, 0), size);
-		return -EINVAL;
-	}
-
-	vb2_set_plane_payload(&buf->vb, 0, size);
-
-	precalculate_bars(dev);
-	precalculate_line(dev);
-
-	return 0;
-}
-
-static void buffer_queue(struct vb2_buffer *vb)
-{
-	struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
-	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
-	struct vivi_dmaqueue *vidq = &dev->vidq;
-	unsigned long flags = 0;
-
-	dprintk(dev, 1, "%s\n", __func__);
-
-	spin_lock_irqsave(&dev->slock, flags);
-	list_add_tail(&buf->list, &vidq->active);
-	spin_unlock_irqrestore(&dev->slock, flags);
-}
-
-static int start_streaming(struct vb2_queue *vq, unsigned int count)
-{
-	struct vivi_dev *dev = vb2_get_drv_priv(vq);
-	int err;
-
-	dprintk(dev, 1, "%s\n", __func__);
-	dev->seq_count = 0;
-	err = vivi_start_generating(dev);
-	if (err) {
-		struct vivi_buffer *buf, *tmp;
-
-		list_for_each_entry_safe(buf, tmp, &dev->vidq.active, list) {
-			list_del(&buf->list);
-			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
-		}
-	}
-	return err;
-}
-
-/* abort streaming and wait for last buffer */
-static void stop_streaming(struct vb2_queue *vq)
-{
-	struct vivi_dev *dev = vb2_get_drv_priv(vq);
-	dprintk(dev, 1, "%s\n", __func__);
-	vivi_stop_generating(dev);
-}
-
-static void vivi_lock(struct vb2_queue *vq)
-{
-	struct vivi_dev *dev = vb2_get_drv_priv(vq);
-	mutex_lock(&dev->mutex);
-}
-
-static void vivi_unlock(struct vb2_queue *vq)
-{
-	struct vivi_dev *dev = vb2_get_drv_priv(vq);
-	mutex_unlock(&dev->mutex);
-}
-
-
-static const struct vb2_ops vivi_video_qops = {
-	.queue_setup		= queue_setup,
-	.buf_prepare		= buffer_prepare,
-	.buf_queue		= buffer_queue,
-	.start_streaming	= start_streaming,
-	.stop_streaming		= stop_streaming,
-	.wait_prepare		= vivi_unlock,
-	.wait_finish		= vivi_lock,
-};
-
-/* ------------------------------------------------------------------
-	IOCTL vidioc handling
-   ------------------------------------------------------------------*/
-static int vidioc_querycap(struct file *file, void  *priv,
-					struct v4l2_capability *cap)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-
-	strcpy(cap->driver, "vivi");
-	strcpy(cap->card, "vivi");
-	snprintf(cap->bus_info, sizeof(cap->bus_info),
-			"platform:%s", dev->v4l2_dev.name);
-	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
-			    V4L2_CAP_READWRITE;
-	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-	return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
-					struct v4l2_fmtdesc *f)
-{
-	const struct vivi_fmt *fmt;
-
-	if (f->index >= ARRAY_SIZE(formats))
-		return -EINVAL;
-
-	fmt = &formats[f->index];
-
-	strlcpy(f->description, fmt->name, sizeof(f->description));
-	f->pixelformat = fmt->fourcc;
-	return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
-					struct v4l2_format *f)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-
-	f->fmt.pix.width        = dev->width;
-	f->fmt.pix.height       = dev->height;
-	f->fmt.pix.field        = V4L2_FIELD_INTERLACED;
-	f->fmt.pix.pixelformat  = dev->fmt->fourcc;
-	f->fmt.pix.bytesperline =
-		(f->fmt.pix.width * dev->fmt->depth) >> 3;
-	f->fmt.pix.sizeimage =
-		f->fmt.pix.height * f->fmt.pix.bytesperline;
-	if (dev->fmt->is_yuv)
-		f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-	else
-		f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
-	return 0;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
-			struct v4l2_format *f)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-	const struct vivi_fmt *fmt;
-
-	fmt = get_format(f);
-	if (!fmt) {
-		dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
-			f->fmt.pix.pixelformat);
-		f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-		fmt = get_format(f);
-	}
-
-	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
-	v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
-			      &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
-	f->fmt.pix.bytesperline =
-		(f->fmt.pix.width * fmt->depth) >> 3;
-	f->fmt.pix.sizeimage =
-		f->fmt.pix.height * f->fmt.pix.bytesperline;
-	if (fmt->is_yuv)
-		f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-	else
-		f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
-	return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-					struct v4l2_format *f)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-	struct vb2_queue *q = &dev->vb_vidq;
-
-	int ret = vidioc_try_fmt_vid_cap(file, priv, f);
-	if (ret < 0)
-		return ret;
-
-	if (vb2_is_busy(q)) {
-		dprintk(dev, 1, "%s device busy\n", __func__);
-		return -EBUSY;
-	}
-
-	dev->fmt = get_format(f);
-	dev->pixelsize = dev->fmt->depth / 8;
-	dev->width = f->fmt.pix.width;
-	dev->height = f->fmt.pix.height;
-
-	return 0;
-}
-
-static int vidioc_enum_framesizes(struct file *file, void *fh,
-					 struct v4l2_frmsizeenum *fsize)
-{
-	static const struct v4l2_frmsize_stepwise sizes = {
-		48, MAX_WIDTH, 4,
-		32, MAX_HEIGHT, 1
-	};
-	int i;
-
-	if (fsize->index)
-		return -EINVAL;
-	for (i = 0; i < ARRAY_SIZE(formats); i++)
-		if (formats[i].fourcc == fsize->pixel_format)
-			break;
-	if (i == ARRAY_SIZE(formats))
-		return -EINVAL;
-	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-	fsize->stepwise = sizes;
-	return 0;
-}
-
-/* only one input in this sample driver */
-static int vidioc_enum_input(struct file *file, void *priv,
-				struct v4l2_input *inp)
-{
-	if (inp->index >= NUM_INPUTS)
-		return -EINVAL;
-
-	inp->type = V4L2_INPUT_TYPE_CAMERA;
-	sprintf(inp->name, "Camera %u", inp->index);
-	return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-
-	*i = dev->input;
-	return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-
-	if (i >= NUM_INPUTS)
-		return -EINVAL;
-
-	if (i == dev->input)
-		return 0;
-
-	dev->input = i;
-	/*
-	 * Modify the brightness range depending on the input.
-	 * This makes it easy to use vivi to test if applications can
-	 * handle control range modifications and is also how this is
-	 * typically used in practice as different inputs may be hooked
-	 * up to different receivers with different control ranges.
-	 */
-	v4l2_ctrl_modify_range(dev->brightness,
-			128 * i, 255 + 128 * i, 1, 127 + 128 * i);
-	precalculate_bars(dev);
-	precalculate_line(dev);
-	return 0;
-}
-
-/* timeperframe is arbitrary and continuous */
-static int vidioc_enum_frameintervals(struct file *file, void *priv,
-					     struct v4l2_frmivalenum *fival)
-{
-	const struct vivi_fmt *fmt;
-
-	if (fival->index)
-		return -EINVAL;
-
-	fmt = __get_format(fival->pixel_format);
-	if (!fmt)
-		return -EINVAL;
-
-	/* check for valid width/height */
-	if (fival->width < 48 || fival->width > MAX_WIDTH || (fival->width & 3))
-		return -EINVAL;
-	if (fival->height < 32 || fival->height > MAX_HEIGHT)
-		return -EINVAL;
-
-	fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
-
-	/* fill in stepwise (step=1.0 is required by V4L2 spec) */
-	fival->stepwise.min  = tpf_min;
-	fival->stepwise.max  = tpf_max;
-	fival->stepwise.step = (struct v4l2_fract) {1, 1};
-
-	return 0;
-}
-
-static int vidioc_g_parm(struct file *file, void *priv,
-			  struct v4l2_streamparm *parm)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-
-	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	parm->parm.capture.capability   = V4L2_CAP_TIMEPERFRAME;
-	parm->parm.capture.timeperframe = dev->timeperframe;
-	parm->parm.capture.readbuffers  = 1;
-	return 0;
-}
-
-#define FRACT_CMP(a, OP, b)	\
-	((u64)(a).numerator * (b).denominator  OP  (u64)(b).numerator * (a).denominator)
-
-static int vidioc_s_parm(struct file *file, void *priv,
-			  struct v4l2_streamparm *parm)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-	struct v4l2_fract tpf;
-
-	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-
-	tpf = parm->parm.capture.timeperframe;
-
-	/* tpf: {*, 0} resets timing; clip to [min, max]*/
-	tpf = tpf.denominator ? tpf : tpf_default;
-	tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf;
-	tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf;
-
-	dev->timeperframe = tpf;
-	parm->parm.capture.timeperframe = tpf;
-	parm->parm.capture.readbuffers  = 1;
-	return 0;
-}
-
-/* --- controls ---------------------------------------------- */
-
-static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
-
-	if (ctrl == dev->autogain)
-		dev->gain->val = jiffies & 0xff;
-	return 0;
-}
-
-static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
-
-	switch (ctrl->id) {
-	case V4L2_CID_ALPHA_COMPONENT:
-		dev->alpha_component = ctrl->val;
-		break;
-	default:
-		if (ctrl == dev->button)
-			dev->button_pressed = 30;
-		break;
-	}
-	return 0;
-}
-
-/* ------------------------------------------------------------------
-	File operations for the device
-   ------------------------------------------------------------------*/
-
-static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
-	.g_volatile_ctrl = vivi_g_volatile_ctrl,
-	.s_ctrl = vivi_s_ctrl,
-};
-
-#define VIVI_CID_CUSTOM_BASE	(V4L2_CID_USER_BASE | 0xf000)
-
-static const struct v4l2_ctrl_config vivi_ctrl_button = {
-	.ops = &vivi_ctrl_ops,
-	.id = VIVI_CID_CUSTOM_BASE + 0,
-	.name = "Button",
-	.type = V4L2_CTRL_TYPE_BUTTON,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_boolean = {
-	.ops = &vivi_ctrl_ops,
-	.id = VIVI_CID_CUSTOM_BASE + 1,
-	.name = "Boolean",
-	.type = V4L2_CTRL_TYPE_BOOLEAN,
-	.min = 0,
-	.max = 1,
-	.step = 1,
-	.def = 1,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
-	.ops = &vivi_ctrl_ops,
-	.id = VIVI_CID_CUSTOM_BASE + 2,
-	.name = "Integer 32 Bits",
-	.type = V4L2_CTRL_TYPE_INTEGER,
-	.min = -0x80000000LL,
-	.max = 0x7fffffff,
-	.step = 1,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
-	.ops = &vivi_ctrl_ops,
-	.id = VIVI_CID_CUSTOM_BASE + 3,
-	.name = "Integer 64 Bits",
-	.type = V4L2_CTRL_TYPE_INTEGER64,
-	.min = LLONG_MIN,
-	.max = LLONG_MAX,
-	.step = 1,
-};
-
-static const char * const vivi_ctrl_menu_strings[] = {
-	"Menu Item 0 (Skipped)",
-	"Menu Item 1",
-	"Menu Item 2 (Skipped)",
-	"Menu Item 3",
-	"Menu Item 4",
-	"Menu Item 5 (Skipped)",
-	NULL,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_menu = {
-	.ops = &vivi_ctrl_ops,
-	.id = VIVI_CID_CUSTOM_BASE + 4,
-	.name = "Menu",
-	.type = V4L2_CTRL_TYPE_MENU,
-	.min = 1,
-	.max = 4,
-	.def = 3,
-	.menu_skip_mask = 0x04,
-	.qmenu = vivi_ctrl_menu_strings,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_string = {
-	.ops = &vivi_ctrl_ops,
-	.id = VIVI_CID_CUSTOM_BASE + 5,
-	.name = "String",
-	.type = V4L2_CTRL_TYPE_STRING,
-	.min = 2,
-	.max = 4,
-	.step = 1,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_bitmask = {
-	.ops = &vivi_ctrl_ops,
-	.id = VIVI_CID_CUSTOM_BASE + 6,
-	.name = "Bitmask",
-	.type = V4L2_CTRL_TYPE_BITMASK,
-	.def = 0x80002000,
-	.min = 0,
-	.max = 0x80402010,
-	.step = 0,
-};
-
-static const s64 vivi_ctrl_int_menu_values[] = {
-	1, 1, 2, 3, 5, 8, 13, 21, 42,
-};
-
-static const struct v4l2_ctrl_config vivi_ctrl_int_menu = {
-	.ops = &vivi_ctrl_ops,
-	.id = VIVI_CID_CUSTOM_BASE + 7,
-	.name = "Integer menu",
-	.type = V4L2_CTRL_TYPE_INTEGER_MENU,
-	.min = 1,
-	.max = 8,
-	.def = 4,
-	.menu_skip_mask = 0x02,
-	.qmenu_int = vivi_ctrl_int_menu_values,
-};
-
-static const struct v4l2_file_operations vivi_fops = {
-	.owner		= THIS_MODULE,
-	.open           = v4l2_fh_open,
-	.release        = vb2_fop_release,
-	.read           = vb2_fop_read,
-	.poll		= vb2_fop_poll,
-	.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
-	.mmap           = vb2_fop_mmap,
-};
-
-static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
-	.vidioc_querycap      = vidioc_querycap,
-	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
-	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
-	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
-	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
-	.vidioc_enum_framesizes   = vidioc_enum_framesizes,
-	.vidioc_reqbufs       = vb2_ioctl_reqbufs,
-	.vidioc_create_bufs   = vb2_ioctl_create_bufs,
-	.vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
-	.vidioc_querybuf      = vb2_ioctl_querybuf,
-	.vidioc_qbuf          = vb2_ioctl_qbuf,
-	.vidioc_dqbuf         = vb2_ioctl_dqbuf,
-	.vidioc_enum_input    = vidioc_enum_input,
-	.vidioc_g_input       = vidioc_g_input,
-	.vidioc_s_input       = vidioc_s_input,
-	.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
-	.vidioc_g_parm        = vidioc_g_parm,
-	.vidioc_s_parm        = vidioc_s_parm,
-	.vidioc_streamon      = vb2_ioctl_streamon,
-	.vidioc_streamoff     = vb2_ioctl_streamoff,
-	.vidioc_log_status    = v4l2_ctrl_log_status,
-	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
-	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static const struct video_device vivi_template = {
-	.name		= "vivi",
-	.fops           = &vivi_fops,
-	.ioctl_ops 	= &vivi_ioctl_ops,
-	.release	= video_device_release_empty,
-};
-
-/* -----------------------------------------------------------------
-	Initialization and module stuff
-   ------------------------------------------------------------------*/
-
-static int vivi_release(void)
-{
-	struct vivi_dev *dev;
-	struct list_head *list;
-
-	while (!list_empty(&vivi_devlist)) {
-		list = vivi_devlist.next;
-		list_del(list);
-		dev = list_entry(list, struct vivi_dev, vivi_devlist);
-
-		v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
-			video_device_node_name(&dev->vdev));
-		video_unregister_device(&dev->vdev);
-		v4l2_device_unregister(&dev->v4l2_dev);
-		v4l2_ctrl_handler_free(&dev->ctrl_handler);
-		kfree(dev);
-	}
-
-	return 0;
-}
-
-static int __init vivi_create_instance(int inst)
-{
-	struct vivi_dev *dev;
-	struct video_device *vfd;
-	struct v4l2_ctrl_handler *hdl;
-	struct vb2_queue *q;
-	int ret;
-
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev)
-		return -ENOMEM;
-
-	snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
-			"%s-%03d", VIVI_MODULE_NAME, inst);
-	ret = v4l2_device_register(NULL, &dev->v4l2_dev);
-	if (ret)
-		goto free_dev;
-
-	dev->fmt = &formats[0];
-	dev->timeperframe = tpf_default;
-	dev->width = 640;
-	dev->height = 480;
-	dev->pixelsize = dev->fmt->depth / 8;
-	hdl = &dev->ctrl_handler;
-	v4l2_ctrl_handler_init(hdl, 11);
-	dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-			V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
-	dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-			V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
-	dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-			V4L2_CID_CONTRAST, 0, 255, 1, 16);
-	dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-			V4L2_CID_SATURATION, 0, 255, 1, 127);
-	dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-			V4L2_CID_HUE, -128, 127, 1, 0);
-	dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
-	dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-			V4L2_CID_GAIN, 0, 255, 1, 100);
-	dev->alpha = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
-			V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
-	dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
-	dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
-	dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
-	dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
-	dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
-	dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
-	dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
-	dev->int_menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int_menu, NULL);
-	if (hdl->error) {
-		ret = hdl->error;
-		goto unreg_dev;
-	}
-	v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
-	dev->v4l2_dev.ctrl_handler = hdl;
-
-	/* initialize locks */
-	spin_lock_init(&dev->slock);
-
-	/* initialize queue */
-	q = &dev->vb_vidq;
-	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
-	q->drv_priv = dev;
-	q->buf_struct_size = sizeof(struct vivi_buffer);
-	q->ops = &vivi_video_qops;
-	q->mem_ops = &vb2_vmalloc_memops;
-	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-
-	ret = vb2_queue_init(q);
-	if (ret)
-		goto unreg_dev;
-
-	mutex_init(&dev->mutex);
-
-	/* init video dma queues */
-	INIT_LIST_HEAD(&dev->vidq.active);
-	init_waitqueue_head(&dev->vidq.wq);
-
-	vfd = &dev->vdev;
-	*vfd = vivi_template;
-	vfd->debug = debug;
-	vfd->v4l2_dev = &dev->v4l2_dev;
-	vfd->queue = q;
-
-	/*
-	 * Provide a mutex to v4l2 core. It will be used to protect
-	 * all fops and v4l2 ioctls.
-	 */
-	vfd->lock = &dev->mutex;
-	video_set_drvdata(vfd, dev);
-
-	ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
-	if (ret < 0)
-		goto unreg_dev;
-
-	/* Now that everything is fine, let's add it to device list */
-	list_add_tail(&dev->vivi_devlist, &vivi_devlist);
-
-	v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
-		  video_device_node_name(vfd));
-	return 0;
-
-unreg_dev:
-	v4l2_ctrl_handler_free(hdl);
-	v4l2_device_unregister(&dev->v4l2_dev);
-free_dev:
-	kfree(dev);
-	return ret;
-}
-
-/* This routine allocates from 1 to n_devs virtual drivers.
-
-   The real maximum number of virtual drivers will depend on how many drivers
-   will succeed. This is limited to the maximum number of devices that
-   videodev supports, which is equal to VIDEO_NUM_DEVICES.
- */
-static int __init vivi_init(void)
-{
-	const struct font_desc *font = find_font("VGA8x16");
-	int ret = 0, i;
-
-	if (font == NULL) {
-		printk(KERN_ERR "vivi: could not find font\n");
-		return -ENODEV;
-	}
-	font8x16 = font->data;
-
-	if (n_devs <= 0)
-		n_devs = 1;
-
-	for (i = 0; i < n_devs; i++) {
-		ret = vivi_create_instance(i);
-		if (ret) {
-			/* If some instantiations succeeded, keep driver */
-			if (i)
-				ret = 0;
-			break;
-		}
-	}
-
-	if (ret < 0) {
-		printk(KERN_ERR "vivi: error %d while loading driver\n", ret);
-		return ret;
-	}
-
-	printk(KERN_INFO "Video Technology Magazine Virtual Video "
-			"Capture Board ver %s successfully loaded.\n",
-			VIVI_VERSION);
-
-	/* n_devs will reflect the actual number of allocated devices */
-	n_devs = i;
-
-	return ret;
-}
-
-static void __exit vivi_exit(void)
-{
-	vivi_release();
-}
-
-module_init(vivi_init);
-module_exit(vivi_exit);
diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig
new file mode 100644
index 0000000..0d2d7c1
--- /dev/null
+++ b/drivers/media/platform/vivid/Kconfig
@@ -0,0 +1,20 @@
+config VIDEO_VIVID
+	tristate "Virtual Video Test Driver"
+	depends on m
+	depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
+	depends on FONT_SUPPORT
+	depends on FONT_8x16
+	select VIDEOBUF2_VMALLOC
+	default n
+	---help---
+	  Enables a virtual video driver. This driver emulates a webcam,
+	  TV, S-Video and HDMI capture hardware, including VBI support for
+	  the SDTV inputs. Also video output, VBI output, radio receivers,
+	  transmitters and software defined radio capture is emulated.
+
+	  It is highly configurable and is ideal for testing applications.
+	  Error injection is supported to test rare errors that are hard
+	  to reproduce in real hardware.
+
+	  Say Y here if you want to test video apps or debug V4L devices.
+	  When in doubt, say N.
diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile
new file mode 100644
index 0000000..b34e643
--- /dev/null
+++ b/drivers/media/platform/vivid/Makefile
@@ -0,0 +1,6 @@
+vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \
+		vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \
+		vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \
+		vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \
+		vivid-osd.o vivid-tpg.o vivid-tpg-colors.o
+obj-$(CPTCFG_VIDEO_VIVID) += vivid.o
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
new file mode 100644
index 0000000..2c61a62
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -0,0 +1,1390 @@
+/*
+ * vivid-core.c - A Virtual Video Test Driver, core initialization
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-vid-cap.h"
+#include "vivid-vid-out.h"
+#include "vivid-radio-common.h"
+#include "vivid-radio-rx.h"
+#include "vivid-radio-tx.h"
+#include "vivid-sdr-cap.h"
+#include "vivid-vbi-cap.h"
+#include "vivid-vbi-out.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.h"
+
+#define VIVID_MODULE_NAME "vivid"
+
+/* The maximum number of vivid devices */
+#define VIVID_MAX_DEVS 64
+
+MODULE_DESCRIPTION("Virtual Video Test Driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static unsigned n_devs = 1;
+module_param(n_devs, uint, 0444);
+MODULE_PARM_DESC(n_devs, " number of driver instances to create");
+
+static int vid_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(vid_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vid_cap_nr, " videoX start number, -1 is autodetect");
+
+static int vid_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(vid_out_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vid_out_nr, " videoX start number, -1 is autodetect");
+
+static int vbi_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(vbi_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vbi_cap_nr, " vbiX start number, -1 is autodetect");
+
+static int vbi_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(vbi_out_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vbi_out_nr, " vbiX start number, -1 is autodetect");
+
+static int sdr_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(sdr_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(sdr_cap_nr, " swradioX start number, -1 is autodetect");
+
+static int radio_rx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(radio_rx_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_rx_nr, " radioX start number, -1 is autodetect");
+
+static int radio_tx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(radio_tx_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_tx_nr, " radioX start number, -1 is autodetect");
+
+static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(ccs_cap_mode, int, NULL, 0444);
+MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n"
+			   "\t\t    bit 0=crop, 1=compose, 2=scale,\n"
+			   "\t\t    -1=user-controlled (default)");
+
+static int ccs_out_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(ccs_out_mode, int, NULL, 0444);
+MODULE_PARM_DESC(ccs_out_mode, " output crop/compose/scale mode:\n"
+			   "\t\t    bit 0=crop, 1=compose, 2=scale,\n"
+			   "\t\t    -1=user-controlled (default)");
+
+static unsigned multiplanar[VIVID_MAX_DEVS];
+module_param_array(multiplanar, uint, NULL, 0444);
+MODULE_PARM_DESC(multiplanar, " 0 (default) is alternating single and multiplanar devices,\n"
+			      "\t\t    1 is single planar devices,\n"
+			      "\t\t    2 is multiplanar devices");
+
+/* Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + vbi-out + vid-out */
+static unsigned node_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0x1d3d };
+module_param_array(node_types, uint, NULL, 0444);
+MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the following meaning:\n"
+			     "\t\t    bit 0: Video Capture node\n"
+			     "\t\t    bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
+			     "\t\t    bit 4: Radio Receiver node\n"
+			     "\t\t    bit 5: Software Defined Radio Receiver node\n"
+			     "\t\t    bit 8: Video Output node\n"
+			     "\t\t    bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
+			     "\t\t    bit 12: Radio Transmitter node\n"
+			     "\t\t    bit 16: Framebuffer for testing overlays");
+
+/* Default: 4 inputs */
+static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 };
+module_param_array(num_inputs, uint, NULL, 0444);
+MODULE_PARM_DESC(num_inputs, " number of inputs, default is 4");
+
+/* Default: input 0 = WEBCAM, 1 = TV, 2 = SVID, 3 = HDMI */
+static unsigned input_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0xe4 };
+module_param_array(input_types, uint, NULL, 0444);
+MODULE_PARM_DESC(input_types, " input types, default is 0xe4. Two bits per input,\n"
+			      "\t\t    bits 0-1 == input 0, bits 31-30 == input 15.\n"
+			      "\t\t    Type 0 == webcam, 1 == TV, 2 == S-Video, 3 == HDMI");
+
+/* Default: 2 outputs */
+static unsigned num_outputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 2 };
+module_param_array(num_outputs, uint, NULL, 0444);
+MODULE_PARM_DESC(num_outputs, " number of outputs, default is 2");
+
+/* Default: output 0 = SVID, 1 = HDMI */
+static unsigned output_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 2 };
+module_param_array(output_types, uint, NULL, 0444);
+MODULE_PARM_DESC(output_types, " output types, default is 0x02. One bit per output,\n"
+			      "\t\t    bit 0 == output 0, bit 15 == output 15.\n"
+			      "\t\t    Type 0 == S-Video, 1 == HDMI");
+
+unsigned vivid_debug;
+module_param(vivid_debug, uint, 0644);
+MODULE_PARM_DESC(vivid_debug, " activates debug info");
+
+static bool no_error_inj;
+module_param(no_error_inj, bool, 0444);
+MODULE_PARM_DESC(no_error_inj, " if set disable the error injecting controls");
+
+static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS];
+
+const struct v4l2_rect vivid_min_rect = {
+	0, 0, MIN_WIDTH, MIN_HEIGHT
+};
+
+const struct v4l2_rect vivid_max_rect = {
+	0, 0, MAX_WIDTH * MAX_ZOOM, MAX_HEIGHT * MAX_ZOOM
+};
+
+static const u8 vivid_hdmi_edid[256] = {
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+	0x63, 0x3a, 0xaa, 0x55, 0x00, 0x00, 0x00, 0x00,
+	0x0a, 0x18, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
+	0x0e, 0x00, 0xb2, 0xa0, 0x57, 0x49, 0x9b, 0x26,
+	0x10, 0x48, 0x4f, 0x2f, 0xcf, 0x00, 0x31, 0x59,
+	0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40,
+	0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x02, 0x3a,
+	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+	0x46, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00, 0x1e,
+	0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18,
+	0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20,
+	0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00,  'v',
+	'4',   'l',  '2',  '-',  'h',  'd',  'm',  'i',
+	0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x10,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0,
+
+	0x02, 0x03, 0x1a, 0xc0, 0x48, 0xa2, 0x10, 0x04,
+	0x02, 0x01, 0x21, 0x14, 0x13, 0x23, 0x09, 0x07,
+	0x07, 0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, 0xe2,
+	0x00, 0x2a, 0x01, 0x1d, 0x00, 0x80, 0x51, 0xd0,
+	0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x1e, 0x8c, 0x0a, 0xd0, 0x8a,
+	0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7
+};
+
+void vivid_lock(struct vb2_queue *vq)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+	mutex_lock(&dev->mutex);
+}
+
+void vivid_unlock(struct vb2_queue *vq)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+	mutex_unlock(&dev->mutex);
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct video_device *vdev = video_devdata(file);
+
+	strcpy(cap->driver, "vivid");
+	strcpy(cap->card, "vivid");
+	snprintf(cap->bus_info, sizeof(cap->bus_info),
+			"platform:%s", dev->v4l2_dev.name);
+
+	if (vdev->vfl_type == VFL_TYPE_GRABBER && vdev->vfl_dir == VFL_DIR_RX)
+		cap->device_caps = dev->vid_cap_caps;
+	if (vdev->vfl_type == VFL_TYPE_GRABBER && vdev->vfl_dir == VFL_DIR_TX)
+		cap->device_caps = dev->vid_out_caps;
+	else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_RX)
+		cap->device_caps = dev->vbi_cap_caps;
+	else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_TX)
+		cap->device_caps = dev->vbi_out_caps;
+	else if (vdev->vfl_type == VFL_TYPE_SDR)
+		cap->device_caps = dev->sdr_cap_caps;
+	else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_RX)
+		cap->device_caps = dev->radio_rx_caps;
+	else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_TX)
+		cap->device_caps = dev->radio_tx_caps;
+	cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps |
+		dev->vbi_cap_caps | dev->vbi_out_caps |
+		dev->radio_rx_caps | dev->radio_tx_caps |
+		dev->sdr_cap_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int vidioc_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_type == VFL_TYPE_RADIO)
+		return vivid_radio_rx_s_hw_freq_seek(file, fh, a);
+	return -ENOTTY;
+}
+
+static int vidioc_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_type == VFL_TYPE_RADIO)
+		return vivid_radio_rx_enum_freq_bands(file, fh, band);
+	if (vdev->vfl_type == VFL_TYPE_SDR)
+		return vivid_sdr_enum_freq_bands(file, fh, band);
+	return -ENOTTY;
+}
+
+static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_type == VFL_TYPE_RADIO)
+		return vivid_radio_rx_g_tuner(file, fh, vt);
+	if (vdev->vfl_type == VFL_TYPE_SDR)
+		return vivid_sdr_g_tuner(file, fh, vt);
+	return vivid_video_g_tuner(file, fh, vt);
+}
+
+static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_type == VFL_TYPE_RADIO)
+		return vivid_radio_rx_s_tuner(file, fh, vt);
+	if (vdev->vfl_type == VFL_TYPE_SDR)
+		return vivid_sdr_s_tuner(file, fh, vt);
+	return vivid_video_s_tuner(file, fh, vt);
+}
+
+static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_type == VFL_TYPE_RADIO)
+		return vivid_radio_g_frequency(file,
+			vdev->vfl_dir == VFL_DIR_RX ?
+			&dev->radio_rx_freq : &dev->radio_tx_freq, vf);
+	if (vdev->vfl_type == VFL_TYPE_SDR)
+		return vivid_sdr_g_frequency(file, fh, vf);
+	return vivid_video_g_frequency(file, fh, vf);
+}
+
+static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_type == VFL_TYPE_RADIO)
+		return vivid_radio_s_frequency(file,
+			vdev->vfl_dir == VFL_DIR_RX ?
+			&dev->radio_rx_freq : &dev->radio_tx_freq, vf);
+	if (vdev->vfl_type == VFL_TYPE_SDR)
+		return vivid_sdr_s_frequency(file, fh, vf);
+	return vivid_video_s_frequency(file, fh, vf);
+}
+
+static int vidioc_overlay(struct file *file, void *fh, unsigned i)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		return vivid_vid_cap_overlay(file, fh, i);
+	return vivid_vid_out_overlay(file, fh, i);
+}
+
+static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		return vivid_vid_cap_g_fbuf(file, fh, a);
+	return vivid_vid_out_g_fbuf(file, fh, a);
+}
+
+static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		return vivid_vid_cap_s_fbuf(file, fh, a);
+	return vivid_vid_out_s_fbuf(file, fh, a);
+}
+
+static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		return vivid_vid_cap_s_std(file, fh, id);
+	return vivid_vid_out_s_std(file, fh, id);
+}
+
+static int vidioc_s_dv_timings(struct file *file, void *fh, struct v4l2_dv_timings *timings)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		return vivid_vid_cap_s_dv_timings(file, fh, timings);
+	return vivid_vid_out_s_dv_timings(file, fh, timings);
+}
+
+static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cc)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		return vivid_vid_cap_cropcap(file, fh, cc);
+	return vivid_vid_out_cropcap(file, fh, cc);
+}
+
+static int vidioc_g_selection(struct file *file, void *fh,
+			      struct v4l2_selection *sel)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		return vivid_vid_cap_g_selection(file, fh, sel);
+	return vivid_vid_out_g_selection(file, fh, sel);
+}
+
+static int vidioc_s_selection(struct file *file, void *fh,
+			      struct v4l2_selection *sel)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		return vivid_vid_cap_s_selection(file, fh, sel);
+	return vivid_vid_out_s_selection(file, fh, sel);
+}
+
+static int vidioc_g_parm(struct file *file, void *fh,
+			  struct v4l2_streamparm *parm)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		return vivid_vid_cap_g_parm(file, fh, parm);
+	return vivid_vid_out_g_parm(file, fh, parm);
+}
+
+static int vidioc_s_parm(struct file *file, void *fh,
+			  struct v4l2_streamparm *parm)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		return vivid_vid_cap_s_parm(file, fh, parm);
+	return vivid_vid_out_g_parm(file, fh, parm);
+}
+
+static ssize_t vivid_radio_read(struct file *file, char __user *buf,
+			 size_t size, loff_t *offset)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_TX)
+		return -EINVAL;
+	return vivid_radio_rx_read(file, buf, size, offset);
+}
+
+static ssize_t vivid_radio_write(struct file *file, const char __user *buf,
+			  size_t size, loff_t *offset)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		return -EINVAL;
+	return vivid_radio_tx_write(file, buf, size, offset);
+}
+
+static unsigned int vivid_radio_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		return vivid_radio_rx_poll(file, wait);
+	return vivid_radio_tx_poll(file, wait);
+}
+
+static bool vivid_is_in_use(struct video_device *vdev)
+{
+	unsigned long flags;
+	bool res;
+
+	spin_lock_irqsave(&vdev->fh_lock, flags);
+	res = !list_empty(&vdev->fh_list);
+	spin_unlock_irqrestore(&vdev->fh_lock, flags);
+	return res;
+}
+
+static bool vivid_is_last_user(struct vivid_dev *dev)
+{
+	unsigned uses = vivid_is_in_use(&dev->vid_cap_dev) +
+			vivid_is_in_use(&dev->vid_out_dev) +
+			vivid_is_in_use(&dev->vbi_cap_dev) +
+			vivid_is_in_use(&dev->vbi_out_dev) +
+			vivid_is_in_use(&dev->sdr_cap_dev) +
+			vivid_is_in_use(&dev->radio_rx_dev) +
+			vivid_is_in_use(&dev->radio_tx_dev);
+
+	return uses == 1;
+}
+
+static int vivid_fop_release(struct file *file)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct video_device *vdev = video_devdata(file);
+
+	mutex_lock(&dev->mutex);
+	if (!no_error_inj && v4l2_fh_is_singular_file(file) &&
+	    !video_is_registered(vdev) && vivid_is_last_user(dev)) {
+		/*
+		 * I am the last user of this driver, and a disconnect
+		 * was forced (since this video_device is unregistered),
+		 * so re-register all video_device's again.
+		 */
+		v4l2_info(&dev->v4l2_dev, "reconnect\n");
+		set_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags);
+		set_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags);
+		set_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags);
+		set_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags);
+		set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags);
+		set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags);
+		set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
+	}
+	mutex_unlock(&dev->mutex);
+	if (file->private_data == dev->overlay_cap_owner)
+		dev->overlay_cap_owner = NULL;
+	if (file->private_data == dev->radio_rx_rds_owner) {
+		dev->radio_rx_rds_last_block = 0;
+		dev->radio_rx_rds_owner = NULL;
+	}
+	if (file->private_data == dev->radio_tx_rds_owner) {
+		dev->radio_tx_rds_last_block = 0;
+		dev->radio_tx_rds_owner = NULL;
+	}
+	if (vdev->queue)
+		return vb2_fop_release(file);
+	return v4l2_fh_release(file);
+}
+
+static const struct v4l2_file_operations vivid_fops = {
+	.owner		= THIS_MODULE,
+	.open           = v4l2_fh_open,
+	.release        = vivid_fop_release,
+	.read           = vb2_fop_read,
+	.write          = vb2_fop_write,
+	.poll		= vb2_fop_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap           = vb2_fop_mmap,
+};
+
+static const struct v4l2_file_operations vivid_radio_fops = {
+	.owner		= THIS_MODULE,
+	.open           = v4l2_fh_open,
+	.release        = vivid_fop_release,
+	.read           = vivid_radio_read,
+	.write          = vivid_radio_write,
+	.poll		= vivid_radio_poll,
+	.unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
+	.vidioc_querycap		= vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap	= vidioc_enum_fmt_vid,
+	.vidioc_g_fmt_vid_cap		= vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap		= vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap		= vidioc_s_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_mplane,
+	.vidioc_g_fmt_vid_cap_mplane	= vidioc_g_fmt_vid_cap_mplane,
+	.vidioc_try_fmt_vid_cap_mplane	= vidioc_try_fmt_vid_cap_mplane,
+	.vidioc_s_fmt_vid_cap_mplane	= vidioc_s_fmt_vid_cap_mplane,
+
+	.vidioc_enum_fmt_vid_out	= vidioc_enum_fmt_vid,
+	.vidioc_g_fmt_vid_out		= vidioc_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out		= vidioc_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out		= vidioc_s_fmt_vid_out,
+	.vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_mplane,
+	.vidioc_g_fmt_vid_out_mplane	= vidioc_g_fmt_vid_out_mplane,
+	.vidioc_try_fmt_vid_out_mplane	= vidioc_try_fmt_vid_out_mplane,
+	.vidioc_s_fmt_vid_out_mplane	= vidioc_s_fmt_vid_out_mplane,
+
+	.vidioc_g_selection		= vidioc_g_selection,
+	.vidioc_s_selection		= vidioc_s_selection,
+	.vidioc_cropcap			= vidioc_cropcap,
+
+	.vidioc_g_fmt_vbi_cap		= vidioc_g_fmt_vbi_cap,
+	.vidioc_try_fmt_vbi_cap		= vidioc_g_fmt_vbi_cap,
+	.vidioc_s_fmt_vbi_cap		= vidioc_s_fmt_vbi_cap,
+
+	.vidioc_g_fmt_sliced_vbi_cap    = vidioc_g_fmt_sliced_vbi_cap,
+	.vidioc_try_fmt_sliced_vbi_cap  = vidioc_try_fmt_sliced_vbi_cap,
+	.vidioc_s_fmt_sliced_vbi_cap    = vidioc_s_fmt_sliced_vbi_cap,
+	.vidioc_g_sliced_vbi_cap	= vidioc_g_sliced_vbi_cap,
+
+	.vidioc_g_fmt_vbi_out		= vidioc_g_fmt_vbi_out,
+	.vidioc_try_fmt_vbi_out		= vidioc_g_fmt_vbi_out,
+	.vidioc_s_fmt_vbi_out		= vidioc_s_fmt_vbi_out,
+
+	.vidioc_g_fmt_sliced_vbi_out    = vidioc_g_fmt_sliced_vbi_out,
+	.vidioc_try_fmt_sliced_vbi_out  = vidioc_try_fmt_sliced_vbi_out,
+	.vidioc_s_fmt_sliced_vbi_out    = vidioc_s_fmt_sliced_vbi_out,
+
+	.vidioc_enum_fmt_sdr_cap	= vidioc_enum_fmt_sdr_cap,
+	.vidioc_g_fmt_sdr_cap		= vidioc_g_fmt_sdr_cap,
+	.vidioc_try_fmt_sdr_cap		= vidioc_g_fmt_sdr_cap,
+	.vidioc_s_fmt_sdr_cap		= vidioc_g_fmt_sdr_cap,
+
+	.vidioc_overlay			= vidioc_overlay,
+	.vidioc_enum_framesizes		= vidioc_enum_framesizes,
+	.vidioc_enum_frameintervals	= vidioc_enum_frameintervals,
+	.vidioc_g_parm			= vidioc_g_parm,
+	.vidioc_s_parm			= vidioc_s_parm,
+
+	.vidioc_enum_fmt_vid_overlay	= vidioc_enum_fmt_vid_overlay,
+	.vidioc_g_fmt_vid_overlay	= vidioc_g_fmt_vid_overlay,
+	.vidioc_try_fmt_vid_overlay	= vidioc_try_fmt_vid_overlay,
+	.vidioc_s_fmt_vid_overlay	= vidioc_s_fmt_vid_overlay,
+	.vidioc_g_fmt_vid_out_overlay	= vidioc_g_fmt_vid_out_overlay,
+	.vidioc_try_fmt_vid_out_overlay	= vidioc_try_fmt_vid_out_overlay,
+	.vidioc_s_fmt_vid_out_overlay	= vidioc_s_fmt_vid_out_overlay,
+	.vidioc_g_fbuf			= vidioc_g_fbuf,
+	.vidioc_s_fbuf			= vidioc_s_fbuf,
+
+	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
+	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
+	.vidioc_querybuf		= vb2_ioctl_querybuf,
+	.vidioc_qbuf			= vb2_ioctl_qbuf,
+	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
+/* Not yet	.vidioc_expbuf		= vb2_ioctl_expbuf,*/
+	.vidioc_streamon		= vb2_ioctl_streamon,
+	.vidioc_streamoff		= vb2_ioctl_streamoff,
+
+	.vidioc_enum_input		= vidioc_enum_input,
+	.vidioc_g_input			= vidioc_g_input,
+	.vidioc_s_input			= vidioc_s_input,
+	.vidioc_s_audio			= vidioc_s_audio,
+	.vidioc_g_audio			= vidioc_g_audio,
+	.vidioc_enumaudio		= vidioc_enumaudio,
+	.vidioc_s_frequency		= vidioc_s_frequency,
+	.vidioc_g_frequency		= vidioc_g_frequency,
+	.vidioc_s_tuner			= vidioc_s_tuner,
+	.vidioc_g_tuner			= vidioc_g_tuner,
+	.vidioc_s_modulator		= vidioc_s_modulator,
+	.vidioc_g_modulator		= vidioc_g_modulator,
+	.vidioc_s_hw_freq_seek		= vidioc_s_hw_freq_seek,
+	.vidioc_enum_freq_bands		= vidioc_enum_freq_bands,
+
+	.vidioc_enum_output		= vidioc_enum_output,
+	.vidioc_g_output		= vidioc_g_output,
+	.vidioc_s_output		= vidioc_s_output,
+	.vidioc_s_audout		= vidioc_s_audout,
+	.vidioc_g_audout		= vidioc_g_audout,
+	.vidioc_enumaudout		= vidioc_enumaudout,
+
+	.vidioc_querystd		= vidioc_querystd,
+	.vidioc_g_std			= vidioc_g_std,
+	.vidioc_s_std			= vidioc_s_std,
+	.vidioc_s_dv_timings		= vidioc_s_dv_timings,
+	.vidioc_g_dv_timings		= vidioc_g_dv_timings,
+	.vidioc_query_dv_timings	= vidioc_query_dv_timings,
+	.vidioc_enum_dv_timings		= vidioc_enum_dv_timings,
+	.vidioc_dv_timings_cap		= vidioc_dv_timings_cap,
+	.vidioc_g_edid			= vidioc_g_edid,
+	.vidioc_s_edid			= vidioc_s_edid,
+
+	.vidioc_log_status		= v4l2_ctrl_log_status,
+	.vidioc_subscribe_event		= vidioc_subscribe_event,
+	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
+};
+
+/* -----------------------------------------------------------------
+	Initialization and module stuff
+   ------------------------------------------------------------------*/
+
+static int __init vivid_create_instance(int inst)
+{
+	static const struct v4l2_dv_timings def_dv_timings =
+					V4L2_DV_BT_CEA_1280X720P60;
+	unsigned in_type_counter[4] = { 0, 0, 0, 0 };
+	unsigned out_type_counter[4] = { 0, 0, 0, 0 };
+	int ccs_cap = ccs_cap_mode[inst];
+	int ccs_out = ccs_out_mode[inst];
+	bool has_tuner;
+	bool has_modulator;
+	struct vivid_dev *dev;
+	struct video_device *vfd;
+	struct vb2_queue *q;
+	unsigned node_type = node_types[inst];
+	v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0;
+	int ret;
+	int i;
+
+	/* allocate main vivid state structure */
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->inst = inst;
+
+	/* register v4l2_device */
+	snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+			"%s-%03d", VIVID_MODULE_NAME, inst);
+	ret = v4l2_device_register(NULL, &dev->v4l2_dev);
+	if (ret)
+		goto free_dev;
+
+	/* start detecting feature set */
+
+	/* do we use single- or multi-planar? */
+	if (multiplanar[inst] == 0)
+		dev->multiplanar = inst & 1;
+	else
+		dev->multiplanar = multiplanar[inst] > 1;
+	v4l2_info(&dev->v4l2_dev, "using %splanar format API\n",
+			dev->multiplanar ? "multi" : "single ");
+
+	/* how many inputs do we have and of what type? */
+	dev->num_inputs = num_inputs[inst];
+	if (dev->num_inputs < 1)
+		dev->num_inputs = 1;
+	if (dev->num_inputs >= MAX_INPUTS)
+		dev->num_inputs = MAX_INPUTS;
+	for (i = 0; i < dev->num_inputs; i++) {
+		dev->input_type[i] = (input_types[inst] >> (i * 2)) & 0x3;
+		dev->input_name_counter[i] = in_type_counter[dev->input_type[i]]++;
+	}
+	dev->has_audio_inputs = in_type_counter[TV] && in_type_counter[SVID];
+
+	/* how many outputs do we have and of what type? */
+	dev->num_outputs = num_outputs[inst];
+	if (dev->num_outputs < 1)
+		dev->num_outputs = 1;
+	if (dev->num_outputs >= MAX_OUTPUTS)
+		dev->num_outputs = MAX_OUTPUTS;
+	for (i = 0; i < dev->num_outputs; i++) {
+		dev->output_type[i] = ((output_types[inst] >> i) & 1) ? HDMI : SVID;
+		dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++;
+	}
+	dev->has_audio_outputs = out_type_counter[SVID];
+
+	/* do we create a video capture device? */
+	dev->has_vid_cap = node_type & 0x0001;
+
+	/* do we create a vbi capture device? */
+	if (in_type_counter[TV] || in_type_counter[SVID]) {
+		dev->has_raw_vbi_cap = node_type & 0x0004;
+		dev->has_sliced_vbi_cap = node_type & 0x0008;
+		dev->has_vbi_cap = dev->has_raw_vbi_cap | dev->has_sliced_vbi_cap;
+	}
+
+	/* do we create a video output device? */
+	dev->has_vid_out = node_type & 0x0100;
+
+	/* do we create a vbi output device? */
+	if (out_type_counter[SVID]) {
+		dev->has_raw_vbi_out = node_type & 0x0400;
+		dev->has_sliced_vbi_out = node_type & 0x0800;
+		dev->has_vbi_out = dev->has_raw_vbi_out | dev->has_sliced_vbi_out;
+	}
+
+	/* do we create a radio receiver device? */
+	dev->has_radio_rx = node_type & 0x0010;
+
+	/* do we create a radio transmitter device? */
+	dev->has_radio_tx = node_type & 0x1000;
+
+	/* do we create a software defined radio capture device? */
+	dev->has_sdr_cap = node_type & 0x0020;
+
+	/* do we have a tuner? */
+	has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) ||
+		    dev->has_radio_rx || dev->has_sdr_cap;
+
+	/* do we have a modulator? */
+	has_modulator = dev->has_radio_tx;
+
+	if (dev->has_vid_cap)
+		/* do we have a framebuffer for overlay testing? */
+		dev->has_fb = node_type & 0x10000;
+
+	/* can we do crop/compose/scaling while capturing? */
+	if (no_error_inj && ccs_cap == -1)
+		ccs_cap = 7;
+
+	/* if ccs_cap == -1, then the use can select it using controls */
+	if (ccs_cap != -1) {
+		dev->has_crop_cap = ccs_cap & 1;
+		dev->has_compose_cap = ccs_cap & 2;
+		dev->has_scaler_cap = ccs_cap & 4;
+		v4l2_info(&dev->v4l2_dev, "Capture Crop: %c Compose: %c Scaler: %c\n",
+			dev->has_crop_cap ? 'Y' : 'N',
+			dev->has_compose_cap ? 'Y' : 'N',
+			dev->has_scaler_cap ? 'Y' : 'N');
+	}
+
+	/* can we do crop/compose/scaling with video output? */
+	if (no_error_inj && ccs_out == -1)
+		ccs_out = 7;
+
+	/* if ccs_out == -1, then the use can select it using controls */
+	if (ccs_out != -1) {
+		dev->has_crop_out = ccs_out & 1;
+		dev->has_compose_out = ccs_out & 2;
+		dev->has_scaler_out = ccs_out & 4;
+		v4l2_info(&dev->v4l2_dev, "Output Crop: %c Compose: %c Scaler: %c\n",
+			dev->has_crop_out ? 'Y' : 'N',
+			dev->has_compose_out ? 'Y' : 'N',
+			dev->has_scaler_out ? 'Y' : 'N');
+	}
+
+	/* end detecting feature set */
+
+	if (dev->has_vid_cap) {
+		/* set up the capabilities of the video capture device */
+		dev->vid_cap_caps = dev->multiplanar ?
+			V4L2_CAP_VIDEO_CAPTURE_MPLANE :
+			V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY;
+		dev->vid_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+		if (dev->has_audio_inputs)
+			dev->vid_cap_caps |= V4L2_CAP_AUDIO;
+		if (in_type_counter[TV])
+			dev->vid_cap_caps |= V4L2_CAP_TUNER;
+	}
+	if (dev->has_vid_out) {
+		/* set up the capabilities of the video output device */
+		dev->vid_out_caps = dev->multiplanar ?
+			V4L2_CAP_VIDEO_OUTPUT_MPLANE :
+			V4L2_CAP_VIDEO_OUTPUT;
+		if (dev->has_fb)
+			dev->vid_out_caps |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+		dev->vid_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+		if (dev->has_audio_outputs)
+			dev->vid_out_caps |= V4L2_CAP_AUDIO;
+	}
+	if (dev->has_vbi_cap) {
+		/* set up the capabilities of the vbi capture device */
+		dev->vbi_cap_caps = (dev->has_raw_vbi_cap ? V4L2_CAP_VBI_CAPTURE : 0) |
+				    (dev->has_sliced_vbi_cap ? V4L2_CAP_SLICED_VBI_CAPTURE : 0);
+		dev->vbi_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+		if (dev->has_audio_inputs)
+			dev->vbi_cap_caps |= V4L2_CAP_AUDIO;
+		if (in_type_counter[TV])
+			dev->vbi_cap_caps |= V4L2_CAP_TUNER;
+	}
+	if (dev->has_vbi_out) {
+		/* set up the capabilities of the vbi output device */
+		dev->vbi_out_caps = (dev->has_raw_vbi_out ? V4L2_CAP_VBI_OUTPUT : 0) |
+				    (dev->has_sliced_vbi_out ? V4L2_CAP_SLICED_VBI_OUTPUT : 0);
+		dev->vbi_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+		if (dev->has_audio_outputs)
+			dev->vbi_out_caps |= V4L2_CAP_AUDIO;
+	}
+	if (dev->has_sdr_cap) {
+		/* set up the capabilities of the sdr capture device */
+		dev->sdr_cap_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER;
+		dev->sdr_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+	}
+	/* set up the capabilities of the radio receiver device */
+	if (dev->has_radio_rx)
+		dev->radio_rx_caps = V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE |
+				     V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
+				     V4L2_CAP_READWRITE;
+	/* set up the capabilities of the radio transmitter device */
+	if (dev->has_radio_tx)
+		dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR |
+				     V4L2_CAP_READWRITE;
+
+	/* initialize the test pattern generator */
+	tpg_init(&dev->tpg, 640, 360);
+	if (tpg_alloc(&dev->tpg, MAX_ZOOM * MAX_WIDTH))
+		goto free_dev;
+	dev->scaled_line = vzalloc(MAX_ZOOM * MAX_WIDTH);
+	if (!dev->scaled_line)
+		goto free_dev;
+	dev->blended_line = vzalloc(MAX_ZOOM * MAX_WIDTH);
+	if (!dev->blended_line)
+		goto free_dev;
+
+	/* load the edid */
+	dev->edid = vmalloc(256 * 128);
+	if (!dev->edid)
+		goto free_dev;
+
+	/* create a string array containing the names of all the preset timings */
+	while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width)
+		dev->query_dv_timings_size++;
+	dev->query_dv_timings_qmenu = kmalloc(dev->query_dv_timings_size *
+					   (sizeof(void *) + 32), GFP_KERNEL);
+	if (dev->query_dv_timings_qmenu == NULL)
+		goto free_dev;
+	for (i = 0; i < dev->query_dv_timings_size; i++) {
+		const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt;
+		char *p = (char *)&dev->query_dv_timings_qmenu[dev->query_dv_timings_size];
+		u32 htot, vtot;
+
+		p += i * 32;
+		dev->query_dv_timings_qmenu[i] = p;
+
+		htot = V4L2_DV_BT_FRAME_WIDTH(bt);
+		vtot = V4L2_DV_BT_FRAME_HEIGHT(bt);
+		snprintf(p, 32, "%ux%u%s%u",
+			bt->width, bt->height, bt->interlaced ? "i" : "p",
+			(u32)bt->pixelclock / (htot * vtot));
+	}
+
+	/* disable invalid ioctls based on the feature set */
+	if (!dev->has_audio_inputs) {
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_AUDIO);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_AUDIO);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMAUDIO);
+		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_AUDIO);
+		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_AUDIO);
+		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_ENUMAUDIO);
+	}
+	if (!dev->has_audio_outputs) {
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT);
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_AUDOUT);
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMAUDOUT);
+		v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_AUDOUT);
+		v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_AUDOUT);
+		v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_ENUMAUDOUT);
+	}
+	if (!in_type_counter[TV] && !in_type_counter[SVID]) {
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_STD);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_STD);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMSTD);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERYSTD);
+	}
+	if (!out_type_counter[SVID]) {
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_STD);
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_STD);
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMSTD);
+	}
+	if (!has_tuner && !has_modulator) {
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_FREQUENCY);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_FREQUENCY);
+		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_FREQUENCY);
+		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY);
+	}
+	if (!has_tuner) {
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_TUNER);
+		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_TUNER);
+		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER);
+	}
+	if (in_type_counter[HDMI] == 0) {
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_EDID);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_DV_TIMINGS_CAP);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_DV_TIMINGS);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_DV_TIMINGS);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUM_DV_TIMINGS);
+		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERY_DV_TIMINGS);
+	}
+	if (out_type_counter[HDMI] == 0) {
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_EDID);
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_DV_TIMINGS_CAP);
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_DV_TIMINGS);
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_DV_TIMINGS);
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_DV_TIMINGS);
+	}
+	if (!dev->has_fb) {
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FBUF);
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FBUF);
+		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_OVERLAY);
+	}
+	v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+	v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+	v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+	v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY);
+	v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY);
+	v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES);
+	v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMEINTERVALS);
+	v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_FREQUENCY);
+	v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_FREQUENCY);
+
+	/* configure internal data */
+	dev->fmt_cap = &vivid_formats[0];
+	dev->fmt_out = &vivid_formats[0];
+	if (!dev->multiplanar)
+		vivid_formats[0].data_offset[0] = 0;
+	dev->webcam_size_idx = 1;
+	dev->webcam_ival_idx = 3;
+	tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
+	dev->std_cap = V4L2_STD_PAL;
+	dev->std_out = V4L2_STD_PAL;
+	if (dev->input_type[0] == TV || dev->input_type[0] == SVID)
+		tvnorms_cap = V4L2_STD_ALL;
+	if (dev->output_type[0] == SVID)
+		tvnorms_out = V4L2_STD_ALL;
+	dev->dv_timings_cap = def_dv_timings;
+	dev->dv_timings_out = def_dv_timings;
+	dev->tv_freq = 2804 /* 175.25 * 16 */;
+	dev->tv_audmode = V4L2_TUNER_MODE_STEREO;
+	dev->tv_field_cap = V4L2_FIELD_INTERLACED;
+	dev->tv_field_out = V4L2_FIELD_INTERLACED;
+	dev->radio_rx_freq = 95000 * 16;
+	dev->radio_rx_audmode = V4L2_TUNER_MODE_STEREO;
+	if (dev->has_radio_tx) {
+		dev->radio_tx_freq = 95500 * 16;
+		dev->radio_rds_loop = false;
+	}
+	dev->radio_tx_subchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS;
+	dev->sdr_adc_freq = 300000;
+	dev->sdr_fm_freq = 50000000;
+	dev->edid_max_blocks = dev->edid_blocks = 2;
+	memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid));
+	ktime_get_ts(&dev->radio_rds_init_ts);
+
+	/* create all controls */
+	ret = vivid_create_controls(dev, ccs_cap == -1, ccs_out == -1, no_error_inj,
+			in_type_counter[TV] || in_type_counter[SVID] ||
+			out_type_counter[SVID],
+			in_type_counter[HDMI] || out_type_counter[HDMI]);
+	if (ret)
+		goto unreg_dev;
+
+	/*
+	 * update the capture and output formats to do a proper initial
+	 * configuration.
+	 */
+	vivid_update_format_cap(dev, false);
+	vivid_update_format_out(dev);
+
+	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);
+	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out);
+	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap);
+	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out);
+	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx);
+	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx);
+	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
+
+	/* initialize overlay */
+	dev->fb_cap.fmt.width = dev->src_rect.width;
+	dev->fb_cap.fmt.height = dev->src_rect.height;
+	dev->fb_cap.fmt.pixelformat = dev->fmt_cap->fourcc;
+	dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
+	dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
+
+	/* initialize locks */
+	spin_lock_init(&dev->slock);
+	mutex_init(&dev->mutex);
+
+	/* init dma queues */
+	INIT_LIST_HEAD(&dev->vid_cap_active);
+	INIT_LIST_HEAD(&dev->vid_out_active);
+	INIT_LIST_HEAD(&dev->vbi_cap_active);
+	INIT_LIST_HEAD(&dev->vbi_out_active);
+	INIT_LIST_HEAD(&dev->sdr_cap_active);
+
+	/* start creating the vb2 queues */
+	if (dev->has_vid_cap) {
+		/* initialize vid_cap queue */
+		q = &dev->vb_vid_cap_q;
+		q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+			V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+		q->drv_priv = dev;
+		q->buf_struct_size = sizeof(struct vivid_buffer);
+		q->ops = &vivid_vid_cap_qops;
+		q->mem_ops = &vb2_vmalloc_memops;
+		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+		q->min_buffers_needed = 2;
+
+		ret = vb2_queue_init(q);
+		if (ret)
+			goto unreg_dev;
+	}
+
+	if (dev->has_vid_out) {
+		/* initialize vid_out queue */
+		q = &dev->vb_vid_out_q;
+		q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+			V4L2_BUF_TYPE_VIDEO_OUTPUT;
+		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE;
+		q->drv_priv = dev;
+		q->buf_struct_size = sizeof(struct vivid_buffer);
+		q->ops = &vivid_vid_out_qops;
+		q->mem_ops = &vb2_vmalloc_memops;
+		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+		q->min_buffers_needed = 2;
+
+		ret = vb2_queue_init(q);
+		if (ret)
+			goto unreg_dev;
+	}
+
+	if (dev->has_vbi_cap) {
+		/* initialize vbi_cap queue */
+		q = &dev->vb_vbi_cap_q;
+		q->type = dev->has_raw_vbi_cap ? V4L2_BUF_TYPE_VBI_CAPTURE :
+					      V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+		q->drv_priv = dev;
+		q->buf_struct_size = sizeof(struct vivid_buffer);
+		q->ops = &vivid_vbi_cap_qops;
+		q->mem_ops = &vb2_vmalloc_memops;
+		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+		q->min_buffers_needed = 2;
+
+		ret = vb2_queue_init(q);
+		if (ret)
+			goto unreg_dev;
+	}
+
+	if (dev->has_vbi_out) {
+		/* initialize vbi_out queue */
+		q = &dev->vb_vbi_out_q;
+		q->type = dev->has_raw_vbi_out ? V4L2_BUF_TYPE_VBI_OUTPUT :
+					      V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
+		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE;
+		q->drv_priv = dev;
+		q->buf_struct_size = sizeof(struct vivid_buffer);
+		q->ops = &vivid_vbi_out_qops;
+		q->mem_ops = &vb2_vmalloc_memops;
+		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+		q->min_buffers_needed = 2;
+
+		ret = vb2_queue_init(q);
+		if (ret)
+			goto unreg_dev;
+	}
+
+	if (dev->has_sdr_cap) {
+		/* initialize sdr_cap queue */
+		q = &dev->vb_sdr_cap_q;
+		q->type = V4L2_BUF_TYPE_SDR_CAPTURE;
+		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+		q->drv_priv = dev;
+		q->buf_struct_size = sizeof(struct vivid_buffer);
+		q->ops = &vivid_sdr_cap_qops;
+		q->mem_ops = &vb2_vmalloc_memops;
+		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+		q->min_buffers_needed = 8;
+
+		ret = vb2_queue_init(q);
+		if (ret)
+			goto unreg_dev;
+	}
+
+	if (dev->has_fb) {
+		/* Create framebuffer for testing capture/output overlay */
+		ret = vivid_fb_init(dev);
+		if (ret)
+			goto unreg_dev;
+		v4l2_info(&dev->v4l2_dev, "Framebuffer device registered as fb%d\n",
+				dev->fb_info.node);
+	}
+
+	/* finally start creating the device nodes */
+	if (dev->has_vid_cap) {
+		vfd = &dev->vid_cap_dev;
+		strlcpy(vfd->name, "vivid-vid-cap", sizeof(vfd->name));
+		vfd->fops = &vivid_fops;
+		vfd->ioctl_ops = &vivid_ioctl_ops;
+		vfd->release = video_device_release_empty;
+		vfd->v4l2_dev = &dev->v4l2_dev;
+		vfd->queue = &dev->vb_vid_cap_q;
+		vfd->tvnorms = tvnorms_cap;
+
+		/*
+		 * Provide a mutex to v4l2 core. It will be used to protect
+		 * all fops and v4l2 ioctls.
+		 */
+		vfd->lock = &dev->mutex;
+		video_set_drvdata(vfd, dev);
+
+		ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_cap_nr[inst]);
+		if (ret < 0)
+			goto unreg_dev;
+		v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n",
+					  video_device_node_name(vfd));
+	}
+
+	if (dev->has_vid_out) {
+		vfd = &dev->vid_out_dev;
+		strlcpy(vfd->name, "vivid-vid-out", sizeof(vfd->name));
+		vfd->vfl_dir = VFL_DIR_TX;
+		vfd->fops = &vivid_fops;
+		vfd->ioctl_ops = &vivid_ioctl_ops;
+		vfd->release = video_device_release_empty;
+		vfd->v4l2_dev = &dev->v4l2_dev;
+		vfd->queue = &dev->vb_vid_out_q;
+		vfd->tvnorms = tvnorms_out;
+
+		/*
+		 * Provide a mutex to v4l2 core. It will be used to protect
+		 * all fops and v4l2 ioctls.
+		 */
+		vfd->lock = &dev->mutex;
+		video_set_drvdata(vfd, dev);
+
+		ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_out_nr[inst]);
+		if (ret < 0)
+			goto unreg_dev;
+		v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s\n",
+					  video_device_node_name(vfd));
+	}
+
+	if (dev->has_vbi_cap) {
+		vfd = &dev->vbi_cap_dev;
+		strlcpy(vfd->name, "vivid-vbi-cap", sizeof(vfd->name));
+		vfd->fops = &vivid_fops;
+		vfd->ioctl_ops = &vivid_ioctl_ops;
+		vfd->release = video_device_release_empty;
+		vfd->v4l2_dev = &dev->v4l2_dev;
+		vfd->queue = &dev->vb_vbi_cap_q;
+		vfd->lock = &dev->mutex;
+		vfd->tvnorms = tvnorms_cap;
+		video_set_drvdata(vfd, dev);
+
+		ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_cap_nr[inst]);
+		if (ret < 0)
+			goto unreg_dev;
+		v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s, supports %s VBI\n",
+					  video_device_node_name(vfd),
+					  (dev->has_raw_vbi_cap && dev->has_sliced_vbi_cap) ?
+					  "raw and sliced" :
+					  (dev->has_raw_vbi_cap ? "raw" : "sliced"));
+	}
+
+	if (dev->has_vbi_out) {
+		vfd = &dev->vbi_out_dev;
+		strlcpy(vfd->name, "vivid-vbi-out", sizeof(vfd->name));
+		vfd->vfl_dir = VFL_DIR_TX;
+		vfd->fops = &vivid_fops;
+		vfd->ioctl_ops = &vivid_ioctl_ops;
+		vfd->release = video_device_release_empty;
+		vfd->v4l2_dev = &dev->v4l2_dev;
+		vfd->queue = &dev->vb_vbi_out_q;
+		vfd->lock = &dev->mutex;
+		vfd->tvnorms = tvnorms_out;
+		video_set_drvdata(vfd, dev);
+
+		ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_out_nr[inst]);
+		if (ret < 0)
+			goto unreg_dev;
+		v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s, supports %s VBI\n",
+					  video_device_node_name(vfd),
+					  (dev->has_raw_vbi_out && dev->has_sliced_vbi_out) ?
+					  "raw and sliced" :
+					  (dev->has_raw_vbi_out ? "raw" : "sliced"));
+	}
+
+	if (dev->has_sdr_cap) {
+		vfd = &dev->sdr_cap_dev;
+		strlcpy(vfd->name, "vivid-sdr-cap", sizeof(vfd->name));
+		vfd->fops = &vivid_fops;
+		vfd->ioctl_ops = &vivid_ioctl_ops;
+		vfd->release = video_device_release_empty;
+		vfd->v4l2_dev = &dev->v4l2_dev;
+		vfd->queue = &dev->vb_sdr_cap_q;
+		vfd->lock = &dev->mutex;
+		video_set_drvdata(vfd, dev);
+
+		ret = video_register_device(vfd, VFL_TYPE_SDR, sdr_cap_nr[inst]);
+		if (ret < 0)
+			goto unreg_dev;
+		v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n",
+					  video_device_node_name(vfd));
+	}
+
+	if (dev->has_radio_rx) {
+		vfd = &dev->radio_rx_dev;
+		strlcpy(vfd->name, "vivid-rad-rx", sizeof(vfd->name));
+		vfd->fops = &vivid_radio_fops;
+		vfd->ioctl_ops = &vivid_ioctl_ops;
+		vfd->release = video_device_release_empty;
+		vfd->v4l2_dev = &dev->v4l2_dev;
+		vfd->lock = &dev->mutex;
+		video_set_drvdata(vfd, dev);
+
+		ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_rx_nr[inst]);
+		if (ret < 0)
+			goto unreg_dev;
+		v4l2_info(&dev->v4l2_dev, "V4L2 receiver device registered as %s\n",
+					  video_device_node_name(vfd));
+	}
+
+	if (dev->has_radio_tx) {
+		vfd = &dev->radio_tx_dev;
+		strlcpy(vfd->name, "vivid-rad-tx", sizeof(vfd->name));
+		vfd->vfl_dir = VFL_DIR_TX;
+		vfd->fops = &vivid_radio_fops;
+		vfd->ioctl_ops = &vivid_ioctl_ops;
+		vfd->release = video_device_release_empty;
+		vfd->v4l2_dev = &dev->v4l2_dev;
+		vfd->lock = &dev->mutex;
+		video_set_drvdata(vfd, dev);
+
+		ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_tx_nr[inst]);
+		if (ret < 0)
+			goto unreg_dev;
+		v4l2_info(&dev->v4l2_dev, "V4L2 transmitter device registered as %s\n",
+					  video_device_node_name(vfd));
+	}
+
+	/* Now that everything is fine, let's add it to device list */
+	vivid_devs[inst] = dev;
+
+	return 0;
+
+unreg_dev:
+	video_unregister_device(&dev->radio_tx_dev);
+	video_unregister_device(&dev->radio_rx_dev);
+	video_unregister_device(&dev->sdr_cap_dev);
+	video_unregister_device(&dev->vbi_out_dev);
+	video_unregister_device(&dev->vbi_cap_dev);
+	video_unregister_device(&dev->vid_out_dev);
+	video_unregister_device(&dev->vid_cap_dev);
+	vivid_free_controls(dev);
+	v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+	vfree(dev->scaled_line);
+	vfree(dev->blended_line);
+	vfree(dev->edid);
+	tpg_free(&dev->tpg);
+	kfree(dev->query_dv_timings_qmenu);
+	kfree(dev);
+	return ret;
+}
+
+/* This routine allocates from 1 to n_devs virtual drivers.
+
+   The real maximum number of virtual drivers will depend on how many drivers
+   will succeed. This is limited to the maximum number of devices that
+   videodev supports, which is equal to VIDEO_NUM_DEVICES.
+ */
+static int __init vivid_init(void)
+{
+	const struct font_desc *font = find_font("VGA8x16");
+	int ret = 0, i;
+
+	if (font == NULL) {
+		pr_err("vivid: could not find font\n");
+		return -ENODEV;
+	}
+
+	tpg_set_font(font->data);
+
+	n_devs = clamp_t(unsigned, n_devs, 1, VIVID_MAX_DEVS);
+
+	for (i = 0; i < n_devs; i++) {
+		ret = vivid_create_instance(i);
+		if (ret) {
+			/* If some instantiations succeeded, keep driver */
+			if (i)
+				ret = 0;
+			break;
+		}
+	}
+
+	if (ret < 0) {
+		pr_err("vivid: error %d while loading driver\n", ret);
+		return ret;
+	}
+
+	/* n_devs will reflect the actual number of allocated devices */
+	n_devs = i;
+
+	return ret;
+}
+
+static void __exit vivid_exit(void)
+{
+	struct vivid_dev *dev;
+	unsigned i;
+
+	for (i = 0; vivid_devs[i]; i++) {
+		dev = vivid_devs[i];
+
+		if (dev->has_vid_cap) {
+			v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+				video_device_node_name(&dev->vid_cap_dev));
+			video_unregister_device(&dev->vid_cap_dev);
+		}
+		if (dev->has_vid_out) {
+			v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+				video_device_node_name(&dev->vid_out_dev));
+			video_unregister_device(&dev->vid_out_dev);
+		}
+		if (dev->has_vbi_cap) {
+			v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+				video_device_node_name(&dev->vbi_cap_dev));
+			video_unregister_device(&dev->vbi_cap_dev);
+		}
+		if (dev->has_vbi_out) {
+			v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+				video_device_node_name(&dev->vbi_out_dev));
+			video_unregister_device(&dev->vbi_out_dev);
+		}
+		if (dev->has_sdr_cap) {
+			v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+				video_device_node_name(&dev->sdr_cap_dev));
+			video_unregister_device(&dev->sdr_cap_dev);
+		}
+		if (dev->has_radio_rx) {
+			v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+				video_device_node_name(&dev->radio_rx_dev));
+			video_unregister_device(&dev->radio_rx_dev);
+		}
+		if (dev->has_radio_tx) {
+			v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+				video_device_node_name(&dev->radio_tx_dev));
+			video_unregister_device(&dev->radio_tx_dev);
+		}
+		if (dev->has_fb) {
+			v4l2_info(&dev->v4l2_dev, "unregistering fb%d\n",
+				dev->fb_info.node);
+			unregister_framebuffer(&dev->fb_info);
+			vivid_fb_release_buffers(dev);
+		}
+		v4l2_device_unregister(&dev->v4l2_dev);
+		vivid_free_controls(dev);
+		vfree(dev->scaled_line);
+		vfree(dev->blended_line);
+		vfree(dev->edid);
+		vfree(dev->bitmap_cap);
+		vfree(dev->bitmap_out);
+		tpg_free(&dev->tpg);
+		kfree(dev->query_dv_timings_qmenu);
+		kfree(dev);
+		vivid_devs[i] = NULL;
+	}
+}
+
+module_init(vivid_init);
+module_exit(vivid_exit);
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
new file mode 100644
index 0000000..811c286
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -0,0 +1,520 @@
+/*
+ * vivid-core.h - core datastructures
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_CORE_H_
+#define _VIVID_CORE_H_
+
+#include <linux/fb.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ctrls.h>
+#include "vivid-tpg.h"
+#include "vivid-rds-gen.h"
+#include "vivid-vbi-gen.h"
+
+#define dprintk(dev, level, fmt, arg...) \
+	v4l2_dbg(level, vivid_debug, &dev->v4l2_dev, fmt, ## arg)
+
+/* Maximum allowed frame rate
+ *
+ * vivid will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range.
+ *
+ * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that
+ * might hit application errors when they manipulate these values.
+ *
+ * Besides, for tpf < 10ms image-generation logic should be changed, to avoid
+ * producing frames with equal content.
+ */
+#define FPS_MAX 100
+
+/* The maximum number of clip rectangles */
+#define MAX_CLIPS  16
+/* The maximum number of inputs */
+#define MAX_INPUTS 16
+/* The maximum number of outputs */
+#define MAX_OUTPUTS 16
+/* The maximum up or down scaling factor is 4 */
+#define MAX_ZOOM  4
+/* The maximum image width/height are set to 4K DMT */
+#define MAX_WIDTH  4096
+#define MAX_HEIGHT 2160
+/* The minimum image width/height */
+#define MIN_WIDTH  16
+#define MIN_HEIGHT 16
+/* The data_offset of plane 0 for the multiplanar formats */
+#define PLANE0_DATA_OFFSET 128
+
+/* The supported TV frequency range in MHz */
+#define MIN_TV_FREQ (44U * 16U)
+#define MAX_TV_FREQ (958U * 16U)
+
+/* The number of samples returned in every SDR buffer */
+#define SDR_CAP_SAMPLES_PER_BUF 0x4000
+
+/* used by the threads to know when to resync internal counters */
+#define JIFFIES_PER_DAY (3600U * 24U * HZ)
+#define JIFFIES_RESYNC (JIFFIES_PER_DAY * (0xf0000000U / JIFFIES_PER_DAY))
+
+extern const struct v4l2_rect vivid_min_rect;
+extern const struct v4l2_rect vivid_max_rect;
+extern unsigned vivid_debug;
+
+struct vivid_fmt {
+	const char *name;
+	u32	fourcc;          /* v4l2 format id */
+	u8	depth;
+	bool	is_yuv;
+	bool	can_do_overlay;
+	u32	alpha_mask;
+	u8	planes;
+	u32	data_offset[2];
+};
+
+extern struct vivid_fmt vivid_formats[];
+
+/* buffer for one video frame */
+struct vivid_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct vb2_buffer	vb;
+	struct list_head	list;
+};
+
+enum vivid_input {
+	WEBCAM,
+	TV,
+	SVID,
+	HDMI,
+};
+
+enum vivid_signal_mode {
+	CURRENT_DV_TIMINGS,
+	CURRENT_STD = CURRENT_DV_TIMINGS,
+	NO_SIGNAL,
+	NO_LOCK,
+	OUT_OF_RANGE,
+	SELECTED_DV_TIMINGS,
+	SELECTED_STD = SELECTED_DV_TIMINGS,
+	CYCLE_DV_TIMINGS,
+	CYCLE_STD = CYCLE_DV_TIMINGS,
+	CUSTOM_DV_TIMINGS,
+};
+
+#define VIVID_INVALID_SIGNAL(mode) \
+	((mode) == NO_SIGNAL || (mode) == NO_LOCK || (mode) == OUT_OF_RANGE)
+
+struct vivid_dev {
+	unsigned			inst;
+	struct v4l2_device		v4l2_dev;
+	struct v4l2_ctrl_handler	ctrl_hdl_user_gen;
+	struct v4l2_ctrl_handler	ctrl_hdl_user_vid;
+	struct v4l2_ctrl_handler	ctrl_hdl_user_aud;
+	struct v4l2_ctrl_handler	ctrl_hdl_streaming;
+	struct v4l2_ctrl_handler	ctrl_hdl_sdtv_cap;
+	struct v4l2_ctrl_handler	ctrl_hdl_loop_out;
+	struct video_device		vid_cap_dev;
+	struct v4l2_ctrl_handler	ctrl_hdl_vid_cap;
+	struct video_device		vid_out_dev;
+	struct v4l2_ctrl_handler	ctrl_hdl_vid_out;
+	struct video_device		vbi_cap_dev;
+	struct v4l2_ctrl_handler	ctrl_hdl_vbi_cap;
+	struct video_device		vbi_out_dev;
+	struct v4l2_ctrl_handler	ctrl_hdl_vbi_out;
+	struct video_device		radio_rx_dev;
+	struct v4l2_ctrl_handler	ctrl_hdl_radio_rx;
+	struct video_device		radio_tx_dev;
+	struct v4l2_ctrl_handler	ctrl_hdl_radio_tx;
+	struct video_device		sdr_cap_dev;
+	struct v4l2_ctrl_handler	ctrl_hdl_sdr_cap;
+	spinlock_t			slock;
+	struct mutex			mutex;
+
+	/* capabilities */
+	u32				vid_cap_caps;
+	u32				vid_out_caps;
+	u32				vbi_cap_caps;
+	u32				vbi_out_caps;
+	u32				sdr_cap_caps;
+	u32				radio_rx_caps;
+	u32				radio_tx_caps;
+
+	/* supported features */
+	bool				multiplanar;
+	unsigned			num_inputs;
+	u8				input_type[MAX_INPUTS];
+	u8				input_name_counter[MAX_INPUTS];
+	unsigned			num_outputs;
+	u8				output_type[MAX_OUTPUTS];
+	u8				output_name_counter[MAX_OUTPUTS];
+	bool				has_audio_inputs;
+	bool				has_audio_outputs;
+	bool				has_vid_cap;
+	bool				has_vid_out;
+	bool				has_vbi_cap;
+	bool				has_raw_vbi_cap;
+	bool				has_sliced_vbi_cap;
+	bool				has_vbi_out;
+	bool				has_raw_vbi_out;
+	bool				has_sliced_vbi_out;
+	bool				has_radio_rx;
+	bool				has_radio_tx;
+	bool				has_sdr_cap;
+	bool				has_fb;
+
+	bool				can_loop_video;
+
+	/* controls */
+	struct v4l2_ctrl		*brightness;
+	struct v4l2_ctrl		*contrast;
+	struct v4l2_ctrl		*saturation;
+	struct v4l2_ctrl		*hue;
+	struct {
+		/* autogain/gain cluster */
+		struct v4l2_ctrl	*autogain;
+		struct v4l2_ctrl	*gain;
+	};
+	struct v4l2_ctrl		*volume;
+	struct v4l2_ctrl		*mute;
+	struct v4l2_ctrl		*alpha;
+	struct v4l2_ctrl		*button;
+	struct v4l2_ctrl		*boolean;
+	struct v4l2_ctrl		*int32;
+	struct v4l2_ctrl		*int64;
+	struct v4l2_ctrl		*menu;
+	struct v4l2_ctrl		*string;
+	struct v4l2_ctrl		*bitmask;
+	struct v4l2_ctrl		*int_menu;
+	struct v4l2_ctrl		*test_pattern;
+	struct v4l2_ctrl		*colorspace;
+	struct v4l2_ctrl		*rgb_range_cap;
+	struct v4l2_ctrl		*real_rgb_range_cap;
+	struct {
+		/* std_signal_mode/standard cluster */
+		struct v4l2_ctrl	*ctrl_std_signal_mode;
+		struct v4l2_ctrl	*ctrl_standard;
+	};
+	struct {
+		/* dv_timings_signal_mode/timings cluster */
+		struct v4l2_ctrl	*ctrl_dv_timings_signal_mode;
+		struct v4l2_ctrl	*ctrl_dv_timings;
+	};
+	struct v4l2_ctrl		*ctrl_has_crop_cap;
+	struct v4l2_ctrl		*ctrl_has_compose_cap;
+	struct v4l2_ctrl		*ctrl_has_scaler_cap;
+	struct v4l2_ctrl		*ctrl_has_crop_out;
+	struct v4l2_ctrl		*ctrl_has_compose_out;
+	struct v4l2_ctrl		*ctrl_has_scaler_out;
+	struct v4l2_ctrl		*ctrl_tx_mode;
+	struct v4l2_ctrl		*ctrl_tx_rgb_range;
+
+	struct v4l2_ctrl		*radio_tx_rds_pi;
+	struct v4l2_ctrl		*radio_tx_rds_pty;
+	struct v4l2_ctrl		*radio_tx_rds_mono_stereo;
+	struct v4l2_ctrl		*radio_tx_rds_art_head;
+	struct v4l2_ctrl		*radio_tx_rds_compressed;
+	struct v4l2_ctrl		*radio_tx_rds_dyn_pty;
+	struct v4l2_ctrl		*radio_tx_rds_ta;
+	struct v4l2_ctrl		*radio_tx_rds_tp;
+	struct v4l2_ctrl		*radio_tx_rds_ms;
+	struct v4l2_ctrl		*radio_tx_rds_psname;
+	struct v4l2_ctrl		*radio_tx_rds_radiotext;
+
+	struct v4l2_ctrl		*radio_rx_rds_pty;
+	struct v4l2_ctrl		*radio_rx_rds_ta;
+	struct v4l2_ctrl		*radio_rx_rds_tp;
+	struct v4l2_ctrl		*radio_rx_rds_ms;
+	struct v4l2_ctrl		*radio_rx_rds_psname;
+	struct v4l2_ctrl		*radio_rx_rds_radiotext;
+
+	unsigned			input_brightness[MAX_INPUTS];
+	unsigned			osd_mode;
+	unsigned			button_pressed;
+	bool				sensor_hflip;
+	bool				sensor_vflip;
+	bool				hflip;
+	bool				vflip;
+	bool				vbi_cap_interlaced;
+	bool				loop_video;
+
+	/* Framebuffer */
+	unsigned long			video_pbase;
+	void				*video_vbase;
+	u32				video_buffer_size;
+	int				display_width;
+	int				display_height;
+	int				display_byte_stride;
+	int				bits_per_pixel;
+	int				bytes_per_pixel;
+	struct fb_info			fb_info;
+	struct fb_var_screeninfo	fb_defined;
+	struct fb_fix_screeninfo	fb_fix;
+
+	/* Error injection */
+	bool				queue_setup_error;
+	bool				buf_prepare_error;
+	bool				start_streaming_error;
+	bool				dqbuf_error;
+	bool				seq_wrap;
+	bool				time_wrap;
+	__kernel_time_t			time_wrap_offset;
+	unsigned			perc_dropped_buffers;
+	enum vivid_signal_mode		std_signal_mode;
+	unsigned			query_std_last;
+	v4l2_std_id			query_std;
+	enum tpg_video_aspect		std_aspect_ratio;
+
+	enum vivid_signal_mode		dv_timings_signal_mode;
+	char				**query_dv_timings_qmenu;
+	unsigned			query_dv_timings_size;
+	unsigned			query_dv_timings_last;
+	unsigned			query_dv_timings;
+	enum tpg_video_aspect		dv_timings_aspect_ratio;
+
+	/* Input */
+	unsigned			input;
+	v4l2_std_id			std_cap;
+	struct v4l2_dv_timings		dv_timings_cap;
+	u32				service_set_cap;
+	struct vivid_vbi_gen_data	vbi_gen;
+	u8				*edid;
+	unsigned			edid_blocks;
+	unsigned			edid_max_blocks;
+	unsigned			webcam_size_idx;
+	unsigned			webcam_ival_idx;
+	unsigned			tv_freq;
+	unsigned			tv_audmode;
+	unsigned			tv_field_cap;
+	unsigned			tv_audio_input;
+
+	/* Capture Overlay */
+	struct v4l2_framebuffer		fb_cap;
+	struct v4l2_fh			*overlay_cap_owner;
+	void				*fb_vbase_cap;
+	int				overlay_cap_top, overlay_cap_left;
+	enum v4l2_field			overlay_cap_field;
+	void				*bitmap_cap;
+	struct v4l2_clip		clips_cap[MAX_CLIPS];
+	struct v4l2_clip		try_clips_cap[MAX_CLIPS];
+	unsigned			clipcount_cap;
+
+	/* Output */
+	unsigned			output;
+	v4l2_std_id			std_out;
+	struct v4l2_dv_timings		dv_timings_out;
+	u32				colorspace_out;
+	u32				service_set_out;
+	u32				bytesperline_out[2];
+	unsigned			tv_field_out;
+	unsigned			tv_audio_output;
+	bool				vbi_out_have_wss;
+	u8				vbi_out_wss[2];
+	bool				vbi_out_have_cc[2];
+	u8				vbi_out_cc[2][2];
+	bool				dvi_d_out;
+	u8				*scaled_line;
+	u8				*blended_line;
+	unsigned			cur_scaled_line;
+
+	/* Output Overlay */
+	void				*fb_vbase_out;
+	bool				overlay_out_enabled;
+	int				overlay_out_top, overlay_out_left;
+	void				*bitmap_out;
+	struct v4l2_clip		clips_out[MAX_CLIPS];
+	struct v4l2_clip		try_clips_out[MAX_CLIPS];
+	unsigned			clipcount_out;
+	unsigned			fbuf_out_flags;
+	u32				chromakey_out;
+	u8				global_alpha_out;
+
+	/* video capture */
+	struct tpg_data			tpg;
+	unsigned			ms_vid_cap;
+	bool				must_blank[VIDEO_MAX_FRAME];
+
+	const struct vivid_fmt		*fmt_cap;
+	struct v4l2_fract		timeperframe_vid_cap;
+	enum v4l2_field			field_cap;
+	struct v4l2_rect		src_rect;
+	struct v4l2_rect		fmt_cap_rect;
+	struct v4l2_rect		crop_cap;
+	struct v4l2_rect		compose_cap;
+	struct v4l2_rect		crop_bounds_cap;
+	struct vb2_queue		vb_vid_cap_q;
+	struct list_head		vid_cap_active;
+	struct vb2_queue		vb_vbi_cap_q;
+	struct list_head		vbi_cap_active;
+
+	/* thread for generating video capture stream */
+	struct task_struct		*kthread_vid_cap;
+	unsigned long			jiffies_vid_cap;
+	u32				cap_seq_offset;
+	u32				cap_seq_count;
+	bool				cap_seq_resync;
+	u32				vid_cap_seq_start;
+	u32				vid_cap_seq_count;
+	bool				vid_cap_streaming;
+	u32				vbi_cap_seq_start;
+	u32				vbi_cap_seq_count;
+	bool				vbi_cap_streaming;
+	bool				stream_sliced_vbi_cap;
+
+	/* video output */
+	const struct vivid_fmt		*fmt_out;
+	struct v4l2_fract		timeperframe_vid_out;
+	enum v4l2_field			field_out;
+	struct v4l2_rect		sink_rect;
+	struct v4l2_rect		fmt_out_rect;
+	struct v4l2_rect		crop_out;
+	struct v4l2_rect		compose_out;
+	struct v4l2_rect		compose_bounds_out;
+	struct vb2_queue		vb_vid_out_q;
+	struct list_head		vid_out_active;
+	struct vb2_queue		vb_vbi_out_q;
+	struct list_head		vbi_out_active;
+
+	/* video loop precalculated rectangles */
+
+	/*
+	 * Intersection between what the output side composes and the capture side
+	 * crops. I.e., what actually needs to be copied from the output buffer to
+	 * the capture buffer.
+	 */
+	struct v4l2_rect		loop_vid_copy;
+	/* The part of the output buffer that (after scaling) corresponds to loop_vid_copy. */
+	struct v4l2_rect		loop_vid_out;
+	/* The part of the capture buffer that (after scaling) corresponds to loop_vid_copy. */
+	struct v4l2_rect		loop_vid_cap;
+	/*
+	 * The intersection of the framebuffer, the overlay output window and
+	 * loop_vid_copy. I.e., the part of the framebuffer that actually should be
+	 * blended with the compose_out rectangle. This uses the framebuffer origin.
+	 */
+	struct v4l2_rect		loop_fb_copy;
+	/* The same as loop_fb_copy but with compose_out origin. */
+	struct v4l2_rect		loop_vid_overlay;
+	/*
+	 * The part of the capture buffer that (after scaling) corresponds
+	 * to loop_vid_overlay.
+	 */
+	struct v4l2_rect		loop_vid_overlay_cap;
+
+	/* thread for generating video output stream */
+	struct task_struct		*kthread_vid_out;
+	unsigned long			jiffies_vid_out;
+	u32				out_seq_offset;
+	u32				out_seq_count;
+	bool				out_seq_resync;
+	u32				vid_out_seq_start;
+	u32				vid_out_seq_count;
+	bool				vid_out_streaming;
+	u32				vbi_out_seq_start;
+	u32				vbi_out_seq_count;
+	bool				vbi_out_streaming;
+	bool				stream_sliced_vbi_out;
+
+	/* SDR capture */
+	struct vb2_queue		vb_sdr_cap_q;
+	struct list_head		sdr_cap_active;
+	unsigned			sdr_adc_freq;
+	unsigned			sdr_fm_freq;
+	int				sdr_fixp_src_phase;
+	int				sdr_fixp_mod_phase;
+
+	bool				tstamp_src_is_soe;
+	bool				has_crop_cap;
+	bool				has_compose_cap;
+	bool				has_scaler_cap;
+	bool				has_crop_out;
+	bool				has_compose_out;
+	bool				has_scaler_out;
+
+	/* thread for generating SDR stream */
+	struct task_struct		*kthread_sdr_cap;
+	unsigned long			jiffies_sdr_cap;
+	u32				sdr_cap_seq_offset;
+	u32				sdr_cap_seq_count;
+	bool				sdr_cap_seq_resync;
+
+	/* RDS generator */
+	struct vivid_rds_gen		rds_gen;
+
+	/* Radio receiver */
+	unsigned			radio_rx_freq;
+	unsigned			radio_rx_audmode;
+	int				radio_rx_sig_qual;
+	unsigned			radio_rx_hw_seek_mode;
+	bool				radio_rx_hw_seek_prog_lim;
+	bool				radio_rx_rds_controls;
+	bool				radio_rx_rds_enabled;
+	unsigned			radio_rx_rds_use_alternates;
+	unsigned			radio_rx_rds_last_block;
+	struct v4l2_fh			*radio_rx_rds_owner;
+
+	/* Radio transmitter */
+	unsigned			radio_tx_freq;
+	unsigned			radio_tx_subchans;
+	bool				radio_tx_rds_controls;
+	unsigned			radio_tx_rds_last_block;
+	struct v4l2_fh			*radio_tx_rds_owner;
+
+	/* Shared between radio receiver and transmitter */
+	bool				radio_rds_loop;
+	struct timespec			radio_rds_init_ts;
+};
+
+static inline bool vivid_is_webcam(const struct vivid_dev *dev)
+{
+	return dev->input_type[dev->input] == WEBCAM;
+}
+
+static inline bool vivid_is_tv_cap(const struct vivid_dev *dev)
+{
+	return dev->input_type[dev->input] == TV;
+}
+
+static inline bool vivid_is_svid_cap(const struct vivid_dev *dev)
+{
+	return dev->input_type[dev->input] == SVID;
+}
+
+static inline bool vivid_is_hdmi_cap(const struct vivid_dev *dev)
+{
+	return dev->input_type[dev->input] == HDMI;
+}
+
+static inline bool vivid_is_sdtv_cap(const struct vivid_dev *dev)
+{
+	return vivid_is_tv_cap(dev) || vivid_is_svid_cap(dev);
+}
+
+static inline bool vivid_is_svid_out(const struct vivid_dev *dev)
+{
+	return dev->output_type[dev->output] == SVID;
+}
+
+static inline bool vivid_is_hdmi_out(const struct vivid_dev *dev)
+{
+	return dev->output_type[dev->output] == HDMI;
+}
+
+void vivid_lock(struct vb2_queue *vq);
+void vivid_unlock(struct vb2_queue *vq);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
new file mode 100644
index 0000000..d5cbf00
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -0,0 +1,1502 @@
+/*
+ * vivid-ctrls.c - control support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-cap.h"
+#include "vivid-vid-out.h"
+#include "vivid-vid-common.h"
+#include "vivid-radio-common.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.h"
+
+#define VIVID_CID_CUSTOM_BASE		(V4L2_CID_USER_BASE | 0xf000)
+#define VIVID_CID_BUTTON		(VIVID_CID_CUSTOM_BASE + 0)
+#define VIVID_CID_BOOLEAN		(VIVID_CID_CUSTOM_BASE + 1)
+#define VIVID_CID_INTEGER		(VIVID_CID_CUSTOM_BASE + 2)
+#define VIVID_CID_INTEGER64		(VIVID_CID_CUSTOM_BASE + 3)
+#define VIVID_CID_MENU			(VIVID_CID_CUSTOM_BASE + 4)
+#define VIVID_CID_STRING		(VIVID_CID_CUSTOM_BASE + 5)
+#define VIVID_CID_BITMASK		(VIVID_CID_CUSTOM_BASE + 6)
+#define VIVID_CID_INTMENU		(VIVID_CID_CUSTOM_BASE + 7)
+
+#define VIVID_CID_VIVID_BASE		(0x00f00000 | 0xf000)
+#define VIVID_CID_VIVID_CLASS		(0x00f00000 | 1)
+#define VIVID_CID_TEST_PATTERN		(VIVID_CID_VIVID_BASE + 0)
+#define VIVID_CID_OSD_TEXT_MODE		(VIVID_CID_VIVID_BASE + 1)
+#define VIVID_CID_HOR_MOVEMENT		(VIVID_CID_VIVID_BASE + 2)
+#define VIVID_CID_VERT_MOVEMENT		(VIVID_CID_VIVID_BASE + 3)
+#define VIVID_CID_SHOW_BORDER		(VIVID_CID_VIVID_BASE + 4)
+#define VIVID_CID_SHOW_SQUARE		(VIVID_CID_VIVID_BASE + 5)
+#define VIVID_CID_INSERT_SAV		(VIVID_CID_VIVID_BASE + 6)
+#define VIVID_CID_INSERT_EAV		(VIVID_CID_VIVID_BASE + 7)
+#define VIVID_CID_VBI_CAP_INTERLACED	(VIVID_CID_VIVID_BASE + 8)
+
+#define VIVID_CID_HFLIP			(VIVID_CID_VIVID_BASE + 20)
+#define VIVID_CID_VFLIP			(VIVID_CID_VIVID_BASE + 21)
+#define VIVID_CID_STD_ASPECT_RATIO	(VIVID_CID_VIVID_BASE + 22)
+#define VIVID_CID_DV_TIMINGS_ASPECT_RATIO	(VIVID_CID_VIVID_BASE + 23)
+#define VIVID_CID_TSTAMP_SRC		(VIVID_CID_VIVID_BASE + 24)
+#define VIVID_CID_COLORSPACE		(VIVID_CID_VIVID_BASE + 25)
+#define VIVID_CID_LIMITED_RGB_RANGE	(VIVID_CID_VIVID_BASE + 26)
+#define VIVID_CID_ALPHA_MODE		(VIVID_CID_VIVID_BASE + 27)
+#define VIVID_CID_HAS_CROP_CAP		(VIVID_CID_VIVID_BASE + 28)
+#define VIVID_CID_HAS_COMPOSE_CAP	(VIVID_CID_VIVID_BASE + 29)
+#define VIVID_CID_HAS_SCALER_CAP	(VIVID_CID_VIVID_BASE + 30)
+#define VIVID_CID_HAS_CROP_OUT		(VIVID_CID_VIVID_BASE + 31)
+#define VIVID_CID_HAS_COMPOSE_OUT	(VIVID_CID_VIVID_BASE + 32)
+#define VIVID_CID_HAS_SCALER_OUT	(VIVID_CID_VIVID_BASE + 33)
+#define VIVID_CID_LOOP_VIDEO		(VIVID_CID_VIVID_BASE + 34)
+#define VIVID_CID_SEQ_WRAP		(VIVID_CID_VIVID_BASE + 35)
+#define VIVID_CID_TIME_WRAP		(VIVID_CID_VIVID_BASE + 36)
+#define VIVID_CID_MAX_EDID_BLOCKS	(VIVID_CID_VIVID_BASE + 37)
+#define VIVID_CID_PERCENTAGE_FILL	(VIVID_CID_VIVID_BASE + 38)
+
+#define VIVID_CID_STD_SIGNAL_MODE	(VIVID_CID_VIVID_BASE + 60)
+#define VIVID_CID_STANDARD		(VIVID_CID_VIVID_BASE + 61)
+#define VIVID_CID_DV_TIMINGS_SIGNAL_MODE	(VIVID_CID_VIVID_BASE + 62)
+#define VIVID_CID_DV_TIMINGS		(VIVID_CID_VIVID_BASE + 63)
+#define VIVID_CID_PERC_DROPPED		(VIVID_CID_VIVID_BASE + 64)
+#define VIVID_CID_DISCONNECT		(VIVID_CID_VIVID_BASE + 65)
+#define VIVID_CID_DQBUF_ERROR		(VIVID_CID_VIVID_BASE + 66)
+#define VIVID_CID_QUEUE_SETUP_ERROR	(VIVID_CID_VIVID_BASE + 67)
+#define VIVID_CID_BUF_PREPARE_ERROR	(VIVID_CID_VIVID_BASE + 68)
+#define VIVID_CID_START_STR_ERROR	(VIVID_CID_VIVID_BASE + 69)
+#define VIVID_CID_QUEUE_ERROR		(VIVID_CID_VIVID_BASE + 70)
+#define VIVID_CID_CLEAR_FB		(VIVID_CID_VIVID_BASE + 71)
+
+#define VIVID_CID_RADIO_SEEK_MODE	(VIVID_CID_VIVID_BASE + 90)
+#define VIVID_CID_RADIO_SEEK_PROG_LIM	(VIVID_CID_VIVID_BASE + 91)
+#define VIVID_CID_RADIO_RX_RDS_RBDS	(VIVID_CID_VIVID_BASE + 92)
+#define VIVID_CID_RADIO_RX_RDS_BLOCKIO	(VIVID_CID_VIVID_BASE + 93)
+
+#define VIVID_CID_RADIO_TX_RDS_BLOCKIO	(VIVID_CID_VIVID_BASE + 94)
+
+
+/* General User Controls */
+
+static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_gen);
+
+	switch (ctrl->id) {
+	case VIVID_CID_DISCONNECT:
+		v4l2_info(&dev->v4l2_dev, "disconnect\n");
+		clear_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags);
+		clear_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags);
+		clear_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags);
+		clear_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags);
+		clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags);
+		clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags);
+		clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
+		break;
+	case VIVID_CID_CLEAR_FB:
+		vivid_clear_fb(dev);
+		break;
+	case VIVID_CID_BUTTON:
+		dev->button_pressed = 30;
+		break;
+	}
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_user_gen_ctrl_ops = {
+	.s_ctrl = vivid_user_gen_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_button = {
+	.ops = &vivid_user_gen_ctrl_ops,
+	.id = VIVID_CID_BUTTON,
+	.name = "Button",
+	.type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_boolean = {
+	.ops = &vivid_user_gen_ctrl_ops,
+	.id = VIVID_CID_BOOLEAN,
+	.name = "Boolean",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.min = 0,
+	.max = 1,
+	.step = 1,
+	.def = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_int32 = {
+	.ops = &vivid_user_gen_ctrl_ops,
+	.id = VIVID_CID_INTEGER,
+	.name = "Integer 32 Bits",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0xffffffff80000000ULL,
+	.max = 0x7fffffff,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_int64 = {
+	.ops = &vivid_user_gen_ctrl_ops,
+	.id = VIVID_CID_INTEGER64,
+	.name = "Integer 64 Bits",
+	.type = V4L2_CTRL_TYPE_INTEGER64,
+	.min = 0x8000000000000000ULL,
+	.max = 0x7fffffffffffffffLL,
+	.step = 1,
+};
+
+static const char * const vivid_ctrl_menu_strings[] = {
+	"Menu Item 0 (Skipped)",
+	"Menu Item 1",
+	"Menu Item 2 (Skipped)",
+	"Menu Item 3",
+	"Menu Item 4",
+	"Menu Item 5 (Skipped)",
+	NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_menu = {
+	.ops = &vivid_user_gen_ctrl_ops,
+	.id = VIVID_CID_MENU,
+	.name = "Menu",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.min = 1,
+	.max = 4,
+	.def = 3,
+	.menu_skip_mask = 0x04,
+	.qmenu = vivid_ctrl_menu_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_string = {
+	.ops = &vivid_user_gen_ctrl_ops,
+	.id = VIVID_CID_STRING,
+	.name = "String",
+	.type = V4L2_CTRL_TYPE_STRING,
+	.min = 2,
+	.max = 4,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_bitmask = {
+	.ops = &vivid_user_gen_ctrl_ops,
+	.id = VIVID_CID_BITMASK,
+	.name = "Bitmask",
+	.type = V4L2_CTRL_TYPE_BITMASK,
+	.def = 0x80002000,
+	.min = 0,
+	.max = 0x80402010,
+	.step = 0,
+};
+
+static const s64 vivid_ctrl_int_menu_values[] = {
+	1, 1, 2, 3, 5, 8, 13, 21, 42,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_int_menu = {
+	.ops = &vivid_user_gen_ctrl_ops,
+	.id = VIVID_CID_INTMENU,
+	.name = "Integer Menu",
+	.type = V4L2_CTRL_TYPE_INTEGER_MENU,
+	.min = 1,
+	.max = 8,
+	.def = 4,
+	.menu_skip_mask = 0x02,
+	.qmenu_int = vivid_ctrl_int_menu_values,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_disconnect = {
+	.ops = &vivid_user_gen_ctrl_ops,
+	.id = VIVID_CID_DISCONNECT,
+	.name = "Disconnect",
+	.type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_clear_fb = {
+	.ops = &vivid_user_gen_ctrl_ops,
+	.id = VIVID_CID_CLEAR_FB,
+	.name = "Clear Framebuffer",
+	.type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+
+/* Video User Controls */
+
+static int vivid_user_vid_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTOGAIN:
+		dev->gain->val = dev->jiffies_vid_cap & 0xff;
+		break;
+	}
+	return 0;
+}
+
+static int vivid_user_vid_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		dev->input_brightness[dev->input] = ctrl->val - dev->input * 128;
+		tpg_s_brightness(&dev->tpg, dev->input_brightness[dev->input]);
+		break;
+	case V4L2_CID_CONTRAST:
+		tpg_s_contrast(&dev->tpg, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		tpg_s_saturation(&dev->tpg, ctrl->val);
+		break;
+	case V4L2_CID_HUE:
+		tpg_s_hue(&dev->tpg, ctrl->val);
+		break;
+	case V4L2_CID_HFLIP:
+		dev->hflip = ctrl->val;
+		tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip);
+		break;
+	case V4L2_CID_VFLIP:
+		dev->vflip = ctrl->val;
+		tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip);
+		break;
+	case V4L2_CID_ALPHA_COMPONENT:
+		tpg_s_alpha_component(&dev->tpg, ctrl->val);
+		break;
+	}
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_user_vid_ctrl_ops = {
+	.g_volatile_ctrl = vivid_user_vid_g_volatile_ctrl,
+	.s_ctrl = vivid_user_vid_s_ctrl,
+};
+
+
+/* Video Capture Controls */
+
+static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap);
+	unsigned i;
+
+	switch (ctrl->id) {
+	case VIVID_CID_TEST_PATTERN:
+		vivid_update_quality(dev);
+		tpg_s_pattern(&dev->tpg, ctrl->val);
+		break;
+	case VIVID_CID_COLORSPACE:
+		tpg_s_colorspace(&dev->tpg, ctrl->val);
+		vivid_send_source_change(dev, TV);
+		vivid_send_source_change(dev, SVID);
+		vivid_send_source_change(dev, HDMI);
+		vivid_send_source_change(dev, WEBCAM);
+		break;
+	case V4L2_CID_DV_RX_RGB_RANGE:
+		if (!vivid_is_hdmi_cap(dev))
+			break;
+		tpg_s_rgb_range(&dev->tpg, ctrl->val);
+		break;
+	case VIVID_CID_LIMITED_RGB_RANGE:
+		tpg_s_real_rgb_range(&dev->tpg, ctrl->val ?
+				V4L2_DV_RGB_RANGE_LIMITED : V4L2_DV_RGB_RANGE_FULL);
+		break;
+	case VIVID_CID_ALPHA_MODE:
+		tpg_s_alpha_mode(&dev->tpg, ctrl->val);
+		break;
+	case VIVID_CID_HOR_MOVEMENT:
+		tpg_s_mv_hor_mode(&dev->tpg, ctrl->val);
+		break;
+	case VIVID_CID_VERT_MOVEMENT:
+		tpg_s_mv_vert_mode(&dev->tpg, ctrl->val);
+		break;
+	case VIVID_CID_OSD_TEXT_MODE:
+		dev->osd_mode = ctrl->val;
+		break;
+	case VIVID_CID_PERCENTAGE_FILL:
+		tpg_s_perc_fill(&dev->tpg, ctrl->val);
+		for (i = 0; i < VIDEO_MAX_FRAME; i++)
+			dev->must_blank[i] = ctrl->val < 100;
+		break;
+	case VIVID_CID_INSERT_SAV:
+		tpg_s_insert_sav(&dev->tpg, ctrl->val);
+		break;
+	case VIVID_CID_INSERT_EAV:
+		tpg_s_insert_eav(&dev->tpg, ctrl->val);
+		break;
+	case VIVID_CID_HFLIP:
+		dev->sensor_hflip = ctrl->val;
+		tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip);
+		break;
+	case VIVID_CID_VFLIP:
+		dev->sensor_vflip = ctrl->val;
+		tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip);
+		break;
+	case VIVID_CID_HAS_CROP_CAP:
+		dev->has_crop_cap = ctrl->val;
+		vivid_update_format_cap(dev, true);
+		break;
+	case VIVID_CID_HAS_COMPOSE_CAP:
+		dev->has_compose_cap = ctrl->val;
+		vivid_update_format_cap(dev, true);
+		break;
+	case VIVID_CID_HAS_SCALER_CAP:
+		dev->has_scaler_cap = ctrl->val;
+		vivid_update_format_cap(dev, true);
+		break;
+	case VIVID_CID_SHOW_BORDER:
+		tpg_s_show_border(&dev->tpg, ctrl->val);
+		break;
+	case VIVID_CID_SHOW_SQUARE:
+		tpg_s_show_square(&dev->tpg, ctrl->val);
+		break;
+	case VIVID_CID_STD_ASPECT_RATIO:
+		dev->std_aspect_ratio = ctrl->val;
+		tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
+		break;
+	case VIVID_CID_DV_TIMINGS_SIGNAL_MODE:
+		dev->dv_timings_signal_mode = dev->ctrl_dv_timings_signal_mode->val;
+		if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS)
+			dev->query_dv_timings = dev->ctrl_dv_timings->val;
+		v4l2_ctrl_activate(dev->ctrl_dv_timings,
+				dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS);
+		vivid_update_quality(dev);
+		vivid_send_source_change(dev, HDMI);
+		break;
+	case VIVID_CID_DV_TIMINGS_ASPECT_RATIO:
+		dev->dv_timings_aspect_ratio = ctrl->val;
+		tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
+		break;
+	case VIVID_CID_TSTAMP_SRC:
+		dev->tstamp_src_is_soe = ctrl->val;
+		dev->vb_vid_cap_q.timestamp_flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+		if (dev->tstamp_src_is_soe)
+			dev->vb_vid_cap_q.timestamp_flags |= V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
+		break;
+	case VIVID_CID_MAX_EDID_BLOCKS:
+		dev->edid_max_blocks = ctrl->val;
+		if (dev->edid_blocks > dev->edid_max_blocks)
+			dev->edid_blocks = dev->edid_max_blocks;
+		break;
+	}
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_vid_cap_ctrl_ops = {
+	.s_ctrl = vivid_vid_cap_s_ctrl,
+};
+
+static const char * const vivid_ctrl_hor_movement_strings[] = {
+	"Move Left Fast",
+	"Move Left",
+	"Move Left Slow",
+	"No Movement",
+	"Move Right Slow",
+	"Move Right",
+	"Move Right Fast",
+	NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_hor_movement = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_HOR_MOVEMENT,
+	.name = "Horizontal Movement",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.max = TPG_MOVE_POS_FAST,
+	.def = TPG_MOVE_NONE,
+	.qmenu = vivid_ctrl_hor_movement_strings,
+};
+
+static const char * const vivid_ctrl_vert_movement_strings[] = {
+	"Move Up Fast",
+	"Move Up",
+	"Move Up Slow",
+	"No Movement",
+	"Move Down Slow",
+	"Move Down",
+	"Move Down Fast",
+	NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_vert_movement = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_VERT_MOVEMENT,
+	.name = "Vertical Movement",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.max = TPG_MOVE_POS_FAST,
+	.def = TPG_MOVE_NONE,
+	.qmenu = vivid_ctrl_vert_movement_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_show_border = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_SHOW_BORDER,
+	.name = "Show Border",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_show_square = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_SHOW_SQUARE,
+	.name = "Show Square",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+static const char * const vivid_ctrl_osd_mode_strings[] = {
+	"All",
+	"Counters Only",
+	"None",
+	NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_osd_mode = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_OSD_TEXT_MODE,
+	.name = "OSD Text Mode",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.max = 2,
+	.qmenu = vivid_ctrl_osd_mode_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_perc_fill = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_PERCENTAGE_FILL,
+	.name = "Fill Percentage of Frame",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = 100,
+	.def = 100,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_insert_sav = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_INSERT_SAV,
+	.name = "Insert SAV Code in Image",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_insert_eav = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_INSERT_EAV,
+	.name = "Insert EAV Code in Image",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_hflip = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_HFLIP,
+	.name = "Sensor Flipped Horizontally",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_vflip = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_VFLIP,
+	.name = "Sensor Flipped Vertically",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_crop_cap = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_HAS_CROP_CAP,
+	.name = "Enable Capture Cropping",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.def = 1,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_compose_cap = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_HAS_COMPOSE_CAP,
+	.name = "Enable Capture Composing",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.def = 1,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_cap = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_HAS_SCALER_CAP,
+	.name = "Enable Capture Scaler",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.def = 1,
+	.step = 1,
+};
+
+static const char * const vivid_ctrl_tstamp_src_strings[] = {
+	"End of Frame",
+	"Start of Exposure",
+	NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_tstamp_src = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_TSTAMP_SRC,
+	.name = "Timestamp Source",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.max = 1,
+	.qmenu = vivid_ctrl_tstamp_src_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_std_aspect_ratio = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_STD_ASPECT_RATIO,
+	.name = "Standard Aspect Ratio",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.min = 1,
+	.max = 4,
+	.def = 1,
+	.qmenu = tpg_aspect_strings,
+};
+
+static const char * const vivid_ctrl_dv_timings_signal_mode_strings[] = {
+	"Current DV Timings",
+	"No Signal",
+	"No Lock",
+	"Out of Range",
+	"Selected DV Timings",
+	"Cycle Through All DV Timings",
+	"Custom DV Timings",
+	NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_signal_mode = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_DV_TIMINGS_SIGNAL_MODE,
+	.name = "DV Timings Signal Mode",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.max = 5,
+	.qmenu = vivid_ctrl_dv_timings_signal_mode_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_aspect_ratio = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_DV_TIMINGS_ASPECT_RATIO,
+	.name = "DV Timings Aspect Ratio",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.max = 3,
+	.qmenu = tpg_aspect_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_max_edid_blocks = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_MAX_EDID_BLOCKS,
+	.name = "Maximum EDID Blocks",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 1,
+	.max = 256,
+	.def = 2,
+	.step = 1,
+};
+
+static const char * const vivid_ctrl_colorspace_strings[] = {
+	"",
+	"SMPTE 170M",
+	"SMPTE 240M",
+	"REC 709",
+	"", /* Skip Bt878 entry */
+	"470 System M",
+	"470 System BG",
+	"", /* Skip JPEG entry */
+	"sRGB",
+	NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_colorspace = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_COLORSPACE,
+	.name = "Colorspace",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.min = 1,
+	.max = 8,
+	.menu_skip_mask = (1 << 4) | (1 << 7),
+	.def = 8,
+	.qmenu = vivid_ctrl_colorspace_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_alpha_mode = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_ALPHA_MODE,
+	.name = "Apply Alpha To Red Only",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_limited_rgb_range = {
+	.ops = &vivid_vid_cap_ctrl_ops,
+	.id = VIVID_CID_LIMITED_RGB_RANGE,
+	.name = "Limited RGB Range (16-235)",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+
+/* VBI Capture Control */
+
+static int vivid_vbi_cap_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vbi_cap);
+
+	switch (ctrl->id) {
+	case VIVID_CID_VBI_CAP_INTERLACED:
+		dev->vbi_cap_interlaced = ctrl->val;
+		break;
+	}
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_vbi_cap_ctrl_ops = {
+	.s_ctrl = vivid_vbi_cap_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_vbi_cap_interlaced = {
+	.ops = &vivid_vbi_cap_ctrl_ops,
+	.id = VIVID_CID_VBI_CAP_INTERLACED,
+	.name = "Interlaced VBI Format",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+
+/* Video Output Controls */
+
+static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_out);
+	struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
+
+	switch (ctrl->id) {
+	case VIVID_CID_HAS_CROP_OUT:
+		dev->has_crop_out = ctrl->val;
+		vivid_update_format_out(dev);
+		break;
+	case VIVID_CID_HAS_COMPOSE_OUT:
+		dev->has_compose_out = ctrl->val;
+		vivid_update_format_out(dev);
+		break;
+	case VIVID_CID_HAS_SCALER_OUT:
+		dev->has_scaler_out = ctrl->val;
+		vivid_update_format_out(dev);
+		break;
+	case V4L2_CID_DV_TX_MODE:
+		dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D;
+		if (!vivid_is_hdmi_out(dev))
+			break;
+		if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) {
+			if (bt->width == 720 && bt->height <= 576)
+				dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
+			else
+				dev->colorspace_out = V4L2_COLORSPACE_REC709;
+		} else {
+			dev->colorspace_out = V4L2_COLORSPACE_SRGB;
+		}
+		if (dev->loop_video)
+			vivid_send_source_change(dev, HDMI);
+		break;
+	}
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_vid_out_ctrl_ops = {
+	.s_ctrl = vivid_vid_out_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_crop_out = {
+	.ops = &vivid_vid_out_ctrl_ops,
+	.id = VIVID_CID_HAS_CROP_OUT,
+	.name = "Enable Output Cropping",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.def = 1,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_compose_out = {
+	.ops = &vivid_vid_out_ctrl_ops,
+	.id = VIVID_CID_HAS_COMPOSE_OUT,
+	.name = "Enable Output Composing",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.def = 1,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = {
+	.ops = &vivid_vid_out_ctrl_ops,
+	.id = VIVID_CID_HAS_SCALER_OUT,
+	.name = "Enable Output Scaler",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.def = 1,
+	.step = 1,
+};
+
+
+/* Streaming Controls */
+
+static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_streaming);
+	struct timeval tv;
+
+	switch (ctrl->id) {
+	case VIVID_CID_DQBUF_ERROR:
+		dev->dqbuf_error = true;
+		break;
+	case VIVID_CID_PERC_DROPPED:
+		dev->perc_dropped_buffers = ctrl->val;
+		break;
+	case VIVID_CID_QUEUE_SETUP_ERROR:
+		dev->queue_setup_error = true;
+		break;
+	case VIVID_CID_BUF_PREPARE_ERROR:
+		dev->buf_prepare_error = true;
+		break;
+	case VIVID_CID_START_STR_ERROR:
+		dev->start_streaming_error = true;
+		break;
+	case VIVID_CID_QUEUE_ERROR:
+		if (dev->vb_vid_cap_q.start_streaming_called)
+			vb2_queue_error(&dev->vb_vid_cap_q);
+		if (dev->vb_vbi_cap_q.start_streaming_called)
+			vb2_queue_error(&dev->vb_vbi_cap_q);
+		if (dev->vb_vid_out_q.start_streaming_called)
+			vb2_queue_error(&dev->vb_vid_out_q);
+		if (dev->vb_vbi_out_q.start_streaming_called)
+			vb2_queue_error(&dev->vb_vbi_out_q);
+		if (dev->vb_sdr_cap_q.start_streaming_called)
+			vb2_queue_error(&dev->vb_sdr_cap_q);
+		break;
+	case VIVID_CID_SEQ_WRAP:
+		dev->seq_wrap = ctrl->val;
+		break;
+	case VIVID_CID_TIME_WRAP:
+		dev->time_wrap = ctrl->val;
+		if (ctrl->val == 0) {
+			dev->time_wrap_offset = 0;
+			break;
+		}
+		v4l2_get_timestamp(&tv);
+		dev->time_wrap_offset = -tv.tv_sec - 16;
+		break;
+	}
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_streaming_ctrl_ops = {
+	.s_ctrl = vivid_streaming_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_dqbuf_error = {
+	.ops = &vivid_streaming_ctrl_ops,
+	.id = VIVID_CID_DQBUF_ERROR,
+	.name = "Inject V4L2_BUF_FLAG_ERROR",
+	.type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_perc_dropped = {
+	.ops = &vivid_streaming_ctrl_ops,
+	.id = VIVID_CID_PERC_DROPPED,
+	.name = "Percentage of Dropped Buffers",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = 100,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_queue_setup_error = {
+	.ops = &vivid_streaming_ctrl_ops,
+	.id = VIVID_CID_QUEUE_SETUP_ERROR,
+	.name = "Inject VIDIOC_REQBUFS Error",
+	.type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_buf_prepare_error = {
+	.ops = &vivid_streaming_ctrl_ops,
+	.id = VIVID_CID_BUF_PREPARE_ERROR,
+	.name = "Inject VIDIOC_QBUF Error",
+	.type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_start_streaming_error = {
+	.ops = &vivid_streaming_ctrl_ops,
+	.id = VIVID_CID_START_STR_ERROR,
+	.name = "Inject VIDIOC_STREAMON Error",
+	.type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_queue_error = {
+	.ops = &vivid_streaming_ctrl_ops,
+	.id = VIVID_CID_QUEUE_ERROR,
+	.name = "Inject Fatal Streaming Error",
+	.type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_seq_wrap = {
+	.ops = &vivid_streaming_ctrl_ops,
+	.id = VIVID_CID_SEQ_WRAP,
+	.name = "Wrap Sequence Number",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_time_wrap = {
+	.ops = &vivid_streaming_ctrl_ops,
+	.id = VIVID_CID_TIME_WRAP,
+	.name = "Wrap Timestamp",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+
+/* SDTV Capture Controls */
+
+static int vivid_sdtv_cap_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_sdtv_cap);
+
+	switch (ctrl->id) {
+	case VIVID_CID_STD_SIGNAL_MODE:
+		dev->std_signal_mode = dev->ctrl_std_signal_mode->val;
+		if (dev->std_signal_mode == SELECTED_STD)
+			dev->query_std = vivid_standard[dev->ctrl_standard->val];
+		v4l2_ctrl_activate(dev->ctrl_standard, dev->std_signal_mode == SELECTED_STD);
+		vivid_update_quality(dev);
+		vivid_send_source_change(dev, TV);
+		vivid_send_source_change(dev, SVID);
+		break;
+	}
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_sdtv_cap_ctrl_ops = {
+	.s_ctrl = vivid_sdtv_cap_s_ctrl,
+};
+
+static const char * const vivid_ctrl_std_signal_mode_strings[] = {
+	"Current Standard",
+	"No Signal",
+	"No Lock",
+	"",
+	"Selected Standard",
+	"Cycle Through All Standards",
+	NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_std_signal_mode = {
+	.ops = &vivid_sdtv_cap_ctrl_ops,
+	.id = VIVID_CID_STD_SIGNAL_MODE,
+	.name = "Standard Signal Mode",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.max = 5,
+	.menu_skip_mask = 1 << 3,
+	.qmenu = vivid_ctrl_std_signal_mode_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_standard = {
+	.ops = &vivid_sdtv_cap_ctrl_ops,
+	.id = VIVID_CID_STANDARD,
+	.name = "Standard",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.max = 14,
+	.qmenu = vivid_ctrl_standard_strings,
+};
+
+
+
+/* Radio Receiver Controls */
+
+static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_rx);
+
+	switch (ctrl->id) {
+	case VIVID_CID_RADIO_SEEK_MODE:
+		dev->radio_rx_hw_seek_mode = ctrl->val;
+		break;
+	case VIVID_CID_RADIO_SEEK_PROG_LIM:
+		dev->radio_rx_hw_seek_prog_lim = ctrl->val;
+		break;
+	case VIVID_CID_RADIO_RX_RDS_RBDS:
+		dev->rds_gen.use_rbds = ctrl->val;
+		break;
+	case VIVID_CID_RADIO_RX_RDS_BLOCKIO:
+		dev->radio_rx_rds_controls = ctrl->val;
+		dev->radio_rx_caps &= ~V4L2_CAP_READWRITE;
+		dev->radio_rx_rds_use_alternates = false;
+		if (!dev->radio_rx_rds_controls) {
+			dev->radio_rx_caps |= V4L2_CAP_READWRITE;
+			__v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, 0);
+			__v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, 0);
+			__v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, 0);
+			__v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, 0);
+			__v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, "");
+			__v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, "");
+		}
+		v4l2_ctrl_activate(dev->radio_rx_rds_pty, dev->radio_rx_rds_controls);
+		v4l2_ctrl_activate(dev->radio_rx_rds_psname, dev->radio_rx_rds_controls);
+		v4l2_ctrl_activate(dev->radio_rx_rds_radiotext, dev->radio_rx_rds_controls);
+		v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls);
+		v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls);
+		v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls);
+		break;
+	case V4L2_CID_RDS_RECEPTION:
+		dev->radio_rx_rds_enabled = ctrl->val;
+		break;
+	}
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_radio_rx_ctrl_ops = {
+	.s_ctrl = vivid_radio_rx_s_ctrl,
+};
+
+static const char * const vivid_ctrl_radio_rds_mode_strings[] = {
+	"Block I/O",
+	"Controls",
+	NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_blockio = {
+	.ops = &vivid_radio_rx_ctrl_ops,
+	.id = VIVID_CID_RADIO_RX_RDS_BLOCKIO,
+	.name = "RDS Rx I/O Mode",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.qmenu = vivid_ctrl_radio_rds_mode_strings,
+	.max = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_rbds = {
+	.ops = &vivid_radio_rx_ctrl_ops,
+	.id = VIVID_CID_RADIO_RX_RDS_RBDS,
+	.name = "Generate RBDS Instead of RDS",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+static const char * const vivid_ctrl_radio_hw_seek_mode_strings[] = {
+	"Bounded",
+	"Wrap Around",
+	"Both",
+	NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_mode = {
+	.ops = &vivid_radio_rx_ctrl_ops,
+	.id = VIVID_CID_RADIO_SEEK_MODE,
+	.name = "Radio HW Seek Mode",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.max = 2,
+	.qmenu = vivid_ctrl_radio_hw_seek_mode_strings,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_prog_lim = {
+	.ops = &vivid_radio_rx_ctrl_ops,
+	.id = VIVID_CID_RADIO_SEEK_PROG_LIM,
+	.name = "Radio Programmable HW Seek",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+
+/* Radio Transmitter Controls */
+
+static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_tx);
+
+	switch (ctrl->id) {
+	case VIVID_CID_RADIO_TX_RDS_BLOCKIO:
+		dev->radio_tx_rds_controls = ctrl->val;
+		dev->radio_tx_caps &= ~V4L2_CAP_READWRITE;
+		if (!dev->radio_tx_rds_controls)
+			dev->radio_tx_caps |= V4L2_CAP_READWRITE;
+		break;
+	case V4L2_CID_RDS_TX_PTY:
+		if (dev->radio_rx_rds_controls)
+			v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, ctrl->val);
+		break;
+	case V4L2_CID_RDS_TX_PS_NAME:
+		if (dev->radio_rx_rds_controls)
+			v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, ctrl->p_new.p_char);
+		break;
+	case V4L2_CID_RDS_TX_RADIO_TEXT:
+		if (dev->radio_rx_rds_controls)
+			v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, ctrl->p_new.p_char);
+		break;
+	case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
+		if (dev->radio_rx_rds_controls)
+			v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, ctrl->val);
+		break;
+	case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
+		if (dev->radio_rx_rds_controls)
+			v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, ctrl->val);
+		break;
+	case V4L2_CID_RDS_TX_MUSIC_SPEECH:
+		if (dev->radio_rx_rds_controls)
+			v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, ctrl->val);
+		break;
+	}
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_radio_tx_ctrl_ops = {
+	.s_ctrl = vivid_radio_tx_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_radio_tx_rds_blockio = {
+	.ops = &vivid_radio_tx_ctrl_ops,
+	.id = VIVID_CID_RADIO_TX_RDS_BLOCKIO,
+	.name = "RDS Tx I/O Mode",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.qmenu = vivid_ctrl_radio_rds_mode_strings,
+	.max = 1,
+	.def = 1,
+};
+
+
+
+/* Video Loop Control */
+
+static int vivid_loop_out_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_loop_out);
+
+	switch (ctrl->id) {
+	case VIVID_CID_LOOP_VIDEO:
+		dev->loop_video = ctrl->val;
+		vivid_update_quality(dev);
+		vivid_send_source_change(dev, SVID);
+		vivid_send_source_change(dev, HDMI);
+		break;
+	}
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_loop_out_ctrl_ops = {
+	.s_ctrl = vivid_loop_out_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_loop_video = {
+	.ops = &vivid_loop_out_ctrl_ops,
+	.id = VIVID_CID_LOOP_VIDEO,
+	.name = "Loop Video",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.max = 1,
+	.step = 1,
+};
+
+
+static const struct v4l2_ctrl_config vivid_ctrl_class = {
+	.ops = &vivid_user_gen_ctrl_ops,
+	.flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY,
+	.id = VIVID_CID_VIVID_CLASS,
+	.name = "Vivid Controls",
+	.type = V4L2_CTRL_TYPE_CTRL_CLASS,
+};
+
+int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
+		bool show_ccs_out, bool no_error_inj,
+		bool has_sdtv, bool has_hdmi)
+{
+	struct v4l2_ctrl_handler *hdl_user_gen = &dev->ctrl_hdl_user_gen;
+	struct v4l2_ctrl_handler *hdl_user_vid = &dev->ctrl_hdl_user_vid;
+	struct v4l2_ctrl_handler *hdl_user_aud = &dev->ctrl_hdl_user_aud;
+	struct v4l2_ctrl_handler *hdl_streaming = &dev->ctrl_hdl_streaming;
+	struct v4l2_ctrl_handler *hdl_sdtv_cap = &dev->ctrl_hdl_sdtv_cap;
+	struct v4l2_ctrl_handler *hdl_loop_out = &dev->ctrl_hdl_loop_out;
+	struct v4l2_ctrl_handler *hdl_vid_cap = &dev->ctrl_hdl_vid_cap;
+	struct v4l2_ctrl_handler *hdl_vid_out = &dev->ctrl_hdl_vid_out;
+	struct v4l2_ctrl_handler *hdl_vbi_cap = &dev->ctrl_hdl_vbi_cap;
+	struct v4l2_ctrl_handler *hdl_vbi_out = &dev->ctrl_hdl_vbi_out;
+	struct v4l2_ctrl_handler *hdl_radio_rx = &dev->ctrl_hdl_radio_rx;
+	struct v4l2_ctrl_handler *hdl_radio_tx = &dev->ctrl_hdl_radio_tx;
+	struct v4l2_ctrl_handler *hdl_sdr_cap = &dev->ctrl_hdl_sdr_cap;
+	struct v4l2_ctrl_config vivid_ctrl_dv_timings = {
+		.ops = &vivid_vid_cap_ctrl_ops,
+		.id = VIVID_CID_DV_TIMINGS,
+		.name = "DV Timings",
+		.type = V4L2_CTRL_TYPE_MENU,
+	};
+	int i;
+
+	v4l2_ctrl_handler_init(hdl_user_gen, 10);
+	v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_class, NULL);
+	v4l2_ctrl_handler_init(hdl_user_vid, 9);
+	v4l2_ctrl_new_custom(hdl_user_vid, &vivid_ctrl_class, NULL);
+	v4l2_ctrl_handler_init(hdl_user_aud, 2);
+	v4l2_ctrl_new_custom(hdl_user_aud, &vivid_ctrl_class, NULL);
+	v4l2_ctrl_handler_init(hdl_streaming, 8);
+	v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_class, NULL);
+	v4l2_ctrl_handler_init(hdl_sdtv_cap, 2);
+	v4l2_ctrl_new_custom(hdl_sdtv_cap, &vivid_ctrl_class, NULL);
+	v4l2_ctrl_handler_init(hdl_loop_out, 1);
+	v4l2_ctrl_new_custom(hdl_loop_out, &vivid_ctrl_class, NULL);
+	v4l2_ctrl_handler_init(hdl_vid_cap, 55);
+	v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL);
+	v4l2_ctrl_handler_init(hdl_vid_out, 26);
+	v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL);
+	v4l2_ctrl_handler_init(hdl_vbi_cap, 21);
+	v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_class, NULL);
+	v4l2_ctrl_handler_init(hdl_vbi_out, 19);
+	v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL);
+	v4l2_ctrl_handler_init(hdl_radio_rx, 17);
+	v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_class, NULL);
+	v4l2_ctrl_handler_init(hdl_radio_tx, 17);
+	v4l2_ctrl_new_custom(hdl_radio_tx, &vivid_ctrl_class, NULL);
+	v4l2_ctrl_handler_init(hdl_sdr_cap, 18);
+	v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_class, NULL);
+
+	/* User Controls */
+	dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL,
+		V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
+	dev->mute = v4l2_ctrl_new_std(hdl_user_aud, NULL,
+		V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+	if (dev->has_vid_cap) {
+		dev->brightness = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+		for (i = 0; i < MAX_INPUTS; i++)
+			dev->input_brightness[i] = 128;
+		dev->contrast = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 128);
+		dev->saturation = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 128);
+		dev->hue = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+			V4L2_CID_HUE, -128, 128, 1, 0);
+		v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+		v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+		dev->autogain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+		dev->gain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+			V4L2_CID_GAIN, 0, 255, 1, 100);
+		dev->alpha = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops,
+			V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
+	}
+	dev->button = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_button, NULL);
+	dev->int32 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int32, NULL);
+	dev->int64 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int64, NULL);
+	dev->boolean = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_boolean, NULL);
+	dev->menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_menu, NULL);
+	dev->string = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_string, NULL);
+	dev->bitmask = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_bitmask, NULL);
+	dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL);
+
+	if (dev->has_vid_cap) {
+		/* Image Processing Controls */
+		struct v4l2_ctrl_config vivid_ctrl_test_pattern = {
+			.ops = &vivid_vid_cap_ctrl_ops,
+			.id = VIVID_CID_TEST_PATTERN,
+			.name = "Test Pattern",
+			.type = V4L2_CTRL_TYPE_MENU,
+			.max = TPG_PAT_NOISE,
+			.qmenu = tpg_pattern_strings,
+		};
+
+		dev->test_pattern = v4l2_ctrl_new_custom(hdl_vid_cap,
+				&vivid_ctrl_test_pattern, NULL);
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_perc_fill, NULL);
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hor_movement, NULL);
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vert_movement, NULL);
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_osd_mode, NULL);
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_border, NULL);
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_square, NULL);
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hflip, NULL);
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vflip, NULL);
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_sav, NULL);
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_eav, NULL);
+		if (show_ccs_cap) {
+			dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
+				&vivid_ctrl_has_crop_cap, NULL);
+			dev->ctrl_has_compose_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
+				&vivid_ctrl_has_compose_cap, NULL);
+			dev->ctrl_has_scaler_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
+				&vivid_ctrl_has_scaler_cap, NULL);
+		}
+
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_tstamp_src, NULL);
+		dev->colorspace = v4l2_ctrl_new_custom(hdl_vid_cap,
+			&vivid_ctrl_colorspace, NULL);
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL);
+	}
+
+	if (dev->has_vid_out && show_ccs_out) {
+		dev->ctrl_has_crop_out = v4l2_ctrl_new_custom(hdl_vid_out,
+			&vivid_ctrl_has_crop_out, NULL);
+		dev->ctrl_has_compose_out = v4l2_ctrl_new_custom(hdl_vid_out,
+			&vivid_ctrl_has_compose_out, NULL);
+		dev->ctrl_has_scaler_out = v4l2_ctrl_new_custom(hdl_vid_out,
+			&vivid_ctrl_has_scaler_out, NULL);
+	}
+
+	/*
+	 * Testing this driver with v4l2-compliance will trigger the error
+	 * injection controls, and after that nothing will work as expected.
+	 * So we have a module option to drop these error injecting controls
+	 * allowing us to run v4l2_compliance again.
+	 */
+	if (!no_error_inj) {
+		v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_disconnect, NULL);
+		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_dqbuf_error, NULL);
+		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_perc_dropped, NULL);
+		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_setup_error, NULL);
+		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_buf_prepare_error, NULL);
+		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_start_streaming_error, NULL);
+		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_error, NULL);
+		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_seq_wrap, NULL);
+		v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_time_wrap, NULL);
+	}
+
+	if (has_sdtv && (dev->has_vid_cap || dev->has_vbi_cap)) {
+		if (dev->has_vid_cap)
+			v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_std_aspect_ratio, NULL);
+		dev->ctrl_std_signal_mode = v4l2_ctrl_new_custom(hdl_sdtv_cap,
+			&vivid_ctrl_std_signal_mode, NULL);
+		dev->ctrl_standard = v4l2_ctrl_new_custom(hdl_sdtv_cap,
+			&vivid_ctrl_standard, NULL);
+		if (dev->ctrl_std_signal_mode)
+			v4l2_ctrl_cluster(2, &dev->ctrl_std_signal_mode);
+		if (dev->has_raw_vbi_cap)
+			v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_vbi_cap_interlaced, NULL);
+	}
+
+	if (has_hdmi && dev->has_vid_cap) {
+		dev->ctrl_dv_timings_signal_mode = v4l2_ctrl_new_custom(hdl_vid_cap,
+					&vivid_ctrl_dv_timings_signal_mode, NULL);
+
+		vivid_ctrl_dv_timings.max = dev->query_dv_timings_size - 1;
+		vivid_ctrl_dv_timings.qmenu =
+			(const char * const *)dev->query_dv_timings_qmenu;
+		dev->ctrl_dv_timings = v4l2_ctrl_new_custom(hdl_vid_cap,
+			&vivid_ctrl_dv_timings, NULL);
+		if (dev->ctrl_dv_timings_signal_mode)
+			v4l2_ctrl_cluster(2, &dev->ctrl_dv_timings_signal_mode);
+
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_dv_timings_aspect_ratio, NULL);
+		v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_max_edid_blocks, NULL);
+		dev->real_rgb_range_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
+			&vivid_ctrl_limited_rgb_range, NULL);
+		dev->rgb_range_cap = v4l2_ctrl_new_std_menu(hdl_vid_cap,
+			&vivid_vid_cap_ctrl_ops,
+			V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
+			0, V4L2_DV_RGB_RANGE_AUTO);
+	}
+	if (has_hdmi && dev->has_vid_out) {
+		/*
+		 * We aren't doing anything with this at the moment, but
+		 * HDMI outputs typically have this controls.
+		 */
+		dev->ctrl_tx_rgb_range = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL,
+			V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
+			0, V4L2_DV_RGB_RANGE_AUTO);
+		dev->ctrl_tx_mode = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL,
+			V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI,
+			0, V4L2_DV_TX_MODE_HDMI);
+	}
+	if ((dev->has_vid_cap && dev->has_vid_out) ||
+	    (dev->has_vbi_cap && dev->has_vbi_out))
+		v4l2_ctrl_new_custom(hdl_loop_out, &vivid_ctrl_loop_video, NULL);
+
+	if (dev->has_fb)
+		v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_clear_fb, NULL);
+
+	if (dev->has_radio_rx) {
+		v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_mode, NULL);
+		v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_prog_lim, NULL);
+		v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_blockio, NULL);
+		v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_rbds, NULL);
+		v4l2_ctrl_new_std(hdl_radio_rx, &vivid_radio_rx_ctrl_ops,
+			V4L2_CID_RDS_RECEPTION, 0, 1, 1, 1);
+		dev->radio_rx_rds_pty = v4l2_ctrl_new_std(hdl_radio_rx,
+			&vivid_radio_rx_ctrl_ops,
+			V4L2_CID_RDS_RX_PTY, 0, 31, 1, 0);
+		dev->radio_rx_rds_psname = v4l2_ctrl_new_std(hdl_radio_rx,
+			&vivid_radio_rx_ctrl_ops,
+			V4L2_CID_RDS_RX_PS_NAME, 0, 8, 8, 0);
+		dev->radio_rx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_rx,
+			&vivid_radio_rx_ctrl_ops,
+			V4L2_CID_RDS_RX_RADIO_TEXT, 0, 64, 64, 0);
+		dev->radio_rx_rds_ta = v4l2_ctrl_new_std(hdl_radio_rx,
+			&vivid_radio_rx_ctrl_ops,
+			V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
+		dev->radio_rx_rds_tp = v4l2_ctrl_new_std(hdl_radio_rx,
+			&vivid_radio_rx_ctrl_ops,
+			V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, 0, 1, 1, 0);
+		dev->radio_rx_rds_ms = v4l2_ctrl_new_std(hdl_radio_rx,
+			&vivid_radio_rx_ctrl_ops,
+			V4L2_CID_RDS_RX_MUSIC_SPEECH, 0, 1, 1, 1);
+	}
+	if (dev->has_radio_tx) {
+		v4l2_ctrl_new_custom(hdl_radio_tx,
+			&vivid_ctrl_radio_tx_rds_blockio, NULL);
+		dev->radio_tx_rds_pi = v4l2_ctrl_new_std(hdl_radio_tx,
+			&vivid_radio_tx_ctrl_ops,
+			V4L2_CID_RDS_TX_PI, 0, 0xffff, 1, 0x8088);
+		dev->radio_tx_rds_pty = v4l2_ctrl_new_std(hdl_radio_tx,
+			&vivid_radio_tx_ctrl_ops,
+			V4L2_CID_RDS_TX_PTY, 0, 31, 1, 3);
+		dev->radio_tx_rds_psname = v4l2_ctrl_new_std(hdl_radio_tx,
+			&vivid_radio_tx_ctrl_ops,
+			V4L2_CID_RDS_TX_PS_NAME, 0, 8, 8, 0);
+		if (dev->radio_tx_rds_psname)
+			v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_psname, "VIVID-TX");
+		dev->radio_tx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_tx,
+			&vivid_radio_tx_ctrl_ops,
+			V4L2_CID_RDS_TX_RADIO_TEXT, 0, 64 * 2, 64, 0);
+		if (dev->radio_tx_rds_radiotext)
+			v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_radiotext,
+			       "This is a VIVID default Radio Text template text, change at will");
+		dev->radio_tx_rds_mono_stereo = v4l2_ctrl_new_std(hdl_radio_tx,
+			&vivid_radio_tx_ctrl_ops,
+			V4L2_CID_RDS_TX_MONO_STEREO, 0, 1, 1, 1);
+		dev->radio_tx_rds_art_head = v4l2_ctrl_new_std(hdl_radio_tx,
+			&vivid_radio_tx_ctrl_ops,
+			V4L2_CID_RDS_TX_ARTIFICIAL_HEAD, 0, 1, 1, 0);
+		dev->radio_tx_rds_compressed = v4l2_ctrl_new_std(hdl_radio_tx,
+			&vivid_radio_tx_ctrl_ops,
+			V4L2_CID_RDS_TX_COMPRESSED, 0, 1, 1, 0);
+		dev->radio_tx_rds_dyn_pty = v4l2_ctrl_new_std(hdl_radio_tx,
+			&vivid_radio_tx_ctrl_ops,
+			V4L2_CID_RDS_TX_DYNAMIC_PTY, 0, 1, 1, 0);
+		dev->radio_tx_rds_ta = v4l2_ctrl_new_std(hdl_radio_tx,
+			&vivid_radio_tx_ctrl_ops,
+			V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
+		dev->radio_tx_rds_tp = v4l2_ctrl_new_std(hdl_radio_tx,
+			&vivid_radio_tx_ctrl_ops,
+			V4L2_CID_RDS_TX_TRAFFIC_PROGRAM, 0, 1, 1, 1);
+		dev->radio_tx_rds_ms = v4l2_ctrl_new_std(hdl_radio_tx,
+			&vivid_radio_tx_ctrl_ops,
+			V4L2_CID_RDS_TX_MUSIC_SPEECH, 0, 1, 1, 1);
+	}
+	if (hdl_user_gen->error)
+		return hdl_user_gen->error;
+	if (hdl_user_vid->error)
+		return hdl_user_vid->error;
+	if (hdl_user_aud->error)
+		return hdl_user_aud->error;
+	if (hdl_streaming->error)
+		return hdl_streaming->error;
+	if (hdl_sdr_cap->error)
+		return hdl_sdr_cap->error;
+	if (hdl_loop_out->error)
+		return hdl_loop_out->error;
+
+	if (dev->autogain)
+		v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
+
+	if (dev->has_vid_cap) {
+		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_gen, NULL);
+		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_vid, NULL);
+		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_aud, NULL);
+		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_streaming, NULL);
+		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_sdtv_cap, NULL);
+		if (hdl_vid_cap->error)
+			return hdl_vid_cap->error;
+		dev->vid_cap_dev.ctrl_handler = hdl_vid_cap;
+	}
+	if (dev->has_vid_out) {
+		v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_gen, NULL);
+		v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_aud, NULL);
+		v4l2_ctrl_add_handler(hdl_vid_out, hdl_streaming, NULL);
+		v4l2_ctrl_add_handler(hdl_vid_out, hdl_loop_out, NULL);
+		if (hdl_vid_out->error)
+			return hdl_vid_out->error;
+		dev->vid_out_dev.ctrl_handler = hdl_vid_out;
+	}
+	if (dev->has_vbi_cap) {
+		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_user_gen, NULL);
+		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_streaming, NULL);
+		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_sdtv_cap, NULL);
+		if (hdl_vbi_cap->error)
+			return hdl_vbi_cap->error;
+		dev->vbi_cap_dev.ctrl_handler = hdl_vbi_cap;
+	}
+	if (dev->has_vbi_out) {
+		v4l2_ctrl_add_handler(hdl_vbi_out, hdl_user_gen, NULL);
+		v4l2_ctrl_add_handler(hdl_vbi_out, hdl_streaming, NULL);
+		v4l2_ctrl_add_handler(hdl_vbi_out, hdl_loop_out, NULL);
+		if (hdl_vbi_out->error)
+			return hdl_vbi_out->error;
+		dev->vbi_out_dev.ctrl_handler = hdl_vbi_out;
+	}
+	if (dev->has_radio_rx) {
+		v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_gen, NULL);
+		v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_aud, NULL);
+		if (hdl_radio_rx->error)
+			return hdl_radio_rx->error;
+		dev->radio_rx_dev.ctrl_handler = hdl_radio_rx;
+	}
+	if (dev->has_radio_tx) {
+		v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_gen, NULL);
+		v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_aud, NULL);
+		if (hdl_radio_tx->error)
+			return hdl_radio_tx->error;
+		dev->radio_tx_dev.ctrl_handler = hdl_radio_tx;
+	}
+	if (dev->has_sdr_cap) {
+		v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_user_gen, NULL);
+		v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_streaming, NULL);
+		if (hdl_sdr_cap->error)
+			return hdl_sdr_cap->error;
+		dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap;
+	}
+	return 0;
+}
+
+void vivid_free_controls(struct vivid_dev *dev)
+{
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_cap);
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_out);
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_cap);
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_out);
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_rx);
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_tx);
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdr_cap);
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_gen);
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_vid);
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_aud);
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_streaming);
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap);
+	v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_out);
+}
diff --git a/drivers/media/platform/vivid/vivid-ctrls.h b/drivers/media/platform/vivid/vivid-ctrls.h
new file mode 100644
index 0000000..9bcca9d
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-ctrls.h
@@ -0,0 +1,34 @@
+/*
+ * vivid-ctrls.h - control support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_CTRLS_H_
+#define _VIVID_CTRLS_H_
+
+enum vivid_hw_seek_modes {
+	VIVID_HW_SEEK_BOUNDED,
+	VIVID_HW_SEEK_WRAP,
+	VIVID_HW_SEEK_BOTH,
+};
+
+int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
+		bool show_ccs_out, bool no_error_inj,
+		bool has_sdtv, bool has_hdmi);
+void vivid_free_controls(struct vivid_dev *dev);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
new file mode 100644
index 0000000..39a67cf
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -0,0 +1,886 @@
+/*
+ * vivid-kthread-cap.h - video/vbi capture thread support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/random.h>
+#include <linux/v4l2-dv-timings.h>
+#include <asm/div64.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-vid-cap.h"
+#include "vivid-vid-out.h"
+#include "vivid-radio-common.h"
+#include "vivid-radio-rx.h"
+#include "vivid-radio-tx.h"
+#include "vivid-sdr-cap.h"
+#include "vivid-vbi-cap.h"
+#include "vivid-vbi-out.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.h"
+#include "vivid-kthread-cap.h"
+
+static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev)
+{
+	if (vivid_is_sdtv_cap(dev))
+		return dev->std_cap;
+	return 0;
+}
+
+static void copy_pix(struct vivid_dev *dev, int win_y, int win_x,
+			u16 *cap, const u16 *osd)
+{
+	u16 out;
+	int left = dev->overlay_out_left;
+	int top = dev->overlay_out_top;
+	int fb_x = win_x + left;
+	int fb_y = win_y + top;
+	int i;
+
+	out = *cap;
+	*cap = *osd;
+	if (dev->bitmap_out) {
+		const u8 *p = dev->bitmap_out;
+		unsigned stride = (dev->compose_out.width + 7) / 8;
+
+		win_x -= dev->compose_out.left;
+		win_y -= dev->compose_out.top;
+		if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7))))
+			return;
+	}
+
+	for (i = 0; i < dev->clipcount_out; i++) {
+		struct v4l2_rect *r = &dev->clips_out[i].c;
+
+		if (fb_y >= r->top && fb_y < r->top + r->height &&
+		    fb_x >= r->left && fb_x < r->left + r->width)
+			return;
+	}
+	if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
+	    *osd != dev->chromakey_out)
+		return;
+	if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) &&
+	    out == dev->chromakey_out)
+		return;
+	if (dev->fmt_cap->alpha_mask) {
+		if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) &&
+		    dev->global_alpha_out)
+			return;
+		if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) &&
+		    *cap & dev->fmt_cap->alpha_mask)
+			return;
+		if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA) &&
+		    !(*cap & dev->fmt_cap->alpha_mask))
+			return;
+	}
+	*cap = out;
+}
+
+static void blend_line(struct vivid_dev *dev, unsigned y_offset, unsigned x_offset,
+		u8 *vcapbuf, const u8 *vosdbuf,
+		unsigned width, unsigned pixsize)
+{
+	unsigned x;
+
+	for (x = 0; x < width; x++, vcapbuf += pixsize, vosdbuf += pixsize) {
+		copy_pix(dev, y_offset, x_offset + x,
+			 (u16 *)vcapbuf, (const u16 *)vosdbuf);
+	}
+}
+
+static void scale_line(const u8 *src, u8 *dst, unsigned srcw, unsigned dstw, unsigned twopixsize)
+{
+	/* Coarse scaling with Bresenham */
+	unsigned int_part;
+	unsigned fract_part;
+	unsigned src_x = 0;
+	unsigned error = 0;
+	unsigned x;
+
+	/*
+	 * We always combine two pixels to prevent color bleed in the packed
+	 * yuv case.
+	 */
+	srcw /= 2;
+	dstw /= 2;
+	int_part = srcw / dstw;
+	fract_part = srcw % dstw;
+	for (x = 0; x < dstw; x++, dst += twopixsize) {
+		memcpy(dst, src + src_x * twopixsize, twopixsize);
+		src_x += int_part;
+		error += fract_part;
+		if (error >= dstw) {
+			error -= dstw;
+			src_x++;
+		}
+	}
+}
+
+/*
+ * Precalculate the rectangles needed to perform video looping:
+ *
+ * The nominal pipeline is that the video output buffer is cropped by
+ * crop_out, scaled to compose_out, overlaid with the output overlay,
+ * cropped on the capture side by crop_cap and scaled again to the video
+ * capture buffer using compose_cap.
+ *
+ * To keep things efficient we calculate the intersection of compose_out
+ * and crop_cap (since that's the only part of the video that will
+ * actually end up in the capture buffer), determine which part of the
+ * video output buffer that is and which part of the video capture buffer
+ * so we can scale the video straight from the output buffer to the capture
+ * buffer without any intermediate steps.
+ *
+ * If we need to deal with an output overlay, then there is no choice and
+ * that intermediate step still has to be taken. For the output overlay
+ * support we calculate the intersection of the framebuffer and the overlay
+ * window (which may be partially or wholly outside of the framebuffer
+ * itself) and the intersection of that with loop_vid_copy (i.e. the part of
+ * the actual looped video that will be overlaid). The result is calculated
+ * both in framebuffer coordinates (loop_fb_copy) and compose_out coordinates
+ * (loop_vid_overlay). Finally calculate the part of the capture buffer that
+ * will receive that overlaid video.
+ */
+static void vivid_precalc_copy_rects(struct vivid_dev *dev)
+{
+	/* Framebuffer rectangle */
+	struct v4l2_rect r_fb = {
+		0, 0, dev->display_width, dev->display_height
+	};
+	/* Overlay window rectangle in framebuffer coordinates */
+	struct v4l2_rect r_overlay = {
+		dev->overlay_out_left, dev->overlay_out_top,
+		dev->compose_out.width, dev->compose_out.height
+	};
+
+	dev->loop_vid_copy = rect_intersect(&dev->crop_cap, &dev->compose_out);
+
+	dev->loop_vid_out = dev->loop_vid_copy;
+	rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out);
+	dev->loop_vid_out.left += dev->crop_out.left;
+	dev->loop_vid_out.top += dev->crop_out.top;
+
+	dev->loop_vid_cap = dev->loop_vid_copy;
+	rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap);
+
+	dprintk(dev, 1,
+		"loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n",
+		dev->loop_vid_copy.width, dev->loop_vid_copy.height,
+		dev->loop_vid_copy.left, dev->loop_vid_copy.top,
+		dev->loop_vid_out.width, dev->loop_vid_out.height,
+		dev->loop_vid_out.left, dev->loop_vid_out.top,
+		dev->loop_vid_cap.width, dev->loop_vid_cap.height,
+		dev->loop_vid_cap.left, dev->loop_vid_cap.top);
+
+	r_overlay = rect_intersect(&r_fb, &r_overlay);
+
+	/* shift r_overlay to the same origin as compose_out */
+	r_overlay.left += dev->compose_out.left - dev->overlay_out_left;
+	r_overlay.top += dev->compose_out.top - dev->overlay_out_top;
+
+	dev->loop_vid_overlay = rect_intersect(&r_overlay, &dev->loop_vid_copy);
+	dev->loop_fb_copy = dev->loop_vid_overlay;
+
+	/* shift dev->loop_fb_copy back again to the fb origin */
+	dev->loop_fb_copy.left -= dev->compose_out.left - dev->overlay_out_left;
+	dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top;
+
+	dev->loop_vid_overlay_cap = dev->loop_vid_overlay;
+	rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap);
+
+	dprintk(dev, 1,
+		"loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n",
+		dev->loop_fb_copy.width, dev->loop_fb_copy.height,
+		dev->loop_fb_copy.left, dev->loop_fb_copy.top,
+		dev->loop_vid_overlay.width, dev->loop_vid_overlay.height,
+		dev->loop_vid_overlay.left, dev->loop_vid_overlay.top,
+		dev->loop_vid_overlay_cap.width, dev->loop_vid_overlay_cap.height,
+		dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top);
+}
+
+static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
+		struct vivid_buffer *vid_cap_buf)
+{
+	bool blank = dev->must_blank[vid_cap_buf->vb.v4l2_buf.index];
+	struct tpg_data *tpg = &dev->tpg;
+	struct vivid_buffer *vid_out_buf = NULL;
+	unsigned pixsize = tpg_g_twopixelsize(tpg, p) / 2;
+	unsigned img_width = dev->compose_cap.width;
+	unsigned img_height = dev->compose_cap.height;
+	unsigned stride_cap = tpg->bytesperline[p];
+	unsigned stride_out = dev->bytesperline_out[p];
+	unsigned stride_osd = dev->display_byte_stride;
+	unsigned hmax = (img_height * tpg->perc_fill) / 100;
+	u8 *voutbuf;
+	u8 *vosdbuf = NULL;
+	unsigned y;
+	bool blend = dev->bitmap_out || dev->clipcount_out || dev->fbuf_out_flags;
+	/* Coarse scaling with Bresenham */
+	unsigned vid_out_int_part;
+	unsigned vid_out_fract_part;
+	unsigned vid_out_y = 0;
+	unsigned vid_out_error = 0;
+	unsigned vid_overlay_int_part = 0;
+	unsigned vid_overlay_fract_part = 0;
+	unsigned vid_overlay_y = 0;
+	unsigned vid_overlay_error = 0;
+	unsigned vid_cap_right;
+	bool quick;
+
+	vid_out_int_part = dev->loop_vid_out.height / dev->loop_vid_cap.height;
+	vid_out_fract_part = dev->loop_vid_out.height % dev->loop_vid_cap.height;
+
+	if (!list_empty(&dev->vid_out_active))
+		vid_out_buf = list_entry(dev->vid_out_active.next,
+					 struct vivid_buffer, list);
+	if (vid_out_buf == NULL)
+		return -ENODATA;
+
+	vid_cap_buf->vb.v4l2_buf.field = vid_out_buf->vb.v4l2_buf.field;
+
+	voutbuf = vb2_plane_vaddr(&vid_out_buf->vb, p) +
+				  vid_out_buf->vb.v4l2_planes[p].data_offset;
+	voutbuf += dev->loop_vid_out.left * pixsize + dev->loop_vid_out.top * stride_out;
+	vcapbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride_cap;
+
+	if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) {
+		/*
+		 * If there is nothing to copy, then just fill the capture window
+		 * with black.
+		 */
+		for (y = 0; y < hmax; y++, vcapbuf += stride_cap)
+			memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize);
+		return 0;
+	}
+
+	if (dev->overlay_out_enabled &&
+	    dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) {
+		vosdbuf = dev->video_vbase;
+		vosdbuf += dev->loop_fb_copy.left * pixsize +
+			   dev->loop_fb_copy.top * stride_osd;
+		vid_overlay_int_part = dev->loop_vid_overlay.height /
+				       dev->loop_vid_overlay_cap.height;
+		vid_overlay_fract_part = dev->loop_vid_overlay.height %
+					 dev->loop_vid_overlay_cap.height;
+	}
+
+	vid_cap_right = dev->loop_vid_cap.left + dev->loop_vid_cap.width;
+	/* quick is true if no video scaling is needed */
+	quick = dev->loop_vid_out.width == dev->loop_vid_cap.width;
+
+	dev->cur_scaled_line = dev->loop_vid_out.height;
+	for (y = 0; y < hmax; y++, vcapbuf += stride_cap) {
+		/* osdline is true if this line requires overlay blending */
+		bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top &&
+			  y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height;
+
+		/*
+		 * If this line of the capture buffer doesn't get any video, then
+		 * just fill with black.
+		 */
+		if (y < dev->loop_vid_cap.top ||
+		    y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) {
+			memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize);
+			continue;
+		}
+
+		/* fill the left border with black */
+		if (dev->loop_vid_cap.left)
+			memcpy(vcapbuf, tpg->black_line[p], dev->loop_vid_cap.left * pixsize);
+
+		/* fill the right border with black */
+		if (vid_cap_right < img_width)
+			memcpy(vcapbuf + vid_cap_right * pixsize,
+				tpg->black_line[p], (img_width - vid_cap_right) * pixsize);
+
+		if (quick && !osdline) {
+			memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
+			       voutbuf + vid_out_y * stride_out,
+			       dev->loop_vid_cap.width * pixsize);
+			goto update_vid_out_y;
+		}
+		if (dev->cur_scaled_line == vid_out_y) {
+			memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
+			       dev->scaled_line,
+			       dev->loop_vid_cap.width * pixsize);
+			goto update_vid_out_y;
+		}
+		if (!osdline) {
+			scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line,
+				dev->loop_vid_out.width, dev->loop_vid_cap.width,
+				tpg_g_twopixelsize(tpg, p));
+		} else {
+			/*
+			 * Offset in bytes within loop_vid_copy to the start of the
+			 * loop_vid_overlay rectangle.
+			 */
+			unsigned offset =
+				(dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * pixsize;
+			u8 *osd = vosdbuf + vid_overlay_y * stride_osd;
+
+			scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line,
+				dev->loop_vid_out.width, dev->loop_vid_copy.width,
+				tpg_g_twopixelsize(tpg, p));
+			if (blend)
+				blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top,
+					   dev->loop_vid_overlay.left,
+					   dev->blended_line + offset, osd,
+					   dev->loop_vid_overlay.width, pixsize);
+			else
+				memcpy(dev->blended_line + offset,
+				       osd, dev->loop_vid_overlay.width * pixsize);
+			scale_line(dev->blended_line, dev->scaled_line,
+					dev->loop_vid_copy.width, dev->loop_vid_cap.width,
+					tpg_g_twopixelsize(tpg, p));
+		}
+		dev->cur_scaled_line = vid_out_y;
+		memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize,
+		       dev->scaled_line,
+		       dev->loop_vid_cap.width * pixsize);
+
+update_vid_out_y:
+		if (osdline) {
+			vid_overlay_y += vid_overlay_int_part;
+			vid_overlay_error += vid_overlay_fract_part;
+			if (vid_overlay_error >= dev->loop_vid_overlay_cap.height) {
+				vid_overlay_error -= dev->loop_vid_overlay_cap.height;
+				vid_overlay_y++;
+			}
+		}
+		vid_out_y += vid_out_int_part;
+		vid_out_error += vid_out_fract_part;
+		if (vid_out_error >= dev->loop_vid_cap.height) {
+			vid_out_error -= dev->loop_vid_cap.height;
+			vid_out_y++;
+		}
+	}
+
+	if (!blank)
+		return 0;
+	for (; y < img_height; y++, vcapbuf += stride_cap)
+		memcpy(vcapbuf, tpg->contrast_line[p], img_width * pixsize);
+	return 0;
+}
+
+static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+	unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
+	unsigned line_height = 16 / factor;
+	bool is_tv = vivid_is_sdtv_cap(dev);
+	bool is_60hz = is_tv && (dev->std_cap & V4L2_STD_525_60);
+	unsigned p;
+	int line = 1;
+	u8 *basep[TPG_MAX_PLANES][2];
+	unsigned ms;
+	char str[100];
+	s32 gain;
+	bool is_loop = false;
+
+	if (dev->loop_video && dev->can_loop_video &&
+	    ((vivid_is_svid_cap(dev) && !VIVID_INVALID_SIGNAL(dev->std_signal_mode)) ||
+	     (vivid_is_hdmi_cap(dev) && !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode))))
+		is_loop = true;
+
+	buf->vb.v4l2_buf.sequence = dev->vid_cap_seq_count;
+	/*
+	 * Take the timestamp now if the timestamp source is set to
+	 * "Start of Exposure".
+	 */
+	if (dev->tstamp_src_is_soe)
+		v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+	if (dev->field_cap == V4L2_FIELD_ALTERNATE) {
+		/*
+		 * 60 Hz standards start with the bottom field, 50 Hz standards
+		 * with the top field. So if the 0-based seq_count is even,
+		 * then the field is TOP for 50 Hz and BOTTOM for 60 Hz
+		 * standards.
+		 */
+		buf->vb.v4l2_buf.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ?
+			V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
+		/*
+		 * The sequence counter counts frames, not fields. So divide
+		 * by two.
+		 */
+		buf->vb.v4l2_buf.sequence /= 2;
+	} else {
+		buf->vb.v4l2_buf.field = dev->field_cap;
+	}
+	tpg_s_field(&dev->tpg, buf->vb.v4l2_buf.field);
+	tpg_s_perc_fill_blank(&dev->tpg, dev->must_blank[buf->vb.v4l2_buf.index]);
+
+	vivid_precalc_copy_rects(dev);
+
+	for (p = 0; p < tpg_g_planes(&dev->tpg); p++) {
+		void *vbuf = vb2_plane_vaddr(&buf->vb, p);
+
+		/*
+		 * The first plane of a multiplanar format has a non-zero
+		 * data_offset. This helps testing whether the application
+		 * correctly supports non-zero data offsets.
+		 */
+		if (dev->fmt_cap->data_offset[p]) {
+			memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff,
+			       dev->fmt_cap->data_offset[p]);
+			vbuf += dev->fmt_cap->data_offset[p];
+		}
+		tpg_calc_text_basep(&dev->tpg, basep, p, vbuf);
+		if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf))
+			tpg_fillbuffer(&dev->tpg, vivid_get_std_cap(dev), p, vbuf);
+	}
+	dev->must_blank[buf->vb.v4l2_buf.index] = false;
+
+	/* Updates stream time, only update at the start of a new frame. */
+	if (dev->field_cap != V4L2_FIELD_ALTERNATE || (buf->vb.v4l2_buf.sequence & 1) == 0)
+		dev->ms_vid_cap = jiffies_to_msecs(jiffies - dev->jiffies_vid_cap);
+
+	ms = dev->ms_vid_cap;
+	if (dev->osd_mode <= 1) {
+		snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d %u%s",
+				(ms / (60 * 60 * 1000)) % 24,
+				(ms / (60 * 1000)) % 60,
+				(ms / 1000) % 60,
+				ms % 1000,
+				buf->vb.v4l2_buf.sequence,
+				(dev->field_cap == V4L2_FIELD_ALTERNATE) ?
+					(buf->vb.v4l2_buf.field == V4L2_FIELD_TOP ?
+					 " top" : " bottom") : "");
+		tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+	}
+	if (dev->osd_mode == 0) {
+		snprintf(str, sizeof(str), " %dx%d, input %d ",
+				dev->src_rect.width, dev->src_rect.height, dev->input);
+		tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+
+		gain = v4l2_ctrl_g_ctrl(dev->gain);
+		mutex_lock(dev->ctrl_hdl_user_vid.lock);
+		snprintf(str, sizeof(str),
+			" brightness %3d, contrast %3d, saturation %3d, hue %d ",
+			dev->brightness->cur.val,
+			dev->contrast->cur.val,
+			dev->saturation->cur.val,
+			dev->hue->cur.val);
+		tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+		snprintf(str, sizeof(str),
+			" autogain %d, gain %3d, alpha 0x%02x ",
+			dev->autogain->cur.val, gain, dev->alpha->cur.val);
+		mutex_unlock(dev->ctrl_hdl_user_vid.lock);
+		tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+		mutex_lock(dev->ctrl_hdl_user_aud.lock);
+		snprintf(str, sizeof(str),
+			" volume %3d, mute %d ",
+			dev->volume->cur.val, dev->mute->cur.val);
+		mutex_unlock(dev->ctrl_hdl_user_aud.lock);
+		tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+		mutex_lock(dev->ctrl_hdl_user_gen.lock);
+		snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
+			dev->int32->cur.val,
+			*dev->int64->p_cur.p_s64,
+			dev->bitmask->cur.val);
+		tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+		snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
+			dev->boolean->cur.val,
+			dev->menu->qmenu[dev->menu->cur.val],
+			dev->string->p_cur.p_char);
+		tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+		snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
+			dev->int_menu->qmenu_int[dev->int_menu->cur.val],
+			dev->int_menu->cur.val);
+		mutex_unlock(dev->ctrl_hdl_user_gen.lock);
+		tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+		if (dev->button_pressed) {
+			dev->button_pressed--;
+			snprintf(str, sizeof(str), " button pressed!");
+			tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str);
+		}
+	}
+
+	/*
+	 * If "End of Frame" is specified at the timestamp source, then take
+	 * the timestamp now.
+	 */
+	if (!dev->tstamp_src_is_soe)
+		v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+	buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+}
+
+/*
+ * Return true if this pixel coordinate is a valid video pixel.
+ */
+static bool valid_pix(struct vivid_dev *dev, int win_y, int win_x, int fb_y, int fb_x)
+{
+	int i;
+
+	if (dev->bitmap_cap) {
+		/*
+		 * Only if the corresponding bit in the bitmap is set can
+		 * the video pixel be shown. Coordinates are relative to
+		 * the overlay window set by VIDIOC_S_FMT.
+		 */
+		const u8 *p = dev->bitmap_cap;
+		unsigned stride = (dev->compose_cap.width + 7) / 8;
+
+		if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7))))
+			return false;
+	}
+
+	for (i = 0; i < dev->clipcount_cap; i++) {
+		/*
+		 * Only if the framebuffer coordinate is not in any of the
+		 * clip rectangles will be video pixel be shown.
+		 */
+		struct v4l2_rect *r = &dev->clips_cap[i].c;
+
+		if (fb_y >= r->top && fb_y < r->top + r->height &&
+		    fb_x >= r->left && fb_x < r->left + r->width)
+			return false;
+	}
+	return true;
+}
+
+/*
+ * Draw the image into the overlay buffer.
+ * Note that the combination of overlay and multiplanar is not supported.
+ */
+static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+	struct tpg_data *tpg = &dev->tpg;
+	unsigned pixsize = tpg_g_twopixelsize(tpg, 0) / 2;
+	void *vbase = dev->fb_vbase_cap;
+	void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+	unsigned img_width = dev->compose_cap.width;
+	unsigned img_height = dev->compose_cap.height;
+	unsigned stride = tpg->bytesperline[0];
+	/* if quick is true, then valid_pix() doesn't have to be called */
+	bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0;
+	int x, y, w, out_x = 0;
+
+	if ((dev->overlay_cap_field == V4L2_FIELD_TOP ||
+	     dev->overlay_cap_field == V4L2_FIELD_BOTTOM) &&
+	    dev->overlay_cap_field != buf->vb.v4l2_buf.field)
+		return;
+
+	vbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride;
+	x = dev->overlay_cap_left;
+	w = img_width;
+	if (x < 0) {
+		out_x = -x;
+		w = w - out_x;
+		x = 0;
+	} else {
+		w = dev->fb_cap.fmt.width - x;
+		if (w > img_width)
+			w = img_width;
+	}
+	if (w <= 0)
+		return;
+	if (dev->overlay_cap_top >= 0)
+		vbase += dev->overlay_cap_top * dev->fb_cap.fmt.bytesperline;
+	for (y = dev->overlay_cap_top;
+	     y < dev->overlay_cap_top + (int)img_height;
+	     y++, vbuf += stride) {
+		int px;
+
+		if (y < 0 || y > dev->fb_cap.fmt.height)
+			continue;
+		if (quick) {
+			memcpy(vbase + x * pixsize,
+			       vbuf + out_x * pixsize, w * pixsize);
+			vbase += dev->fb_cap.fmt.bytesperline;
+			continue;
+		}
+		for (px = 0; px < w; px++) {
+			if (!valid_pix(dev, y - dev->overlay_cap_top,
+				       px + out_x, y, px + x))
+				continue;
+			memcpy(vbase + (px + x) * pixsize,
+			       vbuf + (px + out_x) * pixsize,
+			       pixsize);
+		}
+		vbase += dev->fb_cap.fmt.bytesperline;
+	}
+}
+
+static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
+{
+	struct vivid_buffer *vid_cap_buf = NULL;
+	struct vivid_buffer *vbi_cap_buf = NULL;
+
+	dprintk(dev, 1, "Video Capture Thread Tick\n");
+
+	while (dropped_bufs-- > 1)
+		tpg_update_mv_count(&dev->tpg,
+				dev->field_cap == V4L2_FIELD_NONE ||
+				dev->field_cap == V4L2_FIELD_ALTERNATE);
+
+	/* Drop a certain percentage of buffers. */
+	if (dev->perc_dropped_buffers &&
+	    prandom_u32_max(100) < dev->perc_dropped_buffers)
+		goto update_mv;
+
+	spin_lock(&dev->slock);
+	if (!list_empty(&dev->vid_cap_active)) {
+		vid_cap_buf = list_entry(dev->vid_cap_active.next, struct vivid_buffer, list);
+		list_del(&vid_cap_buf->list);
+	}
+	if (!list_empty(&dev->vbi_cap_active)) {
+		if (dev->field_cap != V4L2_FIELD_ALTERNATE ||
+		    (dev->vbi_cap_seq_count & 1)) {
+			vbi_cap_buf = list_entry(dev->vbi_cap_active.next,
+						 struct vivid_buffer, list);
+			list_del(&vbi_cap_buf->list);
+		}
+	}
+	spin_unlock(&dev->slock);
+
+	if (!vid_cap_buf && !vbi_cap_buf)
+		goto update_mv;
+
+	if (vid_cap_buf) {
+		/* Fill buffer */
+		vivid_fillbuff(dev, vid_cap_buf);
+		dprintk(dev, 1, "filled buffer %d\n",
+			vid_cap_buf->vb.v4l2_buf.index);
+
+		/* Handle overlay */
+		if (dev->overlay_cap_owner && dev->fb_cap.base &&
+				dev->fb_cap.fmt.pixelformat == dev->fmt_cap->fourcc)
+			vivid_overlay(dev, vid_cap_buf);
+
+		vb2_buffer_done(&vid_cap_buf->vb, dev->dqbuf_error ?
+				VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+		dprintk(dev, 2, "vid_cap buffer %d done\n",
+				vid_cap_buf->vb.v4l2_buf.index);
+	}
+
+	if (vbi_cap_buf) {
+		if (dev->stream_sliced_vbi_cap)
+			vivid_sliced_vbi_cap_process(dev, vbi_cap_buf);
+		else
+			vivid_raw_vbi_cap_process(dev, vbi_cap_buf);
+		vb2_buffer_done(&vbi_cap_buf->vb, dev->dqbuf_error ?
+				VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+		dprintk(dev, 2, "vbi_cap %d done\n",
+				vbi_cap_buf->vb.v4l2_buf.index);
+	}
+	dev->dqbuf_error = false;
+
+update_mv:
+	/* Update the test pattern movement counters */
+	tpg_update_mv_count(&dev->tpg, dev->field_cap == V4L2_FIELD_NONE ||
+				       dev->field_cap == V4L2_FIELD_ALTERNATE);
+}
+
+static int vivid_thread_vid_cap(void *data)
+{
+	struct vivid_dev *dev = data;
+	u64 numerators_since_start;
+	u64 buffers_since_start;
+	u64 next_jiffies_since_start;
+	unsigned long jiffies_since_start;
+	unsigned long cur_jiffies;
+	unsigned wait_jiffies;
+	unsigned numerator;
+	unsigned denominator;
+	int dropped_bufs;
+
+	dprintk(dev, 1, "Video Capture Thread Start\n");
+
+	set_freezable();
+
+	/* Resets frame counters */
+	dev->cap_seq_offset = 0;
+	dev->cap_seq_count = 0;
+	dev->cap_seq_resync = false;
+	dev->jiffies_vid_cap = jiffies;
+
+	for (;;) {
+		try_to_freeze();
+		if (kthread_should_stop())
+			break;
+
+		mutex_lock(&dev->mutex);
+		cur_jiffies = jiffies;
+		if (dev->cap_seq_resync) {
+			dev->jiffies_vid_cap = cur_jiffies;
+			dev->cap_seq_offset = dev->cap_seq_count + 1;
+			dev->cap_seq_count = 0;
+			dev->cap_seq_resync = false;
+		}
+		numerator = dev->timeperframe_vid_cap.numerator;
+		denominator = dev->timeperframe_vid_cap.denominator;
+
+		if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+			denominator *= 2;
+
+		/* Calculate the number of jiffies since we started streaming */
+		jiffies_since_start = cur_jiffies - dev->jiffies_vid_cap;
+		/* Get the number of buffers streamed since the start */
+		buffers_since_start = (u64)jiffies_since_start * denominator +
+				      (HZ * numerator) / 2;
+		do_div(buffers_since_start, HZ * numerator);
+
+		/*
+		 * After more than 0xf0000000 (rounded down to a multiple of
+		 * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
+		 * jiffies have passed since we started streaming reset the
+		 * counters and keep track of the sequence offset.
+		 */
+		if (jiffies_since_start > JIFFIES_RESYNC) {
+			dev->jiffies_vid_cap = cur_jiffies;
+			dev->cap_seq_offset = buffers_since_start;
+			buffers_since_start = 0;
+		}
+		dropped_bufs = buffers_since_start + dev->cap_seq_offset - dev->cap_seq_count;
+		dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset;
+		dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start;
+		dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start;
+
+		vivid_thread_vid_cap_tick(dev, dropped_bufs);
+
+		/*
+		 * Calculate the number of 'numerators' streamed since we started,
+		 * including the current buffer.
+		 */
+		numerators_since_start = ++buffers_since_start * numerator;
+
+		/* And the number of jiffies since we started */
+		jiffies_since_start = jiffies - dev->jiffies_vid_cap;
+
+		mutex_unlock(&dev->mutex);
+
+		/*
+		 * Calculate when that next buffer is supposed to start
+		 * in jiffies since we started streaming.
+		 */
+		next_jiffies_since_start = numerators_since_start * HZ +
+					   denominator / 2;
+		do_div(next_jiffies_since_start, denominator);
+		/* If it is in the past, then just schedule asap */
+		if (next_jiffies_since_start < jiffies_since_start)
+			next_jiffies_since_start = jiffies_since_start;
+
+		wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+		schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
+	}
+	dprintk(dev, 1, "Video Capture Thread End\n");
+	return 0;
+}
+
+static void vivid_grab_controls(struct vivid_dev *dev, bool grab)
+{
+	v4l2_ctrl_grab(dev->ctrl_has_crop_cap, grab);
+	v4l2_ctrl_grab(dev->ctrl_has_compose_cap, grab);
+	v4l2_ctrl_grab(dev->ctrl_has_scaler_cap, grab);
+}
+
+int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
+{
+	dprintk(dev, 1, "%s\n", __func__);
+
+	if (dev->kthread_vid_cap) {
+		u32 seq_count = dev->cap_seq_count + dev->seq_wrap * 128;
+
+		if (pstreaming == &dev->vid_cap_streaming)
+			dev->vid_cap_seq_start = seq_count;
+		else
+			dev->vbi_cap_seq_start = seq_count;
+		*pstreaming = true;
+		return 0;
+	}
+
+	/* Resets frame counters */
+	tpg_init_mv_count(&dev->tpg);
+
+	dev->vid_cap_seq_start = dev->seq_wrap * 128;
+	dev->vbi_cap_seq_start = dev->seq_wrap * 128;
+
+	dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev,
+			"%s-vid-cap", dev->v4l2_dev.name);
+
+	if (IS_ERR(dev->kthread_vid_cap)) {
+		v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+		return PTR_ERR(dev->kthread_vid_cap);
+	}
+	*pstreaming = true;
+	vivid_grab_controls(dev, true);
+
+	dprintk(dev, 1, "returning from %s\n", __func__);
+	return 0;
+}
+
+void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
+{
+	dprintk(dev, 1, "%s\n", __func__);
+
+	if (dev->kthread_vid_cap == NULL)
+		return;
+
+	*pstreaming = false;
+	if (pstreaming == &dev->vid_cap_streaming) {
+		/* Release all active buffers */
+		while (!list_empty(&dev->vid_cap_active)) {
+			struct vivid_buffer *buf;
+
+			buf = list_entry(dev->vid_cap_active.next,
+					 struct vivid_buffer, list);
+			list_del(&buf->list);
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+			dprintk(dev, 2, "vid_cap buffer %d done\n",
+				buf->vb.v4l2_buf.index);
+		}
+	}
+
+	if (pstreaming == &dev->vbi_cap_streaming) {
+		while (!list_empty(&dev->vbi_cap_active)) {
+			struct vivid_buffer *buf;
+
+			buf = list_entry(dev->vbi_cap_active.next,
+					 struct vivid_buffer, list);
+			list_del(&buf->list);
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+			dprintk(dev, 2, "vbi_cap buffer %d done\n",
+				buf->vb.v4l2_buf.index);
+		}
+	}
+
+	if (dev->vid_cap_streaming || dev->vbi_cap_streaming)
+		return;
+
+	/* shutdown control thread */
+	vivid_grab_controls(dev, false);
+	mutex_unlock(&dev->mutex);
+	kthread_stop(dev->kthread_vid_cap);
+	dev->kthread_vid_cap = NULL;
+	mutex_lock(&dev->mutex);
+}
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.h b/drivers/media/platform/vivid/vivid-kthread-cap.h
new file mode 100644
index 0000000..5b92fc9
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.h
@@ -0,0 +1,26 @@
+/*
+ * vivid-kthread-cap.h - video/vbi capture thread support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_KTHREAD_CAP_H_
+#define _VIVID_KTHREAD_CAP_H_
+
+int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming);
+void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c
new file mode 100644
index 0000000..d9f36cc
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-out.c
@@ -0,0 +1,305 @@
+/*
+ * vivid-kthread-out.h - video/vbi output thread support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/random.h>
+#include <linux/v4l2-dv-timings.h>
+#include <asm/div64.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-vid-cap.h"
+#include "vivid-vid-out.h"
+#include "vivid-radio-common.h"
+#include "vivid-radio-rx.h"
+#include "vivid-radio-tx.h"
+#include "vivid-sdr-cap.h"
+#include "vivid-vbi-cap.h"
+#include "vivid-vbi-out.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.h"
+#include "vivid-kthread-out.h"
+
+static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
+{
+	struct vivid_buffer *vid_out_buf = NULL;
+	struct vivid_buffer *vbi_out_buf = NULL;
+
+	dprintk(dev, 1, "Video Output Thread Tick\n");
+
+	/* Drop a certain percentage of buffers. */
+	if (dev->perc_dropped_buffers &&
+	    prandom_u32_max(100) < dev->perc_dropped_buffers)
+		return;
+
+	spin_lock(&dev->slock);
+	/*
+	 * Only dequeue buffer if there is at least one more pending.
+	 * This makes video loopback possible.
+	 */
+	if (!list_empty(&dev->vid_out_active) &&
+	    !list_is_singular(&dev->vid_out_active)) {
+		vid_out_buf = list_entry(dev->vid_out_active.next,
+					 struct vivid_buffer, list);
+		list_del(&vid_out_buf->list);
+	}
+	if (!list_empty(&dev->vbi_out_active) &&
+	    (dev->field_out != V4L2_FIELD_ALTERNATE ||
+	     (dev->vbi_out_seq_count & 1))) {
+		vbi_out_buf = list_entry(dev->vbi_out_active.next,
+					 struct vivid_buffer, list);
+		list_del(&vbi_out_buf->list);
+	}
+	spin_unlock(&dev->slock);
+
+	if (!vid_out_buf && !vbi_out_buf)
+		return;
+
+	if (vid_out_buf) {
+		vid_out_buf->vb.v4l2_buf.sequence = dev->vid_out_seq_count;
+		if (dev->field_out == V4L2_FIELD_ALTERNATE) {
+			/*
+			 * The sequence counter counts frames, not fields. So divide
+			 * by two.
+			 */
+			vid_out_buf->vb.v4l2_buf.sequence /= 2;
+		}
+		v4l2_get_timestamp(&vid_out_buf->vb.v4l2_buf.timestamp);
+		vid_out_buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+		vb2_buffer_done(&vid_out_buf->vb, dev->dqbuf_error ?
+				VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+		dprintk(dev, 2, "vid_out buffer %d done\n",
+			vid_out_buf->vb.v4l2_buf.index);
+	}
+
+	if (vbi_out_buf) {
+		if (dev->stream_sliced_vbi_out)
+			vivid_sliced_vbi_out_process(dev, vbi_out_buf);
+
+		vbi_out_buf->vb.v4l2_buf.sequence = dev->vbi_out_seq_count;
+		v4l2_get_timestamp(&vbi_out_buf->vb.v4l2_buf.timestamp);
+		vbi_out_buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+		vb2_buffer_done(&vbi_out_buf->vb, dev->dqbuf_error ?
+				VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+		dprintk(dev, 2, "vbi_out buffer %d done\n",
+			vbi_out_buf->vb.v4l2_buf.index);
+	}
+	dev->dqbuf_error = false;
+}
+
+static int vivid_thread_vid_out(void *data)
+{
+	struct vivid_dev *dev = data;
+	u64 numerators_since_start;
+	u64 buffers_since_start;
+	u64 next_jiffies_since_start;
+	unsigned long jiffies_since_start;
+	unsigned long cur_jiffies;
+	unsigned wait_jiffies;
+	unsigned numerator;
+	unsigned denominator;
+
+	dprintk(dev, 1, "Video Output Thread Start\n");
+
+	set_freezable();
+
+	/* Resets frame counters */
+	dev->out_seq_offset = 0;
+	if (dev->seq_wrap)
+		dev->out_seq_count = 0xffffff80U;
+	dev->jiffies_vid_out = jiffies;
+	dev->vid_out_seq_start = dev->vbi_out_seq_start = 0;
+	dev->out_seq_resync = false;
+
+	for (;;) {
+		try_to_freeze();
+		if (kthread_should_stop())
+			break;
+
+		mutex_lock(&dev->mutex);
+		cur_jiffies = jiffies;
+		if (dev->out_seq_resync) {
+			dev->jiffies_vid_out = cur_jiffies;
+			dev->out_seq_offset = dev->out_seq_count + 1;
+			dev->out_seq_count = 0;
+			dev->out_seq_resync = false;
+		}
+		numerator = dev->timeperframe_vid_out.numerator;
+		denominator = dev->timeperframe_vid_out.denominator;
+
+		if (dev->field_out == V4L2_FIELD_ALTERNATE)
+			denominator *= 2;
+
+		/* Calculate the number of jiffies since we started streaming */
+		jiffies_since_start = cur_jiffies - dev->jiffies_vid_out;
+		/* Get the number of buffers streamed since the start */
+		buffers_since_start = (u64)jiffies_since_start * denominator +
+				      (HZ * numerator) / 2;
+		do_div(buffers_since_start, HZ * numerator);
+
+		/*
+		 * After more than 0xf0000000 (rounded down to a multiple of
+		 * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
+		 * jiffies have passed since we started streaming reset the
+		 * counters and keep track of the sequence offset.
+		 */
+		if (jiffies_since_start > JIFFIES_RESYNC) {
+			dev->jiffies_vid_out = cur_jiffies;
+			dev->out_seq_offset = buffers_since_start;
+			buffers_since_start = 0;
+		}
+		dev->out_seq_count = buffers_since_start + dev->out_seq_offset;
+		dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start;
+		dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start;
+
+		vivid_thread_vid_out_tick(dev);
+		mutex_unlock(&dev->mutex);
+
+		/*
+		 * Calculate the number of 'numerators' streamed since we started,
+		 * not including the current buffer.
+		 */
+		numerators_since_start = buffers_since_start * numerator;
+
+		/* And the number of jiffies since we started */
+		jiffies_since_start = jiffies - dev->jiffies_vid_out;
+
+		/* Increase by the 'numerator' of one buffer */
+		numerators_since_start += numerator;
+		/*
+		 * Calculate when that next buffer is supposed to start
+		 * in jiffies since we started streaming.
+		 */
+		next_jiffies_since_start = numerators_since_start * HZ +
+					   denominator / 2;
+		do_div(next_jiffies_since_start, denominator);
+		/* If it is in the past, then just schedule asap */
+		if (next_jiffies_since_start < jiffies_since_start)
+			next_jiffies_since_start = jiffies_since_start;
+
+		wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+		schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
+	}
+	dprintk(dev, 1, "Video Output Thread End\n");
+	return 0;
+}
+
+static void vivid_grab_controls(struct vivid_dev *dev, bool grab)
+{
+	v4l2_ctrl_grab(dev->ctrl_has_crop_out, grab);
+	v4l2_ctrl_grab(dev->ctrl_has_compose_out, grab);
+	v4l2_ctrl_grab(dev->ctrl_has_scaler_out, grab);
+	v4l2_ctrl_grab(dev->ctrl_tx_mode, grab);
+	v4l2_ctrl_grab(dev->ctrl_tx_rgb_range, grab);
+}
+
+int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
+{
+	dprintk(dev, 1, "%s\n", __func__);
+
+	if (dev->kthread_vid_out) {
+		u32 seq_count = dev->out_seq_count + dev->seq_wrap * 128;
+
+		if (pstreaming == &dev->vid_out_streaming)
+			dev->vid_out_seq_start = seq_count;
+		else
+			dev->vbi_out_seq_start = seq_count;
+		*pstreaming = true;
+		return 0;
+	}
+
+	/* Resets frame counters */
+	dev->jiffies_vid_out = jiffies;
+	dev->vid_out_seq_start = dev->seq_wrap * 128;
+	dev->vbi_out_seq_start = dev->seq_wrap * 128;
+
+	dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev,
+			"%s-vid-out", dev->v4l2_dev.name);
+
+	if (IS_ERR(dev->kthread_vid_out)) {
+		v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+		return PTR_ERR(dev->kthread_vid_out);
+	}
+	*pstreaming = true;
+	vivid_grab_controls(dev, true);
+
+	dprintk(dev, 1, "returning from %s\n", __func__);
+	return 0;
+}
+
+void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
+{
+	dprintk(dev, 1, "%s\n", __func__);
+
+	if (dev->kthread_vid_out == NULL)
+		return;
+
+	*pstreaming = false;
+	if (pstreaming == &dev->vid_out_streaming) {
+		/* Release all active buffers */
+		while (!list_empty(&dev->vid_out_active)) {
+			struct vivid_buffer *buf;
+
+			buf = list_entry(dev->vid_out_active.next,
+					 struct vivid_buffer, list);
+			list_del(&buf->list);
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+			dprintk(dev, 2, "vid_out buffer %d done\n",
+				buf->vb.v4l2_buf.index);
+		}
+	}
+
+	if (pstreaming == &dev->vbi_out_streaming) {
+		while (!list_empty(&dev->vbi_out_active)) {
+			struct vivid_buffer *buf;
+
+			buf = list_entry(dev->vbi_out_active.next,
+					 struct vivid_buffer, list);
+			list_del(&buf->list);
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+			dprintk(dev, 2, "vbi_out buffer %d done\n",
+				buf->vb.v4l2_buf.index);
+		}
+	}
+
+	if (dev->vid_out_streaming || dev->vbi_out_streaming)
+		return;
+
+	/* shutdown control thread */
+	vivid_grab_controls(dev, false);
+	mutex_unlock(&dev->mutex);
+	kthread_stop(dev->kthread_vid_out);
+	dev->kthread_vid_out = NULL;
+	mutex_lock(&dev->mutex);
+}
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.h b/drivers/media/platform/vivid/vivid-kthread-out.h
new file mode 100644
index 0000000..2bf04a1
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-out.h
@@ -0,0 +1,26 @@
+/*
+ * vivid-kthread-out.h - video/vbi output thread support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_KTHREAD_OUT_H_
+#define _VIVID_KTHREAD_OUT_H_
+
+int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming);
+void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c
new file mode 100644
index 0000000..084d346
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-osd.c
@@ -0,0 +1,400 @@
+/*
+ * vivid-osd.c - osd support for testing overlays.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/fb.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
+
+#include "vivid-core.h"
+#include "vivid-osd.h"
+
+#define MAX_OSD_WIDTH  720
+#define MAX_OSD_HEIGHT 576
+
+/*
+ * Order: white, yellow, cyan, green, magenta, red, blue, black,
+ * and same again with the alpha bit set (if any)
+ */
+static const u16 rgb555[16] = {
+	0x7fff, 0x7fe0, 0x03ff, 0x03e0, 0x7c1f, 0x7c00, 0x001f, 0x0000,
+	0xffff, 0xffe0, 0x83ff, 0x83e0, 0xfc1f, 0xfc00, 0x801f, 0x8000
+};
+
+static const u16 rgb565[16] = {
+	0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000,
+	0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000
+};
+
+void vivid_clear_fb(struct vivid_dev *dev)
+{
+	void *p = dev->video_vbase;
+	const u16 *rgb = rgb555;
+	unsigned x, y;
+
+	if (dev->fb_defined.green.length == 6)
+		rgb = rgb565;
+
+	for (y = 0; y < dev->display_height; y++) {
+		u16 *d = p;
+
+		for (x = 0; x < dev->display_width; x++)
+			d[x] = rgb[(y / 16 + x / 16) % 16];
+		p += dev->display_byte_stride;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static int vivid_fb_ioctl(struct fb_info *info, unsigned cmd, unsigned long arg)
+{
+	struct vivid_dev *dev = (struct vivid_dev *)info->par;
+
+	switch (cmd) {
+	case FBIOGET_VBLANK: {
+		struct fb_vblank vblank;
+
+		vblank.flags = FB_VBLANK_HAVE_COUNT | FB_VBLANK_HAVE_VCOUNT |
+			FB_VBLANK_HAVE_VSYNC;
+		vblank.count = 0;
+		vblank.vcount = 0;
+		vblank.hcount = 0;
+		if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
+			return -EFAULT;
+		return 0;
+	}
+
+	default:
+		dprintk(dev, 1, "Unknown ioctl %08x\n", cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Framebuffer device handling */
+
+static int vivid_fb_set_var(struct vivid_dev *dev, struct fb_var_screeninfo *var)
+{
+	dprintk(dev, 1, "vivid_fb_set_var\n");
+
+	if (var->bits_per_pixel != 16) {
+		dprintk(dev, 1, "vivid_fb_set_var - Invalid bpp\n");
+		return -EINVAL;
+	}
+	dev->display_byte_stride = var->xres * dev->bytes_per_pixel;
+
+	return 0;
+}
+
+static int vivid_fb_get_fix(struct vivid_dev *dev, struct fb_fix_screeninfo *fix)
+{
+	dprintk(dev, 1, "vivid_fb_get_fix\n");
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strlcpy(fix->id, "vioverlay fb", sizeof(fix->id));
+	fix->smem_start = dev->video_pbase;
+	fix->smem_len = dev->video_buffer_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->visual = FB_VISUAL_TRUECOLOR;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	fix->line_length = dev->display_byte_stride;
+	fix->accel = FB_ACCEL_NONE;
+	return 0;
+}
+
+/* Check the requested display mode, returning -EINVAL if we can't
+   handle it. */
+
+static int _vivid_fb_check_var(struct fb_var_screeninfo *var, struct vivid_dev *dev)
+{
+	dprintk(dev, 1, "vivid_fb_check_var\n");
+
+	var->bits_per_pixel = 16;
+	if (var->green.length == 5) {
+		var->red.offset = 10;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 5;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 15;
+		var->transp.length = 1;
+	} else {
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+	}
+	var->xoffset = var->yoffset = 0;
+	var->left_margin = var->upper_margin = 0;
+	var->nonstd = 0;
+
+	var->vmode &= ~FB_VMODE_MASK;
+	var->vmode = FB_VMODE_NONINTERLACED;
+
+	/* Dummy values */
+	var->hsync_len = 24;
+	var->vsync_len = 2;
+	var->pixclock = 84316;
+	var->right_margin = 776;
+	var->lower_margin = 591;
+	return 0;
+}
+
+static int vivid_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct vivid_dev *dev = (struct vivid_dev *) info->par;
+
+	dprintk(dev, 1, "vivid_fb_check_var\n");
+	return _vivid_fb_check_var(var, dev);
+}
+
+static int vivid_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	return 0;
+}
+
+static int vivid_fb_set_par(struct fb_info *info)
+{
+	int rc = 0;
+	struct vivid_dev *dev = (struct vivid_dev *) info->par;
+
+	dprintk(dev, 1, "vivid_fb_set_par\n");
+
+	rc = vivid_fb_set_var(dev, &info->var);
+	vivid_fb_get_fix(dev, &info->fix);
+	return rc;
+}
+
+static int vivid_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+				unsigned blue, unsigned transp,
+				struct fb_info *info)
+{
+	u32 color, *palette;
+
+	if (regno >= info->cmap.len)
+		return -EINVAL;
+
+	color = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) |
+		 (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+	if (regno >= 16)
+		return -EINVAL;
+
+	palette = info->pseudo_palette;
+	if (info->var.bits_per_pixel == 16) {
+		switch (info->var.green.length) {
+		case 6:
+			color = (red & 0xf800) |
+				((green & 0xfc00) >> 5) |
+				((blue & 0xf800) >> 11);
+			break;
+		case 5:
+			color = ((red & 0xf800) >> 1) |
+				((green & 0xf800) >> 6) |
+				((blue & 0xf800) >> 11) |
+				(transp ? 0x8000 : 0);
+			break;
+		}
+	}
+	palette[regno] = color;
+	return 0;
+}
+
+/* We don't really support blanking. All this does is enable or
+   disable the OSD. */
+static int vivid_fb_blank(int blank_mode, struct fb_info *info)
+{
+	struct vivid_dev *dev = (struct vivid_dev *)info->par;
+
+	dprintk(dev, 1, "Set blanking mode : %d\n", blank_mode);
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		break;
+	case FB_BLANK_NORMAL:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_POWERDOWN:
+		break;
+	}
+	return 0;
+}
+
+static struct fb_ops vivid_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_check_var   = vivid_fb_check_var,
+	.fb_set_par     = vivid_fb_set_par,
+	.fb_setcolreg   = vivid_fb_setcolreg,
+	.fb_fillrect    = cfb_fillrect,
+	.fb_copyarea    = cfb_copyarea,
+	.fb_imageblit   = cfb_imageblit,
+	.fb_cursor      = NULL,
+	.fb_ioctl       = vivid_fb_ioctl,
+	.fb_pan_display = vivid_fb_pan_display,
+	.fb_blank       = vivid_fb_blank,
+};
+
+/* Initialization */
+
+
+/* Setup our initial video mode */
+static int vivid_fb_init_vidmode(struct vivid_dev *dev)
+{
+	struct v4l2_rect start_window;
+
+	/* Color mode */
+
+	dev->bits_per_pixel = 16;
+	dev->bytes_per_pixel = dev->bits_per_pixel / 8;
+
+	start_window.width = MAX_OSD_WIDTH;
+	start_window.left = 0;
+
+	dev->display_byte_stride = start_window.width * dev->bytes_per_pixel;
+
+	/* Vertical size & position */
+
+	start_window.height = MAX_OSD_HEIGHT;
+	start_window.top = 0;
+
+	dev->display_width = start_window.width;
+	dev->display_height = start_window.height;
+
+	/* Generate a valid fb_var_screeninfo */
+
+	dev->fb_defined.xres = dev->display_width;
+	dev->fb_defined.yres = dev->display_height;
+	dev->fb_defined.xres_virtual = dev->display_width;
+	dev->fb_defined.yres_virtual = dev->display_height;
+	dev->fb_defined.bits_per_pixel = dev->bits_per_pixel;
+	dev->fb_defined.vmode = FB_VMODE_NONINTERLACED;
+	dev->fb_defined.left_margin = start_window.left + 1;
+	dev->fb_defined.upper_margin = start_window.top + 1;
+	dev->fb_defined.accel_flags = FB_ACCEL_NONE;
+	dev->fb_defined.nonstd = 0;
+	/* set default to 1:5:5:5 */
+	dev->fb_defined.green.length = 5;
+
+	/* We've filled in the most data, let the usual mode check
+	   routine fill in the rest. */
+	_vivid_fb_check_var(&dev->fb_defined, dev);
+
+	/* Generate valid fb_fix_screeninfo */
+
+	vivid_fb_get_fix(dev, &dev->fb_fix);
+
+	/* Generate valid fb_info */
+
+	dev->fb_info.node = -1;
+	dev->fb_info.flags = FBINFO_FLAG_DEFAULT;
+	dev->fb_info.fbops = &vivid_fb_ops;
+	dev->fb_info.par = dev;
+	dev->fb_info.var = dev->fb_defined;
+	dev->fb_info.fix = dev->fb_fix;
+	dev->fb_info.screen_base = (u8 __iomem *)dev->video_vbase;
+	dev->fb_info.fbops = &vivid_fb_ops;
+
+	/* Supply some monitor specs. Bogus values will do for now */
+	dev->fb_info.monspecs.hfmin = 8000;
+	dev->fb_info.monspecs.hfmax = 70000;
+	dev->fb_info.monspecs.vfmin = 10;
+	dev->fb_info.monspecs.vfmax = 100;
+
+	/* Allocate color map */
+	if (fb_alloc_cmap(&dev->fb_info.cmap, 256, 1)) {
+		pr_err("abort, unable to alloc cmap\n");
+		return -ENOMEM;
+	}
+
+	/* Allocate the pseudo palette */
+	dev->fb_info.pseudo_palette = kmalloc_array(16, sizeof(u32), GFP_KERNEL);
+
+	return dev->fb_info.pseudo_palette ? 0 : -ENOMEM;
+}
+
+/* Release any memory we've grabbed */
+void vivid_fb_release_buffers(struct vivid_dev *dev)
+{
+	if (dev->video_vbase == NULL)
+		return;
+
+	/* Release cmap */
+	if (dev->fb_info.cmap.len)
+		fb_dealloc_cmap(&dev->fb_info.cmap);
+
+	/* Release pseudo palette */
+	kfree(dev->fb_info.pseudo_palette);
+	kfree((void *)dev->video_vbase);
+}
+
+/* Initialize the specified card */
+
+int vivid_fb_init(struct vivid_dev *dev)
+{
+	int ret;
+
+	dev->video_buffer_size = MAX_OSD_HEIGHT * MAX_OSD_WIDTH * 2;
+	dev->video_vbase = kzalloc(dev->video_buffer_size, GFP_KERNEL | GFP_DMA32);
+	if (dev->video_vbase == NULL)
+		return -ENOMEM;
+	dev->video_pbase = virt_to_phys(dev->video_vbase);
+
+	pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+			dev->video_pbase, dev->video_vbase,
+			dev->video_buffer_size / 1024);
+
+	/* Set the startup video mode information */
+	ret = vivid_fb_init_vidmode(dev);
+	if (ret) {
+		vivid_fb_release_buffers(dev);
+		return ret;
+	}
+
+	vivid_clear_fb(dev);
+
+	/* Register the framebuffer */
+	if (register_framebuffer(&dev->fb_info) < 0) {
+		vivid_fb_release_buffers(dev);
+		return -EINVAL;
+	}
+
+	/* Set the card to the requested mode */
+	vivid_fb_set_par(&dev->fb_info);
+	return 0;
+
+}
diff --git a/drivers/media/platform/vivid/vivid-osd.h b/drivers/media/platform/vivid/vivid-osd.h
new file mode 100644
index 0000000..57c9daa
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-osd.h
@@ -0,0 +1,27 @@
+/*
+ * vivid-osd.h - output overlay support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_OSD_H_
+#define _VIVID_OSD_H_
+
+int vivid_fb_init(struct vivid_dev *dev);
+void vivid_fb_release_buffers(struct vivid_dev *dev);
+void vivid_clear_fb(struct vivid_dev *dev);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-radio-common.c b/drivers/media/platform/vivid/vivid-radio-common.c
new file mode 100644
index 0000000..78c1e92
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-radio-common.c
@@ -0,0 +1,189 @@
+/*
+ * vivid-radio-common.c - common radio rx/tx support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-radio-common.h"
+#include "vivid-rds-gen.h"
+
+/*
+ * These functions are shared between the vivid receiver and transmitter
+ * since both use the same frequency bands.
+ */
+
+const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS] = {
+	/* Band FM */
+	{
+		.type = V4L2_TUNER_RADIO,
+		.index = 0,
+		.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+			      V4L2_TUNER_CAP_FREQ_BANDS,
+		.rangelow   = FM_FREQ_RANGE_LOW,
+		.rangehigh  = FM_FREQ_RANGE_HIGH,
+		.modulation = V4L2_BAND_MODULATION_FM,
+	},
+	/* Band AM */
+	{
+		.type = V4L2_TUNER_RADIO,
+		.index = 1,
+		.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
+		.rangelow   = AM_FREQ_RANGE_LOW,
+		.rangehigh  = AM_FREQ_RANGE_HIGH,
+		.modulation = V4L2_BAND_MODULATION_AM,
+	},
+	/* Band SW */
+	{
+		.type = V4L2_TUNER_RADIO,
+		.index = 2,
+		.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
+		.rangelow   = SW_FREQ_RANGE_LOW,
+		.rangehigh  = SW_FREQ_RANGE_HIGH,
+		.modulation = V4L2_BAND_MODULATION_AM,
+	},
+};
+
+/*
+ * Initialize the RDS generator. If we can loop, then the RDS generator
+ * is set up with the values from the RDS TX controls, otherwise it
+ * will fill in standard values using one of two alternates.
+ */
+void vivid_radio_rds_init(struct vivid_dev *dev)
+{
+	struct vivid_rds_gen *rds = &dev->rds_gen;
+	bool alt = dev->radio_rx_rds_use_alternates;
+
+	/* Do nothing, blocks will be filled by the transmitter */
+	if (dev->radio_rds_loop && !dev->radio_tx_rds_controls)
+		return;
+
+	if (dev->radio_rds_loop) {
+		v4l2_ctrl_lock(dev->radio_tx_rds_pi);
+		rds->picode = dev->radio_tx_rds_pi->cur.val;
+		rds->pty = dev->radio_tx_rds_pty->cur.val;
+		rds->mono_stereo = dev->radio_tx_rds_mono_stereo->cur.val;
+		rds->art_head = dev->radio_tx_rds_art_head->cur.val;
+		rds->compressed = dev->radio_tx_rds_compressed->cur.val;
+		rds->dyn_pty = dev->radio_tx_rds_dyn_pty->cur.val;
+		rds->ta = dev->radio_tx_rds_ta->cur.val;
+		rds->tp = dev->radio_tx_rds_tp->cur.val;
+		rds->ms = dev->radio_tx_rds_ms->cur.val;
+		strlcpy(rds->psname,
+			dev->radio_tx_rds_psname->p_cur.p_char,
+			sizeof(rds->psname));
+		strlcpy(rds->radiotext,
+			dev->radio_tx_rds_radiotext->p_cur.p_char + alt * 64,
+			sizeof(rds->radiotext));
+		v4l2_ctrl_unlock(dev->radio_tx_rds_pi);
+	} else {
+		vivid_rds_gen_fill(rds, dev->radio_rx_freq, alt);
+	}
+	if (dev->radio_rx_rds_controls) {
+		v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, rds->pty);
+		v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, rds->ta);
+		v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, rds->tp);
+		v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, rds->ms);
+		v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, rds->psname);
+		v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, rds->radiotext);
+		if (!dev->radio_rds_loop)
+			dev->radio_rx_rds_use_alternates = !dev->radio_rx_rds_use_alternates;
+	}
+	vivid_rds_generate(rds);
+}
+
+/*
+ * Calculate the emulated signal quality taking into account the frequency
+ * the transmitter is using.
+ */
+static void vivid_radio_calc_sig_qual(struct vivid_dev *dev)
+{
+	int mod = 16000;
+	int delta = 800;
+	int sig_qual, sig_qual_tx = mod;
+
+	/*
+	 * For SW and FM there is a channel every 1000 kHz, for AM there is one
+	 * every 100 kHz.
+	 */
+	if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH) {
+		mod /= 10;
+		delta /= 10;
+	}
+	sig_qual = (dev->radio_rx_freq + delta) % mod - delta;
+	if (dev->has_radio_tx)
+		sig_qual_tx = dev->radio_rx_freq - dev->radio_tx_freq;
+	if (abs(sig_qual_tx) <= abs(sig_qual)) {
+		sig_qual = sig_qual_tx;
+		/*
+		 * Zero the internal rds buffer if we are going to loop
+		 * rds blocks.
+		 */
+		if (!dev->radio_rds_loop && !dev->radio_tx_rds_controls)
+			memset(dev->rds_gen.data, 0,
+			       sizeof(dev->rds_gen.data));
+		dev->radio_rds_loop = dev->radio_rx_freq >= FM_FREQ_RANGE_LOW;
+	} else {
+		dev->radio_rds_loop = false;
+	}
+	if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH)
+		sig_qual *= 10;
+	dev->radio_rx_sig_qual = sig_qual;
+}
+
+int vivid_radio_g_frequency(struct file *file, const unsigned *pfreq, struct v4l2_frequency *vf)
+{
+	if (vf->tuner != 0)
+		return -EINVAL;
+	vf->frequency = *pfreq;
+	return 0;
+}
+
+int vivid_radio_s_frequency(struct file *file, unsigned *pfreq, const struct v4l2_frequency *vf)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	unsigned freq;
+	unsigned band;
+
+	if (vf->tuner != 0)
+		return -EINVAL;
+
+	if (vf->frequency >= (FM_FREQ_RANGE_LOW + SW_FREQ_RANGE_HIGH) / 2)
+		band = BAND_FM;
+	else if (vf->frequency <= (AM_FREQ_RANGE_HIGH + SW_FREQ_RANGE_LOW) / 2)
+		band = BAND_AM;
+	else
+		band = BAND_SW;
+
+	freq = clamp_t(u32, vf->frequency, vivid_radio_bands[band].rangelow,
+					   vivid_radio_bands[band].rangehigh);
+	*pfreq = freq;
+
+	/*
+	 * For both receiver and transmitter recalculate the signal quality
+	 * (since that depends on both frequencies) and re-init the rds
+	 * generator.
+	 */
+	vivid_radio_calc_sig_qual(dev);
+	vivid_radio_rds_init(dev);
+	return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-radio-common.h b/drivers/media/platform/vivid/vivid-radio-common.h
new file mode 100644
index 0000000..92fe589
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-radio-common.h
@@ -0,0 +1,40 @@
+/*
+ * vivid-radio-common.h - common radio rx/tx support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_RADIO_COMMON_H_
+#define _VIVID_RADIO_COMMON_H_
+
+/* The supported radio frequency ranges in kHz */
+#define FM_FREQ_RANGE_LOW       (64000U * 16U)
+#define FM_FREQ_RANGE_HIGH      (108000U * 16U)
+#define AM_FREQ_RANGE_LOW       (520U * 16U)
+#define AM_FREQ_RANGE_HIGH      (1710U * 16U)
+#define SW_FREQ_RANGE_LOW       (2300U * 16U)
+#define SW_FREQ_RANGE_HIGH      (26100U * 16U)
+
+enum { BAND_FM, BAND_AM, BAND_SW, TOT_BANDS };
+
+extern const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS];
+
+int vivid_radio_g_frequency(struct file *file, const unsigned *freq, struct v4l2_frequency *vf);
+int vivid_radio_s_frequency(struct file *file, unsigned *freq, const struct v4l2_frequency *vf);
+
+void vivid_radio_rds_init(struct vivid_dev *dev);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c
new file mode 100644
index 0000000..c7651a5
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-radio-rx.c
@@ -0,0 +1,287 @@
+/*
+ * vivid-radio-rx.c - radio receiver support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-radio-common.h"
+#include "vivid-rds-gen.h"
+#include "vivid-radio-rx.h"
+
+ssize_t vivid_radio_rx_read(struct file *file, char __user *buf,
+			 size_t size, loff_t *offset)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct timespec ts;
+	struct v4l2_rds_data *data = dev->rds_gen.data;
+	bool use_alternates;
+	unsigned blk;
+	int perc;
+	int i;
+
+	if (dev->radio_rx_rds_controls)
+		return -EINVAL;
+	if (size < sizeof(*data))
+		return 0;
+	size = sizeof(*data) * (size / sizeof(*data));
+
+	if (mutex_lock_interruptible(&dev->mutex))
+		return -ERESTARTSYS;
+	if (dev->radio_rx_rds_owner &&
+	    file->private_data != dev->radio_rx_rds_owner) {
+		mutex_unlock(&dev->mutex);
+		return -EBUSY;
+	}
+	if (dev->radio_rx_rds_owner == NULL) {
+		vivid_radio_rds_init(dev);
+		dev->radio_rx_rds_owner = file->private_data;
+	}
+
+retry:
+	ktime_get_ts(&ts);
+	use_alternates = ts.tv_sec % 10 >= 5;
+	if (dev->radio_rx_rds_last_block == 0 ||
+	    dev->radio_rx_rds_use_alternates != use_alternates) {
+		dev->radio_rx_rds_use_alternates = use_alternates;
+		/* Re-init the RDS generator */
+		vivid_radio_rds_init(dev);
+	}
+	ts = timespec_sub(ts, dev->radio_rds_init_ts);
+	blk = ts.tv_sec * 100 + ts.tv_nsec / 10000000;
+	blk = (blk * VIVID_RDS_GEN_BLOCKS) / 500;
+	if (blk >= dev->radio_rx_rds_last_block + VIVID_RDS_GEN_BLOCKS)
+		dev->radio_rx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1;
+
+	/*
+	 * No data is available if there hasn't been time to get new data,
+	 * or if the RDS receiver has been disabled, or if we use the data
+	 * from the RDS transmitter and that RDS transmitter has been disabled,
+	 * or if the signal quality is too weak.
+	 */
+	if (blk == dev->radio_rx_rds_last_block || !dev->radio_rx_rds_enabled ||
+	    (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) ||
+	    abs(dev->radio_rx_sig_qual) > 200) {
+		mutex_unlock(&dev->mutex);
+		if (file->f_flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+		if (msleep_interruptible(20) && signal_pending(current))
+			return -EINTR;
+		if (mutex_lock_interruptible(&dev->mutex))
+			return -ERESTARTSYS;
+		goto retry;
+	}
+
+	/* abs(dev->radio_rx_sig_qual) <= 200, map that to a 0-50% range */
+	perc = abs(dev->radio_rx_sig_qual) / 4;
+
+	for (i = 0; i < size && blk > dev->radio_rx_rds_last_block;
+			dev->radio_rx_rds_last_block++) {
+		unsigned data_blk = dev->radio_rx_rds_last_block % VIVID_RDS_GEN_BLOCKS;
+		struct v4l2_rds_data rds = data[data_blk];
+
+		if (data_blk == 0 && dev->radio_rds_loop)
+			vivid_radio_rds_init(dev);
+		if (perc && prandom_u32_max(100) < perc) {
+			switch (prandom_u32_max(4)) {
+			case 0:
+				rds.block |= V4L2_RDS_BLOCK_CORRECTED;
+				break;
+			case 1:
+				rds.block |= V4L2_RDS_BLOCK_INVALID;
+				break;
+			case 2:
+				rds.block |= V4L2_RDS_BLOCK_ERROR;
+				rds.lsb = prandom_u32_max(256);
+				rds.msb = prandom_u32_max(256);
+				break;
+			case 3: /* Skip block altogether */
+				if (i)
+					continue;
+				/*
+				 * Must make sure at least one block is
+				 * returned, otherwise the application
+				 * might think that end-of-file occurred.
+				 */
+				break;
+			}
+		}
+		if (copy_to_user(buf + i, &rds, sizeof(rds))) {
+			i = -EFAULT;
+			break;
+		}
+		i += sizeof(rds);
+	}
+	mutex_unlock(&dev->mutex);
+	return i;
+}
+
+unsigned int vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait)
+{
+	return POLLIN | POLLRDNORM | v4l2_ctrl_poll(file, wait);
+}
+
+int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band)
+{
+	if (band->tuner != 0)
+		return -EINVAL;
+
+	if (band->index >= TOT_BANDS)
+		return -EINVAL;
+
+	*band = vivid_radio_bands[band->index];
+	return 0;
+}
+
+int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	unsigned low, high;
+	unsigned freq;
+	unsigned spacing;
+	unsigned band;
+
+	if (a->tuner)
+		return -EINVAL;
+	if (a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_BOUNDED)
+		return -EINVAL;
+
+	if (!a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_WRAP)
+		return -EINVAL;
+	if (!a->rangelow ^ !a->rangehigh)
+		return -EINVAL;
+
+	if (file->f_flags & O_NONBLOCK)
+		return -EWOULDBLOCK;
+
+	if (a->rangelow) {
+		for (band = 0; band < TOT_BANDS; band++)
+			if (a->rangelow >= vivid_radio_bands[band].rangelow &&
+			    a->rangehigh <= vivid_radio_bands[band].rangehigh)
+				break;
+		if (band == TOT_BANDS)
+			return -EINVAL;
+		if (!dev->radio_rx_hw_seek_prog_lim &&
+		    (a->rangelow != vivid_radio_bands[band].rangelow ||
+		     a->rangehigh != vivid_radio_bands[band].rangehigh))
+			return -EINVAL;
+		low = a->rangelow;
+		high = a->rangehigh;
+	} else {
+		for (band = 0; band < TOT_BANDS; band++)
+			if (dev->radio_rx_freq >= vivid_radio_bands[band].rangelow &&
+			    dev->radio_rx_freq <= vivid_radio_bands[band].rangehigh)
+				break;
+		low = vivid_radio_bands[band].rangelow;
+		high = vivid_radio_bands[band].rangehigh;
+	}
+	spacing = band == BAND_AM ? 1600 : 16000;
+	freq = clamp(dev->radio_rx_freq, low, high);
+
+	if (a->seek_upward) {
+		freq = spacing * (freq / spacing) + spacing;
+		if (freq > high) {
+			if (!a->wrap_around)
+				return -ENODATA;
+			freq = spacing * (low / spacing) + spacing;
+			if (freq >= dev->radio_rx_freq)
+				return -ENODATA;
+		}
+	} else {
+		freq = spacing * ((freq + spacing - 1) / spacing) - spacing;
+		if (freq < low) {
+			if (!a->wrap_around)
+				return -ENODATA;
+			freq = spacing * ((high + spacing - 1) / spacing) - spacing;
+			if (freq <= dev->radio_rx_freq)
+				return -ENODATA;
+		}
+	}
+	return 0;
+}
+
+int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	int delta = 800;
+	int sig_qual;
+
+	if (vt->index > 0)
+		return -EINVAL;
+
+	strlcpy(vt->name, "AM/FM/SW Receiver", sizeof(vt->name));
+	vt->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+			 V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS |
+			 (dev->radio_rx_rds_controls ?
+				V4L2_TUNER_CAP_RDS_CONTROLS :
+				V4L2_TUNER_CAP_RDS_BLOCK_IO) |
+			 (dev->radio_rx_hw_seek_prog_lim ?
+				V4L2_TUNER_CAP_HWSEEK_PROG_LIM : 0);
+	switch (dev->radio_rx_hw_seek_mode) {
+	case VIVID_HW_SEEK_BOUNDED:
+		vt->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED;
+		break;
+	case VIVID_HW_SEEK_WRAP:
+		vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP;
+		break;
+	case VIVID_HW_SEEK_BOTH:
+		vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP |
+				  V4L2_TUNER_CAP_HWSEEK_BOUNDED;
+		break;
+	}
+	vt->rangelow = AM_FREQ_RANGE_LOW;
+	vt->rangehigh = FM_FREQ_RANGE_HIGH;
+	sig_qual = dev->radio_rx_sig_qual;
+	vt->signal = abs(sig_qual) > delta ? 0 :
+		     0xffff - (abs(sig_qual) * 0xffff) / delta;
+	vt->afc = sig_qual > delta ? 0 : sig_qual;
+	if (abs(sig_qual) > delta)
+		vt->rxsubchans = 0;
+	else if (dev->radio_rx_freq < FM_FREQ_RANGE_LOW || vt->signal < 0x8000)
+		vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+	else if (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_STEREO))
+		vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+	else
+		vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+	if (dev->radio_rx_rds_enabled &&
+	    (!dev->radio_rds_loop || (dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) &&
+	    dev->radio_rx_freq >= FM_FREQ_RANGE_LOW && vt->signal >= 0xc000)
+		vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
+	if (dev->radio_rx_rds_controls)
+		vivid_radio_rds_init(dev);
+	vt->audmode = dev->radio_rx_audmode;
+	return 0;
+}
+
+int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (vt->index)
+		return -EINVAL;
+	dev->radio_rx_audmode = vt->audmode >= V4L2_TUNER_MODE_STEREO;
+	return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-radio-rx.h b/drivers/media/platform/vivid/vivid-radio-rx.h
new file mode 100644
index 0000000..1077d8f
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-radio-rx.h
@@ -0,0 +1,31 @@
+/*
+ * vivid-radio-rx.h - radio receiver support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_RADIO_RX_H_
+#define _VIVID_RADIO_RX_H_
+
+ssize_t vivid_radio_rx_read(struct file *, char __user *, size_t, loff_t *);
+unsigned int vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait);
+
+int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band);
+int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a);
+int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt);
+int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.c b/drivers/media/platform/vivid/vivid-radio-tx.c
new file mode 100644
index 0000000..8c59d4f
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-radio-tx.c
@@ -0,0 +1,141 @@
+/*
+ * vivid-radio-tx.c - radio transmitter support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-radio-common.h"
+#include "vivid-radio-tx.h"
+
+ssize_t vivid_radio_tx_write(struct file *file, const char __user *buf,
+			  size_t size, loff_t *offset)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_rds_data *data = dev->rds_gen.data;
+	struct timespec ts;
+	unsigned blk;
+	int i;
+
+	if (dev->radio_tx_rds_controls)
+		return -EINVAL;
+
+	if (size < sizeof(*data))
+		return -EINVAL;
+	size = sizeof(*data) * (size / sizeof(*data));
+
+	if (mutex_lock_interruptible(&dev->mutex))
+		return -ERESTARTSYS;
+	if (dev->radio_tx_rds_owner &&
+	    file->private_data != dev->radio_tx_rds_owner) {
+		mutex_unlock(&dev->mutex);
+		return -EBUSY;
+	}
+	dev->radio_tx_rds_owner = file->private_data;
+
+retry:
+	ktime_get_ts(&ts);
+	ts = timespec_sub(ts, dev->radio_rds_init_ts);
+	blk = ts.tv_sec * 100 + ts.tv_nsec / 10000000;
+	blk = (blk * VIVID_RDS_GEN_BLOCKS) / 500;
+	if (blk - VIVID_RDS_GEN_BLOCKS >= dev->radio_tx_rds_last_block)
+		dev->radio_tx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1;
+
+	/*
+	 * No data is available if there hasn't been time to get new data,
+	 * or if the RDS receiver has been disabled, or if we use the data
+	 * from the RDS transmitter and that RDS transmitter has been disabled,
+	 * or if the signal quality is too weak.
+	 */
+	if (blk == dev->radio_tx_rds_last_block ||
+	    !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) {
+		mutex_unlock(&dev->mutex);
+		if (file->f_flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+		if (msleep_interruptible(20) && signal_pending(current))
+			return -EINTR;
+		if (mutex_lock_interruptible(&dev->mutex))
+			return -ERESTARTSYS;
+		goto retry;
+	}
+
+	for (i = 0; i < size && blk > dev->radio_tx_rds_last_block;
+			dev->radio_tx_rds_last_block++) {
+		unsigned data_blk = dev->radio_tx_rds_last_block % VIVID_RDS_GEN_BLOCKS;
+		struct v4l2_rds_data rds;
+
+		if (copy_from_user(&rds, buf + i, sizeof(rds))) {
+			i = -EFAULT;
+			break;
+		}
+		i += sizeof(rds);
+		if (!dev->radio_rds_loop)
+			continue;
+		if ((rds.block & V4L2_RDS_BLOCK_MSK) == V4L2_RDS_BLOCK_INVALID ||
+		    (rds.block & V4L2_RDS_BLOCK_ERROR))
+			continue;
+		rds.block &= V4L2_RDS_BLOCK_MSK;
+		data[data_blk] = rds;
+	}
+	mutex_unlock(&dev->mutex);
+	return i;
+}
+
+unsigned int vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait)
+{
+	return POLLOUT | POLLWRNORM | v4l2_ctrl_poll(file, wait);
+}
+
+int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (a->index > 0)
+		return -EINVAL;
+
+	strlcpy(a->name, "AM/FM/SW Transmitter", sizeof(a->name));
+	a->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+			V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS |
+			(dev->radio_tx_rds_controls ?
+				V4L2_TUNER_CAP_RDS_CONTROLS :
+				V4L2_TUNER_CAP_RDS_BLOCK_IO);
+	a->rangelow = AM_FREQ_RANGE_LOW;
+	a->rangehigh = FM_FREQ_RANGE_HIGH;
+	a->txsubchans = dev->radio_tx_subchans;
+	return 0;
+}
+
+int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (a->index)
+		return -EINVAL;
+	if (a->txsubchans & ~0x13)
+		return -EINVAL;
+	dev->radio_tx_subchans = a->txsubchans;
+	return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.h b/drivers/media/platform/vivid/vivid-radio-tx.h
new file mode 100644
index 0000000..7f8ff75
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-radio-tx.h
@@ -0,0 +1,29 @@
+/*
+ * vivid-radio-tx.h - radio transmitter support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_RADIO_TX_H_
+#define _VIVID_RADIO_TX_H_
+
+ssize_t vivid_radio_tx_write(struct file *, const char __user *, size_t, loff_t *);
+unsigned int vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait);
+
+int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a);
+int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c
new file mode 100644
index 0000000..c382343
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-rds-gen.c
@@ -0,0 +1,166 @@
+/*
+ * vivid-rds-gen.c - rds (radio data system) generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+
+#include "vivid-rds-gen.h"
+
+static u8 vivid_get_di(const struct vivid_rds_gen *rds, unsigned grp)
+{
+	switch (grp) {
+	case 0:
+		return (rds->dyn_pty << 2) | (grp & 3);
+	case 1:
+		return (rds->compressed << 2) | (grp & 3);
+	case 2:
+		return (rds->art_head << 2) | (grp & 3);
+	case 3:
+		return (rds->mono_stereo << 2) | (grp & 3);
+	}
+	return 0;
+}
+
+/*
+ * This RDS generator creates 57 RDS groups (one group == four RDS blocks).
+ * Groups 0-3, 22-25 and 44-47 (spaced 22 groups apart) are filled with a
+ * standard 0B group containing the PI code and PS name.
+ *
+ * Groups 4-19 and 26-41 use group 2A for the radio text.
+ *
+ * Group 56 contains the time (group 4A).
+ *
+ * All remaining groups use a filler group 15B block that just repeats
+ * the PI and PTY codes.
+ */
+void vivid_rds_generate(struct vivid_rds_gen *rds)
+{
+	struct v4l2_rds_data *data = rds->data;
+	unsigned grp;
+	struct tm tm;
+	unsigned date;
+	unsigned time;
+	int l;
+
+	for (grp = 0; grp < VIVID_RDS_GEN_GROUPS; grp++, data += VIVID_RDS_GEN_BLKS_PER_GRP) {
+		data[0].lsb = rds->picode & 0xff;
+		data[0].msb = rds->picode >> 8;
+		data[0].block = V4L2_RDS_BLOCK_A | (V4L2_RDS_BLOCK_A << 3);
+		data[1].lsb = rds->pty << 5;
+		data[1].msb = (rds->pty >> 3) | (rds->tp << 2);
+		data[1].block = V4L2_RDS_BLOCK_B | (V4L2_RDS_BLOCK_B << 3);
+		data[3].block = V4L2_RDS_BLOCK_D | (V4L2_RDS_BLOCK_D << 3);
+
+		switch (grp) {
+		case 0 ... 3:
+		case 22 ... 25:
+		case 44 ... 47: /* Group 0B */
+			data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
+			data[1].lsb |= vivid_get_di(rds, grp % 22);
+			data[1].msb |= 1 << 3;
+			data[2].lsb = rds->picode & 0xff;
+			data[2].msb = rds->picode >> 8;
+			data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
+			data[3].lsb = rds->psname[2 * (grp % 22) + 1];
+			data[3].msb = rds->psname[2 * (grp % 22)];
+			break;
+		case 4 ... 19:
+		case 26 ... 41: /* Group 2A */
+			data[1].lsb |= (grp - 4) % 22;
+			data[1].msb |= 4 << 3;
+			data[2].msb = rds->radiotext[4 * ((grp - 4) % 22)];
+			data[2].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 1];
+			data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
+			data[3].msb = rds->radiotext[4 * ((grp - 4) % 22) + 2];
+			data[3].lsb = rds->radiotext[4 * ((grp - 4) % 22) + 3];
+			break;
+		case 56:
+			/*
+			 * Group 4A
+			 *
+			 * Uses the algorithm from Annex G of the RDS standard
+			 * EN 50067:1998 to convert a UTC date to an RDS Modified
+			 * Julian Day.
+			 */
+			time_to_tm(get_seconds(), 0, &tm);
+			l = tm.tm_mon <= 1;
+			date = 14956 + tm.tm_mday + ((tm.tm_year - l) * 1461) / 4 +
+				((tm.tm_mon + 2 + l * 12) * 306001) / 10000;
+			time = (tm.tm_hour << 12) |
+			       (tm.tm_min << 6) |
+			       (sys_tz.tz_minuteswest >= 0 ? 0x20 : 0) |
+			       (abs(sys_tz.tz_minuteswest) / 30);
+			data[1].lsb &= ~3;
+			data[1].lsb |= date >> 15;
+			data[1].msb |= 8 << 3;
+			data[2].lsb = (date << 1) & 0xfe;
+			data[2].lsb |= (time >> 16) & 1;
+			data[2].msb = (date >> 7) & 0xff;
+			data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
+			data[3].lsb = time & 0xff;
+			data[3].msb = (time >> 8) & 0xff;
+			break;
+		default: /* Group 15B */
+			data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
+			data[1].lsb |= vivid_get_di(rds, grp % 22);
+			data[1].msb |= 0x1f << 3;
+			data[2].lsb = rds->picode & 0xff;
+			data[2].msb = rds->picode >> 8;
+			data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
+			data[3].lsb = rds->pty << 5;
+			data[3].lsb |= (rds->ta << 4) | (rds->ms << 3);
+			data[3].lsb |= vivid_get_di(rds, grp % 22);
+			data[3].msb |= rds->pty >> 3;
+			data[3].msb |= 0x1f << 3;
+			break;
+		}
+	}
+}
+
+void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq,
+			  bool alt)
+{
+	/* Alternate PTY between Info and Weather */
+	if (rds->use_rbds) {
+		rds->picode = 0x2e75; /* 'KLNX' call sign */
+		rds->pty = alt ? 29 : 2;
+	} else {
+		rds->picode = 0x8088;
+		rds->pty = alt ? 16 : 3;
+	}
+	rds->mono_stereo = true;
+	rds->art_head = false;
+	rds->compressed = false;
+	rds->dyn_pty = false;
+	rds->tp = true;
+	rds->ta = alt;
+	rds->ms = true;
+	snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d",
+		 freq / 16, ((freq & 0xf) * 10) / 16);
+	if (alt)
+		strlcpy(rds->radiotext,
+			" The Radio Data System can switch between different Radio Texts ",
+			sizeof(rds->radiotext));
+	else
+		strlcpy(rds->radiotext,
+			"An example of Radio Text as transmitted by the Radio Data System",
+			sizeof(rds->radiotext));
+}
diff --git a/drivers/media/platform/vivid/vivid-rds-gen.h b/drivers/media/platform/vivid/vivid-rds-gen.h
new file mode 100644
index 0000000..eff4bf5
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-rds-gen.h
@@ -0,0 +1,53 @@
+/*
+ * vivid-rds-gen.h - rds (radio data system) generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_RDS_GEN_H_
+#define _VIVID_RDS_GEN_H_
+
+/*
+ * It takes almost exactly 5 seconds to transmit 57 RDS groups.
+ * Each group has 4 blocks and each block has a payload of 16 bits + a
+ * block identification. The driver will generate the contents of these
+ * 57 groups only when necessary and it will just be played continuously.
+ */
+#define VIVID_RDS_GEN_GROUPS 57
+#define VIVID_RDS_GEN_BLKS_PER_GRP 4
+#define VIVID_RDS_GEN_BLOCKS (VIVID_RDS_GEN_BLKS_PER_GRP * VIVID_RDS_GEN_GROUPS)
+
+struct vivid_rds_gen {
+	struct v4l2_rds_data	data[VIVID_RDS_GEN_BLOCKS];
+	bool			use_rbds;
+	u16			picode;
+	u8			pty;
+	bool			mono_stereo;
+	bool			art_head;
+	bool			compressed;
+	bool			dyn_pty;
+	bool			ta;
+	bool			tp;
+	bool			ms;
+	char			psname[8 + 1];
+	char			radiotext[64 + 1];
+};
+
+void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq,
+		    bool use_alternate);
+void vivid_rds_generate(struct vivid_rds_gen *rds);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c
new file mode 100644
index 0000000..8c5d661
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.c
@@ -0,0 +1,499 @@
+/*
+ * vivid-sdr-cap.c - software defined radio support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-sdr-cap.h"
+
+static const struct v4l2_frequency_band bands_adc[] = {
+	{
+		.tuner = 0,
+		.type = V4L2_TUNER_ADC,
+		.index = 0,
+		.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+		.rangelow   =  300000,
+		.rangehigh  =  300000,
+	},
+	{
+		.tuner = 0,
+		.type = V4L2_TUNER_ADC,
+		.index = 1,
+		.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+		.rangelow   =  900001,
+		.rangehigh  = 2800000,
+	},
+	{
+		.tuner = 0,
+		.type = V4L2_TUNER_ADC,
+		.index = 2,
+		.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+		.rangelow   = 3200000,
+		.rangehigh  = 3200000,
+	},
+};
+
+/* ADC band midpoints */
+#define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2)
+#define BAND_ADC_1 ((bands_adc[1].rangehigh + bands_adc[2].rangelow) / 2)
+
+static const struct v4l2_frequency_band bands_fm[] = {
+	{
+		.tuner = 1,
+		.type = V4L2_TUNER_RF,
+		.index = 0,
+		.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+		.rangelow   =    50000000,
+		.rangehigh  =  2000000000,
+	},
+};
+
+static void vivid_thread_sdr_cap_tick(struct vivid_dev *dev)
+{
+	struct vivid_buffer *sdr_cap_buf = NULL;
+
+	dprintk(dev, 1, "SDR Capture Thread Tick\n");
+
+	/* Drop a certain percentage of buffers. */
+	if (dev->perc_dropped_buffers &&
+	    prandom_u32_max(100) < dev->perc_dropped_buffers)
+		return;
+
+	spin_lock(&dev->slock);
+	if (!list_empty(&dev->sdr_cap_active)) {
+		sdr_cap_buf = list_entry(dev->sdr_cap_active.next,
+					 struct vivid_buffer, list);
+		list_del(&sdr_cap_buf->list);
+	}
+	spin_unlock(&dev->slock);
+
+	if (sdr_cap_buf) {
+		sdr_cap_buf->vb.v4l2_buf.sequence = dev->sdr_cap_seq_count;
+		vivid_sdr_cap_process(dev, sdr_cap_buf);
+		v4l2_get_timestamp(&sdr_cap_buf->vb.v4l2_buf.timestamp);
+		sdr_cap_buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+		vb2_buffer_done(&sdr_cap_buf->vb, dev->dqbuf_error ?
+				VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+		dev->dqbuf_error = false;
+	}
+}
+
+static int vivid_thread_sdr_cap(void *data)
+{
+	struct vivid_dev *dev = data;
+	u64 samples_since_start;
+	u64 buffers_since_start;
+	u64 next_jiffies_since_start;
+	unsigned long jiffies_since_start;
+	unsigned long cur_jiffies;
+	unsigned wait_jiffies;
+
+	dprintk(dev, 1, "SDR Capture Thread Start\n");
+
+	set_freezable();
+
+	/* Resets frame counters */
+	dev->sdr_cap_seq_offset = 0;
+	if (dev->seq_wrap)
+		dev->sdr_cap_seq_offset = 0xffffff80U;
+	dev->jiffies_sdr_cap = jiffies;
+	dev->sdr_cap_seq_resync = false;
+
+	for (;;) {
+		try_to_freeze();
+		if (kthread_should_stop())
+			break;
+
+		mutex_lock(&dev->mutex);
+		cur_jiffies = jiffies;
+		if (dev->sdr_cap_seq_resync) {
+			dev->jiffies_sdr_cap = cur_jiffies;
+			dev->sdr_cap_seq_offset = dev->sdr_cap_seq_count + 1;
+			dev->sdr_cap_seq_count = 0;
+			dev->sdr_cap_seq_resync = false;
+		}
+		/* Calculate the number of jiffies since we started streaming */
+		jiffies_since_start = cur_jiffies - dev->jiffies_sdr_cap;
+		/* Get the number of buffers streamed since the start */
+		buffers_since_start = (u64)jiffies_since_start * dev->sdr_adc_freq +
+				      (HZ * SDR_CAP_SAMPLES_PER_BUF) / 2;
+		do_div(buffers_since_start, HZ * SDR_CAP_SAMPLES_PER_BUF);
+
+		/*
+		 * After more than 0xf0000000 (rounded down to a multiple of
+		 * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
+		 * jiffies have passed since we started streaming reset the
+		 * counters and keep track of the sequence offset.
+		 */
+		if (jiffies_since_start > JIFFIES_RESYNC) {
+			dev->jiffies_sdr_cap = cur_jiffies;
+			dev->sdr_cap_seq_offset = buffers_since_start;
+			buffers_since_start = 0;
+		}
+		dev->sdr_cap_seq_count = buffers_since_start + dev->sdr_cap_seq_offset;
+
+		vivid_thread_sdr_cap_tick(dev);
+		mutex_unlock(&dev->mutex);
+
+		/*
+		 * Calculate the number of samples streamed since we started,
+		 * not including the current buffer.
+		 */
+		samples_since_start = buffers_since_start * SDR_CAP_SAMPLES_PER_BUF;
+
+		/* And the number of jiffies since we started */
+		jiffies_since_start = jiffies - dev->jiffies_sdr_cap;
+
+		/* Increase by the number of samples in one buffer */
+		samples_since_start += SDR_CAP_SAMPLES_PER_BUF;
+		/*
+		 * Calculate when that next buffer is supposed to start
+		 * in jiffies since we started streaming.
+		 */
+		next_jiffies_since_start = samples_since_start * HZ +
+					   dev->sdr_adc_freq / 2;
+		do_div(next_jiffies_since_start, dev->sdr_adc_freq);
+		/* If it is in the past, then just schedule asap */
+		if (next_jiffies_since_start < jiffies_since_start)
+			next_jiffies_since_start = jiffies_since_start;
+
+		wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+		schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
+	}
+	dprintk(dev, 1, "SDR Capture Thread End\n");
+	return 0;
+}
+
+static int sdr_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+		       unsigned *nbuffers, unsigned *nplanes,
+		       unsigned sizes[], void *alloc_ctxs[])
+{
+	/* 2 = max 16-bit sample returned */
+	sizes[0] = SDR_CAP_SAMPLES_PER_BUF * 2;
+	*nplanes = 1;
+	return 0;
+}
+
+static int sdr_cap_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	unsigned size = SDR_CAP_SAMPLES_PER_BUF * 2;
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	if (dev->buf_prepare_error) {
+		/*
+		 * Error injection: test what happens if buf_prepare() returns
+		 * an error.
+		 */
+		dev->buf_prepare_error = false;
+		return -EINVAL;
+	}
+	if (vb2_plane_size(vb, 0) < size) {
+		dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+				__func__, vb2_plane_size(vb, 0), size);
+		return -EINVAL;
+	}
+	vb2_set_plane_payload(vb, 0, size);
+
+	return 0;
+}
+
+static void sdr_cap_buf_queue(struct vb2_buffer *vb)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	spin_lock(&dev->slock);
+	list_add_tail(&buf->list, &dev->sdr_cap_active);
+	spin_unlock(&dev->slock);
+}
+
+static int sdr_cap_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+	int err = 0;
+
+	dprintk(dev, 1, "%s\n", __func__);
+	dev->sdr_cap_seq_count = 0;
+	if (dev->start_streaming_error) {
+		dev->start_streaming_error = false;
+		err = -EINVAL;
+	} else if (dev->kthread_sdr_cap == NULL) {
+		dev->kthread_sdr_cap = kthread_run(vivid_thread_sdr_cap, dev,
+				"%s-sdr-cap", dev->v4l2_dev.name);
+
+		if (IS_ERR(dev->kthread_sdr_cap)) {
+			v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+			err = PTR_ERR(dev->kthread_sdr_cap);
+			dev->kthread_sdr_cap = NULL;
+		}
+	}
+	if (err) {
+		struct vivid_buffer *buf, *tmp;
+
+		list_for_each_entry_safe(buf, tmp, &dev->sdr_cap_active, list) {
+			list_del(&buf->list);
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+		}
+	}
+	return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void sdr_cap_stop_streaming(struct vb2_queue *vq)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+	if (dev->kthread_sdr_cap == NULL)
+		return;
+
+	while (!list_empty(&dev->sdr_cap_active)) {
+		struct vivid_buffer *buf;
+
+		buf = list_entry(dev->sdr_cap_active.next, struct vivid_buffer, list);
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+
+	/* shutdown control thread */
+	mutex_unlock(&dev->mutex);
+	kthread_stop(dev->kthread_sdr_cap);
+	dev->kthread_sdr_cap = NULL;
+	mutex_lock(&dev->mutex);
+}
+
+const struct vb2_ops vivid_sdr_cap_qops = {
+	.queue_setup		= sdr_cap_queue_setup,
+	.buf_prepare		= sdr_cap_buf_prepare,
+	.buf_queue		= sdr_cap_buf_queue,
+	.start_streaming	= sdr_cap_start_streaming,
+	.stop_streaming		= sdr_cap_stop_streaming,
+	.wait_prepare		= vivid_unlock,
+	.wait_finish		= vivid_lock,
+};
+
+int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band)
+{
+	switch (band->tuner) {
+	case 0:
+		if (band->index >= ARRAY_SIZE(bands_adc))
+			return -EINVAL;
+		*band = bands_adc[band->index];
+		return 0;
+	case 1:
+		if (band->index >= ARRAY_SIZE(bands_fm))
+			return -EINVAL;
+		*band = bands_fm[band->index];
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	switch (vf->tuner) {
+	case 0:
+		vf->frequency = dev->sdr_adc_freq;
+		vf->type = V4L2_TUNER_ADC;
+		return 0;
+	case 1:
+		vf->frequency = dev->sdr_fm_freq;
+		vf->type = V4L2_TUNER_RF;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	unsigned freq = vf->frequency;
+	unsigned band;
+
+	switch (vf->tuner) {
+	case 0:
+		if (vf->type != V4L2_TUNER_ADC)
+			return -EINVAL;
+		if (freq < BAND_ADC_0)
+			band = 0;
+		else if (freq < BAND_ADC_1)
+			band = 1;
+		else
+			band = 2;
+
+		freq = clamp_t(unsigned, freq,
+				bands_adc[band].rangelow,
+				bands_adc[band].rangehigh);
+
+		if (vb2_is_streaming(&dev->vb_sdr_cap_q) &&
+		    freq != dev->sdr_adc_freq) {
+			/* resync the thread's timings */
+			dev->sdr_cap_seq_resync = true;
+		}
+		dev->sdr_adc_freq = freq;
+		return 0;
+	case 1:
+		if (vf->type != V4L2_TUNER_RF)
+			return -EINVAL;
+		dev->sdr_fm_freq = clamp_t(unsigned, freq,
+				bands_fm[0].rangelow,
+				bands_fm[0].rangehigh);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	switch (vt->index) {
+	case 0:
+		strlcpy(vt->name, "ADC", sizeof(vt->name));
+		vt->type = V4L2_TUNER_ADC;
+		vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+		vt->rangelow = bands_adc[0].rangelow;
+		vt->rangehigh = bands_adc[2].rangehigh;
+		return 0;
+	case 1:
+		strlcpy(vt->name, "RF", sizeof(vt->name));
+		vt->type = V4L2_TUNER_RF;
+		vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+		vt->rangelow = bands_fm[0].rangelow;
+		vt->rangehigh = bands_fm[0].rangehigh;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
+{
+	if (vt->index > 1)
+		return -EINVAL;
+	return 0;
+}
+
+int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+	if (f->index)
+		return -EINVAL;
+	f->pixelformat = V4L2_SDR_FMT_CU8;
+	strlcpy(f->description, "IQ U8", sizeof(f->description));
+	return 0;
+}
+
+int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+	f->fmt.sdr.pixelformat = V4L2_SDR_FMT_CU8;
+	f->fmt.sdr.buffersize = SDR_CAP_SAMPLES_PER_BUF * 2;
+	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+	return 0;
+}
+
+#define FIXP_FRAC    (1 << 15)
+#define FIXP_PI      ((int)(FIXP_FRAC * 3.141592653589))
+
+/* cos() from cx88 driver: cx88-dsp.c */
+static s32 fixp_cos(unsigned int x)
+{
+	u32 t2, t4, t6, t8;
+	u16 period = x / FIXP_PI;
+
+	if (period % 2)
+		return -fixp_cos(x - FIXP_PI);
+	x = x % FIXP_PI;
+	if (x > FIXP_PI/2)
+		return -fixp_cos(FIXP_PI/2 - (x % (FIXP_PI/2)));
+	/* Now x is between 0 and FIXP_PI/2.
+	 * To calculate cos(x) we use it's Taylor polinom. */
+	t2 = x*x/FIXP_FRAC/2;
+	t4 = t2*x/FIXP_FRAC*x/FIXP_FRAC/3/4;
+	t6 = t4*x/FIXP_FRAC*x/FIXP_FRAC/5/6;
+	t8 = t6*x/FIXP_FRAC*x/FIXP_FRAC/7/8;
+	return FIXP_FRAC-t2+t4-t6+t8;
+}
+
+static inline s32 fixp_sin(unsigned int x)
+{
+	return -fixp_cos(x + (FIXP_PI / 2));
+}
+
+void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+	u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+	unsigned long i;
+	unsigned long plane_size = vb2_plane_size(&buf->vb, 0);
+	int fixp_src_phase_step, fixp_i, fixp_q;
+
+	/*
+	 * TODO: Generated beep tone goes very crackly when sample rate is
+	 * increased to ~1Msps or more. That is because of huge rounding error
+	 * of phase angle caused by used cosine implementation.
+	 */
+
+	/* calculate phase step */
+	#define BEEP_FREQ 1000 /* 1kHz beep */
+	fixp_src_phase_step = DIV_ROUND_CLOSEST(2 * FIXP_PI * BEEP_FREQ,
+			dev->sdr_adc_freq);
+
+	for (i = 0; i < plane_size; i += 2) {
+		dev->sdr_fixp_mod_phase += fixp_cos(dev->sdr_fixp_src_phase);
+		dev->sdr_fixp_src_phase += fixp_src_phase_step;
+
+		/*
+		 * Transfer phases to [0 / 2xPI] in order to avoid variable
+		 * overflow and make it suitable for cosine implementation
+		 * used, which does not support negative angles.
+		 */
+		while (dev->sdr_fixp_mod_phase < (0 * FIXP_PI))
+			dev->sdr_fixp_mod_phase += (2 * FIXP_PI);
+		while (dev->sdr_fixp_mod_phase > (2 * FIXP_PI))
+			dev->sdr_fixp_mod_phase -= (2 * FIXP_PI);
+
+		while (dev->sdr_fixp_src_phase > (2 * FIXP_PI))
+			dev->sdr_fixp_src_phase -= (2 * FIXP_PI);
+
+		fixp_i = fixp_cos(dev->sdr_fixp_mod_phase);
+		fixp_q = fixp_sin(dev->sdr_fixp_mod_phase);
+
+		/* convert 'fixp float' to u8 */
+		/* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */
+		fixp_i = fixp_i * 1275 + FIXP_FRAC * 1275;
+		fixp_q = fixp_q * 1275 + FIXP_FRAC * 1275;
+		*vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10);
+		*vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10);
+	}
+}
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.h b/drivers/media/platform/vivid/vivid-sdr-cap.h
new file mode 100644
index 0000000..79c1890
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.h
@@ -0,0 +1,34 @@
+/*
+ * vivid-sdr-cap.h - software defined radio support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_SDR_CAP_H_
+#define _VIVID_SDR_CAP_H_
+
+int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band);
+int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf);
+int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt);
+int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt);
+int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f);
+int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f);
+void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+
+extern const struct vb2_ops vivid_sdr_cap_qops;
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.c b/drivers/media/platform/vivid/vivid-tpg-colors.c
new file mode 100644
index 0000000..2adddc0
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-tpg-colors.c
@@ -0,0 +1,310 @@
+/*
+ * vivid-color.c - A table that converts colors to various colorspaces
+ *
+ * The test pattern generator uses the tpg_colors for its test patterns.
+ * For testing colorspaces the first 8 colors of that table need to be
+ * converted to their equivalent in the target colorspace.
+ *
+ * The tpg_csc_colors[] table is the result of that conversion and since
+ * it is precalculated the colorspace conversion is just a simple table
+ * lookup.
+ *
+ * This source also contains the code used to generate the tpg_csc_colors
+ * table. Run the following command to compile it:
+ *
+ *	gcc vivid-colors.c -DCOMPILE_APP -o gen-colors -lm
+ *
+ * and run the utility.
+ *
+ * Note that the converted colors are in the range 0x000-0xff0 (so times 16)
+ * in order to preserve precision.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/videodev2.h>
+
+#include "vivid-tpg-colors.h"
+
+/* sRGB colors with range [0-255] */
+const struct color tpg_colors[TPG_COLOR_MAX] = {
+	/*
+	 * Colors to test colorspace conversion: converting these colors
+	 * to other colorspaces will never lead to out-of-gamut colors.
+	 */
+	{ 191, 191, 191 }, /* TPG_COLOR_CSC_WHITE */
+	{ 191, 191,  50 }, /* TPG_COLOR_CSC_YELLOW */
+	{  50, 191, 191 }, /* TPG_COLOR_CSC_CYAN */
+	{  50, 191,  50 }, /* TPG_COLOR_CSC_GREEN */
+	{ 191,  50, 191 }, /* TPG_COLOR_CSC_MAGENTA */
+	{ 191,  50,  50 }, /* TPG_COLOR_CSC_RED */
+	{  50,  50, 191 }, /* TPG_COLOR_CSC_BLUE */
+	{  50,  50,  50 }, /* TPG_COLOR_CSC_BLACK */
+
+	/* 75% colors */
+	{ 191, 191,   0 }, /* TPG_COLOR_75_YELLOW */
+	{   0, 191, 191 }, /* TPG_COLOR_75_CYAN */
+	{   0, 191,   0 }, /* TPG_COLOR_75_GREEN */
+	{ 191,   0, 191 }, /* TPG_COLOR_75_MAGENTA */
+	{ 191,   0,   0 }, /* TPG_COLOR_75_RED */
+	{   0,   0, 191 }, /* TPG_COLOR_75_BLUE */
+
+	/* 100% colors */
+	{ 255, 255, 255 }, /* TPG_COLOR_100_WHITE */
+	{ 255, 255,   0 }, /* TPG_COLOR_100_YELLOW */
+	{   0, 255, 255 }, /* TPG_COLOR_100_CYAN */
+	{   0, 255,   0 }, /* TPG_COLOR_100_GREEN */
+	{ 255,   0, 255 }, /* TPG_COLOR_100_MAGENTA */
+	{ 255,   0,   0 }, /* TPG_COLOR_100_RED */
+	{   0,   0, 255 }, /* TPG_COLOR_100_BLUE */
+	{   0,   0,   0 }, /* TPG_COLOR_100_BLACK */
+
+	{   0,   0,   0 }, /* TPG_COLOR_RANDOM placeholder */
+};
+
+#ifndef COMPILE_APP
+
+/* Generated table */
+const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1] = {
+	[V4L2_COLORSPACE_SMPTE170M][0] = { 2953, 2939, 2939 },
+	[V4L2_COLORSPACE_SMPTE170M][1] = { 2954, 2963, 585 },
+	[V4L2_COLORSPACE_SMPTE170M][2] = { 84, 2967, 2937 },
+	[V4L2_COLORSPACE_SMPTE170M][3] = { 93, 2990, 575 },
+	[V4L2_COLORSPACE_SMPTE170M][4] = { 3030, 259, 2933 },
+	[V4L2_COLORSPACE_SMPTE170M][5] = { 3031, 406, 557 },
+	[V4L2_COLORSPACE_SMPTE170M][6] = { 544, 428, 2931 },
+	[V4L2_COLORSPACE_SMPTE170M][7] = { 551, 547, 547 },
+	[V4L2_COLORSPACE_SMPTE240M][0] = { 2926, 2926, 2926 },
+	[V4L2_COLORSPACE_SMPTE240M][1] = { 2926, 2926, 857 },
+	[V4L2_COLORSPACE_SMPTE240M][2] = { 1594, 2901, 2901 },
+	[V4L2_COLORSPACE_SMPTE240M][3] = { 1594, 2901, 774 },
+	[V4L2_COLORSPACE_SMPTE240M][4] = { 2484, 618, 2858 },
+	[V4L2_COLORSPACE_SMPTE240M][5] = { 2484, 618, 617 },
+	[V4L2_COLORSPACE_SMPTE240M][6] = { 507, 507, 2832 },
+	[V4L2_COLORSPACE_SMPTE240M][7] = { 507, 507, 507 },
+	[V4L2_COLORSPACE_REC709][0] = { 2939, 2939, 2939 },
+	[V4L2_COLORSPACE_REC709][1] = { 2939, 2939, 547 },
+	[V4L2_COLORSPACE_REC709][2] = { 547, 2939, 2939 },
+	[V4L2_COLORSPACE_REC709][3] = { 547, 2939, 547 },
+	[V4L2_COLORSPACE_REC709][4] = { 2939, 547, 2939 },
+	[V4L2_COLORSPACE_REC709][5] = { 2939, 547, 547 },
+	[V4L2_COLORSPACE_REC709][6] = { 547, 547, 2939 },
+	[V4L2_COLORSPACE_REC709][7] = { 547, 547, 547 },
+	[V4L2_COLORSPACE_470_SYSTEM_M][0] = { 2894, 2988, 2808 },
+	[V4L2_COLORSPACE_470_SYSTEM_M][1] = { 2847, 3070, 843 },
+	[V4L2_COLORSPACE_470_SYSTEM_M][2] = { 1656, 2962, 2783 },
+	[V4L2_COLORSPACE_470_SYSTEM_M][3] = { 1572, 3045, 763 },
+	[V4L2_COLORSPACE_470_SYSTEM_M][4] = { 2477, 229, 2743 },
+	[V4L2_COLORSPACE_470_SYSTEM_M][5] = { 2422, 672, 614 },
+	[V4L2_COLORSPACE_470_SYSTEM_M][6] = { 725, 63, 2718 },
+	[V4L2_COLORSPACE_470_SYSTEM_M][7] = { 534, 561, 509 },
+	[V4L2_COLORSPACE_470_SYSTEM_BG][0] = { 2939, 2939, 2939 },
+	[V4L2_COLORSPACE_470_SYSTEM_BG][1] = { 2939, 2939, 621 },
+	[V4L2_COLORSPACE_470_SYSTEM_BG][2] = { 786, 2939, 2939 },
+	[V4L2_COLORSPACE_470_SYSTEM_BG][3] = { 786, 2939, 621 },
+	[V4L2_COLORSPACE_470_SYSTEM_BG][4] = { 2879, 547, 2923 },
+	[V4L2_COLORSPACE_470_SYSTEM_BG][5] = { 2879, 547, 547 },
+	[V4L2_COLORSPACE_470_SYSTEM_BG][6] = { 547, 547, 2923 },
+	[V4L2_COLORSPACE_470_SYSTEM_BG][7] = { 547, 547, 547 },
+	[V4L2_COLORSPACE_SRGB][0] = { 3056, 3056, 3056 },
+	[V4L2_COLORSPACE_SRGB][1] = { 3056, 3056, 800 },
+	[V4L2_COLORSPACE_SRGB][2] = { 800, 3056, 3056 },
+	[V4L2_COLORSPACE_SRGB][3] = { 800, 3056, 800 },
+	[V4L2_COLORSPACE_SRGB][4] = { 3056, 800, 3056 },
+	[V4L2_COLORSPACE_SRGB][5] = { 3056, 800, 800 },
+	[V4L2_COLORSPACE_SRGB][6] = { 800, 800, 3056 },
+	[V4L2_COLORSPACE_SRGB][7] = { 800, 800, 800 },
+};
+
+#else
+
+/* This code generates the table above */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static const double rec709_to_ntsc1953[3][3] = {
+	{ 0.6698, 0.2678,  0.0323 },
+	{ 0.0185, 1.0742, -0.0603 },
+	{ 0.0162, 0.0432,  0.8551 }
+};
+
+static const double rec709_to_ebu[3][3] = {
+	{ 0.9578, 0.0422, 0      },
+	{ 0     , 1     , 0      },
+	{ 0     , 0.0118, 0.9882 }
+};
+
+static const double rec709_to_170m[3][3] = {
+	{  1.0654, -0.0554, -0.0010 },
+	{ -0.0196,  1.0364, -0.0167 },
+	{  0.0016,  0.0044,  0.9940 }
+};
+
+static const double rec709_to_240m[3][3] = {
+	{ 0.7151, 0.2849, 0      },
+	{ 0.0179, 0.9821, 0      },
+	{ 0.0177, 0.0472, 0.9350 }
+};
+
+
+static void mult_matrix(double *r, double *g, double *b, const double m[3][3])
+{
+	double ir, ig, ib;
+
+	ir = m[0][0] * (*r) + m[0][1] * (*g) + m[0][2] * (*b);
+	ig = m[1][0] * (*r) + m[1][1] * (*g) + m[1][2] * (*b);
+	ib = m[2][0] * (*r) + m[2][1] * (*g) + m[2][2] * (*b);
+	*r = ir;
+	*g = ig;
+	*b = ib;
+}
+
+static double transfer_srgb_to_rgb(double v)
+{
+	return (v <= 0.03928) ? v / 12.92 : pow((v + 0.055) / 1.055, 2.4);
+}
+
+static double transfer_rgb_to_smpte240m(double v)
+{
+	return (v <= 0.0228) ? v * 4.0 : 1.1115 * pow(v, 0.45) - 0.1115;
+}
+
+static double transfer_rgb_to_rec709(double v)
+{
+	return (v < 0.018) ? v * 4.5 : 1.099 * pow(v, 0.45) - 0.099;
+}
+
+static double transfer_srgb_to_rec709(double v)
+{
+	return transfer_rgb_to_rec709(transfer_srgb_to_rgb(v));
+}
+
+static void csc(enum v4l2_colorspace colorspace, double *r, double *g, double *b)
+{
+	/* Convert the primaries of Rec. 709 Linear RGB */
+	switch (colorspace) {
+	case V4L2_COLORSPACE_SMPTE240M:
+		*r = transfer_srgb_to_rgb(*r);
+		*g = transfer_srgb_to_rgb(*g);
+		*b = transfer_srgb_to_rgb(*b);
+		mult_matrix(r, g, b, rec709_to_240m);
+		break;
+	case V4L2_COLORSPACE_SMPTE170M:
+		*r = transfer_srgb_to_rgb(*r);
+		*g = transfer_srgb_to_rgb(*g);
+		*b = transfer_srgb_to_rgb(*b);
+		mult_matrix(r, g, b, rec709_to_170m);
+		break;
+	case V4L2_COLORSPACE_470_SYSTEM_BG:
+		*r = transfer_srgb_to_rgb(*r);
+		*g = transfer_srgb_to_rgb(*g);
+		*b = transfer_srgb_to_rgb(*b);
+		mult_matrix(r, g, b, rec709_to_ebu);
+		break;
+	case V4L2_COLORSPACE_470_SYSTEM_M:
+		*r = transfer_srgb_to_rgb(*r);
+		*g = transfer_srgb_to_rgb(*g);
+		*b = transfer_srgb_to_rgb(*b);
+		mult_matrix(r, g, b, rec709_to_ntsc1953);
+		break;
+	case V4L2_COLORSPACE_SRGB:
+	case V4L2_COLORSPACE_REC709:
+	default:
+		break;
+	}
+
+	*r = ((*r) < 0) ? 0 : (((*r) > 1) ? 1 : (*r));
+	*g = ((*g) < 0) ? 0 : (((*g) > 1) ? 1 : (*g));
+	*b = ((*b) < 0) ? 0 : (((*b) > 1) ? 1 : (*b));
+
+	/* Encode to gamma corrected colorspace */
+	switch (colorspace) {
+	case V4L2_COLORSPACE_SMPTE240M:
+		*r = transfer_rgb_to_smpte240m(*r);
+		*g = transfer_rgb_to_smpte240m(*g);
+		*b = transfer_rgb_to_smpte240m(*b);
+		break;
+	case V4L2_COLORSPACE_SMPTE170M:
+	case V4L2_COLORSPACE_470_SYSTEM_M:
+	case V4L2_COLORSPACE_470_SYSTEM_BG:
+		*r = transfer_rgb_to_rec709(*r);
+		*g = transfer_rgb_to_rec709(*g);
+		*b = transfer_rgb_to_rec709(*b);
+		break;
+	case V4L2_COLORSPACE_SRGB:
+		break;
+	case V4L2_COLORSPACE_REC709:
+	default:
+		*r = transfer_srgb_to_rec709(*r);
+		*g = transfer_srgb_to_rec709(*g);
+		*b = transfer_srgb_to_rec709(*b);
+		break;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	static const unsigned colorspaces[] = {
+		0,
+		V4L2_COLORSPACE_SMPTE170M,
+		V4L2_COLORSPACE_SMPTE240M,
+		V4L2_COLORSPACE_REC709,
+		0,
+		V4L2_COLORSPACE_470_SYSTEM_M,
+		V4L2_COLORSPACE_470_SYSTEM_BG,
+		0,
+		V4L2_COLORSPACE_SRGB,
+	};
+	static const char * const colorspace_names[] = {
+		"",
+		"V4L2_COLORSPACE_SMPTE170M",
+		"V4L2_COLORSPACE_SMPTE240M",
+		"V4L2_COLORSPACE_REC709",
+		"",
+		"V4L2_COLORSPACE_470_SYSTEM_M",
+		"V4L2_COLORSPACE_470_SYSTEM_BG",
+		"",
+		"V4L2_COLORSPACE_SRGB",
+	};
+	int i;
+	int c;
+
+	printf("/* Generated table */\n");
+	printf("const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1] = {\n");
+	for (c = 0; c <= V4L2_COLORSPACE_SRGB; c++) {
+		for (i = 0; i <= TPG_COLOR_CSC_BLACK; i++) {
+			double r, g, b;
+
+			if (colorspaces[c] == 0)
+				continue;
+
+			r = tpg_colors[i].r / 255.0;
+			g = tpg_colors[i].g / 255.0;
+			b = tpg_colors[i].b / 255.0;
+
+			csc(c, &r, &g, &b);
+
+			printf("\t[%s][%d] = { %d, %d, %d },\n", colorspace_names[c], i,
+				(int)(r * 4080), (int)(g * 4080), (int)(b * 4080));
+		}
+	}
+	printf("};\n\n");
+	return 0;
+}
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.h b/drivers/media/platform/vivid/vivid-tpg-colors.h
new file mode 100644
index 0000000..a2678fb
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-tpg-colors.h
@@ -0,0 +1,64 @@
+/*
+ * vivid-color.h - Color definitions for the test pattern generator
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_COLORS_H_
+#define _VIVID_COLORS_H_
+
+struct color {
+	unsigned char r, g, b;
+};
+
+struct color16 {
+	int r, g, b;
+};
+
+enum tpg_color {
+	TPG_COLOR_CSC_WHITE,
+	TPG_COLOR_CSC_YELLOW,
+	TPG_COLOR_CSC_CYAN,
+	TPG_COLOR_CSC_GREEN,
+	TPG_COLOR_CSC_MAGENTA,
+	TPG_COLOR_CSC_RED,
+	TPG_COLOR_CSC_BLUE,
+	TPG_COLOR_CSC_BLACK,
+	TPG_COLOR_75_YELLOW,
+	TPG_COLOR_75_CYAN,
+	TPG_COLOR_75_GREEN,
+	TPG_COLOR_75_MAGENTA,
+	TPG_COLOR_75_RED,
+	TPG_COLOR_75_BLUE,
+	TPG_COLOR_100_WHITE,
+	TPG_COLOR_100_YELLOW,
+	TPG_COLOR_100_CYAN,
+	TPG_COLOR_100_GREEN,
+	TPG_COLOR_100_MAGENTA,
+	TPG_COLOR_100_RED,
+	TPG_COLOR_100_BLUE,
+	TPG_COLOR_100_BLACK,
+	TPG_COLOR_TEXTFG,
+	TPG_COLOR_TEXTBG,
+	TPG_COLOR_RANDOM,
+	TPG_COLOR_RAMP,
+	TPG_COLOR_MAX = TPG_COLOR_RAMP + 256
+};
+
+extern const struct color tpg_colors[TPG_COLOR_MAX];
+extern const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1];
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c
new file mode 100644
index 0000000..0c6fa53
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-tpg.c
@@ -0,0 +1,1439 @@
+/*
+ * vivid-tpg.c - Test Pattern Generator
+ *
+ * Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the
+ * vivi.c source for the copyright information of those functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "vivid-tpg.h"
+
+/* Must remain in sync with enum tpg_pattern */
+const char * const tpg_pattern_strings[] = {
+	"75% Colorbar",
+	"100% Colorbar",
+	"CSC Colorbar",
+	"Horizontal 100% Colorbar",
+	"100% Color Squares",
+	"100% Black",
+	"100% White",
+	"100% Red",
+	"100% Green",
+	"100% Blue",
+	"16x16 Checkers",
+	"1x1 Checkers",
+	"Alternating Hor Lines",
+	"Alternating Vert Lines",
+	"One Pixel Wide Cross",
+	"Two Pixels Wide Cross",
+	"Ten Pixels Wide Cross",
+	"Gray Ramp",
+	"Noise",
+	NULL
+};
+
+/* Must remain in sync with enum tpg_aspect */
+const char * const tpg_aspect_strings[] = {
+	"Source Width x Height",
+	"4x3",
+	"14x9",
+	"16x9",
+	"16x9 Anamorphic",
+	NULL
+};
+
+/*
+ * Sine table: sin[0] = 127 * sin(-180 degrees)
+ *             sin[128] = 127 * sin(0 degrees)
+ *             sin[256] = 127 * sin(180 degrees)
+ */
+static const s8 sin[257] = {
+	   0,   -4,   -7,  -11,  -13,  -18,  -20,  -22,  -26,  -29,  -33,  -35,  -37,  -41,  -43,  -48,
+	 -50,  -52,  -56,  -58,  -62,  -63,  -65,  -69,  -71,  -75,  -76,  -78,  -82,  -83,  -87,  -88,
+	 -90,  -93,  -94,  -97,  -99, -101, -103, -104, -107, -108, -110, -111, -112, -114, -115, -117,
+	-118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -127, -127, -127, -127,
+	-127, -127, -127, -127, -126, -126, -125, -125, -124, -124, -123, -122, -121, -120, -119, -118,
+	-117, -116, -114, -113, -111, -110, -109, -107, -105, -103, -101, -100,  -97,  -96,  -93,  -91,
+	 -90,  -87,  -85,  -82,  -80,  -76,  -75,  -73,  -69,  -67,  -63,  -62,  -60,  -56,  -54,  -50,
+	 -48,  -46,  -41,  -39,  -35,  -33,  -31,  -26,  -24,  -20,  -18,  -15,  -11,   -9,   -4,   -2,
+	   0,    2,    4,    9,   11,   15,   18,   20,   24,   26,   31,   33,   35,   39,   41,   46,
+	  48,   50,   54,   56,   60,   62,   64,   67,   69,   73,   75,   76,   80,   82,   85,   87,
+	  90,   91,   93,   96,   97,  100,  101,  103,  105,  107,  109,  110,  111,  113,  114,  116,
+	 117,  118,  119,  120,  121,  122,  123,  124,  124,  125,  125,  126,  126,  127,  127,  127,
+	 127,  127,  127,  127,  127,  126,  126,  125,  125,  124,  123,  123,  122,  121,  120,  119,
+	 118,  117,  115,  114,  112,  111,  110,  108,  107,  104,  103,  101,   99,   97,   94,   93,
+	  90,   88,   87,   83,   82,   78,   76,   75,   71,   69,   65,   64,   62,   58,   56,   52,
+	  50,   48,   43,   41,   37,   35,   33,   29,   26,   22,   20,   18,   13,   11,    7,    4,
+	   0,
+};
+
+#define cos(idx) sin[((idx) + 64) % sizeof(sin)]
+
+/* Global font descriptor */
+static const u8 *font8x16;
+
+void tpg_set_font(const u8 *f)
+{
+	font8x16 = f;
+}
+
+void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
+{
+	memset(tpg, 0, sizeof(*tpg));
+	tpg->scaled_width = tpg->src_width = w;
+	tpg->src_height = tpg->buf_height = h;
+	tpg->crop.width = tpg->compose.width = w;
+	tpg->crop.height = tpg->compose.height = h;
+	tpg->recalc_colors = true;
+	tpg->recalc_square_border = true;
+	tpg->brightness = 128;
+	tpg->contrast = 128;
+	tpg->saturation = 128;
+	tpg->hue = 0;
+	tpg->mv_hor_mode = TPG_MOVE_NONE;
+	tpg->mv_vert_mode = TPG_MOVE_NONE;
+	tpg->field = V4L2_FIELD_NONE;
+	tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24);
+	tpg->colorspace = V4L2_COLORSPACE_SRGB;
+	tpg->perc_fill = 100;
+}
+
+int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
+{
+	unsigned pat;
+	unsigned plane;
+
+	tpg->max_line_width = max_w;
+	for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) {
+		for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+			unsigned pixelsz = plane ? 1 : 4;
+
+			tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz);
+			if (!tpg->lines[pat][plane])
+				return -ENOMEM;
+		}
+	}
+	for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+		unsigned pixelsz = plane ? 1 : 4;
+
+		tpg->contrast_line[plane] = vzalloc(max_w * pixelsz);
+		if (!tpg->contrast_line[plane])
+			return -ENOMEM;
+		tpg->black_line[plane] = vzalloc(max_w * pixelsz);
+		if (!tpg->black_line[plane])
+			return -ENOMEM;
+		tpg->random_line[plane] = vzalloc(max_w * pixelsz);
+		if (!tpg->random_line[plane])
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+void tpg_free(struct tpg_data *tpg)
+{
+	unsigned pat;
+	unsigned plane;
+
+	for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++)
+		for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+			vfree(tpg->lines[pat][plane]);
+			tpg->lines[pat][plane] = NULL;
+		}
+	for (plane = 0; plane < TPG_MAX_PLANES; plane++) {
+		vfree(tpg->contrast_line[plane]);
+		vfree(tpg->black_line[plane]);
+		vfree(tpg->random_line[plane]);
+		tpg->contrast_line[plane] = NULL;
+		tpg->black_line[plane] = NULL;
+		tpg->random_line[plane] = NULL;
+	}
+}
+
+bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
+{
+	tpg->fourcc = fourcc;
+	tpg->planes = 1;
+	tpg->recalc_colors = true;
+	switch (fourcc) {
+	case V4L2_PIX_FMT_RGB565:
+	case V4L2_PIX_FMT_RGB565X:
+	case V4L2_PIX_FMT_RGB555:
+	case V4L2_PIX_FMT_XRGB555:
+	case V4L2_PIX_FMT_ARGB555:
+	case V4L2_PIX_FMT_RGB555X:
+	case V4L2_PIX_FMT_RGB24:
+	case V4L2_PIX_FMT_BGR24:
+	case V4L2_PIX_FMT_RGB32:
+	case V4L2_PIX_FMT_BGR32:
+	case V4L2_PIX_FMT_XRGB32:
+	case V4L2_PIX_FMT_XBGR32:
+	case V4L2_PIX_FMT_ARGB32:
+	case V4L2_PIX_FMT_ABGR32:
+		tpg->is_yuv = false;
+		break;
+	case V4L2_PIX_FMT_NV16M:
+	case V4L2_PIX_FMT_NV61M:
+		tpg->planes = 2;
+		/* fall-through */
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_VYUY:
+		tpg->is_yuv = true;
+		break;
+	default:
+		return false;
+	}
+
+	switch (fourcc) {
+	case V4L2_PIX_FMT_RGB565:
+	case V4L2_PIX_FMT_RGB565X:
+	case V4L2_PIX_FMT_RGB555:
+	case V4L2_PIX_FMT_XRGB555:
+	case V4L2_PIX_FMT_ARGB555:
+	case V4L2_PIX_FMT_RGB555X:
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_YVYU:
+	case V4L2_PIX_FMT_VYUY:
+		tpg->twopixelsize[0] = 2 * 2;
+		break;
+	case V4L2_PIX_FMT_RGB24:
+	case V4L2_PIX_FMT_BGR24:
+		tpg->twopixelsize[0] = 2 * 3;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+	case V4L2_PIX_FMT_BGR32:
+	case V4L2_PIX_FMT_XRGB32:
+	case V4L2_PIX_FMT_XBGR32:
+	case V4L2_PIX_FMT_ARGB32:
+	case V4L2_PIX_FMT_ABGR32:
+		tpg->twopixelsize[0] = 2 * 4;
+		break;
+	case V4L2_PIX_FMT_NV16M:
+	case V4L2_PIX_FMT_NV61M:
+		tpg->twopixelsize[0] = 2;
+		tpg->twopixelsize[1] = 2;
+		break;
+	}
+	return true;
+}
+
+void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
+		const struct v4l2_rect *compose)
+{
+	tpg->crop = *crop;
+	tpg->compose = *compose;
+	tpg->scaled_width = (tpg->src_width * tpg->compose.width +
+				 tpg->crop.width - 1) / tpg->crop.width;
+	tpg->scaled_width &= ~1;
+	if (tpg->scaled_width > tpg->max_line_width)
+		tpg->scaled_width = tpg->max_line_width;
+	if (tpg->scaled_width < 2)
+		tpg->scaled_width = 2;
+	tpg->recalc_lines = true;
+}
+
+void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
+		       u32 field)
+{
+	unsigned p;
+
+	tpg->src_width = width;
+	tpg->src_height = height;
+	tpg->field = field;
+	tpg->buf_height = height;
+	if (V4L2_FIELD_HAS_T_OR_B(field))
+		tpg->buf_height /= 2;
+	tpg->scaled_width = width;
+	tpg->crop.top = tpg->crop.left = 0;
+	tpg->crop.width = width;
+	tpg->crop.height = height;
+	tpg->compose.top = tpg->compose.left = 0;
+	tpg->compose.width = width;
+	tpg->compose.height = tpg->buf_height;
+	for (p = 0; p < tpg->planes; p++)
+		tpg->bytesperline[p] = width * tpg->twopixelsize[p] / 2;
+	tpg->recalc_square_border = true;
+}
+
+static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
+{
+	switch (tpg->pattern) {
+	case TPG_PAT_BLACK:
+		return TPG_COLOR_100_WHITE;
+	case TPG_PAT_CSC_COLORBAR:
+		return TPG_COLOR_CSC_BLACK;
+	default:
+		return TPG_COLOR_100_BLACK;
+	}
+}
+
+static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
+{
+	switch (tpg->pattern) {
+	case TPG_PAT_75_COLORBAR:
+	case TPG_PAT_CSC_COLORBAR:
+		return TPG_COLOR_CSC_WHITE;
+	case TPG_PAT_BLACK:
+		return TPG_COLOR_100_BLACK;
+	default:
+		return TPG_COLOR_100_WHITE;
+	}
+}
+
+static u16 color_to_y(struct tpg_data *tpg, int r, int g, int b)
+{
+	switch (tpg->colorspace) {
+	case V4L2_COLORSPACE_SMPTE170M:
+	case V4L2_COLORSPACE_470_SYSTEM_M:
+	case V4L2_COLORSPACE_470_SYSTEM_BG:
+		return ((16829 * r + 33039 * g + 6416 * b + 16 * 32768) >> 16) + (16 << 4);
+	case V4L2_COLORSPACE_SMPTE240M:
+		return ((11932 * r + 39455 * g + 4897 * b + 16 * 32768) >> 16) + (16 << 4);
+	case V4L2_COLORSPACE_REC709:
+	case V4L2_COLORSPACE_SRGB:
+	default:
+		return ((11966 * r + 40254 * g + 4064 * b + 16 * 32768) >> 16) + (16 << 4);
+	}
+}
+
+static u16 color_to_cb(struct tpg_data *tpg, int r, int g, int b)
+{
+	switch (tpg->colorspace) {
+	case V4L2_COLORSPACE_SMPTE170M:
+	case V4L2_COLORSPACE_470_SYSTEM_M:
+	case V4L2_COLORSPACE_470_SYSTEM_BG:
+		return ((-9714 * r - 19070 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
+	case V4L2_COLORSPACE_SMPTE240M:
+		return ((-6684 * r - 22100 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
+	case V4L2_COLORSPACE_REC709:
+	case V4L2_COLORSPACE_SRGB:
+	default:
+		return ((-6596 * r - 22189 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
+	}
+}
+
+static u16 color_to_cr(struct tpg_data *tpg, int r, int g, int b)
+{
+	switch (tpg->colorspace) {
+	case V4L2_COLORSPACE_SMPTE170M:
+	case V4L2_COLORSPACE_470_SYSTEM_M:
+	case V4L2_COLORSPACE_470_SYSTEM_BG:
+		return ((28784 * r - 24103 * g - 4681 * b + 16 * 32768) >> 16) + (128 << 4);
+	case V4L2_COLORSPACE_SMPTE240M:
+		return ((28784 * r - 25606 * g - 3178 * b + 16 * 32768) >> 16) + (128 << 4);
+	case V4L2_COLORSPACE_REC709:
+	case V4L2_COLORSPACE_SRGB:
+	default:
+		return ((28784 * r - 26145 * g - 2639 * b + 16 * 32768) >> 16) + (128 << 4);
+	}
+}
+
+static u16 ycbcr_to_r(struct tpg_data *tpg, int y, int cb, int cr)
+{
+	int r;
+
+	y -= 16 << 4;
+	cb -= 128 << 4;
+	cr -= 128 << 4;
+	switch (tpg->colorspace) {
+	case V4L2_COLORSPACE_SMPTE170M:
+	case V4L2_COLORSPACE_470_SYSTEM_M:
+	case V4L2_COLORSPACE_470_SYSTEM_BG:
+		r = 4769 * y + 6537 * cr;
+		break;
+	case V4L2_COLORSPACE_SMPTE240M:
+		r = 4769 * y + 7376 * cr;
+		break;
+	case V4L2_COLORSPACE_REC709:
+	case V4L2_COLORSPACE_SRGB:
+	default:
+		r = 4769 * y + 7343 * cr;
+		break;
+	}
+	return clamp(r >> 12, 0, 0xff0);
+}
+
+static u16 ycbcr_to_g(struct tpg_data *tpg, int y, int cb, int cr)
+{
+	int g;
+
+	y -= 16 << 4;
+	cb -= 128 << 4;
+	cr -= 128 << 4;
+	switch (tpg->colorspace) {
+	case V4L2_COLORSPACE_SMPTE170M:
+	case V4L2_COLORSPACE_470_SYSTEM_M:
+	case V4L2_COLORSPACE_470_SYSTEM_BG:
+		g = 4769 * y - 1605 * cb - 3330 * cr;
+		break;
+	case V4L2_COLORSPACE_SMPTE240M:
+		g = 4769 * y - 1055 * cb - 2341 * cr;
+		break;
+	case V4L2_COLORSPACE_REC709:
+	case V4L2_COLORSPACE_SRGB:
+	default:
+		g = 4769 * y - 873 * cb - 2183 * cr;
+		break;
+	}
+	return clamp(g >> 12, 0, 0xff0);
+}
+
+static u16 ycbcr_to_b(struct tpg_data *tpg, int y, int cb, int cr)
+{
+	int b;
+
+	y -= 16 << 4;
+	cb -= 128 << 4;
+	cr -= 128 << 4;
+	switch (tpg->colorspace) {
+	case V4L2_COLORSPACE_SMPTE170M:
+	case V4L2_COLORSPACE_470_SYSTEM_M:
+	case V4L2_COLORSPACE_470_SYSTEM_BG:
+		b = 4769 * y + 7343 * cb;
+		break;
+	case V4L2_COLORSPACE_SMPTE240M:
+		b = 4769 * y + 8552 * cb;
+		break;
+	case V4L2_COLORSPACE_REC709:
+	case V4L2_COLORSPACE_SRGB:
+	default:
+		b = 4769 * y + 8652 * cb;
+		break;
+	}
+	return clamp(b >> 12, 0, 0xff0);
+}
+
+/* precalculate color bar values to speed up rendering */
+static void precalculate_color(struct tpg_data *tpg, int k)
+{
+	int col = k;
+	int r = tpg_colors[col].r;
+	int g = tpg_colors[col].g;
+	int b = tpg_colors[col].b;
+
+	if (k == TPG_COLOR_TEXTBG) {
+		col = tpg_get_textbg_color(tpg);
+
+		r = tpg_colors[col].r;
+		g = tpg_colors[col].g;
+		b = tpg_colors[col].b;
+	} else if (k == TPG_COLOR_TEXTFG) {
+		col = tpg_get_textfg_color(tpg);
+
+		r = tpg_colors[col].r;
+		g = tpg_colors[col].g;
+		b = tpg_colors[col].b;
+	} else if (tpg->pattern == TPG_PAT_NOISE) {
+		r = g = b = prandom_u32_max(256);
+	} else if (k == TPG_COLOR_RANDOM) {
+		r = g = b = tpg->qual_offset + prandom_u32_max(196);
+	} else if (k >= TPG_COLOR_RAMP) {
+		r = g = b = k - TPG_COLOR_RAMP;
+	}
+
+	if (tpg->pattern == TPG_PAT_CSC_COLORBAR && col <= TPG_COLOR_CSC_BLACK) {
+		r = tpg_csc_colors[tpg->colorspace][col].r;
+		g = tpg_csc_colors[tpg->colorspace][col].g;
+		b = tpg_csc_colors[tpg->colorspace][col].b;
+	} else {
+		r <<= 4;
+		g <<= 4;
+		b <<= 4;
+	}
+	if (tpg->qual == TPG_QUAL_GRAY)
+		r = g = b = color_to_y(tpg, r, g, b);
+
+	/*
+	 * The assumption is that the RGB output is always full range,
+	 * so only if the rgb_range overrides the 'real' rgb range do
+	 * we need to convert the RGB values.
+	 *
+	 * Currently there is no way of signalling to userspace if you
+	 * are actually giving it limited range RGB (or full range
+	 * YUV for that matter).
+	 *
+	 * Remember that r, g and b are still in the 0 - 0xff0 range.
+	 */
+	if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
+	    tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) {
+		/*
+		 * Convert from full range (which is what r, g and b are)
+		 * to limited range (which is the 'real' RGB range), which
+		 * is then interpreted as full range.
+		 */
+		r = (r * 219) / 255 + (16 << 4);
+		g = (g * 219) / 255 + (16 << 4);
+		b = (b * 219) / 255 + (16 << 4);
+	} else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED &&
+		   tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) {
+		/*
+		 * Clamp r, g and b to the limited range and convert to full
+		 * range since that's what we deliver.
+		 */
+		r = clamp(r, 16 << 4, 235 << 4);
+		g = clamp(g, 16 << 4, 235 << 4);
+		b = clamp(b, 16 << 4, 235 << 4);
+		r = (r - (16 << 4)) * 255 / 219;
+		g = (g - (16 << 4)) * 255 / 219;
+		b = (b - (16 << 4)) * 255 / 219;
+	}
+
+	if (tpg->brightness != 128 || tpg->contrast != 128 ||
+	    tpg->saturation != 128 || tpg->hue) {
+		/* Implement these operations */
+
+		/* First convert to YCbCr */
+		int y = color_to_y(tpg, r, g, b);	/* Luma */
+		int cb = color_to_cb(tpg, r, g, b);	/* Cb */
+		int cr = color_to_cr(tpg, r, g, b);	/* Cr */
+		int tmp_cb, tmp_cr;
+
+		y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
+		y += (tpg->brightness << 4) - (128 << 4);
+
+		cb -= 128 << 4;
+		cr -= 128 << 4;
+		tmp_cb = (cb * cos(128 + tpg->hue)) / 127 + (cr * sin[128 + tpg->hue]) / 127;
+		tmp_cr = (cr * cos(128 + tpg->hue)) / 127 - (cb * sin[128 + tpg->hue]) / 127;
+
+		cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128);
+		cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128);
+		if (tpg->is_yuv) {
+			tpg->colors[k][0] = clamp(y >> 4, 1, 254);
+			tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
+			tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
+			return;
+		}
+		r = ycbcr_to_r(tpg, y, cb, cr);
+		g = ycbcr_to_g(tpg, y, cb, cr);
+		b = ycbcr_to_b(tpg, y, cb, cr);
+	}
+
+	if (tpg->is_yuv) {
+		/* Convert to YCbCr */
+		u16 y = color_to_y(tpg, r, g, b);	/* Luma */
+		u16 cb = color_to_cb(tpg, r, g, b);	/* Cb */
+		u16 cr = color_to_cr(tpg, r, g, b);	/* Cr */
+
+		tpg->colors[k][0] = clamp(y >> 4, 1, 254);
+		tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
+		tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
+	} else {
+		switch (tpg->fourcc) {
+		case V4L2_PIX_FMT_RGB565:
+		case V4L2_PIX_FMT_RGB565X:
+			r >>= 7;
+			g >>= 6;
+			b >>= 7;
+			break;
+		case V4L2_PIX_FMT_RGB555:
+		case V4L2_PIX_FMT_XRGB555:
+		case V4L2_PIX_FMT_ARGB555:
+		case V4L2_PIX_FMT_RGB555X:
+			r >>= 7;
+			g >>= 7;
+			b >>= 7;
+			break;
+		default:
+			r >>= 4;
+			g >>= 4;
+			b >>= 4;
+			break;
+		}
+
+		tpg->colors[k][0] = r;
+		tpg->colors[k][1] = g;
+		tpg->colors[k][2] = b;
+	}
+}
+
+static void tpg_precalculate_colors(struct tpg_data *tpg)
+{
+	int k;
+
+	for (k = 0; k < TPG_COLOR_MAX; k++)
+		precalculate_color(tpg, k);
+}
+
+/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
+static void gen_twopix(struct tpg_data *tpg,
+		u8 buf[TPG_MAX_PLANES][8], int color, bool odd)
+{
+	unsigned offset = odd * tpg->twopixelsize[0] / 2;
+	u8 alpha = tpg->alpha_component;
+	u8 r_y, g_u, b_v;
+
+	if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED &&
+				   color != TPG_COLOR_100_RED &&
+				   color != TPG_COLOR_75_RED)
+		alpha = 0;
+	if (color == TPG_COLOR_RANDOM)
+		precalculate_color(tpg, color);
+	r_y = tpg->colors[color][0]; /* R or precalculated Y */
+	g_u = tpg->colors[color][1]; /* G or precalculated U */
+	b_v = tpg->colors[color][2]; /* B or precalculated V */
+
+	switch (tpg->fourcc) {
+	case V4L2_PIX_FMT_NV16M:
+		buf[0][offset] = r_y;
+		buf[1][offset] = odd ? b_v : g_u;
+		break;
+	case V4L2_PIX_FMT_NV61M:
+		buf[0][offset] = r_y;
+		buf[1][offset] = odd ? g_u : b_v;
+		break;
+
+	case V4L2_PIX_FMT_YUYV:
+		buf[0][offset] = r_y;
+		buf[0][offset + 1] = odd ? b_v : g_u;
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		buf[0][offset] = odd ? b_v : g_u;
+		buf[0][offset + 1] = r_y;
+		break;
+	case V4L2_PIX_FMT_YVYU:
+		buf[0][offset] = r_y;
+		buf[0][offset + 1] = odd ? g_u : b_v;
+		break;
+	case V4L2_PIX_FMT_VYUY:
+		buf[0][offset] = odd ? g_u : b_v;
+		buf[0][offset + 1] = r_y;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		buf[0][offset] = (g_u << 5) | b_v;
+		buf[0][offset + 1] = (r_y << 3) | (g_u >> 3);
+		break;
+	case V4L2_PIX_FMT_RGB565X:
+		buf[0][offset] = (r_y << 3) | (g_u >> 3);
+		buf[0][offset + 1] = (g_u << 5) | b_v;
+		break;
+	case V4L2_PIX_FMT_RGB555:
+	case V4L2_PIX_FMT_XRGB555:
+		alpha = 0;
+		/* fall through */
+	case V4L2_PIX_FMT_ARGB555:
+		buf[0][offset] = (g_u << 5) | b_v;
+		buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+		break;
+	case V4L2_PIX_FMT_RGB555X:
+		buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+		buf[0][offset + 1] = (g_u << 5) | b_v;
+		break;
+	case V4L2_PIX_FMT_RGB24:
+		buf[0][offset] = r_y;
+		buf[0][offset + 1] = g_u;
+		buf[0][offset + 2] = b_v;
+		break;
+	case V4L2_PIX_FMT_BGR24:
+		buf[0][offset] = b_v;
+		buf[0][offset + 1] = g_u;
+		buf[0][offset + 2] = r_y;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+	case V4L2_PIX_FMT_XRGB32:
+		alpha = 0;
+		/* fall through */
+	case V4L2_PIX_FMT_ARGB32:
+		buf[0][offset] = alpha;
+		buf[0][offset + 1] = r_y;
+		buf[0][offset + 2] = g_u;
+		buf[0][offset + 3] = b_v;
+		break;
+	case V4L2_PIX_FMT_BGR32:
+	case V4L2_PIX_FMT_XBGR32:
+		alpha = 0;
+		/* fall through */
+	case V4L2_PIX_FMT_ABGR32:
+		buf[0][offset] = b_v;
+		buf[0][offset + 1] = g_u;
+		buf[0][offset + 2] = r_y;
+		buf[0][offset + 3] = alpha;
+		break;
+	}
+}
+
+/* Return how many pattern lines are used by the current pattern. */
+static unsigned tpg_get_pat_lines(struct tpg_data *tpg)
+{
+	switch (tpg->pattern) {
+	case TPG_PAT_CHECKERS_16X16:
+	case TPG_PAT_CHECKERS_1X1:
+	case TPG_PAT_ALTERNATING_HLINES:
+	case TPG_PAT_CROSS_1_PIXEL:
+	case TPG_PAT_CROSS_2_PIXELS:
+	case TPG_PAT_CROSS_10_PIXELS:
+		return 2;
+	case TPG_PAT_100_COLORSQUARES:
+	case TPG_PAT_100_HCOLORBAR:
+		return 8;
+	default:
+		return 1;
+	}
+}
+
+/* Which pattern line should be used for the given frame line. */
+static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line)
+{
+	switch (tpg->pattern) {
+	case TPG_PAT_CHECKERS_16X16:
+		return (line >> 4) & 1;
+	case TPG_PAT_CHECKERS_1X1:
+	case TPG_PAT_ALTERNATING_HLINES:
+		return line & 1;
+	case TPG_PAT_100_COLORSQUARES:
+	case TPG_PAT_100_HCOLORBAR:
+		return (line * 8) / tpg->src_height;
+	case TPG_PAT_CROSS_1_PIXEL:
+		return line == tpg->src_height / 2;
+	case TPG_PAT_CROSS_2_PIXELS:
+		return (line + 1) / 2 == tpg->src_height / 4;
+	case TPG_PAT_CROSS_10_PIXELS:
+		return (line + 10) / 20 == tpg->src_height / 40;
+	default:
+		return 0;
+	}
+}
+
+/*
+ * Which color should be used for the given pattern line and X coordinate.
+ * Note: x is in the range 0 to 2 * tpg->src_width.
+ */
+static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, unsigned x)
+{
+	/* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code
+	   should be modified */
+	static const enum tpg_color bars[3][8] = {
+		/* Standard ITU-R 75% color bar sequence */
+		{ TPG_COLOR_CSC_WHITE,   TPG_COLOR_75_YELLOW,
+		  TPG_COLOR_75_CYAN,     TPG_COLOR_75_GREEN,
+		  TPG_COLOR_75_MAGENTA,  TPG_COLOR_75_RED,
+		  TPG_COLOR_75_BLUE,     TPG_COLOR_100_BLACK, },
+		/* Standard ITU-R 100% color bar sequence */
+		{ TPG_COLOR_100_WHITE,   TPG_COLOR_100_YELLOW,
+		  TPG_COLOR_100_CYAN,    TPG_COLOR_100_GREEN,
+		  TPG_COLOR_100_MAGENTA, TPG_COLOR_100_RED,
+		  TPG_COLOR_100_BLUE,    TPG_COLOR_100_BLACK, },
+		/* Color bar sequence suitable to test CSC */
+		{ TPG_COLOR_CSC_WHITE,   TPG_COLOR_CSC_YELLOW,
+		  TPG_COLOR_CSC_CYAN,    TPG_COLOR_CSC_GREEN,
+		  TPG_COLOR_CSC_MAGENTA, TPG_COLOR_CSC_RED,
+		  TPG_COLOR_CSC_BLUE,    TPG_COLOR_CSC_BLACK, },
+	};
+
+	switch (tpg->pattern) {
+	case TPG_PAT_75_COLORBAR:
+	case TPG_PAT_100_COLORBAR:
+	case TPG_PAT_CSC_COLORBAR:
+		return bars[tpg->pattern][((x * 8) / tpg->src_width) % 8];
+	case TPG_PAT_100_COLORSQUARES:
+		return bars[1][(pat_line + (x * 8) / tpg->src_width) % 8];
+	case TPG_PAT_100_HCOLORBAR:
+		return bars[1][pat_line];
+	case TPG_PAT_BLACK:
+		return TPG_COLOR_100_BLACK;
+	case TPG_PAT_WHITE:
+		return TPG_COLOR_100_WHITE;
+	case TPG_PAT_RED:
+		return TPG_COLOR_100_RED;
+	case TPG_PAT_GREEN:
+		return TPG_COLOR_100_GREEN;
+	case TPG_PAT_BLUE:
+		return TPG_COLOR_100_BLUE;
+	case TPG_PAT_CHECKERS_16X16:
+		return (((x >> 4) & 1) ^ (pat_line & 1)) ?
+			TPG_COLOR_100_BLACK : TPG_COLOR_100_WHITE;
+	case TPG_PAT_CHECKERS_1X1:
+		return ((x & 1) ^ (pat_line & 1)) ?
+			TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+	case TPG_PAT_ALTERNATING_HLINES:
+		return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+	case TPG_PAT_ALTERNATING_VLINES:
+		return (x & 1) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK;
+	case TPG_PAT_CROSS_1_PIXEL:
+		if (pat_line || (x % tpg->src_width) == tpg->src_width / 2)
+			return TPG_COLOR_100_BLACK;
+		return TPG_COLOR_100_WHITE;
+	case TPG_PAT_CROSS_2_PIXELS:
+		if (pat_line || ((x % tpg->src_width) + 1) / 2 == tpg->src_width / 4)
+			return TPG_COLOR_100_BLACK;
+		return TPG_COLOR_100_WHITE;
+	case TPG_PAT_CROSS_10_PIXELS:
+		if (pat_line || ((x % tpg->src_width) + 10) / 20 == tpg->src_width / 40)
+			return TPG_COLOR_100_BLACK;
+		return TPG_COLOR_100_WHITE;
+	case TPG_PAT_GRAY_RAMP:
+		return TPG_COLOR_RAMP + ((x % tpg->src_width) * 256) / tpg->src_width;
+	default:
+		return TPG_COLOR_100_RED;
+	}
+}
+
+/*
+ * Given the pixel aspect ratio and video aspect ratio calculate the
+ * coordinates of a centered square and the coordinates of the border of
+ * the active video area. The coordinates are relative to the source
+ * frame rectangle.
+ */
+static void tpg_calculate_square_border(struct tpg_data *tpg)
+{
+	unsigned w = tpg->src_width;
+	unsigned h = tpg->src_height;
+	unsigned sq_w, sq_h;
+
+	sq_w = (w * 2 / 5) & ~1;
+	if (((w - sq_w) / 2) & 1)
+		sq_w += 2;
+	sq_h = sq_w;
+	tpg->square.width = sq_w;
+	if (tpg->vid_aspect == TPG_VIDEO_ASPECT_16X9_ANAMORPHIC) {
+		unsigned ana_sq_w = (sq_w / 4) * 3;
+
+		if (((w - ana_sq_w) / 2) & 1)
+			ana_sq_w += 2;
+		tpg->square.width = ana_sq_w;
+	}
+	tpg->square.left = (w - tpg->square.width) / 2;
+	if (tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC)
+		sq_h = sq_w * 10 / 11;
+	else if (tpg->pix_aspect == TPG_PIXEL_ASPECT_PAL)
+		sq_h = sq_w * 59 / 54;
+	tpg->square.height = sq_h;
+	tpg->square.top = (h - sq_h) / 2;
+	tpg->border.left = 0;
+	tpg->border.width = w;
+	tpg->border.top = 0;
+	tpg->border.height = h;
+	switch (tpg->vid_aspect) {
+	case TPG_VIDEO_ASPECT_4X3:
+		if (tpg->pix_aspect)
+			return;
+		if (3 * w >= 4 * h) {
+			tpg->border.width = ((4 * h) / 3) & ~1;
+			if (((w - tpg->border.width) / 2) & ~1)
+				tpg->border.width -= 2;
+			tpg->border.left = (w - tpg->border.width) / 2;
+			break;
+		}
+		tpg->border.height = ((3 * w) / 4) & ~1;
+		tpg->border.top = (h - tpg->border.height) / 2;
+		break;
+	case TPG_VIDEO_ASPECT_14X9_CENTRE:
+		if (tpg->pix_aspect) {
+			tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 420 : 506;
+			tpg->border.top = (h - tpg->border.height) / 2;
+			break;
+		}
+		if (9 * w >= 14 * h) {
+			tpg->border.width = ((14 * h) / 9) & ~1;
+			if (((w - tpg->border.width) / 2) & ~1)
+				tpg->border.width -= 2;
+			tpg->border.left = (w - tpg->border.width) / 2;
+			break;
+		}
+		tpg->border.height = ((9 * w) / 14) & ~1;
+		tpg->border.top = (h - tpg->border.height) / 2;
+		break;
+	case TPG_VIDEO_ASPECT_16X9_CENTRE:
+		if (tpg->pix_aspect) {
+			tpg->border.height = tpg->pix_aspect == TPG_PIXEL_ASPECT_NTSC ? 368 : 442;
+			tpg->border.top = (h - tpg->border.height) / 2;
+			break;
+		}
+		if (9 * w >= 16 * h) {
+			tpg->border.width = ((16 * h) / 9) & ~1;
+			if (((w - tpg->border.width) / 2) & ~1)
+				tpg->border.width -= 2;
+			tpg->border.left = (w - tpg->border.width) / 2;
+			break;
+		}
+		tpg->border.height = ((9 * w) / 16) & ~1;
+		tpg->border.top = (h - tpg->border.height) / 2;
+		break;
+	default:
+		break;
+	}
+}
+
+static void tpg_precalculate_line(struct tpg_data *tpg)
+{
+	enum tpg_color contrast;
+	unsigned pat;
+	unsigned p;
+	unsigned x;
+
+	switch (tpg->pattern) {
+	case TPG_PAT_GREEN:
+		contrast = TPG_COLOR_100_RED;
+		break;
+	case TPG_PAT_CSC_COLORBAR:
+		contrast = TPG_COLOR_CSC_GREEN;
+		break;
+	default:
+		contrast = TPG_COLOR_100_GREEN;
+		break;
+	}
+
+	for (pat = 0; pat < tpg_get_pat_lines(tpg); pat++) {
+		/* Coarse scaling with Bresenham */
+		unsigned int_part = tpg->src_width / tpg->scaled_width;
+		unsigned fract_part = tpg->src_width % tpg->scaled_width;
+		unsigned src_x = 0;
+		unsigned error = 0;
+
+		for (x = 0; x < tpg->scaled_width * 2; x += 2) {
+			unsigned real_x = src_x;
+			enum tpg_color color1, color2;
+			u8 pix[TPG_MAX_PLANES][8];
+
+			real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
+			color1 = tpg_get_color(tpg, pat, real_x);
+
+			src_x += int_part;
+			error += fract_part;
+			if (error >= tpg->scaled_width) {
+				error -= tpg->scaled_width;
+				src_x++;
+			}
+
+			real_x = src_x;
+			real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x;
+			color2 = tpg_get_color(tpg, pat, real_x);
+
+			src_x += int_part;
+			error += fract_part;
+			if (error >= tpg->scaled_width) {
+				error -= tpg->scaled_width;
+				src_x++;
+			}
+
+			gen_twopix(tpg, pix, tpg->hflip ? color2 : color1, 0);
+			gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1);
+			for (p = 0; p < tpg->planes; p++) {
+				unsigned twopixsize = tpg->twopixelsize[p];
+				u8 *pos = tpg->lines[pat][p] + x * twopixsize / 2;
+
+				memcpy(pos, pix[p], twopixsize);
+			}
+		}
+	}
+	for (x = 0; x < tpg->scaled_width; x += 2) {
+		u8 pix[TPG_MAX_PLANES][8];
+
+		gen_twopix(tpg, pix, contrast, 0);
+		gen_twopix(tpg, pix, contrast, 1);
+		for (p = 0; p < tpg->planes; p++) {
+			unsigned twopixsize = tpg->twopixelsize[p];
+			u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2;
+
+			memcpy(pos, pix[p], twopixsize);
+		}
+	}
+	for (x = 0; x < tpg->scaled_width; x += 2) {
+		u8 pix[TPG_MAX_PLANES][8];
+
+		gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0);
+		gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1);
+		for (p = 0; p < tpg->planes; p++) {
+			unsigned twopixsize = tpg->twopixelsize[p];
+			u8 *pos = tpg->black_line[p] + x * twopixsize / 2;
+
+			memcpy(pos, pix[p], twopixsize);
+		}
+	}
+	for (x = 0; x < tpg->scaled_width * 2; x += 2) {
+		u8 pix[TPG_MAX_PLANES][8];
+
+		gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0);
+		gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1);
+		for (p = 0; p < tpg->planes; p++) {
+			unsigned twopixsize = tpg->twopixelsize[p];
+			u8 *pos = tpg->random_line[p] + x * twopixsize / 2;
+
+			memcpy(pos, pix[p], twopixsize);
+		}
+	}
+	gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0);
+	gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1);
+	gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0);
+	gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 1);
+}
+
+/* need this to do rgb24 rendering */
+typedef struct { u16 __; u8 _; } __packed x24;
+
+void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
+		int y, int x, char *text)
+{
+	int line;
+	unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
+	unsigned div = step;
+	unsigned first = 0;
+	unsigned len = strlen(text);
+	unsigned p;
+
+	if (font8x16 == NULL || basep == NULL)
+		return;
+
+	/* Checks if it is possible to show string */
+	if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width)
+		return;
+
+	if (len > (tpg->compose.width - x) / 8)
+		len = (tpg->compose.width - x) / 8;
+	if (tpg->vflip)
+		y = tpg->compose.height - y - 16;
+	if (tpg->hflip)
+		x = tpg->compose.width - x - 8;
+	y += tpg->compose.top;
+	x += tpg->compose.left;
+	if (tpg->field == V4L2_FIELD_BOTTOM)
+		first = 1;
+	else if (tpg->field == V4L2_FIELD_SEQ_TB || tpg->field == V4L2_FIELD_SEQ_BT)
+		div = 2;
+
+	for (p = 0; p < tpg->planes; p++) {
+		/* Print stream time */
+#define PRINTSTR(PIXTYPE) do {	\
+	PIXTYPE fg;	\
+	PIXTYPE bg;	\
+	memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE));	\
+	memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE));	\
+	\
+	for (line = first; line < 16; line += step) {	\
+		int l = tpg->vflip ? 15 - line : line; \
+		PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \
+			       ((y * step + l) / div) * tpg->bytesperline[p] + \
+			       x * sizeof(PIXTYPE));	\
+		unsigned s;	\
+	\
+		for (s = 0; s < len; s++) {	\
+			u8 chr = font8x16[text[s] * 16 + line];	\
+	\
+			if (tpg->hflip) { \
+				pos[7] = (chr & (0x01 << 7) ? fg : bg);	\
+				pos[6] = (chr & (0x01 << 6) ? fg : bg);	\
+				pos[5] = (chr & (0x01 << 5) ? fg : bg);	\
+				pos[4] = (chr & (0x01 << 4) ? fg : bg);	\
+				pos[3] = (chr & (0x01 << 3) ? fg : bg);	\
+				pos[2] = (chr & (0x01 << 2) ? fg : bg);	\
+				pos[1] = (chr & (0x01 << 1) ? fg : bg);	\
+				pos[0] = (chr & (0x01 << 0) ? fg : bg);	\
+			} else { \
+				pos[0] = (chr & (0x01 << 7) ? fg : bg);	\
+				pos[1] = (chr & (0x01 << 6) ? fg : bg);	\
+				pos[2] = (chr & (0x01 << 5) ? fg : bg);	\
+				pos[3] = (chr & (0x01 << 4) ? fg : bg);	\
+				pos[4] = (chr & (0x01 << 3) ? fg : bg);	\
+				pos[5] = (chr & (0x01 << 2) ? fg : bg);	\
+				pos[6] = (chr & (0x01 << 1) ? fg : bg);	\
+				pos[7] = (chr & (0x01 << 0) ? fg : bg);	\
+			} \
+	\
+			pos += tpg->hflip ? -8 : 8;	\
+		}	\
+	}	\
+} while (0)
+
+		switch (tpg->twopixelsize[p]) {
+		case 2:
+			PRINTSTR(u8); break;
+		case 4:
+			PRINTSTR(u16); break;
+		case 6:
+			PRINTSTR(x24); break;
+		case 8:
+			PRINTSTR(u32); break;
+		}
+	}
+}
+
+void tpg_update_mv_step(struct tpg_data *tpg)
+{
+	int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1;
+
+	if (tpg->hflip)
+		factor = -factor;
+	switch (tpg->mv_hor_mode) {
+	case TPG_MOVE_NEG_FAST:
+	case TPG_MOVE_POS_FAST:
+		tpg->mv_hor_step = ((tpg->src_width + 319) / 320) * 4;
+		break;
+	case TPG_MOVE_NEG:
+	case TPG_MOVE_POS:
+		tpg->mv_hor_step = ((tpg->src_width + 639) / 640) * 4;
+		break;
+	case TPG_MOVE_NEG_SLOW:
+	case TPG_MOVE_POS_SLOW:
+		tpg->mv_hor_step = 2;
+		break;
+	case TPG_MOVE_NONE:
+		tpg->mv_hor_step = 0;
+		break;
+	}
+	if (factor < 0)
+		tpg->mv_hor_step = tpg->src_width - tpg->mv_hor_step;
+
+	factor = tpg->mv_vert_mode > TPG_MOVE_NONE ? -1 : 1;
+	switch (tpg->mv_vert_mode) {
+	case TPG_MOVE_NEG_FAST:
+	case TPG_MOVE_POS_FAST:
+		tpg->mv_vert_step = ((tpg->src_width + 319) / 320) * 4;
+		break;
+	case TPG_MOVE_NEG:
+	case TPG_MOVE_POS:
+		tpg->mv_vert_step = ((tpg->src_width + 639) / 640) * 4;
+		break;
+	case TPG_MOVE_NEG_SLOW:
+	case TPG_MOVE_POS_SLOW:
+		tpg->mv_vert_step = 1;
+		break;
+	case TPG_MOVE_NONE:
+		tpg->mv_vert_step = 0;
+		break;
+	}
+	if (factor < 0)
+		tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
+}
+
+/* Map the line number relative to the crop rectangle to a frame line number */
+static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y,
+				    unsigned field)
+{
+	switch (field) {
+	case V4L2_FIELD_TOP:
+		return tpg->crop.top + src_y * 2;
+	case V4L2_FIELD_BOTTOM:
+		return tpg->crop.top + src_y * 2 + 1;
+	default:
+		return src_y + tpg->crop.top;
+	}
+}
+
+/*
+ * Map the line number relative to the compose rectangle to a destination
+ * buffer line number.
+ */
+static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y,
+				    unsigned field)
+{
+	y += tpg->compose.top;
+	switch (field) {
+	case V4L2_FIELD_SEQ_TB:
+		if (y & 1)
+			return tpg->buf_height / 2 + y / 2;
+		return y / 2;
+	case V4L2_FIELD_SEQ_BT:
+		if (y & 1)
+			return y / 2;
+		return tpg->buf_height / 2 + y / 2;
+	default:
+		return y;
+	}
+}
+
+static void tpg_recalc(struct tpg_data *tpg)
+{
+	if (tpg->recalc_colors) {
+		tpg->recalc_colors = false;
+		tpg->recalc_lines = true;
+		tpg_precalculate_colors(tpg);
+	}
+	if (tpg->recalc_square_border) {
+		tpg->recalc_square_border = false;
+		tpg_calculate_square_border(tpg);
+	}
+	if (tpg->recalc_lines) {
+		tpg->recalc_lines = false;
+		tpg_precalculate_line(tpg);
+	}
+}
+
+void tpg_calc_text_basep(struct tpg_data *tpg,
+		u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf)
+{
+	unsigned stride = tpg->bytesperline[p];
+
+	tpg_recalc(tpg);
+
+	basep[p][0] = vbuf;
+	basep[p][1] = vbuf;
+	if (tpg->field == V4L2_FIELD_SEQ_TB)
+		basep[p][1] += tpg->buf_height * stride / 2;
+	else if (tpg->field == V4L2_FIELD_SEQ_BT)
+		basep[p][0] += tpg->buf_height * stride / 2;
+}
+
+void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
+{
+	bool is_tv = std;
+	bool is_60hz = is_tv && (std & V4L2_STD_525_60);
+	unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width;
+	unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width;
+	unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height;
+	unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height;
+	unsigned wss_width;
+	unsigned f;
+	int hmax = (tpg->compose.height * tpg->perc_fill) / 100;
+	int h;
+	unsigned twopixsize = tpg->twopixelsize[p];
+	unsigned img_width = tpg->compose.width * twopixsize / 2;
+	unsigned line_offset;
+	unsigned left_pillar_width = 0;
+	unsigned right_pillar_start = img_width;
+	unsigned stride = tpg->bytesperline[p];
+	unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1;
+	u8 *orig_vbuf = vbuf;
+
+	/* Coarse scaling with Bresenham */
+	unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height;
+	unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height;
+	unsigned src_y = 0;
+	unsigned error = 0;
+
+	tpg_recalc(tpg);
+
+	mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1;
+	mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1;
+	wss_width = tpg->crop.left < tpg->src_width / 2 ?
+			tpg->src_width / 2 - tpg->crop.left : 0;
+	if (wss_width > tpg->crop.width)
+		wss_width = tpg->crop.width;
+	wss_width = wss_width * tpg->scaled_width / tpg->src_width;
+
+	vbuf += tpg->compose.left * twopixsize / 2;
+	line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width;
+	line_offset = (line_offset & ~1) * twopixsize / 2;
+	if (tpg->crop.left < tpg->border.left) {
+		left_pillar_width = tpg->border.left - tpg->crop.left;
+		if (left_pillar_width > tpg->crop.width)
+			left_pillar_width = tpg->crop.width;
+		left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width;
+		left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2;
+	}
+	if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) {
+		right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left;
+		right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width;
+		right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2;
+		if (right_pillar_start > img_width)
+			right_pillar_start = img_width;
+	}
+
+	f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
+
+	for (h = 0; h < tpg->compose.height; h++) {
+		bool even;
+		bool fill_blank = false;
+		unsigned frame_line;
+		unsigned buf_line;
+		unsigned pat_line_old;
+		unsigned pat_line_new;
+		u8 *linestart_older;
+		u8 *linestart_newer;
+		u8 *linestart_top;
+		u8 *linestart_bottom;
+
+		frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
+		even = !(frame_line & 1);
+		buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
+		src_y += int_part;
+		error += fract_part;
+		if (error >= tpg->compose.height) {
+			error -= tpg->compose.height;
+			src_y++;
+		}
+
+		if (h >= hmax) {
+			if (hmax == tpg->compose.height)
+				continue;
+			if (!tpg->perc_fill_blank)
+				continue;
+			fill_blank = true;
+		}
+
+		if (tpg->vflip)
+			frame_line = tpg->src_height - frame_line - 1;
+
+		if (fill_blank) {
+			linestart_older = tpg->contrast_line[p];
+			linestart_newer = tpg->contrast_line[p];
+		} else if (tpg->qual != TPG_QUAL_NOISE &&
+			   (frame_line < tpg->border.top ||
+			    frame_line >= tpg->border.top + tpg->border.height)) {
+			linestart_older = tpg->black_line[p];
+			linestart_newer = tpg->black_line[p];
+		} else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) {
+			linestart_older = tpg->random_line[p] +
+					  twopixsize * prandom_u32_max(tpg->src_width / 2);
+			linestart_newer = tpg->random_line[p] +
+					  twopixsize * prandom_u32_max(tpg->src_width / 2);
+		} else {
+			pat_line_old = tpg_get_pat_line(tpg,
+						(frame_line + mv_vert_old) % tpg->src_height);
+			pat_line_new = tpg_get_pat_line(tpg,
+						(frame_line + mv_vert_new) % tpg->src_height);
+			linestart_older = tpg->lines[pat_line_old][p] +
+					  mv_hor_old * twopixsize / 2;
+			linestart_newer = tpg->lines[pat_line_new][p] +
+					  mv_hor_new * twopixsize / 2;
+			linestart_older += line_offset;
+			linestart_newer += line_offset;
+		}
+		if (is_60hz) {
+			linestart_top = linestart_newer;
+			linestart_bottom = linestart_older;
+		} else {
+			linestart_top = linestart_older;
+			linestart_bottom = linestart_newer;
+		}
+
+		switch (tpg->field) {
+		case V4L2_FIELD_INTERLACED:
+		case V4L2_FIELD_INTERLACED_TB:
+		case V4L2_FIELD_SEQ_TB:
+		case V4L2_FIELD_SEQ_BT:
+			if (even)
+				memcpy(vbuf + buf_line * stride, linestart_top, img_width);
+			else
+				memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
+			break;
+		case V4L2_FIELD_INTERLACED_BT:
+			if (even)
+				memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
+			else
+				memcpy(vbuf + buf_line * stride, linestart_top, img_width);
+			break;
+		case V4L2_FIELD_TOP:
+			memcpy(vbuf + buf_line * stride, linestart_top, img_width);
+			break;
+		case V4L2_FIELD_BOTTOM:
+			memcpy(vbuf + buf_line * stride, linestart_bottom, img_width);
+			break;
+		case V4L2_FIELD_NONE:
+		default:
+			memcpy(vbuf + buf_line * stride, linestart_older, img_width);
+			break;
+		}
+
+		if (is_tv && !is_60hz && frame_line == 0 && wss_width) {
+			/*
+			 * Replace the first half of the top line of a 50 Hz frame
+			 * with random data to simulate a WSS signal.
+			 */
+			u8 *wss = tpg->random_line[p] +
+				  twopixsize * prandom_u32_max(tpg->src_width / 2);
+
+			memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2);
+		}
+	}
+
+	vbuf = orig_vbuf;
+	vbuf += tpg->compose.left * twopixsize / 2;
+	src_y = 0;
+	error = 0;
+	for (h = 0; h < tpg->compose.height; h++) {
+		unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field);
+		unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field);
+		const struct v4l2_rect *sq = &tpg->square;
+		const struct v4l2_rect *b = &tpg->border;
+		const struct v4l2_rect *c = &tpg->crop;
+
+		src_y += int_part;
+		error += fract_part;
+		if (error >= tpg->compose.height) {
+			error -= tpg->compose.height;
+			src_y++;
+		}
+
+		if (tpg->show_border && frame_line >= b->top &&
+		    frame_line < b->top + b->height) {
+			unsigned bottom = b->top + b->height - 1;
+			unsigned left = left_pillar_width;
+			unsigned right = right_pillar_start;
+
+			if (frame_line == b->top || frame_line == b->top + 1 ||
+			    frame_line == bottom || frame_line == bottom - 1) {
+				memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p],
+						right - left);
+			} else {
+				if (b->left >= c->left &&
+				    b->left < c->left + c->width)
+					memcpy(vbuf + buf_line * stride + left,
+						tpg->contrast_line[p], twopixsize);
+				if (b->left + b->width > c->left &&
+				    b->left + b->width <= c->left + c->width)
+					memcpy(vbuf + buf_line * stride + right - twopixsize,
+						tpg->contrast_line[p], twopixsize);
+			}
+		}
+		if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top &&
+		    frame_line < b->top + b->height) {
+			memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width);
+			memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p],
+			       img_width - right_pillar_start);
+		}
+		if (tpg->show_square && frame_line >= sq->top &&
+		    frame_line < sq->top + sq->height &&
+		    sq->left < c->left + c->width &&
+		    sq->left + sq->width >= c->left) {
+			unsigned left = sq->left;
+			unsigned width = sq->width;
+
+			if (c->left > left) {
+				width -= c->left - left;
+				left = c->left;
+			}
+			if (c->left + c->width < left + width)
+				width -= left + width - c->left - c->width;
+			left -= c->left;
+			left = (left * tpg->scaled_width) / tpg->src_width;
+			left = (left & ~1) * twopixsize / 2;
+			width = (width * tpg->scaled_width) / tpg->src_width;
+			width = (width & ~1) * twopixsize / 2;
+			memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width);
+		}
+		if (tpg->insert_sav) {
+			unsigned offset = (tpg->compose.width / 6) * twopixsize;
+			u8 *p = vbuf + buf_line * stride + offset;
+			unsigned vact = 0, hact = 0;
+
+			p[0] = 0xff;
+			p[1] = 0;
+			p[2] = 0;
+			p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
+				((hact ^ vact) << 3) |
+				((hact ^ f) << 2) |
+				((f ^ vact) << 1) |
+				(hact ^ vact ^ f);
+		}
+		if (tpg->insert_eav) {
+			unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize;
+			u8 *p = vbuf + buf_line * stride + offset;
+			unsigned vact = 0, hact = 1;
+
+			p[0] = 0xff;
+			p[1] = 0;
+			p[2] = 0;
+			p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) |
+				((hact ^ vact) << 3) |
+				((hact ^ f) << 2) |
+				((f ^ vact) << 1) |
+				(hact ^ vact ^ f);
+		}
+	}
+}
diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h
new file mode 100644
index 0000000..8ef3e52
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-tpg.h
@@ -0,0 +1,439 @@
+/*
+ * vivid-tpg.h - Test Pattern Generator
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_TPG_H_
+#define _VIVID_TPG_H_
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+
+#include "vivid-tpg-colors.h"
+
+enum tpg_pattern {
+	TPG_PAT_75_COLORBAR,
+	TPG_PAT_100_COLORBAR,
+	TPG_PAT_CSC_COLORBAR,
+	TPG_PAT_100_HCOLORBAR,
+	TPG_PAT_100_COLORSQUARES,
+	TPG_PAT_BLACK,
+	TPG_PAT_WHITE,
+	TPG_PAT_RED,
+	TPG_PAT_GREEN,
+	TPG_PAT_BLUE,
+	TPG_PAT_CHECKERS_16X16,
+	TPG_PAT_CHECKERS_1X1,
+	TPG_PAT_ALTERNATING_HLINES,
+	TPG_PAT_ALTERNATING_VLINES,
+	TPG_PAT_CROSS_1_PIXEL,
+	TPG_PAT_CROSS_2_PIXELS,
+	TPG_PAT_CROSS_10_PIXELS,
+	TPG_PAT_GRAY_RAMP,
+
+	/* Must be the last pattern */
+	TPG_PAT_NOISE,
+};
+
+extern const char * const tpg_pattern_strings[];
+
+enum tpg_quality {
+	TPG_QUAL_COLOR,
+	TPG_QUAL_GRAY,
+	TPG_QUAL_NOISE
+};
+
+enum tpg_video_aspect {
+	TPG_VIDEO_ASPECT_IMAGE,
+	TPG_VIDEO_ASPECT_4X3,
+	TPG_VIDEO_ASPECT_14X9_CENTRE,
+	TPG_VIDEO_ASPECT_16X9_CENTRE,
+	TPG_VIDEO_ASPECT_16X9_ANAMORPHIC,
+};
+
+enum tpg_pixel_aspect {
+	TPG_PIXEL_ASPECT_SQUARE,
+	TPG_PIXEL_ASPECT_NTSC,
+	TPG_PIXEL_ASPECT_PAL,
+};
+
+enum tpg_move_mode {
+	TPG_MOVE_NEG_FAST,
+	TPG_MOVE_NEG,
+	TPG_MOVE_NEG_SLOW,
+	TPG_MOVE_NONE,
+	TPG_MOVE_POS_SLOW,
+	TPG_MOVE_POS,
+	TPG_MOVE_POS_FAST,
+};
+
+extern const char * const tpg_aspect_strings[];
+
+#define TPG_MAX_PLANES 2
+#define TPG_MAX_PAT_LINES 8
+
+struct tpg_data {
+	/* Source frame size */
+	unsigned			src_width, src_height;
+	/* Buffer height */
+	unsigned			buf_height;
+	/* Scaled output frame size */
+	unsigned			scaled_width;
+	u32				field;
+	/* crop coordinates are frame-based */
+	struct v4l2_rect		crop;
+	/* compose coordinates are format-based */
+	struct v4l2_rect		compose;
+	/* border and square coordinates are frame-based */
+	struct v4l2_rect		border;
+	struct v4l2_rect		square;
+
+	/* Color-related fields */
+	enum tpg_quality		qual;
+	unsigned			qual_offset;
+	u8				alpha_component;
+	bool				alpha_red_only;
+	u8				brightness;
+	u8				contrast;
+	u8				saturation;
+	s16				hue;
+	u32				fourcc;
+	bool				is_yuv;
+	u32				colorspace;
+	enum tpg_video_aspect		vid_aspect;
+	enum tpg_pixel_aspect		pix_aspect;
+	unsigned			rgb_range;
+	unsigned			real_rgb_range;
+	unsigned			planes;
+	/* Used to store the colors in native format, either RGB or YUV */
+	u8				colors[TPG_COLOR_MAX][3];
+	u8				textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8];
+	/* size in bytes for two pixels in each plane */
+	unsigned			twopixelsize[TPG_MAX_PLANES];
+	unsigned			bytesperline[TPG_MAX_PLANES];
+
+	/* Configuration */
+	enum tpg_pattern		pattern;
+	bool				hflip;
+	bool				vflip;
+	unsigned			perc_fill;
+	bool				perc_fill_blank;
+	bool				show_border;
+	bool				show_square;
+	bool				insert_sav;
+	bool				insert_eav;
+
+	/* Test pattern movement */
+	enum tpg_move_mode		mv_hor_mode;
+	int				mv_hor_count;
+	int				mv_hor_step;
+	enum tpg_move_mode		mv_vert_mode;
+	int				mv_vert_count;
+	int				mv_vert_step;
+
+	bool				recalc_colors;
+	bool				recalc_lines;
+	bool				recalc_square_border;
+
+	/* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */
+	unsigned			max_line_width;
+	u8				*lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES];
+	u8				*random_line[TPG_MAX_PLANES];
+	u8				*contrast_line[TPG_MAX_PLANES];
+	u8				*black_line[TPG_MAX_PLANES];
+};
+
+void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h);
+int tpg_alloc(struct tpg_data *tpg, unsigned max_w);
+void tpg_free(struct tpg_data *tpg);
+void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
+		       u32 field);
+
+void tpg_set_font(const u8 *f);
+void tpg_gen_text(struct tpg_data *tpg,
+		u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text);
+void tpg_calc_text_basep(struct tpg_data *tpg,
+		u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf);
+void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf);
+bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc);
+void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
+		const struct v4l2_rect *compose);
+
+static inline void tpg_s_pattern(struct tpg_data *tpg, enum tpg_pattern pattern)
+{
+	if (tpg->pattern == pattern)
+		return;
+	tpg->pattern = pattern;
+	tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_quality(struct tpg_data *tpg,
+				    enum tpg_quality qual, unsigned qual_offset)
+{
+	if (tpg->qual == qual && tpg->qual_offset == qual_offset)
+		return;
+	tpg->qual = qual;
+	tpg->qual_offset = qual_offset;
+	tpg->recalc_colors = true;
+}
+
+static inline enum tpg_quality tpg_g_quality(const struct tpg_data *tpg)
+{
+	return tpg->qual;
+}
+
+static inline void tpg_s_alpha_component(struct tpg_data *tpg,
+					    u8 alpha_component)
+{
+	if (tpg->alpha_component == alpha_component)
+		return;
+	tpg->alpha_component = alpha_component;
+	tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_alpha_mode(struct tpg_data *tpg,
+					    bool red_only)
+{
+	if (tpg->alpha_red_only == red_only)
+		return;
+	tpg->alpha_red_only = red_only;
+	tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_brightness(struct tpg_data *tpg,
+					u8 brightness)
+{
+	if (tpg->brightness == brightness)
+		return;
+	tpg->brightness = brightness;
+	tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_contrast(struct tpg_data *tpg,
+					u8 contrast)
+{
+	if (tpg->contrast == contrast)
+		return;
+	tpg->contrast = contrast;
+	tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_saturation(struct tpg_data *tpg,
+					u8 saturation)
+{
+	if (tpg->saturation == saturation)
+		return;
+	tpg->saturation = saturation;
+	tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_hue(struct tpg_data *tpg,
+					s16 hue)
+{
+	if (tpg->hue == hue)
+		return;
+	tpg->hue = hue;
+	tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_rgb_range(struct tpg_data *tpg,
+					unsigned rgb_range)
+{
+	if (tpg->rgb_range == rgb_range)
+		return;
+	tpg->rgb_range = rgb_range;
+	tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_real_rgb_range(struct tpg_data *tpg,
+					unsigned rgb_range)
+{
+	if (tpg->real_rgb_range == rgb_range)
+		return;
+	tpg->real_rgb_range = rgb_range;
+	tpg->recalc_colors = true;
+}
+
+static inline void tpg_s_colorspace(struct tpg_data *tpg, u32 colorspace)
+{
+	if (tpg->colorspace == colorspace)
+		return;
+	tpg->colorspace = colorspace;
+	tpg->recalc_colors = true;
+}
+
+static inline u32 tpg_g_colorspace(const struct tpg_data *tpg)
+{
+	return tpg->colorspace;
+}
+
+static inline unsigned tpg_g_planes(const struct tpg_data *tpg)
+{
+	return tpg->planes;
+}
+
+static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane)
+{
+	return tpg->twopixelsize[plane];
+}
+
+static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane)
+{
+	return tpg->bytesperline[plane];
+}
+
+static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl)
+{
+	tpg->bytesperline[plane] = bpl;
+}
+
+static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h)
+{
+	tpg->buf_height = h;
+}
+
+static inline void tpg_s_field(struct tpg_data *tpg, unsigned field)
+{
+	tpg->field = field;
+}
+
+static inline void tpg_s_perc_fill(struct tpg_data *tpg,
+				      unsigned perc_fill)
+{
+	tpg->perc_fill = perc_fill;
+}
+
+static inline unsigned tpg_g_perc_fill(const struct tpg_data *tpg)
+{
+	return tpg->perc_fill;
+}
+
+static inline void tpg_s_perc_fill_blank(struct tpg_data *tpg,
+					 bool perc_fill_blank)
+{
+	tpg->perc_fill_blank = perc_fill_blank;
+}
+
+static inline void tpg_s_video_aspect(struct tpg_data *tpg,
+					enum tpg_video_aspect vid_aspect)
+{
+	if (tpg->vid_aspect == vid_aspect)
+		return;
+	tpg->vid_aspect = vid_aspect;
+	tpg->recalc_square_border = true;
+}
+
+static inline enum tpg_video_aspect tpg_g_video_aspect(const struct tpg_data *tpg)
+{
+	return tpg->vid_aspect;
+}
+
+static inline void tpg_s_pixel_aspect(struct tpg_data *tpg,
+					enum tpg_pixel_aspect pix_aspect)
+{
+	if (tpg->pix_aspect == pix_aspect)
+		return;
+	tpg->pix_aspect = pix_aspect;
+	tpg->recalc_square_border = true;
+}
+
+static inline void tpg_s_show_border(struct tpg_data *tpg,
+					bool show_border)
+{
+	tpg->show_border = show_border;
+}
+
+static inline void tpg_s_show_square(struct tpg_data *tpg,
+					bool show_square)
+{
+	tpg->show_square = show_square;
+}
+
+static inline void tpg_s_insert_sav(struct tpg_data *tpg, bool insert_sav)
+{
+	tpg->insert_sav = insert_sav;
+}
+
+static inline void tpg_s_insert_eav(struct tpg_data *tpg, bool insert_eav)
+{
+	tpg->insert_eav = insert_eav;
+}
+
+void tpg_update_mv_step(struct tpg_data *tpg);
+
+static inline void tpg_s_mv_hor_mode(struct tpg_data *tpg,
+				enum tpg_move_mode mv_hor_mode)
+{
+	tpg->mv_hor_mode = mv_hor_mode;
+	tpg_update_mv_step(tpg);
+}
+
+static inline void tpg_s_mv_vert_mode(struct tpg_data *tpg,
+				enum tpg_move_mode mv_vert_mode)
+{
+	tpg->mv_vert_mode = mv_vert_mode;
+	tpg_update_mv_step(tpg);
+}
+
+static inline void tpg_init_mv_count(struct tpg_data *tpg)
+{
+	tpg->mv_hor_count = tpg->mv_vert_count = 0;
+}
+
+static inline void tpg_update_mv_count(struct tpg_data *tpg, bool frame_is_field)
+{
+	tpg->mv_hor_count += tpg->mv_hor_step * (frame_is_field ? 1 : 2);
+	tpg->mv_vert_count += tpg->mv_vert_step * (frame_is_field ? 1 : 2);
+}
+
+static inline void tpg_s_hflip(struct tpg_data *tpg, bool hflip)
+{
+	if (tpg->hflip == hflip)
+		return;
+	tpg->hflip = hflip;
+	tpg_update_mv_step(tpg);
+	tpg->recalc_lines = true;
+}
+
+static inline bool tpg_g_hflip(const struct tpg_data *tpg)
+{
+	return tpg->hflip;
+}
+
+static inline void tpg_s_vflip(struct tpg_data *tpg, bool vflip)
+{
+	tpg->vflip = vflip;
+}
+
+static inline bool tpg_g_vflip(const struct tpg_data *tpg)
+{
+	return tpg->vflip;
+}
+
+static inline bool tpg_pattern_is_static(const struct tpg_data *tpg)
+{
+	return tpg->pattern != TPG_PAT_NOISE &&
+	       tpg->mv_hor_mode == TPG_MOVE_NONE &&
+	       tpg->mv_vert_mode == TPG_MOVE_NONE;
+}
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c
new file mode 100644
index 0000000..2166d0b
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-vbi-cap.c
@@ -0,0 +1,371 @@
+/*
+ * vivid-vbi-cap.c - vbi capture support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+#include "vivid-core.h"
+#include "vivid-kthread-cap.h"
+#include "vivid-vbi-cap.h"
+#include "vivid-vbi-gen.h"
+
+static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr)
+{
+	struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen;
+	bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+
+	vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr);
+
+	if (!is_60hz) {
+		if (dev->loop_video) {
+			if (dev->vbi_out_have_wss) {
+				vbi_gen->data[12].data[0] = dev->vbi_out_wss[0];
+				vbi_gen->data[12].data[1] = dev->vbi_out_wss[1];
+			} else {
+				vbi_gen->data[12].id = 0;
+			}
+		} else {
+			switch (tpg_g_video_aspect(&dev->tpg)) {
+			case TPG_VIDEO_ASPECT_14X9_CENTRE:
+				vbi_gen->data[12].data[0] = 0x01;
+				break;
+			case TPG_VIDEO_ASPECT_16X9_CENTRE:
+				vbi_gen->data[12].data[0] = 0x0b;
+				break;
+			case TPG_VIDEO_ASPECT_16X9_ANAMORPHIC:
+				vbi_gen->data[12].data[0] = 0x07;
+				break;
+			case TPG_VIDEO_ASPECT_4X3:
+			default:
+				vbi_gen->data[12].data[0] = 0x08;
+				break;
+			}
+		}
+	} else if (dev->loop_video && is_60hz) {
+		if (dev->vbi_out_have_cc[0]) {
+			vbi_gen->data[0].data[0] = dev->vbi_out_cc[0][0];
+			vbi_gen->data[0].data[1] = dev->vbi_out_cc[0][1];
+		} else {
+			vbi_gen->data[0].id = 0;
+		}
+		if (dev->vbi_out_have_cc[1]) {
+			vbi_gen->data[1].data[0] = dev->vbi_out_cc[1][0];
+			vbi_gen->data[1].data[1] = dev->vbi_out_cc[1][1];
+		} else {
+			vbi_gen->data[1].id = 0;
+		}
+	}
+}
+
+static void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi)
+{
+	bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+
+	vbi->sampling_rate = 27000000;
+	vbi->offset = 24;
+	vbi->samples_per_line = 1440;
+	vbi->sample_format = V4L2_PIX_FMT_GREY;
+	vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5;
+	vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5;
+	vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18;
+	vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0;
+	vbi->reserved[0] = 0;
+	vbi->reserved[1] = 0;
+}
+
+void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+	struct v4l2_vbi_format vbi;
+	u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+
+	vivid_g_fmt_vbi_cap(dev, &vbi);
+	buf->vb.v4l2_buf.sequence = dev->vbi_cap_seq_count;
+	if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+		buf->vb.v4l2_buf.sequence /= 2;
+
+	vivid_sliced_vbi_cap_fill(dev, buf->vb.v4l2_buf.sequence);
+
+	memset(vbuf, 0x10, vb2_plane_size(&buf->vb, 0));
+
+	if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode))
+		vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf);
+
+	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+	buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+}
+
+
+void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+	struct v4l2_sliced_vbi_data *vbuf = vb2_plane_vaddr(&buf->vb, 0);
+
+	buf->vb.v4l2_buf.sequence = dev->vbi_cap_seq_count;
+	if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+		buf->vb.v4l2_buf.sequence /= 2;
+
+	vivid_sliced_vbi_cap_fill(dev, buf->vb.v4l2_buf.sequence);
+
+	memset(vbuf, 0, vb2_plane_size(&buf->vb, 0));
+	if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) {
+		unsigned i;
+
+		for (i = 0; i < 25; i++)
+			vbuf[i] = dev->vbi_gen.data[i];
+	}
+
+	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+	buf->vb.v4l2_buf.timestamp.tv_sec += dev->time_wrap_offset;
+}
+
+static int vbi_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+		       unsigned *nbuffers, unsigned *nplanes,
+		       unsigned sizes[], void *alloc_ctxs[])
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+	bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+	unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ?
+		36 * sizeof(struct v4l2_sliced_vbi_data) :
+		1440 * 2 * (is_60hz ? 12 : 18);
+
+	if (!vivid_is_sdtv_cap(dev))
+		return -EINVAL;
+
+	sizes[0] = size;
+
+	if (vq->num_buffers + *nbuffers < 2)
+		*nbuffers = 2 - vq->num_buffers;
+
+	*nplanes = 1;
+	return 0;
+}
+
+static int vbi_cap_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+	unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ?
+		36 * sizeof(struct v4l2_sliced_vbi_data) :
+		1440 * 2 * (is_60hz ? 12 : 18);
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	if (dev->buf_prepare_error) {
+		/*
+		 * Error injection: test what happens if buf_prepare() returns
+		 * an error.
+		 */
+		dev->buf_prepare_error = false;
+		return -EINVAL;
+	}
+	if (vb2_plane_size(vb, 0) < size) {
+		dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+				__func__, vb2_plane_size(vb, 0), size);
+		return -EINVAL;
+	}
+	vb2_set_plane_payload(vb, 0, size);
+
+	return 0;
+}
+
+static void vbi_cap_buf_queue(struct vb2_buffer *vb)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	spin_lock(&dev->slock);
+	list_add_tail(&buf->list, &dev->vbi_cap_active);
+	spin_unlock(&dev->slock);
+}
+
+static int vbi_cap_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+	int err;
+
+	dprintk(dev, 1, "%s\n", __func__);
+	dev->vbi_cap_seq_count = 0;
+	if (dev->start_streaming_error) {
+		dev->start_streaming_error = false;
+		err = -EINVAL;
+	} else {
+		err = vivid_start_generating_vid_cap(dev, &dev->vbi_cap_streaming);
+	}
+	if (err) {
+		struct vivid_buffer *buf, *tmp;
+
+		list_for_each_entry_safe(buf, tmp, &dev->vbi_cap_active, list) {
+			list_del(&buf->list);
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+		}
+	}
+	return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void vbi_cap_stop_streaming(struct vb2_queue *vq)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+	dprintk(dev, 1, "%s\n", __func__);
+	vivid_stop_generating_vid_cap(dev, &dev->vbi_cap_streaming);
+}
+
+const struct vb2_ops vivid_vbi_cap_qops = {
+	.queue_setup		= vbi_cap_queue_setup,
+	.buf_prepare		= vbi_cap_buf_prepare,
+	.buf_queue		= vbi_cap_buf_queue,
+	.start_streaming	= vbi_cap_start_streaming,
+	.stop_streaming		= vbi_cap_stop_streaming,
+	.wait_prepare		= vivid_unlock,
+	.wait_finish		= vivid_lock,
+};
+
+int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_vbi_format *vbi = &f->fmt.vbi;
+
+	if (!vivid_is_sdtv_cap(dev) || !dev->has_raw_vbi_cap)
+		return -EINVAL;
+
+	vivid_g_fmt_vbi_cap(dev, vbi);
+	return 0;
+}
+
+int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	int ret = vidioc_g_fmt_vbi_cap(file, priv, f);
+
+	if (ret)
+		return ret;
+	if (dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q))
+		return -EBUSY;
+	dev->stream_sliced_vbi_cap = false;
+	dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+	return 0;
+}
+
+void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set)
+{
+	vbi->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+	vbi->service_set = service_set;
+	memset(vbi->service_lines, 0, sizeof(vbi->service_lines));
+	memset(vbi->reserved, 0, sizeof(vbi->reserved));
+
+	if (vbi->service_set == 0)
+		return;
+
+	if (vbi->service_set & V4L2_SLICED_CAPTION_525) {
+		vbi->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+		vbi->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+	}
+	if (vbi->service_set & V4L2_SLICED_WSS_625) {
+		unsigned i;
+
+		for (i = 7; i <= 18; i++)
+			vbi->service_lines[0][i] =
+			vbi->service_lines[1][i] = V4L2_SLICED_TELETEXT_B;
+		vbi->service_lines[0][23] = V4L2_SLICED_WSS_625;
+	}
+}
+
+int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+
+	if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap)
+		return -EINVAL;
+
+	vivid_fill_service_lines(vbi, dev->service_set_cap);
+	return 0;
+}
+
+int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+	bool is_60hz = dev->std_cap & V4L2_STD_525_60;
+	u32 service_set = vbi->service_set;
+
+	if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap)
+		return -EINVAL;
+
+	service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 :
+				 V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+	vivid_fill_service_lines(vbi, service_set);
+	return 0;
+}
+
+int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+	int ret = vidioc_try_fmt_sliced_vbi_cap(file, fh, fmt);
+
+	if (ret)
+		return ret;
+	if (!dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q))
+		return -EBUSY;
+	dev->service_set_cap = vbi->service_set;
+	dev->stream_sliced_vbi_cap = true;
+	dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+	return 0;
+}
+
+int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct video_device *vdev = video_devdata(file);
+	bool is_60hz;
+
+	if (vdev->vfl_dir == VFL_DIR_RX) {
+		is_60hz = dev->std_cap & V4L2_STD_525_60;
+		if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap ||
+		    cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+			return -EINVAL;
+	} else {
+		is_60hz = dev->std_out & V4L2_STD_525_60;
+		if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out ||
+		    cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
+			return -EINVAL;
+	}
+
+	cap->service_set = is_60hz ? V4L2_SLICED_CAPTION_525 :
+				     V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+	if (is_60hz) {
+		cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+		cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+	} else {
+		unsigned i;
+
+		for (i = 7; i <= 18; i++)
+			cap->service_lines[0][i] =
+			cap->service_lines[1][i] = V4L2_SLICED_TELETEXT_B;
+		cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+	}
+	return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.h b/drivers/media/platform/vivid/vivid-vbi-cap.h
new file mode 100644
index 0000000..2d8ea0b
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-vbi-cap.h
@@ -0,0 +1,40 @@
+/*
+ * vivid-vbi-cap.h - vbi capture support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_VBI_CAP_H_
+#define _VIVID_VBI_CAP_H_
+
+void vivid_fill_time_of_day_packet(u8 *packet);
+void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+					struct v4l2_format *f);
+int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
+					struct v4l2_format *f);
+int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap);
+
+void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set);
+
+extern const struct vb2_ops vivid_vbi_cap_qops;
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.c b/drivers/media/platform/vivid/vivid-vbi-gen.c
new file mode 100644
index 0000000..a2159de
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-vbi-gen.c
@@ -0,0 +1,323 @@
+/*
+ * vivid-vbi-gen.c - vbi generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/string.h>
+#include <linux/videodev2.h>
+
+#include "vivid-vbi-gen.h"
+
+static void wss_insert(u8 *wss, u32 val, unsigned size)
+{
+	while (size--)
+		*wss++ = (val & (1 << size)) ? 0xc0 : 0x10;
+}
+
+static void vivid_vbi_gen_wss_raw(const struct v4l2_sliced_vbi_data *data,
+		u8 *buf, unsigned sampling_rate)
+{
+	const unsigned rate = 5000000;	/* WSS has a 5 MHz transmission rate */
+	u8 wss[29 + 24 + 24 + 24 + 18 + 18] = { 0 };
+	const unsigned zero = 0x07;
+	const unsigned one = 0x38;
+	unsigned bit = 0;
+	u16 wss_data;
+	int i;
+
+	wss_insert(wss + bit, 0x1f1c71c7, 29); bit += 29;
+	wss_insert(wss + bit, 0x1e3c1f, 24); bit += 24;
+
+	wss_data = (data->data[1] << 8) | data->data[0];
+	for (i = 0; i <= 13; i++, bit += 6)
+		wss_insert(wss + bit, (wss_data & (1 << i)) ? one : zero, 6);
+
+	for (i = 0, bit = 0; bit < sizeof(wss); bit++) {
+		unsigned n = ((bit + 1) * sampling_rate) / rate;
+
+		while (i < n)
+			buf[i++] = wss[bit];
+	}
+}
+
+static void vivid_vbi_gen_teletext_raw(const struct v4l2_sliced_vbi_data *data,
+		u8 *buf, unsigned sampling_rate)
+{
+	const unsigned rate = 6937500 / 10;	/* Teletext has a 6.9375 MHz transmission rate */
+	u8 teletext[45] = { 0x55, 0x55, 0x27 };
+	unsigned bit = 0;
+	int i;
+
+	memcpy(teletext + 3, data->data, sizeof(teletext) - 3);
+	/* prevents 32 bit overflow */
+	sampling_rate /= 10;
+
+	for (i = 0, bit = 0; bit < sizeof(teletext) * 8; bit++) {
+		unsigned n = ((bit + 1) * sampling_rate) / rate;
+		u8 val = (teletext[bit / 8] & (1 << (bit & 7))) ? 0xc0 : 0x10;
+
+		while (i < n)
+			buf[i++] = val;
+	}
+}
+
+static void cc_insert(u8 *cc, u8 ch)
+{
+	unsigned tot = 0;
+	unsigned i;
+
+	for (i = 0; i < 7; i++) {
+		cc[2 * i] = cc[2 * i + 1] = (ch & (1 << i)) ? 1 : 0;
+		tot += cc[2 * i];
+	}
+	cc[14] = cc[15] = !(tot & 1);
+}
+
+#define CC_PREAMBLE_BITS (14 + 4 + 2)
+
+static void vivid_vbi_gen_cc_raw(const struct v4l2_sliced_vbi_data *data,
+		u8 *buf, unsigned sampling_rate)
+{
+	const unsigned rate = 1000000;	/* CC has a 1 MHz transmission rate */
+
+	u8 cc[CC_PREAMBLE_BITS + 2 * 16] = {
+		/* Clock run-in: 7 cycles */
+		0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+		/* 2 cycles of 0 */
+		0, 0, 0, 0,
+		/* Start bit of 1 (each bit is two cycles) */
+		1, 1
+	};
+	unsigned bit, i;
+
+	cc_insert(cc + CC_PREAMBLE_BITS, data->data[0]);
+	cc_insert(cc + CC_PREAMBLE_BITS + 16, data->data[1]);
+
+	for (i = 0, bit = 0; bit < sizeof(cc); bit++) {
+		unsigned n = ((bit + 1) * sampling_rate) / rate;
+
+		while (i < n)
+			buf[i++] = cc[bit] ? 0xc0 : 0x10;
+	}
+}
+
+void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi,
+		const struct v4l2_vbi_format *vbi_fmt, u8 *buf)
+{
+	unsigned idx;
+
+	for (idx = 0; idx < 25; idx++) {
+		const struct v4l2_sliced_vbi_data *data = vbi->data + idx;
+		unsigned start_2nd_field;
+		unsigned line = data->line;
+		u8 *linebuf = buf;
+
+		start_2nd_field = (data->id & V4L2_SLICED_VBI_525) ? 263 : 313;
+		if (data->field)
+			line += start_2nd_field;
+		line -= vbi_fmt->start[data->field];
+
+		if (vbi_fmt->flags & V4L2_VBI_INTERLACED)
+			linebuf += (line * 2 + data->field) *
+				vbi_fmt->samples_per_line;
+		else
+			linebuf += (line + data->field * vbi_fmt->count[0]) *
+				vbi_fmt->samples_per_line;
+		if (data->id == V4L2_SLICED_CAPTION_525)
+			vivid_vbi_gen_cc_raw(data, linebuf, vbi_fmt->sampling_rate);
+		else if (data->id == V4L2_SLICED_WSS_625)
+			vivid_vbi_gen_wss_raw(data, linebuf, vbi_fmt->sampling_rate);
+		else if (data->id == V4L2_SLICED_TELETEXT_B)
+			vivid_vbi_gen_teletext_raw(data, linebuf, vbi_fmt->sampling_rate);
+	}
+}
+
+static const u8 vivid_cc_sequence1[30] = {
+	0x14, 0x20,	/* Resume Caption Loading */
+	'H',  'e',
+	'l',  'l',
+	'o',  ' ',
+	'w',  'o',
+	'r',  'l',
+	'd',  '!',
+	0x14, 0x2f,	/* End of Caption */
+};
+
+static const u8 vivid_cc_sequence2[30] = {
+	0x14, 0x20,	/* Resume Caption Loading */
+	'C',  'l',
+	'o',  's',
+	'e',  'd',
+	' ',  'c',
+	'a',  'p',
+	't',  'i',
+	'o',  'n',
+	's',  ' ',
+	't',  'e',
+	's',  't',
+	0x14, 0x2f,	/* End of Caption */
+};
+
+static u8 calc_parity(u8 val)
+{
+	unsigned i;
+	unsigned tot = 0;
+
+	for (i = 0; i < 7; i++)
+		tot += (val & (1 << i)) ? 1 : 0;
+	return val | ((tot & 1) ? 0 : 0x80);
+}
+
+static void vivid_vbi_gen_set_time_of_day(u8 *packet)
+{
+	struct tm tm;
+	u8 checksum, i;
+
+	time_to_tm(get_seconds(), 0, &tm);
+	packet[0] = calc_parity(0x07);
+	packet[1] = calc_parity(0x01);
+	packet[2] = calc_parity(0x40 | tm.tm_min);
+	packet[3] = calc_parity(0x40 | tm.tm_hour);
+	packet[4] = calc_parity(0x40 | tm.tm_mday);
+	if (tm.tm_mday == 1 && tm.tm_mon == 2 &&
+	    sys_tz.tz_minuteswest > tm.tm_min + tm.tm_hour * 60)
+		packet[4] = calc_parity(0x60 | tm.tm_mday);
+	packet[5] = calc_parity(0x40 | (1 + tm.tm_mon));
+	packet[6] = calc_parity(0x40 | (1 + tm.tm_wday));
+	packet[7] = calc_parity(0x40 | ((tm.tm_year - 90) & 0x3f));
+	packet[8] = calc_parity(0x0f);
+	for (checksum = i = 0; i <= 8; i++)
+		checksum += packet[i] & 0x7f;
+	packet[9] = calc_parity(0x100 - checksum);
+	checksum = 0;
+	packet[10] = calc_parity(0x07);
+	packet[11] = calc_parity(0x04);
+	if (sys_tz.tz_minuteswest >= 0)
+		packet[12] = calc_parity(0x40 | ((sys_tz.tz_minuteswest / 60) & 0x1f));
+	else
+		packet[12] = calc_parity(0x40 | ((24 + sys_tz.tz_minuteswest / 60) & 0x1f));
+	packet[13] = calc_parity(0);
+	packet[14] = calc_parity(0x0f);
+	for (checksum = 0, i = 10; i <= 14; i++)
+		checksum += packet[i] & 0x7f;
+	packet[15] = calc_parity(0x100 - checksum);
+}
+
+static const u8 hamming[16] = {
+	0x15, 0x02, 0x49, 0x5e, 0x64, 0x73, 0x38, 0x2f,
+	0xd0, 0xc7, 0x8c, 0x9b, 0xa1, 0xb6, 0xfd, 0xea
+};
+
+static void vivid_vbi_gen_teletext(u8 *packet, unsigned line, unsigned frame)
+{
+	unsigned offset = 2;
+	unsigned i;
+
+	packet[0] = hamming[1 + ((line & 1) << 3)];
+	packet[1] = hamming[line >> 1];
+	memset(packet + 2, 0x20, 40);
+	if (line == 0) {
+		/* subcode */
+		packet[2] = hamming[frame % 10];
+		packet[3] = hamming[frame / 10];
+		packet[4] = hamming[0];
+		packet[5] = hamming[0];
+		packet[6] = hamming[0];
+		packet[7] = hamming[0];
+		packet[8] = hamming[0];
+		packet[9] = hamming[1];
+		offset = 10;
+	}
+	packet += offset;
+	memcpy(packet, "Page: 100 Row: 10", 17);
+	packet[7] = '0' + frame / 10;
+	packet[8] = '0' + frame % 10;
+	packet[15] = '0' + line / 10;
+	packet[16] = '0' + line % 10;
+	for (i = 0; i < 42 - offset; i++)
+		packet[i] = calc_parity(packet[i]);
+}
+
+void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi,
+		bool is_60hz, unsigned seqnr)
+{
+	struct v4l2_sliced_vbi_data *data0 = vbi->data;
+	struct v4l2_sliced_vbi_data *data1 = vbi->data + 1;
+	unsigned frame = seqnr % 60;
+
+	memset(vbi->data, 0, sizeof(vbi->data));
+
+	if (!is_60hz) {
+		unsigned i;
+
+		for (i = 0; i <= 11; i++) {
+			data0->id = V4L2_SLICED_TELETEXT_B;
+			data0->line = 7 + i;
+			vivid_vbi_gen_teletext(data0->data, i, frame);
+			data0++;
+		}
+		data0->id = V4L2_SLICED_WSS_625;
+		data0->line = 23;
+		/* 4x3 video aspect ratio */
+		data0->data[0] = 0x08;
+		data0++;
+		for (i = 0; i <= 11; i++) {
+			data0->id = V4L2_SLICED_TELETEXT_B;
+			data0->field = 1;
+			data0->line = 7 + i;
+			vivid_vbi_gen_teletext(data0->data, 12 + i, frame);
+			data0++;
+		}
+		return;
+	}
+
+	data0->id = V4L2_SLICED_CAPTION_525;
+	data0->line = 21;
+	data1->id = V4L2_SLICED_CAPTION_525;
+	data1->field = 1;
+	data1->line = 21;
+
+	if (frame < 15) {
+		data0->data[0] = calc_parity(vivid_cc_sequence1[2 * frame]);
+		data0->data[1] = calc_parity(vivid_cc_sequence1[2 * frame + 1]);
+	} else if (frame >= 30 && frame < 45) {
+		frame -= 30;
+		data0->data[0] = calc_parity(vivid_cc_sequence2[2 * frame]);
+		data0->data[1] = calc_parity(vivid_cc_sequence2[2 * frame + 1]);
+	} else {
+		data0->data[0] = calc_parity(0);
+		data0->data[1] = calc_parity(0);
+	}
+
+	frame = seqnr % (30 * 60);
+	switch (frame) {
+	case 0:
+		vivid_vbi_gen_set_time_of_day(vbi->time_of_day_packet);
+		/* fall through */
+	case 1 ... 7:
+		data1->data[0] = vbi->time_of_day_packet[frame * 2];
+		data1->data[1] = vbi->time_of_day_packet[frame * 2 + 1];
+		break;
+	default:
+		data1->data[0] = calc_parity(0);
+		data1->data[1] = calc_parity(0);
+		break;
+	}
+}
diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.h b/drivers/media/platform/vivid/vivid-vbi-gen.h
new file mode 100644
index 0000000..8444abe
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-vbi-gen.h
@@ -0,0 +1,33 @@
+/*
+ * vivid-vbi-gen.h - vbi generator support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_VBI_GEN_H_
+#define _VIVID_VBI_GEN_H_
+
+struct vivid_vbi_gen_data {
+	struct v4l2_sliced_vbi_data data[25];
+	u8 time_of_day_packet[16];
+};
+
+void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi,
+		bool is_60hz, unsigned seqnr);
+void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi,
+		const struct v4l2_vbi_format *vbi_fmt, u8 *buf);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c
new file mode 100644
index 0000000..9d00a07
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-vbi-out.c
@@ -0,0 +1,248 @@
+/*
+ * vivid-vbi-out.c - vbi output support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+#include "vivid-core.h"
+#include "vivid-kthread-out.h"
+#include "vivid-vbi-out.h"
+#include "vivid-vbi-cap.h"
+
+static int vbi_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+		       unsigned *nbuffers, unsigned *nplanes,
+		       unsigned sizes[], void *alloc_ctxs[])
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+	bool is_60hz = dev->std_out & V4L2_STD_525_60;
+	unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ?
+		36 * sizeof(struct v4l2_sliced_vbi_data) :
+		1440 * 2 * (is_60hz ? 12 : 18);
+
+	if (!vivid_is_svid_out(dev))
+		return -EINVAL;
+
+	sizes[0] = size;
+
+	if (vq->num_buffers + *nbuffers < 2)
+		*nbuffers = 2 - vq->num_buffers;
+
+	*nplanes = 1;
+	return 0;
+}
+
+static int vbi_out_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	bool is_60hz = dev->std_out & V4L2_STD_525_60;
+	unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ?
+		36 * sizeof(struct v4l2_sliced_vbi_data) :
+		1440 * 2 * (is_60hz ? 12 : 18);
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	if (dev->buf_prepare_error) {
+		/*
+		 * Error injection: test what happens if buf_prepare() returns
+		 * an error.
+		 */
+		dev->buf_prepare_error = false;
+		return -EINVAL;
+	}
+	if (vb2_plane_size(vb, 0) < size) {
+		dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+				__func__, vb2_plane_size(vb, 0), size);
+		return -EINVAL;
+	}
+	vb2_set_plane_payload(vb, 0, size);
+
+	return 0;
+}
+
+static void vbi_out_buf_queue(struct vb2_buffer *vb)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	spin_lock(&dev->slock);
+	list_add_tail(&buf->list, &dev->vbi_out_active);
+	spin_unlock(&dev->slock);
+}
+
+static int vbi_out_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+	int err;
+
+	dprintk(dev, 1, "%s\n", __func__);
+	dev->vbi_out_seq_count = 0;
+	if (dev->start_streaming_error) {
+		dev->start_streaming_error = false;
+		err = -EINVAL;
+	} else {
+		err = vivid_start_generating_vid_out(dev, &dev->vbi_out_streaming);
+	}
+	if (err) {
+		struct vivid_buffer *buf, *tmp;
+
+		list_for_each_entry_safe(buf, tmp, &dev->vbi_out_active, list) {
+			list_del(&buf->list);
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+		}
+	}
+	return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void vbi_out_stop_streaming(struct vb2_queue *vq)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+	dprintk(dev, 1, "%s\n", __func__);
+	vivid_stop_generating_vid_out(dev, &dev->vbi_out_streaming);
+	dev->vbi_out_have_wss = false;
+	dev->vbi_out_have_cc[0] = false;
+	dev->vbi_out_have_cc[1] = false;
+}
+
+const struct vb2_ops vivid_vbi_out_qops = {
+	.queue_setup		= vbi_out_queue_setup,
+	.buf_prepare		= vbi_out_buf_prepare,
+	.buf_queue		= vbi_out_buf_queue,
+	.start_streaming	= vbi_out_start_streaming,
+	.stop_streaming		= vbi_out_stop_streaming,
+	.wait_prepare		= vivid_unlock,
+	.wait_finish		= vivid_lock,
+};
+
+int vidioc_g_fmt_vbi_out(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_vbi_format *vbi = &f->fmt.vbi;
+	bool is_60hz = dev->std_out & V4L2_STD_525_60;
+
+	if (!vivid_is_svid_out(dev) || !dev->has_raw_vbi_out)
+		return -EINVAL;
+
+	vbi->sampling_rate = 25000000;
+	vbi->offset = 24;
+	vbi->samples_per_line = 1440;
+	vbi->sample_format = V4L2_PIX_FMT_GREY;
+	vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5;
+	vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5;
+	vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18;
+	vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0;
+	vbi->reserved[0] = 0;
+	vbi->reserved[1] = 0;
+	return 0;
+}
+
+int vidioc_s_fmt_vbi_out(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	int ret = vidioc_g_fmt_vbi_out(file, priv, f);
+
+	if (ret)
+		return ret;
+	if (vb2_is_busy(&dev->vb_vbi_out_q))
+		return -EBUSY;
+	dev->stream_sliced_vbi_out = false;
+	dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_VBI_OUTPUT;
+	return 0;
+}
+
+int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+
+	if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out)
+		return -EINVAL;
+
+	vivid_fill_service_lines(vbi, dev->service_set_out);
+	return 0;
+}
+
+int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+	bool is_60hz = dev->std_out & V4L2_STD_525_60;
+	u32 service_set = vbi->service_set;
+
+	if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out)
+		return -EINVAL;
+
+	service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 :
+				 V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+	vivid_fill_service_lines(vbi, service_set);
+	return 0;
+}
+
+int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced;
+	int ret = vidioc_try_fmt_sliced_vbi_out(file, fh, fmt);
+
+	if (ret)
+		return ret;
+	if (vb2_is_busy(&dev->vb_vbi_out_q))
+		return -EBUSY;
+	dev->service_set_out = vbi->service_set;
+	dev->stream_sliced_vbi_out = true;
+	dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
+	return 0;
+}
+
+void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+	struct v4l2_sliced_vbi_data *vbi = vb2_plane_vaddr(&buf->vb, 0);
+	unsigned elems = vb2_get_plane_payload(&buf->vb, 0) / sizeof(*vbi);
+
+	dev->vbi_out_have_cc[0] = false;
+	dev->vbi_out_have_cc[1] = false;
+	dev->vbi_out_have_wss = false;
+	while (elems--) {
+		switch (vbi->id) {
+		case V4L2_SLICED_CAPTION_525:
+			if ((dev->std_out & V4L2_STD_525_60) && vbi->line == 21) {
+				dev->vbi_out_have_cc[!!vbi->field] = true;
+				dev->vbi_out_cc[!!vbi->field][0] = vbi->data[0];
+				dev->vbi_out_cc[!!vbi->field][1] = vbi->data[1];
+			}
+			break;
+		case V4L2_SLICED_WSS_625:
+			if ((dev->std_out & V4L2_STD_625_50) &&
+			    vbi->field == 0 && vbi->line == 23) {
+				dev->vbi_out_have_wss = true;
+				dev->vbi_out_wss[0] = vbi->data[0];
+				dev->vbi_out_wss[1] = vbi->data[1];
+			}
+			break;
+		}
+		vbi++;
+	}
+}
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.h b/drivers/media/platform/vivid/vivid-vbi-out.h
new file mode 100644
index 0000000..6555ba9
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-vbi-out.h
@@ -0,0 +1,34 @@
+/*
+ * vivid-vbi-out.h - vbi output support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_VBI_OUT_H_
+#define _VIVID_VBI_OUT_H_
+
+void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+int vidioc_g_fmt_vbi_out(struct file *file, void *priv,
+					struct v4l2_format *f);
+int vidioc_s_fmt_vbi_out(struct file *file, void *priv,
+					struct v4l2_format *f);
+int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt);
+int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt);
+
+extern const struct vb2_ops vivid_vbi_out_qops;
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
new file mode 100644
index 0000000..331c544
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -0,0 +1,1730 @@
+/*
+ * vivid-vid-cap.c - video capture support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-kthread-cap.h"
+#include "vivid-vid-cap.h"
+
+/* timeperframe: min/max and default */
+static const struct v4l2_fract
+	tpf_min     = {.numerator = 1,		.denominator = FPS_MAX},
+	tpf_max     = {.numerator = FPS_MAX,	.denominator = 1},
+	tpf_default = {.numerator = 1,		.denominator = 30};
+
+static const struct vivid_fmt formats_ovl[] = {
+	{
+		.name     = "RGB565 (LE)",
+		.fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+		.depth    = 16,
+		.planes   = 1,
+	},
+	{
+		.name     = "XRGB555 (LE)",
+		.fourcc   = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */
+		.depth    = 16,
+		.planes   = 1,
+	},
+	{
+		.name     = "ARGB555 (LE)",
+		.fourcc   = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */
+		.depth    = 16,
+		.planes   = 1,
+	},
+};
+
+/* The number of discrete webcam framesizes */
+#define VIVID_WEBCAM_SIZES 3
+/* The number of discrete webcam frameintervals */
+#define VIVID_WEBCAM_IVALS (VIVID_WEBCAM_SIZES * 2)
+
+/* Sizes must be in increasing order */
+static const struct v4l2_frmsize_discrete webcam_sizes[VIVID_WEBCAM_SIZES] = {
+	{  320, 180 },
+	{  640, 360 },
+	{ 1280, 720 },
+};
+
+/*
+ * Intervals must be in increasing order and there must be twice as many
+ * elements in this array as there are in webcam_sizes.
+ */
+static const struct v4l2_fract webcam_intervals[VIVID_WEBCAM_IVALS] = {
+	{  1, 10 },
+	{  1, 15 },
+	{  1, 25 },
+	{  1, 30 },
+	{  1, 50 },
+	{  1, 60 },
+};
+
+static const struct v4l2_discrete_probe webcam_probe = {
+	webcam_sizes,
+	VIVID_WEBCAM_SIZES
+};
+
+static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+		       unsigned *nbuffers, unsigned *nplanes,
+		       unsigned sizes[], void *alloc_ctxs[])
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+	unsigned planes = tpg_g_planes(&dev->tpg);
+	unsigned h = dev->fmt_cap_rect.height;
+	unsigned p;
+
+	if (dev->field_cap == V4L2_FIELD_ALTERNATE) {
+		/*
+		 * You cannot use read() with FIELD_ALTERNATE since the field
+		 * information (TOP/BOTTOM) cannot be passed back to the user.
+		 */
+		if (vb2_fileio_is_active(vq))
+			return -EINVAL;
+	}
+
+	if (dev->queue_setup_error) {
+		/*
+		 * Error injection: test what happens if queue_setup() returns
+		 * an error.
+		 */
+		dev->queue_setup_error = false;
+		return -EINVAL;
+	}
+	if (fmt) {
+		const struct v4l2_pix_format_mplane *mp;
+		struct v4l2_format mp_fmt;
+		const struct vivid_fmt *vfmt;
+
+		if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+			fmt_sp2mp(fmt, &mp_fmt);
+			fmt = &mp_fmt;
+		}
+		mp = &fmt->fmt.pix_mp;
+		/*
+		 * Check if the number of planes in the specified format match
+		 * the number of planes in the current format. You can't mix that.
+		 */
+		if (mp->num_planes != planes)
+			return -EINVAL;
+		vfmt = vivid_get_format(dev, mp->pixelformat);
+		for (p = 0; p < planes; p++) {
+			sizes[p] = mp->plane_fmt[p].sizeimage;
+			if (sizes[0] < tpg_g_bytesperline(&dev->tpg, 0) * h +
+							vfmt->data_offset[p])
+				return -EINVAL;
+		}
+	} else {
+		for (p = 0; p < planes; p++)
+			sizes[p] = tpg_g_bytesperline(&dev->tpg, p) * h +
+					dev->fmt_cap->data_offset[p];
+	}
+
+	if (vq->num_buffers + *nbuffers < 2)
+		*nbuffers = 2 - vq->num_buffers;
+
+	*nplanes = planes;
+
+	/*
+	 * videobuf2-vmalloc allocator is context-less so no need to set
+	 * alloc_ctxs array.
+	 */
+
+	if (planes == 2)
+		dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__,
+			*nbuffers, sizes[0], sizes[1]);
+	else
+		dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__,
+			*nbuffers, sizes[0]);
+
+	return 0;
+}
+
+static int vid_cap_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	unsigned long size;
+	unsigned planes = tpg_g_planes(&dev->tpg);
+	unsigned p;
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	if (WARN_ON(NULL == dev->fmt_cap))
+		return -EINVAL;
+
+	if (dev->buf_prepare_error) {
+		/*
+		 * Error injection: test what happens if buf_prepare() returns
+		 * an error.
+		 */
+		dev->buf_prepare_error = false;
+		return -EINVAL;
+	}
+	for (p = 0; p < planes; p++) {
+		size = tpg_g_bytesperline(&dev->tpg, p) * dev->fmt_cap_rect.height +
+			dev->fmt_cap->data_offset[p];
+
+		if (vb2_plane_size(vb, 0) < size) {
+			dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n",
+					__func__, p, vb2_plane_size(vb, 0), size);
+			return -EINVAL;
+		}
+
+		vb2_set_plane_payload(vb, p, size);
+		vb->v4l2_planes[p].data_offset = dev->fmt_cap->data_offset[p];
+	}
+
+	return 0;
+}
+
+static void vid_cap_buf_finish(struct vb2_buffer *vb)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct v4l2_timecode *tc = &vb->v4l2_buf.timecode;
+	unsigned fps = 25;
+	unsigned seq = vb->v4l2_buf.sequence;
+
+	if (!vivid_is_sdtv_cap(dev))
+		return;
+
+	/*
+	 * Set the timecode. Rarely used, so it is interesting to
+	 * test this.
+	 */
+	vb->v4l2_buf.flags |= V4L2_BUF_FLAG_TIMECODE;
+	if (dev->std_cap & V4L2_STD_525_60)
+		fps = 30;
+	tc->type = (fps == 30) ? V4L2_TC_TYPE_30FPS : V4L2_TC_TYPE_25FPS;
+	tc->flags = 0;
+	tc->frames = seq % fps;
+	tc->seconds = (seq / fps) % 60;
+	tc->minutes = (seq / (60 * fps)) % 60;
+	tc->hours = (seq / (60 * 60 * fps)) % 24;
+}
+
+static void vid_cap_buf_queue(struct vb2_buffer *vb)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	spin_lock(&dev->slock);
+	list_add_tail(&buf->list, &dev->vid_cap_active);
+	spin_unlock(&dev->slock);
+}
+
+static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+	unsigned i;
+	int err;
+
+	if (vb2_is_streaming(&dev->vb_vid_out_q))
+		dev->can_loop_video = vivid_vid_can_loop(dev);
+
+	if (dev->kthread_vid_cap)
+		return 0;
+
+	dev->vid_cap_seq_count = 0;
+	dprintk(dev, 1, "%s\n", __func__);
+	for (i = 0; i < VIDEO_MAX_FRAME; i++)
+		dev->must_blank[i] = tpg_g_perc_fill(&dev->tpg) < 100;
+	if (dev->start_streaming_error) {
+		dev->start_streaming_error = false;
+		err = -EINVAL;
+	} else {
+		err = vivid_start_generating_vid_cap(dev, &dev->vid_cap_streaming);
+	}
+	if (err) {
+		struct vivid_buffer *buf, *tmp;
+
+		list_for_each_entry_safe(buf, tmp, &dev->vid_cap_active, list) {
+			list_del(&buf->list);
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+		}
+	}
+	return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void vid_cap_stop_streaming(struct vb2_queue *vq)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+	dprintk(dev, 1, "%s\n", __func__);
+	vivid_stop_generating_vid_cap(dev, &dev->vid_cap_streaming);
+	dev->can_loop_video = false;
+}
+
+const struct vb2_ops vivid_vid_cap_qops = {
+	.queue_setup		= vid_cap_queue_setup,
+	.buf_prepare		= vid_cap_buf_prepare,
+	.buf_finish		= vid_cap_buf_finish,
+	.buf_queue		= vid_cap_buf_queue,
+	.start_streaming	= vid_cap_start_streaming,
+	.stop_streaming		= vid_cap_stop_streaming,
+	.wait_prepare		= vivid_unlock,
+	.wait_finish		= vivid_lock,
+};
+
+/*
+ * Determine the 'picture' quality based on the current TV frequency: either
+ * COLOR for a good 'signal', GRAY (grayscale picture) for a slightly off
+ * signal or NOISE for no signal.
+ */
+void vivid_update_quality(struct vivid_dev *dev)
+{
+	unsigned freq_modulus;
+
+	if (dev->loop_video && (vivid_is_svid_cap(dev) || vivid_is_hdmi_cap(dev))) {
+		/*
+		 * The 'noise' will only be replaced by the actual video
+		 * if the output video matches the input video settings.
+		 */
+		tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
+		return;
+	}
+	if (vivid_is_hdmi_cap(dev) && VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode)) {
+		tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
+		return;
+	}
+	if (vivid_is_sdtv_cap(dev) && VIVID_INVALID_SIGNAL(dev->std_signal_mode)) {
+		tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0);
+		return;
+	}
+	if (!vivid_is_tv_cap(dev)) {
+		tpg_s_quality(&dev->tpg, TPG_QUAL_COLOR, 0);
+		return;
+	}
+
+	/*
+	 * There is a fake channel every 6 MHz at 49.25, 55.25, etc.
+	 * From +/- 0.25 MHz around the channel there is color, and from
+	 * +/- 1 MHz there is grayscale (chroma is lost).
+	 * Everywhere else it is just noise.
+	 */
+	freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16);
+	if (freq_modulus > 2 * 16) {
+		tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE,
+			next_pseudo_random32(dev->tv_freq ^ 0x55) & 0x3f);
+		return;
+	}
+	if (freq_modulus < 12 /*0.75 * 16*/ || freq_modulus > 20 /*1.25 * 16*/)
+		tpg_s_quality(&dev->tpg, TPG_QUAL_GRAY, 0);
+	else
+		tpg_s_quality(&dev->tpg, TPG_QUAL_COLOR, 0);
+}
+
+/*
+ * Get the current picture quality and the associated afc value.
+ */
+static enum tpg_quality vivid_get_quality(struct vivid_dev *dev, s32 *afc)
+{
+	unsigned freq_modulus;
+
+	if (afc)
+		*afc = 0;
+	if (tpg_g_quality(&dev->tpg) == TPG_QUAL_COLOR ||
+	    tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE)
+		return tpg_g_quality(&dev->tpg);
+
+	/*
+	 * There is a fake channel every 6 MHz at 49.25, 55.25, etc.
+	 * From +/- 0.25 MHz around the channel there is color, and from
+	 * +/- 1 MHz there is grayscale (chroma is lost).
+	 * Everywhere else it is just gray.
+	 */
+	freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16);
+	if (afc)
+		*afc = freq_modulus - 1 * 16;
+	return TPG_QUAL_GRAY;
+}
+
+enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev)
+{
+	if (vivid_is_sdtv_cap(dev))
+		return dev->std_aspect_ratio;
+
+	if (vivid_is_hdmi_cap(dev))
+		return dev->dv_timings_aspect_ratio;
+
+	return TPG_VIDEO_ASPECT_IMAGE;
+}
+
+static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev)
+{
+	if (vivid_is_sdtv_cap(dev))
+		return (dev->std_cap & V4L2_STD_525_60) ?
+			TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
+
+	if (vivid_is_hdmi_cap(dev) &&
+	    dev->src_rect.width == 720 && dev->src_rect.height <= 576)
+		return dev->src_rect.height == 480 ?
+			TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
+
+	return TPG_PIXEL_ASPECT_SQUARE;
+}
+
+/*
+ * Called whenever the format has to be reset which can occur when
+ * changing inputs, standard, timings, etc.
+ */
+void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
+{
+	struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
+	unsigned size;
+
+	switch (dev->input_type[dev->input]) {
+	case WEBCAM:
+	default:
+		dev->src_rect.width = webcam_sizes[dev->webcam_size_idx].width;
+		dev->src_rect.height = webcam_sizes[dev->webcam_size_idx].height;
+		dev->timeperframe_vid_cap = webcam_intervals[dev->webcam_ival_idx];
+		dev->field_cap = V4L2_FIELD_NONE;
+		tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO);
+		break;
+	case TV:
+	case SVID:
+		dev->field_cap = dev->tv_field_cap;
+		dev->src_rect.width = 720;
+		if (dev->std_cap & V4L2_STD_525_60) {
+			dev->src_rect.height = 480;
+			dev->timeperframe_vid_cap = (struct v4l2_fract) { 1001, 30000 };
+			dev->service_set_cap = V4L2_SLICED_CAPTION_525;
+		} else {
+			dev->src_rect.height = 576;
+			dev->timeperframe_vid_cap = (struct v4l2_fract) { 1000, 25000 };
+			dev->service_set_cap = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+		}
+		tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO);
+		break;
+	case HDMI:
+		dev->src_rect.width = bt->width;
+		dev->src_rect.height = bt->height;
+		size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
+		dev->timeperframe_vid_cap = (struct v4l2_fract) {
+			size / 100, (u32)bt->pixelclock / 100
+		};
+		if (bt->interlaced)
+			dev->field_cap = V4L2_FIELD_ALTERNATE;
+		else
+			dev->field_cap = V4L2_FIELD_NONE;
+
+		/*
+		 * We can be called from within s_ctrl, in that case we can't
+		 * set/get controls. Luckily we don't need to in that case.
+		 */
+		if (keep_controls || !dev->colorspace)
+			break;
+		if (bt->standards & V4L2_DV_BT_STD_CEA861) {
+			if (bt->width == 720 && bt->height <= 576)
+				v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M);
+			else
+				v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_REC709);
+			v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 1);
+		} else {
+			v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB);
+			v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 0);
+		}
+		tpg_s_rgb_range(&dev->tpg, v4l2_ctrl_g_ctrl(dev->rgb_range_cap));
+		break;
+	}
+	vivid_update_quality(dev);
+	tpg_reset_source(&dev->tpg, dev->src_rect.width, dev->src_rect.height, dev->field_cap);
+	dev->crop_cap = dev->src_rect;
+	dev->crop_bounds_cap = dev->src_rect;
+	dev->compose_cap = dev->crop_cap;
+	if (V4L2_FIELD_HAS_T_OR_B(dev->field_cap))
+		dev->compose_cap.height /= 2;
+	dev->fmt_cap_rect = dev->compose_cap;
+	tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
+	tpg_s_pixel_aspect(&dev->tpg, vivid_get_pixel_aspect(dev));
+	tpg_update_mv_step(&dev->tpg);
+}
+
+/* Map the field to something that is valid for the current input */
+static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field field)
+{
+	if (vivid_is_sdtv_cap(dev)) {
+		switch (field) {
+		case V4L2_FIELD_INTERLACED_TB:
+		case V4L2_FIELD_INTERLACED_BT:
+		case V4L2_FIELD_SEQ_TB:
+		case V4L2_FIELD_SEQ_BT:
+		case V4L2_FIELD_TOP:
+		case V4L2_FIELD_BOTTOM:
+		case V4L2_FIELD_ALTERNATE:
+			return field;
+		case V4L2_FIELD_INTERLACED:
+		default:
+			return V4L2_FIELD_INTERLACED;
+		}
+	}
+	if (vivid_is_hdmi_cap(dev))
+		return dev->dv_timings_cap.bt.interlaced ? V4L2_FIELD_ALTERNATE :
+						       V4L2_FIELD_NONE;
+	return V4L2_FIELD_NONE;
+}
+
+static unsigned vivid_colorspace_cap(struct vivid_dev *dev)
+{
+	if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+		return tpg_g_colorspace(&dev->tpg);
+	return dev->colorspace_out;
+}
+
+int vivid_g_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+	unsigned p;
+
+	mp->width        = dev->fmt_cap_rect.width;
+	mp->height       = dev->fmt_cap_rect.height;
+	mp->field        = dev->field_cap;
+	mp->pixelformat  = dev->fmt_cap->fourcc;
+	mp->colorspace   = vivid_colorspace_cap(dev);
+	mp->num_planes = dev->fmt_cap->planes;
+	for (p = 0; p < mp->num_planes; p++) {
+		mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p);
+		mp->plane_fmt[p].sizeimage =
+			mp->plane_fmt[p].bytesperline * mp->height +
+			dev->fmt_cap->data_offset[p];
+	}
+	return 0;
+}
+
+int vivid_try_fmt_vid_cap(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+	struct v4l2_plane_pix_format *pfmt = mp->plane_fmt;
+	struct vivid_dev *dev = video_drvdata(file);
+	const struct vivid_fmt *fmt;
+	unsigned bytesperline, max_bpl;
+	unsigned factor = 1;
+	unsigned w, h;
+	unsigned p;
+
+	fmt = vivid_get_format(dev, mp->pixelformat);
+	if (!fmt) {
+		dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
+			mp->pixelformat);
+		mp->pixelformat = V4L2_PIX_FMT_YUYV;
+		fmt = vivid_get_format(dev, mp->pixelformat);
+	}
+
+	mp->field = vivid_field_cap(dev, mp->field);
+	if (vivid_is_webcam(dev)) {
+		const struct v4l2_frmsize_discrete *sz =
+			v4l2_find_nearest_format(&webcam_probe, mp->width, mp->height);
+
+		w = sz->width;
+		h = sz->height;
+	} else if (vivid_is_sdtv_cap(dev)) {
+		w = 720;
+		h = (dev->std_cap & V4L2_STD_525_60) ? 480 : 576;
+	} else {
+		w = dev->src_rect.width;
+		h = dev->src_rect.height;
+	}
+	if (V4L2_FIELD_HAS_T_OR_B(mp->field))
+		factor = 2;
+	if (vivid_is_webcam(dev) ||
+	    (!dev->has_scaler_cap && !dev->has_crop_cap && !dev->has_compose_cap)) {
+		mp->width = w;
+		mp->height = h / factor;
+	} else {
+		struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor };
+
+		rect_set_min_size(&r, &vivid_min_rect);
+		rect_set_max_size(&r, &vivid_max_rect);
+		if (dev->has_scaler_cap && !dev->has_compose_cap) {
+			struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h };
+
+			rect_set_max_size(&r, &max_r);
+		} else if (!dev->has_scaler_cap && dev->has_crop_cap && !dev->has_compose_cap) {
+			rect_set_max_size(&r, &dev->src_rect);
+		} else if (!dev->has_scaler_cap && !dev->has_crop_cap) {
+			rect_set_min_size(&r, &dev->src_rect);
+		}
+		mp->width = r.width;
+		mp->height = r.height / factor;
+	}
+
+	/* This driver supports custom bytesperline values */
+
+	/* Calculate the minimum supported bytesperline value */
+	bytesperline = (mp->width * fmt->depth) >> 3;
+	/* Calculate the maximum supported bytesperline value */
+	max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3;
+	mp->num_planes = fmt->planes;
+	for (p = 0; p < mp->num_planes; p++) {
+		if (pfmt[p].bytesperline > max_bpl)
+			pfmt[p].bytesperline = max_bpl;
+		if (pfmt[p].bytesperline < bytesperline)
+			pfmt[p].bytesperline = bytesperline;
+		pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height +
+			fmt->data_offset[p];
+		memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
+	}
+	mp->colorspace = vivid_colorspace_cap(dev);
+	memset(mp->reserved, 0, sizeof(mp->reserved));
+	return 0;
+}
+
+int vivid_s_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_rect *crop = &dev->crop_cap;
+	struct v4l2_rect *compose = &dev->compose_cap;
+	struct vb2_queue *q = &dev->vb_vid_cap_q;
+	int ret = vivid_try_fmt_vid_cap(file, priv, f);
+	unsigned factor = 1;
+	unsigned i;
+
+	if (ret < 0)
+		return ret;
+
+	if (vb2_is_busy(q)) {
+		dprintk(dev, 1, "%s device busy\n", __func__);
+		return -EBUSY;
+	}
+
+	if (dev->overlay_cap_owner && dev->fb_cap.fmt.pixelformat != mp->pixelformat) {
+		dprintk(dev, 1, "overlay is active, can't change pixelformat\n");
+		return -EBUSY;
+	}
+
+	dev->fmt_cap = vivid_get_format(dev, mp->pixelformat);
+	if (V4L2_FIELD_HAS_T_OR_B(mp->field))
+		factor = 2;
+
+	/* Note: the webcam input doesn't support scaling, cropping or composing */
+
+	if (!vivid_is_webcam(dev) &&
+	    (dev->has_scaler_cap || dev->has_crop_cap || dev->has_compose_cap)) {
+		struct v4l2_rect r = { 0, 0, mp->width, mp->height };
+
+		if (dev->has_scaler_cap) {
+			if (dev->has_compose_cap)
+				rect_map_inside(compose, &r);
+			else
+				*compose = r;
+			if (dev->has_crop_cap && !dev->has_compose_cap) {
+				struct v4l2_rect min_r = {
+					0, 0,
+					r.width / MAX_ZOOM,
+					factor * r.height / MAX_ZOOM
+				};
+				struct v4l2_rect max_r = {
+					0, 0,
+					r.width * MAX_ZOOM,
+					factor * r.height * MAX_ZOOM
+				};
+
+				rect_set_min_size(crop, &min_r);
+				rect_set_max_size(crop, &max_r);
+				rect_map_inside(crop, &dev->crop_bounds_cap);
+			} else if (dev->has_crop_cap) {
+				struct v4l2_rect min_r = {
+					0, 0,
+					compose->width / MAX_ZOOM,
+					factor * compose->height / MAX_ZOOM
+				};
+				struct v4l2_rect max_r = {
+					0, 0,
+					compose->width * MAX_ZOOM,
+					factor * compose->height * MAX_ZOOM
+				};
+
+				rect_set_min_size(crop, &min_r);
+				rect_set_max_size(crop, &max_r);
+				rect_map_inside(crop, &dev->crop_bounds_cap);
+			}
+		} else if (dev->has_crop_cap && !dev->has_compose_cap) {
+			r.height *= factor;
+			rect_set_size_to(crop, &r);
+			rect_map_inside(crop, &dev->crop_bounds_cap);
+			r = *crop;
+			r.height /= factor;
+			rect_set_size_to(compose, &r);
+		} else if (!dev->has_crop_cap) {
+			rect_map_inside(compose, &r);
+		} else {
+			r.height *= factor;
+			rect_set_max_size(crop, &r);
+			rect_map_inside(crop, &dev->crop_bounds_cap);
+			compose->top *= factor;
+			compose->height *= factor;
+			rect_set_size_to(compose, crop);
+			rect_map_inside(compose, &r);
+			compose->top /= factor;
+			compose->height /= factor;
+		}
+	} else if (vivid_is_webcam(dev)) {
+		/* Guaranteed to be a match */
+		for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++)
+			if (webcam_sizes[i].width == mp->width &&
+					webcam_sizes[i].height == mp->height)
+				break;
+		dev->webcam_size_idx = i;
+		if (dev->webcam_ival_idx >= 2 * (3 - i))
+			dev->webcam_ival_idx = 2 * (3 - i) - 1;
+		vivid_update_format_cap(dev, false);
+	} else {
+		struct v4l2_rect r = { 0, 0, mp->width, mp->height };
+
+		rect_set_size_to(compose, &r);
+		r.height *= factor;
+		rect_set_size_to(crop, &r);
+	}
+
+	dev->fmt_cap_rect.width = mp->width;
+	dev->fmt_cap_rect.height = mp->height;
+	tpg_s_buf_height(&dev->tpg, mp->height);
+	tpg_s_bytesperline(&dev->tpg, 0, mp->plane_fmt[0].bytesperline);
+	if (tpg_g_planes(&dev->tpg) > 1)
+		tpg_s_bytesperline(&dev->tpg, 1, mp->plane_fmt[1].bytesperline);
+	dev->field_cap = mp->field;
+	tpg_s_field(&dev->tpg, dev->field_cap);
+	tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap);
+	tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
+	if (vivid_is_sdtv_cap(dev))
+		dev->tv_field_cap = mp->field;
+	tpg_update_mv_step(&dev->tpg);
+	return 0;
+}
+
+int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!dev->multiplanar)
+		return -ENOTTY;
+	return vivid_g_fmt_vid_cap(file, priv, f);
+}
+
+int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!dev->multiplanar)
+		return -ENOTTY;
+	return vivid_try_fmt_vid_cap(file, priv, f);
+}
+
+int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!dev->multiplanar)
+		return -ENOTTY;
+	return vivid_s_fmt_vid_cap(file, priv, f);
+}
+
+int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (dev->multiplanar)
+		return -ENOTTY;
+	return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_cap);
+}
+
+int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (dev->multiplanar)
+		return -ENOTTY;
+	return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_cap);
+}
+
+int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (dev->multiplanar)
+		return -ENOTTY;
+	return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_cap);
+}
+
+int vivid_vid_cap_g_selection(struct file *file, void *priv,
+			      struct v4l2_selection *sel)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!dev->has_crop_cap && !dev->has_compose_cap)
+		return -ENOTTY;
+	if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (vivid_is_webcam(dev))
+		return -EINVAL;
+
+	sel->r.left = sel->r.top = 0;
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP:
+		if (!dev->has_crop_cap)
+			return -EINVAL;
+		sel->r = dev->crop_cap;
+		break;
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		if (!dev->has_crop_cap)
+			return -EINVAL;
+		sel->r = dev->src_rect;
+		break;
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		if (!dev->has_compose_cap)
+			return -EINVAL;
+		sel->r = vivid_max_rect;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		if (!dev->has_compose_cap)
+			return -EINVAL;
+		sel->r = dev->compose_cap;
+		break;
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+		if (!dev->has_compose_cap)
+			return -EINVAL;
+		sel->r = dev->fmt_cap_rect;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_rect *crop = &dev->crop_cap;
+	struct v4l2_rect *compose = &dev->compose_cap;
+	unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
+	int ret;
+
+	if (!dev->has_crop_cap && !dev->has_compose_cap)
+		return -ENOTTY;
+	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (vivid_is_webcam(dev))
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+		if (!dev->has_crop_cap)
+			return -EINVAL;
+		ret = vivid_vid_adjust_sel(s->flags, &s->r);
+		if (ret)
+			return ret;
+		rect_set_min_size(&s->r, &vivid_min_rect);
+		rect_set_max_size(&s->r, &dev->src_rect);
+		rect_map_inside(&s->r, &dev->crop_bounds_cap);
+		s->r.top /= factor;
+		s->r.height /= factor;
+		if (dev->has_scaler_cap) {
+			struct v4l2_rect fmt = dev->fmt_cap_rect;
+			struct v4l2_rect max_rect = {
+				0, 0,
+				s->r.width * MAX_ZOOM,
+				s->r.height * MAX_ZOOM
+			};
+			struct v4l2_rect min_rect = {
+				0, 0,
+				s->r.width / MAX_ZOOM,
+				s->r.height / MAX_ZOOM
+			};
+
+			rect_set_min_size(&fmt, &min_rect);
+			if (!dev->has_compose_cap)
+				rect_set_max_size(&fmt, &max_rect);
+			if (!rect_same_size(&dev->fmt_cap_rect, &fmt) &&
+			    vb2_is_busy(&dev->vb_vid_cap_q))
+				return -EBUSY;
+			if (dev->has_compose_cap) {
+				rect_set_min_size(compose, &min_rect);
+				rect_set_max_size(compose, &max_rect);
+			}
+			dev->fmt_cap_rect = fmt;
+			tpg_s_buf_height(&dev->tpg, fmt.height);
+		} else if (dev->has_compose_cap) {
+			struct v4l2_rect fmt = dev->fmt_cap_rect;
+
+			rect_set_min_size(&fmt, &s->r);
+			if (!rect_same_size(&dev->fmt_cap_rect, &fmt) &&
+			    vb2_is_busy(&dev->vb_vid_cap_q))
+				return -EBUSY;
+			dev->fmt_cap_rect = fmt;
+			tpg_s_buf_height(&dev->tpg, fmt.height);
+			rect_set_size_to(compose, &s->r);
+			rect_map_inside(compose, &dev->fmt_cap_rect);
+		} else {
+			if (!rect_same_size(&s->r, &dev->fmt_cap_rect) &&
+			    vb2_is_busy(&dev->vb_vid_cap_q))
+				return -EBUSY;
+			rect_set_size_to(&dev->fmt_cap_rect, &s->r);
+			rect_set_size_to(compose, &s->r);
+			rect_map_inside(compose, &dev->fmt_cap_rect);
+			tpg_s_buf_height(&dev->tpg, dev->fmt_cap_rect.height);
+		}
+		s->r.top *= factor;
+		s->r.height *= factor;
+		*crop = s->r;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		if (!dev->has_compose_cap)
+			return -EINVAL;
+		ret = vivid_vid_adjust_sel(s->flags, &s->r);
+		if (ret)
+			return ret;
+		rect_set_min_size(&s->r, &vivid_min_rect);
+		rect_set_max_size(&s->r, &dev->fmt_cap_rect);
+		if (dev->has_scaler_cap) {
+			struct v4l2_rect max_rect = {
+				0, 0,
+				dev->src_rect.width * MAX_ZOOM,
+				(dev->src_rect.height / factor) * MAX_ZOOM
+			};
+
+			rect_set_max_size(&s->r, &max_rect);
+			if (dev->has_crop_cap) {
+				struct v4l2_rect min_rect = {
+					0, 0,
+					s->r.width / MAX_ZOOM,
+					(s->r.height * factor) / MAX_ZOOM
+				};
+				struct v4l2_rect max_rect = {
+					0, 0,
+					s->r.width * MAX_ZOOM,
+					(s->r.height * factor) * MAX_ZOOM
+				};
+
+				rect_set_min_size(crop, &min_rect);
+				rect_set_max_size(crop, &max_rect);
+				rect_map_inside(crop, &dev->crop_bounds_cap);
+			}
+		} else if (dev->has_crop_cap) {
+			s->r.top *= factor;
+			s->r.height *= factor;
+			rect_set_max_size(&s->r, &dev->src_rect);
+			rect_set_size_to(crop, &s->r);
+			rect_map_inside(crop, &dev->crop_bounds_cap);
+			s->r.top /= factor;
+			s->r.height /= factor;
+		} else {
+			rect_set_size_to(&s->r, &dev->src_rect);
+			s->r.height /= factor;
+		}
+		rect_map_inside(&s->r, &dev->fmt_cap_rect);
+		if (dev->bitmap_cap && (compose->width != s->r.width ||
+					compose->height != s->r.height)) {
+			kfree(dev->bitmap_cap);
+			dev->bitmap_cap = NULL;
+		}
+		*compose = s->r;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	tpg_s_crop_compose(&dev->tpg, crop, compose);
+	return 0;
+}
+
+int vivid_vid_cap_cropcap(struct file *file, void *priv,
+			      struct v4l2_cropcap *cap)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	switch (vivid_get_pixel_aspect(dev)) {
+	case TPG_PIXEL_ASPECT_NTSC:
+		cap->pixelaspect.numerator = 11;
+		cap->pixelaspect.denominator = 10;
+		break;
+	case TPG_PIXEL_ASPECT_PAL:
+		cap->pixelaspect.numerator = 54;
+		cap->pixelaspect.denominator = 59;
+		break;
+	case TPG_PIXEL_ASPECT_SQUARE:
+		cap->pixelaspect.numerator = 1;
+		cap->pixelaspect.denominator = 1;
+		break;
+	}
+	return 0;
+}
+
+int vidioc_enum_fmt_vid_overlay(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	const struct vivid_fmt *fmt;
+
+	if (f->index >= ARRAY_SIZE(formats_ovl))
+		return -EINVAL;
+
+	fmt = &formats_ovl[f->index];
+
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+	return 0;
+}
+
+int vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	const struct v4l2_rect *compose = &dev->compose_cap;
+	struct v4l2_window *win = &f->fmt.win;
+	unsigned clipcount = win->clipcount;
+
+	win->w.top = dev->overlay_cap_top;
+	win->w.left = dev->overlay_cap_left;
+	win->w.width = compose->width;
+	win->w.height = compose->height;
+	win->field = dev->overlay_cap_field;
+	win->clipcount = dev->clipcount_cap;
+	if (clipcount > dev->clipcount_cap)
+		clipcount = dev->clipcount_cap;
+	if (dev->bitmap_cap == NULL)
+		win->bitmap = NULL;
+	else if (win->bitmap) {
+		if (copy_to_user(win->bitmap, dev->bitmap_cap,
+		    ((compose->width + 7) / 8) * compose->height))
+			return -EFAULT;
+	}
+	if (clipcount && win->clips) {
+		if (copy_to_user(win->clips, dev->clips_cap,
+				 clipcount * sizeof(dev->clips_cap[0])))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	const struct v4l2_rect *compose = &dev->compose_cap;
+	struct v4l2_window *win = &f->fmt.win;
+	int i, j;
+
+	win->w.left = clamp_t(int, win->w.left,
+			      -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width);
+	win->w.top = clamp_t(int, win->w.top,
+			     -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height);
+	win->w.width = compose->width;
+	win->w.height = compose->height;
+	if (win->field != V4L2_FIELD_BOTTOM && win->field != V4L2_FIELD_TOP)
+		win->field = V4L2_FIELD_ANY;
+	win->chromakey = 0;
+	win->global_alpha = 0;
+	if (win->clipcount && !win->clips)
+		win->clipcount = 0;
+	if (win->clipcount > MAX_CLIPS)
+		win->clipcount = MAX_CLIPS;
+	if (win->clipcount) {
+		if (copy_from_user(dev->try_clips_cap, win->clips,
+				   win->clipcount * sizeof(dev->clips_cap[0])))
+			return -EFAULT;
+		for (i = 0; i < win->clipcount; i++) {
+			struct v4l2_rect *r = &dev->try_clips_cap[i].c;
+
+			r->top = clamp_t(s32, r->top, 0, dev->fb_cap.fmt.height - 1);
+			r->height = clamp_t(s32, r->height, 1, dev->fb_cap.fmt.height - r->top);
+			r->left = clamp_t(u32, r->left, 0, dev->fb_cap.fmt.width - 1);
+			r->width = clamp_t(u32, r->width, 1, dev->fb_cap.fmt.width - r->left);
+		}
+		/*
+		 * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small
+		 * number and it's typically a one-time deal.
+		 */
+		for (i = 0; i < win->clipcount - 1; i++) {
+			struct v4l2_rect *r1 = &dev->try_clips_cap[i].c;
+
+			for (j = i + 1; j < win->clipcount; j++) {
+				struct v4l2_rect *r2 = &dev->try_clips_cap[j].c;
+
+				if (rect_overlap(r1, r2))
+					return -EINVAL;
+			}
+		}
+		if (copy_to_user(win->clips, dev->try_clips_cap,
+				 win->clipcount * sizeof(dev->clips_cap[0])))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	const struct v4l2_rect *compose = &dev->compose_cap;
+	struct v4l2_window *win = &f->fmt.win;
+	int ret = vidioc_try_fmt_vid_overlay(file, priv, f);
+	unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height;
+	unsigned clips_size = win->clipcount * sizeof(dev->clips_cap[0]);
+	void *new_bitmap = NULL;
+
+	if (ret)
+		return ret;
+
+	if (win->bitmap) {
+		new_bitmap = vzalloc(bitmap_size);
+
+		if (new_bitmap == NULL)
+			return -ENOMEM;
+		if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) {
+			vfree(new_bitmap);
+			return -EFAULT;
+		}
+	}
+
+	dev->overlay_cap_top = win->w.top;
+	dev->overlay_cap_left = win->w.left;
+	dev->overlay_cap_field = win->field;
+	vfree(dev->bitmap_cap);
+	dev->bitmap_cap = new_bitmap;
+	dev->clipcount_cap = win->clipcount;
+	if (dev->clipcount_cap)
+		memcpy(dev->clips_cap, dev->try_clips_cap, clips_size);
+	return 0;
+}
+
+int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (i && dev->fb_vbase_cap == NULL)
+		return -EINVAL;
+
+	if (i && dev->fb_cap.fmt.pixelformat != dev->fmt_cap->fourcc) {
+		dprintk(dev, 1, "mismatch between overlay and video capture pixelformats\n");
+		return -EINVAL;
+	}
+
+	if (dev->overlay_cap_owner && dev->overlay_cap_owner != fh)
+		return -EBUSY;
+	dev->overlay_cap_owner = i ? fh : NULL;
+	return 0;
+}
+
+int vivid_vid_cap_g_fbuf(struct file *file, void *fh,
+				struct v4l2_framebuffer *a)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	*a = dev->fb_cap;
+	a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING |
+			V4L2_FBUF_CAP_LIST_CLIPPING;
+	a->flags = V4L2_FBUF_FLAG_PRIMARY;
+	a->fmt.field = V4L2_FIELD_NONE;
+	a->fmt.colorspace = V4L2_COLORSPACE_SRGB;
+	a->fmt.priv = 0;
+	return 0;
+}
+
+int vivid_vid_cap_s_fbuf(struct file *file, void *fh,
+				const struct v4l2_framebuffer *a)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	const struct vivid_fmt *fmt;
+
+	if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	if (dev->overlay_cap_owner)
+		return -EBUSY;
+
+	if (a->base == NULL) {
+		dev->fb_cap.base = NULL;
+		dev->fb_vbase_cap = NULL;
+		return 0;
+	}
+
+	if (a->fmt.width < 48 || a->fmt.height < 32)
+		return -EINVAL;
+	fmt = vivid_get_format(dev, a->fmt.pixelformat);
+	if (!fmt || !fmt->can_do_overlay)
+		return -EINVAL;
+	if (a->fmt.bytesperline < (a->fmt.width * fmt->depth) / 8)
+		return -EINVAL;
+	if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage)
+		return -EINVAL;
+
+	dev->fb_vbase_cap = phys_to_virt((unsigned long)a->base);
+	dev->fb_cap = *a;
+	dev->overlay_cap_left = clamp_t(int, dev->overlay_cap_left,
+				    -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width);
+	dev->overlay_cap_top = clamp_t(int, dev->overlay_cap_top,
+				   -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height);
+	return 0;
+}
+
+static const struct v4l2_audio vivid_audio_inputs[] = {
+	{ 0, "TV", V4L2_AUDCAP_STEREO },
+	{ 1, "Line-In", V4L2_AUDCAP_STEREO },
+};
+
+int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *inp)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (inp->index >= dev->num_inputs)
+		return -EINVAL;
+
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	switch (dev->input_type[inp->index]) {
+	case WEBCAM:
+		snprintf(inp->name, sizeof(inp->name), "Webcam %u",
+				dev->input_name_counter[inp->index]);
+		inp->capabilities = 0;
+		break;
+	case TV:
+		snprintf(inp->name, sizeof(inp->name), "TV %u",
+				dev->input_name_counter[inp->index]);
+		inp->type = V4L2_INPUT_TYPE_TUNER;
+		inp->std = V4L2_STD_ALL;
+		if (dev->has_audio_inputs)
+			inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1;
+		inp->capabilities = V4L2_IN_CAP_STD;
+		break;
+	case SVID:
+		snprintf(inp->name, sizeof(inp->name), "S-Video %u",
+				dev->input_name_counter[inp->index]);
+		inp->std = V4L2_STD_ALL;
+		if (dev->has_audio_inputs)
+			inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1;
+		inp->capabilities = V4L2_IN_CAP_STD;
+		break;
+	case HDMI:
+		snprintf(inp->name, sizeof(inp->name), "HDMI %u",
+				dev->input_name_counter[inp->index]);
+		inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
+		if (dev->edid_blocks == 0 ||
+		    dev->dv_timings_signal_mode == NO_SIGNAL)
+			inp->status |= V4L2_IN_ST_NO_SIGNAL;
+		else if (dev->dv_timings_signal_mode == NO_LOCK ||
+			 dev->dv_timings_signal_mode == OUT_OF_RANGE)
+			inp->status |= V4L2_IN_ST_NO_H_LOCK;
+		break;
+	}
+	if (dev->sensor_hflip)
+		inp->status |= V4L2_IN_ST_HFLIP;
+	if (dev->sensor_vflip)
+		inp->status |= V4L2_IN_ST_VFLIP;
+	if (dev->input == inp->index && vivid_is_sdtv_cap(dev)) {
+		if (dev->std_signal_mode == NO_SIGNAL) {
+			inp->status |= V4L2_IN_ST_NO_SIGNAL;
+		} else if (dev->std_signal_mode == NO_LOCK) {
+			inp->status |= V4L2_IN_ST_NO_H_LOCK;
+		} else if (vivid_is_tv_cap(dev)) {
+			switch (tpg_g_quality(&dev->tpg)) {
+			case TPG_QUAL_GRAY:
+				inp->status |= V4L2_IN_ST_COLOR_KILL;
+				break;
+			case TPG_QUAL_NOISE:
+				inp->status |= V4L2_IN_ST_NO_H_LOCK;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+int vidioc_g_input(struct file *file, void *priv, unsigned *i)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	*i = dev->input;
+	return 0;
+}
+
+int vidioc_s_input(struct file *file, void *priv, unsigned i)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
+	unsigned brightness;
+
+	if (i >= dev->num_inputs)
+		return -EINVAL;
+
+	if (i == dev->input)
+		return 0;
+
+	if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q))
+		return -EBUSY;
+
+	dev->input = i;
+	dev->vid_cap_dev.tvnorms = 0;
+	if (dev->input_type[i] == TV || dev->input_type[i] == SVID) {
+		dev->tv_audio_input = (dev->input_type[i] == TV) ? 0 : 1;
+		dev->vid_cap_dev.tvnorms = V4L2_STD_ALL;
+	}
+	dev->vbi_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms;
+	vivid_update_format_cap(dev, false);
+
+	if (dev->colorspace) {
+		switch (dev->input_type[i]) {
+		case WEBCAM:
+			v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB);
+			break;
+		case TV:
+		case SVID:
+			v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M);
+			break;
+		case HDMI:
+			if (bt->standards & V4L2_DV_BT_STD_CEA861) {
+				if (dev->src_rect.width == 720 && dev->src_rect.height <= 576)
+					v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M);
+				else
+					v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_REC709);
+			} else {
+				v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB);
+			}
+			break;
+		}
+	}
+
+	/*
+	 * Modify the brightness range depending on the input.
+	 * This makes it easy to use vivid to test if applications can
+	 * handle control range modifications and is also how this is
+	 * typically used in practice as different inputs may be hooked
+	 * up to different receivers with different control ranges.
+	 */
+	brightness = 128 * i + dev->input_brightness[i];
+	v4l2_ctrl_modify_range(dev->brightness,
+			128 * i, 255 + 128 * i, 1, 128 + 128 * i);
+	v4l2_ctrl_s_ctrl(dev->brightness, brightness);
+	return 0;
+}
+
+int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+	if (vin->index >= ARRAY_SIZE(vivid_audio_inputs))
+		return -EINVAL;
+	*vin = vivid_audio_inputs[vin->index];
+	return 0;
+}
+
+int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!vivid_is_sdtv_cap(dev))
+		return -EINVAL;
+	*vin = vivid_audio_inputs[dev->tv_audio_input];
+	return 0;
+}
+
+int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!vivid_is_sdtv_cap(dev))
+		return -EINVAL;
+	if (vin->index >= ARRAY_SIZE(vivid_audio_inputs))
+		return -EINVAL;
+	dev->tv_audio_input = vin->index;
+	return 0;
+}
+
+int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (vf->tuner != 0)
+		return -EINVAL;
+	vf->frequency = dev->tv_freq;
+	return 0;
+}
+
+int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (vf->tuner != 0)
+		return -EINVAL;
+	dev->tv_freq = clamp_t(unsigned, vf->frequency, MIN_TV_FREQ, MAX_TV_FREQ);
+	if (vivid_is_tv_cap(dev))
+		vivid_update_quality(dev);
+	return 0;
+}
+
+int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (vt->index != 0)
+		return -EINVAL;
+	if (vt->audmode > V4L2_TUNER_MODE_LANG1_LANG2)
+		return -EINVAL;
+	dev->tv_audmode = vt->audmode;
+	return 0;
+}
+
+int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	enum tpg_quality qual;
+
+	if (vt->index != 0)
+		return -EINVAL;
+
+	vt->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
+			 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+	vt->audmode = dev->tv_audmode;
+	vt->rangelow = MIN_TV_FREQ;
+	vt->rangehigh = MAX_TV_FREQ;
+	qual = vivid_get_quality(dev, &vt->afc);
+	if (qual == TPG_QUAL_COLOR)
+		vt->signal = 0xffff;
+	else if (qual == TPG_QUAL_GRAY)
+		vt->signal = 0x8000;
+	else
+		vt->signal = 0;
+	if (qual == TPG_QUAL_NOISE) {
+		vt->rxsubchans = 0;
+	} else if (qual == TPG_QUAL_GRAY) {
+		vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+	} else {
+		unsigned channel_nr = dev->tv_freq / (6 * 16);
+		unsigned options = (dev->std_cap & V4L2_STD_NTSC_M) ? 4 : 3;
+
+		switch (channel_nr % options) {
+		case 0:
+			vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+			break;
+		case 1:
+			vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+			break;
+		case 2:
+			if (dev->std_cap & V4L2_STD_NTSC_M)
+				vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP;
+			else
+				vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+			break;
+		case 3:
+			vt->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_SAP;
+			break;
+		}
+	}
+	strlcpy(vt->name, "TV Tuner", sizeof(vt->name));
+	return 0;
+}
+
+/* Must remain in sync with the vivid_ctrl_standard_strings array */
+const v4l2_std_id vivid_standard[] = {
+	V4L2_STD_NTSC_M,
+	V4L2_STD_NTSC_M_JP,
+	V4L2_STD_NTSC_M_KR,
+	V4L2_STD_NTSC_443,
+	V4L2_STD_PAL_BG | V4L2_STD_PAL_H,
+	V4L2_STD_PAL_I,
+	V4L2_STD_PAL_DK,
+	V4L2_STD_PAL_M,
+	V4L2_STD_PAL_N,
+	V4L2_STD_PAL_Nc,
+	V4L2_STD_PAL_60,
+	V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
+	V4L2_STD_SECAM_DK,
+	V4L2_STD_SECAM_L,
+	V4L2_STD_SECAM_LC,
+	V4L2_STD_UNKNOWN
+};
+
+/* Must remain in sync with the vivid_standard array */
+const char * const vivid_ctrl_standard_strings[] = {
+	"NTSC-M",
+	"NTSC-M-JP",
+	"NTSC-M-KR",
+	"NTSC-443",
+	"PAL-BGH",
+	"PAL-I",
+	"PAL-DK",
+	"PAL-M",
+	"PAL-N",
+	"PAL-Nc",
+	"PAL-60",
+	"SECAM-BGH",
+	"SECAM-DK",
+	"SECAM-L",
+	"SECAM-Lc",
+	NULL,
+};
+
+int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!vivid_is_sdtv_cap(dev))
+		return -ENODATA;
+	if (dev->std_signal_mode == NO_SIGNAL ||
+	    dev->std_signal_mode == NO_LOCK) {
+		*id = V4L2_STD_UNKNOWN;
+		return 0;
+	}
+	if (vivid_is_tv_cap(dev) && tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) {
+		*id = V4L2_STD_UNKNOWN;
+	} else if (dev->std_signal_mode == CURRENT_STD) {
+		*id = dev->std_cap;
+	} else if (dev->std_signal_mode == SELECTED_STD) {
+		*id = dev->query_std;
+	} else {
+		*id = vivid_standard[dev->query_std_last];
+		dev->query_std_last = (dev->query_std_last + 1) % ARRAY_SIZE(vivid_standard);
+	}
+
+	return 0;
+}
+
+int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!vivid_is_sdtv_cap(dev))
+		return -ENODATA;
+	if (dev->std_cap == id)
+		return 0;
+	if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q))
+		return -EBUSY;
+	dev->std_cap = id;
+	vivid_update_format_cap(dev, false);
+	return 0;
+}
+
+int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh,
+				    struct v4l2_dv_timings *timings)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!vivid_is_hdmi_cap(dev))
+		return -ENODATA;
+	if (vb2_is_busy(&dev->vb_vid_cap_q))
+		return -EBUSY;
+	if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap,
+				0, NULL, NULL))
+		return -EINVAL;
+	if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0))
+		return 0;
+	dev->dv_timings_cap = *timings;
+	vivid_update_format_cap(dev, false);
+	return 0;
+}
+
+int vidioc_query_dv_timings(struct file *file, void *_fh,
+				    struct v4l2_dv_timings *timings)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!vivid_is_hdmi_cap(dev))
+		return -ENODATA;
+	if (dev->dv_timings_signal_mode == NO_SIGNAL ||
+	    dev->edid_blocks == 0)
+		return -ENOLINK;
+	if (dev->dv_timings_signal_mode == NO_LOCK)
+		return -ENOLCK;
+	if (dev->dv_timings_signal_mode == OUT_OF_RANGE) {
+		timings->bt.pixelclock = vivid_dv_timings_cap.bt.max_pixelclock * 2;
+		return -ERANGE;
+	}
+	if (dev->dv_timings_signal_mode == CURRENT_DV_TIMINGS) {
+		*timings = dev->dv_timings_cap;
+	} else if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) {
+		*timings = v4l2_dv_timings_presets[dev->query_dv_timings];
+	} else {
+		*timings = v4l2_dv_timings_presets[dev->query_dv_timings_last];
+		dev->query_dv_timings_last = (dev->query_dv_timings_last + 1) %
+						dev->query_dv_timings_size;
+	}
+	return 0;
+}
+
+int vidioc_s_edid(struct file *file, void *_fh,
+			 struct v4l2_edid *edid)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	memset(edid->reserved, 0, sizeof(edid->reserved));
+	if (edid->pad >= dev->num_inputs)
+		return -EINVAL;
+	if (dev->input_type[edid->pad] != HDMI || edid->start_block)
+		return -EINVAL;
+	if (edid->blocks == 0) {
+		dev->edid_blocks = 0;
+		return 0;
+	}
+	if (edid->blocks > dev->edid_max_blocks) {
+		edid->blocks = dev->edid_max_blocks;
+		return -E2BIG;
+	}
+	dev->edid_blocks = edid->blocks;
+	memcpy(dev->edid, edid->edid, edid->blocks * 128);
+	return 0;
+}
+
+int vidioc_enum_framesizes(struct file *file, void *fh,
+					 struct v4l2_frmsizeenum *fsize)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!vivid_is_webcam(dev) && !dev->has_scaler_cap)
+		return -EINVAL;
+	if (vivid_get_format(dev, fsize->pixel_format) == NULL)
+		return -EINVAL;
+	if (vivid_is_webcam(dev)) {
+		if (fsize->index >= ARRAY_SIZE(webcam_sizes))
+			return -EINVAL;
+		fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+		fsize->discrete = webcam_sizes[fsize->index];
+		return 0;
+	}
+	if (fsize->index)
+		return -EINVAL;
+	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+	fsize->stepwise.min_width = MIN_WIDTH;
+	fsize->stepwise.max_width = MAX_WIDTH * MAX_ZOOM;
+	fsize->stepwise.step_width = 2;
+	fsize->stepwise.min_height = MIN_HEIGHT;
+	fsize->stepwise.max_height = MAX_HEIGHT * MAX_ZOOM;
+	fsize->stepwise.step_height = 2;
+	return 0;
+}
+
+/* timeperframe is arbitrary and continuous */
+int vidioc_enum_frameintervals(struct file *file, void *priv,
+					     struct v4l2_frmivalenum *fival)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	const struct vivid_fmt *fmt;
+	int i;
+
+	fmt = vivid_get_format(dev, fival->pixel_format);
+	if (!fmt)
+		return -EINVAL;
+
+	if (!vivid_is_webcam(dev)) {
+		static const struct v4l2_fract step = { 1, 1 };
+
+		if (fival->index)
+			return -EINVAL;
+		if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM)
+			return -EINVAL;
+		if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM)
+			return -EINVAL;
+		fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
+		fival->stepwise.min = tpf_min;
+		fival->stepwise.max = tpf_max;
+		fival->stepwise.step = step;
+		return 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++)
+		if (fival->width == webcam_sizes[i].width &&
+		    fival->height == webcam_sizes[i].height)
+			break;
+	if (i == ARRAY_SIZE(webcam_sizes))
+		return -EINVAL;
+	if (fival->index >= 2 * (3 - i))
+		return -EINVAL;
+	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	fival->discrete = webcam_intervals[fival->index];
+	return 0;
+}
+
+int vivid_vid_cap_g_parm(struct file *file, void *priv,
+			  struct v4l2_streamparm *parm)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (parm->type != (dev->multiplanar ?
+			   V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+			   V4L2_BUF_TYPE_VIDEO_CAPTURE))
+		return -EINVAL;
+
+	parm->parm.capture.capability   = V4L2_CAP_TIMEPERFRAME;
+	parm->parm.capture.timeperframe = dev->timeperframe_vid_cap;
+	parm->parm.capture.readbuffers  = 1;
+	return 0;
+}
+
+#define FRACT_CMP(a, OP, b)	\
+	((u64)(a).numerator * (b).denominator  OP  (u64)(b).numerator * (a).denominator)
+
+int vivid_vid_cap_s_parm(struct file *file, void *priv,
+			  struct v4l2_streamparm *parm)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	unsigned ival_sz = 2 * (3 - dev->webcam_size_idx);
+	struct v4l2_fract tpf;
+	unsigned i;
+
+	if (parm->type != (dev->multiplanar ?
+			   V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+			   V4L2_BUF_TYPE_VIDEO_CAPTURE))
+		return -EINVAL;
+	if (!vivid_is_webcam(dev))
+		return vivid_vid_cap_g_parm(file, priv, parm);
+
+	tpf = parm->parm.capture.timeperframe;
+
+	if (tpf.denominator == 0)
+		tpf = webcam_intervals[ival_sz - 1];
+	for (i = 0; i < ival_sz; i++)
+		if (FRACT_CMP(tpf, >=, webcam_intervals[i]))
+			break;
+	if (i == ival_sz)
+		i = ival_sz - 1;
+	dev->webcam_ival_idx = i;
+	tpf = webcam_intervals[dev->webcam_ival_idx];
+	tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf;
+	tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf;
+
+	/* resync the thread's timings */
+	dev->cap_seq_resync = true;
+	dev->timeperframe_vid_cap = tpf;
+	parm->parm.capture.timeperframe = tpf;
+	parm->parm.capture.readbuffers  = 1;
+	return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.h b/drivers/media/platform/vivid/vivid-vid-cap.h
new file mode 100644
index 0000000..9407981
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-vid-cap.h
@@ -0,0 +1,71 @@
+/*
+ * vivid-vid-cap.h - video capture support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_VID_CAP_H_
+#define _VIVID_VID_CAP_H_
+
+void vivid_update_quality(struct vivid_dev *dev);
+void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls);
+enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev);
+
+extern const v4l2_std_id vivid_standard[];
+extern const char * const vivid_ctrl_standard_strings[];
+
+extern const struct vb2_ops vivid_vid_cap_qops;
+
+int vivid_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_vid_cap_g_selection(struct file *file, void *priv, struct v4l2_selection *sel);
+int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s);
+int vivid_vid_cap_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap);
+int vidioc_enum_fmt_vid_overlay(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i);
+int vivid_vid_cap_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a);
+int vivid_vid_cap_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a);
+int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp);
+int vidioc_g_input(struct file *file, void *priv, unsigned *i);
+int vidioc_s_input(struct file *file, void *priv, unsigned i);
+int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin);
+int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin);
+int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin);
+int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf);
+int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt);
+int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt);
+int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id);
+int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id);
+int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
+int vidioc_query_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
+int vidioc_s_edid(struct file *file, void *_fh, struct v4l2_edid *edid);
+int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize);
+int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival);
+int vivid_vid_cap_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm);
+int vivid_vid_cap_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
new file mode 100644
index 0000000..16cd6d2
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-vid-common.c
@@ -0,0 +1,571 @@
+/*
+ * vivid-vid-common.c - common video support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+
+const struct v4l2_dv_timings_cap vivid_dv_timings_cap = {
+	.type = V4L2_DV_BT_656_1120,
+	/* keep this initialization for compatibility with GCC < 4.4.6 */
+	.reserved = { 0 },
+	V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 25000000, 600000000,
+		V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT,
+		V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED)
+};
+
+/* ------------------------------------------------------------------
+	Basic structures
+   ------------------------------------------------------------------*/
+
+struct vivid_fmt vivid_formats[] = {
+	{
+		.name     = "4:2:2, packed, YUYV",
+		.fourcc   = V4L2_PIX_FMT_YUYV,
+		.depth    = 16,
+		.is_yuv   = true,
+		.planes   = 1,
+		.data_offset = { PLANE0_DATA_OFFSET, 0 },
+	},
+	{
+		.name     = "4:2:2, packed, UYVY",
+		.fourcc   = V4L2_PIX_FMT_UYVY,
+		.depth    = 16,
+		.is_yuv   = true,
+		.planes   = 1,
+	},
+	{
+		.name     = "4:2:2, packed, YVYU",
+		.fourcc   = V4L2_PIX_FMT_YVYU,
+		.depth    = 16,
+		.is_yuv   = true,
+		.planes   = 1,
+	},
+	{
+		.name     = "4:2:2, packed, VYUY",
+		.fourcc   = V4L2_PIX_FMT_VYUY,
+		.depth    = 16,
+		.is_yuv   = true,
+		.planes   = 1,
+	},
+	{
+		.name     = "RGB565 (LE)",
+		.fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+		.depth    = 16,
+		.planes   = 1,
+		.can_do_overlay = true,
+	},
+	{
+		.name     = "RGB565 (BE)",
+		.fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+		.depth    = 16,
+		.planes   = 1,
+		.can_do_overlay = true,
+	},
+	{
+		.name     = "RGB555 (LE)",
+		.fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
+		.depth    = 16,
+		.planes   = 1,
+		.can_do_overlay = true,
+	},
+	{
+		.name     = "XRGB555 (LE)",
+		.fourcc   = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */
+		.depth    = 16,
+		.planes   = 1,
+		.can_do_overlay = true,
+	},
+	{
+		.name     = "ARGB555 (LE)",
+		.fourcc   = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */
+		.depth    = 16,
+		.planes   = 1,
+		.can_do_overlay = true,
+		.alpha_mask = 0x8000,
+	},
+	{
+		.name     = "RGB555 (BE)",
+		.fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
+		.depth    = 16,
+		.planes   = 1,
+		.can_do_overlay = true,
+	},
+	{
+		.name     = "RGB24 (LE)",
+		.fourcc   = V4L2_PIX_FMT_RGB24, /* rgb */
+		.depth    = 24,
+		.planes   = 1,
+	},
+	{
+		.name     = "RGB24 (BE)",
+		.fourcc   = V4L2_PIX_FMT_BGR24, /* bgr */
+		.depth    = 24,
+		.planes   = 1,
+	},
+	{
+		.name     = "RGB32 (LE)",
+		.fourcc   = V4L2_PIX_FMT_RGB32, /* argb */
+		.depth    = 32,
+		.planes   = 1,
+	},
+	{
+		.name     = "RGB32 (BE)",
+		.fourcc   = V4L2_PIX_FMT_BGR32, /* bgra */
+		.depth    = 32,
+		.planes   = 1,
+	},
+	{
+		.name     = "XRGB32 (LE)",
+		.fourcc   = V4L2_PIX_FMT_XRGB32, /* argb */
+		.depth    = 32,
+		.planes   = 1,
+	},
+	{
+		.name     = "XRGB32 (BE)",
+		.fourcc   = V4L2_PIX_FMT_XBGR32, /* bgra */
+		.depth    = 32,
+		.planes   = 1,
+	},
+	{
+		.name     = "ARGB32 (LE)",
+		.fourcc   = V4L2_PIX_FMT_ARGB32, /* argb */
+		.depth    = 32,
+		.planes   = 1,
+		.alpha_mask = 0x000000ff,
+	},
+	{
+		.name     = "ARGB32 (BE)",
+		.fourcc   = V4L2_PIX_FMT_ABGR32, /* bgra */
+		.depth    = 32,
+		.planes   = 1,
+		.alpha_mask = 0xff000000,
+	},
+	{
+		.name     = "4:2:2, planar, YUV",
+		.fourcc   = V4L2_PIX_FMT_NV16M,
+		.depth    = 8,
+		.is_yuv   = true,
+		.planes   = 2,
+		.data_offset = { PLANE0_DATA_OFFSET, 0 },
+	},
+	{
+		.name     = "4:2:2, planar, YVU",
+		.fourcc   = V4L2_PIX_FMT_NV61M,
+		.depth    = 8,
+		.is_yuv   = true,
+		.planes   = 2,
+		.data_offset = { 0, PLANE0_DATA_OFFSET },
+	},
+};
+
+/* There are 2 multiplanar formats in the list */
+#define VIVID_MPLANAR_FORMATS 2
+
+const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat)
+{
+	const struct vivid_fmt *fmt;
+	unsigned k;
+
+	for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) {
+		fmt = &vivid_formats[k];
+		if (fmt->fourcc == pixelformat)
+			if (fmt->planes == 1 || dev->multiplanar)
+				return fmt;
+	}
+
+	return NULL;
+}
+
+bool vivid_vid_can_loop(struct vivid_dev *dev)
+{
+	if (dev->src_rect.width != dev->sink_rect.width ||
+	    dev->src_rect.height != dev->sink_rect.height)
+		return false;
+	if (dev->fmt_cap->fourcc != dev->fmt_out->fourcc)
+		return false;
+	if (dev->field_cap != dev->field_out)
+		return false;
+	if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) {
+		if (!(dev->std_cap & V4L2_STD_525_60) !=
+		    !(dev->std_out & V4L2_STD_525_60))
+			return false;
+		return true;
+	}
+	if (vivid_is_hdmi_cap(dev) && vivid_is_hdmi_out(dev))
+		return true;
+	return false;
+}
+
+void vivid_send_source_change(struct vivid_dev *dev, unsigned type)
+{
+	struct v4l2_event ev = {
+		.type = V4L2_EVENT_SOURCE_CHANGE,
+		.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+	};
+	unsigned i;
+
+	for (i = 0; i < dev->num_inputs; i++) {
+		ev.id = i;
+		if (dev->input_type[i] == type) {
+			if (video_is_registered(&dev->vid_cap_dev) && dev->has_vid_cap)
+				v4l2_event_queue(&dev->vid_cap_dev, &ev);
+			if (video_is_registered(&dev->vbi_cap_dev) && dev->has_vbi_cap)
+				v4l2_event_queue(&dev->vbi_cap_dev, &ev);
+		}
+	}
+}
+
+/*
+ * Conversion function that converts a single-planar format to a
+ * single-plane multiplanar format.
+ */
+void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt)
+{
+	struct v4l2_pix_format_mplane *mp = &mp_fmt->fmt.pix_mp;
+	struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0];
+	const struct v4l2_pix_format *pix = &sp_fmt->fmt.pix;
+	bool is_out = sp_fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+	memset(mp->reserved, 0, sizeof(mp->reserved));
+	mp_fmt->type = is_out ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+			   V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+	mp->width = pix->width;
+	mp->height = pix->height;
+	mp->pixelformat = pix->pixelformat;
+	mp->field = pix->field;
+	mp->colorspace = pix->colorspace;
+	mp->num_planes = 1;
+	mp->flags = pix->flags;
+	ppix->sizeimage = pix->sizeimage;
+	ppix->bytesperline = pix->bytesperline;
+	memset(ppix->reserved, 0, sizeof(ppix->reserved));
+}
+
+int fmt_sp2mp_func(struct file *file, void *priv,
+		struct v4l2_format *f, fmtfunc func)
+{
+	struct v4l2_format fmt;
+	struct v4l2_pix_format_mplane *mp = &fmt.fmt.pix_mp;
+	struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0];
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	int ret;
+
+	/* Converts to a mplane format */
+	fmt_sp2mp(f, &fmt);
+	/* Passes it to the generic mplane format function */
+	ret = func(file, priv, &fmt);
+	/* Copies back the mplane data to the single plane format */
+	pix->width = mp->width;
+	pix->height = mp->height;
+	pix->pixelformat = mp->pixelformat;
+	pix->field = mp->field;
+	pix->colorspace = mp->colorspace;
+	pix->sizeimage = ppix->sizeimage;
+	pix->bytesperline = ppix->bytesperline;
+	pix->flags = mp->flags;
+	return ret;
+}
+
+/* v4l2_rect helper function: copy the width/height values */
+void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size)
+{
+	r->width = size->width;
+	r->height = size->height;
+}
+
+/* v4l2_rect helper function: width and height of r should be >= min_size */
+void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size)
+{
+	if (r->width < min_size->width)
+		r->width = min_size->width;
+	if (r->height < min_size->height)
+		r->height = min_size->height;
+}
+
+/* v4l2_rect helper function: width and height of r should be <= max_size */
+void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size)
+{
+	if (r->width > max_size->width)
+		r->width = max_size->width;
+	if (r->height > max_size->height)
+		r->height = max_size->height;
+}
+
+/* v4l2_rect helper function: r should be inside boundary */
+void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary)
+{
+	rect_set_max_size(r, boundary);
+	if (r->left < boundary->left)
+		r->left = boundary->left;
+	if (r->top < boundary->top)
+		r->top = boundary->top;
+	if (r->left + r->width > boundary->width)
+		r->left = boundary->width - r->width;
+	if (r->top + r->height > boundary->height)
+		r->top = boundary->height - r->height;
+}
+
+/* v4l2_rect helper function: return true if r1 has the same size as r2 */
+bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
+{
+	return r1->width == r2->width && r1->height == r2->height;
+}
+
+/* v4l2_rect helper function: calculate the intersection of two rects */
+struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b)
+{
+	struct v4l2_rect r;
+	int right, bottom;
+
+	r.top = max(a->top, b->top);
+	r.left = max(a->left, b->left);
+	bottom = min(a->top + a->height, b->top + b->height);
+	right = min(a->left + a->width, b->left + b->width);
+	r.height = max(0, bottom - r.top);
+	r.width = max(0, right - r.left);
+	return r;
+}
+
+/*
+ * v4l2_rect helper function: scale rect r by to->width / from->width and
+ * to->height / from->height.
+ */
+void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from,
+				     const struct v4l2_rect *to)
+{
+	if (from->width == 0 || from->height == 0) {
+		r->left = r->top = r->width = r->height = 0;
+		return;
+	}
+	r->left = (((r->left - from->left) * to->width) / from->width) & ~1;
+	r->width = ((r->width * to->width) / from->width) & ~1;
+	r->top = ((r->top - from->top) * to->height) / from->height;
+	r->height = (r->height * to->height) / from->height;
+}
+
+bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
+{
+	/*
+	 * IF the left side of r1 is to the right of the right side of r2 OR
+	 *    the left side of r2 is to the right of the right side of r1 THEN
+	 * they do not overlap.
+	 */
+	if (r1->left >= r2->left + r2->width ||
+	    r2->left >= r1->left + r1->width)
+		return false;
+	/*
+	 * IF the top side of r1 is below the bottom of r2 OR
+	 *    the top side of r2 is below the bottom of r1 THEN
+	 * they do not overlap.
+	 */
+	if (r1->top >= r2->top + r2->height ||
+	    r2->top >= r1->top + r1->height)
+		return false;
+	return true;
+}
+int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r)
+{
+	unsigned w = r->width;
+	unsigned h = r->height;
+
+	if (!(flags & V4L2_SEL_FLAG_LE)) {
+		w++;
+		h++;
+		if (w < 2)
+			w = 2;
+		if (h < 2)
+			h = 2;
+	}
+	if (!(flags & V4L2_SEL_FLAG_GE)) {
+		if (w > MAX_WIDTH)
+			w = MAX_WIDTH;
+		if (h > MAX_HEIGHT)
+			h = MAX_HEIGHT;
+	}
+	w = w & ~1;
+	h = h & ~1;
+	if (w < 2 || h < 2)
+		return -ERANGE;
+	if (w > MAX_WIDTH || h > MAX_HEIGHT)
+		return -ERANGE;
+	if (r->top < 0)
+		r->top = 0;
+	if (r->left < 0)
+		r->left = 0;
+	r->left &= ~1;
+	r->top &= ~1;
+	if (r->left + w > MAX_WIDTH)
+		r->left = MAX_WIDTH - w;
+	if (r->top + h > MAX_HEIGHT)
+		r->top = MAX_HEIGHT - h;
+	if ((flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)) ==
+			(V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE) &&
+	    (r->width != w || r->height != h))
+		return -ERANGE;
+	r->width = w;
+	r->height = h;
+	return 0;
+}
+
+int vivid_enum_fmt_vid(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	const struct vivid_fmt *fmt;
+
+	if (f->index >= ARRAY_SIZE(vivid_formats) -
+	    (dev->multiplanar ? 0 : VIVID_MPLANAR_FORMATS))
+		return -EINVAL;
+
+	fmt = &vivid_formats[f->index];
+
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+	return 0;
+}
+
+int vidioc_enum_fmt_vid_mplane(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!dev->multiplanar)
+		return -ENOTTY;
+	return vivid_enum_fmt_vid(file, priv, f);
+}
+
+int vidioc_enum_fmt_vid(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (dev->multiplanar)
+		return -ENOTTY;
+	return vivid_enum_fmt_vid(file, priv, f);
+}
+
+int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX) {
+		if (!vivid_is_sdtv_cap(dev))
+			return -ENODATA;
+		*id = dev->std_cap;
+	} else {
+		if (!vivid_is_svid_out(dev))
+			return -ENODATA;
+		*id = dev->std_out;
+	}
+	return 0;
+}
+
+int vidioc_g_dv_timings(struct file *file, void *_fh,
+				    struct v4l2_dv_timings *timings)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX) {
+		if (!vivid_is_hdmi_cap(dev))
+			return -ENODATA;
+		*timings = dev->dv_timings_cap;
+	} else {
+		if (!vivid_is_hdmi_out(dev))
+			return -ENODATA;
+		*timings = dev->dv_timings_out;
+	}
+	return 0;
+}
+
+int vidioc_enum_dv_timings(struct file *file, void *_fh,
+				    struct v4l2_enum_dv_timings *timings)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX) {
+		if (!vivid_is_hdmi_cap(dev))
+			return -ENODATA;
+	} else {
+		if (!vivid_is_hdmi_out(dev))
+			return -ENODATA;
+	}
+	return v4l2_enum_dv_timings_cap(timings, &vivid_dv_timings_cap,
+			NULL, NULL);
+}
+
+int vidioc_dv_timings_cap(struct file *file, void *_fh,
+				    struct v4l2_dv_timings_cap *cap)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct video_device *vdev = video_devdata(file);
+
+	if (vdev->vfl_dir == VFL_DIR_RX) {
+		if (!vivid_is_hdmi_cap(dev))
+			return -ENODATA;
+	} else {
+		if (!vivid_is_hdmi_out(dev))
+			return -ENODATA;
+	}
+	*cap = vivid_dv_timings_cap;
+	return 0;
+}
+
+int vidioc_g_edid(struct file *file, void *_fh,
+			 struct v4l2_edid *edid)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct video_device *vdev = video_devdata(file);
+
+	memset(edid->reserved, 0, sizeof(edid->reserved));
+	if (vdev->vfl_dir == VFL_DIR_RX) {
+		if (edid->pad >= dev->num_inputs)
+			return -EINVAL;
+		if (dev->input_type[edid->pad] != HDMI)
+			return -EINVAL;
+	} else {
+		if (edid->pad >= dev->num_outputs)
+			return -EINVAL;
+		if (dev->output_type[edid->pad] != HDMI)
+			return -EINVAL;
+	}
+	if (edid->start_block == 0 && edid->blocks == 0) {
+		edid->blocks = dev->edid_blocks;
+		return 0;
+	}
+	if (dev->edid_blocks == 0)
+		return -ENODATA;
+	if (edid->start_block >= dev->edid_blocks)
+		return -EINVAL;
+	if (edid->start_block + edid->blocks > dev->edid_blocks)
+		edid->blocks = dev->edid_blocks - edid->start_block;
+	memcpy(edid->edid, dev->edid, edid->blocks * 128);
+	return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h
new file mode 100644
index 0000000..3ec4fa8
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-vid-common.h
@@ -0,0 +1,61 @@
+/*
+ * vivid-vid-common.h - common video support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_VID_COMMON_H_
+#define _VIVID_VID_COMMON_H_
+
+typedef int (*fmtfunc)(struct file *file, void *priv, struct v4l2_format *f);
+
+/*
+ * Conversion function that converts a single-planar format to a
+ * single-plane multiplanar format.
+ */
+void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt);
+int fmt_sp2mp_func(struct file *file, void *priv,
+		struct v4l2_format *f, fmtfunc func);
+
+extern const struct v4l2_dv_timings_cap vivid_dv_timings_cap;
+
+const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat);
+
+bool vivid_vid_can_loop(struct vivid_dev *dev);
+void vivid_send_source_change(struct vivid_dev *dev, unsigned type);
+
+bool rect_overlap(const struct v4l2_rect *r1, const struct v4l2_rect *r2);
+void rect_set_size_to(struct v4l2_rect *r, const struct v4l2_rect *size);
+void rect_set_min_size(struct v4l2_rect *r, const struct v4l2_rect *min_size);
+void rect_set_max_size(struct v4l2_rect *r, const struct v4l2_rect *max_size);
+void rect_map_inside(struct v4l2_rect *r, const struct v4l2_rect *boundary);
+bool rect_same_size(const struct v4l2_rect *r1, const struct v4l2_rect *r2);
+struct v4l2_rect rect_intersect(const struct v4l2_rect *a, const struct v4l2_rect *b);
+void rect_scale(struct v4l2_rect *r, const struct v4l2_rect *from,
+				     const struct v4l2_rect *to);
+int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r);
+
+int vivid_enum_fmt_vid(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_enum_fmt_vid_mplane(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_enum_fmt_vid(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id);
+int vidioc_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
+int vidioc_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings);
+int vidioc_dv_timings_cap(struct file *file, void *_fh, struct v4l2_dv_timings_cap *cap);
+int vidioc_g_edid(struct file *file, void *_fh, struct v4l2_edid *edid);
+int vidioc_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
new file mode 100644
index 0000000..69c2dbd
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-vid-out.c
@@ -0,0 +1,1146 @@
+/*
+ * vivid-vid-out.c - video output support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+
+#include "vivid-core.h"
+#include "vivid-vid-common.h"
+#include "vivid-kthread-out.h"
+#include "vivid-vid-out.h"
+
+static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+		       unsigned *nbuffers, unsigned *nplanes,
+		       unsigned sizes[], void *alloc_ctxs[])
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+	unsigned planes = dev->fmt_out->planes;
+	unsigned h = dev->fmt_out_rect.height;
+	unsigned size = dev->bytesperline_out[0] * h;
+
+	if (dev->field_out == V4L2_FIELD_ALTERNATE) {
+		/*
+		 * You cannot use write() with FIELD_ALTERNATE since the field
+		 * information (TOP/BOTTOM) cannot be passed to the kernel.
+		 */
+		if (vb2_fileio_is_active(vq))
+			return -EINVAL;
+	}
+
+	if (dev->queue_setup_error) {
+		/*
+		 * Error injection: test what happens if queue_setup() returns
+		 * an error.
+		 */
+		dev->queue_setup_error = false;
+		return -EINVAL;
+	}
+
+	if (fmt) {
+		const struct v4l2_pix_format_mplane *mp;
+		struct v4l2_format mp_fmt;
+
+		if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
+			fmt_sp2mp(fmt, &mp_fmt);
+			fmt = &mp_fmt;
+		}
+		mp = &fmt->fmt.pix_mp;
+		/*
+		 * Check if the number of planes in the specified format match
+		 * the number of planes in the current format. You can't mix that.
+		 */
+		if (mp->num_planes != planes)
+			return -EINVAL;
+		sizes[0] = mp->plane_fmt[0].sizeimage;
+		if (planes == 2) {
+			sizes[1] = mp->plane_fmt[1].sizeimage;
+			if (sizes[0] < dev->bytesperline_out[0] * h ||
+			    sizes[1] < dev->bytesperline_out[1] * h)
+				return -EINVAL;
+		} else if (sizes[0] < size) {
+			return -EINVAL;
+		}
+	} else {
+		if (planes == 2) {
+			sizes[0] = dev->bytesperline_out[0] * h;
+			sizes[1] = dev->bytesperline_out[1] * h;
+		} else {
+			sizes[0] = size;
+		}
+	}
+
+	if (vq->num_buffers + *nbuffers < 2)
+		*nbuffers = 2 - vq->num_buffers;
+
+	*nplanes = planes;
+
+	/*
+	 * videobuf2-vmalloc allocator is context-less so no need to set
+	 * alloc_ctxs array.
+	 */
+
+	if (planes == 2)
+		dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__,
+			*nbuffers, sizes[0], sizes[1]);
+	else
+		dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__,
+			*nbuffers, sizes[0]);
+	return 0;
+}
+
+static int vid_out_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	unsigned long size;
+	unsigned planes = dev->fmt_out->planes;
+	unsigned p;
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	if (WARN_ON(NULL == dev->fmt_out))
+		return -EINVAL;
+
+	if (dev->buf_prepare_error) {
+		/*
+		 * Error injection: test what happens if buf_prepare() returns
+		 * an error.
+		 */
+		dev->buf_prepare_error = false;
+		return -EINVAL;
+	}
+
+	if (dev->field_out != V4L2_FIELD_ALTERNATE)
+		vb->v4l2_buf.field = dev->field_out;
+	else if (vb->v4l2_buf.field != V4L2_FIELD_TOP &&
+		 vb->v4l2_buf.field != V4L2_FIELD_BOTTOM)
+		return -EINVAL;
+
+	for (p = 0; p < planes; p++) {
+		size = dev->bytesperline_out[p] * dev->fmt_out_rect.height +
+			vb->v4l2_planes[p].data_offset;
+
+		if (vb2_get_plane_payload(vb, p) < size) {
+			dprintk(dev, 1, "%s the payload is too small for plane %u (%lu < %lu)\n",
+					__func__, p, vb2_get_plane_payload(vb, p), size);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static void vid_out_buf_queue(struct vb2_buffer *vb)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct vivid_buffer *buf = container_of(vb, struct vivid_buffer, vb);
+
+	dprintk(dev, 1, "%s\n", __func__);
+
+	spin_lock(&dev->slock);
+	list_add_tail(&buf->list, &dev->vid_out_active);
+	spin_unlock(&dev->slock);
+}
+
+static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+	int err;
+
+	if (vb2_is_streaming(&dev->vb_vid_cap_q))
+		dev->can_loop_video = vivid_vid_can_loop(dev);
+
+	if (dev->kthread_vid_out)
+		return 0;
+
+	dev->vid_out_seq_count = 0;
+	dprintk(dev, 1, "%s\n", __func__);
+	if (dev->start_streaming_error) {
+		dev->start_streaming_error = false;
+		err = -EINVAL;
+	} else {
+		err = vivid_start_generating_vid_out(dev, &dev->vid_out_streaming);
+	}
+	if (err) {
+		struct vivid_buffer *buf, *tmp;
+
+		list_for_each_entry_safe(buf, tmp, &dev->vid_out_active, list) {
+			list_del(&buf->list);
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+		}
+	}
+	return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void vid_out_stop_streaming(struct vb2_queue *vq)
+{
+	struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+	dprintk(dev, 1, "%s\n", __func__);
+	vivid_stop_generating_vid_out(dev, &dev->vid_out_streaming);
+	dev->can_loop_video = false;
+}
+
+const struct vb2_ops vivid_vid_out_qops = {
+	.queue_setup		= vid_out_queue_setup,
+	.buf_prepare		= vid_out_buf_prepare,
+	.buf_queue		= vid_out_buf_queue,
+	.start_streaming	= vid_out_start_streaming,
+	.stop_streaming		= vid_out_stop_streaming,
+	.wait_prepare		= vivid_unlock,
+	.wait_finish		= vivid_lock,
+};
+
+/*
+ * Called whenever the format has to be reset which can occur when
+ * changing outputs, standard, timings, etc.
+ */
+void vivid_update_format_out(struct vivid_dev *dev)
+{
+	struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
+	unsigned size;
+
+	switch (dev->output_type[dev->output]) {
+	case SVID:
+	default:
+		dev->field_out = dev->tv_field_out;
+		dev->sink_rect.width = 720;
+		if (dev->std_out & V4L2_STD_525_60) {
+			dev->sink_rect.height = 480;
+			dev->timeperframe_vid_out = (struct v4l2_fract) { 1001, 30000 };
+			dev->service_set_out = V4L2_SLICED_CAPTION_525;
+		} else {
+			dev->sink_rect.height = 576;
+			dev->timeperframe_vid_out = (struct v4l2_fract) { 1000, 25000 };
+			dev->service_set_out = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B;
+		}
+		dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
+		break;
+	case HDMI:
+		dev->sink_rect.width = bt->width;
+		dev->sink_rect.height = bt->height;
+		size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
+		dev->timeperframe_vid_out = (struct v4l2_fract) {
+			size / 100, (u32)bt->pixelclock / 100
+		};
+		if (bt->interlaced)
+			dev->field_out = V4L2_FIELD_ALTERNATE;
+		else
+			dev->field_out = V4L2_FIELD_NONE;
+		if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) {
+			if (bt->width == 720 && bt->height <= 576)
+				dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
+			else
+				dev->colorspace_out = V4L2_COLORSPACE_REC709;
+		} else {
+			dev->colorspace_out = V4L2_COLORSPACE_SRGB;
+		}
+		break;
+	}
+	dev->compose_out = dev->sink_rect;
+	dev->compose_bounds_out = dev->sink_rect;
+	dev->crop_out = dev->compose_out;
+	if (V4L2_FIELD_HAS_T_OR_B(dev->field_out))
+		dev->crop_out.height /= 2;
+	dev->fmt_out_rect = dev->crop_out;
+	dev->bytesperline_out[0] = (dev->sink_rect.width * dev->fmt_out->depth) / 8;
+	if (dev->fmt_out->planes == 2)
+		dev->bytesperline_out[1] = (dev->sink_rect.width * dev->fmt_out->depth) / 8;
+}
+
+/* Map the field to something that is valid for the current output */
+static enum v4l2_field vivid_field_out(struct vivid_dev *dev, enum v4l2_field field)
+{
+	if (vivid_is_svid_out(dev)) {
+		switch (field) {
+		case V4L2_FIELD_INTERLACED_TB:
+		case V4L2_FIELD_INTERLACED_BT:
+		case V4L2_FIELD_SEQ_TB:
+		case V4L2_FIELD_SEQ_BT:
+		case V4L2_FIELD_ALTERNATE:
+			return field;
+		case V4L2_FIELD_INTERLACED:
+		default:
+			return V4L2_FIELD_INTERLACED;
+		}
+	}
+	if (vivid_is_hdmi_out(dev))
+		return dev->dv_timings_out.bt.interlaced ? V4L2_FIELD_ALTERNATE :
+						       V4L2_FIELD_NONE;
+	return V4L2_FIELD_NONE;
+}
+
+static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev)
+{
+	if (vivid_is_svid_out(dev))
+		return (dev->std_out & V4L2_STD_525_60) ?
+			TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
+
+	if (vivid_is_hdmi_out(dev) &&
+	    dev->sink_rect.width == 720 && dev->sink_rect.height <= 576)
+		return dev->sink_rect.height == 480 ?
+			TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL;
+
+	return TPG_PIXEL_ASPECT_SQUARE;
+}
+
+int vivid_g_fmt_vid_out(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+	unsigned p;
+
+	mp->width        = dev->fmt_out_rect.width;
+	mp->height       = dev->fmt_out_rect.height;
+	mp->field        = dev->field_out;
+	mp->pixelformat  = dev->fmt_out->fourcc;
+	mp->colorspace   = dev->colorspace_out;
+	mp->num_planes = dev->fmt_out->planes;
+	for (p = 0; p < mp->num_planes; p++) {
+		mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p];
+		mp->plane_fmt[p].sizeimage =
+			mp->plane_fmt[p].bytesperline * mp->height;
+	}
+	return 0;
+}
+
+int vivid_try_fmt_vid_out(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
+	struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+	struct v4l2_plane_pix_format *pfmt = mp->plane_fmt;
+	const struct vivid_fmt *fmt;
+	unsigned bytesperline, max_bpl;
+	unsigned factor = 1;
+	unsigned w, h;
+	unsigned p;
+
+	fmt = vivid_get_format(dev, mp->pixelformat);
+	if (!fmt) {
+		dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
+			mp->pixelformat);
+		mp->pixelformat = V4L2_PIX_FMT_YUYV;
+		fmt = vivid_get_format(dev, mp->pixelformat);
+	}
+
+	mp->field = vivid_field_out(dev, mp->field);
+	if (vivid_is_svid_out(dev)) {
+		w = 720;
+		h = (dev->std_out & V4L2_STD_525_60) ? 480 : 576;
+	} else {
+		w = dev->sink_rect.width;
+		h = dev->sink_rect.height;
+	}
+	if (V4L2_FIELD_HAS_T_OR_B(mp->field))
+		factor = 2;
+	if (!dev->has_scaler_out && !dev->has_crop_out && !dev->has_compose_out) {
+		mp->width = w;
+		mp->height = h / factor;
+	} else {
+		struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor };
+
+		rect_set_min_size(&r, &vivid_min_rect);
+		rect_set_max_size(&r, &vivid_max_rect);
+		if (dev->has_scaler_out && !dev->has_crop_out) {
+			struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h };
+
+			rect_set_max_size(&r, &max_r);
+		} else if (!dev->has_scaler_out && dev->has_compose_out && !dev->has_crop_out) {
+			rect_set_max_size(&r, &dev->sink_rect);
+		} else if (!dev->has_scaler_out && !dev->has_compose_out) {
+			rect_set_min_size(&r, &dev->sink_rect);
+		}
+		mp->width = r.width;
+		mp->height = r.height / factor;
+	}
+
+	/* This driver supports custom bytesperline values */
+
+	/* Calculate the minimum supported bytesperline value */
+	bytesperline = (mp->width * fmt->depth) >> 3;
+	/* Calculate the maximum supported bytesperline value */
+	max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3;
+	mp->num_planes = fmt->planes;
+	for (p = 0; p < mp->num_planes; p++) {
+		if (pfmt[p].bytesperline > max_bpl)
+			pfmt[p].bytesperline = max_bpl;
+		if (pfmt[p].bytesperline < bytesperline)
+			pfmt[p].bytesperline = bytesperline;
+		pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height;
+		memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
+	}
+	if (vivid_is_svid_out(dev))
+		mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861))
+		mp->colorspace = V4L2_COLORSPACE_SRGB;
+	else if (bt->width == 720 && bt->height <= 576)
+		mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M &&
+		 mp->colorspace != V4L2_COLORSPACE_REC709 &&
+		 mp->colorspace != V4L2_COLORSPACE_SRGB)
+		mp->colorspace = V4L2_COLORSPACE_REC709;
+	memset(mp->reserved, 0, sizeof(mp->reserved));
+	return 0;
+}
+
+int vivid_s_fmt_vid_out(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_rect *crop = &dev->crop_out;
+	struct v4l2_rect *compose = &dev->compose_out;
+	struct vb2_queue *q = &dev->vb_vid_out_q;
+	int ret = vivid_try_fmt_vid_out(file, priv, f);
+	unsigned factor = 1;
+
+	if (ret < 0)
+		return ret;
+
+	if (vb2_is_busy(q) &&
+	    (vivid_is_svid_out(dev) ||
+	     mp->width != dev->fmt_out_rect.width ||
+	     mp->height != dev->fmt_out_rect.height ||
+	     mp->pixelformat != dev->fmt_out->fourcc ||
+	     mp->field != dev->field_out)) {
+		dprintk(dev, 1, "%s device busy\n", __func__);
+		return -EBUSY;
+	}
+
+	/*
+	 * Allow for changing the colorspace on the fly. Useful for testing
+	 * purposes, and it is something that HDMI transmitters are able
+	 * to do.
+	 */
+	if (vb2_is_busy(q))
+		goto set_colorspace;
+
+	dev->fmt_out = vivid_get_format(dev, mp->pixelformat);
+	if (V4L2_FIELD_HAS_T_OR_B(mp->field))
+		factor = 2;
+
+	if (dev->has_scaler_out || dev->has_crop_out || dev->has_compose_out) {
+		struct v4l2_rect r = { 0, 0, mp->width, mp->height };
+
+		if (dev->has_scaler_out) {
+			if (dev->has_crop_out)
+				rect_map_inside(crop, &r);
+			else
+				*crop = r;
+			if (dev->has_compose_out && !dev->has_crop_out) {
+				struct v4l2_rect min_r = {
+					0, 0,
+					r.width / MAX_ZOOM,
+					factor * r.height / MAX_ZOOM
+				};
+				struct v4l2_rect max_r = {
+					0, 0,
+					r.width * MAX_ZOOM,
+					factor * r.height * MAX_ZOOM
+				};
+
+				rect_set_min_size(compose, &min_r);
+				rect_set_max_size(compose, &max_r);
+				rect_map_inside(compose, &dev->compose_bounds_out);
+			} else if (dev->has_compose_out) {
+				struct v4l2_rect min_r = {
+					0, 0,
+					crop->width / MAX_ZOOM,
+					factor * crop->height / MAX_ZOOM
+				};
+				struct v4l2_rect max_r = {
+					0, 0,
+					crop->width * MAX_ZOOM,
+					factor * crop->height * MAX_ZOOM
+				};
+
+				rect_set_min_size(compose, &min_r);
+				rect_set_max_size(compose, &max_r);
+				rect_map_inside(compose, &dev->compose_bounds_out);
+			}
+		} else if (dev->has_compose_out && !dev->has_crop_out) {
+			rect_set_size_to(crop, &r);
+			r.height *= factor;
+			rect_set_size_to(compose, &r);
+			rect_map_inside(compose, &dev->compose_bounds_out);
+		} else if (!dev->has_compose_out) {
+			rect_map_inside(crop, &r);
+			r.height /= factor;
+			rect_set_size_to(compose, &r);
+		} else {
+			r.height *= factor;
+			rect_set_max_size(compose, &r);
+			rect_map_inside(compose, &dev->compose_bounds_out);
+			crop->top *= factor;
+			crop->height *= factor;
+			rect_set_size_to(crop, compose);
+			rect_map_inside(crop, &r);
+			crop->top /= factor;
+			crop->height /= factor;
+		}
+	} else {
+		struct v4l2_rect r = { 0, 0, mp->width, mp->height };
+
+		rect_set_size_to(crop, &r);
+		r.height /= factor;
+		rect_set_size_to(compose, &r);
+	}
+
+	dev->fmt_out_rect.width = mp->width;
+	dev->fmt_out_rect.height = mp->height;
+	dev->bytesperline_out[0] = mp->plane_fmt[0].bytesperline;
+	if (mp->num_planes > 1)
+		dev->bytesperline_out[1] = mp->plane_fmt[1].bytesperline;
+	dev->field_out = mp->field;
+	if (vivid_is_svid_out(dev))
+		dev->tv_field_out = mp->field;
+
+set_colorspace:
+	dev->colorspace_out = mp->colorspace;
+	if (dev->loop_video) {
+		vivid_send_source_change(dev, SVID);
+		vivid_send_source_change(dev, HDMI);
+	}
+	return 0;
+}
+
+int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!dev->multiplanar)
+		return -ENOTTY;
+	return vivid_g_fmt_vid_out(file, priv, f);
+}
+
+int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!dev->multiplanar)
+		return -ENOTTY;
+	return vivid_try_fmt_vid_out(file, priv, f);
+}
+
+int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!dev->multiplanar)
+		return -ENOTTY;
+	return vivid_s_fmt_vid_out(file, priv, f);
+}
+
+int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (dev->multiplanar)
+		return -ENOTTY;
+	return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_out);
+}
+
+int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (dev->multiplanar)
+		return -ENOTTY;
+	return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_out);
+}
+
+int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (dev->multiplanar)
+		return -ENOTTY;
+	return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_out);
+}
+
+int vivid_vid_out_g_selection(struct file *file, void *priv,
+			      struct v4l2_selection *sel)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!dev->has_crop_out && !dev->has_compose_out)
+		return -ENOTTY;
+	if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	sel->r.left = sel->r.top = 0;
+	switch (sel->target) {
+	case V4L2_SEL_TGT_CROP:
+		if (!dev->has_crop_out)
+			return -EINVAL;
+		sel->r = dev->crop_out;
+		break;
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		if (!dev->has_crop_out)
+			return -EINVAL;
+		sel->r = dev->fmt_out_rect;
+		break;
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		if (!dev->has_compose_out)
+			return -EINVAL;
+		sel->r = vivid_max_rect;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		if (!dev->has_compose_out)
+			return -EINVAL;
+		sel->r = dev->compose_out;
+		break;
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		if (!dev->has_compose_out)
+			return -EINVAL;
+		sel->r = dev->sink_rect;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	struct v4l2_rect *crop = &dev->crop_out;
+	struct v4l2_rect *compose = &dev->compose_out;
+	unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_out) ? 2 : 1;
+	int ret;
+
+	if (!dev->has_crop_out && !dev->has_compose_out)
+		return -ENOTTY;
+	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+		if (!dev->has_crop_out)
+			return -EINVAL;
+		ret = vivid_vid_adjust_sel(s->flags, &s->r);
+		if (ret)
+			return ret;
+		rect_set_min_size(&s->r, &vivid_min_rect);
+		rect_set_max_size(&s->r, &dev->fmt_out_rect);
+		if (dev->has_scaler_out) {
+			struct v4l2_rect max_rect = {
+				0, 0,
+				dev->sink_rect.width * MAX_ZOOM,
+				(dev->sink_rect.height / factor) * MAX_ZOOM
+			};
+
+			rect_set_max_size(&s->r, &max_rect);
+			if (dev->has_compose_out) {
+				struct v4l2_rect min_rect = {
+					0, 0,
+					s->r.width / MAX_ZOOM,
+					(s->r.height * factor) / MAX_ZOOM
+				};
+				struct v4l2_rect max_rect = {
+					0, 0,
+					s->r.width * MAX_ZOOM,
+					(s->r.height * factor) * MAX_ZOOM
+				};
+
+				rect_set_min_size(compose, &min_rect);
+				rect_set_max_size(compose, &max_rect);
+				rect_map_inside(compose, &dev->compose_bounds_out);
+			}
+		} else if (dev->has_compose_out) {
+			s->r.top *= factor;
+			s->r.height *= factor;
+			rect_set_max_size(&s->r, &dev->sink_rect);
+			rect_set_size_to(compose, &s->r);
+			rect_map_inside(compose, &dev->compose_bounds_out);
+			s->r.top /= factor;
+			s->r.height /= factor;
+		} else {
+			rect_set_size_to(&s->r, &dev->sink_rect);
+			s->r.height /= factor;
+		}
+		rect_map_inside(&s->r, &dev->fmt_out_rect);
+		*crop = s->r;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		if (!dev->has_compose_out)
+			return -EINVAL;
+		ret = vivid_vid_adjust_sel(s->flags, &s->r);
+		if (ret)
+			return ret;
+		rect_set_min_size(&s->r, &vivid_min_rect);
+		rect_set_max_size(&s->r, &dev->sink_rect);
+		rect_map_inside(&s->r, &dev->compose_bounds_out);
+		s->r.top /= factor;
+		s->r.height /= factor;
+		if (dev->has_scaler_out) {
+			struct v4l2_rect fmt = dev->fmt_out_rect;
+			struct v4l2_rect max_rect = {
+				0, 0,
+				s->r.width * MAX_ZOOM,
+				s->r.height * MAX_ZOOM
+			};
+			struct v4l2_rect min_rect = {
+				0, 0,
+				s->r.width / MAX_ZOOM,
+				s->r.height / MAX_ZOOM
+			};
+
+			rect_set_min_size(&fmt, &min_rect);
+			if (!dev->has_crop_out)
+				rect_set_max_size(&fmt, &max_rect);
+			if (!rect_same_size(&dev->fmt_out_rect, &fmt) &&
+			    vb2_is_busy(&dev->vb_vid_out_q))
+				return -EBUSY;
+			if (dev->has_crop_out) {
+				rect_set_min_size(crop, &min_rect);
+				rect_set_max_size(crop, &max_rect);
+			}
+			dev->fmt_out_rect = fmt;
+		} else if (dev->has_crop_out) {
+			struct v4l2_rect fmt = dev->fmt_out_rect;
+
+			rect_set_min_size(&fmt, &s->r);
+			if (!rect_same_size(&dev->fmt_out_rect, &fmt) &&
+			    vb2_is_busy(&dev->vb_vid_out_q))
+				return -EBUSY;
+			dev->fmt_out_rect = fmt;
+			rect_set_size_to(crop, &s->r);
+			rect_map_inside(crop, &dev->fmt_out_rect);
+		} else {
+			if (!rect_same_size(&s->r, &dev->fmt_out_rect) &&
+			    vb2_is_busy(&dev->vb_vid_out_q))
+				return -EBUSY;
+			rect_set_size_to(&dev->fmt_out_rect, &s->r);
+			rect_set_size_to(crop, &s->r);
+			crop->height /= factor;
+			rect_map_inside(crop, &dev->fmt_out_rect);
+		}
+		s->r.top *= factor;
+		s->r.height *= factor;
+		if (dev->bitmap_out && (compose->width != s->r.width ||
+					compose->height != s->r.height)) {
+			kfree(dev->bitmap_out);
+			dev->bitmap_out = NULL;
+		}
+		*compose = s->r;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int vivid_vid_out_cropcap(struct file *file, void *priv,
+			      struct v4l2_cropcap *cap)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (cap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	switch (vivid_get_pixel_aspect(dev)) {
+	case TPG_PIXEL_ASPECT_NTSC:
+		cap->pixelaspect.numerator = 11;
+		cap->pixelaspect.denominator = 10;
+		break;
+	case TPG_PIXEL_ASPECT_PAL:
+		cap->pixelaspect.numerator = 54;
+		cap->pixelaspect.denominator = 59;
+		break;
+	case TPG_PIXEL_ASPECT_SQUARE:
+		cap->pixelaspect.numerator = 1;
+		cap->pixelaspect.denominator = 1;
+		break;
+	}
+	return 0;
+}
+
+int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	const struct v4l2_rect *compose = &dev->compose_out;
+	struct v4l2_window *win = &f->fmt.win;
+	unsigned clipcount = win->clipcount;
+
+	if (!dev->has_fb)
+		return -EINVAL;
+	win->w.top = dev->overlay_out_top;
+	win->w.left = dev->overlay_out_left;
+	win->w.width = compose->width;
+	win->w.height = compose->height;
+	win->clipcount = dev->clipcount_out;
+	win->field = V4L2_FIELD_ANY;
+	win->chromakey = dev->chromakey_out;
+	win->global_alpha = dev->global_alpha_out;
+	if (clipcount > dev->clipcount_out)
+		clipcount = dev->clipcount_out;
+	if (dev->bitmap_out == NULL)
+		win->bitmap = NULL;
+	else if (win->bitmap) {
+		if (copy_to_user(win->bitmap, dev->bitmap_out,
+		    ((dev->compose_out.width + 7) / 8) * dev->compose_out.height))
+			return -EFAULT;
+	}
+	if (clipcount && win->clips) {
+		if (copy_to_user(win->clips, dev->clips_out,
+				 clipcount * sizeof(dev->clips_out[0])))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	const struct v4l2_rect *compose = &dev->compose_out;
+	struct v4l2_window *win = &f->fmt.win;
+	int i, j;
+
+	if (!dev->has_fb)
+		return -EINVAL;
+	win->w.left = clamp_t(int, win->w.left,
+			      -dev->display_width, dev->display_width);
+	win->w.top = clamp_t(int, win->w.top,
+			     -dev->display_height, dev->display_height);
+	win->w.width = compose->width;
+	win->w.height = compose->height;
+	/*
+	 * It makes no sense for an OSD to overlay only top or bottom fields,
+	 * so always set this to ANY.
+	 */
+	win->field = V4L2_FIELD_ANY;
+	if (win->clipcount && !win->clips)
+		win->clipcount = 0;
+	if (win->clipcount > MAX_CLIPS)
+		win->clipcount = MAX_CLIPS;
+	if (win->clipcount) {
+		if (copy_from_user(dev->try_clips_out, win->clips,
+				   win->clipcount * sizeof(dev->clips_out[0])))
+			return -EFAULT;
+		for (i = 0; i < win->clipcount; i++) {
+			struct v4l2_rect *r = &dev->try_clips_out[i].c;
+
+			r->top = clamp_t(s32, r->top, 0, dev->display_height - 1);
+			r->height = clamp_t(s32, r->height, 1, dev->display_height - r->top);
+			r->left = clamp_t(u32, r->left, 0, dev->display_width - 1);
+			r->width = clamp_t(u32, r->width, 1, dev->display_width - r->left);
+		}
+		/*
+		 * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small
+		 * number and it's typically a one-time deal.
+		 */
+		for (i = 0; i < win->clipcount - 1; i++) {
+			struct v4l2_rect *r1 = &dev->try_clips_out[i].c;
+
+			for (j = i + 1; j < win->clipcount; j++) {
+				struct v4l2_rect *r2 = &dev->try_clips_out[j].c;
+
+				if (rect_overlap(r1, r2))
+					return -EINVAL;
+			}
+		}
+		if (copy_to_user(win->clips, dev->try_clips_out,
+				 win->clipcount * sizeof(dev->clips_out[0])))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	const struct v4l2_rect *compose = &dev->compose_out;
+	struct v4l2_window *win = &f->fmt.win;
+	int ret = vidioc_try_fmt_vid_out_overlay(file, priv, f);
+	unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height;
+	unsigned clips_size = win->clipcount * sizeof(dev->clips_out[0]);
+	void *new_bitmap = NULL;
+
+	if (ret)
+		return ret;
+
+	if (win->bitmap) {
+		new_bitmap = memdup_user(win->bitmap, bitmap_size);
+
+		if (IS_ERR(new_bitmap))
+			return PTR_ERR(new_bitmap);
+	}
+
+	dev->overlay_out_top = win->w.top;
+	dev->overlay_out_left = win->w.left;
+	kfree(dev->bitmap_out);
+	dev->bitmap_out = new_bitmap;
+	dev->clipcount_out = win->clipcount;
+	if (dev->clipcount_out)
+		memcpy(dev->clips_out, dev->try_clips_out, clips_size);
+	dev->chromakey_out = win->chromakey;
+	dev->global_alpha_out = win->global_alpha;
+	return ret;
+}
+
+int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (i && !dev->fmt_out->can_do_overlay) {
+		dprintk(dev, 1, "unsupported output format for output overlay\n");
+		return -EINVAL;
+	}
+
+	dev->overlay_out_enabled = i;
+	return 0;
+}
+
+int vivid_vid_out_g_fbuf(struct file *file, void *fh,
+				struct v4l2_framebuffer *a)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
+			V4L2_FBUF_CAP_BITMAP_CLIPPING |
+			V4L2_FBUF_CAP_LIST_CLIPPING |
+			V4L2_FBUF_CAP_CHROMAKEY |
+			V4L2_FBUF_CAP_SRC_CHROMAKEY |
+			V4L2_FBUF_CAP_GLOBAL_ALPHA |
+			V4L2_FBUF_CAP_LOCAL_ALPHA |
+			V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+	a->flags = V4L2_FBUF_FLAG_OVERLAY | dev->fbuf_out_flags;
+	a->base = (void *)dev->video_pbase;
+	a->fmt.width = dev->display_width;
+	a->fmt.height = dev->display_height;
+	if (dev->fb_defined.green.length == 5)
+		a->fmt.pixelformat = V4L2_PIX_FMT_ARGB555;
+	else
+		a->fmt.pixelformat = V4L2_PIX_FMT_RGB565;
+	a->fmt.bytesperline = dev->display_byte_stride;
+	a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline;
+	a->fmt.field = V4L2_FIELD_NONE;
+	a->fmt.colorspace = V4L2_COLORSPACE_SRGB;
+	a->fmt.priv = 0;
+	return 0;
+}
+
+int vivid_vid_out_s_fbuf(struct file *file, void *fh,
+				const struct v4l2_framebuffer *a)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+	const unsigned chroma_flags = V4L2_FBUF_FLAG_CHROMAKEY |
+				      V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+	const unsigned alpha_flags = V4L2_FBUF_FLAG_GLOBAL_ALPHA |
+				     V4L2_FBUF_FLAG_LOCAL_ALPHA |
+				     V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
+
+
+	if ((a->flags & chroma_flags) == chroma_flags)
+		return -EINVAL;
+	switch (a->flags & alpha_flags) {
+	case 0:
+	case V4L2_FBUF_FLAG_GLOBAL_ALPHA:
+	case V4L2_FBUF_FLAG_LOCAL_ALPHA:
+	case V4L2_FBUF_FLAG_LOCAL_INV_ALPHA:
+		break;
+	default:
+		return -EINVAL;
+	}
+	dev->fbuf_out_flags &= ~(chroma_flags | alpha_flags);
+	dev->fbuf_out_flags = a->flags & (chroma_flags | alpha_flags);
+	return 0;
+}
+
+static const struct v4l2_audioout vivid_audio_outputs[] = {
+	{ 0, "Line-Out 1" },
+	{ 1, "Line-Out 2" },
+};
+
+int vidioc_enum_output(struct file *file, void *priv,
+				struct v4l2_output *out)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (out->index >= dev->num_outputs)
+		return -EINVAL;
+
+	out->type = V4L2_OUTPUT_TYPE_ANALOG;
+	switch (dev->output_type[out->index]) {
+	case SVID:
+		snprintf(out->name, sizeof(out->name), "S-Video %u",
+				dev->output_name_counter[out->index]);
+		out->std = V4L2_STD_ALL;
+		if (dev->has_audio_outputs)
+			out->audioset = (1 << ARRAY_SIZE(vivid_audio_outputs)) - 1;
+		out->capabilities = V4L2_OUT_CAP_STD;
+		break;
+	case HDMI:
+		snprintf(out->name, sizeof(out->name), "HDMI %u",
+				dev->output_name_counter[out->index]);
+		out->capabilities = V4L2_OUT_CAP_DV_TIMINGS;
+		break;
+	}
+	return 0;
+}
+
+int vidioc_g_output(struct file *file, void *priv, unsigned *o)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	*o = dev->output;
+	return 0;
+}
+
+int vidioc_s_output(struct file *file, void *priv, unsigned o)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (o >= dev->num_outputs)
+		return -EINVAL;
+
+	if (o == dev->output)
+		return 0;
+
+	if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q))
+		return -EBUSY;
+
+	dev->output = o;
+	dev->tv_audio_output = 0;
+	if (dev->output_type[o] == SVID)
+		dev->vid_out_dev.tvnorms = V4L2_STD_ALL;
+	else
+		dev->vid_out_dev.tvnorms = 0;
+
+	dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms;
+	vivid_update_format_out(dev);
+	return 0;
+}
+
+int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout)
+{
+	if (vout->index >= ARRAY_SIZE(vivid_audio_outputs))
+		return -EINVAL;
+	*vout = vivid_audio_outputs[vout->index];
+	return 0;
+}
+
+int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!vivid_is_svid_out(dev))
+		return -EINVAL;
+	*vout = vivid_audio_outputs[dev->tv_audio_output];
+	return 0;
+}
+
+int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!vivid_is_svid_out(dev))
+		return -EINVAL;
+	if (vout->index >= ARRAY_SIZE(vivid_audio_outputs))
+		return -EINVAL;
+	dev->tv_audio_output = vout->index;
+	return 0;
+}
+
+int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!vivid_is_svid_out(dev))
+		return -ENODATA;
+	if (dev->std_out == id)
+		return 0;
+	if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q))
+		return -EBUSY;
+	dev->std_out = id;
+	vivid_update_format_out(dev);
+	return 0;
+}
+
+int vivid_vid_out_s_dv_timings(struct file *file, void *_fh,
+				    struct v4l2_dv_timings *timings)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (!vivid_is_hdmi_out(dev))
+		return -ENODATA;
+	if (vb2_is_busy(&dev->vb_vid_out_q))
+		return -EBUSY;
+	if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap,
+				0, NULL, NULL))
+		return -EINVAL;
+	if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0))
+		return 0;
+	dev->dv_timings_out = *timings;
+	vivid_update_format_out(dev);
+	return 0;
+}
+
+int vivid_vid_out_g_parm(struct file *file, void *priv,
+			  struct v4l2_streamparm *parm)
+{
+	struct vivid_dev *dev = video_drvdata(file);
+
+	if (parm->type != (dev->multiplanar ?
+			   V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+			   V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	parm->parm.output.capability   = V4L2_CAP_TIMEPERFRAME;
+	parm->parm.output.timeperframe = dev->timeperframe_vid_out;
+	parm->parm.output.writebuffers  = 1;
+return 0;
+}
+
+int vidioc_subscribe_event(struct v4l2_fh *fh,
+			const struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_CTRL:
+		return v4l2_ctrl_subscribe_event(fh, sub);
+	case V4L2_EVENT_SOURCE_CHANGE:
+		if (fh->vdev->vfl_dir == VFL_DIR_RX)
+			return v4l2_src_change_event_subscribe(fh, sub);
+		break;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
diff --git a/drivers/media/platform/vivid/vivid-vid-out.h b/drivers/media/platform/vivid/vivid-vid-out.h
new file mode 100644
index 0000000..dfa84db
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-vid-out.h
@@ -0,0 +1,56 @@
+/*
+ * vivid-vid-out.h - video output support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_VID_OUT_H_
+#define _VIVID_VID_OUT_H_
+
+extern const struct vb2_ops vivid_vid_out_qops;
+
+void vivid_update_format_out(struct vivid_dev *dev);
+
+int vivid_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_vid_out_g_selection(struct file *file, void *priv, struct v4l2_selection *sel);
+int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s);
+int vivid_vid_out_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cap);
+int vidioc_enum_fmt_vid_out_overlay(struct file *file, void  *priv, struct v4l2_fmtdesc *f);
+int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i);
+int vivid_vid_out_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a);
+int vivid_vid_out_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a);
+int vidioc_enum_output(struct file *file, void *priv, struct v4l2_output *out);
+int vidioc_g_output(struct file *file, void *priv, unsigned *i);
+int vidioc_s_output(struct file *file, void *priv, unsigned i);
+int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout);
+int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout);
+int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout);
+int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id);
+int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings);
+int vivid_vid_out_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm);
+
+#endif
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 550d1a4..fd0e944 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -332,7 +332,7 @@
 
 static void __exit gemtek_exit(void)
 {
-	hardmute = 1;	/* Turn off PLL */
+	hardmute = true;	/* Turn off PLL */
 #ifdef CONFIG_PNP
 	pnp_unregister_driver(&gemtek_driver.pnp_driver);
 #endif
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index d7ce8fe..28a8946 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -56,7 +56,7 @@
 
 static struct fmi fmi_card;
 static struct pnp_dev *dev;
-bool pnp_attached;
+static bool pnp_attached;
 
 #define RSF16_MINFREQ (87U * 16000)
 #define RSF16_MAXFREQ (108U * 16000)
@@ -285,7 +285,7 @@
 				io = isapnp_fmi_probe();
 				if (io < 0)
 					continue;
-				pnp_attached = 1;
+				pnp_attached = true;
 			}
 			if (!request_region(io, 2, "radio-sf16fmi")) {
 				if (pnp_attached)
@@ -349,7 +349,7 @@
 	mutex_init(&fmi->lock);
 
 	/* mute card and set default frequency */
-	fmi->mute = 1;
+	fmi->mute = true;
 	fmi->curfreq = RSF16_MINFREQ;
 	fmi_set_freq(fmi);
 
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 93d864e..b8d61cb 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -305,7 +305,7 @@
 	pnp_set_drvdata(pdev, NULL);
 }
 
-struct isa_driver fmr2_isa_driver = {
+static struct isa_driver fmr2_isa_driver = {
 	.match		= fmr2_isa_match,
 	.remove		= fmr2_isa_remove,
 	.driver		= {
@@ -313,7 +313,7 @@
 	},
 };
 
-struct pnp_driver fmr2_pnp_driver = {
+static struct pnp_driver fmr2_pnp_driver = {
 	.name		= "radio-sf16fmr2",
 	.id_table	= fmr2_pnp_ids,
 	.probe		= fmr2_pnp_probe,
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index 1b06ffa..0a4e7db 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -124,11 +124,11 @@
 
 struct tea5764_write_regs {
 	u8 intreg;				/* INTMSK */
-	u16 frqset;				/* FRQSETMSB & FRQSETLSB */
-	u16 tnctrl;				/* TNCTRL1 & TNCTRL2 */
-	u16 testreg;				/* TESTBITS & TESTMODE */
-	u16 rdsctrl;				/* RDSCTRL1 & RDSCTRL2 */
-	u16 rdsbbl;				/* PAUSEDET & RDSBBL */
+	__be16 frqset;				/* FRQSETMSB & FRQSETLSB */
+	__be16 tnctrl;				/* TNCTRL1 & TNCTRL2 */
+	__be16 testreg;				/* TESTBITS & TESTMODE */
+	__be16 rdsctrl;				/* RDSCTRL1 & RDSCTRL2 */
+	__be16 rdsbbl;				/* PAUSEDET & RDSBBL */
 } __attribute__ ((packed));
 
 #ifdef CPTCFG_RADIO_TEA5764_XTAL
@@ -165,7 +165,7 @@
 	if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1)
 		return -EIO;
 	for (i = 0; i < sizeof(struct tea5764_regs) / sizeof(u16); i++)
-		p[i] = __be16_to_cpu(p[i]);
+		p[i] = __be16_to_cpu((__force __be16)p[i]);
 
 	return 0;
 }
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 0e750ae..909c3f9 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -208,7 +208,7 @@
 static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
 {
 	int retval;
-	bool timed_out = 0;
+	bool timed_out = false;
 
 	/* start tuning */
 	radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
@@ -300,7 +300,7 @@
 {
 	int band, retval;
 	unsigned int freq;
-	bool timed_out = 0;
+	bool timed_out = false;
 
 	/* set band */
 	if (seek->rangelow || seek->rangehigh) {
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index 494fac0..57f0bc3 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -607,9 +607,7 @@
 	/* Set up interrupt endpoint information. */
 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
 		endpoint = &iface_desc->endpoint[i].desc;
-		if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
-		 USB_DIR_IN) && ((endpoint->bmAttributes &
-		 USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT))
+		if (usb_endpoint_is_int_in(endpoint))
 			radio->int_in_endpoint = endpoint;
 	}
 	if (!radio->int_in_endpoint) {
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index 4b2e9e8..6f28f6e 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -440,7 +440,7 @@
 		 * command with u16 payload - convert to be16
 		 */
 		if (payload != NULL)
-			*(u16 *)payload = cpu_to_be16(*(u16 *)payload);
+			*(__be16 *)payload = cpu_to_be16(*(u16 *)payload);
 
 	} else if (payload != NULL) {
 		fm_cb(skb)->fm_op = *((u8 *)payload + 2);
@@ -595,7 +595,7 @@
 	skb_pull(skb, sizeof(struct fm_event_msg_hdr));
 	memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen);
 
-	fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag);
+	fmdev->irq_info.flag = be16_to_cpu((__force __be16)fmdev->irq_info.flag);
 	fmdbg("irq: flag register(0x%x)\n", fmdev->irq_info.flag);
 
 	/* Continue next function in interrupt handler table */
@@ -764,7 +764,7 @@
 			 * Extract PI code and store in local cache.
 			 * We need this during AF switch processing.
 			 */
-			cur_picode = be16_to_cpu(rds_fmt.data.groupgeneral.pidata);
+			cur_picode = be16_to_cpu((__force __be16)rds_fmt.data.groupgeneral.pidata);
 			if (fmdev->rx.stat_info.picode != cur_picode)
 				fmdev->rx.stat_info.picode = cur_picode;
 
@@ -989,7 +989,7 @@
 	/* Skip header info and copy only response data */
 	skb_pull(skb, sizeof(struct fm_event_msg_hdr));
 	memcpy(&read_freq, skb->data, sizeof(read_freq));
-	read_freq = be16_to_cpu(read_freq);
+	read_freq = be16_to_cpu((__force __be16)read_freq);
 	curr_freq = fmdev->rx.region.bot_freq + ((u32)read_freq * FM_FREQ_MUL);
 
 	jumped_freq = fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx];
@@ -1317,7 +1317,8 @@
 /* Does FM power on sequence */
 static int fm_power_up(struct fmdev *fmdev, u8 mode)
 {
-	u16 payload, asic_id, asic_ver;
+	u16 payload;
+	__be16 asic_id, asic_ver;
 	int resp_len, ret;
 	u8 fw_name[50];
 
diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c
index ebf09a3..09632cb 100644
--- a/drivers/media/radio/wl128x/fmdrv_rx.c
+++ b/drivers/media/radio/wl128x/fmdrv_rx.c
@@ -116,7 +116,7 @@
 	if (ret < 0)
 		goto exit;
 
-	curr_frq = be16_to_cpu(curr_frq);
+	curr_frq = be16_to_cpu((__force __be16)curr_frq);
 	curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL));
 
 	if (curr_frq_in_khz != freq) {
@@ -189,7 +189,7 @@
 	if (ret < 0)
 		return ret;
 
-	curr_frq = be16_to_cpu(curr_frq);
+	curr_frq = be16_to_cpu((__force __be16)curr_frq);
 	last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
 
 	/* Check the offset in order to be aligned to the channel spacing*/
@@ -285,7 +285,7 @@
 		if (ret < 0)
 			return ret;
 
-		curr_frq = be16_to_cpu(curr_frq);
+		curr_frq = be16_to_cpu((__force __be16)curr_frq);
 		fmdev->rx.freq = (fmdev->rx.region.bot_freq +
 				((u32)curr_frq * FM_FREQ_MUL));
 
@@ -517,7 +517,7 @@
 /* Returns the signal strength level of current channel */
 int fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
 {
-	u16 curr_rssi_lel;
+	__be16 curr_rssi_lel;
 	u32 resp_len;
 	int ret;
 
@@ -608,7 +608,7 @@
 /* Gets current RX stereo/mono mode */
 int fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
 {
-	u16 curr_mode;
+	__be16 curr_mode;
 	u32 resp_len;
 	int ret;
 
diff --git a/drivers/media/radio/wl128x/fmdrv_tx.c b/drivers/media/radio/wl128x/fmdrv_tx.c
index 6ea33e0..839970b 100644
--- a/drivers/media/radio/wl128x/fmdrv_tx.c
+++ b/drivers/media/radio/wl128x/fmdrv_tx.c
@@ -374,7 +374,7 @@
 	if (ret < 0)
 		return ret;
 
-	curr_val = be16_to_cpu(curr_val);
+	curr_val = be16_to_cpu((__force __be16)curr_val);
 
 	return curr_val;
 }
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 797867f..a4c907d 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -178,6 +178,19 @@
 	   To compile this driver as a module, choose M here: the
 	   module will be called ene_ir.
 
+config IR_HIX5HD2
+	depends on !BACKPORT_KERNEL_3_7
+	depends on CONFIG_MFD_SYSCON
+	tristate "Hisilicon hix5hd2 IR remote control"
+	depends on m
+	depends on RC_CORE
+	help
+	 Say Y here if you want to use hisilicon hix5hd2 remote control.
+	 To compile this driver as a module, choose M here: the module will be
+	 called ir-hix5hd2.
+
+	 If you're not sure, select N here
+
 config IR_IMON
 	tristate "SoundGraph iMON Receiver and Display"
 	depends on m
@@ -361,7 +374,8 @@
 config RC_ST
 	tristate "ST remote control receiver"
 	depends on m
-	depends on ARCH_STI && RC_CORE
+	depends on RC_CORE
+	depends on ARCH_STI || COMPILE_TEST
 	help
 	 Say Y here if you want support for ST remote control driver
 	 which allows both IR and UHF RX.
@@ -373,7 +387,7 @@
     tristate "SUNXI IR remote control"
     depends on m
     depends on RC_CORE
-    depends on ARCH_SUNXI
+    depends on ARCH_SUNXI || COMPILE_TEST
     ---help---
       Say Y if you want to use sunXi internal IR Controller
 
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 58cb9fb..9bba1fd 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -17,6 +17,7 @@
 
 # stand-alone IR receivers/transmitters
 obj-$(CPTCFG_RC_ATI_REMOTE) += ati_remote.o
+obj-$(CPTCFG_IR_HIX5HD2) += ir-hix5hd2.o
 obj-$(CPTCFG_IR_IMON) += imon.o
 obj-$(CPTCFG_IR_ITE_CIR) += ite-cir.o
 obj-$(CPTCFG_IR_MCEUSB) += mceusb.o
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index d16d9b4..e80f2c6 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -979,7 +979,7 @@
 	dev->tx_reg = 0;
 	dev->tx_done = 0;
 	dev->tx_sample = 0;
-	dev->tx_sample_pulse = 0;
+	dev->tx_sample_pulse = false;
 
 	dbg("TX: %d samples", dev->tx_len);
 
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index f0a1f7d..b516757 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -148,7 +148,6 @@
 	u8 vendor_major, vendor_minor;
 	u8 portsel, ir_class;
 	u16 vendor, chip;
-	int ret = 0;
 
 	fintek_config_mode_enable(fintek);
 
@@ -208,7 +207,7 @@
 
 	spin_unlock_irqrestore(&fintek->fintek_lock, flags);
 
-	return ret;
+	return 0;
 }
 
 static void fintek_cir_ldev_init(struct fintek_dev *fintek)
@@ -644,7 +643,6 @@
 
 static int fintek_resume(struct pnp_dev *pdev)
 {
-	int ret = 0;
 	struct fintek_dev *fintek = pnp_get_drvdata(pdev);
 
 	fit_dbg("%s called", __func__);
@@ -661,7 +659,7 @@
 
 	fintek_cir_regs_init(fintek);
 
-	return ret;
+	return 0;
 }
 
 static void fintek_shutdown(struct pnp_dev *pdev)
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index 6ca014c..2ccc3bd 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -25,12 +25,6 @@
 /* Decoders lock (only modified to preprocess them) */
 static DEFINE_SPINLOCK(img_ir_decoders_lock);
 
-extern struct img_ir_decoder img_ir_nec;
-extern struct img_ir_decoder img_ir_jvc;
-extern struct img_ir_decoder img_ir_sony;
-extern struct img_ir_decoder img_ir_sharp;
-extern struct img_ir_decoder img_ir_sanyo;
-
 static bool img_ir_decoders_preprocessed;
 static struct img_ir_decoder *img_ir_decoders[] = {
 #ifdef CPTCFG_IR_IMG_NEC
diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h
index 6000ec8..9119bd1 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.h
+++ b/drivers/media/rc/img-ir/img-ir-hw.h
@@ -168,6 +168,12 @@
 		      struct img_ir_filter *out, u64 protocols);
 };
 
+extern struct img_ir_decoder img_ir_nec;
+extern struct img_ir_decoder img_ir_jvc;
+extern struct img_ir_decoder img_ir_sony;
+extern struct img_ir_decoder img_ir_sharp;
+extern struct img_ir_decoder img_ir_sanyo;
+
 /**
  * struct img_ir_reg_timings - Reg values for decoder timings at clock rate.
  * @ctrl:	Processed control register value.
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 7115e68..b8837dd 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -87,6 +87,18 @@
 
 /*** G L O B A L S ***/
 
+struct imon_panel_key_table {
+	u64 hw_code;
+	u32 keycode;
+};
+
+struct imon_usb_dev_descr {
+	__u16 flags;
+#define IMON_NO_FLAGS 0
+#define IMON_NEED_20MS_PKT_DELAY 1
+	struct imon_panel_key_table key_table[];
+};
+
 struct imon_context {
 	struct device *dev;
 	/* Newer devices have two interfaces */
@@ -150,6 +162,8 @@
 	struct timer_list ttimer;	/* touch screen timer */
 	int touch_x;			/* x coordinate on touchscreen */
 	int touch_y;			/* y coordinate on touchscreen */
+	struct imon_usb_dev_descr *dev_descr; /* device description with key
+						 table for front panels */
 };
 
 #define TOUCH_TIMEOUT	(HZ/30)
@@ -186,8 +200,132 @@
 	IMON_KEY_PANEL	= 2,
 };
 
-enum {
-	IMON_NEED_20MS_PKT_DELAY = 1
+static struct usb_class_driver imon_vfd_class = {
+	.name		= DEVICE_NAME,
+	.fops		= &vfd_fops,
+	.minor_base	= DISPLAY_MINOR_BASE,
+};
+
+static struct usb_class_driver imon_lcd_class = {
+	.name		= DEVICE_NAME,
+	.fops		= &lcd_fops,
+	.minor_base	= DISPLAY_MINOR_BASE,
+};
+
+/* imon receiver front panel/knob key table */
+static const struct imon_usb_dev_descr imon_default_table = {
+	.flags = IMON_NO_FLAGS,
+	.key_table = {
+		{ 0x000000000f00ffeell, KEY_MEDIA }, /* Go */
+		{ 0x000000001200ffeell, KEY_UP },
+		{ 0x000000001300ffeell, KEY_DOWN },
+		{ 0x000000001400ffeell, KEY_LEFT },
+		{ 0x000000001500ffeell, KEY_RIGHT },
+		{ 0x000000001600ffeell, KEY_ENTER },
+		{ 0x000000001700ffeell, KEY_ESC },
+		{ 0x000000001f00ffeell, KEY_AUDIO },
+		{ 0x000000002000ffeell, KEY_VIDEO },
+		{ 0x000000002100ffeell, KEY_CAMERA },
+		{ 0x000000002700ffeell, KEY_DVD },
+		{ 0x000000002300ffeell, KEY_TV },
+		{ 0x000000002b00ffeell, KEY_EXIT },
+		{ 0x000000002c00ffeell, KEY_SELECT },
+		{ 0x000000002d00ffeell, KEY_MENU },
+		{ 0x000000000500ffeell, KEY_PREVIOUS },
+		{ 0x000000000700ffeell, KEY_REWIND },
+		{ 0x000000000400ffeell, KEY_STOP },
+		{ 0x000000003c00ffeell, KEY_PLAYPAUSE },
+		{ 0x000000000800ffeell, KEY_FASTFORWARD },
+		{ 0x000000000600ffeell, KEY_NEXT },
+		{ 0x000000010000ffeell, KEY_RIGHT },
+		{ 0x000001000000ffeell, KEY_LEFT },
+		{ 0x000000003d00ffeell, KEY_SELECT },
+		{ 0x000100000000ffeell, KEY_VOLUMEUP },
+		{ 0x010000000000ffeell, KEY_VOLUMEDOWN },
+		{ 0x000000000100ffeell, KEY_MUTE },
+		/* 0xffdc iMON MCE VFD */
+		{ 0x00010000ffffffeell, KEY_VOLUMEUP },
+		{ 0x01000000ffffffeell, KEY_VOLUMEDOWN },
+		{ 0x00000001ffffffeell, KEY_MUTE },
+		{ 0x0000000fffffffeell, KEY_MEDIA },
+		{ 0x00000012ffffffeell, KEY_UP },
+		{ 0x00000013ffffffeell, KEY_DOWN },
+		{ 0x00000014ffffffeell, KEY_LEFT },
+		{ 0x00000015ffffffeell, KEY_RIGHT },
+		{ 0x00000016ffffffeell, KEY_ENTER },
+		{ 0x00000017ffffffeell, KEY_ESC },
+		/* iMON Knob values */
+		{ 0x000100ffffffffeell, KEY_VOLUMEUP },
+		{ 0x010000ffffffffeell, KEY_VOLUMEDOWN },
+		{ 0x000008ffffffffeell, KEY_MUTE },
+		{ 0, KEY_RESERVED },
+	}
+};
+
+static const struct imon_usb_dev_descr imon_OEM_VFD = {
+	.flags = IMON_NEED_20MS_PKT_DELAY,
+	.key_table = {
+		{ 0x000000000f00ffeell, KEY_MEDIA }, /* Go */
+		{ 0x000000001200ffeell, KEY_UP },
+		{ 0x000000001300ffeell, KEY_DOWN },
+		{ 0x000000001400ffeell, KEY_LEFT },
+		{ 0x000000001500ffeell, KEY_RIGHT },
+		{ 0x000000001600ffeell, KEY_ENTER },
+		{ 0x000000001700ffeell, KEY_ESC },
+		{ 0x000000001f00ffeell, KEY_AUDIO },
+		{ 0x000000002b00ffeell, KEY_EXIT },
+		{ 0x000000002c00ffeell, KEY_SELECT },
+		{ 0x000000002d00ffeell, KEY_MENU },
+		{ 0x000000000500ffeell, KEY_PREVIOUS },
+		{ 0x000000000700ffeell, KEY_REWIND },
+		{ 0x000000000400ffeell, KEY_STOP },
+		{ 0x000000003c00ffeell, KEY_PLAYPAUSE },
+		{ 0x000000000800ffeell, KEY_FASTFORWARD },
+		{ 0x000000000600ffeell, KEY_NEXT },
+		{ 0x000000010000ffeell, KEY_RIGHT },
+		{ 0x000001000000ffeell, KEY_LEFT },
+		{ 0x000000003d00ffeell, KEY_SELECT },
+		{ 0x000100000000ffeell, KEY_VOLUMEUP },
+		{ 0x010000000000ffeell, KEY_VOLUMEDOWN },
+		{ 0x000000000100ffeell, KEY_MUTE },
+		/* 0xffdc iMON MCE VFD */
+		{ 0x00010000ffffffeell, KEY_VOLUMEUP },
+		{ 0x01000000ffffffeell, KEY_VOLUMEDOWN },
+		{ 0x00000001ffffffeell, KEY_MUTE },
+		{ 0x0000000fffffffeell, KEY_MEDIA },
+		{ 0x00000012ffffffeell, KEY_UP },
+		{ 0x00000013ffffffeell, KEY_DOWN },
+		{ 0x00000014ffffffeell, KEY_LEFT },
+		{ 0x00000015ffffffeell, KEY_RIGHT },
+		{ 0x00000016ffffffeell, KEY_ENTER },
+		{ 0x00000017ffffffeell, KEY_ESC },
+		/* iMON Knob values */
+		{ 0x000100ffffffffeell, KEY_VOLUMEUP },
+		{ 0x010000ffffffffeell, KEY_VOLUMEDOWN },
+		{ 0x000008ffffffffeell, KEY_MUTE },
+		{ 0, KEY_RESERVED },
+	}
+};
+
+/* imon receiver front panel/knob key table for DH102*/
+static const struct imon_usb_dev_descr imon_DH102 = {
+	.flags = IMON_NO_FLAGS,
+	.key_table = {
+		{ 0x000100000000ffeell, KEY_VOLUMEUP },
+		{ 0x010000000000ffeell, KEY_VOLUMEDOWN },
+		{ 0x000000010000ffeell, KEY_MUTE },
+		{ 0x0000000f0000ffeell, KEY_MEDIA },
+		{ 0x000000120000ffeell, KEY_UP },
+		{ 0x000000130000ffeell, KEY_DOWN },
+		{ 0x000000140000ffeell, KEY_LEFT },
+		{ 0x000000150000ffeell, KEY_RIGHT },
+		{ 0x000000160000ffeell, KEY_ENTER },
+		{ 0x000000170000ffeell, KEY_ESC },
+		{ 0x0000002b0000ffeell, KEY_EXIT },
+		{ 0x0000002c0000ffeell, KEY_SELECT },
+		{ 0x0000002d0000ffeell, KEY_MENU },
+		{ 0, KEY_RESERVED }
+	}
 };
 
 /*
@@ -208,7 +346,8 @@
 	 * SoundGraph iMON PAD (IR & LCD)
 	 * SoundGraph iMON Knob (IR only)
 	 */
-	{ USB_DEVICE(0x15c2, 0xffdc) },
+	{ USB_DEVICE(0x15c2, 0xffdc),
+	  .driver_info = (unsigned long)&imon_default_table },
 
 	/*
 	 * Newer devices, all driven by the latest iMON Windows driver, full
@@ -216,43 +355,62 @@
 	 * Need user input to fill in details on unknown devices.
 	 */
 	/* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */
-	{ USB_DEVICE(0x15c2, 0x0034) },
+	{ USB_DEVICE(0x15c2, 0x0034),
+	  .driver_info = (unsigned long)&imon_DH102 },
 	/* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */
-	{ USB_DEVICE(0x15c2, 0x0035) },
+	{ USB_DEVICE(0x15c2, 0x0035),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* SoundGraph iMON OEM VFD (IR & VFD) */
-	{ USB_DEVICE(0x15c2, 0x0036), .driver_info = IMON_NEED_20MS_PKT_DELAY },
+	{ USB_DEVICE(0x15c2, 0x0036),
+	  .driver_info = (unsigned long)&imon_OEM_VFD },
 	/* device specifics unknown */
-	{ USB_DEVICE(0x15c2, 0x0037) },
+	{ USB_DEVICE(0x15c2, 0x0037),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* SoundGraph iMON OEM LCD (IR & LCD) */
-	{ USB_DEVICE(0x15c2, 0x0038) },
+	{ USB_DEVICE(0x15c2, 0x0038),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* SoundGraph iMON UltraBay (IR & LCD) */
-	{ USB_DEVICE(0x15c2, 0x0039) },
+	{ USB_DEVICE(0x15c2, 0x0039),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* device specifics unknown */
-	{ USB_DEVICE(0x15c2, 0x003a) },
+	{ USB_DEVICE(0x15c2, 0x003a),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* device specifics unknown */
-	{ USB_DEVICE(0x15c2, 0x003b) },
+	{ USB_DEVICE(0x15c2, 0x003b),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* SoundGraph iMON OEM Inside (IR only) */
-	{ USB_DEVICE(0x15c2, 0x003c) },
+	{ USB_DEVICE(0x15c2, 0x003c),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* device specifics unknown */
-	{ USB_DEVICE(0x15c2, 0x003d) },
+	{ USB_DEVICE(0x15c2, 0x003d),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* device specifics unknown */
-	{ USB_DEVICE(0x15c2, 0x003e) },
+	{ USB_DEVICE(0x15c2, 0x003e),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* device specifics unknown */
-	{ USB_DEVICE(0x15c2, 0x003f) },
+	{ USB_DEVICE(0x15c2, 0x003f),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* device specifics unknown */
-	{ USB_DEVICE(0x15c2, 0x0040) },
+	{ USB_DEVICE(0x15c2, 0x0040),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* SoundGraph iMON MINI (IR only) */
-	{ USB_DEVICE(0x15c2, 0x0041) },
+	{ USB_DEVICE(0x15c2, 0x0041),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* Antec Veris Multimedia Station EZ External (IR only) */
-	{ USB_DEVICE(0x15c2, 0x0042) },
+	{ USB_DEVICE(0x15c2, 0x0042),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* Antec Veris Multimedia Station Basic Internal (IR only) */
-	{ USB_DEVICE(0x15c2, 0x0043) },
+	{ USB_DEVICE(0x15c2, 0x0043),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* Antec Veris Multimedia Station Elite (IR & VFD) */
-	{ USB_DEVICE(0x15c2, 0x0044) },
+	{ USB_DEVICE(0x15c2, 0x0044),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* Antec Veris Multimedia Station Premiere (IR & LCD) */
-	{ USB_DEVICE(0x15c2, 0x0045) },
+	{ USB_DEVICE(0x15c2, 0x0045),
+	  .driver_info = (unsigned long)&imon_default_table},
 	/* device specifics unknown */
-	{ USB_DEVICE(0x15c2, 0x0046) },
+	{ USB_DEVICE(0x15c2, 0x0046),
+	  .driver_info = (unsigned long)&imon_default_table},
 	{}
 };
 
@@ -266,67 +424,6 @@
 	.id_table	= imon_usb_id_table,
 };
 
-static struct usb_class_driver imon_vfd_class = {
-	.name		= DEVICE_NAME,
-	.fops		= &vfd_fops,
-	.minor_base	= DISPLAY_MINOR_BASE,
-};
-
-static struct usb_class_driver imon_lcd_class = {
-	.name		= DEVICE_NAME,
-	.fops		= &lcd_fops,
-	.minor_base	= DISPLAY_MINOR_BASE,
-};
-
-/* imon receiver front panel/knob key table */
-static const struct {
-	u64 hw_code;
-	u32 keycode;
-} imon_panel_key_table[] = {
-	{ 0x000000000f00ffeell, KEY_MEDIA }, /* Go */
-	{ 0x000000001200ffeell, KEY_UP },
-	{ 0x000000001300ffeell, KEY_DOWN },
-	{ 0x000000001400ffeell, KEY_LEFT },
-	{ 0x000000001500ffeell, KEY_RIGHT },
-	{ 0x000000001600ffeell, KEY_ENTER },
-	{ 0x000000001700ffeell, KEY_ESC },
-	{ 0x000000001f00ffeell, KEY_AUDIO },
-	{ 0x000000002000ffeell, KEY_VIDEO },
-	{ 0x000000002100ffeell, KEY_CAMERA },
-	{ 0x000000002700ffeell, KEY_DVD },
-	{ 0x000000002300ffeell, KEY_TV },
-	{ 0x000000002b00ffeell, KEY_EXIT },
-	{ 0x000000002c00ffeell, KEY_SELECT },
-	{ 0x000000002d00ffeell, KEY_MENU },
-	{ 0x000000000500ffeell, KEY_PREVIOUS },
-	{ 0x000000000700ffeell, KEY_REWIND },
-	{ 0x000000000400ffeell, KEY_STOP },
-	{ 0x000000003c00ffeell, KEY_PLAYPAUSE },
-	{ 0x000000000800ffeell, KEY_FASTFORWARD },
-	{ 0x000000000600ffeell, KEY_NEXT },
-	{ 0x000000010000ffeell, KEY_RIGHT },
-	{ 0x000001000000ffeell, KEY_LEFT },
-	{ 0x000000003d00ffeell, KEY_SELECT },
-	{ 0x000100000000ffeell, KEY_VOLUMEUP },
-	{ 0x010000000000ffeell, KEY_VOLUMEDOWN },
-	{ 0x000000000100ffeell, KEY_MUTE },
-	/* 0xffdc iMON MCE VFD */
-	{ 0x00010000ffffffeell, KEY_VOLUMEUP },
-	{ 0x01000000ffffffeell, KEY_VOLUMEDOWN },
-	{ 0x00000001ffffffeell, KEY_MUTE },
-	{ 0x0000000fffffffeell, KEY_MEDIA },
-	{ 0x00000012ffffffeell, KEY_UP },
-	{ 0x00000013ffffffeell, KEY_DOWN },
-	{ 0x00000014ffffffeell, KEY_LEFT },
-	{ 0x00000015ffffffeell, KEY_RIGHT },
-	{ 0x00000016ffffffeell, KEY_ENTER },
-	{ 0x00000017ffffffeell, KEY_ESC },
-	/* iMON Knob values */
-	{ 0x000100ffffffffeell, KEY_VOLUMEUP },
-	{ 0x010000ffffffffeell, KEY_VOLUMEDOWN },
-	{ 0x000008ffffffffeell, KEY_MUTE },
-};
-
 /* to prevent races between open() and disconnect(), probing, etc */
 static DEFINE_MUTEX(driver_lock);
 
@@ -1210,18 +1307,19 @@
 	return keycode;
 }
 
-static u32 imon_panel_key_lookup(u64 code)
+static u32 imon_panel_key_lookup(struct imon_context *ictx, u64 code)
 {
 	int i;
 	u32 keycode = KEY_RESERVED;
+	struct imon_panel_key_table *key_table = ictx->dev_descr->key_table;
 
-	for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
-		if (imon_panel_key_table[i].hw_code == (code | 0xffee)) {
-			keycode = imon_panel_key_table[i].keycode;
+	for (i = 0; key_table[i].hw_code != 0; i++) {
+		if (key_table[i].hw_code == (code | 0xffee)) {
+			keycode = key_table[i].keycode;
 			break;
 		}
 	}
-
+	ictx->release_code = false;
 	return keycode;
 }
 
@@ -1340,7 +1438,7 @@
 				}
 				buf[2] = dir & 0xFF;
 				buf[3] = (dir >> 8) & 0xFF;
-				scancode = be32_to_cpu(*((u32 *)buf));
+				scancode = be32_to_cpu(*((__be32 *)buf));
 			}
 		} else {
 			/*
@@ -1404,7 +1502,7 @@
 			}
 			buf[2] = dir & 0xFF;
 			buf[3] = (dir >> 8) & 0xFF;
-			scancode = be32_to_cpu(*((u32 *)buf));
+			scancode = be32_to_cpu(*((__be32 *)buf));
 		} else {
 			/*
 			 * Hack alert: instead of using keycodes, we have
@@ -1509,11 +1607,12 @@
 
 	/* Figure out what key was pressed */
 	if (len == 8 && buf[7] == 0xee) {
-		scancode = be64_to_cpu(*((u64 *)buf));
+		scancode = be64_to_cpu(*((__be64 *)buf));
 		ktype = IMON_KEY_PANEL;
-		kc = imon_panel_key_lookup(scancode);
+		kc = imon_panel_key_lookup(ictx, scancode);
+		ictx->release_code = false;
 	} else {
-		scancode = be32_to_cpu(*((u32 *)buf));
+		scancode = be32_to_cpu(*((__be32 *)buf));
 		if (ictx->rc_type == RC_BIT_RC6_MCE) {
 			ktype = IMON_KEY_IMON;
 			if (buf[0] == 0x80)
@@ -1908,6 +2007,7 @@
 
 static struct input_dev *imon_init_idev(struct imon_context *ictx)
 {
+	struct imon_panel_key_table *key_table = ictx->dev_descr->key_table;
 	struct input_dev *idev;
 	int ret, i;
 
@@ -1933,8 +2033,8 @@
 		BIT_MASK(REL_WHEEL);
 
 	/* panel and/or knob code support */
-	for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
-		u32 kc = imon_panel_key_table[i].keycode;
+	for (i = 0; key_table[i].hw_code != 0; i++) {
+		u32 kc = key_table[i].keycode;
 		__set_bit(kc, idev->keybit);
 	}
 
@@ -2023,7 +2123,7 @@
 	for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
 		ep = &iface_desc->endpoint[i].desc;
 		ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
-		ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+		ep_type = usb_endpoint_type(ep);
 
 		if (!ir_ep_found && ep_dir == USB_DIR_IN &&
 		    ep_type == USB_ENDPOINT_XFER_INT) {
@@ -2135,9 +2235,11 @@
 	ictx->vendor  = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
 	ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
 
+	/* save drive info for later accessing the panel/knob key table */
+	ictx->dev_descr = (struct imon_usb_dev_descr *)id->driver_info;
 	/* default send_packet delay is 5ms but some devices need more */
-	ictx->send_packet_delay = id->driver_info & IMON_NEED_20MS_PKT_DELAY ?
-				  20 : 5;
+	ictx->send_packet_delay = ictx->dev_descr->flags &
+				  IMON_NEED_20MS_PKT_DELAY ? 20 : 5;
 
 	ret = -ENODEV;
 	iface_desc = intf->cur_altsetting;
@@ -2181,6 +2283,7 @@
 	usb_kill_urb(ictx->rx_urb_intf0);
 urb_submit_failed:
 find_endpoint_failed:
+	usb_put_dev(ictx->usbdev_intf0);
 	mutex_unlock(&ictx->lock);
 	usb_free_urb(tx_urb);
 tx_urb_alloc_failed:
@@ -2253,6 +2356,7 @@
 		input_unregister_device(ictx->touch);
 touch_setup_failed:
 find_endpoint_failed:
+	usb_put_dev(ictx->usbdev_intf1);
 	mutex_unlock(&ictx->lock);
 	usb_free_urb(rx_urb);
 rx_urb_alloc_failed:
@@ -2366,11 +2470,13 @@
 		 usbdev->bus->busnum, usbdev->devnum);
 
 	mutex_unlock(&driver_lock);
+	usb_put_dev(usbdev);
 
 	return 0;
 
 fail:
 	mutex_unlock(&driver_lock);
+	usb_put_dev(usbdev);
 	dev_err(dev, "unable to register, err %d\n", ret);
 
 	return ret;
@@ -2410,6 +2516,7 @@
 	if (ifnum == 0) {
 		ictx->dev_present_intf0 = false;
 		usb_kill_urb(ictx->rx_urb_intf0);
+		usb_put_dev(ictx->usbdev_intf0);
 		input_unregister_device(ictx->idev);
 		rc_unregister_device(ictx->rdev);
 		if (ictx->display_supported) {
@@ -2421,6 +2528,7 @@
 	} else {
 		ictx->dev_present_intf1 = false;
 		usb_kill_urb(ictx->rx_urb_intf1);
+		usb_put_dev(ictx->usbdev_intf1);
 		if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
 			input_unregister_device(ictx->touch);
 			del_timer_sync(&ictx->ttimer);
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
new file mode 100644
index 0000000..b6bcf2b
--- /dev/null
+++ b/drivers/media/rc/ir-hix5hd2.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2014 Linaro Ltd.
+ * Copyright (c) 2014 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <media/rc-core.h>
+#include <linux/of.h>
+
+/* Allow the driver to compile on all architectures */
+#ifndef writel_relaxed
+# define writel_relaxed writel
+#endif
+#ifndef readl_relaxed
+# define readl_relaxed readl
+#endif
+
+#define IR_ENABLE		0x00
+#define IR_CONFIG		0x04
+#define CNT_LEADS		0x08
+#define CNT_LEADE		0x0c
+#define CNT_SLEADE		0x10
+#define CNT0_B			0x14
+#define CNT1_B			0x18
+#define IR_BUSY			0x1c
+#define IR_DATAH		0x20
+#define IR_DATAL		0x24
+#define IR_INTM			0x28
+#define IR_INTS			0x2c
+#define IR_INTC			0x30
+#define IR_START		0x34
+
+/* interrupt mask */
+#define INTMS_SYMBRCV		(BIT(24) | BIT(8))
+#define INTMS_TIMEOUT		(BIT(25) | BIT(9))
+#define INTMS_OVERFLOW		(BIT(26) | BIT(10))
+#define INT_CLR_OVERFLOW	BIT(18)
+#define INT_CLR_TIMEOUT		BIT(17)
+#define INT_CLR_RCV		BIT(16)
+#define INT_CLR_RCVTIMEOUT	(BIT(16) | BIT(17))
+
+#define IR_CLK			0x48
+#define IR_CLK_ENABLE		BIT(4)
+#define IR_CLK_RESET		BIT(5)
+
+#define IR_CFG_WIDTH_MASK	0xffff
+#define IR_CFG_WIDTH_SHIFT	16
+#define IR_CFG_FORMAT_MASK	0x3
+#define IR_CFG_FORMAT_SHIFT	14
+#define IR_CFG_INT_LEVEL_MASK	0x3f
+#define IR_CFG_INT_LEVEL_SHIFT	8
+/* only support raw mode */
+#define IR_CFG_MODE_RAW		BIT(7)
+#define IR_CFG_FREQ_MASK	0x7f
+#define IR_CFG_FREQ_SHIFT	0
+#define IR_CFG_INT_THRESHOLD	1
+/* symbol start from low to high, symbol stream end at high*/
+#define IR_CFG_SYMBOL_FMT	0
+#define IR_CFG_SYMBOL_MAXWIDTH	0x3e80
+
+#define IR_HIX5HD2_NAME		"hix5hd2-ir"
+
+struct hix5hd2_ir_priv {
+	int			irq;
+	void volatile __iomem	*base;
+	struct device		*dev;
+	struct rc_dev		*rdev;
+	struct regmap		*regmap;
+	struct clk		*clock;
+	unsigned long		rate;
+};
+
+static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
+{
+	u32 val;
+
+	regmap_read(dev->regmap, IR_CLK, &val);
+	if (on) {
+		val &= ~IR_CLK_RESET;
+		val |= IR_CLK_ENABLE;
+	} else {
+		val &= ~IR_CLK_ENABLE;
+		val |= IR_CLK_RESET;
+	}
+	regmap_write(dev->regmap, IR_CLK, val);
+}
+
+static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv)
+{
+	int timeout = 10000;
+	u32 val, rate;
+
+	writel_relaxed(0x01, priv->base + IR_ENABLE);
+	while (readl_relaxed(priv->base + IR_BUSY)) {
+		if (timeout--) {
+			udelay(1);
+		} else {
+			dev_err(priv->dev, "IR_BUSY timeout\n");
+			return -ETIMEDOUT;
+		}
+	}
+
+	/* Now only support raw mode, with symbol start from low to high */
+	rate = DIV_ROUND_CLOSEST(priv->rate, 1000000);
+	val = IR_CFG_SYMBOL_MAXWIDTH & IR_CFG_WIDTH_MASK << IR_CFG_WIDTH_SHIFT;
+	val |= IR_CFG_SYMBOL_FMT & IR_CFG_FORMAT_MASK << IR_CFG_FORMAT_SHIFT;
+	val |= (IR_CFG_INT_THRESHOLD - 1) & IR_CFG_INT_LEVEL_MASK
+	       << IR_CFG_INT_LEVEL_SHIFT;
+	val |= IR_CFG_MODE_RAW;
+	val |= (rate - 1) & IR_CFG_FREQ_MASK << IR_CFG_FREQ_SHIFT;
+	writel_relaxed(val, priv->base + IR_CONFIG);
+
+	writel_relaxed(0x00, priv->base + IR_INTM);
+	/* write arbitrary value to start  */
+	writel_relaxed(0x01, priv->base + IR_START);
+	return 0;
+}
+
+static int hix5hd2_ir_open(struct rc_dev *rdev)
+{
+	struct hix5hd2_ir_priv *priv = rdev->priv;
+
+	hix5hd2_ir_enable(priv, true);
+	return hix5hd2_ir_config(priv);
+}
+
+static void hix5hd2_ir_close(struct rc_dev *rdev)
+{
+	struct hix5hd2_ir_priv *priv = rdev->priv;
+
+	hix5hd2_ir_enable(priv, false);
+}
+
+static irqreturn_t hix5hd2_ir_rx_interrupt(int irq, void *data)
+{
+	u32 symb_num, symb_val, symb_time;
+	u32 data_l, data_h;
+	u32 irq_sr, i;
+	struct hix5hd2_ir_priv *priv = data;
+
+	irq_sr = readl_relaxed(priv->base + IR_INTS);
+	if (irq_sr & INTMS_OVERFLOW) {
+		/*
+		 * we must read IR_DATAL first, then we can clean up
+		 * IR_INTS availably since logic would not clear
+		 * fifo when overflow, drv do the job
+		 */
+		ir_raw_event_reset(priv->rdev);
+		symb_num = readl_relaxed(priv->base + IR_DATAH);
+		for (i = 0; i < symb_num; i++)
+			readl_relaxed(priv->base + IR_DATAL);
+
+		writel_relaxed(INT_CLR_OVERFLOW, priv->base + IR_INTC);
+		dev_info(priv->dev, "overflow, level=%d\n",
+			 IR_CFG_INT_THRESHOLD);
+	}
+
+	if ((irq_sr & INTMS_SYMBRCV) || (irq_sr & INTMS_TIMEOUT)) {
+		DEFINE_IR_RAW_EVENT(ev);
+
+		symb_num = readl_relaxed(priv->base + IR_DATAH);
+		for (i = 0; i < symb_num; i++) {
+			symb_val = readl_relaxed(priv->base + IR_DATAL);
+			data_l = ((symb_val & 0xffff) * 10);
+			data_h =  ((symb_val >> 16) & 0xffff) * 10;
+			symb_time = (data_l + data_h) / 10;
+
+			ev.duration = US_TO_NS(data_l);
+			ev.pulse = true;
+			ir_raw_event_store(priv->rdev, &ev);
+
+			if (symb_time < IR_CFG_SYMBOL_MAXWIDTH) {
+				ev.duration = US_TO_NS(data_h);
+				ev.pulse = false;
+				ir_raw_event_store(priv->rdev, &ev);
+			} else {
+				ir_raw_event_set_idle(priv->rdev, true);
+			}
+		}
+
+		if (irq_sr & INTMS_SYMBRCV)
+			writel_relaxed(INT_CLR_RCV, priv->base + IR_INTC);
+		if (irq_sr & INTMS_TIMEOUT)
+			writel_relaxed(INT_CLR_TIMEOUT, priv->base + IR_INTC);
+	}
+
+	/* Empty software fifo */
+	ir_raw_event_handle(priv->rdev);
+	return IRQ_HANDLED;
+}
+
+static int hix5hd2_ir_probe(struct platform_device *pdev)
+{
+	struct rc_dev *rdev;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct hix5hd2_ir_priv *priv;
+	struct device_node *node = pdev->dev.of_node;
+	const char *map_name;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->regmap = syscon_regmap_lookup_by_phandle(node,
+						       "hisilicon,power-syscon");
+	if (IS_ERR(priv->regmap)) {
+		dev_err(dev, "no power-reg\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR((__force void *)priv->base))
+		return PTR_ERR((__force void *)priv->base);
+
+	priv->irq = platform_get_irq(pdev, 0);
+	if (priv->irq < 0) {
+		dev_err(dev, "irq can not get\n");
+		return priv->irq;
+	}
+
+	rdev = rc_allocate_device();
+	if (!rdev)
+		return -ENOMEM;
+
+	priv->clock = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clock)) {
+		dev_err(dev, "clock not found\n");
+		ret = PTR_ERR(priv->clock);
+		goto err;
+	}
+	clk_prepare_enable(priv->clock);
+	priv->rate = clk_get_rate(priv->clock);
+
+	rdev->driver_type = RC_DRIVER_IR_RAW;
+	rdev->allowed_protocols = RC_BIT_ALL;
+	rdev->priv = priv;
+	rdev->open = hix5hd2_ir_open;
+	rdev->close = hix5hd2_ir_close;
+	rdev->driver_name = IR_HIX5HD2_NAME;
+	map_name = of_get_property(node, "linux,rc-map-name", NULL);
+	rdev->map_name = map_name ?: RC_MAP_EMPTY;
+	rdev->input_name = IR_HIX5HD2_NAME;
+	rdev->input_phys = IR_HIX5HD2_NAME "/input0";
+	rdev->input_id.bustype = BUS_HOST;
+	rdev->input_id.vendor = 0x0001;
+	rdev->input_id.product = 0x0001;
+	rdev->input_id.version = 0x0100;
+	rdev->rx_resolution = US_TO_NS(10);
+	rdev->timeout = US_TO_NS(IR_CFG_SYMBOL_MAXWIDTH * 10);
+
+	ret = rc_register_device(rdev);
+	if (ret < 0)
+		goto clkerr;
+
+	if (devm_request_irq(dev, priv->irq, hix5hd2_ir_rx_interrupt,
+			     IRQF_NO_SUSPEND, pdev->name, priv) < 0) {
+		dev_err(dev, "IRQ %d register failed\n", priv->irq);
+		ret = -EINVAL;
+		goto regerr;
+	}
+
+	priv->rdev = rdev;
+	priv->dev = dev;
+	platform_set_drvdata(pdev, priv);
+
+	return ret;
+
+regerr:
+	rc_unregister_device(rdev);
+	rdev = NULL;
+clkerr:
+	clk_disable_unprepare(priv->clock);
+err:
+	rc_free_device(rdev);
+	dev_err(dev, "Unable to register device (%d)\n", ret);
+	return ret;
+}
+
+static int hix5hd2_ir_remove(struct platform_device *pdev)
+{
+	struct hix5hd2_ir_priv *priv = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(priv->clock);
+	rc_unregister_device(priv->rdev);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int hix5hd2_ir_suspend(struct device *dev)
+{
+	struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(priv->clock);
+	hix5hd2_ir_enable(priv, false);
+
+	return 0;
+}
+
+static int hix5hd2_ir_resume(struct device *dev)
+{
+	struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev);
+
+	hix5hd2_ir_enable(priv, true);
+	clk_prepare_enable(priv->clock);
+
+	writel_relaxed(0x01, priv->base + IR_ENABLE);
+	writel_relaxed(0x00, priv->base + IR_INTM);
+	writel_relaxed(0xff, priv->base + IR_INTC);
+	writel_relaxed(0x01, priv->base + IR_START);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(hix5hd2_ir_pm_ops, hix5hd2_ir_suspend,
+			 hix5hd2_ir_resume);
+
+static struct of_device_id hix5hd2_ir_table[] = {
+	{ .compatible = "hisilicon,hix5hd2-ir", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, hix5hd2_ir_table);
+
+static struct platform_driver hix5hd2_ir_driver = {
+	.driver = {
+		.name = IR_HIX5HD2_NAME,
+		.of_match_table = hix5hd2_ir_table,
+		.pm     = &hix5hd2_ir_pm_ops,
+	},
+	.probe = hix5hd2_ir_probe,
+	.remove = hix5hd2_ir_remove,
+};
+
+module_platform_driver(hix5hd2_ir_driver);
+
+MODULE_DESCRIPTION("IR controller driver for hix5hd2 platforms");
+MODULE_AUTHOR("Guoxiong Yan <yanguoxiong@huawei.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:hix5hd2-ir");
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 447fe35..56abf91 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1666,7 +1666,6 @@
 
 static int ite_resume(struct pnp_dev *pdev)
 {
-	int ret = 0;
 	struct ite_dev *dev = pnp_get_drvdata(pdev);
 	unsigned long flags;
 
@@ -1681,7 +1680,7 @@
 
 	spin_unlock_irqrestore(&dev->lock, flags);
 
-	return ret;
+	return 0;
 }
 
 static void ite_shutdown(struct pnp_dev *pdev)
diff --git a/drivers/media/rc/keymaps/Kconfig b/drivers/media/rc/keymaps/Kconfig
index d448fce..147c0b5 100644
--- a/drivers/media/rc/keymaps/Kconfig
+++ b/drivers/media/rc/keymaps/Kconfig
@@ -13,4 +13,4 @@
 	   The ir-keytable program, available at v4l-utils package
 	   provide the tool and the same RC maps for load from
 	   userspace. Its available at
-			http://git.linuxtv.org/v4l-utils
+		http://git.linuxtv.org/cgit.cgi/v4l-utils.git/
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index ba304f7..7fb4a04 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -28,6 +28,7 @@
 			rc-dm1105-nec.o \
 			rc-dntv-live-dvb-t.o \
 			rc-dntv-live-dvbt-pro.o \
+			rc-dvbsky.o \
 			rc-em-terratec.o \
 			rc-encore-enltv2.o \
 			rc-encore-enltv.o \
diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c
new file mode 100644
index 0000000..c5115a1
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-dvbsky.c
@@ -0,0 +1,78 @@
+/* rc-dvbsky.c - Keytable for DVBSky Remote Controllers
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ *
+ * Copyright (c) 2010-2012 by Nibble Max <nibble.max@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+/*
+ * This table contains the complete RC5 code, instead of just the data part
+ */
+
+static struct rc_map_table rc5_dvbsky[] = {
+	{ 0x0000, KEY_0 },
+	{ 0x0001, KEY_1 },
+	{ 0x0002, KEY_2 },
+	{ 0x0003, KEY_3 },
+	{ 0x0004, KEY_4 },
+	{ 0x0005, KEY_5 },
+	{ 0x0006, KEY_6 },
+	{ 0x0007, KEY_7 },
+	{ 0x0008, KEY_8 },
+	{ 0x0009, KEY_9 },
+	{ 0x000a, KEY_MUTE },
+	{ 0x000d, KEY_OK },
+	{ 0x000b, KEY_STOP },
+	{ 0x000c, KEY_EXIT },
+	{ 0x000e, KEY_CAMERA }, /*Snap shot*/
+	{ 0x000f, KEY_SUBTITLE }, /*PIP*/
+	{ 0x0010, KEY_VOLUMEUP },
+	{ 0x0011, KEY_VOLUMEDOWN },
+	{ 0x0012, KEY_FAVORITES },
+	{ 0x0013, KEY_LIST }, /*Info*/
+	{ 0x0016, KEY_PAUSE },
+	{ 0x0017, KEY_PLAY },
+	{ 0x001f, KEY_RECORD },
+	{ 0x0020, KEY_CHANNELDOWN },
+	{ 0x0021, KEY_CHANNELUP },
+	{ 0x0025, KEY_POWER2 },
+	{ 0x0026, KEY_REWIND },
+	{ 0x0027, KEY_FASTFORWARD },
+	{ 0x0029, KEY_LAST },
+	{ 0x002b, KEY_MENU },
+	{ 0x002c, KEY_EPG },
+	{ 0x002d, KEY_ZOOM },
+};
+
+static struct rc_map_list rc5_dvbsky_map = {
+	.map = {
+		.scan    = rc5_dvbsky,
+		.size    = ARRAY_SIZE(rc5_dvbsky),
+		.rc_type = RC_TYPE_RC5,
+		.name    = RC_MAP_DVBSKY,
+	}
+};
+
+static int __init init_rc_map_rc5_dvbsky(void)
+{
+	return rc_map_register(&rc5_dvbsky_map);
+}
+
+static void __exit exit_rc_map_rc5_dvbsky(void)
+{
+	rc_map_unregister(&rc5_dvbsky_map);
+}
+
+module_init(init_rc_map_rc5_dvbsky)
+module_exit(exit_rc_map_rc5_dvbsky)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nibble Max <nibble.max@gmail.com>");
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index dc5cbff..249d2fb 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -595,7 +595,7 @@
 
 	switch (cmd) {
 	case LIRC_GET_FEATURES:
-		result = put_user(ir->d.features, (__u32 *)arg);
+		result = put_user(ir->d.features, (__u32 __user *)arg);
 		break;
 	case LIRC_GET_REC_MODE:
 		if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
@@ -605,7 +605,7 @@
 
 		result = put_user(LIRC_REC2MODE
 				  (ir->d.features & LIRC_CAN_REC_MASK),
-				  (__u32 *)arg);
+				  (__u32 __user *)arg);
 		break;
 	case LIRC_SET_REC_MODE:
 		if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
@@ -613,7 +613,7 @@
 			break;
 		}
 
-		result = get_user(mode, (__u32 *)arg);
+		result = get_user(mode, (__u32 __user *)arg);
 		if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
 			result = -EINVAL;
 		/*
@@ -622,7 +622,7 @@
 		 */
 		break;
 	case LIRC_GET_LENGTH:
-		result = put_user(ir->d.code_length, (__u32 *)arg);
+		result = put_user(ir->d.code_length, (__u32 __user *)arg);
 		break;
 	case LIRC_GET_MIN_TIMEOUT:
 		if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
@@ -631,7 +631,7 @@
 			break;
 		}
 
-		result = put_user(ir->d.min_timeout, (__u32 *)arg);
+		result = put_user(ir->d.min_timeout, (__u32 __user *)arg);
 		break;
 	case LIRC_GET_MAX_TIMEOUT:
 		if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
@@ -640,7 +640,7 @@
 			break;
 		}
 
-		result = put_user(ir->d.max_timeout, (__u32 *)arg);
+		result = put_user(ir->d.max_timeout, (__u32 __user *)arg);
 		break;
 	default:
 		result = -EINVAL;
@@ -736,7 +736,7 @@
 			}
 		} else {
 			lirc_buffer_read(ir->buf, buf);
-			ret = copy_to_user((void *)buffer+written, buf,
+			ret = copy_to_user((void __user *)buffer+written, buf,
 					   ir->buf->chunk_size);
 			if (!ret)
 				written += ir->buf->chunk_size;
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 45b0894..2cdb740 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -397,6 +397,10 @@
 	  .driver_info = HAUPPAUGE_CX_HYBRID_TV },
 	{ USB_DEVICE(VENDOR_HAUPPAUGE, 0xb131),
 	  .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+	{ USB_DEVICE(VENDOR_HAUPPAUGE, 0xb138),
+	  .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+	{ USB_DEVICE(VENDOR_HAUPPAUGE, 0xb139),
+	  .driver_info = HAUPPAUGE_CX_HYBRID_TV },
 	{ USB_DEVICE(VENDOR_PCTV, 0x0259),
 	  .driver_info = HAUPPAUGE_CX_HYBRID_TV },
 	{ USB_DEVICE(VENDOR_PCTV, 0x025e),
@@ -1198,10 +1202,9 @@
 	mce_async_out(ir, FLASH_LED, sizeof(FLASH_LED));
 }
 
-static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir,
-					 struct usb_interface *intf)
+static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
 {
-	struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf));
+	struct usb_device *udev = ir->usbdev;
 	struct device *dev = ir->dev;
 	struct rc_dev *rc;
 	int ret;
@@ -1341,7 +1344,7 @@
 	if (!ir->urb_in)
 		goto urb_in_alloc_fail;
 
-	ir->usbdev = dev;
+	ir->usbdev = usb_get_dev(dev);
 	ir->dev = &intf->dev;
 	ir->len_in = maxp;
 	ir->flags.microsoft_gen1 = is_microsoft_gen1;
@@ -1362,7 +1365,7 @@
 		snprintf(name + strlen(name), sizeof(name) - strlen(name),
 			 " %s", buf);
 
-	ir->rc = mceusb_init_rc_dev(ir, intf);
+	ir->rc = mceusb_init_rc_dev(ir);
 	if (!ir->rc)
 		goto rc_dev_fail;
 
@@ -1408,6 +1411,7 @@
 
 	/* Error-handling path */
 rc_dev_fail:
+	usb_put_dev(ir->usbdev);
 	usb_free_urb(ir->urb_in);
 urb_in_alloc_fail:
 	usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in);
@@ -1435,6 +1439,7 @@
 	usb_kill_urb(ir->urb_in);
 	usb_free_urb(ir->urb_in);
 	usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
+	usb_put_dev(dev);
 
 	kfree(ir);
 }
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 7f4fd85..9c2c863 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -229,7 +229,6 @@
 {
 	unsigned long flags;
 	u8 chip_major, chip_minor;
-	int ret = 0;
 	char chip_id[12];
 	bool chip_unknown = false;
 
@@ -285,7 +284,7 @@
 	nvt->chip_minor = chip_minor;
 	spin_unlock_irqrestore(&nvt->nvt_lock, flags);
 
-	return ret;
+	return 0;
 }
 
 static void nvt_cir_ldev_init(struct nvt_dev *nvt)
@@ -1177,7 +1176,6 @@
 
 static int nvt_resume(struct pnp_dev *pdev)
 {
-	int ret = 0;
 	struct nvt_dev *nvt = pnp_get_drvdata(pdev);
 
 	nvt_dbg("%s called", __func__);
@@ -1195,7 +1193,7 @@
 	nvt_cir_regs_init(nvt);
 	nvt_cir_wake_regs_init(nvt);
 
-	return ret;
+	return 0;
 }
 
 static void nvt_shutdown(struct pnp_dev *pdev)
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
index 5c15135..0e758ae 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -22,8 +22,8 @@
 	int				irq;
 	int				irq_wake;
 	struct clk			*sys_clock;
-	void				*base;	/* Register base address */
-	void				*rx_base;/* RX Register base address */
+	volatile void __iomem		*base;	/* Register base address */
+	volatile void __iomem		*rx_base;/* RX Register base address */
 	struct rc_dev			*rdev;
 	bool				overclocking;
 	int				sample_mult;
@@ -267,8 +267,8 @@
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
 	rc_dev->base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(rc_dev->base)) {
-		ret = PTR_ERR(rc_dev->base);
+	if (IS_ERR((__force void *)rc_dev->base)) {
+		ret = PTR_ERR((__force void *)rc_dev->base);
 		goto err;
 	}
 
@@ -278,7 +278,7 @@
 		rc_dev->rx_base = rc_dev->base;
 
 
-	rc_dev->rstc = reset_control_get(dev, NULL);
+	rc_dev->rstc = reset_control_get_optional(dev, NULL);
 	if (IS_ERR(rc_dev->rstc))
 		rc_dev->rstc = NULL;
 
@@ -376,9 +376,10 @@
 	return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(st_rc_pm_ops, st_rc_suspend, st_rc_resume);
 #endif
 
+static SIMPLE_DEV_PM_OPS(st_rc_pm_ops, st_rc_suspend, st_rc_resume);
+
 #ifdef CONFIG_OF
 static struct of_device_id st_rc_match[] = {
 	{ .compatible = "st,comms-irb", },
@@ -391,11 +392,8 @@
 static struct platform_driver st_rc_driver = {
 	.driver = {
 		.name = IR_ST_NAME,
-		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(st_rc_match),
-#ifdef CONFIG_PM
 		.pm     = &st_rc_pm_ops,
-#endif
 	},
 	.probe = st_rc_probe,
 	.remove = st_rc_remove,
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index 80c4fee..bf4a442 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -362,16 +362,14 @@
 	}
 
 	sz->endpoint = &(iface_host->endpoint[0].desc);
-	if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
-	    != USB_DIR_IN) {
+	if (!usb_endpoint_dir_in(sz->endpoint)) {
 		dev_err(&intf->dev, "%s: endpoint doesn't match input device "
 			"02%02x\n", __func__, sz->endpoint->bEndpointAddress);
 		retval = -ENODEV;
 		goto free_sz;
 	}
 
-	if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-	    != USB_ENDPOINT_XFER_INT) {
+	if (!usb_endpoint_xfer_int(sz->endpoint)) {
 		dev_err(&intf->dev, "%s: endpoint attributes don't match xfer "
 			"02%02x\n", __func__, sz->endpoint->bmAttributes);
 		retval = -ENODEV;
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index 1b75801..02f497c 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -228,15 +228,18 @@
 	  Fitipower FC0013 silicon tuner driver.
 
 config MEDIA_TUNER_TDA18212
+	depends on !BACKPORT_KERNEL_3_4
 	tristate "NXP TDA18212 silicon tuner"
 	depends on m
 	depends on MEDIA_SUPPORT && I2C
+	depends on REGMAP_I2C
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 	help
 	  NXP TDA18212 silicon tuner driver.
 
 config MEDIA_TUNER_E4000
 	depends on !BACKPORT_KERNEL_3_4
+	depends on !BACKPORT_KERNEL_3_4
 	tristate "Elonics E4000 silicon tuner"
 	depends on m
 	depends on MEDIA_SUPPORT && I2C
@@ -254,9 +257,11 @@
 	  FCI FC2580 silicon tuner driver.
 
 config MEDIA_TUNER_M88TS2022
+	depends on !BACKPORT_KERNEL_3_4
 	tristate "Montage M88TS2022 silicon tuner"
 	depends on m
 	depends on MEDIA_SUPPORT && I2C
+	depends on REGMAP_I2C
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 	help
 	  Montage M88TS2022 silicon tuner driver.
@@ -278,9 +283,11 @@
 	  Silicon Labs Si2157 silicon tuner driver.
 
 config MEDIA_TUNER_IT913X
+	depends on !BACKPORT_KERNEL_3_4
 	tristate "ITE Tech IT913x silicon tuner"
 	depends on m
 	depends on MEDIA_SUPPORT && I2C
+	depends on REGMAP_I2C
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 	help
 	  ITE Tech IT913x silicon tuner driver.
@@ -292,4 +299,20 @@
 	default m if !MEDIA_SUBDRV_AUTOSELECT
 	help
 	  Rafael Micro R820T silicon tuner driver.
+
+config MEDIA_TUNER_MXL301RF
+	tristate "MaxLinear MxL301RF tuner"
+	depends on m
+	depends on MEDIA_SUPPORT && I2C
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  MaxLinear MxL301RF OFDM tuner driver.
+
+config MEDIA_TUNER_QM1D1C0042
+	tristate "Sharp QM1D1C0042 tuner"
+	depends on m
+	depends on MEDIA_SUPPORT && I2C
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  Sharp QM1D1C0042 trellis coded 8PSK tuner driver.
 endmenu
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
index 4c7978e..c3e58a6 100644
--- a/drivers/media/tuners/Makefile
+++ b/drivers/media/tuners/Makefile
@@ -37,8 +37,10 @@
 obj-$(CPTCFG_MEDIA_TUNER_FC0011) += fc0011.o
 obj-$(CPTCFG_MEDIA_TUNER_FC0012) += fc0012.o
 obj-$(CPTCFG_MEDIA_TUNER_FC0013) += fc0013.o
-obj-$(CPTCFG_MEDIA_TUNER_IT913X) += tuner_it913x.o
+obj-$(CPTCFG_MEDIA_TUNER_IT913X) += it913x.o
 obj-$(CPTCFG_MEDIA_TUNER_R820T) += r820t.o
+obj-$(CPTCFG_MEDIA_TUNER_MXL301RF) += mxl301rf.o
+obj-$(CPTCFG_MEDIA_TUNER_QM1D1C0042) += qm1d1c0042.o
 
 ccflags-y += -I$(backport_srctree)/drivers/media/dvb-core
 ccflags-y += -I$(backport_srctree)/drivers/media/dvb-frontends
diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c
index 1f3c0aa..99e6653 100644
--- a/drivers/media/tuners/e4000.c
+++ b/drivers/media/tuners/e4000.c
@@ -26,7 +26,7 @@
 	struct e4000 *s = fe->tuner_priv;
 	int ret;
 
-	dev_dbg(&s->client->dev, "%s:\n", __func__);
+	dev_dbg(&s->client->dev, "\n");
 
 	/* dummy I2C to ensure I2C wakes up */
 	ret = regmap_write(s->regmap, 0x02, 0x40);
@@ -87,7 +87,7 @@
 	s->active = true;
 err:
 	if (ret)
-		dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
@@ -97,7 +97,7 @@
 	struct e4000 *s = fe->tuner_priv;
 	int ret;
 
-	dev_dbg(&s->client->dev, "%s:\n", __func__);
+	dev_dbg(&s->client->dev, "\n");
 
 	s->active = false;
 
@@ -106,7 +106,7 @@
 		goto err;
 err:
 	if (ret)
-		dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
@@ -121,9 +121,8 @@
 	u8 buf[5], i_data[4], q_data[4];
 
 	dev_dbg(&s->client->dev,
-			"%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n",
-			__func__, c->delivery_system, c->frequency,
-			c->bandwidth_hz);
+			"delivery_system=%d frequency=%u bandwidth_hz=%u\n",
+			c->delivery_system, c->frequency, c->bandwidth_hz);
 
 	/* gain control manual */
 	ret = regmap_write(s->regmap, 0x1a, 0x00);
@@ -150,9 +149,8 @@
 	buf[3] = 0x00;
 	buf[4] = e4000_pll_lut[i].div;
 
-	dev_dbg(&s->client->dev,
-			"%s: f_vco=%llu pll div=%d sigma_delta=%04x\n",
-			__func__, f_vco, buf[0], sigma_delta);
+	dev_dbg(&s->client->dev, "f_vco=%llu pll div=%d sigma_delta=%04x\n",
+			f_vco, buf[0], sigma_delta);
 
 	ret = regmap_bulk_write(s->regmap, 0x09, buf, 5);
 	if (ret)
@@ -253,7 +251,7 @@
 		goto err;
 err:
 	if (ret)
-		dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
@@ -262,7 +260,7 @@
 {
 	struct e4000 *s = fe->tuner_priv;
 
-	dev_dbg(&s->client->dev, "%s:\n", __func__);
+	dev_dbg(&s->client->dev, "\n");
 
 	*frequency = 0; /* Zero-IF */
 
@@ -276,10 +274,9 @@
 	int ret;
 	u8 u8tmp;
 
-	dev_dbg(&s->client->dev, "%s: lna auto=%d->%d val=%d->%d\n",
-			__func__, s->lna_gain_auto->cur.val,
-			s->lna_gain_auto->val, s->lna_gain->cur.val,
-			s->lna_gain->val);
+	dev_dbg(&s->client->dev, "lna auto=%d->%d val=%d->%d\n",
+			s->lna_gain_auto->cur.val, s->lna_gain_auto->val,
+			s->lna_gain->cur.val, s->lna_gain->val);
 
 	if (s->lna_gain_auto->val && s->if_gain_auto->cur.val)
 		u8tmp = 0x17;
@@ -301,7 +298,7 @@
 	}
 err:
 	if (ret)
-		dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
@@ -312,10 +309,9 @@
 	int ret;
 	u8 u8tmp;
 
-	dev_dbg(&s->client->dev, "%s: mixer auto=%d->%d val=%d->%d\n",
-			__func__, s->mixer_gain_auto->cur.val,
-			s->mixer_gain_auto->val, s->mixer_gain->cur.val,
-			s->mixer_gain->val);
+	dev_dbg(&s->client->dev, "mixer auto=%d->%d val=%d->%d\n",
+			s->mixer_gain_auto->cur.val, s->mixer_gain_auto->val,
+			s->mixer_gain->cur.val, s->mixer_gain->val);
 
 	if (s->mixer_gain_auto->val)
 		u8tmp = 0x15;
@@ -333,7 +329,7 @@
 	}
 err:
 	if (ret)
-		dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
@@ -345,10 +341,9 @@
 	u8 buf[2];
 	u8 u8tmp;
 
-	dev_dbg(&s->client->dev, "%s: if auto=%d->%d val=%d->%d\n",
-			__func__, s->if_gain_auto->cur.val,
-			s->if_gain_auto->val, s->if_gain->cur.val,
-			s->if_gain->val);
+	dev_dbg(&s->client->dev, "if auto=%d->%d val=%d->%d\n",
+			s->if_gain_auto->cur.val, s->if_gain_auto->val,
+			s->if_gain->cur.val, s->if_gain->val);
 
 	if (s->if_gain_auto->val && s->lna_gain_auto->cur.val)
 		u8tmp = 0x17;
@@ -372,7 +367,7 @@
 	}
 err:
 	if (ret)
-		dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
@@ -390,7 +385,7 @@
 	s->pll_lock->val = (utmp & 0x01);
 err:
 	if (ret)
-		dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(&s->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
@@ -400,7 +395,7 @@
 	struct e4000 *s = container_of(ctrl->handler, struct e4000, hdl);
 	int ret;
 
-	if (s->active == false)
+	if (!s->active)
 		return 0;
 
 	switch (ctrl->id) {
@@ -408,8 +403,8 @@
 		ret = e4000_pll_lock(s->fe);
 		break;
 	default:
-		dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
-				__func__, ctrl->id, ctrl->name);
+		dev_dbg(&s->client->dev, "unknown ctrl: id=%d name=%s\n",
+				ctrl->id, ctrl->name);
 		ret = -EINVAL;
 	}
 
@@ -423,7 +418,7 @@
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret;
 
-	if (s->active == false)
+	if (!s->active)
 		return 0;
 
 	switch (ctrl->id) {
@@ -445,8 +440,8 @@
 		ret = e4000_set_if_gain(s->fe);
 		break;
 	default:
-		dev_dbg(&s->client->dev, "%s: unknown ctrl: id=%d name=%s\n",
-				__func__, ctrl->id, ctrl->name);
+		dev_dbg(&s->client->dev, "unknown ctrl: id=%d name=%s\n",
+				ctrl->id, ctrl->name);
 		ret = -EINVAL;
 	}
 
@@ -494,7 +489,7 @@
 	s = kzalloc(sizeof(struct e4000), GFP_KERNEL);
 	if (!s) {
 		ret = -ENOMEM;
-		dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+		dev_err(&client->dev, "kzalloc() failed\n");
 		goto err;
 	}
 
@@ -512,7 +507,7 @@
 	if (ret)
 		goto err;
 
-	dev_dbg(&s->client->dev, "%s: chip id=%02x\n", __func__, utmp);
+	dev_dbg(&s->client->dev, "chip id=%02x\n", utmp);
 
 	if (utmp != 0x40) {
 		ret = -ENODEV;
@@ -559,9 +554,7 @@
 	s->sd.ctrl_handler = &s->hdl;
 #endif
 
-	dev_info(&s->client->dev,
-			"%s: Elonics E4000 successfully identified\n",
-			KBUILD_MODNAME);
+	dev_info(&s->client->dev, "Elonics E4000 successfully identified\n");
 
 	fe->tuner_priv = s;
 	memcpy(&fe->ops.tuner_ops, &e4000_tuner_ops,
@@ -573,7 +566,7 @@
 	return 0;
 err:
 	if (ret) {
-		dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(&client->dev, "failed=%d\n", ret);
 		kfree(s);
 	}
 
@@ -586,7 +579,7 @@
 	struct e4000 *s = container_of(sd, struct e4000, sd);
 	struct dvb_frontend *fe = s->fe;
 
-	dev_dbg(&client->dev, "%s:\n", __func__);
+	dev_dbg(&client->dev, "\n");
 
 #if IS_ENABLED(CPTCFG_VIDEO_V4L2)
 	v4l2_ctrl_handler_free(&s->hdl);
diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c
new file mode 100644
index 0000000..a076c87
--- /dev/null
+++ b/drivers/media/tuners/it913x.c
@@ -0,0 +1,478 @@
+/*
+ * ITE IT913X silicon tuner driver
+ *
+ *  Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
+ *  IT9137 Copyright (C) ITE Tech Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include "it913x.h"
+#include <linux/regmap.h>
+
+struct it913x_dev {
+	struct i2c_client *client;
+	struct regmap *regmap;
+	struct dvb_frontend *fe;
+	u8 chip_ver:2;
+	u8 role:2;
+	u16 xtal;
+	u8 fdiv;
+	u8 clk_mode;
+	u32 fn_min;
+	bool active;
+};
+
+static int it913x_init(struct dvb_frontend *fe)
+{
+	struct it913x_dev *dev = fe->tuner_priv;
+	int ret;
+	unsigned int utmp;
+	u8 iqik_m_cal, nv_val, buf[2];
+	static const u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
+	unsigned long timeout;
+
+	dev_dbg(&dev->client->dev, "role %u\n", dev->role);
+
+	ret = regmap_write(dev->regmap, 0x80ec4c, 0x68);
+	if (ret)
+		goto err;
+
+	usleep_range(10000, 100000);
+
+	ret = regmap_read(dev->regmap, 0x80ec86, &utmp);
+	if (ret)
+		goto err;
+
+	switch (utmp) {
+	case 0:
+		/* 12.000 MHz */
+		dev->clk_mode = utmp;
+		dev->xtal = 2000;
+		dev->fdiv = 3;
+		iqik_m_cal = 16;
+		break;
+	case 1:
+		/* 20.480 MHz */
+		dev->clk_mode = utmp;
+		dev->xtal = 640;
+		dev->fdiv = 1;
+		iqik_m_cal = 6;
+		break;
+	default:
+		dev_err(&dev->client->dev, "unknown clock identifier %d\n", utmp);
+		goto err;
+	}
+
+	ret = regmap_read(dev->regmap, 0x80ed03,  &utmp);
+	if (ret)
+		goto err;
+
+	else if (utmp < ARRAY_SIZE(nv))
+		nv_val = nv[utmp];
+	else
+		nv_val = 2;
+
+	#define TIMEOUT 50
+	timeout = jiffies + msecs_to_jiffies(TIMEOUT);
+	while (!time_after(jiffies, timeout)) {
+		ret = regmap_bulk_read(dev->regmap, 0x80ed23, buf, 2);
+		if (ret)
+			goto err;
+
+		utmp = (buf[1] << 8) | (buf[0] << 0);
+		if (utmp)
+			break;
+	}
+
+	dev_dbg(&dev->client->dev, "r_fbc_m_bdry took %u ms, val %u\n",
+			jiffies_to_msecs(jiffies) -
+			(jiffies_to_msecs(timeout) - TIMEOUT), utmp);
+
+	dev->fn_min = dev->xtal * utmp;
+	dev->fn_min /= (dev->fdiv * nv_val);
+	dev->fn_min *= 1000;
+	dev_dbg(&dev->client->dev, "fn_min %u\n", dev->fn_min);
+
+	/*
+	 * Chip version BX never sets that flag so we just wait 50ms in that
+	 * case. It is possible poll BX similarly than AX and then timeout in
+	 * order to get 50ms delay, but that causes about 120 extra I2C
+	 * messages. As for now, we just wait and reduce IO.
+	 */
+	if (dev->chip_ver == 1) {
+		#define TIMEOUT 50
+		timeout = jiffies + msecs_to_jiffies(TIMEOUT);
+		while (!time_after(jiffies, timeout)) {
+			ret = regmap_read(dev->regmap, 0x80ec82, &utmp);
+			if (ret)
+				goto err;
+
+			if (utmp)
+				break;
+		}
+
+		dev_dbg(&dev->client->dev, "p_tsm_init_mode took %u ms, val %u\n",
+				jiffies_to_msecs(jiffies) -
+				(jiffies_to_msecs(timeout) - TIMEOUT), utmp);
+	} else {
+		msleep(50);
+	}
+
+	ret = regmap_write(dev->regmap, 0x80ed81, iqik_m_cal);
+	if (ret)
+		goto err;
+
+	ret = regmap_write(dev->regmap, 0x80ec57, 0x00);
+	if (ret)
+		goto err;
+
+	ret = regmap_write(dev->regmap, 0x80ec58, 0x00);
+	if (ret)
+		goto err;
+
+	ret = regmap_write(dev->regmap, 0x80ec40, 0x01);
+	if (ret)
+		goto err;
+
+	dev->active = true;
+
+	return 0;
+err:
+	dev_dbg(&dev->client->dev, "failed %d\n", ret);
+	return ret;
+}
+
+static int it913x_sleep(struct dvb_frontend *fe)
+{
+	struct it913x_dev *dev = fe->tuner_priv;
+	int ret, len;
+
+	dev_dbg(&dev->client->dev, "role %u\n", dev->role);
+
+	dev->active = false;
+
+	ret  = regmap_bulk_write(dev->regmap, 0x80ec40, "\x00", 1);
+	if (ret)
+		goto err;
+
+	/*
+	 * Writing '0x00' to master tuner register '0x80ec08' causes slave tuner
+	 * communication lost. Due to that, we cannot put master full sleep.
+	 */
+	if (dev->role == IT913X_ROLE_DUAL_MASTER)
+		len = 4;
+	else
+		len = 15;
+
+	dev_dbg(&dev->client->dev, "role %u, len %d\n", dev->role, len);
+
+	ret = regmap_bulk_write(dev->regmap, 0x80ec02,
+			"\x3f\x1f\x3f\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+			len);
+	if (ret)
+		goto err;
+
+	ret = regmap_bulk_write(dev->regmap, 0x80ec12, "\x00\x00\x00\x00", 4);
+	if (ret)
+		goto err;
+
+	ret = regmap_bulk_write(dev->regmap, 0x80ec17,
+			"\x00\x00\x00\x00\x00\x00\x00\x00\x00", 9);
+	if (ret)
+		goto err;
+
+	ret = regmap_bulk_write(dev->regmap, 0x80ec22,
+			"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 10);
+	if (ret)
+		goto err;
+
+	ret = regmap_bulk_write(dev->regmap, 0x80ec20, "\x00", 1);
+	if (ret)
+		goto err;
+
+	ret = regmap_bulk_write(dev->regmap, 0x80ec3f, "\x01", 1);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	dev_dbg(&dev->client->dev, "failed %d\n", ret);
+	return ret;
+}
+
+static int it913x_set_params(struct dvb_frontend *fe)
+{
+	struct it913x_dev *dev = fe->tuner_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret;
+	unsigned int utmp;
+	u32 pre_lo_freq, t_cal_freq;
+	u16 iqik_m_cal, n_div;
+	u8 u8tmp, n, l_band, lna_band;
+
+	dev_dbg(&dev->client->dev, "role=%u, frequency %u, bandwidth_hz %u\n",
+			dev->role, c->frequency, c->bandwidth_hz);
+
+	if (!dev->active) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (c->frequency <=         74000000) {
+		n_div = 48;
+		n = 0;
+	} else if (c->frequency <= 111000000) {
+		n_div = 32;
+		n = 1;
+	} else if (c->frequency <= 148000000) {
+		n_div = 24;
+		n = 2;
+	} else if (c->frequency <= 222000000) {
+		n_div = 16;
+		n = 3;
+	} else if (c->frequency <= 296000000) {
+		n_div = 12;
+		n = 4;
+	} else if (c->frequency <= 445000000) {
+		n_div = 8;
+		n = 5;
+	} else if (c->frequency <= dev->fn_min) {
+		n_div = 6;
+		n = 6;
+	} else if (c->frequency <= 950000000) {
+		n_div = 4;
+		n = 7;
+	} else {
+		n_div = 2;
+		n = 0;
+	}
+
+	ret = regmap_read(dev->regmap, 0x80ed81, &utmp);
+	if (ret)
+		goto err;
+
+	iqik_m_cal = utmp * n_div;
+
+	if (utmp < 0x20) {
+		if (dev->clk_mode == 0)
+			iqik_m_cal = (iqik_m_cal * 9) >> 5;
+		else
+			iqik_m_cal >>= 1;
+	} else {
+		iqik_m_cal = 0x40 - iqik_m_cal;
+		if (dev->clk_mode == 0)
+			iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
+		else
+			iqik_m_cal = ~(iqik_m_cal >> 1);
+	}
+
+	t_cal_freq = (c->frequency / 1000) * n_div * dev->fdiv;
+	pre_lo_freq = t_cal_freq / dev->xtal;
+	utmp = pre_lo_freq * dev->xtal;
+
+	if ((t_cal_freq - utmp) >= (dev->xtal >> 1))
+		pre_lo_freq++;
+
+	pre_lo_freq += (u32) n << 13;
+	/* Frequency OMEGA_IQIK_M_CAL_MID*/
+	t_cal_freq = pre_lo_freq + (u32)iqik_m_cal;
+	dev_dbg(&dev->client->dev, "t_cal_freq %u, pre_lo_freq %u\n",
+			t_cal_freq, pre_lo_freq);
+
+	if (c->frequency <=         440000000) {
+		l_band = 0;
+		lna_band = 0;
+	} else if (c->frequency <=  484000000) {
+		l_band = 1;
+		lna_band = 1;
+	} else if (c->frequency <=  533000000) {
+		l_band = 1;
+		lna_band = 2;
+	} else if (c->frequency <=  587000000) {
+		l_band = 1;
+		lna_band = 3;
+	} else if (c->frequency <=  645000000) {
+		l_band = 1;
+		lna_band = 4;
+	} else if (c->frequency <=  710000000) {
+		l_band = 1;
+		lna_band = 5;
+	} else if (c->frequency <=  782000000) {
+		l_band = 1;
+		lna_band = 6;
+	} else if (c->frequency <=  860000000) {
+		l_band = 1;
+		lna_band = 7;
+	} else if (c->frequency <= 1492000000) {
+		l_band = 1;
+		lna_band = 0;
+	} else if (c->frequency <= 1685000000) {
+		l_band = 1;
+		lna_band = 1;
+	} else {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* XXX: latest windows driver does not set that at all */
+	ret = regmap_write(dev->regmap, 0x80ee06, lna_band);
+	if (ret)
+		goto err;
+
+	if (c->bandwidth_hz <=      5000000)
+		u8tmp = 0;
+	else if (c->bandwidth_hz <= 6000000)
+		u8tmp = 2;
+	else if (c->bandwidth_hz <= 7000000)
+		u8tmp = 4;
+	else
+		u8tmp = 6;       /* 8000000 */
+
+	ret = regmap_write(dev->regmap, 0x80ec56, u8tmp);
+	if (ret)
+		goto err;
+
+	/* XXX: latest windows driver sets different value (a8 != 68) */
+	ret = regmap_write(dev->regmap, 0x80ec4c, 0xa0 | (l_band << 3));
+	if (ret)
+		goto err;
+
+	ret = regmap_write(dev->regmap, 0x80ec4d, (t_cal_freq >> 0) & 0xff);
+	if (ret)
+		goto err;
+
+	ret = regmap_write(dev->regmap, 0x80ec4e, (t_cal_freq >> 8) & 0xff);
+	if (ret)
+		goto err;
+
+	ret = regmap_write(dev->regmap, 0x80011e, (pre_lo_freq >> 0) & 0xff);
+	if (ret)
+		goto err;
+
+	ret = regmap_write(dev->regmap, 0x80011f, (pre_lo_freq >> 8) & 0xff);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	dev_dbg(&dev->client->dev, "failed %d\n", ret);
+	return ret;
+}
+
+static const struct dvb_tuner_ops it913x_tuner_ops = {
+	.info = {
+		.name           = "ITE IT913X",
+		.frequency_min  = 174000000,
+		.frequency_max  = 862000000,
+	},
+
+	.init = it913x_init,
+	.sleep = it913x_sleep,
+	.set_params = it913x_set_params,
+};
+
+static int it913x_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct it913x_config *cfg = client->dev.platform_data;
+	struct dvb_frontend *fe = cfg->fe;
+	struct it913x_dev *dev;
+	int ret;
+	char *chip_ver_str;
+	static const struct regmap_config regmap_config = {
+		.reg_bits = 24,
+		.val_bits = 8,
+	};
+
+	dev = kzalloc(sizeof(struct it913x_dev), GFP_KERNEL);
+	if (dev == NULL) {
+		ret = -ENOMEM;
+		dev_err(&client->dev, "kzalloc() failed\n");
+		goto err;
+	}
+
+	dev->client = client;
+	dev->fe = cfg->fe;
+	dev->chip_ver = cfg->chip_ver;
+	dev->role = cfg->role;
+	dev->regmap = regmap_init_i2c(client, &regmap_config);
+	if (IS_ERR(dev->regmap)) {
+		ret = PTR_ERR(dev->regmap);
+		goto err_kfree;
+	}
+
+	fe->tuner_priv = dev;
+	memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops,
+			sizeof(struct dvb_tuner_ops));
+	i2c_set_clientdata(client, dev);
+
+	if (dev->chip_ver == 1)
+		chip_ver_str = "AX";
+	else if (dev->chip_ver == 2)
+		chip_ver_str = "BX";
+	else
+		chip_ver_str = "??";
+
+	dev_info(&dev->client->dev, "ITE IT913X %s successfully attached\n",
+			chip_ver_str);
+	dev_dbg(&dev->client->dev, "chip_ver %u, role %u\n",
+			dev->chip_ver, dev->role);
+	return 0;
+
+err_kfree:
+	kfree(dev);
+err:
+	dev_dbg(&client->dev, "failed %d\n", ret);
+	return ret;
+}
+
+static int it913x_remove(struct i2c_client *client)
+{
+	struct it913x_dev *dev = i2c_get_clientdata(client);
+	struct dvb_frontend *fe = dev->fe;
+
+	dev_dbg(&client->dev, "\n");
+
+	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
+	fe->tuner_priv = NULL;
+	regmap_exit(dev->regmap);
+	kfree(dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id it913x_id_table[] = {
+	{"it913x", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, it913x_id_table);
+
+static struct i2c_driver it913x_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "it913x",
+	},
+	.probe		= it913x_probe,
+	.remove		= it913x_remove,
+	.id_table	= it913x_id_table,
+};
+
+module_i2c_driver(it913x_driver);
+
+MODULE_DESCRIPTION("ITE IT913X silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tuner_it913x.h b/drivers/media/tuners/it913x.h
similarity index 67%
rename from drivers/media/tuners/tuner_it913x.h
rename to drivers/media/tuners/it913x.h
index 4a11b48..33de53d 100644
--- a/drivers/media/tuners/tuner_it913x.h
+++ b/drivers/media/tuners/it913x.h
@@ -25,21 +25,30 @@
 
 #include "dvb_frontend.h"
 
-#if defined(CPTCFG_MEDIA_TUNER_IT913X) || \
-	(defined(CPTCFG_MEDIA_TUNER_IT913X_MODULE) && defined(MODULE))
-extern struct dvb_frontend *it913x_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c_adap,
-	u8 i2c_addr,
-	u8 config);
-#else
-static inline struct dvb_frontend *it913x_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c_adap,
-	u8 i2c_addr,
-	u8 config)
-{
-	pr_warn("%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
+/*
+ * I2C address
+ * 0x38, 0x3a, 0x3c, 0x3e
+ */
+struct it913x_config {
+	/*
+	 * pointer to DVB frontend
+	 */
+	struct dvb_frontend *fe;
+
+	/*
+	 * chip version
+	 * 1 = IT9135 AX
+	 * 2 = IT9135 BX
+	 */
+	unsigned int chip_ver:2;
+
+	/*
+	 * tuner role
+	 */
+#define IT913X_ROLE_SINGLE         0
+#define IT913X_ROLE_DUAL_MASTER    1
+#define IT913X_ROLE_DUAL_SLAVE     2
+	unsigned int role:2;
+};
 
 #endif
diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c
index 40c42de..caa5423 100644
--- a/drivers/media/tuners/m88ts2022.c
+++ b/drivers/media/tuners/m88ts2022.c
@@ -18,120 +18,11 @@
 
 #include "m88ts2022_priv.h"
 
-/* write multiple registers */
-static int m88ts2022_wr_regs(struct m88ts2022_priv *priv,
-		u8 reg, const u8 *val, int len)
+static int m88ts2022_cmd(struct m88ts2022_dev *dev, int op, int sleep, u8 reg,
+		u8 mask, u8 val, u8 *reg_val)
 {
-#define MAX_WR_LEN 3
-#define MAX_WR_XFER_LEN (MAX_WR_LEN + 1)
-	int ret;
-	u8 buf[MAX_WR_XFER_LEN];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->client->addr,
-			.flags = 0,
-			.len = 1 + len,
-			.buf = buf,
-		}
-	};
-
-	if (WARN_ON(len > MAX_WR_LEN))
-		return -EINVAL;
-
-	buf[0] = reg;
-	memcpy(&buf[1], val, len);
-
-	ret = i2c_transfer(priv->client->adapter, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		dev_warn(&priv->client->dev,
-				"%s: i2c wr failed=%d reg=%02x len=%d\n",
-				KBUILD_MODNAME, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-/* read multiple registers */
-static int m88ts2022_rd_regs(struct m88ts2022_priv *priv, u8 reg,
-		u8 *val, int len)
-{
-#define MAX_RD_LEN 1
-#define MAX_RD_XFER_LEN (MAX_RD_LEN)
-	int ret;
-	u8 buf[MAX_RD_XFER_LEN];
-	struct i2c_msg msg[2] = {
-		{
-			.addr = priv->client->addr,
-			.flags = 0,
-			.len = 1,
-			.buf = &reg,
-		}, {
-			.addr = priv->client->addr,
-			.flags = I2C_M_RD,
-			.len = len,
-			.buf = buf,
-		}
-	};
-
-	if (WARN_ON(len > MAX_RD_LEN))
-		return -EINVAL;
-
-	ret = i2c_transfer(priv->client->adapter, msg, 2);
-	if (ret == 2) {
-		memcpy(val, buf, len);
-		ret = 0;
-	} else {
-		dev_warn(&priv->client->dev,
-				"%s: i2c rd failed=%d reg=%02x len=%d\n",
-				KBUILD_MODNAME, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-/* write single register */
-static int m88ts2022_wr_reg(struct m88ts2022_priv *priv, u8 reg, u8 val)
-{
-	return m88ts2022_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int m88ts2022_rd_reg(struct m88ts2022_priv *priv, u8 reg, u8 *val)
-{
-	return m88ts2022_rd_regs(priv, reg, val, 1);
-}
-
-/* write single register with mask */
-static int m88ts2022_wr_reg_mask(struct m88ts2022_priv *priv,
-		u8 reg, u8 val, u8 mask)
-{
-	int ret;
-	u8 u8tmp;
-
-	/* no need for read if whole reg is written */
-	if (mask != 0xff) {
-		ret = m88ts2022_rd_regs(priv, reg, &u8tmp, 1);
-		if (ret)
-			return ret;
-
-		val &= mask;
-		u8tmp &= ~mask;
-		val |= u8tmp;
-	}
-
-	return m88ts2022_wr_regs(priv, reg, &val, 1);
-}
-
-static int m88ts2022_cmd(struct dvb_frontend *fe,
-		int op, int sleep, u8 reg, u8 mask, u8 val, u8 *reg_val)
-{
-	struct m88ts2022_priv *priv = fe->tuner_priv;
 	int ret, i;
-	u8 u8tmp;
+	unsigned int utmp;
 	struct m88ts2022_reg_val reg_vals[] = {
 		{0x51, 0x1f - op},
 		{0x51, 0x1f},
@@ -140,12 +31,12 @@
 	};
 
 	for (i = 0; i < 2; i++) {
-		dev_dbg(&priv->client->dev,
-				"%s: i=%d op=%02x reg=%02x mask=%02x val=%02x\n",
-				__func__, i, op, reg, mask, val);
+		dev_dbg(&dev->client->dev,
+				"i=%d op=%02x reg=%02x mask=%02x val=%02x\n",
+				i, op, reg, mask, val);
 
 		for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
-			ret = m88ts2022_wr_reg(priv, reg_vals[i].reg,
+			ret = regmap_write(dev->regmap, reg_vals[i].reg,
 					reg_vals[i].val);
 			if (ret)
 				goto err;
@@ -153,37 +44,38 @@
 
 		usleep_range(sleep * 1000, sleep * 10000);
 
-		ret = m88ts2022_rd_reg(priv, reg, &u8tmp);
+		ret = regmap_read(dev->regmap, reg, &utmp);
 		if (ret)
 			goto err;
 
-		if ((u8tmp & mask) != val)
+		if ((utmp & mask) != val)
 			break;
 	}
 
 	if (reg_val)
-		*reg_val = u8tmp;
+		*reg_val = utmp;
 err:
 	return ret;
 }
 
 static int m88ts2022_set_params(struct dvb_frontend *fe)
 {
-	struct m88ts2022_priv *priv = fe->tuner_priv;
+	struct m88ts2022_dev *dev = fe->tuner_priv;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret;
-	unsigned int frequency_khz, frequency_offset_khz, f_3db_hz;
+	unsigned int utmp, frequency_khz, frequency_offset_khz, f_3db_hz;
 	unsigned int f_ref_khz, f_vco_khz, div_ref, div_out, pll_n, gdiv28;
 	u8 buf[3], u8tmp, cap_code, lpf_gm, lpf_mxdiv, div_max, div_min;
 	u16 u16tmp;
-	dev_dbg(&priv->client->dev,
-			"%s: frequency=%d symbol_rate=%d rolloff=%d\n",
-			__func__, c->frequency, c->symbol_rate, c->rolloff);
+
+	dev_dbg(&dev->client->dev,
+			"frequency=%d symbol_rate=%d rolloff=%d\n",
+			c->frequency, c->symbol_rate, c->rolloff);
 	/*
 	 * Integer-N PLL synthesizer
 	 * kHz is used for all calculations to keep calculations within 32-bit
 	 */
-	f_ref_khz = DIV_ROUND_CLOSEST(priv->cfg.clock, 1000);
+	f_ref_khz = DIV_ROUND_CLOSEST(dev->cfg.clock, 1000);
 	div_ref = DIV_ROUND_CLOSEST(f_ref_khz, 2000);
 
 	if (c->symbol_rate < 5000000)
@@ -203,14 +95,14 @@
 
 	buf[0] = u8tmp;
 	buf[1] = 0x40;
-	ret = m88ts2022_wr_regs(priv, 0x10, buf, 2);
+	ret = regmap_bulk_write(dev->regmap, 0x10, buf, 2);
 	if (ret)
 		goto err;
 
 	f_vco_khz = frequency_khz * div_out;
 	pll_n = f_vco_khz * div_ref / f_ref_khz;
 	pll_n += pll_n % 2;
-	priv->frequency_khz = pll_n * f_ref_khz / div_ref / div_out;
+	dev->frequency_khz = pll_n * f_ref_khz / div_ref / div_out;
 
 	if (pll_n < 4095)
 		u16tmp = pll_n - 1024;
@@ -222,88 +114,87 @@
 	buf[0] = (u16tmp >> 8) & 0x3f;
 	buf[1] = (u16tmp >> 0) & 0xff;
 	buf[2] = div_ref - 8;
-	ret = m88ts2022_wr_regs(priv, 0x01, buf, 3);
+	ret = regmap_bulk_write(dev->regmap, 0x01, buf, 3);
 	if (ret)
 		goto err;
 
-	dev_dbg(&priv->client->dev,
-			"%s: frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n",
-			__func__, priv->frequency_khz,
-			priv->frequency_khz - c->frequency, f_vco_khz, pll_n,
-			div_ref, div_out);
+	dev_dbg(&dev->client->dev,
+			"frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n",
+			dev->frequency_khz, dev->frequency_khz - c->frequency,
+			f_vco_khz, pll_n, div_ref, div_out);
 
-	ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL);
+	ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp);
+	ret = regmap_read(dev->regmap, 0x14, &utmp);
 	if (ret)
 		goto err;
 
-	u8tmp &= 0x7f;
-	if (u8tmp < 64) {
-		ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x80, 0x80);
+	utmp &= 0x7f;
+	if (utmp < 64) {
+		ret = regmap_update_bits(dev->regmap, 0x10, 0x80, 0x80);
 		if (ret)
 			goto err;
 
-		ret = m88ts2022_wr_reg(priv, 0x11, 0x6f);
+		ret = regmap_write(dev->regmap, 0x11, 0x6f);
 		if (ret)
 			goto err;
 
-		ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL);
+		ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL);
 		if (ret)
 			goto err;
 	}
 
-	ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp);
+	ret = regmap_read(dev->regmap, 0x14, &utmp);
 	if (ret)
 		goto err;
 
-	u8tmp &= 0x1f;
-	if (u8tmp > 19) {
-		ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x00, 0x02);
+	utmp &= 0x1f;
+	if (utmp > 19) {
+		ret = regmap_update_bits(dev->regmap, 0x10, 0x02, 0x00);
 		if (ret)
 			goto err;
 	}
 
-	ret = m88ts2022_cmd(fe, 0x08, 5, 0x3c, 0xff, 0x00, NULL);
+	ret = m88ts2022_cmd(dev, 0x08, 5, 0x3c, 0xff, 0x00, NULL);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_wr_reg(priv, 0x25, 0x00);
+	ret = regmap_write(dev->regmap, 0x25, 0x00);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_wr_reg(priv, 0x27, 0x70);
+	ret = regmap_write(dev->regmap, 0x27, 0x70);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_wr_reg(priv, 0x41, 0x09);
+	ret = regmap_write(dev->regmap, 0x41, 0x09);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_wr_reg(priv, 0x08, 0x0b);
+	ret = regmap_write(dev->regmap, 0x08, 0x0b);
 	if (ret)
 		goto err;
 
 	/* filters */
 	gdiv28 = DIV_ROUND_CLOSEST(f_ref_khz * 1694U, 1000000U);
 
-	ret = m88ts2022_wr_reg(priv, 0x04, gdiv28);
+	ret = regmap_write(dev->regmap, 0x04, gdiv28);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+	ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
 	if (ret)
 		goto err;
 
 	cap_code = u8tmp & 0x3f;
 
-	ret = m88ts2022_wr_reg(priv, 0x41, 0x0d);
+	ret = regmap_write(dev->regmap, 0x41, 0x0d);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+	ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
 	if (ret)
 		goto err;
 
@@ -314,7 +205,7 @@
 	div_min = gdiv28 * 78 / 100;
 	div_max = clamp_val(div_max, 0U, 63U);
 
-	f_3db_hz = c->symbol_rate * 135UL / 200UL;
+	f_3db_hz = mult_frac(c->symbol_rate, 135, 200);
 	f_3db_hz +=  2000000U + (frequency_offset_khz * 1000U);
 	f_3db_hz = clamp(f_3db_hz, 7000000U, 40000000U);
 
@@ -327,25 +218,25 @@
 		lpf_mxdiv = DIV_ROUND_CLOSEST(++lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz);
 	lpf_mxdiv = clamp_val(lpf_mxdiv, 0U, div_max);
 
-	ret = m88ts2022_wr_reg(priv, 0x04, lpf_mxdiv);
+	ret = regmap_write(dev->regmap, 0x04, lpf_mxdiv);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_wr_reg(priv, 0x06, lpf_gm);
+	ret = regmap_write(dev->regmap, 0x06, lpf_gm);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+	ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
 	if (ret)
 		goto err;
 
 	cap_code = u8tmp & 0x3f;
 
-	ret = m88ts2022_wr_reg(priv, 0x41, 0x09);
+	ret = regmap_write(dev->regmap, 0x41, 0x09);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+	ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
 	if (ret)
 		goto err;
 
@@ -353,31 +244,31 @@
 	cap_code = (cap_code + u8tmp) / 2;
 
 	u8tmp = cap_code | 0x80;
-	ret = m88ts2022_wr_reg(priv, 0x25, u8tmp);
+	ret = regmap_write(dev->regmap, 0x25, u8tmp);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_wr_reg(priv, 0x27, 0x30);
+	ret = regmap_write(dev->regmap, 0x27, 0x30);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_wr_reg(priv, 0x08, 0x09);
+	ret = regmap_write(dev->regmap, 0x08, 0x09);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_cmd(fe, 0x01, 20, 0x21, 0xff, 0x00, NULL);
+	ret = m88ts2022_cmd(dev, 0x01, 20, 0x21, 0xff, 0x00, NULL);
 	if (ret)
 		goto err;
 err:
 	if (ret)
-		dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 
 	return ret;
 }
 
 static int m88ts2022_init(struct dvb_frontend *fe)
 {
-	struct m88ts2022_priv *priv = fe->tuner_priv;
+	struct m88ts2022_dev *dev = fe->tuner_priv;
 	int ret, i;
 	u8 u8tmp;
 	static const struct m88ts2022_reg_val reg_vals[] = {
@@ -393,23 +284,24 @@
 		{0x24, 0x02},
 		{0x12, 0xa0},
 	};
-	dev_dbg(&priv->client->dev, "%s:\n", __func__);
 
-	ret = m88ts2022_wr_reg(priv, 0x00, 0x01);
+	dev_dbg(&dev->client->dev, "\n");
+
+	ret = regmap_write(dev->regmap, 0x00, 0x01);
 	if (ret)
 		goto err;
 
-	ret = m88ts2022_wr_reg(priv, 0x00, 0x03);
+	ret = regmap_write(dev->regmap, 0x00, 0x03);
 	if (ret)
 		goto err;
 
-	switch (priv->cfg.clock_out) {
+	switch (dev->cfg.clock_out) {
 	case M88TS2022_CLOCK_OUT_DISABLED:
 		u8tmp = 0x60;
 		break;
 	case M88TS2022_CLOCK_OUT_ENABLED:
 		u8tmp = 0x70;
-		ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg.clock_out_div);
+		ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div);
 		if (ret)
 			goto err;
 		break;
@@ -420,58 +312,61 @@
 		goto err;
 	}
 
-	ret = m88ts2022_wr_reg(priv, 0x42, u8tmp);
+	ret = regmap_write(dev->regmap, 0x42, u8tmp);
 	if (ret)
 		goto err;
 
-	if (priv->cfg.loop_through)
+	if (dev->cfg.loop_through)
 		u8tmp = 0xec;
 	else
 		u8tmp = 0x6c;
 
-	ret = m88ts2022_wr_reg(priv, 0x62, u8tmp);
+	ret = regmap_write(dev->regmap, 0x62, u8tmp);
 	if (ret)
 		goto err;
 
 	for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
-		ret = m88ts2022_wr_reg(priv, reg_vals[i].reg, reg_vals[i].val);
+		ret = regmap_write(dev->regmap, reg_vals[i].reg, reg_vals[i].val);
 		if (ret)
 			goto err;
 	}
 err:
 	if (ret)
-		dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
 static int m88ts2022_sleep(struct dvb_frontend *fe)
 {
-	struct m88ts2022_priv *priv = fe->tuner_priv;
+	struct m88ts2022_dev *dev = fe->tuner_priv;
 	int ret;
-	dev_dbg(&priv->client->dev, "%s:\n", __func__);
 
-	ret = m88ts2022_wr_reg(priv, 0x00, 0x00);
+	dev_dbg(&dev->client->dev, "\n");
+
+	ret = regmap_write(dev->regmap, 0x00, 0x00);
 	if (ret)
 		goto err;
 err:
 	if (ret)
-		dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
 static int m88ts2022_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-	struct m88ts2022_priv *priv = fe->tuner_priv;
-	dev_dbg(&priv->client->dev, "%s:\n", __func__);
+	struct m88ts2022_dev *dev = fe->tuner_priv;
 
-	*frequency = priv->frequency_khz;
+	dev_dbg(&dev->client->dev, "\n");
+
+	*frequency = dev->frequency_khz;
 	return 0;
 }
 
 static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-	struct m88ts2022_priv *priv = fe->tuner_priv;
-	dev_dbg(&priv->client->dev, "%s:\n", __func__);
+	struct m88ts2022_dev *dev = fe->tuner_priv;
+
+	dev_dbg(&dev->client->dev, "\n");
 
 	*frequency = 0; /* Zero-IF */
 	return 0;
@@ -479,31 +374,30 @@
 
 static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
 {
-	struct m88ts2022_priv *priv = fe->tuner_priv;
+	struct m88ts2022_dev *dev = fe->tuner_priv;
 	int ret;
-	u8 u8tmp;
 	u16 gain, u16tmp;
-	unsigned int gain1, gain2, gain3;
+	unsigned int utmp, gain1, gain2, gain3;
 
-	ret = m88ts2022_rd_reg(priv, 0x3d, &u8tmp);
+	ret = regmap_read(dev->regmap, 0x3d, &utmp);
 	if (ret)
 		goto err;
 
-	gain1 = (u8tmp >> 0) & 0x1f;
+	gain1 = (utmp >> 0) & 0x1f;
 	gain1 = clamp(gain1, 0U, 15U);
 
-	ret = m88ts2022_rd_reg(priv, 0x21, &u8tmp);
+	ret = regmap_read(dev->regmap, 0x21, &utmp);
 	if (ret)
 		goto err;
 
-	gain2 = (u8tmp >> 0) & 0x1f;
+	gain2 = (utmp >> 0) & 0x1f;
 	gain2 = clamp(gain2, 2U, 16U);
 
-	ret = m88ts2022_rd_reg(priv, 0x66, &u8tmp);
+	ret = regmap_read(dev->regmap, 0x66, &utmp);
 	if (ret)
 		goto err;
 
-	gain3 = (u8tmp >> 3) & 0x07;
+	gain3 = (utmp >> 3) & 0x07;
 	gain3 = clamp(gain3, 0U, 6U);
 
 	gain = gain1 * 265 + gain2 * 338 + gain3 * 285;
@@ -515,7 +409,7 @@
 	*strength = (u16tmp - 59000) * 0xffff / (61500 - 59000);
 err:
 	if (ret)
-		dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -540,46 +434,56 @@
 {
 	struct m88ts2022_config *cfg = client->dev.platform_data;
 	struct dvb_frontend *fe = cfg->fe;
-	struct m88ts2022_priv *priv;
+	struct m88ts2022_dev *dev;
 	int ret;
-	u8 chip_id, u8tmp;
+	u8 u8tmp;
+	unsigned int utmp;
+	static const struct regmap_config regmap_config = {
+		.reg_bits = 8,
+		.val_bits = 8,
+	};
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv) {
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
 		ret = -ENOMEM;
-		dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+		dev_err(&client->dev, "kzalloc() failed\n");
 		goto err;
 	}
 
-	memcpy(&priv->cfg, cfg, sizeof(struct m88ts2022_config));
-	priv->client = client;
+	memcpy(&dev->cfg, cfg, sizeof(struct m88ts2022_config));
+	dev->client = client;
+	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
+	if (IS_ERR(dev->regmap)) {
+		ret = PTR_ERR(dev->regmap);
+		goto err;
+	}
 
 	/* check if the tuner is there */
-	ret = m88ts2022_rd_reg(priv, 0x00, &u8tmp);
+	ret = regmap_read(dev->regmap, 0x00, &utmp);
 	if (ret)
 		goto err;
 
-	if ((u8tmp & 0x03) == 0x00) {
-		ret = m88ts2022_wr_reg(priv, 0x00, 0x01);
-		if (ret < 0)
+	if ((utmp & 0x03) == 0x00) {
+		ret = regmap_write(dev->regmap, 0x00, 0x01);
+		if (ret)
 			goto err;
 
 		usleep_range(2000, 50000);
 	}
 
-	ret = m88ts2022_wr_reg(priv, 0x00, 0x03);
+	ret = regmap_write(dev->regmap, 0x00, 0x03);
 	if (ret)
 		goto err;
 
 	usleep_range(2000, 50000);
 
-	ret = m88ts2022_rd_reg(priv, 0x00, &chip_id);
+	ret = regmap_read(dev->regmap, 0x00, &utmp);
 	if (ret)
 		goto err;
 
-	dev_dbg(&priv->client->dev, "%s: chip_id=%02x\n", __func__, chip_id);
+	dev_dbg(&dev->client->dev, "chip_id=%02x\n", utmp);
 
-	switch (chip_id) {
+	switch (utmp) {
 	case 0xc3:
 	case 0x83:
 		break;
@@ -587,13 +491,13 @@
 		goto err;
 	}
 
-	switch (priv->cfg.clock_out) {
+	switch (dev->cfg.clock_out) {
 	case M88TS2022_CLOCK_OUT_DISABLED:
 		u8tmp = 0x60;
 		break;
 	case M88TS2022_CLOCK_OUT_ENABLED:
 		u8tmp = 0x70;
-		ret = m88ts2022_wr_reg(priv, 0x05, priv->cfg.clock_out_div);
+		ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div);
 		if (ret)
 			goto err;
 		break;
@@ -604,49 +508,48 @@
 		goto err;
 	}
 
-	ret = m88ts2022_wr_reg(priv, 0x42, u8tmp);
+	ret = regmap_write(dev->regmap, 0x42, u8tmp);
 	if (ret)
 		goto err;
 
-	if (priv->cfg.loop_through)
+	if (dev->cfg.loop_through)
 		u8tmp = 0xec;
 	else
 		u8tmp = 0x6c;
 
-	ret = m88ts2022_wr_reg(priv, 0x62, u8tmp);
+	ret = regmap_write(dev->regmap, 0x62, u8tmp);
 	if (ret)
 		goto err;
 
 	/* sleep */
-	ret = m88ts2022_wr_reg(priv, 0x00, 0x00);
+	ret = regmap_write(dev->regmap, 0x00, 0x00);
 	if (ret)
 		goto err;
 
-	dev_info(&priv->client->dev,
-			"%s: Montage M88TS2022 successfully identified\n",
-			KBUILD_MODNAME);
+	dev_info(&dev->client->dev, "Montage M88TS2022 successfully identified\n");
 
-	fe->tuner_priv = priv;
+	fe->tuner_priv = dev;
 	memcpy(&fe->ops.tuner_ops, &m88ts2022_tuner_ops,
 			sizeof(struct dvb_tuner_ops));
 
-	i2c_set_clientdata(client, priv);
+	i2c_set_clientdata(client, dev);
 	return 0;
 err:
-	dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
-	kfree(priv);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
+	kfree(dev);
 	return ret;
 }
 
 static int m88ts2022_remove(struct i2c_client *client)
 {
-	struct m88ts2022_priv *priv = i2c_get_clientdata(client);
-	struct dvb_frontend *fe = priv->cfg.fe;
-	dev_dbg(&client->dev, "%s:\n", __func__);
+	struct m88ts2022_dev *dev = i2c_get_clientdata(client);
+	struct dvb_frontend *fe = dev->cfg.fe;
+
+	dev_dbg(&client->dev, "\n");
 
 	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
 	fe->tuner_priv = NULL;
-	kfree(priv);
+	kfree(dev);
 
 	return 0;
 }
diff --git a/drivers/media/tuners/m88ts2022_priv.h b/drivers/media/tuners/m88ts2022_priv.h
index 0363dd8..feeb5ad 100644
--- a/drivers/media/tuners/m88ts2022_priv.h
+++ b/drivers/media/tuners/m88ts2022_priv.h
@@ -18,11 +18,12 @@
 #define M88TS2022_PRIV_H
 
 #include "m88ts2022.h"
+#include <linux/regmap.h>
 
-struct m88ts2022_priv {
+struct m88ts2022_dev {
 	struct m88ts2022_config cfg;
 	struct i2c_client *client;
-	struct dvb_frontend *fe;
+	struct regmap *regmap;
 	u32 frequency_khz;
 };
 
diff --git a/drivers/media/tuners/msi001.c b/drivers/media/tuners/msi001.c
index ee99e37..26019e7 100644
--- a/drivers/media/tuners/msi001.c
+++ b/drivers/media/tuners/msi001.c
@@ -67,7 +67,8 @@
 {
 	int ret;
 	u32 reg;
-	dev_dbg(&s->spi->dev, "%s: lna=%d mixer=%d if=%d\n", __func__,
+
+	dev_dbg(&s->spi->dev, "lna=%d mixer=%d if=%d\n",
 			lna_gain, mixer_gain, if_gain);
 
 	reg = 1 << 0;
@@ -83,7 +84,7 @@
 
 	return 0;
 err:
-	dev_dbg(&s->spi->dev, "%s: failed %d\n", __func__, ret);
+	dev_dbg(&s->spi->dev, "failed %d\n", ret);
 	return ret;
 };
 
@@ -94,6 +95,7 @@
 	u32 reg;
 	u64 f_vco, tmp64;
 	u8 mode, filter_mode, lo_div;
+
 	static const struct {
 		u32 rf;
 		u8 mode;
@@ -145,9 +147,7 @@
 	#define R_REF 4
 	#define F_OUT_STEP 1
 
-	dev_dbg(&s->spi->dev,
-			"%s: f_rf=%d f_if=%d\n",
-			__func__, f_rf, f_if);
+	dev_dbg(&s->spi->dev, "f_rf=%d f_if=%d\n", f_rf, f_if);
 
 	for (i = 0; i < ARRAY_SIZE(band_lut); i++) {
 		if (f_rf <= band_lut[i].rf) {
@@ -198,8 +198,7 @@
 
 	s->bandwidth->val = bandwidth_lut[i].freq;
 
-	dev_dbg(&s->spi->dev, "%s: bandwidth selected=%d\n",
-			__func__, bandwidth_lut[i].freq);
+	dev_dbg(&s->spi->dev, "bandwidth selected=%d\n", bandwidth_lut[i].freq);
 
 	f_vco = (u64) (f_rf + f_if + f_if1) * lo_div;
 	tmp64 = f_vco;
@@ -225,9 +224,8 @@
 	tmp += 1ul * F_REF * R_REF * frac / thresh;
 	tmp /= lo_div;
 
-	dev_dbg(&s->spi->dev,
-			"%s: rf=%u:%u n=%d thresh=%d frac=%d\n",
-				__func__, f_rf, tmp, n, thresh, frac);
+	dev_dbg(&s->spi->dev, "rf=%u:%u n=%d thresh=%d frac=%d\n",
+				f_rf, tmp, n, thresh, frac);
 
 	ret = msi001_wreg(s, 0x00000e);
 	if (ret)
@@ -276,7 +274,7 @@
 
 	return 0;
 err:
-	dev_dbg(&s->spi->dev, "%s: failed %d\n", __func__, ret);
+	dev_dbg(&s->spi->dev, "failed %d\n", ret);
 	return ret;
 };
 
@@ -284,7 +282,8 @@
 {
 	struct msi001 *s = sd_to_msi001(sd);
 	int ret;
-	dev_dbg(&s->spi->dev, "%s: on=%d\n", __func__, on);
+
+	dev_dbg(&s->spi->dev, "on=%d\n", on);
 
 	if (on)
 		ret = 0;
@@ -301,7 +300,8 @@
 static int msi001_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
 {
 	struct msi001 *s = sd_to_msi001(sd);
-	dev_dbg(&s->spi->dev, "%s: index=%d\n", __func__, v->index);
+
+	dev_dbg(&s->spi->dev, "index=%d\n", v->index);
 
 	strlcpy(v->name, "Mirics MSi001", sizeof(v->name));
 	v->type = V4L2_TUNER_RF;
@@ -315,14 +315,16 @@
 static int msi001_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v)
 {
 	struct msi001 *s = sd_to_msi001(sd);
-	dev_dbg(&s->spi->dev, "%s: index=%d\n", __func__, v->index);
+
+	dev_dbg(&s->spi->dev, "index=%d\n", v->index);
 	return 0;
 }
 
 static int msi001_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
 {
 	struct msi001 *s = sd_to_msi001(sd);
-	dev_dbg(&s->spi->dev, "%s: tuner=%d\n", __func__, f->tuner);
+
+	dev_dbg(&s->spi->dev, "tuner=%d\n", f->tuner);
 	f->frequency = s->f_tuner;
 	return 0;
 }
@@ -332,8 +334,9 @@
 {
 	struct msi001 *s = sd_to_msi001(sd);
 	unsigned int band;
-	dev_dbg(&s->spi->dev, "%s: tuner=%d type=%d frequency=%u\n",
-			__func__, f->tuner, f->type, f->frequency);
+
+	dev_dbg(&s->spi->dev, "tuner=%d type=%d frequency=%u\n",
+			f->tuner, f->type, f->frequency);
 
 	if (f->frequency < ((bands[0].rangehigh + bands[1].rangelow) / 2))
 		band = 0;
@@ -349,8 +352,9 @@
 		struct v4l2_frequency_band *band)
 {
 	struct msi001 *s = sd_to_msi001(sd);
-	dev_dbg(&s->spi->dev, "%s: tuner=%d type=%d index=%d\n",
-			__func__, band->tuner, band->type, band->index);
+
+	dev_dbg(&s->spi->dev, "tuner=%d type=%d index=%d\n",
+			band->tuner, band->type, band->index);
 
 	if (band->index >= ARRAY_SIZE(bands))
 		return -EINVAL;
@@ -380,9 +384,10 @@
 	struct msi001 *s = container_of(ctrl->handler, struct msi001, hdl);
 
 	int ret;
+
 	dev_dbg(&s->spi->dev,
-			"%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
-			__func__, ctrl->id, ctrl->name, ctrl->val,
+			"id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
+			ctrl->id, ctrl->name, ctrl->val,
 			ctrl->minimum, ctrl->maximum, ctrl->step);
 
 	switch (ctrl->id) {
@@ -403,8 +408,7 @@
 				s->mixer_gain->cur.val, s->if_gain->val);
 		break;
 	default:
-		dev_dbg(&s->spi->dev, "%s: unkown control %d\n",
-				__func__, ctrl->id);
+		dev_dbg(&s->spi->dev, "unkown control %d\n", ctrl->id);
 		ret = -EINVAL;
 	}
 
@@ -419,7 +423,8 @@
 {
 	struct msi001 *s;
 	int ret;
-	dev_dbg(&spi->dev, "%s:\n", __func__);
+
+	dev_dbg(&spi->dev, "\n");
 
 	s = kzalloc(sizeof(struct msi001), GFP_KERNEL);
 	if (s == NULL) {
@@ -466,7 +471,8 @@
 {
 	struct v4l2_subdev *sd = spi_get_drvdata(spi);
 	struct msi001 *s = sd_to_msi001(sd);
-	dev_dbg(&spi->dev, "%s:\n", __func__);
+
+	dev_dbg(&spi->dev, "\n");
 
 	/*
 	 * Registered by v4l2_spi_new_subdev() from master driver, but we must
diff --git a/drivers/media/tuners/mt2060.c b/drivers/media/tuners/mt2060.c
index 13381de..b87b254 100644
--- a/drivers/media/tuners/mt2060.c
+++ b/drivers/media/tuners/mt2060.c
@@ -157,7 +157,6 @@
 {
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct mt2060_priv *priv;
-	int ret=0;
 	int i=0;
 	u32 freq;
 	u8  lnaband;
@@ -240,7 +239,7 @@
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
 
-	return ret;
+	return 0;
 }
 
 static void mt2060_calibrate(struct mt2060_priv *priv)
diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c
index f640dcf..9e9c5eb 100644
--- a/drivers/media/tuners/mt2063.c
+++ b/drivers/media/tuners/mt2063.c
@@ -1216,7 +1216,7 @@
 	if (status >= 0) {
 		val =
 		    (state->
-		     reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode]
+		     reg[MT2063_REG_PD1_TGT] & ~0x40) | (RFAGCEN[Mode]
 								   ? 0x40 :
 								   0x00);
 		if (state->reg[MT2063_REG_PD1_TGT] != val)
@@ -1225,7 +1225,7 @@
 
 	/* LNARin */
 	if (status >= 0) {
-		u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) |
+		u8 val = (state->reg[MT2063_REG_CTRL_2C] & ~0x03) |
 			 (LNARIN[Mode] & 0x03);
 		if (state->reg[MT2063_REG_CTRL_2C] != val)
 			status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val);
@@ -1235,19 +1235,19 @@
 	if (status >= 0) {
 		val =
 		    (state->
-		     reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) |
+		     reg[MT2063_REG_FIFF_CTRL2] & ~0xF0) |
 		    (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4);
 		if (state->reg[MT2063_REG_FIFF_CTRL2] != val) {
 			status |=
 			    mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val);
 			/* trigger FIFF calibration, needed after changing FIFFQ */
 			val =
-			    (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01);
+			    (state->reg[MT2063_REG_FIFF_CTRL] | 0x01);
 			status |=
 			    mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
 			val =
 			    (state->
-			     reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01);
+			     reg[MT2063_REG_FIFF_CTRL] & ~0x01);
 			status |=
 			    mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val);
 		}
@@ -1259,7 +1259,7 @@
 
 	/* acLNAmax */
 	if (status >= 0) {
-		u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) |
+		u8 val = (state->reg[MT2063_REG_LNA_OV] & ~0x1F) |
 			 (ACLNAMAX[Mode] & 0x1F);
 		if (state->reg[MT2063_REG_LNA_OV] != val)
 			status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val);
@@ -1267,7 +1267,7 @@
 
 	/* LNATGT */
 	if (status >= 0) {
-		u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) |
+		u8 val = (state->reg[MT2063_REG_LNA_TGT] & ~0x3F) |
 			 (LNATGT[Mode] & 0x3F);
 		if (state->reg[MT2063_REG_LNA_TGT] != val)
 			status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
@@ -1275,7 +1275,7 @@
 
 	/* ACRF */
 	if (status >= 0) {
-		u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) |
+		u8 val = (state->reg[MT2063_REG_RF_OV] & ~0x1F) |
 			 (ACRFMAX[Mode] & 0x1F);
 		if (state->reg[MT2063_REG_RF_OV] != val)
 			status |= mt2063_setreg(state, MT2063_REG_RF_OV, val);
@@ -1283,7 +1283,7 @@
 
 	/* PD1TGT */
 	if (status >= 0) {
-		u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) |
+		u8 val = (state->reg[MT2063_REG_PD1_TGT] & ~0x3F) |
 			 (PD1TGT[Mode] & 0x3F);
 		if (state->reg[MT2063_REG_PD1_TGT] != val)
 			status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
@@ -1294,7 +1294,7 @@
 		u8 val = ACFIFMAX[Mode];
 		if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5)
 			val = 5;
-		val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) |
+		val = (state->reg[MT2063_REG_FIF_OV] & ~0x1F) |
 		      (val & 0x1F);
 		if (state->reg[MT2063_REG_FIF_OV] != val)
 			status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val);
@@ -1302,7 +1302,7 @@
 
 	/* PD2TGT */
 	if (status >= 0) {
-		u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) |
+		u8 val = (state->reg[MT2063_REG_PD2_TGT] & ~0x3F) |
 		    (PD2TGT[Mode] & 0x3F);
 		if (state->reg[MT2063_REG_PD2_TGT] != val)
 			status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val);
@@ -1310,7 +1310,7 @@
 
 	/* Ignore ATN Overload */
 	if (status >= 0) {
-		val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) |
+		val = (state->reg[MT2063_REG_LNA_TGT] & ~0x80) |
 		      (RFOVDIS[Mode] ? 0x80 : 0x00);
 		if (state->reg[MT2063_REG_LNA_TGT] != val)
 			status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val);
@@ -1318,7 +1318,7 @@
 
 	/* Ignore FIF Overload */
 	if (status >= 0) {
-		val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) |
+		val = (state->reg[MT2063_REG_PD1_TGT] & ~0x80) |
 		      (FIFOVDIS[Mode] ? 0x80 : 0x00);
 		if (state->reg[MT2063_REG_PD1_TGT] != val)
 			status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val);
diff --git a/drivers/media/tuners/mxl301rf.c b/drivers/media/tuners/mxl301rf.c
new file mode 100644
index 0000000..1575a5d
--- /dev/null
+++ b/drivers/media/tuners/mxl301rf.c
@@ -0,0 +1,349 @@
+/*
+ * MaxLinear MxL301RF OFDM tuner driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * NOTICE:
+ * This driver is incomplete and lacks init/config of the chips,
+ * as the necessary info is not disclosed.
+ * Other features like get_if_frequency() are missing as well.
+ * It assumes that users of this driver (such as a PCI bridge of
+ * DTV receiver cards) properly init and configure the chip
+ * via I2C *before* calling this driver's init() function.
+ *
+ * Currently, PT3 driver is the only one that uses this driver,
+ * and contains init/config code in its firmware.
+ * Thus some part of the code might be dependent on PT3 specific config.
+ */
+
+#include <linux/kernel.h>
+#include "mxl301rf.h"
+
+struct mxl301rf_state {
+	struct mxl301rf_config cfg;
+	struct i2c_client *i2c;
+};
+
+static struct mxl301rf_state *cfg_to_state(struct mxl301rf_config *c)
+{
+	return container_of(c, struct mxl301rf_state, cfg);
+}
+
+static int raw_write(struct mxl301rf_state *state, const u8 *buf, int len)
+{
+	int ret;
+
+	ret = i2c_master_send(state->i2c, buf, len);
+	if (ret >= 0 && ret < len)
+		ret = -EIO;
+	return (ret == len) ? 0 : ret;
+}
+
+static int reg_write(struct mxl301rf_state *state, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+
+	return raw_write(state, buf, 2);
+}
+
+static int reg_read(struct mxl301rf_state *state, u8 reg, u8 *val)
+{
+	u8 wbuf[2] = { 0xfb, reg };
+	int ret;
+
+	ret = raw_write(state, wbuf, sizeof(wbuf));
+	if (ret == 0)
+		ret = i2c_master_recv(state->i2c, val, 1);
+	if (ret >= 0 && ret < 1)
+		ret = -EIO;
+	return (ret == 1) ? 0 : ret;
+}
+
+/* tuner_ops */
+
+/* get RSSI and update propery cache, set to *out in % */
+static int mxl301rf_get_rf_strength(struct dvb_frontend *fe, u16 *out)
+{
+	struct mxl301rf_state *state;
+	int ret;
+	u8  rf_in1, rf_in2, rf_off1, rf_off2;
+	u16 rf_in, rf_off;
+	s64 level;
+	struct dtv_fe_stats *rssi;
+
+	rssi = &fe->dtv_property_cache.strength;
+	rssi->len = 1;
+	rssi->stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	*out = 0;
+
+	state = fe->tuner_priv;
+	ret = reg_write(state, 0x14, 0x01);
+	if (ret < 0)
+		return ret;
+	usleep_range(1000, 2000);
+
+	ret = reg_read(state, 0x18, &rf_in1);
+	if (ret == 0)
+		ret = reg_read(state, 0x19, &rf_in2);
+	if (ret == 0)
+		ret = reg_read(state, 0xd6, &rf_off1);
+	if (ret == 0)
+		ret = reg_read(state, 0xd7, &rf_off2);
+	if (ret != 0)
+		return ret;
+
+	rf_in = (rf_in2 & 0x07) << 8 | rf_in1;
+	rf_off = (rf_off2 & 0x0f) << 5 | (rf_off1 >> 3);
+	level = rf_in - rf_off - (113 << 3); /* x8 dBm */
+	level = level * 1000 / 8;
+	rssi->stat[0].svalue = level;
+	rssi->stat[0].scale = FE_SCALE_DECIBEL;
+	/* *out = (level - min) * 100 / (max - min) */
+	*out = (rf_in - rf_off + (1 << 9) - 1) * 100 / ((5 << 9) - 2);
+	return 0;
+}
+
+/* spur shift parameters */
+struct shf {
+	u32	freq;		/* Channel center frequency */
+	u32	ofst_th;	/* Offset frequency threshold */
+	u8	shf_val;	/* Spur shift value */
+	u8	shf_dir;	/* Spur shift direction */
+};
+
+static const struct shf shf_tab[] = {
+	{  64500, 500, 0x92, 0x07 },
+	{ 191500, 300, 0xe2, 0x07 },
+	{ 205500, 500, 0x2c, 0x04 },
+	{ 212500, 500, 0x1e, 0x04 },
+	{ 226500, 500, 0xd4, 0x07 },
+	{  99143, 500, 0x9c, 0x07 },
+	{ 173143, 500, 0xd4, 0x07 },
+	{ 191143, 300, 0xd4, 0x07 },
+	{ 207143, 500, 0xce, 0x07 },
+	{ 225143, 500, 0xce, 0x07 },
+	{ 243143, 500, 0xd4, 0x07 },
+	{ 261143, 500, 0xd4, 0x07 },
+	{ 291143, 500, 0xd4, 0x07 },
+	{ 339143, 500, 0x2c, 0x04 },
+	{ 117143, 500, 0x7a, 0x07 },
+	{ 135143, 300, 0x7a, 0x07 },
+	{ 153143, 500, 0x01, 0x07 }
+};
+
+struct reg_val {
+	u8 reg;
+	u8 val;
+} __attribute__ ((__packed__));
+
+static const struct reg_val set_idac[] = {
+	{ 0x0d, 0x00 },
+	{ 0x0c, 0x67 },
+	{ 0x6f, 0x89 },
+	{ 0x70, 0x0c },
+	{ 0x6f, 0x8a },
+	{ 0x70, 0x0e },
+	{ 0x6f, 0x8b },
+	{ 0x70, 0x1c },
+};
+
+static int mxl301rf_set_params(struct dvb_frontend *fe)
+{
+	struct reg_val tune0[] = {
+		{ 0x13, 0x00 },		/* abort tuning */
+		{ 0x3b, 0xc0 },
+		{ 0x3b, 0x80 },
+		{ 0x10, 0x95 },		/* BW */
+		{ 0x1a, 0x05 },
+		{ 0x61, 0x00 },		/* spur shift value (placeholder) */
+		{ 0x62, 0xa0 }		/* spur shift direction (placeholder) */
+	};
+
+	struct reg_val tune1[] = {
+		{ 0x11, 0x40 },		/* RF frequency L (placeholder) */
+		{ 0x12, 0x0e },		/* RF frequency H (placeholder) */
+		{ 0x13, 0x01 }		/* start tune */
+	};
+
+	struct mxl301rf_state *state;
+	u32 freq;
+	u16 f;
+	u32 tmp, div;
+	int i, ret;
+
+	state = fe->tuner_priv;
+	freq = fe->dtv_property_cache.frequency;
+
+	/* spur shift function (for analog) */
+	for (i = 0; i < ARRAY_SIZE(shf_tab); i++) {
+		if (freq >= (shf_tab[i].freq - shf_tab[i].ofst_th) * 1000 &&
+		    freq <= (shf_tab[i].freq + shf_tab[i].ofst_th) * 1000) {
+			tune0[5].val = shf_tab[i].shf_val;
+			tune0[6].val = 0xa0 | shf_tab[i].shf_dir;
+			break;
+		}
+	}
+	ret = raw_write(state, (u8 *) tune0, sizeof(tune0));
+	if (ret < 0)
+		goto failed;
+	usleep_range(3000, 4000);
+
+	/* convert freq to 10.6 fixed point float [MHz] */
+	f = freq / 1000000;
+	tmp = freq % 1000000;
+	div = 1000000;
+	for (i = 0; i < 6; i++) {
+		f <<= 1;
+		div >>= 1;
+		if (tmp > div) {
+			tmp -= div;
+			f |= 1;
+		}
+	}
+	if (tmp > 7812)
+		f++;
+	tune1[0].val = f & 0xff;
+	tune1[1].val = f >> 8;
+	ret = raw_write(state, (u8 *) tune1, sizeof(tune1));
+	if (ret < 0)
+		goto failed;
+	msleep(31);
+
+	ret = reg_write(state, 0x1a, 0x0d);
+	if (ret < 0)
+		goto failed;
+	ret = raw_write(state, (u8 *) set_idac, sizeof(set_idac));
+	if (ret < 0)
+		goto failed;
+	return 0;
+
+failed:
+	dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+		__func__, fe->dvb->num, fe->id);
+	return ret;
+}
+
+static const struct reg_val standby_data[] = {
+	{ 0x01, 0x00 },
+	{ 0x13, 0x00 }
+};
+
+static int mxl301rf_sleep(struct dvb_frontend *fe)
+{
+	struct mxl301rf_state *state;
+	int ret;
+
+	state = fe->tuner_priv;
+	ret = raw_write(state, (u8 *)standby_data, sizeof(standby_data));
+	if (ret < 0)
+		dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+			__func__, fe->dvb->num, fe->id);
+	return ret;
+}
+
+
+/* init sequence is not public.
+ * the parent must have init'ed the device.
+ * just wake up here.
+ */
+static int mxl301rf_init(struct dvb_frontend *fe)
+{
+	struct mxl301rf_state *state;
+	int ret;
+
+	state = fe->tuner_priv;
+
+	ret = reg_write(state, 0x01, 0x01);
+	if (ret < 0) {
+		dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+			 __func__, fe->dvb->num, fe->id);
+		return ret;
+	}
+	return 0;
+}
+
+/* I2C driver functions */
+
+static const struct dvb_tuner_ops mxl301rf_ops = {
+	.info = {
+		.name = "MaxLinear MxL301RF",
+
+		.frequency_min =  93000000,
+		.frequency_max = 803142857,
+	},
+
+	.init = mxl301rf_init,
+	.sleep = mxl301rf_sleep,
+
+	.set_params = mxl301rf_set_params,
+	.get_rf_strength = mxl301rf_get_rf_strength,
+};
+
+
+static int mxl301rf_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct mxl301rf_state *state;
+	struct mxl301rf_config *cfg;
+	struct dvb_frontend *fe;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	state->i2c = client;
+	cfg = client->dev.platform_data;
+
+	memcpy(&state->cfg, cfg, sizeof(state->cfg));
+	fe = cfg->fe;
+	fe->tuner_priv = state;
+	memcpy(&fe->ops.tuner_ops, &mxl301rf_ops, sizeof(mxl301rf_ops));
+
+	i2c_set_clientdata(client, &state->cfg);
+	dev_info(&client->dev, "MaxLinear MxL301RF attached.\n");
+	return 0;
+}
+
+static int mxl301rf_remove(struct i2c_client *client)
+{
+	struct mxl301rf_state *state;
+
+	state = cfg_to_state(i2c_get_clientdata(client));
+	state->cfg.fe->tuner_priv = NULL;
+	kfree(state);
+	return 0;
+}
+
+
+static const struct i2c_device_id mxl301rf_id[] = {
+	{"mxl301rf", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, mxl301rf_id);
+
+static struct i2c_driver mxl301rf_driver = {
+	.driver = {
+		.name	= "mxl301rf",
+	},
+	.probe		= mxl301rf_probe,
+	.remove		= mxl301rf_remove,
+	.id_table	= mxl301rf_id,
+};
+
+module_i2c_driver(mxl301rf_driver);
+
+MODULE_DESCRIPTION("MaxLinear MXL301RF tuner");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/mxl301rf.h b/drivers/media/tuners/mxl301rf.h
new file mode 100644
index 0000000..19e6840
--- /dev/null
+++ b/drivers/media/tuners/mxl301rf.h
@@ -0,0 +1,26 @@
+/*
+ * MaxLinear MxL301RF OFDM tuner driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * 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.
+ */
+
+#ifndef MXL301RF_H
+#define MXL301RF_H
+
+#include "dvb_frontend.h"
+
+struct mxl301rf_config {
+	struct dvb_frontend *fe;
+};
+
+#endif /* MXL301RF_H */
diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c
index b473b76..92a3be4 100644
--- a/drivers/media/tuners/mxl5005s.c
+++ b/drivers/media/tuners/mxl5005s.c
@@ -1692,7 +1692,6 @@
 	)
 {
 	struct mxl5005s_state *state = fe->tuner_priv;
-	u16 status = 0;
 
 	state->Mode = Mode;
 	state->IF_Mode = IF_mode;
@@ -1715,7 +1714,7 @@
 	/* Synthesizer LO frequency calculation */
 	MXL_SynthIFLO_Calc(fe);
 
-	return status;
+	return 0;
 }
 
 static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe)
diff --git a/drivers/media/tuners/qm1d1c0042.c b/drivers/media/tuners/qm1d1c0042.c
new file mode 100644
index 0000000..18bc745
--- /dev/null
+++ b/drivers/media/tuners/qm1d1c0042.c
@@ -0,0 +1,448 @@
+/*
+ * Sharp QM1D1C0042 8PSK tuner driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * 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.
+ */
+
+/*
+ * NOTICE:
+ * As the disclosed information on the chip is very limited,
+ * this driver lacks some features, including chip config like IF freq.
+ * It assumes that users of this driver (such as a PCI bridge of
+ * DTV receiver cards) know the relevant info and
+ * configure the chip via I2C if necessary.
+ *
+ * Currently, PT3 driver is the only one that uses this driver,
+ * and contains init/config code in its firmware.
+ * Thus some part of the code might be dependent on PT3 specific config.
+ */
+
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include "qm1d1c0042.h"
+
+#define QM1D1C0042_NUM_REGS 0x20
+
+static const u8 reg_initval[QM1D1C0042_NUM_REGS] = {
+	0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33,
+	0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+	0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86,
+	0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00
+};
+
+static const struct qm1d1c0042_config default_cfg = {
+	.xtal_freq = 16000,
+	.lpf = 1,
+	.fast_srch = 0,
+	.lpf_wait = 20,
+	.fast_srch_wait = 4,
+	.normal_srch_wait = 15,
+};
+
+struct qm1d1c0042_state {
+	struct qm1d1c0042_config cfg;
+	struct i2c_client *i2c;
+	u8 regs[QM1D1C0042_NUM_REGS];
+};
+
+static struct qm1d1c0042_state *cfg_to_state(struct qm1d1c0042_config *c)
+{
+	return container_of(c, struct qm1d1c0042_state, cfg);
+}
+
+static int reg_write(struct qm1d1c0042_state *state, u8 reg, u8 val)
+{
+	u8 wbuf[2] = { reg, val };
+	int ret;
+
+	ret = i2c_master_send(state->i2c, wbuf, sizeof(wbuf));
+	if (ret >= 0 && ret < sizeof(wbuf))
+		ret = -EIO;
+	return (ret == sizeof(wbuf)) ? 0 : ret;
+}
+
+static int reg_read(struct qm1d1c0042_state *state, u8 reg, u8 *val)
+{
+	struct i2c_msg msgs[2] = {
+		{
+			.addr = state->i2c->addr,
+			.flags = 0,
+			.buf = &reg,
+			.len = 1,
+		},
+		{
+			.addr = state->i2c->addr,
+			.flags = I2C_M_RD,
+			.buf = val,
+			.len = 1,
+		},
+	};
+	int ret;
+
+	ret = i2c_transfer(state->i2c->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret >= 0 && ret < ARRAY_SIZE(msgs))
+		ret = -EIO;
+	return (ret == ARRAY_SIZE(msgs)) ? 0 : ret;
+}
+
+
+static int qm1d1c0042_set_srch_mode(struct qm1d1c0042_state *state, bool fast)
+{
+	if (fast)
+		state->regs[0x03] |= 0x01; /* set fast search mode */
+	else
+		state->regs[0x03] &= ~0x01 & 0xff;
+
+	return reg_write(state, 0x03, state->regs[0x03]);
+}
+
+static int qm1d1c0042_wakeup(struct qm1d1c0042_state *state)
+{
+	int ret;
+
+	state->regs[0x01] |= 1 << 3;             /* BB_Reg_enable */
+	state->regs[0x01] &= (~(1 << 0)) & 0xff; /* NORMAL (wake-up) */
+	state->regs[0x05] &= (~(1 << 3)) & 0xff; /* pfd_rst NORMAL */
+	ret = reg_write(state, 0x01, state->regs[0x01]);
+	if (ret == 0)
+		ret = reg_write(state, 0x05, state->regs[0x05]);
+
+	if (ret < 0)
+		dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+			__func__, state->cfg.fe->dvb->num, state->cfg.fe->id);
+	return ret;
+}
+
+/* tuner_ops */
+
+static int qm1d1c0042_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+	struct qm1d1c0042_state *state;
+	struct qm1d1c0042_config *cfg;
+
+	state = fe->tuner_priv;
+	cfg = priv_cfg;
+
+	if (cfg->fe)
+		state->cfg.fe = cfg->fe;
+
+	if (cfg->xtal_freq != QM1D1C0042_CFG_XTAL_DFLT)
+		dev_warn(&state->i2c->dev,
+			"(%s) changing xtal_freq not supported. ", __func__);
+	state->cfg.xtal_freq = default_cfg.xtal_freq;
+
+	state->cfg.lpf = cfg->lpf;
+	state->cfg.fast_srch = cfg->fast_srch;
+
+	if (cfg->lpf_wait != QM1D1C0042_CFG_WAIT_DFLT)
+		state->cfg.lpf_wait = cfg->lpf_wait;
+	else
+		state->cfg.lpf_wait = default_cfg.lpf_wait;
+
+	if (cfg->fast_srch_wait != QM1D1C0042_CFG_WAIT_DFLT)
+		state->cfg.fast_srch_wait = cfg->fast_srch_wait;
+	else
+		state->cfg.fast_srch_wait = default_cfg.fast_srch_wait;
+
+	if (cfg->normal_srch_wait != QM1D1C0042_CFG_WAIT_DFLT)
+		state->cfg.normal_srch_wait = cfg->normal_srch_wait;
+	else
+		state->cfg.normal_srch_wait = default_cfg.normal_srch_wait;
+	return 0;
+}
+
+/* divisor, vco_band parameters */
+/*  {maxfreq,  param1(band?), param2(div?) */
+static const u32 conv_table[9][3] = {
+	{ 2151000, 1, 7 },
+	{ 1950000, 1, 6 },
+	{ 1800000, 1, 5 },
+	{ 1600000, 1, 4 },
+	{ 1450000, 1, 3 },
+	{ 1250000, 1, 2 },
+	{ 1200000, 0, 7 },
+	{  975000, 0, 6 },
+	{  950000, 0, 0 }
+};
+
+static int qm1d1c0042_set_params(struct dvb_frontend *fe)
+{
+	struct qm1d1c0042_state *state;
+	u32 freq;
+	int i, ret;
+	u8 val, mask;
+	u32 a, sd;
+	s32 b;
+
+	state = fe->tuner_priv;
+	freq = fe->dtv_property_cache.frequency;
+
+	state->regs[0x08] &= 0xf0;
+	state->regs[0x08] |= 0x09;
+
+	state->regs[0x13] &= 0x9f;
+	state->regs[0x13] |= 0x20;
+
+	/* div2/vco_band */
+	val = state->regs[0x02] & 0x0f;
+	for (i = 0; i < 8; i++)
+		if (freq < conv_table[i][0] && freq >= conv_table[i + 1][0]) {
+			val |= conv_table[i][1] << 7;
+			val |= conv_table[i][2] << 4;
+			break;
+		}
+	ret = reg_write(state, 0x02, val);
+	if (ret < 0)
+		return ret;
+
+	a = (freq + state->cfg.xtal_freq / 2) / state->cfg.xtal_freq;
+
+	state->regs[0x06] &= 0x40;
+	state->regs[0x06] |= (a - 12) / 4;
+	ret = reg_write(state, 0x06, state->regs[0x06]);
+	if (ret < 0)
+		return ret;
+
+	state->regs[0x07] &= 0xf0;
+	state->regs[0x07] |= (a - 4 * ((a - 12) / 4 + 1) - 5) & 0x0f;
+	ret = reg_write(state, 0x07, state->regs[0x07]);
+	if (ret < 0)
+		return ret;
+
+	/* LPF */
+	val = state->regs[0x08];
+	if (state->cfg.lpf) {
+		/* LPF_CLK, LPF_FC */
+		val &= 0xf0;
+		val |= 0x02;
+	}
+	ret = reg_write(state, 0x08, val);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * b = (freq / state->cfg.xtal_freq - a) << 20;
+	 * sd = b          (b >= 0)
+	 *      1<<22 + b  (b < 0)
+	 */
+	b = (s32)div64_s64(((s64) freq) << 20, state->cfg.xtal_freq)
+			   - (((s64) a) << 20);
+
+	if (b >= 0)
+		sd = b;
+	else
+		sd = (1 << 22) + b;
+
+	state->regs[0x09] &= 0xc0;
+	state->regs[0x09] |= (sd >> 16) & 0x3f;
+	state->regs[0x0a] = (sd >> 8) & 0xff;
+	state->regs[0x0b] = sd & 0xff;
+	ret = reg_write(state, 0x09, state->regs[0x09]);
+	if (ret == 0)
+		ret = reg_write(state, 0x0a, state->regs[0x0a]);
+	if (ret == 0)
+		ret = reg_write(state, 0x0b, state->regs[0x0b]);
+	if (ret != 0)
+		return ret;
+
+	if (!state->cfg.lpf) {
+		/* CSEL_Offset */
+		ret = reg_write(state, 0x13, state->regs[0x13]);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* VCO_TM, LPF_TM */
+	mask = state->cfg.lpf ? 0x3f : 0x7f;
+	val = state->regs[0x0c] & mask;
+	ret = reg_write(state, 0x0c, val);
+	if (ret < 0)
+		return ret;
+	usleep_range(2000, 3000);
+	val = state->regs[0x0c] | ~mask;
+	ret = reg_write(state, 0x0c, val);
+	if (ret < 0)
+		return ret;
+
+	if (state->cfg.lpf)
+		msleep(state->cfg.lpf_wait);
+	else if (state->regs[0x03] & 0x01)
+		msleep(state->cfg.fast_srch_wait);
+	else
+		msleep(state->cfg.normal_srch_wait);
+
+	if (state->cfg.lpf) {
+		/* LPF_FC */
+		ret = reg_write(state, 0x08, 0x09);
+		if (ret < 0)
+			return ret;
+
+		/* CSEL_Offset */
+		ret = reg_write(state, 0x13, state->regs[0x13]);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static int qm1d1c0042_sleep(struct dvb_frontend *fe)
+{
+	struct qm1d1c0042_state *state;
+	int ret;
+
+	state = fe->tuner_priv;
+	state->regs[0x01] &= (~(1 << 3)) & 0xff; /* BB_Reg_disable */
+	state->regs[0x01] |= 1 << 0;             /* STDBY */
+	state->regs[0x05] |= 1 << 3;             /* pfd_rst STANDBY */
+	ret = reg_write(state, 0x05, state->regs[0x05]);
+	if (ret == 0)
+		ret = reg_write(state, 0x01, state->regs[0x01]);
+	if (ret < 0)
+		dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+			__func__, fe->dvb->num, fe->id);
+	return ret;
+}
+
+static int qm1d1c0042_init(struct dvb_frontend *fe)
+{
+	struct qm1d1c0042_state *state;
+	u8 val;
+	int i, ret;
+
+	state = fe->tuner_priv;
+	memcpy(state->regs, reg_initval, sizeof(reg_initval));
+
+	reg_write(state, 0x01, 0x0c);
+	reg_write(state, 0x01, 0x0c);
+
+	ret = reg_write(state, 0x01, 0x0c); /* soft reset on */
+	if (ret < 0)
+		goto failed;
+	usleep_range(2000, 3000);
+
+	val = state->regs[0x01] | 0x10;
+	ret = reg_write(state, 0x01, val); /* soft reset off */
+	if (ret < 0)
+		goto failed;
+
+	/* check ID */
+	ret = reg_read(state, 0x00, &val);
+	if (ret < 0 || val != 0x48)
+		goto failed;
+	usleep_range(2000, 3000);
+
+	state->regs[0x0c] |= 0x40;
+	ret = reg_write(state, 0x0c, state->regs[0x0c]);
+	if (ret < 0)
+		goto failed;
+	msleep(state->cfg.lpf_wait);
+
+	/* set all writable registers */
+	for (i = 1; i <= 0x0c ; i++) {
+		ret = reg_write(state, i, state->regs[i]);
+		if (ret < 0)
+			goto failed;
+	}
+	for (i = 0x11; i < QM1D1C0042_NUM_REGS; i++) {
+		ret = reg_write(state, i, state->regs[i]);
+		if (ret < 0)
+			goto failed;
+	}
+
+	ret = qm1d1c0042_wakeup(state);
+	if (ret < 0)
+		goto failed;
+
+	ret = qm1d1c0042_set_srch_mode(state, state->cfg.fast_srch);
+	if (ret < 0)
+		goto failed;
+
+	return ret;
+
+failed:
+	dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
+		__func__, fe->dvb->num, fe->id);
+	return ret;
+}
+
+/* I2C driver functions */
+
+static const struct dvb_tuner_ops qm1d1c0042_ops = {
+	.info = {
+		.name = "Sharp QM1D1C0042",
+
+		.frequency_min =  950000,
+		.frequency_max = 2150000,
+	},
+
+	.init = qm1d1c0042_init,
+	.sleep = qm1d1c0042_sleep,
+	.set_config = qm1d1c0042_set_config,
+	.set_params = qm1d1c0042_set_params,
+};
+
+
+static int qm1d1c0042_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct qm1d1c0042_state *state;
+	struct qm1d1c0042_config *cfg;
+	struct dvb_frontend *fe;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+	state->i2c = client;
+
+	cfg = client->dev.platform_data;
+	fe = cfg->fe;
+	fe->tuner_priv = state;
+	qm1d1c0042_set_config(fe, cfg);
+	memcpy(&fe->ops.tuner_ops, &qm1d1c0042_ops, sizeof(qm1d1c0042_ops));
+
+	i2c_set_clientdata(client, &state->cfg);
+	dev_info(&client->dev, "Sharp QM1D1C0042 attached.\n");
+	return 0;
+}
+
+static int qm1d1c0042_remove(struct i2c_client *client)
+{
+	struct qm1d1c0042_state *state;
+
+	state = cfg_to_state(i2c_get_clientdata(client));
+	state->cfg.fe->tuner_priv = NULL;
+	kfree(state);
+	return 0;
+}
+
+
+static const struct i2c_device_id qm1d1c0042_id[] = {
+	{"qm1d1c0042", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, qm1d1c0042_id);
+
+static struct i2c_driver qm1d1c0042_driver = {
+	.driver = {
+		.name	= "qm1d1c0042",
+	},
+	.probe		= qm1d1c0042_probe,
+	.remove		= qm1d1c0042_remove,
+	.id_table	= qm1d1c0042_id,
+};
+
+module_i2c_driver(qm1d1c0042_driver);
+
+MODULE_DESCRIPTION("Sharp QM1D1C0042 tuner");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/qm1d1c0042.h b/drivers/media/tuners/qm1d1c0042.h
new file mode 100644
index 0000000..4f5c188
--- /dev/null
+++ b/drivers/media/tuners/qm1d1c0042.h
@@ -0,0 +1,37 @@
+/*
+ * Sharp QM1D1C0042 8PSK tuner driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ *
+ * 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.
+ */
+
+#ifndef QM1D1C0042_H
+#define QM1D1C0042_H
+
+#include "dvb_frontend.h"
+
+
+struct qm1d1c0042_config {
+	struct dvb_frontend *fe;
+
+	u32  xtal_freq;    /* [kHz] */ /* currently ignored */
+	bool lpf;          /* enable LPF */
+	bool fast_srch;    /* enable fast search mode, no LPF */
+	u32  lpf_wait;         /* wait in tuning with LPF enabled. [ms] */
+	u32  fast_srch_wait;   /* with fast-search mode, no LPF. [ms] */
+	u32  normal_srch_wait; /* with no LPF/fast-search mode. [ms] */
+};
+/* special values indicating to use the default in qm1d1c0042_config */
+#define QM1D1C0042_CFG_XTAL_DFLT 0
+#define QM1D1C0042_CFG_WAIT_DFLT 0
+
+#endif /* QM1D1C0042_H */
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index 6c53edb..cf97142 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2157/2158 silicon tuner driver
+ * Silicon Labs Si2147/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
@@ -55,8 +55,7 @@
 				break;
 		}
 
-		dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n",
-				__func__,
+		dev_dbg(&s->client->dev, "cmd execution took %d ms\n",
 				jiffies_to_msecs(jiffies) -
 				(jiffies_to_msecs(timeout) - TIMEOUT));
 
@@ -75,7 +74,7 @@
 
 	return 0;
 err:
-	dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&s->client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -88,9 +87,12 @@
 	u8 *fw_file;
 	unsigned int chip_id;
 
-	dev_dbg(&s->client->dev, "%s:\n", __func__);
+	dev_dbg(&s->client->dev, "\n");
 
-	/* configure? */
+	if (s->fw_loaded)
+		goto warm;
+
+	/* power up */
 	memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15);
 	cmd.wlen = 15;
 	cmd.rlen = 1;
@@ -111,45 +113,47 @@
 
 	#define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0)
 	#define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
+	#define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
 
 	switch (chip_id) {
 	case SI2158_A20:
 		fw_file = SI2158_A20_FIRMWARE;
 		break;
 	case SI2157_A30:
+	case SI2147_A30:
 		goto skip_fw_download;
 		break;
 	default:
 		dev_err(&s->client->dev,
-				"%s: unkown chip version Si21%d-%c%c%c\n",
-				KBUILD_MODNAME, cmd.args[2], cmd.args[1],
+				"unknown chip version Si21%d-%c%c%c\n",
+				cmd.args[2], cmd.args[1],
 				cmd.args[3], cmd.args[4]);
 		ret = -EINVAL;
 		goto err;
 	}
 
 	/* cold state - try to download firmware */
-	dev_info(&s->client->dev, "%s: found a '%s' in cold state\n",
-			KBUILD_MODNAME, si2157_ops.info.name);
+	dev_info(&s->client->dev, "found a '%s' in cold state\n",
+			si2157_ops.info.name);
 
 	/* request the firmware, this will block and timeout */
 	ret = request_firmware(&fw, fw_file, &s->client->dev);
 	if (ret) {
-		dev_err(&s->client->dev, "%s: firmware file '%s' not found\n",
-				KBUILD_MODNAME, fw_file);
+		dev_err(&s->client->dev, "firmware file '%s' not found\n",
+				fw_file);
 		goto err;
 	}
 
 	/* firmware should be n chunks of 17 bytes */
 	if (fw->size % 17 != 0) {
-		dev_err(&s->client->dev, "%s: firmware file '%s' is invalid\n",
-				KBUILD_MODNAME, fw_file);
+		dev_err(&s->client->dev, "firmware file '%s' is invalid\n",
+				fw_file);
 		ret = -EINVAL;
 		goto err;
 	}
 
-	dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n",
-			KBUILD_MODNAME, fw_file);
+	dev_info(&s->client->dev, "downloading firmware from file '%s'\n",
+			fw_file);
 
 	for (remaining = fw->size; remaining > 0; remaining -= 17) {
 		len = fw->data[fw->size - remaining];
@@ -159,8 +163,8 @@
 		ret = si2157_cmd_execute(s, &cmd);
 		if (ret) {
 			dev_err(&s->client->dev,
-					"%s: firmware download failed=%d\n",
-					KBUILD_MODNAME, ret);
+					"firmware download failed=%d\n",
+					ret);
 			goto err;
 		}
 	}
@@ -177,14 +181,17 @@
 	if (ret)
 		goto err;
 
-	s->active = true;
+	s->fw_loaded = true;
 
+warm:
+	s->active = true;
 	return 0;
+
 err:
 	if (fw)
 		release_firmware(fw);
 
-	dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&s->client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -194,20 +201,21 @@
 	int ret;
 	struct si2157_cmd cmd;
 
-	dev_dbg(&s->client->dev, "%s:\n", __func__);
+	dev_dbg(&s->client->dev, "\n");
 
 	s->active = false;
 
-	memcpy(cmd.args, "\x13", 1);
-	cmd.wlen = 1;
-	cmd.rlen = 0;
+	/* standby */
+	memcpy(cmd.args, "\x16\x00", 2);
+	cmd.wlen = 2;
+	cmd.rlen = 1;
 	ret = si2157_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
 
 	return 0;
 err:
-	dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&s->client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -220,8 +228,8 @@
 	u8 bandwidth, delivery_system;
 
 	dev_dbg(&s->client->dev,
-			"%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n",
-			__func__, c->delivery_system, c->frequency,
+			"delivery_system=%d frequency=%u bandwidth_hz=%u\n",
+			c->delivery_system, c->frequency,
 			c->bandwidth_hz);
 
 	if (!s->active) {
@@ -239,6 +247,9 @@
 		bandwidth = 0x0f;
 
 	switch (c->delivery_system) {
+	case SYS_ATSC:
+			delivery_system = 0x00;
+			break;
 	case SYS_DVBT:
 	case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */
 			delivery_system = 0x20;
@@ -256,7 +267,14 @@
 	if (s->inversion)
 		cmd.args[5] = 0x01;
 	cmd.wlen = 6;
-	cmd.rlen = 1;
+	cmd.rlen = 4;
+	ret = si2157_cmd_execute(s, &cmd);
+	if (ret)
+		goto err;
+
+	memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6);
+	cmd.wlen = 6;
+	cmd.rlen = 4;
 	ret = si2157_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
@@ -275,7 +293,7 @@
 
 	return 0;
 err:
-	dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&s->client->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -310,13 +328,14 @@
 	s = kzalloc(sizeof(struct si2157), GFP_KERNEL);
 	if (!s) {
 		ret = -ENOMEM;
-		dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+		dev_err(&client->dev, "kzalloc() failed\n");
 		goto err;
 	}
 
 	s->client = client;
 	s->fe = cfg->fe;
 	s->inversion = cfg->inversion;
+	s->fw_loaded = false;
 	mutex_init(&s->i2c_mutex);
 
 	/* check if the tuner is there */
@@ -333,11 +352,10 @@
 	i2c_set_clientdata(client, s);
 
 	dev_info(&s->client->dev,
-			"%s: Silicon Labs Si2157/Si2158 successfully attached\n",
-			KBUILD_MODNAME);
+			"Silicon Labs Si2157/Si2158 successfully attached\n");
 	return 0;
 err:
-	dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&client->dev, "failed=%d\n", ret);
 	kfree(s);
 
 	return ret;
@@ -348,7 +366,7 @@
 	struct si2157 *s = i2c_get_clientdata(client);
 	struct dvb_frontend *fe = s->fe;
 
-	dev_dbg(&client->dev, "%s:\n", __func__);
+	dev_dbg(&client->dev, "\n");
 
 	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
 	fe->tuner_priv = NULL;
diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h
index 6da4d5d..d3b19ca 100644
--- a/drivers/media/tuners/si2157.h
+++ b/drivers/media/tuners/si2157.h
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2157/2158 silicon tuner driver
+ * Silicon Labs Si2147/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
index 3ddab5e..e71ffaf 100644
--- a/drivers/media/tuners/si2157_priv.h
+++ b/drivers/media/tuners/si2157_priv.h
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2157/2158 silicon tuner driver
+ * Silicon Labs Si2147/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
@@ -26,6 +26,7 @@
 	struct i2c_client *client;
 	struct dvb_frontend *fe;
 	bool active;
+	bool fw_loaded;
 	bool inversion;
 };
 
diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c
index 05a4ac9..d93e066 100644
--- a/drivers/media/tuners/tda18212.c
+++ b/drivers/media/tuners/tda18212.c
@@ -19,125 +19,19 @@
  */
 
 #include "tda18212.h"
+#include <linux/regmap.h>
 
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE  64
-
-struct tda18212_priv {
-	struct tda18212_config *cfg;
-	struct i2c_adapter *i2c;
+struct tda18212_dev {
+	struct tda18212_config cfg;
+	struct i2c_client *client;
+	struct regmap *regmap;
 
 	u32 if_frequency;
 };
 
-/* write multiple registers */
-static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
-	int len)
-{
-	int ret;
-	u8 buf[MAX_XFER_SIZE];
-	struct i2c_msg msg[1] = {
-		{
-			.addr = priv->cfg->i2c_address,
-			.flags = 0,
-			.len = 1 + len,
-			.buf = buf,
-		}
-	};
-
-	if (1 + len > sizeof(buf)) {
-		dev_warn(&priv->i2c->dev,
-			 "%s: i2c wr reg=%04x: len=%d is too big!\n",
-			 KBUILD_MODNAME, reg, len);
-		return -EINVAL;
-	}
-
-	buf[0] = reg;
-	memcpy(&buf[1], val, len);
-
-	ret = i2c_transfer(priv->i2c, msg, 1);
-	if (ret == 1) {
-		ret = 0;
-	} else {
-		dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
-				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-	return ret;
-}
-
-/* read multiple registers */
-static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
-	int len)
-{
-	int ret;
-	u8 buf[MAX_XFER_SIZE];
-	struct i2c_msg msg[2] = {
-		{
-			.addr = priv->cfg->i2c_address,
-			.flags = 0,
-			.len = 1,
-			.buf = &reg,
-		}, {
-			.addr = priv->cfg->i2c_address,
-			.flags = I2C_M_RD,
-			.len = len,
-			.buf = buf,
-		}
-	};
-
-	if (len > sizeof(buf)) {
-		dev_warn(&priv->i2c->dev,
-			 "%s: i2c rd reg=%04x: len=%d is too big!\n",
-			 KBUILD_MODNAME, reg, len);
-		return -EINVAL;
-	}
-
-	ret = i2c_transfer(priv->i2c, msg, 2);
-	if (ret == 2) {
-		memcpy(val, buf, len);
-		ret = 0;
-	} else {
-		dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
-				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
-		ret = -EREMOTEIO;
-	}
-
-	return ret;
-}
-
-/* write single register */
-static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val)
-{
-	return tda18212_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val)
-{
-	return tda18212_rd_regs(priv, reg, val, 1);
-}
-
-#if 0 /* keep, useful when developing driver */
-static void tda18212_dump_regs(struct tda18212_priv *priv)
-{
-	int i;
-	u8 buf[256];
-
-	#define TDA18212_RD_LEN 32
-	for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN)
-		tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN);
-
-	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf,
-		sizeof(buf), true);
-
-	return;
-}
-#endif
-
 static int tda18212_set_params(struct dvb_frontend *fe)
 {
-	struct tda18212_priv *priv = fe->tuner_priv;
+	struct tda18212_dev *dev = fe->tuner_priv;
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	int ret, i;
 	u32 if_khz;
@@ -166,9 +60,9 @@
 		[ATSC_QAM] = { 0x7d, 0x20, 0x63 },
 	};
 
-	dev_dbg(&priv->i2c->dev,
-			"%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
-			__func__, c->delivery_system, c->frequency,
+	dev_dbg(&dev->client->dev,
+			"delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+			c->delivery_system, c->frequency,
 			c->bandwidth_hz);
 
 	if (fe->ops.i2c_gate_ctrl)
@@ -176,25 +70,25 @@
 
 	switch (c->delivery_system) {
 	case SYS_ATSC:
-		if_khz = priv->cfg->if_atsc_vsb;
+		if_khz = dev->cfg.if_atsc_vsb;
 		i = ATSC_VSB;
 		break;
 	case SYS_DVBC_ANNEX_B:
-		if_khz = priv->cfg->if_atsc_qam;
+		if_khz = dev->cfg.if_atsc_qam;
 		i = ATSC_QAM;
 		break;
 	case SYS_DVBT:
 		switch (c->bandwidth_hz) {
 		case 6000000:
-			if_khz = priv->cfg->if_dvbt_6;
+			if_khz = dev->cfg.if_dvbt_6;
 			i = DVBT_6;
 			break;
 		case 7000000:
-			if_khz = priv->cfg->if_dvbt_7;
+			if_khz = dev->cfg.if_dvbt_7;
 			i = DVBT_7;
 			break;
 		case 8000000:
-			if_khz = priv->cfg->if_dvbt_8;
+			if_khz = dev->cfg.if_dvbt_8;
 			i = DVBT_8;
 			break;
 		default:
@@ -205,15 +99,15 @@
 	case SYS_DVBT2:
 		switch (c->bandwidth_hz) {
 		case 6000000:
-			if_khz = priv->cfg->if_dvbt2_6;
+			if_khz = dev->cfg.if_dvbt2_6;
 			i = DVBT2_6;
 			break;
 		case 7000000:
-			if_khz = priv->cfg->if_dvbt2_7;
+			if_khz = dev->cfg.if_dvbt2_7;
 			i = DVBT2_7;
 			break;
 		case 8000000:
-			if_khz = priv->cfg->if_dvbt2_8;
+			if_khz = dev->cfg.if_dvbt2_8;
 			i = DVBT2_8;
 			break;
 		default:
@@ -223,7 +117,7 @@
 		break;
 	case SYS_DVBC_ANNEX_A:
 	case SYS_DVBC_ANNEX_C:
-		if_khz = priv->cfg->if_dvbc;
+		if_khz = dev->cfg.if_dvbc;
 		i = DVBC_8;
 		break;
 	default:
@@ -231,15 +125,15 @@
 		goto error;
 	}
 
-	ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]);
+	ret = regmap_write(dev->regmap, 0x23, bw_params[i][2]);
 	if (ret)
 		goto error;
 
-	ret = tda18212_wr_reg(priv, 0x06, 0x00);
+	ret = regmap_write(dev->regmap, 0x06, 0x00);
 	if (ret)
 		goto error;
 
-	ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]);
+	ret = regmap_write(dev->regmap, 0x0f, bw_params[i][0]);
 	if (ret)
 		goto error;
 
@@ -252,12 +146,12 @@
 	buf[6] = ((c->frequency / 1000) >>  0) & 0xff;
 	buf[7] = 0xc1;
 	buf[8] = 0x01;
-	ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf));
+	ret = regmap_bulk_write(dev->regmap, 0x12, buf, sizeof(buf));
 	if (ret)
 		goto error;
 
 	/* actual IF rounded as it is on register */
-	priv->if_frequency = buf[3] * 50 * 1000;
+	dev->if_frequency = buf[3] * 50 * 1000;
 
 exit:
 	if (fe->ops.i2c_gate_ctrl)
@@ -266,26 +160,19 @@
 	return ret;
 
 error:
-	dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
 	goto exit;
 }
 
 static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
-	struct tda18212_priv *priv = fe->tuner_priv;
+	struct tda18212_dev *dev = fe->tuner_priv;
 
-	*frequency = priv->if_frequency;
+	*frequency = dev->if_frequency;
 
 	return 0;
 }
 
-static int tda18212_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
 static const struct dvb_tuner_ops tda18212_tuner_ops = {
 	.info = {
 		.name           = "NXP TDA18212",
@@ -295,53 +182,110 @@
 		.frequency_step =      1000,
 	},
 
-	.release       = tda18212_release,
-
 	.set_params    = tda18212_set_params,
 	.get_if_frequency = tda18212_get_if_frequency,
 };
 
-struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, struct tda18212_config *cfg)
+static int tda18212_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
 {
-	struct tda18212_priv *priv = NULL;
+	struct tda18212_config *cfg = client->dev.platform_data;
+	struct dvb_frontend *fe = cfg->fe;
+	struct tda18212_dev *dev;
 	int ret;
-	u8 val;
+	unsigned int chip_id;
+	char *version;
+	static const struct regmap_config regmap_config = {
+		.reg_bits = 8,
+		.val_bits = 8,
+	};
 
-	priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		ret = -ENOMEM;
+		dev_err(&client->dev, "kzalloc() failed\n");
+		goto err;
+	}
 
-	priv->cfg = cfg;
-	priv->i2c = i2c;
-	fe->tuner_priv = priv;
+	memcpy(&dev->cfg, cfg, sizeof(struct tda18212_config));
+	dev->client = client;
+	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
+	if (IS_ERR(dev->regmap)) {
+		ret = PTR_ERR(dev->regmap);
+		goto err;
+	}
 
+	/* check if the tuner is there */
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
 
-	/* check if the tuner is there */
-	ret = tda18212_rd_reg(priv, 0x00, &val);
+	ret = regmap_read(dev->regmap, 0x00, &chip_id);
+	dev_dbg(&dev->client->dev, "chip_id=%02x\n", chip_id);
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 
-	if (!ret)
-		dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, val);
-	if (ret || val != 0xc7) {
-		kfree(priv);
-		return NULL;
+	if (ret)
+		goto err;
+
+	switch (chip_id) {
+	case 0xc7:
+		version = "M"; /* master */
+		break;
+	case 0x47:
+		version = "S"; /* slave */
+		break;
+	default:
+		ret = -ENODEV;
+		goto err;
 	}
 
-	dev_info(&priv->i2c->dev,
-			"%s: NXP TDA18212HN successfully identified\n",
-			KBUILD_MODNAME);
+	dev_info(&dev->client->dev,
+			"NXP TDA18212HN/%s successfully identified\n", version);
 
+	fe->tuner_priv = dev;
 	memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
-		sizeof(struct dvb_tuner_ops));
+			sizeof(struct dvb_tuner_ops));
+	i2c_set_clientdata(client, dev);
 
-	return fe;
+	return 0;
+err:
+	dev_dbg(&client->dev, "failed=%d\n", ret);
+	kfree(dev);
+	return ret;
 }
-EXPORT_SYMBOL(tda18212_attach);
+
+static int tda18212_remove(struct i2c_client *client)
+{
+	struct tda18212_dev *dev = i2c_get_clientdata(client);
+	struct dvb_frontend *fe = dev->cfg.fe;
+
+	dev_dbg(&client->dev, "\n");
+
+	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
+	fe->tuner_priv = NULL;
+	kfree(dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id tda18212_id[] = {
+	{"tda18212", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, tda18212_id);
+
+static struct i2c_driver tda18212_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "tda18212",
+	},
+	.probe		= tda18212_probe,
+	.remove		= tda18212_remove,
+	.id_table	= tda18212_id,
+};
+
+module_i2c_driver(tda18212_driver);
 
 MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/tuners/tda18212.h b/drivers/media/tuners/tda18212.h
index 7337254..e58c909 100644
--- a/drivers/media/tuners/tda18212.h
+++ b/drivers/media/tuners/tda18212.h
@@ -25,8 +25,6 @@
 #include "dvb_frontend.h"
 
 struct tda18212_config {
-	u8 i2c_address;
-
 	u16 if_dvbt_6;
 	u16 if_dvbt_7;
 	u16 if_dvbt_8;
@@ -37,18 +35,11 @@
 	u16 if_dvbc;
 	u16 if_atsc_vsb;
 	u16 if_atsc_qam;
-};
 
-#if IS_ENABLED(CPTCFG_MEDIA_TUNER_TDA18212)
-extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, struct tda18212_config *cfg);
-#else
-static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
-	struct i2c_adapter *i2c, struct tda18212_config *cfg)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-	return NULL;
-}
-#endif
+	/*
+	 * pointer to DVB frontend
+	 */
+	struct dvb_frontend *fe;
+};
 
 #endif
diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c
index 18c77af..86e5e31 100644
--- a/drivers/media/tuners/tda18271-common.c
+++ b/drivers/media/tuners/tda18271-common.c
@@ -714,12 +714,11 @@
 	return ret;
 }
 
-int _tda_printk(struct tda18271_priv *state, const char *level,
-		const char *func, const char *fmt, ...)
+void _tda_printk(struct tda18271_priv *state, const char *level,
+		 const char *func, const char *fmt, ...)
 {
 	struct va_format vaf;
 	va_list args;
-	int rtn;
 
 	va_start(args, fmt);
 
@@ -727,15 +726,13 @@
 	vaf.va = &args;
 
 	if (state)
-		rtn = printk("%s%s: [%d-%04x|%c] %pV",
-			     level, func, i2c_adapter_id(state->i2c_props.adap),
-			     state->i2c_props.addr,
-			     (state->role == TDA18271_MASTER) ? 'M' : 'S',
-			     &vaf);
+		printk("%s%s: [%d-%04x|%c] %pV",
+		       level, func, i2c_adapter_id(state->i2c_props.adap),
+		       state->i2c_props.addr,
+		       (state->role == TDA18271_MASTER) ? 'M' : 'S',
+		       &vaf);
 	else
-		rtn = printk("%s%s: %pV", level, func, &vaf);
+		printk("%s%s: %pV", level, func, &vaf);
 
 	va_end(args);
-
-	return rtn;
 }
diff --git a/drivers/media/tuners/tda18271-priv.h b/drivers/media/tuners/tda18271-priv.h
index 454c152..b36a7b7 100644
--- a/drivers/media/tuners/tda18271-priv.h
+++ b/drivers/media/tuners/tda18271-priv.h
@@ -139,8 +139,8 @@
 #define DBG_CAL  16
 
 __attribute__((format(printf, 4, 5)))
-int _tda_printk(struct tda18271_priv *state, const char *level,
-		const char *func, const char *fmt, ...);
+void _tda_printk(struct tda18271_priv *state, const char *level,
+		 const char *func, const char *fmt, ...);
 
 #define tda_printk(st, lvl, fmt, arg...)			\
 	_tda_printk(st, lvl, __func__, fmt, ##arg)
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
index 565eeeb..d12f5e4 100644
--- a/drivers/media/tuners/tuner-xc2028.c
+++ b/drivers/media/tuners/tuner-xc2028.c
@@ -178,67 +178,67 @@
 #define dump_firm_type(t) 	dump_firm_type_and_int_freq(t, 0)
 static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
 {
-	 if (type & BASE)
+	if (type & BASE)
 		printk("BASE ");
-	 if (type & INIT1)
+	if (type & INIT1)
 		printk("INIT1 ");
-	 if (type & F8MHZ)
+	if (type & F8MHZ)
 		printk("F8MHZ ");
-	 if (type & MTS)
+	if (type & MTS)
 		printk("MTS ");
-	 if (type & D2620)
+	if (type & D2620)
 		printk("D2620 ");
-	 if (type & D2633)
+	if (type & D2633)
 		printk("D2633 ");
-	 if (type & DTV6)
+	if (type & DTV6)
 		printk("DTV6 ");
-	 if (type & QAM)
+	if (type & QAM)
 		printk("QAM ");
-	 if (type & DTV7)
+	if (type & DTV7)
 		printk("DTV7 ");
-	 if (type & DTV78)
+	if (type & DTV78)
 		printk("DTV78 ");
-	 if (type & DTV8)
+	if (type & DTV8)
 		printk("DTV8 ");
-	 if (type & FM)
+	if (type & FM)
 		printk("FM ");
-	 if (type & INPUT1)
+	if (type & INPUT1)
 		printk("INPUT1 ");
-	 if (type & LCD)
+	if (type & LCD)
 		printk("LCD ");
-	 if (type & NOGD)
+	if (type & NOGD)
 		printk("NOGD ");
-	 if (type & MONO)
+	if (type & MONO)
 		printk("MONO ");
-	 if (type & ATSC)
+	if (type & ATSC)
 		printk("ATSC ");
-	 if (type & IF)
+	if (type & IF)
 		printk("IF ");
-	 if (type & LG60)
+	if (type & LG60)
 		printk("LG60 ");
-	 if (type & ATI638)
+	if (type & ATI638)
 		printk("ATI638 ");
-	 if (type & OREN538)
+	if (type & OREN538)
 		printk("OREN538 ");
-	 if (type & OREN36)
+	if (type & OREN36)
 		printk("OREN36 ");
-	 if (type & TOYOTA388)
+	if (type & TOYOTA388)
 		printk("TOYOTA388 ");
-	 if (type & TOYOTA794)
+	if (type & TOYOTA794)
 		printk("TOYOTA794 ");
-	 if (type & DIBCOM52)
+	if (type & DIBCOM52)
 		printk("DIBCOM52 ");
-	 if (type & ZARLINK456)
+	if (type & ZARLINK456)
 		printk("ZARLINK456 ");
-	 if (type & CHINA)
+	if (type & CHINA)
 		printk("CHINA ");
-	 if (type & F6MHZ)
+	if (type & F6MHZ)
 		printk("F6MHZ ");
-	 if (type & INPUT2)
+	if (type & INPUT2)
 		printk("INPUT2 ");
-	 if (type & SCODE)
+	if (type & SCODE)
 		printk("SCODE ");
-	 if (type & HAS_IF)
+	if (type & HAS_IF)
 		printk("HAS_IF_%d ", int_freq);
 }
 
diff --git a/drivers/media/tuners/tuner_it913x.c b/drivers/media/tuners/tuner_it913x.c
deleted file mode 100644
index 3d83c42..0000000
--- a/drivers/media/tuners/tuner_it913x.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * ITE Tech IT9137 silicon tuner driver
- *
- *  Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
- *  IT9137 Copyright (C) ITE Tech Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#include "tuner_it913x_priv.h"
-
-struct it913x_state {
-	struct i2c_adapter *i2c_adap;
-	u8 i2c_addr;
-	u8 chip_ver;
-	u8 tuner_type;
-	u8 firmware_ver;
-	u16 tun_xtal;
-	u8 tun_fdiv;
-	u8 tun_clk_mode;
-	u32 tun_fn_min;
-};
-
-/* read multiple registers */
-static int it913x_rd_regs(struct it913x_state *state,
-		u32 reg, u8 *data, u8 count)
-{
-	int ret;
-	u8 b[3];
-	struct i2c_msg msg[2] = {
-		{ .addr = state->i2c_addr, .flags = 0,
-			.buf = b, .len = sizeof(b) },
-		{ .addr = state->i2c_addr, .flags = I2C_M_RD,
-			.buf = data, .len = count }
-	};
-	b[0] = (u8)(reg >> 16) & 0xff;
-	b[1] = (u8)(reg >> 8) & 0xff;
-	b[2] = (u8) reg & 0xff;
-	b[0] |= 0x80; /* All reads from demodulator */
-
-	ret = i2c_transfer(state->i2c_adap, msg, 2);
-
-	return ret;
-}
-
-/* read single register */
-static int it913x_rd_reg(struct it913x_state *state, u32 reg)
-{
-	int ret;
-	u8 b[1];
-	ret = it913x_rd_regs(state, reg, &b[0], sizeof(b));
-	return (ret < 0) ? -ENODEV : b[0];
-}
-
-/* write multiple registers */
-static int it913x_wr_regs(struct it913x_state *state,
-		u8 pro, u32 reg, u8 buf[], u8 count)
-{
-	u8 b[256];
-	struct i2c_msg msg[1] = {
-		{ .addr = state->i2c_addr, .flags = 0,
-		  .buf = b, .len = 3 + count }
-	};
-	int ret;
-	b[0] = (u8)(reg >> 16) & 0xff;
-	b[1] = (u8)(reg >> 8) & 0xff;
-	b[2] = (u8) reg & 0xff;
-	memcpy(&b[3], buf, count);
-
-	if (pro == PRO_DMOD)
-		b[0] |= 0x80;
-
-	ret = i2c_transfer(state->i2c_adap, msg, 1);
-
-	if (ret < 0)
-		return -EIO;
-
-	return 0;
-}
-
-/* write single register */
-static int it913x_wr_reg(struct it913x_state *state,
-		u8 pro, u32 reg, u32 data)
-{
-	int ret;
-	u8 b[4];
-	u8 s;
-
-	b[0] = data >> 24;
-	b[1] = (data >> 16) & 0xff;
-	b[2] = (data >> 8) & 0xff;
-	b[3] = data & 0xff;
-	/* expand write as needed */
-	if (data < 0x100)
-		s = 3;
-	else if (data < 0x1000)
-		s = 2;
-	else if (data < 0x100000)
-		s = 1;
-	else
-		s = 0;
-
-	ret = it913x_wr_regs(state, pro, reg, &b[s], sizeof(b) - s);
-
-	return ret;
-}
-
-static int it913x_script_loader(struct it913x_state *state,
-		struct it913xset *loadscript)
-{
-	int ret, i;
-	if (loadscript == NULL)
-		return -EINVAL;
-
-	for (i = 0; i < 1000; ++i) {
-		if (loadscript[i].pro == 0xff)
-			break;
-		ret = it913x_wr_regs(state, loadscript[i].pro,
-			loadscript[i].address,
-			loadscript[i].reg, loadscript[i].count);
-		if (ret < 0)
-			return -ENODEV;
-	}
-	return 0;
-}
-
-static int it913x_init(struct dvb_frontend *fe)
-{
-	struct it913x_state *state = fe->tuner_priv;
-	int ret, i, reg;
-	u8 val, nv_val;
-	u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
-	u8 b[2];
-
-	reg = it913x_rd_reg(state, 0xec86);
-	switch (reg) {
-	case 0:
-		state->tun_clk_mode = reg;
-		state->tun_xtal = 2000;
-		state->tun_fdiv = 3;
-		val = 16;
-		break;
-	case -ENODEV:
-		return -ENODEV;
-	case 1:
-	default:
-		state->tun_clk_mode = reg;
-		state->tun_xtal = 640;
-		state->tun_fdiv = 1;
-		val = 6;
-		break;
-	}
-
-	reg = it913x_rd_reg(state, 0xed03);
-
-	if (reg < 0)
-		return -ENODEV;
-	else if (reg < ARRAY_SIZE(nv))
-		nv_val = nv[reg];
-	else
-		nv_val = 2;
-
-	for (i = 0; i < 50; i++) {
-		ret = it913x_rd_regs(state, 0xed23, &b[0], sizeof(b));
-		reg = (b[1] << 8) + b[0];
-		if (reg > 0)
-			break;
-		if (ret < 0)
-			return -ENODEV;
-		udelay(2000);
-	}
-	state->tun_fn_min = state->tun_xtal * reg;
-	state->tun_fn_min /= (state->tun_fdiv * nv_val);
-	dev_dbg(&state->i2c_adap->dev, "%s: Tuner fn_min %d\n", __func__,
-			state->tun_fn_min);
-
-	if (state->chip_ver > 1)
-		msleep(50);
-	else {
-		for (i = 0; i < 50; i++) {
-			reg = it913x_rd_reg(state, 0xec82);
-			if (reg > 0)
-				break;
-			if (reg < 0)
-				return -ENODEV;
-			udelay(2000);
-		}
-	}
-
-	/* Power Up Tuner - common all versions */
-	ret = it913x_wr_reg(state, PRO_DMOD, 0xec40, 0x1);
-	ret |= it913x_wr_reg(state, PRO_DMOD, 0xfba8, 0x0);
-	ret |= it913x_wr_reg(state, PRO_DMOD, 0xec57, 0x0);
-	ret |= it913x_wr_reg(state, PRO_DMOD, 0xec58, 0x0);
-
-	return it913x_wr_reg(state, PRO_DMOD, 0xed81, val);
-}
-
-static int it9137_set_params(struct dvb_frontend *fe)
-{
-	struct it913x_state *state = fe->tuner_priv;
-	struct it913xset *set_tuner = set_it9137_template;
-	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
-	u32 bandwidth = p->bandwidth_hz;
-	u32 frequency_m = p->frequency;
-	int ret, reg;
-	u32 frequency = frequency_m / 1000;
-	u32 freq, temp_f, tmp;
-	u16 iqik_m_cal;
-	u16 n_div;
-	u8 n;
-	u8 l_band;
-	u8 lna_band;
-	u8 bw;
-
-	if (state->firmware_ver == 1)
-		set_tuner = set_it9135_template;
-	else
-		set_tuner = set_it9137_template;
-
-	dev_dbg(&state->i2c_adap->dev, "%s: Tuner Frequency %d Bandwidth %d\n",
-			__func__, frequency, bandwidth);
-
-	if (frequency >= 51000 && frequency <= 440000) {
-		l_band = 0;
-		lna_band = 0;
-	} else if (frequency > 440000 && frequency <= 484000) {
-		l_band = 1;
-		lna_band = 1;
-	} else if (frequency > 484000 && frequency <= 533000) {
-		l_band = 1;
-		lna_band = 2;
-	} else if (frequency > 533000 && frequency <= 587000) {
-		l_band = 1;
-		lna_band = 3;
-	} else if (frequency > 587000 && frequency <= 645000) {
-		l_band = 1;
-		lna_band = 4;
-	} else if (frequency > 645000 && frequency <= 710000) {
-		l_band = 1;
-		lna_band = 5;
-	} else if (frequency > 710000 && frequency <= 782000) {
-		l_band = 1;
-		lna_band = 6;
-	} else if (frequency > 782000 && frequency <= 860000) {
-		l_band = 1;
-		lna_band = 7;
-	} else if (frequency > 1450000 && frequency <= 1492000) {
-		l_band = 1;
-		lna_band = 0;
-	} else if (frequency > 1660000 && frequency <= 1685000) {
-		l_band = 1;
-		lna_band = 1;
-	} else
-		return -EINVAL;
-	set_tuner[0].reg[0] = lna_band;
-
-	switch (bandwidth) {
-	case 5000000:
-		bw = 0;
-		break;
-	case 6000000:
-		bw = 2;
-		break;
-	case 7000000:
-		bw = 4;
-		break;
-	default:
-	case 8000000:
-		bw = 6;
-		break;
-	}
-
-	set_tuner[1].reg[0] = bw;
-	set_tuner[2].reg[0] = 0xa0 | (l_band << 3);
-
-	if (frequency > 53000 && frequency <= 74000) {
-		n_div = 48;
-		n = 0;
-	} else if (frequency > 74000 && frequency <= 111000) {
-		n_div = 32;
-		n = 1;
-	} else if (frequency > 111000 && frequency <= 148000) {
-		n_div = 24;
-		n = 2;
-	} else if (frequency > 148000 && frequency <= 222000) {
-		n_div = 16;
-		n = 3;
-	} else if (frequency > 222000 && frequency <= 296000) {
-		n_div = 12;
-		n = 4;
-	} else if (frequency > 296000 && frequency <= 445000) {
-		n_div = 8;
-		n = 5;
-	} else if (frequency > 445000 && frequency <= state->tun_fn_min) {
-		n_div = 6;
-		n = 6;
-	} else if (frequency > state->tun_fn_min && frequency <= 950000) {
-		n_div = 4;
-		n = 7;
-	} else if (frequency > 1450000 && frequency <= 1680000) {
-		n_div = 2;
-		n = 0;
-	} else
-		return -EINVAL;
-
-	reg = it913x_rd_reg(state, 0xed81);
-	iqik_m_cal = (u16)reg * n_div;
-
-	if (reg < 0x20) {
-		if (state->tun_clk_mode == 0)
-			iqik_m_cal = (iqik_m_cal * 9) >> 5;
-		else
-			iqik_m_cal >>= 1;
-	} else {
-		iqik_m_cal = 0x40 - iqik_m_cal;
-		if (state->tun_clk_mode == 0)
-			iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
-		else
-			iqik_m_cal = ~(iqik_m_cal >> 1);
-	}
-
-	temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv;
-	freq = temp_f / state->tun_xtal;
-	tmp = freq * state->tun_xtal;
-
-	if ((temp_f - tmp) >= (state->tun_xtal >> 1))
-		freq++;
-
-	freq += (u32) n << 13;
-	/* Frequency OMEGA_IQIK_M_CAL_MID*/
-	temp_f = freq + (u32)iqik_m_cal;
-
-	set_tuner[3].reg[0] =  temp_f & 0xff;
-	set_tuner[4].reg[0] =  (temp_f >> 8) & 0xff;
-
-	dev_dbg(&state->i2c_adap->dev, "%s: High Frequency = %04x\n",
-			__func__, temp_f);
-
-	/* Lower frequency */
-	set_tuner[5].reg[0] =  freq & 0xff;
-	set_tuner[6].reg[0] =  (freq >> 8) & 0xff;
-
-	dev_dbg(&state->i2c_adap->dev, "%s: low Frequency = %04x\n",
-			__func__, freq);
-
-	ret = it913x_script_loader(state, set_tuner);
-
-	return (ret < 0) ? -ENODEV : 0;
-}
-
-/* Power sequence */
-/* Power Up	Tuner on -> Frontend suspend off -> Tuner clk on */
-/* Power Down	Frontend suspend on -> Tuner clk off -> Tuner off */
-
-static int it913x_sleep(struct dvb_frontend *fe)
-{
-	struct it913x_state *state = fe->tuner_priv;
-	return it913x_script_loader(state, it9137_tuner_off);
-}
-
-static int it913x_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	return 0;
-}
-
-static const struct dvb_tuner_ops it913x_tuner_ops = {
-	.info = {
-		.name           = "ITE Tech IT913X",
-		.frequency_min  = 174000000,
-		.frequency_max  = 862000000,
-	},
-
-	.release = it913x_release,
-
-	.init = it913x_init,
-	.sleep = it913x_sleep,
-	.set_params = it9137_set_params,
-};
-
-struct dvb_frontend *it913x_attach(struct dvb_frontend *fe,
-		struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 config)
-{
-	struct it913x_state *state = NULL;
-	int ret;
-
-	/* allocate memory for the internal state */
-	state = kzalloc(sizeof(struct it913x_state), GFP_KERNEL);
-	if (state == NULL)
-		return NULL;
-
-	state->i2c_adap = i2c_adap;
-	state->i2c_addr = i2c_addr;
-
-	switch (config) {
-	case AF9033_TUNER_IT9135_38:
-	case AF9033_TUNER_IT9135_51:
-	case AF9033_TUNER_IT9135_52:
-		state->chip_ver = 0x01;
-		break;
-	case AF9033_TUNER_IT9135_60:
-	case AF9033_TUNER_IT9135_61:
-	case AF9033_TUNER_IT9135_62:
-		state->chip_ver = 0x02;
-		break;
-	default:
-		dev_dbg(&i2c_adap->dev,
-				"%s: invalid config=%02x\n", __func__, config);
-		goto error;
-	}
-
-	state->tuner_type = config;
-	state->firmware_ver = 1;
-
-	/* tuner RF initial */
-	ret = it913x_wr_reg(state, PRO_DMOD, 0xec4c, 0x68);
-	if (ret < 0)
-		goto error;
-
-	fe->tuner_priv = state;
-	memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops,
-			sizeof(struct dvb_tuner_ops));
-
-	dev_info(&i2c_adap->dev,
-			"%s: ITE Tech IT913X successfully attached\n",
-			KBUILD_MODNAME);
-	dev_dbg(&i2c_adap->dev, "%s: config=%02x chip_ver=%02x\n",
-			__func__, config, state->chip_ver);
-
-	return fe;
-error:
-	kfree(state);
-	return NULL;
-}
-EXPORT_SYMBOL(it913x_attach);
-
-MODULE_DESCRIPTION("ITE Tech IT913X silicon tuner driver");
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tuner_it913x_priv.h b/drivers/media/tuners/tuner_it913x_priv.h
deleted file mode 100644
index ce65210..0000000
--- a/drivers/media/tuners/tuner_it913x_priv.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * ITE Tech IT9137 silicon tuner driver
- *
- *  Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
- *  IT9137 Copyright (C) ITE Tech Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef IT913X_PRIV_H
-#define IT913X_PRIV_H
-
-#include "tuner_it913x.h"
-#include "af9033.h"
-
-#define PRO_LINK		0x0
-#define PRO_DMOD		0x1
-#define TRIGGER_OFSM		0x0000
-
-struct it913xset {	u32 pro;
-			u32 address;
-			u8 reg[15];
-			u8 count;
-};
-
-/* Tuner setting scripts (still keeping it9137) */
-static struct it913xset it9137_tuner_off[] = {
-	{PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off  */
-	{PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */
-	{PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04},
-	{PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-				0x00, 0x00, 0x00, 0x00}, 0x0c},
-	{PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04},
-	{PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-				0x00}, 0x09},
-	{PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-				0x00, 0x00}, 0x0a},
-	{PRO_DMOD, 0xec20, {0x00}, 0x01},
-	{PRO_DMOD, 0xec3f, {0x01}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-static struct it913xset set_it9135_template[] = {
-	{PRO_DMOD, 0xee06, {0x00}, 0x01},
-	{PRO_DMOD, 0xec56, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4c, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4d, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4e, {0x00}, 0x01},
-	{PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */
-	{PRO_DMOD, 0x011f, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-static struct it913xset set_it9137_template[] = {
-	{PRO_DMOD, 0xee06, {0x00}, 0x01},
-	{PRO_DMOD, 0xec56, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4c, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4d, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4e, {0x00}, 0x01},
-	{PRO_DMOD, 0xec4f, {0x00}, 0x01},
-	{PRO_DMOD, 0xec50, {0x00}, 0x01},
-	{0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
-};
-
-#endif
diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c
index f9ab79e..219ebaf 100644
--- a/drivers/media/tuners/xc4000.c
+++ b/drivers/media/tuners/xc4000.c
@@ -569,67 +569,67 @@
 #define dump_firm_type(t)	dump_firm_type_and_int_freq(t, 0)
 static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
 {
-	 if (type & BASE)
+	if (type & BASE)
 		printk(KERN_CONT "BASE ");
-	 if (type & INIT1)
+	if (type & INIT1)
 		printk(KERN_CONT "INIT1 ");
-	 if (type & F8MHZ)
+	if (type & F8MHZ)
 		printk(KERN_CONT "F8MHZ ");
-	 if (type & MTS)
+	if (type & MTS)
 		printk(KERN_CONT "MTS ");
-	 if (type & D2620)
+	if (type & D2620)
 		printk(KERN_CONT "D2620 ");
-	 if (type & D2633)
+	if (type & D2633)
 		printk(KERN_CONT "D2633 ");
-	 if (type & DTV6)
+	if (type & DTV6)
 		printk(KERN_CONT "DTV6 ");
-	 if (type & QAM)
+	if (type & QAM)
 		printk(KERN_CONT "QAM ");
-	 if (type & DTV7)
+	if (type & DTV7)
 		printk(KERN_CONT "DTV7 ");
-	 if (type & DTV78)
+	if (type & DTV78)
 		printk(KERN_CONT "DTV78 ");
-	 if (type & DTV8)
+	if (type & DTV8)
 		printk(KERN_CONT "DTV8 ");
-	 if (type & FM)
+	if (type & FM)
 		printk(KERN_CONT "FM ");
-	 if (type & INPUT1)
+	if (type & INPUT1)
 		printk(KERN_CONT "INPUT1 ");
-	 if (type & LCD)
+	if (type & LCD)
 		printk(KERN_CONT "LCD ");
-	 if (type & NOGD)
+	if (type & NOGD)
 		printk(KERN_CONT "NOGD ");
-	 if (type & MONO)
+	if (type & MONO)
 		printk(KERN_CONT "MONO ");
-	 if (type & ATSC)
+	if (type & ATSC)
 		printk(KERN_CONT "ATSC ");
-	 if (type & IF)
+	if (type & IF)
 		printk(KERN_CONT "IF ");
-	 if (type & LG60)
+	if (type & LG60)
 		printk(KERN_CONT "LG60 ");
-	 if (type & ATI638)
+	if (type & ATI638)
 		printk(KERN_CONT "ATI638 ");
-	 if (type & OREN538)
+	if (type & OREN538)
 		printk(KERN_CONT "OREN538 ");
-	 if (type & OREN36)
+	if (type & OREN36)
 		printk(KERN_CONT "OREN36 ");
-	 if (type & TOYOTA388)
+	if (type & TOYOTA388)
 		printk(KERN_CONT "TOYOTA388 ");
-	 if (type & TOYOTA794)
+	if (type & TOYOTA794)
 		printk(KERN_CONT "TOYOTA794 ");
-	 if (type & DIBCOM52)
+	if (type & DIBCOM52)
 		printk(KERN_CONT "DIBCOM52 ");
-	 if (type & ZARLINK456)
+	if (type & ZARLINK456)
 		printk(KERN_CONT "ZARLINK456 ");
-	 if (type & CHINA)
+	if (type & CHINA)
 		printk(KERN_CONT "CHINA ");
-	 if (type & F6MHZ)
+	if (type & F6MHZ)
 		printk(KERN_CONT "F6MHZ ");
-	 if (type & INPUT2)
+	if (type & INPUT2)
 		printk(KERN_CONT "INPUT2 ");
-	 if (type & SCODE)
+	if (type & SCODE)
 		printk(KERN_CONT "SCODE ");
-	 if (type & HAS_IF)
+	if (type & HAS_IF)
 		printk(KERN_CONT "HAS_IF_%d ", int_freq);
 }
 
diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c
index e135760..e44c8ab 100644
--- a/drivers/media/tuners/xc5000.c
+++ b/drivers/media/tuners/xc5000.c
@@ -59,6 +59,7 @@
 	u32 freq_hz, freq_offset;
 	u32 bandwidth;
 	u8  video_standard;
+	unsigned int mode;
 	u8  rf_mode;
 	u8  radio_input;
 
@@ -69,6 +70,8 @@
 
 	struct dvb_frontend *fe;
 	struct delayed_work timer_sleep;
+
+	const struct firmware   *firmware;
 };
 
 /* Misc Defines */
@@ -712,9 +715,50 @@
 	}
 }
 
-static int xc5000_set_params(struct dvb_frontend *fe)
+static int xc5000_tune_digital(struct dvb_frontend *fe)
 {
-	int ret, b;
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+	u32 bw = fe->dtv_property_cache.bandwidth_hz;
+
+	ret = xc_set_signal_source(priv, priv->rf_mode);
+	if (ret != 0) {
+		printk(KERN_ERR
+			"xc5000: xc_set_signal_source(%d) failed\n",
+			priv->rf_mode);
+		return -EREMOTEIO;
+	}
+
+	ret = xc_set_tv_standard(priv,
+		xc5000_standard[priv->video_standard].video_mode,
+		xc5000_standard[priv->video_standard].audio_mode, 0);
+	if (ret != 0) {
+		printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n");
+		return -EREMOTEIO;
+	}
+
+	ret = xc_set_IF_frequency(priv, priv->if_khz);
+	if (ret != 0) {
+		printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
+		       priv->if_khz);
+		return -EIO;
+	}
+
+	xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a);
+
+	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	priv->bandwidth = bw;
+
+	return 0;
+}
+
+static int xc5000_set_digital_params(struct dvb_frontend *fe)
+{
+	int b;
 	struct xc5000_priv *priv = fe->tuner_priv;
 	u32 bw = fe->dtv_property_cache.bandwidth_hz;
 	u32 freq = fe->dtv_property_cache.frequency;
@@ -794,43 +838,12 @@
 	}
 
 	priv->freq_hz = freq - priv->freq_offset;
+	priv->mode = V4L2_TUNER_DIGITAL_TV;
 
 	dprintk(1, "%s() frequency=%d (compensated to %d)\n",
 		__func__, freq, priv->freq_hz);
 
-	ret = xc_set_signal_source(priv, priv->rf_mode);
-	if (ret != 0) {
-		printk(KERN_ERR
-			"xc5000: xc_set_signal_source(%d) failed\n",
-			priv->rf_mode);
-		return -EREMOTEIO;
-	}
-
-	ret = xc_set_tv_standard(priv,
-		xc5000_standard[priv->video_standard].video_mode,
-		xc5000_standard[priv->video_standard].audio_mode, 0);
-	if (ret != 0) {
-		printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n");
-		return -EREMOTEIO;
-	}
-
-	ret = xc_set_IF_frequency(priv, priv->if_khz);
-	if (ret != 0) {
-		printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
-		       priv->if_khz);
-		return -EIO;
-	}
-
-	xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a);
-
-	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
-
-	if (debug)
-		xc_debug_dump(priv);
-
-	priv->bandwidth = bw;
-
-	return 0;
+	return xc5000_tune_digital(fe);
 }
 
 static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
@@ -852,12 +865,10 @@
 	return ret;
 }
 
-static int xc5000_set_tv_freq(struct dvb_frontend *fe,
-	struct analog_parameters *params)
+static void xc5000_config_tv(struct dvb_frontend *fe,
+			     struct analog_parameters *params)
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
-	u16 pll_lock_status;
-	int ret;
 
 	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
 		__func__, params->frequency);
@@ -876,42 +887,49 @@
 	if (params->std & V4L2_STD_MN) {
 		/* default to BTSC audio standard */
 		priv->video_standard = MN_NTSC_PAL_BTSC;
-		goto tune_channel;
+		return;
 	}
 
 	if (params->std & V4L2_STD_PAL_BG) {
 		/* default to NICAM audio standard */
 		priv->video_standard = BG_PAL_NICAM;
-		goto tune_channel;
+		return;
 	}
 
 	if (params->std & V4L2_STD_PAL_I) {
 		/* default to NICAM audio standard */
 		priv->video_standard = I_PAL_NICAM;
-		goto tune_channel;
+		return;
 	}
 
 	if (params->std & V4L2_STD_PAL_DK) {
 		/* default to NICAM audio standard */
 		priv->video_standard = DK_PAL_NICAM;
-		goto tune_channel;
+		return;
 	}
 
 	if (params->std & V4L2_STD_SECAM_DK) {
 		/* default to A2 DK1 audio standard */
 		priv->video_standard = DK_SECAM_A2DK1;
-		goto tune_channel;
+		return;
 	}
 
 	if (params->std & V4L2_STD_SECAM_L) {
 		priv->video_standard = L_SECAM_NICAM;
-		goto tune_channel;
+		return;
 	}
 
 	if (params->std & V4L2_STD_SECAM_LC) {
 		priv->video_standard = LC_SECAM_NICAM;
-		goto tune_channel;
+		return;
 	}
+}
+
+static int xc5000_set_tv_freq(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	u16 pll_lock_status;
+	int ret;
 
 tune_channel:
 	ret = xc_set_signal_source(priv, priv->rf_mode);
@@ -955,12 +973,11 @@
 	return 0;
 }
 
-static int xc5000_set_radio_freq(struct dvb_frontend *fe,
-	struct analog_parameters *params)
+static int xc5000_config_radio(struct dvb_frontend *fe,
+			       struct analog_parameters *params)
+
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
-	int ret = -EINVAL;
-	u8 radio_input;
 
 	dprintk(1, "%s() frequency=%d (in units of khz)\n",
 		__func__, params->frequency);
@@ -970,6 +987,18 @@
 		return -EINVAL;
 	}
 
+	priv->freq_hz = params->frequency * 125 / 2;
+	priv->rf_mode = XC_RF_MODE_AIR;
+
+	return 0;
+}
+
+static int xc5000_set_radio_freq(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+	u8 radio_input;
+
 	if (priv->radio_input == XC5000_RADIO_FM1)
 		radio_input = FM_RADIO_INPUT1;
 	else if  (priv->radio_input == XC5000_RADIO_FM2)
@@ -982,10 +1011,6 @@
 		return -EINVAL;
 	}
 
-	priv->freq_hz = params->frequency * 125 / 2;
-
-	priv->rf_mode = XC_RF_MODE_AIR;
-
 	ret = xc_set_tv_standard(priv, xc5000_standard[radio_input].video_mode,
 			       xc5000_standard[radio_input].audio_mode, radio_input);
 
@@ -1013,33 +1038,52 @@
 	return 0;
 }
 
-static int xc5000_set_analog_params(struct dvb_frontend *fe,
-			     struct analog_parameters *params)
+static int xc5000_set_params(struct dvb_frontend *fe)
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
-	int ret = -EINVAL;
-
-	if (priv->i2c_props.adap == NULL)
-		return -EINVAL;
 
 	if (xc_load_fw_and_init_tuner(fe, 0) != 0) {
 		dprintk(1, "Unable to load firmware and init tuner\n");
 		return -EINVAL;
 	}
 
-	switch (params->mode) {
+	switch (priv->mode) {
 	case V4L2_TUNER_RADIO:
-		ret = xc5000_set_radio_freq(fe, params);
-		break;
+		return xc5000_set_radio_freq(fe);
 	case V4L2_TUNER_ANALOG_TV:
+		return xc5000_set_tv_freq(fe);
 	case V4L2_TUNER_DIGITAL_TV:
-		ret = xc5000_set_tv_freq(fe, params);
-		break;
+		return xc5000_tune_digital(fe);
 	}
 
-	return ret;
+	return 0;
 }
 
+static int xc5000_set_analog_params(struct dvb_frontend *fe,
+			     struct analog_parameters *params)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	if (priv->i2c_props.adap == NULL)
+		return -EINVAL;
+
+	switch (params->mode) {
+	case V4L2_TUNER_RADIO:
+		ret = xc5000_config_radio(fe, params);
+		if (ret)
+			return ret;
+		break;
+	case V4L2_TUNER_ANALOG_TV:
+		xc5000_config_tv(fe, params);
+		break;
+	default:
+		break;
+	}
+	priv->mode = params->mode;
+
+	return xc5000_set_params(fe);
+}
 
 static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
 {
@@ -1094,20 +1138,23 @@
 	if (!force && xc5000_is_firmware_loaded(fe) == 0)
 		return 0;
 
-	ret = request_firmware(&fw, desired_fw->name,
-			       priv->i2c_props.adap->dev.parent);
-	if (ret) {
-		printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
-		return ret;
-	}
+	if (!priv->firmware) {
+		ret = request_firmware(&fw, desired_fw->name,
+					priv->i2c_props.adap->dev.parent);
+		if (ret) {
+			pr_err("xc5000: Upload failed. rc %d\n", ret);
+			return ret;
+		}
+		dprintk(1, "firmware read %Zu bytes.\n", fw->size);
 
-	dprintk(1, "firmware read %Zu bytes.\n", fw->size);
-
-	if (fw->size != desired_fw->size) {
-		printk(KERN_ERR "xc5000: Firmware file with incorrect size\n");
-		ret = -EINVAL;
-		goto err;
-	}
+		if (fw->size != desired_fw->size) {
+			pr_err("xc5000: Firmware file with incorrect size\n");
+			release_firmware(fw);
+			return -EINVAL;
+		}
+		priv->firmware = fw;
+	} else
+		fw = priv->firmware;
 
 	/* Try up to 5 times to load firmware */
 	for (i = 0; i < 5; i++) {
@@ -1190,7 +1237,6 @@
 	else
 		printk(KERN_CONT " - too many retries. Giving up\n");
 
-	release_firmware(fw);
 	return ret;
 }
 
@@ -1229,6 +1275,38 @@
 	return 0;
 }
 
+static int xc5000_suspend(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk(1, "%s()\n", __func__);
+
+	cancel_delayed_work(&priv->timer_sleep);
+
+	ret = xc5000_tuner_reset(fe);
+	if (ret != 0)
+		printk(KERN_ERR
+			"xc5000: %s() unable to shutdown tuner\n",
+			__func__);
+
+	return 0;
+}
+
+static int xc5000_resume(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* suspended before firmware is loaded.
+	   Avoid firmware load in resume path. */
+	if (!priv->firmware)
+		return 0;
+
+	return xc5000_set_params(fe);
+}
+
 static int xc5000_init(struct dvb_frontend *fe)
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
@@ -1256,6 +1334,8 @@
 	if (priv) {
 		cancel_delayed_work(&priv->timer_sleep);
 		hybrid_tuner_release_state(priv);
+		if (priv->firmware)
+			release_firmware(priv->firmware);
 	}
 
 	mutex_unlock(&xc5000_list_mutex);
@@ -1293,9 +1373,11 @@
 	.release	   = xc5000_release,
 	.init		   = xc5000_init,
 	.sleep		   = xc5000_sleep,
+	.suspend	   = xc5000_suspend,
+	.resume		   = xc5000_resume,
 
 	.set_config	   = xc5000_set_config,
-	.set_params	   = xc5000_set_params,
+	.set_params	   = xc5000_set_digital_params,
 	.set_analog_params = xc5000_set_analog_params,
 	.get_frequency	   = xc5000_get_frequency,
 	.get_if_frequency  = xc5000_get_if_frequency,
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig
index 94d51e0..056181f 100644
--- a/drivers/media/usb/Kconfig
+++ b/drivers/media/usb/Kconfig
@@ -46,6 +46,7 @@
 source "drivers/media/usb/ttusb-dec/Kconfig"
 source "drivers/media/usb/siano/Kconfig"
 source "drivers/media/usb/b2c2/Kconfig"
+source "drivers/media/usb/as102/Kconfig"
 endif
 
 if (MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT)
@@ -55,8 +56,9 @@
 
 if MEDIA_SDR_SUPPORT
 	comment "Software defined radio USB devices"
-source "drivers/media/usb/msi2500/Kconfig"
 source "drivers/media/usb/airspy/Kconfig"
+source "drivers/media/usb/hackrf/Kconfig"
+source "drivers/media/usb/msi2500/Kconfig"
 endif
 
 endif #MEDIA_USB_SUPPORT
diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile
index ac10cf0..417760e 100644
--- a/drivers/media/usb/Makefile
+++ b/drivers/media/usb/Makefile
@@ -9,8 +9,9 @@
 obj-$(CPTCFG_USB_VIDEO_CLASS)	+= uvc/
 obj-$(CPTCFG_USB_GSPCA)         += gspca/
 obj-$(CPTCFG_USB_PWC)           += pwc/
-obj-$(CPTCFG_USB_MSI2500)       += msi2500/
 obj-$(CPTCFG_USB_AIRSPY)        += airspy/
+obj-$(CPTCFG_USB_HACKRF)        += hackrf/
+obj-$(CPTCFG_USB_MSI2500)       += msi2500/
 obj-$(CPTCFG_VIDEO_CPIA2) += cpia2/
 obj-$(CPTCFG_VIDEO_AU0828) += au0828/
 obj-$(CPTCFG_VIDEO_HDPVR)	+= hdpvr/
@@ -23,3 +24,4 @@
 obj-$(CPTCFG_VIDEO_EM28XX) += em28xx/
 obj-$(CPTCFG_VIDEO_USBTV) += usbtv/
 obj-$(CPTCFG_VIDEO_GO7007) += go7007/
+obj-$(CPTCFG_DVB_AS102) += as102/
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index ce15fe5..7ae8d41 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -108,6 +108,7 @@
 #define USB_STATE_URB_BUF  (1 << 3)
 	unsigned long flags;
 
+	struct device *dev;
 	struct usb_device *udev;
 	struct video_device vdev;
 	struct v4l2_device v4l2_dev;
@@ -155,16 +156,15 @@
 	unsigned int sample_measured;
 };
 
-#define airspy_dbg_usb_control_msg(_udev, _r, _t, _v, _i, _b, _l) { \
+#define airspy_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \
 	char *_direction; \
 	if (_t & USB_DIR_IN) \
 		_direction = "<<<"; \
 	else \
 		_direction = ">>>"; \
-	dev_dbg(&_udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \
-			"%s %*ph\n",  __func__, _t, _r, _v & 0xff, _v >> 8, \
-			_i & 0xff, _i >> 8, _l & 0xff, _l >> 8, _direction, \
-			_l, _b); \
+	dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \
+			_t, _r, _v & 0xff, _v >> 8, _i & 0xff, _i >> 8, \
+			_l & 0xff, _l >> 8, _direction, _l, _b); \
 }
 
 /* execute firmware command */
@@ -193,7 +193,7 @@
 		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
 		break;
 	default:
-		dev_err(&s->udev->dev, "Unknown command %02x\n", request);
+		dev_err(s->dev, "Unknown command %02x\n", request);
 		ret = -EINVAL;
 		goto err;
 	}
@@ -204,11 +204,10 @@
 
 	ret = usb_control_msg(s->udev, pipe, request, requesttype, value,
 			index, s->buf, size, 1000);
-	airspy_dbg_usb_control_msg(s->udev, request, requesttype, value,
+	airspy_dbg_usb_control_msg(s->dev, request, requesttype, value,
 			index, s->buf, size);
 	if (ret < 0) {
-		dev_err(&s->udev->dev,
-				"usb_control_msg() failed %d request %02x\n",
+		dev_err(s->dev, "usb_control_msg() failed %d request %02x\n",
 				ret, request);
 		goto err;
 	}
@@ -225,7 +224,7 @@
 /* Private functions */
 static struct airspy_frame_buf *airspy_get_next_fill_buf(struct airspy *s)
 {
-	unsigned long flags = 0;
+	unsigned long flags;
 	struct airspy_frame_buf *buf = NULL;
 
 	spin_lock_irqsave(&s->queued_bufs_lock, flags);
@@ -252,16 +251,18 @@
 		dst_len = 0;
 	}
 
-	/* calculate samping rate and output it in 10 seconds intervals */
+	/* calculate sample rate and output it in 10 seconds intervals */
 	if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
 		#define MSECS 10000UL
+		unsigned int msecs = jiffies_to_msecs(jiffies -
+				s->jiffies_next + msecs_to_jiffies(MSECS));
 		unsigned int samples = s->sample - s->sample_measured;
+
 		s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
 		s->sample_measured = s->sample;
-		dev_dbg(&s->udev->dev,
-				"slen=%d samples=%u msecs=%lu sample rate=%lu\n",
-				src_len, samples, MSECS,
-				samples * 1000UL / MSECS);
+		dev_dbg(s->dev, "slen=%u samples=%u msecs=%u sample rate=%lu\n",
+				src_len, samples, msecs,
+				samples * 1000UL / msecs);
 	}
 
 	/* total number of samples */
@@ -279,9 +280,8 @@
 	struct airspy *s = urb->context;
 	struct airspy_frame_buf *fbuf;
 
-	dev_dbg_ratelimited(&s->udev->dev,
-			"%s: status=%d length=%d/%d errors=%d\n",
-			__func__, urb->status, urb->actual_length,
+	dev_dbg_ratelimited(s->dev, "status=%d length=%d/%d errors=%d\n",
+			urb->status, urb->actual_length,
 			urb->transfer_buffer_length, urb->error_count);
 
 	switch (urb->status) {
@@ -293,8 +293,7 @@
 	case -ESHUTDOWN:
 		return;
 	default:            /* error */
-		dev_err_ratelimited(&s->udev->dev, "URB failed %d\n",
-				urb->status);
+		dev_err_ratelimited(s->dev, "URB failed %d\n", urb->status);
 		break;
 	}
 
@@ -305,7 +304,7 @@
 		fbuf = airspy_get_next_fill_buf(s);
 		if (unlikely(fbuf == NULL)) {
 			s->vb_full++;
-			dev_notice_ratelimited(&s->udev->dev,
+			dev_notice_ratelimited(s->dev,
 					"videobuf is full, %d packets dropped\n",
 					s->vb_full);
 			goto skip;
@@ -329,7 +328,7 @@
 	int i;
 
 	for (i = s->urbs_submitted - 1; i >= 0; i--) {
-		dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i);
+		dev_dbg(s->dev, "kill urb=%d\n", i);
 		/* stop the URB */
 		usb_kill_urb(s->urb_list[i]);
 	}
@@ -343,11 +342,10 @@
 	int i, ret;
 
 	for (i = 0; i < s->urbs_initialized; i++) {
-		dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i);
+		dev_dbg(s->dev, "submit urb=%d\n", i);
 		ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC);
 		if (ret) {
-			dev_err(&s->udev->dev,
-					"Could not submit URB no. %d - get them all back\n",
+			dev_err(s->dev, "Could not submit URB no. %d - get them all back\n",
 					i);
 			airspy_kill_urbs(s);
 			return ret;
@@ -363,8 +361,7 @@
 	if (s->flags & USB_STATE_URB_BUF) {
 		while (s->buf_num) {
 			s->buf_num--;
-			dev_dbg(&s->udev->dev, "%s: free buf=%d\n",
-					__func__, s->buf_num);
+			dev_dbg(s->dev, "free buf=%d\n", s->buf_num);
 			usb_free_coherent(s->udev, s->buf_size,
 					  s->buf_list[s->buf_num],
 					  s->dma_addr[s->buf_num]);
@@ -380,23 +377,20 @@
 	s->buf_num = 0;
 	s->buf_size = BULK_BUFFER_SIZE;
 
-	dev_dbg(&s->udev->dev,
-			"%s: all in all I will use %u bytes for streaming\n",
-			__func__,  MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+	dev_dbg(s->dev, "all in all I will use %u bytes for streaming\n",
+			MAX_BULK_BUFS * BULK_BUFFER_SIZE);
 
 	for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) {
 		s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev,
 				BULK_BUFFER_SIZE, GFP_ATOMIC,
 				&s->dma_addr[s->buf_num]);
 		if (!s->buf_list[s->buf_num]) {
-			dev_dbg(&s->udev->dev, "%s: alloc buf=%d failed\n",
-					__func__, s->buf_num);
+			dev_dbg(s->dev, "alloc buf=%d failed\n", s->buf_num);
 			airspy_free_stream_bufs(s);
 			return -ENOMEM;
 		}
 
-		dev_dbg(&s->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
-				__func__, s->buf_num,
+		dev_dbg(s->dev, "alloc buf=%d %p (dma %llu)\n", s->buf_num,
 				s->buf_list[s->buf_num],
 				(long long)s->dma_addr[s->buf_num]);
 		s->flags |= USB_STATE_URB_BUF;
@@ -413,8 +407,7 @@
 
 	for (i = s->urbs_initialized - 1; i >= 0; i--) {
 		if (s->urb_list[i]) {
-			dev_dbg(&s->udev->dev, "%s: free urb=%d\n",
-					__func__, i);
+			dev_dbg(s->dev, "free urb=%d\n", i);
 			/* free the URBs */
 			usb_free_urb(s->urb_list[i]);
 		}
@@ -430,10 +423,10 @@
 
 	/* allocate the URBs */
 	for (i = 0; i < MAX_BULK_BUFS; i++) {
-		dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+		dev_dbg(s->dev, "alloc urb=%d\n", i);
 		s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
 		if (!s->urb_list[i]) {
-			dev_dbg(&s->udev->dev, "%s: failed\n", __func__);
+			dev_dbg(s->dev, "failed\n");
 			for (j = 0; j < i; j++)
 				usb_free_urb(s->urb_list[j]);
 			return -ENOMEM;
@@ -456,13 +449,14 @@
 /* Must be called with vb_queue_lock hold */
 static void airspy_cleanup_queued_bufs(struct airspy *s)
 {
-	unsigned long flags = 0;
+	unsigned long flags;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	spin_lock_irqsave(&s->queued_bufs_lock, flags);
 	while (!list_empty(&s->queued_bufs)) {
 		struct airspy_frame_buf *buf;
+
 		buf = list_entry(s->queued_bufs.next,
 				struct airspy_frame_buf, list);
 		list_del(&buf->list);
@@ -477,7 +471,7 @@
 	struct v4l2_device *v = usb_get_intfdata(intf);
 	struct airspy *s = container_of(v, struct airspy, v4l2_dev);
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	mutex_lock(&s->vb_queue_lock);
 	mutex_lock(&s->v4l2_lock);
@@ -498,7 +492,7 @@
 {
 	struct airspy *s = vb2_get_drv_priv(vq);
 
-	dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
+	dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers);
 
 	/* Need at least 8 buffers */
 	if (vq->num_buffers + *nbuffers < 8)
@@ -506,8 +500,7 @@
 	*nplanes = 1;
 	sizes[0] = PAGE_ALIGN(s->buffersize);
 
-	dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
-			__func__, *nbuffers, sizes[0]);
+	dev_dbg(s->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
 	return 0;
 }
 
@@ -516,7 +509,7 @@
 	struct airspy *s = vb2_get_drv_priv(vb->vb2_queue);
 	struct airspy_frame_buf *buf =
 			container_of(vb, struct airspy_frame_buf, vb);
-	unsigned long flags = 0;
+	unsigned long flags;
 
 	/* Check the device has not disconnected between prep and queuing */
 	if (unlikely(!s->udev)) {
@@ -534,34 +527,56 @@
 	struct airspy *s = vb2_get_drv_priv(vq);
 	int ret;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	if (!s->udev)
 		return -ENODEV;
 
 	mutex_lock(&s->v4l2_lock);
 
-	set_bit(POWER_ON, &s->flags);
-
 	s->sequence = 0;
 
+	set_bit(POWER_ON, &s->flags);
+
 	ret = airspy_alloc_stream_bufs(s);
 	if (ret)
-		goto err;
+		goto err_clear_bit;
 
 	ret = airspy_alloc_urbs(s);
 	if (ret)
-		goto err;
+		goto err_free_stream_bufs;
 
 	ret = airspy_submit_urbs(s);
 	if (ret)
-		goto err;
+		goto err_free_urbs;
 
 	/* start hardware streaming */
 	ret = airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 1, 0, NULL, 0);
 	if (ret)
-		goto err;
-err:
+		goto err_kill_urbs;
+
+	goto exit_mutex_unlock;
+
+err_kill_urbs:
+	airspy_kill_urbs(s);
+err_free_urbs:
+	airspy_free_urbs(s);
+err_free_stream_bufs:
+	airspy_free_stream_bufs(s);
+err_clear_bit:
+	clear_bit(POWER_ON, &s->flags);
+
+	/* return all queued buffers to vb2 */
+	{
+		struct airspy_frame_buf *buf, *tmp;
+
+		list_for_each_entry_safe(buf, tmp, &s->queued_bufs, list) {
+			list_del(&buf->list);
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+		}
+	}
+
+exit_mutex_unlock:
 	mutex_unlock(&s->v4l2_lock);
 
 	return ret;
@@ -571,7 +586,7 @@
 {
 	struct airspy *s = vb2_get_drv_priv(vq);
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	mutex_lock(&s->v4l2_lock);
 
@@ -603,8 +618,6 @@
 {
 	struct airspy *s = video_drvdata(file);
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
-
 	strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
 	strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
 	usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info));
@@ -618,10 +631,6 @@
 static int airspy_enum_fmt_sdr_cap(struct file *file, void *priv,
 		struct v4l2_fmtdesc *f)
 {
-	struct airspy *s = video_drvdata(file);
-
-	dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, f->index);
-
 	if (f->index >= NUM_FORMATS)
 		return -EINVAL;
 
@@ -636,9 +645,6 @@
 {
 	struct airspy *s = video_drvdata(file);
 
-	dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
-			(char *)&s->pixelformat);
-
 	f->fmt.sdr.pixelformat = s->pixelformat;
 	f->fmt.sdr.buffersize = s->buffersize;
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
@@ -653,9 +659,6 @@
 	struct vb2_queue *q = &s->vb_queue;
 	int i;
 
-	dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
-			(char *)&f->fmt.sdr.pixelformat);
-
 	if (vb2_is_busy(q))
 		return -EBUSY;
 
@@ -680,12 +683,8 @@
 static int airspy_try_fmt_sdr_cap(struct file *file, void *priv,
 		struct v4l2_format *f)
 {
-	struct airspy *s = video_drvdata(file);
 	int i;
 
-	dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
-			(char *)&f->fmt.sdr.pixelformat);
-
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
 	for (i = 0; i < NUM_FORMATS; i++) {
 		if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
@@ -703,11 +702,8 @@
 static int airspy_s_tuner(struct file *file, void *priv,
 		const struct v4l2_tuner *v)
 {
-	struct airspy *s = video_drvdata(file);
 	int ret;
 
-	dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
-
 	if (v->index == 0)
 		ret = 0;
 	else if (v->index == 1)
@@ -720,11 +716,8 @@
 
 static int airspy_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
 {
-	struct airspy *s = video_drvdata(file);
 	int ret;
 
-	dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
-
 	if (v->index == 0) {
 		strlcpy(v->name, "AirSpy ADC", sizeof(v->name));
 		v->type = V4L2_TUNER_ADC;
@@ -750,17 +743,18 @@
 		struct v4l2_frequency *f)
 {
 	struct airspy *s = video_drvdata(file);
-	int ret  = 0;
-	dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
-			__func__, f->tuner, f->type);
+	int ret;
 
 	if (f->tuner == 0) {
 		f->type = V4L2_TUNER_ADC;
 		f->frequency = s->f_adc;
+		dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc);
 		ret = 0;
 	} else if (f->tuner == 1) {
 		f->type = V4L2_TUNER_RF;
 		f->frequency = s->f_rf;
+		dev_dbg(s->dev, "RF frequency=%u Hz\n", s->f_rf);
+		ret = 0;
 	} else {
 		ret = -EINVAL;
 	}
@@ -775,22 +769,17 @@
 	int ret;
 	u8 buf[4];
 
-	dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
-			__func__, f->tuner, f->type, f->frequency);
-
 	if (f->tuner == 0) {
 		s->f_adc = clamp_t(unsigned int, f->frequency,
 				bands[0].rangelow,
 				bands[0].rangehigh);
-		dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
-				__func__, s->f_adc);
+		dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc);
 		ret = 0;
 	} else if (f->tuner == 1) {
 		s->f_rf = clamp_t(unsigned int, f->frequency,
 				bands_rf[0].rangelow,
 				bands_rf[0].rangehigh);
-		dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n",
-				__func__, s->f_rf);
+		dev_dbg(s->dev, "RF frequency=%u Hz\n", s->f_rf);
 		buf[0] = (s->f_rf >>  0) & 0xff;
 		buf[1] = (s->f_rf >>  8) & 0xff;
 		buf[2] = (s->f_rf >> 16) & 0xff;
@@ -806,10 +795,7 @@
 static int airspy_enum_freq_bands(struct file *file, void *priv,
 		struct v4l2_frequency_band *band)
 {
-	struct airspy *s = video_drvdata(file);
 	int ret;
-	dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
-			__func__, band->tuner, band->type, band->index);
 
 	if (band->tuner == 0) {
 		if (band->index >= ARRAY_SIZE(bands)) {
@@ -893,10 +879,9 @@
 	int ret;
 	u8 u8tmp;
 
-	dev_dbg(&s->udev->dev, "%s: lna auto=%d->%d val=%d->%d\n",
-			__func__, s->lna_gain_auto->cur.val,
-			s->lna_gain_auto->val, s->lna_gain->cur.val,
-			s->lna_gain->val);
+	dev_dbg(s->dev, "lna auto=%d->%d val=%d->%d\n",
+			s->lna_gain_auto->cur.val, s->lna_gain_auto->val,
+			s->lna_gain->cur.val, s->lna_gain->val);
 
 	ret = airspy_ctrl_msg(s, CMD_SET_LNA_AGC, 0, s->lna_gain_auto->val,
 			&u8tmp, 1);
@@ -911,7 +896,7 @@
 	}
 err:
 	if (ret)
-		dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(s->dev, "failed=%d\n", ret);
 
 	return ret;
 }
@@ -921,10 +906,9 @@
 	int ret;
 	u8 u8tmp;
 
-	dev_dbg(&s->udev->dev, "%s: mixer auto=%d->%d val=%d->%d\n",
-			__func__, s->mixer_gain_auto->cur.val,
-			s->mixer_gain_auto->val, s->mixer_gain->cur.val,
-			s->mixer_gain->val);
+	dev_dbg(s->dev, "mixer auto=%d->%d val=%d->%d\n",
+			s->mixer_gain_auto->cur.val, s->mixer_gain_auto->val,
+			s->mixer_gain->cur.val, s->mixer_gain->val);
 
 	ret = airspy_ctrl_msg(s, CMD_SET_MIXER_AGC, 0, s->mixer_gain_auto->val,
 			&u8tmp, 1);
@@ -939,7 +923,7 @@
 	}
 err:
 	if (ret)
-		dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(s->dev, "failed=%d\n", ret);
 
 	return ret;
 }
@@ -949,8 +933,7 @@
 	int ret;
 	u8 u8tmp;
 
-	dev_dbg(&s->udev->dev, "%s: val=%d->%d\n",
-			__func__, s->if_gain->cur.val, s->if_gain->val);
+	dev_dbg(s->dev, "val=%d->%d\n", s->if_gain->cur.val, s->if_gain->val);
 
 	ret = airspy_ctrl_msg(s, CMD_SET_VGA_GAIN, 0, s->if_gain->val,
 			&u8tmp, 1);
@@ -958,7 +941,7 @@
 		goto err;
 err:
 	if (ret)
-		dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret);
+		dev_dbg(s->dev, "failed=%d\n", ret);
 
 	return ret;
 }
@@ -981,8 +964,8 @@
 		ret = airspy_set_if_gain(s);
 		break;
 	default:
-		dev_dbg(&s->udev->dev, "%s: unknown ctrl: id=%d name=%s\n",
-				__func__, ctrl->id, ctrl->name);
+		dev_dbg(s->dev, "unknown ctrl: id=%d name=%s\n",
+				ctrl->id, ctrl->name);
 		ret = -EINVAL;
 	}
 
@@ -996,15 +979,13 @@
 static int airspy_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct airspy *s = NULL;
+	struct airspy *s;
 	int ret;
 	u8 u8tmp, buf[BUF_SIZE];
 
 	s = kzalloc(sizeof(struct airspy), GFP_KERNEL);
 	if (s == NULL) {
-		dev_err(&udev->dev,
-				"Could not allocate memory for airspy state\n");
+		dev_err(&intf->dev, "Could not allocate memory for state\n");
 		return -ENOMEM;
 	}
 
@@ -1012,7 +993,8 @@
 	mutex_init(&s->vb_queue_lock);
 	spin_lock_init(&s->queued_bufs_lock);
 	INIT_LIST_HEAD(&s->queued_bufs);
-	s->udev = udev;
+	s->dev = &intf->dev;
+	s->udev = interface_to_usbdev(intf);
 	s->f_adc = bands[0].rangelow;
 	s->f_rf = bands_rf[0].rangelow;
 	s->pixelformat = formats[0].pixelformat;
@@ -1024,14 +1006,14 @@
 		ret = airspy_ctrl_msg(s, CMD_VERSION_STRING_READ, 0, 0,
 				buf, BUF_SIZE);
 	if (ret) {
-		dev_err(&s->udev->dev, "Could not detect board\n");
+		dev_err(s->dev, "Could not detect board\n");
 		goto err_free_mem;
 	}
 
 	buf[BUF_SIZE - 1] = '\0';
 
-	dev_info(&s->udev->dev, "Board ID: %02x\n", u8tmp);
-	dev_info(&s->udev->dev, "Firmware version: %s\n", buf);
+	dev_info(s->dev, "Board ID: %02x\n", u8tmp);
+	dev_info(s->dev, "Firmware version: %s\n", buf);
 
 	/* Init videobuf2 queue structure */
 	s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
@@ -1043,7 +1025,7 @@
 	s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
 	ret = vb2_queue_init(&s->vb_queue);
 	if (ret) {
-		dev_err(&s->udev->dev, "Could not initialize vb2 queue\n");
+		dev_err(s->dev, "Could not initialize vb2 queue\n");
 		goto err_free_mem;
 	}
 
@@ -1057,8 +1039,7 @@
 	s->v4l2_dev.release = airspy_video_release;
 	ret = v4l2_device_register(&intf->dev, &s->v4l2_dev);
 	if (ret) {
-		dev_err(&s->udev->dev,
-				"Failed to register v4l2-device (%d)\n", ret);
+		dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret);
 		goto err_free_mem;
 	}
 
@@ -1078,7 +1059,7 @@
 			V4L2_CID_RF_TUNER_IF_GAIN, 0, 15, 1, 0);
 	if (s->hdl.error) {
 		ret = s->hdl.error;
-		dev_err(&s->udev->dev, "Could not initialize controls\n");
+		dev_err(s->dev, "Could not initialize controls\n");
 		goto err_free_controls;
 	}
 
@@ -1090,16 +1071,13 @@
 
 	ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
 	if (ret) {
-		dev_err(&s->udev->dev,
-				"Failed to register as video device (%d)\n",
+		dev_err(s->dev, "Failed to register as video device (%d)\n",
 				ret);
 		goto err_unregister_v4l2_dev;
 	}
-	dev_info(&s->udev->dev, "Registered as %s\n",
+	dev_info(s->dev, "Registered as %s\n",
 			video_device_node_name(&s->vdev));
-	dev_notice(&s->udev->dev,
-			"%s: SDR API is still slightly experimental and functionality changes may follow\n",
-			KBUILD_MODNAME);
+	dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
 	return 0;
 
 err_free_controls:
diff --git a/drivers/media/usb/as102/Kconfig b/drivers/media/usb/as102/Kconfig
new file mode 100644
index 0000000..93bab6b
--- /dev/null
+++ b/drivers/media/usb/as102/Kconfig
@@ -0,0 +1,9 @@
+config DVB_AS102
+	tristate "Abilis AS102 DVB receiver"
+	depends on m
+	depends on DVB_CORE && USB && I2C && INPUT
+	depends on FW_LOADER
+	help
+	  Choose Y or M here if you have a device containing an AS102
+
+	  To compile this driver as a module, choose M here
diff --git a/drivers/media/usb/as102/Makefile b/drivers/media/usb/as102/Makefile
new file mode 100644
index 0000000..287af8f
--- /dev/null
+++ b/drivers/media/usb/as102/Makefile
@@ -0,0 +1,7 @@
+dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \
+		  as102_usb_drv.o as10x_cmd_cfg.o
+
+obj-$(CPTCFG_DVB_AS102) += dvb-as102.o
+
+ccflags-y += -I$(backport_srctree)/drivers/media/dvb-core
+ccflags-y += -I$(backport_srctree)/drivers/media/dvb-frontends
diff --git a/drivers/media/usb/as102/as102_drv.c b/drivers/media/usb/as102/as102_drv.c
new file mode 100644
index 0000000..8be1474
--- /dev/null
+++ b/drivers/media/usb/as102/as102_drv.c
@@ -0,0 +1,401 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/kref.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+/* header file for usb device driver*/
+#include "as102_drv.h"
+#include "as10x_cmd.h"
+#include "as102_fe.h"
+#include "as102_fw.h"
+#include "dvbdev.h"
+
+int dual_tuner;
+module_param_named(dual_tuner, dual_tuner, int, 0644);
+MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)");
+
+static int fw_upload = 1;
+module_param_named(fw_upload, fw_upload, int, 0644);
+MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)");
+
+static int pid_filtering;
+module_param_named(pid_filtering, pid_filtering, int, 0644);
+MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)");
+
+static int ts_auto_disable;
+module_param_named(ts_auto_disable, ts_auto_disable, int, 0644);
+MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)");
+
+int elna_enable = 1;
+module_param_named(elna_enable, elna_enable, int, 0644);
+MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static void as102_stop_stream(struct as102_dev_t *dev)
+{
+	struct as10x_bus_adapter_t *bus_adap;
+
+	if (dev != NULL)
+		bus_adap = &dev->bus_adap;
+	else
+		return;
+
+	if (bus_adap->ops->stop_stream != NULL)
+		bus_adap->ops->stop_stream(dev);
+
+	if (ts_auto_disable) {
+		if (mutex_lock_interruptible(&dev->bus_adap.lock))
+			return;
+
+		if (as10x_cmd_stop_streaming(bus_adap) < 0)
+			dev_dbg(&dev->bus_adap.usb_dev->dev,
+				"as10x_cmd_stop_streaming failed\n");
+
+		mutex_unlock(&dev->bus_adap.lock);
+	}
+}
+
+static int as102_start_stream(struct as102_dev_t *dev)
+{
+	struct as10x_bus_adapter_t *bus_adap;
+	int ret = -EFAULT;
+
+	if (dev != NULL)
+		bus_adap = &dev->bus_adap;
+	else
+		return ret;
+
+	if (bus_adap->ops->start_stream != NULL)
+		ret = bus_adap->ops->start_stream(dev);
+
+	if (ts_auto_disable) {
+		if (mutex_lock_interruptible(&dev->bus_adap.lock))
+			return -EFAULT;
+
+		ret = as10x_cmd_start_streaming(bus_adap);
+
+		mutex_unlock(&dev->bus_adap.lock);
+	}
+
+	return ret;
+}
+
+static int as10x_pid_filter(struct as102_dev_t *dev,
+			    int index, u16 pid, int onoff) {
+
+	struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap;
+	int ret = -EFAULT;
+
+	if (mutex_lock_interruptible(&dev->bus_adap.lock)) {
+		dev_dbg(&dev->bus_adap.usb_dev->dev,
+			"amutex_lock_interruptible(lock) failed !\n");
+		return -EBUSY;
+	}
+
+	switch (onoff) {
+	case 0:
+		ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid);
+		dev_dbg(&dev->bus_adap.usb_dev->dev,
+			"DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n",
+			index, pid, ret);
+		break;
+	case 1:
+	{
+		struct as10x_ts_filter filter;
+
+		filter.type = TS_PID_TYPE_TS;
+		filter.idx = 0xFF;
+		filter.pid = pid;
+
+		ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
+		dev_dbg(&dev->bus_adap.usb_dev->dev,
+			"ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
+			index, filter.idx, filter.pid, ret);
+		break;
+	}
+	}
+
+	mutex_unlock(&dev->bus_adap.lock);
+	return ret;
+}
+
+static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	int ret = 0;
+	struct dvb_demux *demux = dvbdmxfeed->demux;
+	struct as102_dev_t *as102_dev = demux->priv;
+
+	if (mutex_lock_interruptible(&as102_dev->sem))
+		return -ERESTARTSYS;
+
+	if (pid_filtering)
+		as10x_pid_filter(as102_dev, dvbdmxfeed->index,
+				 dvbdmxfeed->pid, 1);
+
+	if (as102_dev->streaming++ == 0)
+		ret = as102_start_stream(as102_dev);
+
+	mutex_unlock(&as102_dev->sem);
+	return ret;
+}
+
+static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *demux = dvbdmxfeed->demux;
+	struct as102_dev_t *as102_dev = demux->priv;
+
+	if (mutex_lock_interruptible(&as102_dev->sem))
+		return -ERESTARTSYS;
+
+	if (--as102_dev->streaming == 0)
+		as102_stop_stream(as102_dev);
+
+	if (pid_filtering)
+		as10x_pid_filter(as102_dev, dvbdmxfeed->index,
+				 dvbdmxfeed->pid, 0);
+
+	mutex_unlock(&as102_dev->sem);
+	return 0;
+}
+
+static int as102_set_tune(void *priv, struct as10x_tune_args *tune_args)
+{
+	struct as10x_bus_adapter_t *bus_adap = priv;
+	int ret;
+
+	/* Set frontend arguments */
+	if (mutex_lock_interruptible(&bus_adap->lock))
+		return -EBUSY;
+
+	ret =  as10x_cmd_set_tune(bus_adap, tune_args);
+	if (ret != 0)
+		dev_dbg(&bus_adap->usb_dev->dev,
+			"as10x_cmd_set_tune failed. (err = %d)\n", ret);
+
+	mutex_unlock(&bus_adap->lock);
+
+	return ret;
+}
+
+static int as102_get_tps(void *priv, struct as10x_tps *tps)
+{
+	struct as10x_bus_adapter_t *bus_adap = priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&bus_adap->lock))
+		return -EBUSY;
+
+	/* send abilis command: GET_TPS */
+	ret = as10x_cmd_get_tps(bus_adap, tps);
+
+	mutex_unlock(&bus_adap->lock);
+
+	return ret;
+}
+
+static int as102_get_status(void *priv, struct as10x_tune_status *tstate)
+{
+	struct as10x_bus_adapter_t *bus_adap = priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&bus_adap->lock))
+		return -EBUSY;
+
+	/* send abilis command: GET_TUNE_STATUS */
+	ret = as10x_cmd_get_tune_status(bus_adap, tstate);
+	if (ret < 0) {
+		dev_dbg(&bus_adap->usb_dev->dev,
+			"as10x_cmd_get_tune_status failed (err = %d)\n",
+			ret);
+	}
+
+	mutex_unlock(&bus_adap->lock);
+
+	return ret;
+}
+
+static int as102_get_stats(void *priv, struct as10x_demod_stats *demod_stats)
+{
+	struct as10x_bus_adapter_t *bus_adap = priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&bus_adap->lock))
+		return -EBUSY;
+
+	/* send abilis command: GET_TUNE_STATUS */
+	ret = as10x_cmd_get_demod_stats(bus_adap, demod_stats);
+	if (ret < 0) {
+		dev_dbg(&bus_adap->usb_dev->dev,
+			"as10x_cmd_get_demod_stats failed (probably not tuned)\n");
+	} else {
+		dev_dbg(&bus_adap->usb_dev->dev,
+			"demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n",
+			demod_stats->frame_count,
+			demod_stats->bad_frame_count,
+			demod_stats->bytes_fixed_by_rs,
+			demod_stats->mer);
+	}
+	mutex_unlock(&bus_adap->lock);
+
+	return ret;
+}
+
+static int as102_stream_ctrl(void *priv, int acquire, uint32_t elna_cfg)
+{
+	struct as10x_bus_adapter_t *bus_adap = priv;
+	int ret;
+
+	if (mutex_lock_interruptible(&bus_adap->lock))
+		return -EBUSY;
+
+	if (acquire) {
+		if (elna_enable)
+			as10x_cmd_set_context(bus_adap,
+					      CONTEXT_LNA, elna_cfg);
+
+		ret = as10x_cmd_turn_on(bus_adap);
+	} else {
+		ret = as10x_cmd_turn_off(bus_adap);
+	}
+
+	mutex_unlock(&bus_adap->lock);
+
+	return ret;
+}
+
+static const struct as102_fe_ops as102_fe_ops = {
+	.set_tune = as102_set_tune,
+	.get_tps  = as102_get_tps,
+	.get_status = as102_get_status,
+	.get_stats = as102_get_stats,
+	.stream_ctrl = as102_stream_ctrl,
+};
+
+int as102_dvb_register(struct as102_dev_t *as102_dev)
+{
+	struct device *dev = &as102_dev->bus_adap.usb_dev->dev;
+	int ret;
+
+	ret = dvb_register_adapter(&as102_dev->dvb_adap,
+			   as102_dev->name, THIS_MODULE,
+			   dev, adapter_nr);
+	if (ret < 0) {
+		dev_err(dev, "%s: dvb_register_adapter() failed: %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	as102_dev->dvb_dmx.priv = as102_dev;
+	as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256;
+	as102_dev->dvb_dmx.feednum = 256;
+	as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed;
+	as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed;
+
+	as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING |
+					      DMX_SECTION_FILTERING;
+
+	as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum;
+	as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx;
+	as102_dev->dvb_dmxdev.capabilities = 0;
+
+	ret = dvb_dmx_init(&as102_dev->dvb_dmx);
+	if (ret < 0) {
+		dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret);
+		goto edmxinit;
+	}
+
+	ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap);
+	if (ret < 0) {
+		dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n",
+			__func__, ret);
+		goto edmxdinit;
+	}
+
+	/* Attach the frontend */
+	as102_dev->dvb_fe = dvb_attach(as102_attach, as102_dev->name,
+				       &as102_fe_ops,
+				       &as102_dev->bus_adap,
+				       as102_dev->elna_cfg);
+	if (!as102_dev->dvb_fe) {
+		dev_err(dev, "%s: as102_attach() failed: %d",
+		    __func__, ret);
+		goto efereg;
+	}
+
+	ret =  dvb_register_frontend(&as102_dev->dvb_adap, as102_dev->dvb_fe);
+	if (ret < 0) {
+		dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d",
+		    __func__, ret);
+		goto efereg;
+	}
+
+	/* init bus mutex for token locking */
+	mutex_init(&as102_dev->bus_adap.lock);
+
+	/* init start / stop stream mutex */
+	mutex_init(&as102_dev->sem);
+
+	/*
+	 * try to load as102 firmware. If firmware upload failed, we'll be
+	 * able to upload it later.
+	 */
+	if (fw_upload)
+		try_then_request_module(as102_fw_upload(&as102_dev->bus_adap),
+				"firmware_class");
+
+	pr_info("Registered device %s", as102_dev->name);
+	return 0;
+
+efereg:
+	dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
+edmxdinit:
+	dvb_dmx_release(&as102_dev->dvb_dmx);
+edmxinit:
+	dvb_unregister_adapter(&as102_dev->dvb_adap);
+	return ret;
+}
+
+void as102_dvb_unregister(struct as102_dev_t *as102_dev)
+{
+	/* unregister as102 frontend */
+	dvb_unregister_frontend(as102_dev->dvb_fe);
+
+	/* detach frontend */
+	dvb_frontend_detach(as102_dev->dvb_fe);
+
+	/* unregister demux device */
+	dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
+	dvb_dmx_release(&as102_dev->dvb_dmx);
+
+	/* unregister dvb adapter */
+	dvb_unregister_adapter(&as102_dev->dvb_adap);
+
+	pr_info("Unregistered device %s", as102_dev->name);
+}
+
+module_usb_driver(as102_usb_driver);
+
+/* modinfo details */
+MODULE_DESCRIPTION(DRIVER_FULL_NAME);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
diff --git a/drivers/media/usb/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h
new file mode 100644
index 0000000..aee2d76
--- /dev/null
+++ b/drivers/media/usb/as102/as102_drv.h
@@ -0,0 +1,83 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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.
+ */
+
+#ifndef _AS102_DRV_H
+#define _AS102_DRV_H
+#include <linux/usb.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
+#include <dmxdev.h>
+#include "as10x_handle.h"
+#include "as10x_cmd.h"
+#include "as102_usb_drv.h"
+
+#define DRIVER_FULL_NAME "Abilis Systems as10x usb driver"
+#define DRIVER_NAME "as10x_usb"
+
+#define debug	as102_debug
+extern struct usb_driver as102_usb_driver;
+extern int elna_enable;
+
+#define AS102_DEVICE_MAJOR	192
+
+#define AS102_USB_BUF_SIZE	512
+#define MAX_STREAM_URB		32
+
+struct as10x_bus_adapter_t {
+	struct usb_device *usb_dev;
+	/* bus token lock */
+	struct mutex lock;
+	/* low level interface for bus adapter */
+	union as10x_bus_token_t {
+		/* usb token */
+		struct as10x_usb_token_cmd_t usb;
+	} token;
+
+	/* token cmd xfer id */
+	uint16_t cmd_xid;
+
+	/* as10x command and response for dvb interface*/
+	struct as10x_cmd_t *cmd, *rsp;
+
+	/* bus adapter private ops callback */
+	struct as102_priv_ops_t *ops;
+};
+
+struct as102_dev_t {
+	const char *name;
+	struct as10x_bus_adapter_t bus_adap;
+	struct list_head device_entry;
+	struct kref kref;
+	uint8_t elna_cfg;
+
+	struct dvb_adapter dvb_adap;
+	struct dvb_frontend *dvb_fe;
+	struct dvb_demux dvb_dmx;
+	struct dmxdev dvb_dmxdev;
+
+	/* timer handle to trig ts stream download */
+	struct timer_list timer_handle;
+
+	struct mutex sem;
+	dma_addr_t dma_addr;
+	void *stream;
+	int streaming;
+	struct urb *stream_urb[MAX_STREAM_URB];
+};
+
+int as102_dvb_register(struct as102_dev_t *dev);
+void as102_dvb_unregister(struct as102_dev_t *dev);
+
+#endif
diff --git a/drivers/media/usb/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c
new file mode 100644
index 0000000..07d08c4
--- /dev/null
+++ b/drivers/media/usb/as102/as102_fw.c
@@ -0,0 +1,228 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+
+#include "as102_drv.h"
+#include "as102_fw.h"
+
+static const char as102_st_fw1[] = "as102_data1_st.hex";
+static const char as102_st_fw2[] = "as102_data2_st.hex";
+static const char as102_dt_fw1[] = "as102_data1_dt.hex";
+static const char as102_dt_fw2[] = "as102_data2_dt.hex";
+
+static unsigned char atohx(unsigned char *dst, char *src)
+{
+	unsigned char value = 0;
+
+	char msb = tolower(*src) - '0';
+	char lsb = tolower(*(src + 1)) - '0';
+
+	if (msb > 9)
+		msb -= 7;
+	if (lsb > 9)
+		lsb -= 7;
+
+	*dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
+	return value;
+}
+
+/*
+ * Parse INTEL HEX firmware file to extract address and data.
+ */
+static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
+			  unsigned char *data, int *dataLength,
+			  unsigned char *addr_has_changed) {
+
+	int count = 0;
+	unsigned char *src, dst;
+
+	if (*fw_data++ != ':') {
+		pr_err("invalid firmware file\n");
+		return -EFAULT;
+	}
+
+	/* locate end of line */
+	for (src = fw_data; *src != '\n'; src += 2) {
+		atohx(&dst, src);
+		/* parse line to split addr / data */
+		switch (count) {
+		case 0:
+			*dataLength = dst;
+			break;
+		case 1:
+			addr[2] = dst;
+			break;
+		case 2:
+			addr[3] = dst;
+			break;
+		case 3:
+			/* check if data is an address */
+			if (dst == 0x04)
+				*addr_has_changed = 1;
+			else
+				*addr_has_changed = 0;
+			break;
+		case  4:
+		case  5:
+			if (*addr_has_changed)
+				addr[(count - 4)] = dst;
+			else
+				data[(count - 4)] = dst;
+			break;
+		default:
+			data[(count - 4)] = dst;
+			break;
+		}
+		count++;
+	}
+
+	/* return read value + ':' + '\n' */
+	return (count * 2) + 2;
+}
+
+static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
+				 unsigned char *cmd,
+				 const struct firmware *firmware) {
+
+	struct as10x_fw_pkt_t fw_pkt;
+	int total_read_bytes = 0, errno = 0;
+	unsigned char addr_has_changed = 0;
+
+	for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
+		int read_bytes = 0, data_len = 0;
+
+		/* parse intel hex line */
+		read_bytes = parse_hex_line(
+				(u8 *) (firmware->data + total_read_bytes),
+				fw_pkt.raw.address,
+				fw_pkt.raw.data,
+				&data_len,
+				&addr_has_changed);
+
+		if (read_bytes <= 0)
+			goto error;
+
+		/* detect the end of file */
+		total_read_bytes += read_bytes;
+		if (total_read_bytes == firmware->size) {
+			fw_pkt.u.request[0] = 0x00;
+			fw_pkt.u.request[1] = 0x03;
+
+			/* send EOF command */
+			errno = bus_adap->ops->upload_fw_pkt(bus_adap,
+							     (uint8_t *)
+							     &fw_pkt, 2, 0);
+			if (errno < 0)
+				goto error;
+		} else {
+			if (!addr_has_changed) {
+				/* prepare command to send */
+				fw_pkt.u.request[0] = 0x00;
+				fw_pkt.u.request[1] = 0x01;
+
+				data_len += sizeof(fw_pkt.u.request);
+				data_len += sizeof(fw_pkt.raw.address);
+
+				/* send cmd to device */
+				errno = bus_adap->ops->upload_fw_pkt(bus_adap,
+								     (uint8_t *)
+								     &fw_pkt,
+								     data_len,
+								     0);
+				if (errno < 0)
+					goto error;
+			}
+		}
+	}
+error:
+	return (errno == 0) ? total_read_bytes : errno;
+}
+
+int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
+{
+	int errno = -EFAULT;
+	const struct firmware *firmware = NULL;
+	unsigned char *cmd_buf = NULL;
+	const char *fw1, *fw2;
+	struct usb_device *dev = bus_adap->usb_dev;
+
+	/* select fw file to upload */
+	if (dual_tuner) {
+		fw1 = as102_dt_fw1;
+		fw2 = as102_dt_fw2;
+	} else {
+		fw1 = as102_st_fw1;
+		fw2 = as102_st_fw2;
+	}
+
+	/* allocate buffer to store firmware upload command and data */
+	cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
+	if (cmd_buf == NULL) {
+		errno = -ENOMEM;
+		goto error;
+	}
+
+	/* request kernel to locate firmware file: part1 */
+	errno = request_firmware(&firmware, fw1, &dev->dev);
+	if (errno < 0) {
+		pr_err("%s: unable to locate firmware file: %s\n",
+		       DRIVER_NAME, fw1);
+		goto error;
+	}
+
+	/* initiate firmware upload */
+	errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
+	if (errno < 0) {
+		pr_err("%s: error during firmware upload part1\n",
+		       DRIVER_NAME);
+		goto error;
+	}
+
+	pr_info("%s: firmware: %s loaded with success\n",
+		DRIVER_NAME, fw1);
+	release_firmware(firmware);
+
+	/* wait for boot to complete */
+	mdelay(100);
+
+	/* request kernel to locate firmware file: part2 */
+	errno = request_firmware(&firmware, fw2, &dev->dev);
+	if (errno < 0) {
+		pr_err("%s: unable to locate firmware file: %s\n",
+		       DRIVER_NAME, fw2);
+		goto error;
+	}
+
+	/* initiate firmware upload */
+	errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
+	if (errno < 0) {
+		pr_err("%s: error during firmware upload part2\n",
+		       DRIVER_NAME);
+		goto error;
+	}
+
+	pr_info("%s: firmware: %s loaded with success\n",
+		DRIVER_NAME, fw2);
+error:
+	kfree(cmd_buf);
+	release_firmware(firmware);
+
+	return errno;
+}
diff --git a/drivers/media/usb/as102/as102_fw.h b/drivers/media/usb/as102/as102_fw.h
new file mode 100644
index 0000000..2732b78
--- /dev/null
+++ b/drivers/media/usb/as102/as102_fw.h
@@ -0,0 +1,34 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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.
+ */
+#define MAX_FW_PKT_SIZE	64
+
+extern int dual_tuner;
+
+struct as10x_raw_fw_pkt {
+	unsigned char address[4];
+	unsigned char data[MAX_FW_PKT_SIZE - 6];
+} __packed;
+
+struct as10x_fw_pkt_t {
+	union {
+		unsigned char request[2];
+		unsigned char length[2];
+	} __packed u;
+	struct as10x_raw_fw_pkt raw;
+} __packed;
+
+#ifdef __KERNEL__
+int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap);
+#endif
diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c
new file mode 100644
index 0000000..3f66906
--- /dev/null
+++ b/drivers/media/usb/as102/as102_usb_drv.c
@@ -0,0 +1,475 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+
+#include "as102_drv.h"
+#include "as102_usb_drv.h"
+#include "as102_fw.h"
+
+static void as102_usb_disconnect(struct usb_interface *interface);
+static int as102_usb_probe(struct usb_interface *interface,
+			   const struct usb_device_id *id);
+
+static int as102_usb_start_stream(struct as102_dev_t *dev);
+static void as102_usb_stop_stream(struct as102_dev_t *dev);
+
+static int as102_open(struct inode *inode, struct file *file);
+static int as102_release(struct inode *inode, struct file *file);
+
+static struct usb_device_id as102_usb_id_table[] = {
+	{ USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) },
+	{ USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) },
+	{ USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) },
+	{ USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) },
+	{ USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) },
+	{ } /* Terminating entry */
+};
+
+/* Note that this table must always have the same number of entries as the
+   as102_usb_id_table struct */
+static const char * const as102_device_names[] = {
+	AS102_REFERENCE_DESIGN,
+	AS102_PCTV_74E,
+	AS102_ELGATO_EYETV_DTT_NAME,
+	AS102_NBOX_DVBT_DONGLE_NAME,
+	AS102_SKY_IT_DIGITAL_KEY_NAME,
+	NULL /* Terminating entry */
+};
+
+/* eLNA configuration: devices built on the reference design work best
+   with 0xA0, while custom designs seem to require 0xC0 */
+static uint8_t const as102_elna_cfg[] = {
+	0xA0,
+	0xC0,
+	0xC0,
+	0xA0,
+	0xA0,
+	0x00 /* Terminating entry */
+};
+
+struct usb_driver as102_usb_driver = {
+	.name		= DRIVER_FULL_NAME,
+	.probe		= as102_usb_probe,
+	.disconnect	= as102_usb_disconnect,
+	.id_table	= as102_usb_id_table
+};
+
+static const struct file_operations as102_dev_fops = {
+	.owner		= THIS_MODULE,
+	.open		= as102_open,
+	.release	= as102_release,
+};
+
+static struct usb_class_driver as102_usb_class_driver = {
+	.name		= "aton2-%d",
+	.fops		= &as102_dev_fops,
+	.minor_base	= AS102_DEVICE_MAJOR,
+};
+
+static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap,
+			      unsigned char *send_buf, int send_buf_len,
+			      unsigned char *recv_buf, int recv_buf_len)
+{
+	int ret = 0;
+
+	if (send_buf != NULL) {
+		ret = usb_control_msg(bus_adap->usb_dev,
+				      usb_sndctrlpipe(bus_adap->usb_dev, 0),
+				      AS102_USB_DEVICE_TX_CTRL_CMD,
+				      USB_DIR_OUT | USB_TYPE_VENDOR |
+				      USB_RECIP_DEVICE,
+				      bus_adap->cmd_xid, /* value */
+				      0, /* index */
+				      send_buf, send_buf_len,
+				      USB_CTRL_SET_TIMEOUT /* 200 */);
+		if (ret < 0) {
+			dev_dbg(&bus_adap->usb_dev->dev,
+				"usb_control_msg(send) failed, err %i\n", ret);
+			return ret;
+		}
+
+		if (ret != send_buf_len) {
+			dev_dbg(&bus_adap->usb_dev->dev,
+			"only wrote %d of %d bytes\n", ret, send_buf_len);
+			return -1;
+		}
+	}
+
+	if (recv_buf != NULL) {
+#ifdef TRACE
+		dev_dbg(bus_adap->usb_dev->dev,
+			"want to read: %d bytes\n", recv_buf_len);
+#endif
+		ret = usb_control_msg(bus_adap->usb_dev,
+				      usb_rcvctrlpipe(bus_adap->usb_dev, 0),
+				      AS102_USB_DEVICE_RX_CTRL_CMD,
+				      USB_DIR_IN | USB_TYPE_VENDOR |
+				      USB_RECIP_DEVICE,
+				      bus_adap->cmd_xid, /* value */
+				      0, /* index */
+				      recv_buf, recv_buf_len,
+				      USB_CTRL_GET_TIMEOUT /* 200 */);
+		if (ret < 0) {
+			dev_dbg(&bus_adap->usb_dev->dev,
+				"usb_control_msg(recv) failed, err %i\n", ret);
+			return ret;
+		}
+#ifdef TRACE
+		dev_dbg(bus_adap->usb_dev->dev,
+			"read %d bytes\n", recv_buf_len);
+#endif
+	}
+
+	return ret;
+}
+
+static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap,
+			  unsigned char *send_buf,
+			  int send_buf_len,
+			  int swap32)
+{
+	int ret, actual_len;
+
+	ret = usb_bulk_msg(bus_adap->usb_dev,
+			   usb_sndbulkpipe(bus_adap->usb_dev, 1),
+			   send_buf, send_buf_len, &actual_len, 200);
+	if (ret) {
+		dev_dbg(&bus_adap->usb_dev->dev,
+			"usb_bulk_msg(send) failed, err %i\n", ret);
+		return ret;
+	}
+
+	if (actual_len != send_buf_len) {
+		dev_dbg(&bus_adap->usb_dev->dev, "only wrote %d of %d bytes\n",
+			actual_len, send_buf_len);
+		return -1;
+	}
+	return actual_len;
+}
+
+static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap,
+		   unsigned char *recv_buf, int recv_buf_len)
+{
+	int ret, actual_len;
+
+	if (recv_buf == NULL)
+		return -EINVAL;
+
+	ret = usb_bulk_msg(bus_adap->usb_dev,
+			   usb_rcvbulkpipe(bus_adap->usb_dev, 2),
+			   recv_buf, recv_buf_len, &actual_len, 200);
+	if (ret) {
+		dev_dbg(&bus_adap->usb_dev->dev,
+			"usb_bulk_msg(recv) failed, err %i\n", ret);
+		return ret;
+	}
+
+	if (actual_len != recv_buf_len) {
+		dev_dbg(&bus_adap->usb_dev->dev, "only read %d of %d bytes\n",
+			actual_len, recv_buf_len);
+		return -1;
+	}
+	return actual_len;
+}
+
+static struct as102_priv_ops_t as102_priv_ops = {
+	.upload_fw_pkt	= as102_send_ep1,
+	.xfer_cmd	= as102_usb_xfer_cmd,
+	.as102_read_ep2	= as102_read_ep2,
+	.start_stream	= as102_usb_start_stream,
+	.stop_stream	= as102_usb_stop_stream,
+};
+
+static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb)
+{
+	int err;
+
+	usb_fill_bulk_urb(urb,
+			  dev->bus_adap.usb_dev,
+			  usb_rcvbulkpipe(dev->bus_adap.usb_dev, 0x2),
+			  urb->transfer_buffer,
+			  AS102_USB_BUF_SIZE,
+			  as102_urb_stream_irq,
+			  dev);
+
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err)
+		dev_dbg(&urb->dev->dev,
+			"%s: usb_submit_urb failed\n", __func__);
+
+	return err;
+}
+
+void as102_urb_stream_irq(struct urb *urb)
+{
+	struct as102_dev_t *as102_dev = urb->context;
+
+	if (urb->actual_length > 0) {
+		dvb_dmx_swfilter(&as102_dev->dvb_dmx,
+				 urb->transfer_buffer,
+				 urb->actual_length);
+	} else {
+		if (urb->actual_length == 0)
+			memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE);
+	}
+
+	/* is not stopped, re-submit urb */
+	if (as102_dev->streaming)
+		as102_submit_urb_stream(as102_dev, urb);
+}
+
+static void as102_free_usb_stream_buffer(struct as102_dev_t *dev)
+{
+	int i;
+
+	for (i = 0; i < MAX_STREAM_URB; i++)
+		usb_free_urb(dev->stream_urb[i]);
+
+	usb_free_coherent(dev->bus_adap.usb_dev,
+			MAX_STREAM_URB * AS102_USB_BUF_SIZE,
+			dev->stream,
+			dev->dma_addr);
+}
+
+static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev)
+{
+	int i;
+
+	dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev,
+				       MAX_STREAM_URB * AS102_USB_BUF_SIZE,
+				       GFP_KERNEL,
+				       &dev->dma_addr);
+	if (!dev->stream) {
+		dev_dbg(&dev->bus_adap.usb_dev->dev,
+			"%s: usb_buffer_alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	memset(dev->stream, 0, MAX_STREAM_URB * AS102_USB_BUF_SIZE);
+
+	/* init urb buffers */
+	for (i = 0; i < MAX_STREAM_URB; i++) {
+		struct urb *urb;
+
+		urb = usb_alloc_urb(0, GFP_ATOMIC);
+		if (urb == NULL) {
+			dev_dbg(&dev->bus_adap.usb_dev->dev,
+				"%s: usb_alloc_urb failed\n", __func__);
+			as102_free_usb_stream_buffer(dev);
+			return -ENOMEM;
+		}
+
+		urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE);
+		urb->transfer_dma = dev->dma_addr + (i * AS102_USB_BUF_SIZE);
+		urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+		urb->transfer_buffer_length = AS102_USB_BUF_SIZE;
+
+		dev->stream_urb[i] = urb;
+	}
+	return 0;
+}
+
+static void as102_usb_stop_stream(struct as102_dev_t *dev)
+{
+	int i;
+
+	for (i = 0; i < MAX_STREAM_URB; i++)
+		usb_kill_urb(dev->stream_urb[i]);
+}
+
+static int as102_usb_start_stream(struct as102_dev_t *dev)
+{
+	int i, ret = 0;
+
+	for (i = 0; i < MAX_STREAM_URB; i++) {
+		ret = as102_submit_urb_stream(dev, dev->stream_urb[i]);
+		if (ret) {
+			as102_usb_stop_stream(dev);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void as102_usb_release(struct kref *kref)
+{
+	struct as102_dev_t *as102_dev;
+
+	as102_dev = container_of(kref, struct as102_dev_t, kref);
+	if (as102_dev != NULL) {
+		usb_put_dev(as102_dev->bus_adap.usb_dev);
+		kfree(as102_dev);
+	}
+}
+
+static void as102_usb_disconnect(struct usb_interface *intf)
+{
+	struct as102_dev_t *as102_dev;
+
+	/* extract as102_dev_t from usb_device private data */
+	as102_dev = usb_get_intfdata(intf);
+
+	/* unregister dvb layer */
+	as102_dvb_unregister(as102_dev);
+
+	/* free usb buffers */
+	as102_free_usb_stream_buffer(as102_dev);
+
+	usb_set_intfdata(intf, NULL);
+
+	/* usb unregister device */
+	usb_deregister_dev(intf, &as102_usb_class_driver);
+
+	/* decrement usage counter */
+	kref_put(&as102_dev->kref, as102_usb_release);
+
+	pr_info("%s: device has been disconnected\n", DRIVER_NAME);
+}
+
+static int as102_usb_probe(struct usb_interface *intf,
+			   const struct usb_device_id *id)
+{
+	int ret;
+	struct as102_dev_t *as102_dev;
+	int i;
+
+	/* This should never actually happen */
+	if (ARRAY_SIZE(as102_usb_id_table) !=
+	    (sizeof(as102_device_names) / sizeof(const char *))) {
+		pr_err("Device names table invalid size");
+		return -EINVAL;
+	}
+
+	as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL);
+	if (as102_dev == NULL)
+		return -ENOMEM;
+
+	/* Assign the user-friendly device name */
+	for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) {
+		if (id == &as102_usb_id_table[i]) {
+			as102_dev->name = as102_device_names[i];
+			as102_dev->elna_cfg = as102_elna_cfg[i];
+		}
+	}
+
+	if (as102_dev->name == NULL)
+		as102_dev->name = "Unknown AS102 device";
+
+	/* set private callback functions */
+	as102_dev->bus_adap.ops = &as102_priv_ops;
+
+	/* init cmd token for usb bus */
+	as102_dev->bus_adap.cmd = &as102_dev->bus_adap.token.usb.c;
+	as102_dev->bus_adap.rsp = &as102_dev->bus_adap.token.usb.r;
+
+	/* init kernel device reference */
+	kref_init(&as102_dev->kref);
+
+	/* store as102 device to usb_device private data */
+	usb_set_intfdata(intf, (void *) as102_dev);
+
+	/* store in as102 device the usb_device pointer */
+	as102_dev->bus_adap.usb_dev = usb_get_dev(interface_to_usbdev(intf));
+
+	/* we can register the device now, as it is ready */
+	ret = usb_register_dev(intf, &as102_usb_class_driver);
+	if (ret < 0) {
+		/* something prevented us from registering this driver */
+		dev_err(&intf->dev,
+			"%s: usb_register_dev() failed (errno = %d)\n",
+			__func__, ret);
+		goto failed;
+	}
+
+	pr_info("%s: device has been detected\n", DRIVER_NAME);
+
+	/* request buffer allocation for streaming */
+	ret = as102_alloc_usb_stream_buffer(as102_dev);
+	if (ret != 0)
+		goto failed_stream;
+
+	/* register dvb layer */
+	ret = as102_dvb_register(as102_dev);
+	if (ret != 0)
+		goto failed_dvb;
+
+	return ret;
+
+failed_dvb:
+	as102_free_usb_stream_buffer(as102_dev);
+failed_stream:
+	usb_deregister_dev(intf, &as102_usb_class_driver);
+failed:
+	usb_put_dev(as102_dev->bus_adap.usb_dev);
+	usb_set_intfdata(intf, NULL);
+	kfree(as102_dev);
+	return ret;
+}
+
+static int as102_open(struct inode *inode, struct file *file)
+{
+	int ret = 0, minor = 0;
+	struct usb_interface *intf = NULL;
+	struct as102_dev_t *dev = NULL;
+
+	/* read minor from inode */
+	minor = iminor(inode);
+
+	/* fetch device from usb interface */
+	intf = usb_find_interface(&as102_usb_driver, minor);
+	if (intf == NULL) {
+		pr_err("%s: can't find device for minor %d\n",
+		       __func__, minor);
+		ret = -ENODEV;
+		goto exit;
+	}
+
+	/* get our device */
+	dev = usb_get_intfdata(intf);
+	if (dev == NULL) {
+		ret = -EFAULT;
+		goto exit;
+	}
+
+	/* save our device object in the file's private structure */
+	file->private_data = dev;
+
+	/* increment our usage count for the device */
+	kref_get(&dev->kref);
+
+exit:
+	return ret;
+}
+
+static int as102_release(struct inode *inode, struct file *file)
+{
+	struct as102_dev_t *dev = NULL;
+
+	dev = file->private_data;
+	if (dev != NULL) {
+		/* decrement the count on our device */
+		kref_put(&dev->kref, as102_usb_release);
+	}
+
+	return 0;
+}
+
+MODULE_DEVICE_TABLE(usb, as102_usb_id_table);
diff --git a/drivers/media/usb/as102/as102_usb_drv.h b/drivers/media/usb/as102/as102_usb_drv.h
new file mode 100644
index 0000000..4fb1baa
--- /dev/null
+++ b/drivers/media/usb/as102/as102_usb_drv.h
@@ -0,0 +1,57 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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.
+ */
+#ifndef _AS102_USB_DRV_H_
+#define _AS102_USB_DRV_H_
+
+#define AS102_USB_DEVICE_TX_CTRL_CMD	0xF1
+#define AS102_USB_DEVICE_RX_CTRL_CMD	0xF2
+
+/* define these values to match the supported devices */
+
+/* Abilis system: "TITAN" */
+#define AS102_REFERENCE_DESIGN		"Abilis Systems DVB-Titan"
+#define AS102_USB_DEVICE_VENDOR_ID	0x1BA6
+#define AS102_USB_DEVICE_PID_0001	0x0001
+
+/* PCTV Systems: PCTV picoStick (74e) */
+#define AS102_PCTV_74E			"PCTV Systems picoStick (74e)"
+#define PCTV_74E_USB_VID		0x2013
+#define PCTV_74E_USB_PID		0x0246
+
+/* Elgato: EyeTV DTT Deluxe */
+#define AS102_ELGATO_EYETV_DTT_NAME	"Elgato EyeTV DTT Deluxe"
+#define ELGATO_EYETV_DTT_USB_VID	0x0fd9
+#define ELGATO_EYETV_DTT_USB_PID	0x002c
+
+/* nBox: nBox DVB-T Dongle */
+#define AS102_NBOX_DVBT_DONGLE_NAME	"nBox DVB-T Dongle"
+#define NBOX_DVBT_DONGLE_USB_VID	0x0b89
+#define NBOX_DVBT_DONGLE_USB_PID	0x0007
+
+/* Sky Italia: Digital Key (green led) */
+#define AS102_SKY_IT_DIGITAL_KEY_NAME	"Sky IT Digital Key (green led)"
+#define SKY_IT_DIGITAL_KEY_USB_VID	0x2137
+#define SKY_IT_DIGITAL_KEY_USB_PID	0x0001
+
+void as102_urb_stream_irq(struct urb *urb);
+
+struct as10x_usb_token_cmd_t {
+	/* token cmd */
+	struct as10x_cmd_t c;
+	/* token response */
+	struct as10x_cmd_t r;
+};
+#endif
diff --git a/drivers/media/usb/as102/as10x_cmd.c b/drivers/media/usb/as102/as10x_cmd.c
new file mode 100644
index 0000000..8706179
--- /dev/null
+++ b/drivers/media/usb/as102/as10x_cmd.c
@@ -0,0 +1,413 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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/kernel.h>
+#include "as102_drv.h"
+#include "as10x_cmd.h"
+
+/**
+ * as10x_cmd_turn_on - send turn on command to AS10x
+ * @adap:   pointer to AS10x bus adapter
+ *
+ * Return 0 when no error, < 0 in case of error.
+ */
+int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap)
+{
+	int error = AS10X_CMD_ERROR;
+	struct as10x_cmd_t *pcmd, *prsp;
+
+	pcmd = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(pcmd, (++adap->cmd_xid),
+			sizeof(pcmd->body.turn_on.req));
+
+	/* fill command */
+	pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON);
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+					    sizeof(pcmd->body.turn_on.req) +
+					    HEADER_SIZE,
+					    (uint8_t *) prsp,
+					    sizeof(prsp->body.turn_on.rsp) +
+					    HEADER_SIZE);
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response */
+	error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP);
+
+out:
+	return error;
+}
+
+/**
+ * as10x_cmd_turn_off - send turn off command to AS10x
+ * @adap:   pointer to AS10x bus adapter
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap)
+{
+	int error = AS10X_CMD_ERROR;
+	struct as10x_cmd_t *pcmd, *prsp;
+
+	pcmd = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(pcmd, (++adap->cmd_xid),
+			sizeof(pcmd->body.turn_off.req));
+
+	/* fill command */
+	pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF);
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error = adap->ops->xfer_cmd(
+			adap, (uint8_t *) pcmd,
+			sizeof(pcmd->body.turn_off.req) + HEADER_SIZE,
+			(uint8_t *) prsp,
+			sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE);
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response */
+	error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP);
+
+out:
+	return error;
+}
+
+/**
+ * as10x_cmd_set_tune - send set tune command to AS10x
+ * @adap:    pointer to AS10x bus adapter
+ * @ptune:   tune parameters
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
+		       struct as10x_tune_args *ptune)
+{
+	int error = AS10X_CMD_ERROR;
+	struct as10x_cmd_t *preq, *prsp;
+
+	preq = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(preq, (++adap->cmd_xid),
+			sizeof(preq->body.set_tune.req));
+
+	/* fill command */
+	preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE);
+	preq->body.set_tune.req.args.freq = (__force __u32)cpu_to_le32(ptune->freq);
+	preq->body.set_tune.req.args.bandwidth = ptune->bandwidth;
+	preq->body.set_tune.req.args.hier_select = ptune->hier_select;
+	preq->body.set_tune.req.args.modulation = ptune->modulation;
+	preq->body.set_tune.req.args.hierarchy = ptune->hierarchy;
+	preq->body.set_tune.req.args.interleaving_mode  =
+		ptune->interleaving_mode;
+	preq->body.set_tune.req.args.code_rate  = ptune->code_rate;
+	preq->body.set_tune.req.args.guard_interval = ptune->guard_interval;
+	preq->body.set_tune.req.args.transmission_mode  =
+		ptune->transmission_mode;
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error = adap->ops->xfer_cmd(adap,
+					    (uint8_t *) preq,
+					    sizeof(preq->body.set_tune.req)
+					    + HEADER_SIZE,
+					    (uint8_t *) prsp,
+					    sizeof(prsp->body.set_tune.rsp)
+					    + HEADER_SIZE);
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response */
+	error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP);
+
+out:
+	return error;
+}
+
+/**
+ * as10x_cmd_get_tune_status - send get tune status command to AS10x
+ * @adap: pointer to AS10x bus adapter
+ * @pstatus: pointer to updated status structure of the current tune
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
+			      struct as10x_tune_status *pstatus)
+{
+	int error = AS10X_CMD_ERROR;
+	struct as10x_cmd_t  *preq, *prsp;
+
+	preq = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(preq, (++adap->cmd_xid),
+			sizeof(preq->body.get_tune_status.req));
+
+	/* fill command */
+	preq->body.get_tune_status.req.proc_id =
+		cpu_to_le16(CONTROL_PROC_GETTUNESTAT);
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error = adap->ops->xfer_cmd(
+			adap,
+			(uint8_t *) preq,
+			sizeof(preq->body.get_tune_status.req) + HEADER_SIZE,
+			(uint8_t *) prsp,
+			sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE);
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response */
+	error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTUNESTAT_RSP);
+	if (error < 0)
+		goto out;
+
+	/* Response OK -> get response data */
+	pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state;
+	pstatus->signal_strength  =
+		le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.signal_strength);
+	pstatus->PER = le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.PER);
+	pstatus->BER = le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.BER);
+
+out:
+	return error;
+}
+
+/**
+ * as10x_cmd_get_tps - send get TPS command to AS10x
+ * @adap:      pointer to AS10x handle
+ * @ptps:      pointer to TPS parameters structure
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps)
+{
+	int error = AS10X_CMD_ERROR;
+	struct as10x_cmd_t *pcmd, *prsp;
+
+	pcmd = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(pcmd, (++adap->cmd_xid),
+			sizeof(pcmd->body.get_tps.req));
+
+	/* fill command */
+	pcmd->body.get_tune_status.req.proc_id =
+		cpu_to_le16(CONTROL_PROC_GETTPS);
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error = adap->ops->xfer_cmd(adap,
+					    (uint8_t *) pcmd,
+					    sizeof(pcmd->body.get_tps.req) +
+					    HEADER_SIZE,
+					    (uint8_t *) prsp,
+					    sizeof(prsp->body.get_tps.rsp) +
+					    HEADER_SIZE);
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response */
+	error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTPS_RSP);
+	if (error < 0)
+		goto out;
+
+	/* Response OK -> get response data */
+	ptps->modulation = prsp->body.get_tps.rsp.tps.modulation;
+	ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy;
+	ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode;
+	ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP;
+	ptps->code_rate_LP = prsp->body.get_tps.rsp.tps.code_rate_LP;
+	ptps->guard_interval = prsp->body.get_tps.rsp.tps.guard_interval;
+	ptps->transmission_mode  = prsp->body.get_tps.rsp.tps.transmission_mode;
+	ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP;
+	ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP;
+	ptps->cell_ID = le16_to_cpu((__force __le16)prsp->body.get_tps.rsp.tps.cell_ID);
+
+out:
+	return error;
+}
+
+/**
+ * as10x_cmd_get_demod_stats - send get demod stats command to AS10x
+ * @adap:          pointer to AS10x bus adapter
+ * @pdemod_stats:  pointer to demod stats parameters structure
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap,
+			      struct as10x_demod_stats *pdemod_stats)
+{
+	int error = AS10X_CMD_ERROR;
+	struct as10x_cmd_t *pcmd, *prsp;
+
+	pcmd = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(pcmd, (++adap->cmd_xid),
+			sizeof(pcmd->body.get_demod_stats.req));
+
+	/* fill command */
+	pcmd->body.get_demod_stats.req.proc_id =
+		cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS);
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error = adap->ops->xfer_cmd(adap,
+				(uint8_t *) pcmd,
+				sizeof(pcmd->body.get_demod_stats.req)
+				+ HEADER_SIZE,
+				(uint8_t *) prsp,
+				sizeof(prsp->body.get_demod_stats.rsp)
+				+ HEADER_SIZE);
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response */
+	error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_DEMOD_STATS_RSP);
+	if (error < 0)
+		goto out;
+
+	/* Response OK -> get response data */
+	pdemod_stats->frame_count =
+		le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.frame_count);
+	pdemod_stats->bad_frame_count =
+		le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.bad_frame_count);
+	pdemod_stats->bytes_fixed_by_rs =
+		le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs);
+	pdemod_stats->mer =
+		le16_to_cpu((__force __le16)prsp->body.get_demod_stats.rsp.stats.mer);
+	pdemod_stats->has_started =
+		prsp->body.get_demod_stats.rsp.stats.has_started;
+
+out:
+	return error;
+}
+
+/**
+ * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x
+ * @adap:     pointer to AS10x bus adapter
+ * @is_ready: pointer to value indicating when impulse
+ *	      response data is ready
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
+			       uint8_t *is_ready)
+{
+	int error = AS10X_CMD_ERROR;
+	struct as10x_cmd_t *pcmd, *prsp;
+
+	pcmd = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(pcmd, (++adap->cmd_xid),
+			sizeof(pcmd->body.get_impulse_rsp.req));
+
+	/* fill command */
+	pcmd->body.get_impulse_rsp.req.proc_id =
+		cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP);
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error = adap->ops->xfer_cmd(adap,
+					(uint8_t *) pcmd,
+					sizeof(pcmd->body.get_impulse_rsp.req)
+					+ HEADER_SIZE,
+					(uint8_t *) prsp,
+					sizeof(prsp->body.get_impulse_rsp.rsp)
+					+ HEADER_SIZE);
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response */
+	error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_IMPULSE_RESP_RSP);
+	if (error < 0)
+		goto out;
+
+	/* Response OK -> get response data */
+	*is_ready = prsp->body.get_impulse_rsp.rsp.is_ready;
+
+out:
+	return error;
+}
+
+/**
+ * as10x_cmd_build - build AS10x command header
+ * @pcmd:     pointer to AS10x command buffer
+ * @xid:      sequence id of the command
+ * @cmd_len:  length of the command
+ */
+void as10x_cmd_build(struct as10x_cmd_t *pcmd,
+		     uint16_t xid, uint16_t cmd_len)
+{
+	pcmd->header.req_id = cpu_to_le16(xid);
+	pcmd->header.prog = cpu_to_le16(SERVICE_PROG_ID);
+	pcmd->header.version = cpu_to_le16(SERVICE_PROG_VERSION);
+	pcmd->header.data_len = cpu_to_le16(cmd_len);
+}
+
+/**
+ * as10x_rsp_parse - Parse command response
+ * @prsp:       pointer to AS10x command buffer
+ * @proc_id:    id of the command
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id)
+{
+	int error;
+
+	/* extract command error code */
+	error = prsp->body.common.rsp.error;
+
+	if ((error == 0) &&
+	    (le16_to_cpu(prsp->body.common.rsp.proc_id) == proc_id)) {
+		return 0;
+	}
+
+	return AS10X_CMD_ERROR;
+}
diff --git a/drivers/media/usb/as102/as10x_cmd.h b/drivers/media/usb/as102/as10x_cmd.h
new file mode 100644
index 0000000..e06b84e
--- /dev/null
+++ b/drivers/media/usb/as102/as10x_cmd.h
@@ -0,0 +1,523 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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.
+ */
+#ifndef _AS10X_CMD_H_
+#define _AS10X_CMD_H_
+
+#include <linux/kernel.h>
+
+#include "as102_fe_types.h"
+
+/*********************************/
+/*       MACRO DEFINITIONS       */
+/*********************************/
+#define AS10X_CMD_ERROR		-1
+
+#define SERVICE_PROG_ID		0x0002
+#define SERVICE_PROG_VERSION	0x0001
+
+#define HIER_NONE		0x00
+#define HIER_LOW_PRIORITY	0x01
+
+#define HEADER_SIZE (sizeof(struct as10x_cmd_header_t))
+
+/* context request types */
+#define GET_CONTEXT_DATA	1
+#define SET_CONTEXT_DATA	2
+
+/* ODSP suspend modes */
+#define CFG_MODE_ODSP_RESUME	0
+#define CFG_MODE_ODSP_SUSPEND	1
+
+/* Dump memory size */
+#define DUMP_BLOCK_SIZE_MAX	0x20
+
+/*********************************/
+/*     TYPE DEFINITION           */
+/*********************************/
+enum control_proc {
+	CONTROL_PROC_TURNON			= 0x0001,
+	CONTROL_PROC_TURNON_RSP			= 0x0100,
+	CONTROL_PROC_SET_REGISTER		= 0x0002,
+	CONTROL_PROC_SET_REGISTER_RSP		= 0x0200,
+	CONTROL_PROC_GET_REGISTER		= 0x0003,
+	CONTROL_PROC_GET_REGISTER_RSP		= 0x0300,
+	CONTROL_PROC_SETTUNE			= 0x000A,
+	CONTROL_PROC_SETTUNE_RSP		= 0x0A00,
+	CONTROL_PROC_GETTUNESTAT		= 0x000B,
+	CONTROL_PROC_GETTUNESTAT_RSP		= 0x0B00,
+	CONTROL_PROC_GETTPS			= 0x000D,
+	CONTROL_PROC_GETTPS_RSP			= 0x0D00,
+	CONTROL_PROC_SETFILTER			= 0x000E,
+	CONTROL_PROC_SETFILTER_RSP		= 0x0E00,
+	CONTROL_PROC_REMOVEFILTER		= 0x000F,
+	CONTROL_PROC_REMOVEFILTER_RSP		= 0x0F00,
+	CONTROL_PROC_GET_IMPULSE_RESP		= 0x0012,
+	CONTROL_PROC_GET_IMPULSE_RESP_RSP	= 0x1200,
+	CONTROL_PROC_START_STREAMING		= 0x0013,
+	CONTROL_PROC_START_STREAMING_RSP	= 0x1300,
+	CONTROL_PROC_STOP_STREAMING		= 0x0014,
+	CONTROL_PROC_STOP_STREAMING_RSP		= 0x1400,
+	CONTROL_PROC_GET_DEMOD_STATS		= 0x0015,
+	CONTROL_PROC_GET_DEMOD_STATS_RSP	= 0x1500,
+	CONTROL_PROC_ELNA_CHANGE_MODE		= 0x0016,
+	CONTROL_PROC_ELNA_CHANGE_MODE_RSP	= 0x1600,
+	CONTROL_PROC_ODSP_CHANGE_MODE		= 0x0017,
+	CONTROL_PROC_ODSP_CHANGE_MODE_RSP	= 0x1700,
+	CONTROL_PROC_AGC_CHANGE_MODE		= 0x0018,
+	CONTROL_PROC_AGC_CHANGE_MODE_RSP	= 0x1800,
+
+	CONTROL_PROC_CONTEXT			= 0x00FC,
+	CONTROL_PROC_CONTEXT_RSP		= 0xFC00,
+	CONTROL_PROC_DUMP_MEMORY		= 0x00FD,
+	CONTROL_PROC_DUMP_MEMORY_RSP		= 0xFD00,
+	CONTROL_PROC_DUMPLOG_MEMORY		= 0x00FE,
+	CONTROL_PROC_DUMPLOG_MEMORY_RSP		= 0xFE00,
+	CONTROL_PROC_TURNOFF			= 0x00FF,
+	CONTROL_PROC_TURNOFF_RSP		= 0xFF00
+};
+
+union as10x_turn_on {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* error */
+		uint8_t error;
+	} __packed rsp;
+} __packed;
+
+union as10x_turn_off {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* error */
+		uint8_t err;
+	} __packed rsp;
+} __packed;
+
+union as10x_set_tune {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+		/* tune params */
+		struct as10x_tune_args args;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* response error */
+		uint8_t error;
+	} __packed rsp;
+} __packed;
+
+union as10x_get_tune_status {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* response error */
+		uint8_t error;
+		/* tune status */
+		struct as10x_tune_status sts;
+	} __packed rsp;
+} __packed;
+
+union as10x_get_tps {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* response error */
+		uint8_t error;
+		/* tps details */
+		struct as10x_tps tps;
+	} __packed rsp;
+} __packed;
+
+union as10x_common {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16  proc_id;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* response error */
+		uint8_t error;
+	} __packed rsp;
+} __packed;
+
+union as10x_add_pid_filter {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16  proc_id;
+		/* PID to filter */
+		__le16  pid;
+		/* stream type (MPE, PSI/SI or PES )*/
+		uint8_t stream_type;
+		/* PID index in filter table */
+		uint8_t idx;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* response error */
+		uint8_t error;
+		/* Filter id */
+		uint8_t filter_id;
+	} __packed rsp;
+} __packed;
+
+union as10x_del_pid_filter {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16  proc_id;
+		/* PID to remove */
+		__le16  pid;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* response error */
+		uint8_t error;
+	} __packed rsp;
+} __packed;
+
+union as10x_start_streaming {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* error */
+		uint8_t error;
+	} __packed rsp;
+} __packed;
+
+union as10x_stop_streaming {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* error */
+		uint8_t error;
+	} __packed rsp;
+} __packed;
+
+union as10x_get_demod_stats {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* error */
+		uint8_t error;
+		/* demod stats */
+		struct as10x_demod_stats stats;
+	} __packed rsp;
+} __packed;
+
+union as10x_get_impulse_resp {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* error */
+		uint8_t error;
+		/* impulse response ready */
+		uint8_t is_ready;
+	} __packed rsp;
+} __packed;
+
+union as10x_fw_context {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+		/* value to write (for set context)*/
+		struct as10x_register_value reg_val;
+		/* context tag */
+		__le16 tag;
+		/* context request type */
+		__le16 type;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* value read (for get context) */
+		struct as10x_register_value reg_val;
+		/* context request type */
+		__le16 type;
+		/* error */
+		uint8_t error;
+	} __packed rsp;
+} __packed;
+
+union as10x_set_register {
+	/* request */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* register description */
+		struct as10x_register_addr reg_addr;
+		/* register content */
+		struct as10x_register_value reg_val;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* error */
+		uint8_t error;
+	} __packed rsp;
+} __packed;
+
+union as10x_get_register {
+	/* request */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* register description */
+		struct as10x_register_addr reg_addr;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* error */
+		uint8_t error;
+		/* register content */
+		struct as10x_register_value reg_val;
+	} __packed rsp;
+} __packed;
+
+union as10x_cfg_change_mode {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+		/* mode */
+		uint8_t mode;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* error */
+		uint8_t error;
+	} __packed rsp;
+} __packed;
+
+struct as10x_cmd_header_t {
+	__le16 req_id;
+	__le16 prog;
+	__le16 version;
+	__le16 data_len;
+} __packed;
+
+#define DUMP_BLOCK_SIZE 16
+
+union as10x_dump_memory {
+	/* request */
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+		/* dump memory type request */
+		uint8_t dump_req;
+		/* register description */
+		struct as10x_register_addr reg_addr;
+		/* nb blocks to read */
+		__le16 num_blocks;
+	} __packed req;
+	/* response */
+	struct {
+		/* response identifier */
+		__le16 proc_id;
+		/* error */
+		uint8_t error;
+		/* dump response */
+		uint8_t dump_rsp;
+		/* data */
+		union {
+			uint8_t  data8[DUMP_BLOCK_SIZE];
+			__le16 data16[DUMP_BLOCK_SIZE / sizeof(__le16)];
+			__le32 data32[DUMP_BLOCK_SIZE / sizeof(__le32)];
+		} __packed u;
+	} __packed rsp;
+} __packed;
+
+union as10x_dumplog_memory {
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+		/* dump memory type request */
+		uint8_t dump_req;
+	} __packed req;
+	struct {
+		/* request identifier */
+		__le16 proc_id;
+		/* error */
+		uint8_t error;
+		/* dump response */
+		uint8_t dump_rsp;
+		/* dump data */
+		uint8_t data[DUMP_BLOCK_SIZE];
+	} __packed rsp;
+} __packed;
+
+union as10x_raw_data {
+	/* request */
+	struct {
+		__le16 proc_id;
+		uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
+			     - 2 /* proc_id */];
+	} __packed req;
+	/* response */
+	struct {
+		__le16 proc_id;
+		uint8_t error;
+		uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
+			     - 2 /* proc_id */ - 1 /* rc */];
+	} __packed rsp;
+} __packed;
+
+struct as10x_cmd_t {
+	struct as10x_cmd_header_t header;
+	union {
+		union as10x_turn_on		turn_on;
+		union as10x_turn_off		turn_off;
+		union as10x_set_tune		set_tune;
+		union as10x_get_tune_status	get_tune_status;
+		union as10x_get_tps		get_tps;
+		union as10x_common		common;
+		union as10x_add_pid_filter	add_pid_filter;
+		union as10x_del_pid_filter	del_pid_filter;
+		union as10x_start_streaming	start_streaming;
+		union as10x_stop_streaming	stop_streaming;
+		union as10x_get_demod_stats	get_demod_stats;
+		union as10x_get_impulse_resp	get_impulse_rsp;
+		union as10x_fw_context		context;
+		union as10x_set_register	set_register;
+		union as10x_get_register	get_register;
+		union as10x_cfg_change_mode	cfg_change_mode;
+		union as10x_dump_memory		dump_memory;
+		union as10x_dumplog_memory	dumplog_memory;
+		union as10x_raw_data		raw_data;
+	} __packed body;
+} __packed;
+
+struct as10x_token_cmd_t {
+	/* token cmd */
+	struct as10x_cmd_t c;
+	/* token response */
+	struct as10x_cmd_t r;
+} __packed;
+
+
+/**************************/
+/* FUNCTION DECLARATION   */
+/**************************/
+
+void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t proc_id,
+		      uint16_t cmd_len);
+int as10x_rsp_parse(struct as10x_cmd_t *r, uint16_t proc_id);
+
+/* as10x cmd */
+int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap);
+int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap);
+
+int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
+		       struct as10x_tune_args *ptune);
+
+int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
+			      struct as10x_tune_status *pstatus);
+
+int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap,
+		      struct as10x_tps *ptps);
+
+int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t  *adap,
+			      struct as10x_demod_stats *pdemod_stats);
+
+int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
+			       uint8_t *is_ready);
+
+/* as10x cmd stream */
+int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
+			     struct as10x_ts_filter *filter);
+int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
+			     uint16_t pid_value);
+
+int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap);
+int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap);
+
+/* as10x cmd cfg */
+int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap,
+			  uint16_t tag,
+			  uint32_t value);
+int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap,
+			  uint16_t tag,
+			  uint32_t *pvalue);
+
+int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode);
+int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id);
+#endif
diff --git a/drivers/media/usb/as102/as10x_cmd_cfg.c b/drivers/media/usb/as102/as10x_cmd_cfg.c
new file mode 100644
index 0000000..c87f2ca
--- /dev/null
+++ b/drivers/media/usb/as102/as10x_cmd_cfg.c
@@ -0,0 +1,201 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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/kernel.h>
+#include "as102_drv.h"
+#include "as10x_cmd.h"
+
+/***************************/
+/* FUNCTION DEFINITION     */
+/***************************/
+
+/**
+ * as10x_cmd_get_context - Send get context command to AS10x
+ * @adap:      pointer to AS10x bus adapter
+ * @tag:       context tag
+ * @pvalue:    pointer where to store context value read
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
+			  uint32_t *pvalue)
+{
+	int  error;
+	struct as10x_cmd_t *pcmd, *prsp;
+
+	pcmd = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(pcmd, (++adap->cmd_xid),
+			sizeof(pcmd->body.context.req));
+
+	/* fill command */
+	pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT);
+	pcmd->body.context.req.tag = cpu_to_le16(tag);
+	pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA);
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error  = adap->ops->xfer_cmd(adap,
+					     (uint8_t *) pcmd,
+					     sizeof(pcmd->body.context.req)
+					     + HEADER_SIZE,
+					     (uint8_t *) prsp,
+					     sizeof(prsp->body.context.rsp)
+					     + HEADER_SIZE);
+	} else {
+		error = AS10X_CMD_ERROR;
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response: context command do not follow the common response */
+	/* structure -> specific handling response parse required            */
+	error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
+
+	if (error == 0) {
+		/* Response OK -> get response data */
+		*pvalue = le32_to_cpu((__force __le32)prsp->body.context.rsp.reg_val.u.value32);
+		/* value returned is always a 32-bit value */
+	}
+
+out:
+	return error;
+}
+
+/**
+ * as10x_cmd_set_context - send set context command to AS10x
+ * @adap:      pointer to AS10x bus adapter
+ * @tag:       context tag
+ * @value:     value to set in context
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
+			  uint32_t value)
+{
+	int error;
+	struct as10x_cmd_t *pcmd, *prsp;
+
+	pcmd = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(pcmd, (++adap->cmd_xid),
+			sizeof(pcmd->body.context.req));
+
+	/* fill command */
+	pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT);
+	/* pcmd->body.context.req.reg_val.mode initialization is not required */
+	pcmd->body.context.req.reg_val.u.value32 = (__force u32)cpu_to_le32(value);
+	pcmd->body.context.req.tag = cpu_to_le16(tag);
+	pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA);
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error  = adap->ops->xfer_cmd(adap,
+					     (uint8_t *) pcmd,
+					     sizeof(pcmd->body.context.req)
+					     + HEADER_SIZE,
+					     (uint8_t *) prsp,
+					     sizeof(prsp->body.context.rsp)
+					     + HEADER_SIZE);
+	} else {
+		error = AS10X_CMD_ERROR;
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response: context command do not follow the common response */
+	/* structure -> specific handling response parse required            */
+	error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
+
+out:
+	return error;
+}
+
+/**
+ * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x
+ * @adap:      pointer to AS10x bus adapter
+ * @mode:      mode selected:
+ *	        - ON    : 0x0 => eLNA always ON
+ *	        - OFF   : 0x1 => eLNA always OFF
+ *	        - AUTO  : 0x2 => eLNA follow hysteresis parameters
+ *				 to be ON or OFF
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode)
+{
+	int error;
+	struct as10x_cmd_t *pcmd, *prsp;
+
+	pcmd = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(pcmd, (++adap->cmd_xid),
+			sizeof(pcmd->body.cfg_change_mode.req));
+
+	/* fill command */
+	pcmd->body.cfg_change_mode.req.proc_id =
+		cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE);
+	pcmd->body.cfg_change_mode.req.mode = mode;
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error  = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+				sizeof(pcmd->body.cfg_change_mode.req)
+				+ HEADER_SIZE, (uint8_t *) prsp,
+				sizeof(prsp->body.cfg_change_mode.rsp)
+				+ HEADER_SIZE);
+	} else {
+		error = AS10X_CMD_ERROR;
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response */
+	error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP);
+
+out:
+	return error;
+}
+
+/**
+ * as10x_context_rsp_parse - Parse context command response
+ * @prsp:       pointer to AS10x command response buffer
+ * @proc_id:    id of the command
+ *
+ * Since the contex command response does not follow the common
+ * response, a specific parse function is required.
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id)
+{
+	int err;
+
+	err = prsp->body.context.rsp.error;
+
+	if ((err == 0) &&
+	    (le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) {
+		return 0;
+	}
+	return AS10X_CMD_ERROR;
+}
diff --git a/drivers/media/usb/as102/as10x_cmd_stream.c b/drivers/media/usb/as102/as10x_cmd_stream.c
new file mode 100644
index 0000000..126aea9
--- /dev/null
+++ b/drivers/media/usb/as102/as10x_cmd_stream.c
@@ -0,0 +1,207 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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/kernel.h>
+#include "as102_drv.h"
+#include "as10x_cmd.h"
+
+/**
+ * as10x_cmd_add_PID_filter - send add filter command to AS10x
+ * @adap:      pointer to AS10x bus adapter
+ * @filter:    TSFilter filter for DVB-T
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
+			     struct as10x_ts_filter *filter)
+{
+	int error;
+	struct as10x_cmd_t *pcmd, *prsp;
+
+	pcmd = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(pcmd, (++adap->cmd_xid),
+			sizeof(pcmd->body.add_pid_filter.req));
+
+	/* fill command */
+	pcmd->body.add_pid_filter.req.proc_id =
+		cpu_to_le16(CONTROL_PROC_SETFILTER);
+	pcmd->body.add_pid_filter.req.pid = cpu_to_le16(filter->pid);
+	pcmd->body.add_pid_filter.req.stream_type = filter->type;
+
+	if (filter->idx < 16)
+		pcmd->body.add_pid_filter.req.idx = filter->idx;
+	else
+		pcmd->body.add_pid_filter.req.idx = 0xFF;
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+				sizeof(pcmd->body.add_pid_filter.req)
+				+ HEADER_SIZE, (uint8_t *) prsp,
+				sizeof(prsp->body.add_pid_filter.rsp)
+				+ HEADER_SIZE);
+	} else {
+		error = AS10X_CMD_ERROR;
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response */
+	error = as10x_rsp_parse(prsp, CONTROL_PROC_SETFILTER_RSP);
+
+	if (error == 0) {
+		/* Response OK -> get response data */
+		filter->idx = prsp->body.add_pid_filter.rsp.filter_id;
+	}
+
+out:
+	return error;
+}
+
+/**
+ * as10x_cmd_del_PID_filter - Send delete filter command to AS10x
+ * @adap:         pointer to AS10x bus adapte
+ * @pid_value:    PID to delete
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
+			     uint16_t pid_value)
+{
+	int error;
+	struct as10x_cmd_t *pcmd, *prsp;
+
+	pcmd = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(pcmd, (++adap->cmd_xid),
+			sizeof(pcmd->body.del_pid_filter.req));
+
+	/* fill command */
+	pcmd->body.del_pid_filter.req.proc_id =
+		cpu_to_le16(CONTROL_PROC_REMOVEFILTER);
+	pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value);
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+				sizeof(pcmd->body.del_pid_filter.req)
+				+ HEADER_SIZE, (uint8_t *) prsp,
+				sizeof(prsp->body.del_pid_filter.rsp)
+				+ HEADER_SIZE);
+	} else {
+		error = AS10X_CMD_ERROR;
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response */
+	error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP);
+
+out:
+	return error;
+}
+
+/**
+ * as10x_cmd_start_streaming - Send start streaming command to AS10x
+ * @adap:   pointer to AS10x bus adapter
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap)
+{
+	int error;
+	struct as10x_cmd_t *pcmd, *prsp;
+
+	pcmd = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(pcmd, (++adap->cmd_xid),
+			sizeof(pcmd->body.start_streaming.req));
+
+	/* fill command */
+	pcmd->body.start_streaming.req.proc_id =
+		cpu_to_le16(CONTROL_PROC_START_STREAMING);
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+				sizeof(pcmd->body.start_streaming.req)
+				+ HEADER_SIZE, (uint8_t *) prsp,
+				sizeof(prsp->body.start_streaming.rsp)
+				+ HEADER_SIZE);
+	} else {
+		error = AS10X_CMD_ERROR;
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response */
+	error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP);
+
+out:
+	return error;
+}
+
+/**
+ * as10x_cmd_stop_streaming - Send stop streaming command to AS10x
+ * @adap:   pointer to AS10x bus adapter
+ *
+ * Return 0 on success or negative value in case of error.
+ */
+int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap)
+{
+	int8_t error;
+	struct as10x_cmd_t *pcmd, *prsp;
+
+	pcmd = adap->cmd;
+	prsp = adap->rsp;
+
+	/* prepare command */
+	as10x_cmd_build(pcmd, (++adap->cmd_xid),
+			sizeof(pcmd->body.stop_streaming.req));
+
+	/* fill command */
+	pcmd->body.stop_streaming.req.proc_id =
+		cpu_to_le16(CONTROL_PROC_STOP_STREAMING);
+
+	/* send command */
+	if (adap->ops->xfer_cmd) {
+		error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd,
+				sizeof(pcmd->body.stop_streaming.req)
+				+ HEADER_SIZE, (uint8_t *) prsp,
+				sizeof(prsp->body.stop_streaming.rsp)
+				+ HEADER_SIZE);
+	} else {
+		error = AS10X_CMD_ERROR;
+	}
+
+	if (error < 0)
+		goto out;
+
+	/* parse response */
+	error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP);
+
+out:
+	return error;
+}
diff --git a/drivers/media/usb/as102/as10x_handle.h b/drivers/media/usb/as102/as10x_handle.h
new file mode 100644
index 0000000..d6b58c7
--- /dev/null
+++ b/drivers/media/usb/as102/as10x_handle.h
@@ -0,0 +1,51 @@
+/*
+ * Abilis Systems Single DVB-T Receiver
+ * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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.
+ */
+#ifndef _AS10X_HANDLE_H
+#define _AS10X_HANDLE_H
+struct as10x_bus_adapter_t;
+struct as102_dev_t;
+
+#include "as10x_cmd.h"
+
+/* values for "mode" field */
+#define REGMODE8	8
+#define REGMODE16	16
+#define REGMODE32	32
+
+struct as102_priv_ops_t {
+	int (*upload_fw_pkt)(struct as10x_bus_adapter_t *bus_adap,
+			      unsigned char *buf, int buflen, int swap32);
+
+	int (*send_cmd)(struct as10x_bus_adapter_t *bus_adap,
+			 unsigned char *buf, int buflen);
+
+	int (*xfer_cmd)(struct as10x_bus_adapter_t *bus_adap,
+			 unsigned char *send_buf, int send_buf_len,
+			 unsigned char *recv_buf, int recv_buf_len);
+
+	int (*start_stream)(struct as102_dev_t *dev);
+	void (*stop_stream)(struct as102_dev_t *dev);
+
+	int (*reset_target)(struct as10x_bus_adapter_t *bus_adap);
+
+	int (*read_write)(struct as10x_bus_adapter_t *bus_adap, uint8_t mode,
+			  uint32_t rd_addr, uint16_t rd_len,
+			  uint32_t wr_addr, uint16_t wr_len);
+
+	int (*as102_read_ep2)(struct as10x_bus_adapter_t *bus_adap,
+			       unsigned char *recv_buf,
+			       int recv_buf_len);
+};
+#endif
diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c
index f15ccf0..6c164d9 100644
--- a/drivers/media/usb/au0828/au0828-cards.c
+++ b/drivers/media/usb/au0828/au0828-cards.c
@@ -46,6 +46,8 @@
 		.name	= "Hauppauge HVR850",
 		.tuner_type = TUNER_XC5000,
 		.tuner_addr = 0x61,
+		.has_ir_i2c = 1,
+		.has_analog = 1,
 		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
 		.input = {
 			{
@@ -72,12 +74,7 @@
 		.tuner_type = TUNER_XC5000,
 		.tuner_addr = 0x61,
 		.has_ir_i2c = 1,
-		/* The au0828 hardware i2c implementation does not properly
-		   support the xc5000's i2c clock stretching.  So we need to
-		   lower the clock frequency enough where the 15us clock
-		   stretch fits inside of a normal clock cycle, or else the
-		   au0828 fails to set the STOP bit.  A 30 KHz clock puts the
-		   clock pulse width at 18us */
+		.has_analog = 1,
 		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
 		.input = {
 			{
@@ -101,20 +98,20 @@
 	},
 	[AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
 		.name	= "Hauppauge HVR950Q rev xxF8",
-		.tuner_type = UNSET,
-		.tuner_addr = ADDR_UNSET,
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
 		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
 	},
 	[AU0828_BOARD_DVICO_FUSIONHDTV7] = {
 		.name	= "DViCO FusionHDTV USB",
-		.tuner_type = UNSET,
-		.tuner_addr = ADDR_UNSET,
+		.tuner_type = TUNER_XC5000,
+		.tuner_addr = 0x61,
 		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
 	},
 	[AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
 		.name = "Hauppauge Woodbury",
-		.tuner_type = UNSET,
-		.tuner_addr = ADDR_UNSET,
+		.tuner_type = TUNER_NXP_TDA18271,
+		.tuner_addr = 0x60,
 		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
 	},
 };
@@ -142,8 +139,7 @@
 			mdelay(10);
 			return 0;
 		} else {
-			printk(KERN_ERR
-				"%s(): Unknown command.\n", __func__);
+			pr_err("%s(): Unknown command.\n", __func__);
 			return -EINVAL;
 		}
 		break;
@@ -177,12 +173,12 @@
 	case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
 		break;
 	default:
-		printk(KERN_WARNING "%s: warning: "
-		       "unknown hauppauge model #%d\n", __func__, tv.model);
+		pr_warn("%s: warning: unknown hauppauge model #%d\n",
+			__func__, tv.model);
 		break;
 	}
 
-	printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+	pr_info("%s: hauppauge eeprom: model=%d\n",
 	       __func__, tv.model);
 }
 
@@ -228,16 +224,16 @@
 		sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
 				"au8522", 0x8e >> 1, NULL);
 		if (sd == NULL)
-			printk(KERN_ERR "analog subdev registration failed\n");
+			pr_err("analog subdev registration failed\n");
 	}
 
 	/* Setup tuners */
-	if (dev->board.tuner_type != TUNER_ABSENT) {
+	if (dev->board.tuner_type != TUNER_ABSENT && dev->board.has_analog) {
 		/* Load the tuner module, which does the attach */
 		sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
 				"tuner", dev->board.tuner_addr, NULL);
 		if (sd == NULL)
-			printk(KERN_ERR "tuner subdev registration fail\n");
+			pr_err("tuner subdev registration fail\n");
 
 		tun_setup.mode_mask      = mode_mask;
 		tun_setup.type           = dev->board.tuner_type;
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index 2f12307..c697199 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -19,14 +19,14 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
-#include "au0828.h"
-
 /*
  * 1 = General debug messages
  * 2 = USB handling
@@ -90,7 +90,7 @@
 		status = min(status, 0);
 
 		if (status < 0) {
-			printk(KERN_ERR "%s() Failed sending control message, error %d.\n",
+			pr_err("%s() Failed sending control message, error %d.\n",
 				__func__, status);
 		}
 
@@ -115,7 +115,7 @@
 		status = min(status, 0);
 
 		if (status < 0) {
-			printk(KERN_ERR "%s() Failed receiving control message, error %d.\n",
+			pr_err("%s() Failed receiving control message, error %d.\n",
 				__func__, status);
 		}
 
@@ -153,9 +153,7 @@
 
 	dprintk(1, "%s()\n", __func__);
 
-#ifdef CPTCFG_VIDEO_AU0828_RC
 	au0828_rc_unregister(dev);
-#endif
 	/* Digital TV */
 	au0828_dvb_unregister(dev);
 
@@ -199,15 +197,14 @@
 	 * not enough even for most Digital TV streams.
 	 */
 	if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
-		printk(KERN_ERR "au0828: Device initialization failed.\n");
-		printk(KERN_ERR "au0828: Device must be connected to a "
-		       "high-speed USB 2.0 port.\n");
+		pr_err("au0828: Device initialization failed.\n");
+		pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n");
 		return -ENODEV;
 	}
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL) {
-		printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
+		pr_err("%s() Unable to allocate memory\n", __func__);
 		return -ENOMEM;
 	}
 
@@ -266,10 +263,8 @@
 		pr_err("%s() au0282_dev_register failed\n",
 		       __func__);
 
-#ifdef CPTCFG_VIDEO_AU0828_RC
 	/* Remote controller */
 	au0828_rc_register(dev);
-#endif
 
 	/*
 	 * Store the pointer to the au0828_dev so it can be accessed in
@@ -277,7 +272,7 @@
 	 */
 	usb_set_intfdata(interface, dev);
 
-	printk(KERN_INFO "Registered device AU0828 [%s]\n",
+	pr_info("Registered device AU0828 [%s]\n",
 		dev->board.name == NULL ? "Unset" : dev->board.name);
 
 	mutex_unlock(&dev->lock);
@@ -285,13 +280,56 @@
 	return retval;
 }
 
+static int au0828_suspend(struct usb_interface *interface,
+				pm_message_t message)
+{
+	struct au0828_dev *dev = usb_get_intfdata(interface);
+
+	if (!dev)
+		return 0;
+
+	pr_info("Suspend\n");
+
+	au0828_rc_suspend(dev);
+	au0828_v4l2_suspend(dev);
+	au0828_dvb_suspend(dev);
+
+	/* FIXME: should suspend also ATV/DTV */
+
+	return 0;
+}
+
+static int au0828_resume(struct usb_interface *interface)
+{
+	struct au0828_dev *dev = usb_get_intfdata(interface);
+	if (!dev)
+		return 0;
+
+	pr_info("Resume\n");
+
+	/* Power Up the bridge */
+	au0828_write(dev, REG_600, 1 << 4);
+
+	/* Bring up the GPIO's and supporting devices */
+	au0828_gpio_setup(dev);
+
+	au0828_rc_resume(dev);
+	au0828_v4l2_resume(dev);
+	au0828_dvb_resume(dev);
+
+	/* FIXME: should resume also ATV/DTV */
+
+	return 0;
+}
+
 static struct usb_driver au0828_usb_driver = {
-	.name		= DRIVER_NAME,
+	.name		= KBUILD_MODNAME,
 	.probe		= au0828_usb_probe,
 	.disconnect	= au0828_usb_disconnect,
 	.id_table	= au0828_usb_id_table,
-
-	/* FIXME: Add suspend and resume functions */
+	.suspend	= au0828_suspend,
+	.resume		= au0828_resume,
+	.reset_resume	= au0828_resume,
 };
 
 static int __init au0828_init(void)
@@ -299,27 +337,27 @@
 	int ret;
 
 	if (au0828_debug & 1)
-		printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
+		pr_info("%s() Debugging is enabled\n", __func__);
 
 	if (au0828_debug & 2)
-		printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
+		pr_info("%s() USB Debugging is enabled\n", __func__);
 
 	if (au0828_debug & 4)
-		printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
+		pr_info("%s() I2C Debugging is enabled\n", __func__);
 
 	if (au0828_debug & 8)
-		printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
+		pr_info("%s() Bridge Debugging is enabled\n",
 		       __func__);
 
 	if (au0828_debug & 16)
-		printk(KERN_INFO "%s() IR Debugging is enabled\n",
+		pr_info("%s() IR Debugging is enabled\n",
 		       __func__);
 
-	printk(KERN_INFO "au0828 driver loaded\n");
+	pr_info("au0828 driver loaded\n");
 
 	ret = usb_register(&au0828_usb_driver);
 	if (ret)
-		printk(KERN_ERR "usb_register failed, error = %d\n", ret);
+		pr_err("usb_register failed, error = %d\n", ret);
 
 	return ret;
 }
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
index d8b5d94..00ab156 100644
--- a/drivers/media/usb/au0828/au0828-dvb.c
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -19,15 +19,15 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/device.h>
-#include <linux/suspend.h>
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
 
-#include "au0828.h"
 #include "au8522.h"
 #include "xc5000.h"
 #include "mxl5007t.h"
@@ -121,13 +121,13 @@
 		return;
 	}
 
-	if (dev->urb_streaming == 0) {
+	if (!dev->urb_streaming) {
 		dprintk(2, "%s: not streaming!\n", __func__);
 		return;
 	}
 
 	if (ptype != PIPE_BULK) {
-		printk(KERN_ERR "%s: Unsupported URB type %d\n",
+		pr_err("%s: Unsupported URB type %d\n",
 		       __func__, ptype);
 		return;
 	}
@@ -159,7 +159,10 @@
 
 	dprintk(2, "%s()\n", __func__);
 
-	dev->urb_streaming = 0;
+	if (!dev->urb_streaming)
+		return 0;
+
+	dev->urb_streaming = false;
 	for (i = 0; i < URB_COUNT; i++) {
 		if (dev->urbs[i]) {
 			usb_kill_urb(dev->urbs[i]);
@@ -202,8 +205,7 @@
 		if (!purb->transfer_buffer) {
 			usb_free_urb(purb);
 			dev->urbs[i] = NULL;
-			printk(KERN_ERR
-			       "%s: failed big buffer allocation, err = %d\n",
+			pr_err("%s: failed big buffer allocation, err = %d\n",
 			       __func__, ret);
 			goto err;
 		}
@@ -224,13 +226,13 @@
 		ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);
 		if (ret != 0) {
 			stop_urb_transfer(dev);
-			printk(KERN_ERR "%s: failed urb submission, "
-			       "err = %d\n", __func__, ret);
+			pr_err("%s: failed urb submission, err = %d\n",
+			       __func__, ret);
 			return ret;
 		}
 	}
 
-	dev->urb_streaming = 1;
+	dev->urb_streaming = true;
 	ret = 0;
 
 err:
@@ -268,7 +270,7 @@
 	if (!demux->dmx.frontend)
 		return -EINVAL;
 
-	if (dvb) {
+	if (dvb->frontend) {
 		mutex_lock(&dvb->lock);
 		dvb->start_count++;
 		dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
@@ -297,7 +299,7 @@
 
 	dprintk(1, "%s()\n", __func__);
 
-	if (dvb) {
+	if (dvb->frontend) {
 		cancel_work_sync(&dev->restart_streaming);
 
 		mutex_lock(&dvb->lock);
@@ -324,7 +326,7 @@
 					      restart_streaming);
 	struct au0828_dvb *dvb = &dev->dvb;
 
-	if (dev->urb_streaming == 0)
+	if (!dev->urb_streaming)
 		return;
 
 	dprintk(1, "Restarting streaming...!\n");
@@ -393,9 +395,8 @@
 			if (!dev->dig_transfer_buffer[i]) {
 				result = -ENOMEM;
 
-				printk(KERN_ERR
-				       "%s: failed buffer allocation (errno = %d)\n",
-				       DRIVER_NAME, result);
+				pr_err("failed buffer allocation (errno = %d)\n",
+				       result);
 				goto fail_adapter;
 			}
 		}
@@ -404,11 +405,12 @@
 	INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming);
 
 	/* register adapter */
-	result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
+	result = dvb_register_adapter(&dvb->adapter,
+				      KBUILD_MODNAME, THIS_MODULE,
 				      &dev->usbdev->dev, adapter_nr);
 	if (result < 0) {
-		printk(KERN_ERR "%s: dvb_register_adapter failed "
-		       "(errno = %d)\n", DRIVER_NAME, result);
+		pr_err("dvb_register_adapter failed (errno = %d)\n",
+		       result);
 		goto fail_adapter;
 	}
 	dvb->adapter.priv = dev;
@@ -416,8 +418,8 @@
 	/* register frontend */
 	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
 	if (result < 0) {
-		printk(KERN_ERR "%s: dvb_register_frontend failed "
-		       "(errno = %d)\n", DRIVER_NAME, result);
+		pr_err("dvb_register_frontend failed (errno = %d)\n",
+		       result);
 		goto fail_frontend;
 	}
 
@@ -436,8 +438,7 @@
 	dvb->demux.stop_feed  = au0828_dvb_stop_feed;
 	result = dvb_dmx_init(&dvb->demux);
 	if (result < 0) {
-		printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",
-		       DRIVER_NAME, result);
+		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
 		goto fail_dmx;
 	}
 
@@ -446,31 +447,29 @@
 	dvb->dmxdev.capabilities = 0;
 	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
 	if (result < 0) {
-		printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
-		       DRIVER_NAME, result);
+		pr_err("dvb_dmxdev_init failed (errno = %d)\n", result);
 		goto fail_dmxdev;
 	}
 
 	dvb->fe_hw.source = DMX_FRONTEND_0;
 	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 	if (result < 0) {
-		printk(KERN_ERR "%s: add_frontend failed "
-		       "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);
+		pr_err("add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+		       result);
 		goto fail_fe_hw;
 	}
 
 	dvb->fe_mem.source = DMX_MEMORY_FE;
 	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
 	if (result < 0) {
-		printk(KERN_ERR "%s: add_frontend failed "
-		       "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);
+		pr_err("add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+		       result);
 		goto fail_fe_mem;
 	}
 
 	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 	if (result < 0) {
-		printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",
-		       DRIVER_NAME, result);
+		pr_err("connect_frontend failed (errno = %d)\n", result);
 		goto fail_fe_conn;
 	}
 
@@ -530,8 +529,7 @@
 		for (i = 0; i < URB_COUNT; i++)
 			kfree(dev->dig_transfer_buffer[i]);
 	}
-
-
+	dvb->frontend = NULL;
 }
 
 /* All the DVB attach calls go here, this function get's modified
@@ -596,12 +594,11 @@
 		}
 		break;
 	default:
-		printk(KERN_WARNING "The frontend of your DVB/ATSC card "
-		       "isn't supported yet\n");
+		pr_warn("The frontend of your DVB/ATSC card isn't supported yet\n");
 		break;
 	}
 	if (NULL == dvb->frontend) {
-		printk(KERN_ERR "%s() Frontend initialization failed\n",
+		pr_err("%s() Frontend initialization failed\n",
 		       __func__);
 		return -1;
 	}
@@ -613,8 +610,49 @@
 	if (ret < 0) {
 		if (dvb->frontend->ops.release)
 			dvb->frontend->ops.release(dvb->frontend);
+		dvb->frontend = NULL;
 		return ret;
 	}
 
 	return 0;
 }
+
+void au0828_dvb_suspend(struct au0828_dev *dev)
+{
+	struct au0828_dvb *dvb = &dev->dvb;
+	int rc;
+
+	if (dvb->frontend) {
+		if (dev->urb_streaming) {
+			cancel_work_sync(&dev->restart_streaming);
+			/* Stop transport */
+			mutex_lock(&dvb->lock);
+			stop_urb_transfer(dev);
+			au0828_stop_transport(dev, 1);
+			mutex_unlock(&dvb->lock);
+			dev->need_urb_start = true;
+		}
+		/* suspend frontend - does tuner and fe to sleep */
+		rc = dvb_frontend_suspend(dvb->frontend);
+		pr_info("au0828_dvb_suspend(): Suspending DVB fe %d\n", rc);
+	}
+}
+
+void au0828_dvb_resume(struct au0828_dev *dev)
+{
+	struct au0828_dvb *dvb = &dev->dvb;
+	int rc;
+
+	if (dvb->frontend) {
+		/* resume frontend - does fe and tuner init */
+		rc = dvb_frontend_resume(dvb->frontend);
+		pr_info("au0828_dvb_resume(): Resuming DVB fe %d\n", rc);
+		if (dev->need_urb_start) {
+			/* Start transport */
+			mutex_lock(&dvb->lock);
+			au0828_start_transport(dev);
+			start_urb_transfer(dev);
+			mutex_unlock(&dvb->lock);
+		}
+	}
+}
diff --git a/drivers/media/usb/au0828/au0828-i2c.c b/drivers/media/usb/au0828/au0828-i2c.c
index 17d0b4f..01456ba 100644
--- a/drivers/media/usb/au0828/au0828-i2c.c
+++ b/drivers/media/usb/au0828/au0828-i2c.c
@@ -19,13 +19,14 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 
-#include "au0828.h"
 #include "media/tuner.h"
 #include <media/v4l2-common.h>
 
@@ -340,7 +341,7 @@
 /* ----------------------------------------------------------------------- */
 
 static struct i2c_adapter au0828_i2c_adap_template = {
-	.name              = DRIVER_NAME,
+	.name              = KBUILD_MODNAME,
 	.owner             = THIS_MODULE,
 	.algo              = &au0828_i2c_algo_template,
 };
@@ -365,7 +366,7 @@
 		rc = i2c_master_recv(c, &buf, 0);
 		if (rc < 0)
 			continue;
-		printk(KERN_INFO "%s: i2c scan: found device @ 0x%x  [%s]\n",
+		pr_info("%s: i2c scan: found device @ 0x%x  [%s]\n",
 		       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
 	}
 }
@@ -381,7 +382,7 @@
 
 	dev->i2c_adap.dev.parent = &dev->usbdev->dev;
 
-	strlcpy(dev->i2c_adap.name, DRIVER_NAME,
+	strlcpy(dev->i2c_adap.name, KBUILD_MODNAME,
 		sizeof(dev->i2c_adap.name));
 
 	dev->i2c_adap.algo = &dev->i2c_algo;
@@ -396,11 +397,11 @@
 	dev->i2c_client.adapter = &dev->i2c_adap;
 
 	if (0 == dev->i2c_rc) {
-		printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME);
+		pr_info("i2c bus registered\n");
 		if (i2c_scan)
-			do_i2c_scan(DRIVER_NAME, &dev->i2c_client);
+			do_i2c_scan(KBUILD_MODNAME, &dev->i2c_client);
 	} else
-		printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME);
+		pr_info("i2c bus register FAILED\n");
 
 	return dev->i2c_rc;
 }
diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c
index fd0d3a9..63995f9 100644
--- a/drivers/media/usb/au0828/au0828-input.c
+++ b/drivers/media/usb/au0828/au0828-input.c
@@ -17,6 +17,8 @@
   GNU General Public License for more details.
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -25,7 +27,9 @@
 #include <linux/slab.h>
 #include <media/rc-core.h>
 
-#include "au0828.h"
+static int disable_ir;
+module_param(disable_ir,        int, 0444);
+MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
 
 struct au0828_rc {
 	struct au0828_dev *dev;
@@ -90,14 +94,19 @@
 static int au8522_rc_andor(struct au0828_rc *ir, u16 reg, u8 mask, u8 value)
 {
 	int rc;
-	char buf;
+	char buf, oldbuf;
 
 	rc = au8522_rc_read(ir, reg, -1, &buf, 1);
 	if (rc < 0)
 		return rc;
 
+	oldbuf = buf;
 	buf = (buf & ~mask) | (value & mask);
 
+	/* Nothing to do, just return */
+	if (buf == oldbuf)
+		return 0;
+
 	return au8522_rc_write(ir, reg, buf);
 }
 
@@ -122,8 +131,11 @@
 
 	/* Check IR int */
 	rc = au8522_rc_read(ir, 0xe1, -1, buf, 1);
-	if (rc < 0 || !(buf[0] & (1 << 4)))
+	if (rc < 0 || !(buf[0] & (1 << 4))) {
+		/* Be sure that IR is enabled */
+		au8522_rc_set(ir, 0xe0, 1 << 4);
 		return 0;
+	}
 
 	/* Something arrived. Get the data */
 	rc = au8522_rc_read(ir, 0xe3, 0x11, buf, sizeof(buf));
@@ -135,8 +147,6 @@
 	/* Disable IR */
 	au8522_rc_clear(ir, 0xe0, 1 << 4);
 
-	usleep_range(45000, 46000);
-
 	/* Enable IR */
 	au8522_rc_set(ir, 0xe0, 1 << 4);
 
@@ -243,10 +253,10 @@
 {
 	struct au0828_rc *ir = rc->priv;
 
+	cancel_delayed_work_sync(&ir->work);
+
 	/* Disable IR */
 	au8522_rc_clear(ir, 0xe0, 1 << 4);
-
-	cancel_delayed_work_sync(&ir->work);
 }
 
 static int au0828_probe_i2c_ir(struct au0828_dev *dev)
@@ -273,7 +283,7 @@
 	int err = -ENOMEM;
 	u16 i2c_rc_dev_addr = 0;
 
-	if (!dev->board.has_ir_i2c)
+	if (!dev->board.has_ir_i2c || disable_ir)
 		return 0;
 
 	i2c_rc_dev_addr = au0828_probe_i2c_ir(dev);
@@ -368,8 +378,13 @@
 	if (!ir)
 		return 0;
 
+	pr_info("Stopping RC\n");
+
 	cancel_delayed_work_sync(&ir->work);
 
+	/* Disable IR */
+	au8522_rc_clear(ir, 0xe0, 1 << 4);
+
 	return 0;
 }
 
@@ -380,6 +395,11 @@
 	if (!ir)
 		return 0;
 
+	pr_info("Restarting RC\n");
+
+	/* Enable IR */
+	au8522_rc_set(ir, 0xe0, 1 << 4);
+
 	schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
 
 	return 0;
diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c
index 63f5930..932d24f 100644
--- a/drivers/media/usb/au0828/au0828-vbi.c
+++ b/drivers/media/usb/au0828/au0828-vbi.c
@@ -21,13 +21,13 @@
    02110-1301, USA.
  */
 
+#include "au0828.h"
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 
-#include "au0828.h"
-
 static unsigned int vbibufs = 5;
 module_param(vbibufs, int, 0644);
 MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index ce55931..2e94235 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -28,16 +28,16 @@
  *
  */
 
+#include "au0828.h"
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/device.h>
-#include <linux/suspend.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
 #include <media/tuner.h>
-#include "au0828.h"
 #include "au0828-reg.h"
 
 static DEFINE_MUTEX(au0828_sysfs_lock);
@@ -53,7 +53,7 @@
 #define au0828_isocdbg(fmt, arg...) \
 do {\
 	if (isoc_debug) { \
-		printk(KERN_INFO "au0828 %s :"fmt, \
+		pr_info("au0828 %s :"fmt, \
 		       __func__ , ##arg);	   \
 	} \
   } while (0)
@@ -106,12 +106,12 @@
 static int check_dev(struct au0828_dev *dev)
 {
 	if (dev->dev_state & DEV_DISCONNECTED) {
-		printk(KERN_INFO "v4l2 ioctl: device not present\n");
+		pr_info("v4l2 ioctl: device not present\n");
 		return -ENODEV;
 	}
 
 	if (dev->dev_state & DEV_MISCONFIGURED) {
-		printk(KERN_INFO "v4l2 ioctl: device is misconfigured; "
+		pr_info("v4l2 ioctl: device is misconfigured; "
 		       "close and open it again\n");
 		return -EIO;
 	}
@@ -159,6 +159,7 @@
 		au0828_isocdbg("urb resubmit failed (error=%i)\n",
 			       urb->status);
 	}
+	dev->stream_state = STREAM_ON;
 }
 
 /*
@@ -198,6 +199,8 @@
 	dev->isoc_ctl.urb = NULL;
 	dev->isoc_ctl.transfer_buffer = NULL;
 	dev->isoc_ctl.num_bufs = 0;
+
+	dev->stream_state = STREAM_OFF;
 }
 
 /*
@@ -717,7 +720,7 @@
 	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		rc = videobuf_iolock(vq, &buf->vb, NULL);
 		if (rc < 0) {
-			printk(KERN_INFO "videobuf_iolock failed\n");
+			pr_info("videobuf_iolock failed\n");
 			goto fail;
 		}
 	}
@@ -730,7 +733,7 @@
 				      AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
 				      au0828_isoc_copy);
 		if (rc < 0) {
-			printk(KERN_INFO "au0828_init_isoc failed\n");
+			pr_info("au0828_init_isoc failed\n");
 			goto fail;
 		}
 	}
@@ -801,7 +804,7 @@
 		/* set au0828 interface0 to AS5 here again */
 		ret = usb_set_interface(d->usbdev, 0, 5);
 		if (ret < 0) {
-			printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
+			pr_info("Au0828 can't set alt setting to 5!\n");
 			return -EBUSY;
 		}
 	}
@@ -1090,7 +1093,7 @@
 		   USB bandwidth */
 		ret = usb_set_interface(dev->usbdev, 0, 0);
 		if (ret < 0)
-			printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
+			pr_info("Au0828 can't set alternate to 0!\n");
 	}
 	mutex_unlock(&dev->lock);
 
@@ -1344,7 +1347,7 @@
 		return rc;
 
 	if (videobuf_queue_is_busy(&fh->vb_vidq)) {
-		printk(KERN_INFO "%s queue busy\n", __func__);
+		pr_info("%s queue busy\n", __func__);
 		rc = -EBUSY;
 		goto out;
 	}
@@ -1868,6 +1871,69 @@
 	return rc;
 }
 
+void au0828_v4l2_suspend(struct au0828_dev *dev)
+{
+	struct urb *urb;
+	int i;
+
+	pr_info("stopping V4L2\n");
+
+	if (dev->stream_state == STREAM_ON) {
+		pr_info("stopping V4L2 active URBs\n");
+		au0828_analog_stream_disable(dev);
+		/* stop urbs */
+		for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+			urb = dev->isoc_ctl.urb[i];
+			if (urb) {
+				if (!irqs_disabled())
+					usb_kill_urb(urb);
+				else
+					usb_unlink_urb(urb);
+			}
+		}
+	}
+
+	if (dev->vid_timeout_running)
+		del_timer_sync(&dev->vid_timeout);
+	if (dev->vbi_timeout_running)
+		del_timer_sync(&dev->vbi_timeout);
+}
+
+void au0828_v4l2_resume(struct au0828_dev *dev)
+{
+	int i, rc;
+
+	pr_info("restarting V4L2\n");
+
+	if (dev->stream_state == STREAM_ON) {
+		au0828_stream_interrupt(dev);
+		au0828_init_tuner(dev);
+	}
+
+	if (dev->vid_timeout_running)
+		mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+	if (dev->vbi_timeout_running)
+		mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+
+	/* If we were doing ac97 instead of i2s, it would go here...*/
+	au0828_i2s_init(dev);
+
+	au0828_analog_stream_enable(dev);
+
+	if (!(dev->stream_state == STREAM_ON)) {
+		au0828_analog_stream_reset(dev);
+		/* submit urbs */
+		for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+			rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+			if (rc) {
+				au0828_isocdbg("submit of urb %i failed (error=%i)\n",
+					       i, rc);
+				au0828_uninit_isoc(dev);
+			}
+		}
+	}
+}
+
 static struct v4l2_file_operations au0828_v4l_fops = {
 	.owner      = THIS_MODULE,
 	.open       = au0828_v4l2_open,
@@ -1939,7 +2005,7 @@
 	retval = usb_set_interface(dev->usbdev,
 			interface->cur_altsetting->desc.bInterfaceNumber, 5);
 	if (retval != 0) {
-		printk(KERN_INFO "Failure setting usb interface0 to as5\n");
+		pr_info("Failure setting usb interface0 to as5\n");
 		return retval;
 	}
 
@@ -1963,7 +2029,7 @@
 		}
 	}
 	if (!(dev->isoc_in_endpointaddr)) {
-		printk(KERN_INFO "Could not locate isoc endpoint\n");
+		pr_info("Could not locate isoc endpoint\n");
 		kfree(dev);
 		return -ENODEV;
 	}
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index 29f0a56..53025e2 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -19,6 +19,8 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/usb.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -42,7 +44,6 @@
 #include "au0828-reg.h"
 #include "au0828-cards.h"
 
-#define DRIVER_NAME "au0828"
 #define URB_COUNT   16
 #define URB_BUFSIZE (0xe522)
 
@@ -89,6 +90,7 @@
 	unsigned char tuner_addr;
 	unsigned char i2c_clk_divider;
 	unsigned char has_ir_i2c:1;
+	unsigned char has_analog:1;
 	struct au0828_input input[AU0828_MAX_INPUT];
 
 };
@@ -266,8 +268,8 @@
 	char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc
 						   transfer */
 
-	/* USB / URB Related */
-	int		urb_streaming;
+	/* DVB USB / URB Related */
+	bool		urb_streaming, need_urb_start;
 	struct urb	*urbs[URB_COUNT];
 
 	/* Preallocated transfer digital transfer buffers */
@@ -311,22 +313,38 @@
 			   struct usb_interface *interface);
 int au0828_analog_stream_disable(struct au0828_dev *d);
 void au0828_analog_unregister(struct au0828_dev *dev);
+#ifdef CPTCFG_VIDEO_AU0828_V4L2
+void au0828_v4l2_suspend(struct au0828_dev *dev);
+void au0828_v4l2_resume(struct au0828_dev *dev);
+#else
+static inline void au0828_v4l2_suspend(struct au0828_dev *dev) { };
+static inline void au0828_v4l2_resume(struct au0828_dev *dev) { };
+#endif
 
 /* ----------------------------------------------------------- */
 /* au0828-dvb.c */
 extern int au0828_dvb_register(struct au0828_dev *dev);
 extern void au0828_dvb_unregister(struct au0828_dev *dev);
+void au0828_dvb_suspend(struct au0828_dev *dev);
+void au0828_dvb_resume(struct au0828_dev *dev);
 
 /* au0828-vbi.c */
 extern struct videobuf_queue_ops au0828_vbi_qops;
 
 #define dprintk(level, fmt, arg...)\
 	do { if (au0828_debug & level)\
-		printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
+		printk(KERN_DEBUG pr_fmt(fmt), ## arg);\
 	} while (0)
 
 /* au0828-input.c */
-int au0828_rc_register(struct au0828_dev *dev);
-void au0828_rc_unregister(struct au0828_dev *dev);
-int au0828_rc_suspend(struct au0828_dev *dev);
-int au0828_rc_resume(struct au0828_dev *dev);
+#ifdef CPTCFG_VIDEO_AU0828_RC
+extern int au0828_rc_register(struct au0828_dev *dev);
+extern void au0828_rc_unregister(struct au0828_dev *dev);
+extern int au0828_rc_suspend(struct au0828_dev *dev);
+extern int au0828_rc_resume(struct au0828_dev *dev);
+#else
+static inline int au0828_rc_register(struct au0828_dev *dev) { return 0; }
+static inline void au0828_rc_unregister(struct au0828_dev *dev) { }
+static inline int au0828_rc_suspend(struct au0828_dev *dev) { return 0; }
+static inline int au0828_rc_resume(struct au0828_dev *dev) { return 0; }
+#endif
diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c
index a428c10..40a6987 100644
--- a/drivers/media/usb/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c
@@ -1595,7 +1595,7 @@
 		if_freq = 16000000;
 	}
 
-	cx231xx_info("Enter IF=%zd\n",
+	cx231xx_info("Enter IF=%zu\n",
 			ARRAY_SIZE(Dif_set_array));
 	for (i = 0; i < ARRAY_SIZE(Dif_set_array); i++) {
 		if (Dif_set_array[i].if_freq == if_freq) {
@@ -2223,7 +2223,7 @@
 	if (status < 0)
 		return status;
 
-	tmp = le32_to_cpu(*((u32 *) value));
+	tmp = le32_to_cpu(*((__le32 *) value));
 
 	switch (mode) {
 	case POLARIS_AVMODE_ENXTERNAL_AV:
@@ -2444,7 +2444,7 @@
 	if (status > 0)
 		return status;
 
-	tmp = le32_to_cpu(*((u32 *) value));
+	tmp = le32_to_cpu(*((__le32 *) value));
 	tmp &= (~PWR_MODE_MASK);
 
 	value[0] = (u8) tmp;
@@ -2472,7 +2472,7 @@
 	if (status < 0)
 		return status;
 
-	tmp = le32_to_cpu(*((u32 *) value));
+	tmp = le32_to_cpu(*((__le32 *) value));
 	tmp |= ep_mask;
 	value[0] = (u8) tmp;
 	value[1] = (u8) (tmp >> 8);
@@ -2497,7 +2497,7 @@
 	if (status < 0)
 		return status;
 
-	tmp = le32_to_cpu(*((u32 *) value));
+	tmp = le32_to_cpu(*((__le32 *) value));
 	tmp &= (~ep_mask);
 	value[0] = (u8) tmp;
 	value[1] = (u8) (tmp >> 8);
@@ -2644,7 +2644,7 @@
 {
 	int status = 0;
 
-	gpio_val = cpu_to_le32(gpio_val);
+	gpio_val = (__force u32)cpu_to_le32(gpio_val);
 	status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&gpio_val, 4, 0, 0);
 
 	return status;
@@ -2652,7 +2652,7 @@
 
 static int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 *gpio_val)
 {
-	u32 tmp;
+	__le32 tmp;
 	int status = 0;
 
 	status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&tmp, 4, 0, 1);
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 8039b76..791f00c 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -705,7 +705,7 @@
 		},
 	},
 	[CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx] = {
-		.name = "Hauppauge WinTV 930C-HD (1113xx) / PCTV QuatroStick 521e",
+		.name = "Hauppauge WinTV 930C-HD (1113xx) / HVR-900H (111xxx) / PCTV QuatroStick 521e",
 		.tuner_type = TUNER_NXP_TDA18271,
 		.tuner_addr = 0x60,
 		.tuner_gpio = RDE250_XCV_TUNER,
@@ -744,7 +744,7 @@
 		} },
 	},
 	[CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx] = {
-		.name = "Hauppauge WinTV 930C-HD (1114xx) / PCTV QuatroStick 522e",
+		.name = "Hauppauge WinTV 930C-HD (1114xx) / HVR-901H (1114xx) / PCTV QuatroStick 522e",
 		.tuner_type = TUNER_ABSENT,
 		.tuner_addr = 0x60,
 		.tuner_gpio = RDE250_XCV_TUNER,
@@ -815,6 +815,12 @@
 	 .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx},
 	{USB_DEVICE(0x2040, 0xb131),
 	 .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx},
+	/* Hauppauge WinTV-HVR-900-H */
+	{USB_DEVICE(0x2040, 0xb138),
+	 .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx},
+	/* Hauppauge WinTV-HVR-901-H */
+	{USB_DEVICE(0x2040, 0xb139),
+	 .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx},
 	{USB_DEVICE(0x2040, 0xb140),
 	 .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
 	{USB_DEVICE(0x2040, 0xc200),
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index 513194a..180103e 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -1491,7 +1491,7 @@
 	if (status < 0)
 		return status;
 
-	tmp = le32_to_cpu(*((u32 *) value));
+	tmp = le32_to_cpu(*((__le32 *) value));
 	tmp |= mode;
 
 	value[0] = (u8) tmp;
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index 1fa7974..6c7b5e2 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -403,8 +403,6 @@
 
 int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
 {
-	int status = 0;
-
 	if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
 
 		struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
@@ -423,7 +421,7 @@
 
 	}
 
-	return status;
+	return 0;
 }
 
 int cx231xx_reset_analog_tuner(struct cx231xx *dev)
@@ -740,7 +738,7 @@
 			goto out_free;
 		}
 
-		dev->dvb->frontend->ops.i2c_gate_ctrl = 0;
+		dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
 		dvb->frontend->callback = cx231xx_tuner_callback;
@@ -773,7 +771,7 @@
 			goto out_free;
 		}
 
-		dev->dvb->frontend->ops.i2c_gate_ctrl = 0;
+		dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
 
 		/* define general-purpose callback pointer */
 		dvb->frontend->callback = cx231xx_tuner_callback;
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index 5152f0c..3d39fb7 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -31,6 +31,7 @@
 	  Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
 
 config DVB_USB_AF9035
+	depends on !BACKPORT_KERNEL_3_4
 	tristate "Afatech AF9035 DVB-T USB2.0 support"
 	depends on m
 	depends on DVB_USB_V2
@@ -45,6 +46,7 @@
 	  Say Y here to support the Afatech AF9035 based DVB USB receiver.
 
 config DVB_USB_ANYSEE
+	depends on !BACKPORT_KERNEL_3_4
 	tristate "Anysee DVB-T/C USB2.0 support"
 	depends on m
 	depends on DVB_USB_V2
@@ -154,3 +156,12 @@
 	help
 	  Say Y here to support the Realtek RTL28xxU DVB USB receiver.
 
+config DVB_USB_DVBSKY
+	depends on !BACKPORT_KERNEL_3_4
+	tristate "DVBSky USB support"
+	depends on m
+	depends on DVB_USB_V2
+	select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
+	select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
+	help
+	  Say Y here to support the USB receivers from DVBSky.
diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile
index 2e9bc9a..df732d8 100644
--- a/drivers/media/usb/dvb-usb-v2/Makefile
+++ b/drivers/media/usb/dvb-usb-v2/Makefile
@@ -37,6 +37,9 @@
 dvb-usb-rtl28xxu-objs := rtl28xxu.o
 obj-$(CPTCFG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
 
+dvb-usb-dvbsky-objs := dvbsky.o
+obj-$(CPTCFG_DVB_USB_DVBSKY) += dvb-usb-dvbsky.o
+
 ccflags-y += -I$(backport_srctree)/drivers/media/dvb-core
 ccflags-y += -I$(backport_srctree)/drivers/media/dvb-frontends
 ccflags-y += -I$(backport_srctree)/drivers/media/tuners
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index 308d86e..c9b5a2e 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -419,7 +419,7 @@
 	/* calculate checksum */
 	for (i = 0; i < AF9015_EEPROM_SIZE / sizeof(u32); i++) {
 		state->eeprom_sum *= GOLDEN_RATIO_PRIME_32;
-		state->eeprom_sum += le32_to_cpu(((u32 *)buf)[i]);
+		state->eeprom_sum += le32_to_cpu(((__le32 *)buf)[i]);
 	}
 
 	for (i = 0; i < AF9015_EEPROM_SIZE; i += 16)
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 7139c13..badc331 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -193,6 +193,92 @@
 	return af9035_wr_regs(d, reg, &val, 1);
 }
 
+static int af9035_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr,
+		void *platform_data, struct i2c_adapter *adapter)
+{
+	int ret, num;
+	struct state *state = d_to_priv(d);
+	struct i2c_client *client;
+	struct i2c_board_info board_info = {
+		.addr = addr,
+		.platform_data = platform_data,
+	};
+
+	strlcpy(board_info.type, type, I2C_NAME_SIZE);
+
+	/* find first free client */
+	for (num = 0; num < AF9035_I2C_CLIENT_MAX; num++) {
+		if (state->i2c_client[num] == NULL)
+			break;
+	}
+
+	dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
+
+	if (num == AF9035_I2C_CLIENT_MAX) {
+		dev_err(&d->udev->dev, "%s: I2C client out of index\n",
+				KBUILD_MODNAME);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	request_module(board_info.type);
+
+	/* register I2C device */
+	client = i2c_new_device(adapter, &board_info);
+	if (client == NULL || client->dev.driver == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	/* increase I2C driver usage count */
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	state->i2c_client[num] = client;
+	return 0;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static void af9035_del_i2c_dev(struct dvb_usb_device *d)
+{
+	int num;
+	struct state *state = d_to_priv(d);
+	struct i2c_client *client;
+
+	/* find last used client */
+	num = AF9035_I2C_CLIENT_MAX;
+	while (num--) {
+		if (state->i2c_client[num] != NULL)
+			break;
+	}
+
+	dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
+
+	if (num == -1) {
+		dev_err(&d->udev->dev, "%s: I2C client out of index\n",
+				KBUILD_MODNAME);
+		goto err;
+	}
+
+	client = state->i2c_client[num];
+
+	/* decrease I2C driver usage count */
+	module_put(client->dev.driver->owner);
+
+	/* unregister I2C device */
+	i2c_unregister_device(client);
+
+	state->i2c_client[num] = NULL;
+	return;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed\n", __func__);
+}
+
 static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
 		struct i2c_msg msg[], int num)
 {
@@ -204,7 +290,7 @@
 		return -EAGAIN;
 
 	/*
-	 * I2C sub header is 5 bytes long. Meaning of those bytes are:
+	 * AF9035 I2C sub header is 5 bytes long. Meaning of those bytes are:
 	 * 0: data len
 	 * 1: I2C addr << 1
 	 * 2: reg addr len
@@ -218,110 +304,156 @@
 	 * NOTE: As a firmware knows tuner type there is very small possibility
 	 * there could be some tuner I2C hacks done by firmware and this may
 	 * lead problems if firmware expects those bytes are used.
+	 *
+	 * TODO: Here is few hacks. AF9035 chip integrates AF9033 demodulator.
+	 * IT9135 chip integrates AF9033 demodulator and RF tuner. For dual
+	 * tuner devices, there is also external AF9033 demodulator connected
+	 * via external I2C bus. All AF9033 demod I2C traffic, both single and
+	 * dual tuner configuration, is covered by firmware - actual USB IO
+	 * looks just like a memory access.
+	 * In case of IT913x chip, there is own tuner driver. It is implemented
+	 * currently as a I2C driver, even tuner IP block is likely build
+	 * directly into the demodulator memory space and there is no own I2C
+	 * bus. I2C subsystem does not allow register multiple devices to same
+	 * bus, having same slave address. Due to that we reuse demod address,
+	 * shifted by one bit, on that case.
+	 *
+	 * For IT930x we use a different command and the sub header is
+	 * different as well:
+	 * 0: data len
+	 * 1: I2C bus (0x03 seems to be only value used)
+	 * 2: I2C addr << 1
 	 */
-	if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
-			(msg[1].flags & I2C_M_RD)) {
+#define AF9035_IS_I2C_XFER_WRITE_READ(_msg, _num) \
+	(_num == 2 && !(_msg[0].flags & I2C_M_RD) && (_msg[1].flags & I2C_M_RD))
+#define AF9035_IS_I2C_XFER_WRITE(_msg, _num) \
+	(_num == 1 && !(_msg[0].flags & I2C_M_RD))
+#define AF9035_IS_I2C_XFER_READ(_msg, _num) \
+	(_num == 1 && (_msg[0].flags & I2C_M_RD))
+
+	if (AF9035_IS_I2C_XFER_WRITE_READ(msg, num)) {
 		if (msg[0].len > 40 || msg[1].len > 40) {
 			/* TODO: correct limits > 40 */
 			ret = -EOPNOTSUPP;
-		} else if ((msg[0].addr == state->af9033_config[0].i2c_addr) ||
-			   (msg[0].addr == state->af9033_config[1].i2c_addr)) {
+		} else if ((msg[0].addr == state->af9033_i2c_addr[0]) ||
+			   (msg[0].addr == state->af9033_i2c_addr[1]) ||
+			   (state->chip_type == 0x9135)) {
 			/* demod access via firmware interface */
 			u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
 					msg[0].buf[2];
 
-			if (msg[0].addr == state->af9033_config[1].i2c_addr)
+			if (msg[0].addr == state->af9033_i2c_addr[1] ||
+			    msg[0].addr == (state->af9033_i2c_addr[1] >> 1))
 				reg |= 0x100000;
 
 			ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
 					msg[1].len);
 		} else {
-			/* I2C */
+			/* I2C write + read */
 			u8 buf[MAX_XFER_SIZE];
 			struct usb_req req = { CMD_I2C_RD, 0, 5 + msg[0].len,
 					buf, msg[1].len, msg[1].buf };
 
-			if (5 + msg[0].len > sizeof(buf)) {
-				dev_warn(&d->udev->dev,
-					 "%s: i2c xfer: len=%d is too big!\n",
-					 KBUILD_MODNAME, msg[0].len);
-				ret = -EOPNOTSUPP;
-				goto unlock;
+			if (state->chip_type == 0x9306) {
+				req.cmd = CMD_GENERIC_I2C_RD;
+				req.wlen = 3 + msg[0].len;
 			}
 			req.mbox |= ((msg[0].addr & 0x80)  >>  3);
+
 			buf[0] = msg[1].len;
-			buf[1] = msg[0].addr << 1;
-			buf[2] = 0x00; /* reg addr len */
-			buf[3] = 0x00; /* reg addr MSB */
-			buf[4] = 0x00; /* reg addr LSB */
-			memcpy(&buf[5], msg[0].buf, msg[0].len);
+			if (state->chip_type == 0x9306) {
+				buf[1] = 0x03; /* I2C bus */
+				buf[2] = msg[0].addr << 1;
+				memcpy(&buf[3], msg[0].buf, msg[0].len);
+			} else {
+				buf[1] = msg[0].addr << 1;
+				buf[2] = 0x00; /* reg addr len */
+				buf[3] = 0x00; /* reg addr MSB */
+				buf[4] = 0x00; /* reg addr LSB */
+				memcpy(&buf[5], msg[0].buf, msg[0].len);
+			}
 			ret = af9035_ctrl_msg(d, &req);
 		}
-	} else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+	} else if (AF9035_IS_I2C_XFER_WRITE(msg, num)) {
 		if (msg[0].len > 40) {
 			/* TODO: correct limits > 40 */
 			ret = -EOPNOTSUPP;
-		} else if ((msg[0].addr == state->af9033_config[0].i2c_addr) ||
-			   (msg[0].addr == state->af9033_config[1].i2c_addr)) {
+		} else if ((msg[0].addr == state->af9033_i2c_addr[0]) ||
+			   (msg[0].addr == state->af9033_i2c_addr[1]) ||
+			   (state->chip_type == 0x9135)) {
 			/* demod access via firmware interface */
 			u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
 					msg[0].buf[2];
 
-			if (msg[0].addr == state->af9033_config[1].i2c_addr)
+			if (msg[0].addr == state->af9033_i2c_addr[1] ||
+			    msg[0].addr == (state->af9033_i2c_addr[1] >> 1))
 				reg |= 0x100000;
 
 			ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
 					msg[0].len - 3);
 		} else {
-			/* I2C */
+			/* I2C write */
 			u8 buf[MAX_XFER_SIZE];
 			struct usb_req req = { CMD_I2C_WR, 0, 5 + msg[0].len,
 					buf, 0, NULL };
 
-			if (5 + msg[0].len > sizeof(buf)) {
-				dev_warn(&d->udev->dev,
-					 "%s: i2c xfer: len=%d is too big!\n",
-					 KBUILD_MODNAME, msg[0].len);
-				ret = -EOPNOTSUPP;
-				goto unlock;
+			if (state->chip_type == 0x9306) {
+				req.cmd = CMD_GENERIC_I2C_WR;
+				req.wlen = 3 + msg[0].len;
 			}
+
 			req.mbox |= ((msg[0].addr & 0x80)  >>  3);
 			buf[0] = msg[0].len;
-			buf[1] = msg[0].addr << 1;
-			buf[2] = 0x00; /* reg addr len */
-			buf[3] = 0x00; /* reg addr MSB */
-			buf[4] = 0x00; /* reg addr LSB */
-			memcpy(&buf[5], msg[0].buf, msg[0].len);
+			if (state->chip_type == 0x9306) {
+				buf[1] = 0x03; /* I2C bus */
+				buf[2] = msg[0].addr << 1;
+				memcpy(&buf[3], msg[0].buf, msg[0].len);
+			} else {
+				buf[1] = msg[0].addr << 1;
+				buf[2] = 0x00; /* reg addr len */
+				buf[3] = 0x00; /* reg addr MSB */
+				buf[4] = 0x00; /* reg addr LSB */
+				memcpy(&buf[5], msg[0].buf, msg[0].len);
+			}
 			ret = af9035_ctrl_msg(d, &req);
 		}
-	} else if (num == 1 && (msg[0].flags & I2C_M_RD)) {
+	} else if (AF9035_IS_I2C_XFER_READ(msg, num)) {
 		if (msg[0].len > 40) {
 			/* TODO: correct limits > 40 */
 			ret = -EOPNOTSUPP;
 		} else {
-			/* I2C */
+			/* I2C read */
 			u8 buf[5];
 			struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
-					buf, msg[0].len, msg[0].buf };
+						buf, msg[0].len, msg[0].buf };
+
+			if (state->chip_type == 0x9306) {
+				req.cmd = CMD_GENERIC_I2C_RD;
+				req.wlen = 3;
+			}
 			req.mbox |= ((msg[0].addr & 0x80)  >>  3);
 			buf[0] = msg[0].len;
-			buf[1] = msg[0].addr << 1;
-			buf[2] = 0x00; /* reg addr len */
-			buf[3] = 0x00; /* reg addr MSB */
-			buf[4] = 0x00; /* reg addr LSB */
+			if (state->chip_type == 0x9306) {
+				buf[1] = 0x03; /* I2C bus */
+				buf[2] = msg[0].addr << 1;
+			} else {
+				buf[1] = msg[0].addr << 1;
+				buf[2] = 0x00; /* reg addr len */
+				buf[3] = 0x00; /* reg addr MSB */
+				buf[4] = 0x00; /* reg addr LSB */
+			}
 			ret = af9035_ctrl_msg(d, &req);
 		}
 	} else {
 		/*
 		 * We support only three kind of I2C transactions:
-		 * 1) 1 x read + 1 x write (repeated start)
+		 * 1) 1 x write + 1 x read (repeated start)
 		 * 2) 1 x write
 		 * 3) 1 x read
 		 */
 		ret = -EOPNOTSUPP;
 	}
 
-unlock:
 	mutex_unlock(&d->i2c_mutex);
 
 	if (ret < 0)
@@ -371,6 +503,9 @@
 		else
 			*name = AF9035_FIRMWARE_IT9135_V1;
 		state->eeprom_addr = EEPROM_BASE_IT9135;
+	} else if (state->chip_type == 0x9306) {
+		*name = AF9035_FIRMWARE_IT9303;
+		state->eeprom_addr = EEPROM_BASE_IT9135;
 	} else {
 		*name = AF9035_FIRMWARE_AF9035;
 		state->eeprom_addr = EEPROM_BASE_AF9035;
@@ -536,6 +671,7 @@
 	u8 tmp;
 	struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
 	struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf };
+
 	dev_dbg(&d->udev->dev, "%s:\n", __func__);
 
 	/*
@@ -579,7 +715,8 @@
 		if (!tmp)
 			tmp = 0x3a;
 
-		if (state->chip_type == 0x9135) {
+		if ((state->chip_type == 0x9135) ||
+				(state->chip_type == 0x9306)) {
 			ret = af9035_wr_reg(d, 0x004bfb, tmp);
 			if (ret < 0)
 				goto err;
@@ -640,23 +777,26 @@
 	u16 tmp16, addr;
 
 	/* demod I2C "address" */
-	state->af9033_config[0].i2c_addr = 0x38;
-	state->af9033_config[1].i2c_addr = 0x3a;
+	state->af9033_i2c_addr[0] = 0x38;
+	state->af9033_i2c_addr[1] = 0x3a;
 	state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
 	state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
 	state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
 	state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
 
-	/* eeprom memory mapped location */
 	if (state->chip_type == 0x9135) {
+		/* feed clock for integrated RF tuner */
+		state->af9033_config[0].dyn0_clk = true;
+		state->af9033_config[1].dyn0_clk = true;
+
 		if (state->chip_version == 0x02) {
 			state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60;
 			state->af9033_config[1].tuner = AF9033_TUNER_IT9135_60;
-			tmp16 = 0x00461d;
+			tmp16 = 0x00461d; /* eeprom memory mapped location */
 		} else {
 			state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38;
 			state->af9033_config[1].tuner = AF9033_TUNER_IT9135_38;
-			tmp16 = 0x00461b;
+			tmp16 = 0x00461b; /* eeprom memory mapped location */
 		}
 
 		/* check if eeprom exists */
@@ -668,8 +808,16 @@
 			dev_dbg(&d->udev->dev, "%s: no eeprom\n", __func__);
 			goto skip_eeprom;
 		}
+	} else if (state->chip_type == 0x9306) {
+		/*
+		 * IT930x is an USB bridge, only single demod-single tuner
+		 * configurations seen so far.
+		 */
+		return 0;
 	}
 
+
+
 	/* check if there is dual tuners */
 	ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp);
 	if (ret < 0)
@@ -690,7 +838,7 @@
 			goto err;
 
 		if (tmp)
-			state->af9033_config[1].i2c_addr = tmp;
+			state->af9033_i2c_addr[1] = tmp;
 
 		dev_dbg(&d->udev->dev, "%s: 2nd demod I2C addr=%02x\n",
 				__func__, tmp);
@@ -799,25 +947,6 @@
 		addr += 0x10; /* shift for the 2nd tuner params */
 	}
 
-	/*
-	 * These AVerMedia devices has a bad EEPROM content :-(
-	 * Override some wrong values here.
-	 */
-	if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA) {
-		switch (le16_to_cpu(d->udev->descriptor.idProduct)) {
-		case USB_PID_AVERMEDIA_A835B_1835:
-		case USB_PID_AVERMEDIA_A835B_2835:
-		case USB_PID_AVERMEDIA_A835B_3835:
-			dev_info(&d->udev->dev,
-				 "%s: overriding tuner from %02x to %02x\n",
-				 KBUILD_MODNAME, state->af9033_config[0].tuner,
-				 AF9033_TUNER_IT9135_60);
-
-			state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60;
-			break;
-		}
-	}
-
 skip_eeprom:
 	/* get demod clock */
 	ret = af9035_rd_reg(d, 0x00d800, &tmp);
@@ -990,6 +1119,7 @@
 static int af9035_get_adapter_count(struct dvb_usb_device *d)
 {
 	struct state *state = d_to_priv(d);
+
 	return state->dual_mode + 1;
 }
 
@@ -998,7 +1128,8 @@
 	struct state *state = adap_to_priv(adap);
 	struct dvb_usb_device *d = adap_to_d(adap);
 	int ret;
-	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
 
 	if (!state->af9033_config[adap->id].tuner) {
 		/* unsupported tuner */
@@ -1006,9 +1137,13 @@
 		goto err;
 	}
 
-	/* attach demodulator */
-	adap->fe[0] = dvb_attach(af9033_attach, &state->af9033_config[adap->id],
-			&d->i2c_adap, &state->ops);
+	state->af9033_config[adap->id].fe = &adap->fe[0];
+	state->af9033_config[adap->id].ops = &state->ops;
+	ret = af9035_add_i2c_dev(d, "af9033", state->af9033_i2c_addr[adap->id],
+			&state->af9033_config[adap->id], &d->i2c_adap);
+	if (ret)
+		goto err;
+
 	if (adap->fe[0] == NULL) {
 		ret = -ENODEV;
 		goto err;
@@ -1026,6 +1161,78 @@
 	return ret;
 }
 
+static int it930x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	int ret;
+	struct si2168_config si2168_config;
+	struct i2c_adapter *adapter;
+
+	dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
+
+	si2168_config.i2c_adapter = &adapter;
+	si2168_config.fe = &adap->fe[0];
+	si2168_config.ts_mode = SI2168_TS_SERIAL;
+
+	state->af9033_config[adap->id].fe = &adap->fe[0];
+	state->af9033_config[adap->id].ops = &state->ops;
+	ret = af9035_add_i2c_dev(d, "si2168", 0x67, &si2168_config,
+				&d->i2c_adap);
+	if (ret)
+		goto err;
+
+	if (adap->fe[0] == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+	state->i2c_adapter_demod = adapter;
+
+	return 0;
+
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+static int af9035_frontend_detach(struct dvb_usb_adapter *adap)
+{
+	struct state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	int demod2;
+
+	dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
+
+	/*
+	 * For dual tuner devices we have to resolve 2nd demod client, as there
+	 * is two different kind of tuner drivers; one is using I2C binding
+	 * and the other is using DVB attach/detach binding.
+	 */
+	switch (state->af9033_config[adap->id].tuner) {
+	case AF9033_TUNER_IT9135_38:
+	case AF9033_TUNER_IT9135_51:
+	case AF9033_TUNER_IT9135_52:
+	case AF9033_TUNER_IT9135_60:
+	case AF9033_TUNER_IT9135_61:
+	case AF9033_TUNER_IT9135_62:
+		demod2 = 2;
+		break;
+	default:
+		demod2 = 1;
+	}
+
+	if (adap->id == 1) {
+		if (state->i2c_client[demod2])
+			af9035_del_i2c_dev(d);
+	} else if (adap->id == 0) {
+		if (state->i2c_client[0])
+			af9035_del_i2c_dev(d);
+	}
+
+	return 0;
+}
+
 static struct tua9001_config af9035_tua9001_config = {
 	.i2c_addr = 0x60,
 };
@@ -1084,7 +1291,8 @@
 	struct dvb_frontend *fe;
 	struct i2c_msg msg[1];
 	u8 tuner_addr;
-	dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+	dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
 
 	/*
 	 * XXX: Hack used in that function: we abuse unused I2C address bit [7]
@@ -1243,14 +1451,53 @@
 	case AF9033_TUNER_IT9135_38:
 	case AF9033_TUNER_IT9135_51:
 	case AF9033_TUNER_IT9135_52:
+	{
+		struct it913x_config it913x_config = {
+			.fe = adap->fe[0],
+			.chip_ver = 1,
+		};
+
+		if (state->dual_mode) {
+			if (adap->id == 0)
+				it913x_config.role = IT913X_ROLE_DUAL_MASTER;
+			else
+				it913x_config.role = IT913X_ROLE_DUAL_SLAVE;
+		}
+
+		ret = af9035_add_i2c_dev(d, "it913x",
+				state->af9033_i2c_addr[adap->id] >> 1,
+				&it913x_config, &d->i2c_adap);
+		if (ret)
+			goto err;
+
+		fe = adap->fe[0];
+		break;
+	}
 	case AF9033_TUNER_IT9135_60:
 	case AF9033_TUNER_IT9135_61:
 	case AF9033_TUNER_IT9135_62:
-		/* attach tuner */
-		fe = dvb_attach(it913x_attach, adap->fe[0], &d->i2c_adap,
-				state->af9033_config[adap->id].i2c_addr,
-				state->af9033_config[0].tuner);
+	{
+		struct it913x_config it913x_config = {
+			.fe = adap->fe[0],
+			.chip_ver = 2,
+		};
+
+		if (state->dual_mode) {
+			if (adap->id == 0)
+				it913x_config.role = IT913X_ROLE_DUAL_MASTER;
+			else
+				it913x_config.role = IT913X_ROLE_DUAL_SLAVE;
+		}
+
+		ret = af9035_add_i2c_dev(d, "it913x",
+				state->af9033_i2c_addr[adap->id] >> 1,
+				&it913x_config, &d->i2c_adap);
+		if (ret)
+			goto err;
+
+		fe = adap->fe[0];
 		break;
+	}
 	default:
 		fe = NULL;
 	}
@@ -1268,6 +1515,119 @@
 	return ret;
 }
 
+static int it930x_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	int ret;
+	struct si2157_config si2157_config;
+
+	dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
+
+	/* I2C master bus 2 clock speed 300k */
+	ret = af9035_wr_reg(d, 0x00f6a7, 0x07);
+	if (ret < 0)
+		goto err;
+
+	/* I2C master bus 1,3 clock speed 300k */
+	ret = af9035_wr_reg(d, 0x00f103, 0x07);
+	if (ret < 0)
+		goto err;
+
+	/* set gpio11 low */
+	ret = af9035_wr_reg_mask(d, 0xd8d4, 0x01, 0x01);
+	if (ret < 0)
+		goto err;
+
+	ret = af9035_wr_reg_mask(d, 0xd8d5, 0x01, 0x01);
+	if (ret < 0)
+		goto err;
+
+	ret = af9035_wr_reg_mask(d, 0xd8d3, 0x01, 0x01);
+	if (ret < 0)
+		goto err;
+
+	/* Tuner enable using gpiot2_en, gpiot2_on and gpiot2_o (reset) */
+	ret = af9035_wr_reg_mask(d, 0xd8b8, 0x01, 0x01);
+	if (ret < 0)
+		goto err;
+
+	ret = af9035_wr_reg_mask(d, 0xd8b9, 0x01, 0x01);
+	if (ret < 0)
+		goto err;
+
+	ret = af9035_wr_reg_mask(d, 0xd8b7, 0x00, 0x01);
+	if (ret < 0)
+		goto err;
+
+	msleep(200);
+
+	ret = af9035_wr_reg_mask(d, 0xd8b7, 0x01, 0x01);
+	if (ret < 0)
+		goto err;
+
+	memset(&si2157_config, 0, sizeof(si2157_config));
+	si2157_config.fe = adap->fe[0];
+	ret = af9035_add_i2c_dev(d, "si2157", 0x63,
+			&si2157_config, state->i2c_adapter_demod);
+
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+
+static int it930x_tuner_detach(struct dvb_usb_adapter *adap)
+{
+	struct state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+
+	dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
+
+	if (adap->id == 1) {
+		if (state->i2c_client[3])
+			af9035_del_i2c_dev(d);
+	} else if (adap->id == 0) {
+		if (state->i2c_client[1])
+			af9035_del_i2c_dev(d);
+	}
+
+	return 0;
+}
+
+
+static int af9035_tuner_detach(struct dvb_usb_adapter *adap)
+{
+	struct state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+
+	dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
+
+	switch (state->af9033_config[adap->id].tuner) {
+	case AF9033_TUNER_IT9135_38:
+	case AF9033_TUNER_IT9135_51:
+	case AF9033_TUNER_IT9135_52:
+	case AF9033_TUNER_IT9135_60:
+	case AF9033_TUNER_IT9135_61:
+	case AF9033_TUNER_IT9135_62:
+		if (adap->id == 1) {
+			if (state->i2c_client[3])
+				af9035_del_i2c_dev(d);
+		} else if (adap->id == 0) {
+			if (state->i2c_client[1])
+				af9035_del_i2c_dev(d);
+		}
+	}
+
+	return 0;
+}
+
 static int af9035_init(struct dvb_usb_device *d)
 {
 	struct state *state = d_to_priv(d);
@@ -1315,6 +1675,89 @@
 	return ret;
 }
 
+static int it930x_init(struct dvb_usb_device *d)
+{
+	struct state *state = d_to_priv(d);
+	int ret, i;
+	u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 816) * 188 / 4;
+	u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4;
+	struct reg_val_mask tab[] = {
+		{ 0x00da1a, 0x00, 0x01 }, /* ignore_sync_byte */
+		{ 0x00f41f, 0x04, 0x04 }, /* dvbt_inten */
+		{ 0x00da10, 0x00, 0x01 }, /* mpeg_full_speed */
+		{ 0x00f41a, 0x01, 0x01 }, /* dvbt_en */
+		{ 0x00da1d, 0x01, 0x01 }, /* mp2_sw_rst, reset EP4 */
+		{ 0x00dd11, 0x00, 0x20 }, /* ep4_tx_en, disable EP4 */
+		{ 0x00dd13, 0x00, 0x20 }, /* ep4_tx_nak, disable EP4 NAK */
+		{ 0x00dd11, 0x20, 0x20 }, /* ep4_tx_en, enable EP4 */
+		{ 0x00dd11, 0x00, 0x40 }, /* ep5_tx_en, disable EP5 */
+		{ 0x00dd13, 0x00, 0x40 }, /* ep5_tx_nak, disable EP5 NAK */
+		{ 0x00dd11, state->dual_mode << 6, 0x40 }, /* enable EP5 */
+		{ 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
+		{ 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
+		{ 0x00dd0c, packet_size, 0xff},
+		{ 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
+		{ 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
+		{ 0x00dd0d, packet_size, 0xff },
+		{ 0x00da1d, 0x00, 0x01 }, /* mp2_sw_rst, disable */
+		{ 0x00d833, 0x01, 0xff }, /* slew rate ctrl: slew rate boosts */
+		{ 0x00d830, 0x00, 0xff }, /* Bit 0 of output driving control */
+		{ 0x00d831, 0x01, 0xff }, /* Bit 1 of output driving control */
+		{ 0x00d832, 0x00, 0xff }, /* Bit 2 of output driving control */
+
+		/* suspend gpio1 for TS-C */
+		{ 0x00d8b0, 0x01, 0xff }, /* gpio1 */
+		{ 0x00d8b1, 0x01, 0xff }, /* gpio1 */
+		{ 0x00d8af, 0x00, 0xff }, /* gpio1 */
+
+		/* suspend gpio7 for TS-D */
+		{ 0x00d8c4, 0x01, 0xff }, /* gpio7 */
+		{ 0x00d8c5, 0x01, 0xff }, /* gpio7 */
+		{ 0x00d8c3, 0x00, 0xff }, /* gpio7 */
+
+		/* suspend gpio13 for TS-B */
+		{ 0x00d8dc, 0x01, 0xff }, /* gpio13 */
+		{ 0x00d8dd, 0x01, 0xff }, /* gpio13 */
+		{ 0x00d8db, 0x00, 0xff }, /* gpio13 */
+
+		/* suspend gpio14 for TS-E */
+		{ 0x00d8e4, 0x01, 0xff }, /* gpio14 */
+		{ 0x00d8e5, 0x01, 0xff }, /* gpio14 */
+		{ 0x00d8e3, 0x00, 0xff }, /* gpio14 */
+
+		/* suspend gpio15 for TS-A */
+		{ 0x00d8e8, 0x01, 0xff }, /* gpio15 */
+		{ 0x00d8e9, 0x01, 0xff }, /* gpio15 */
+		{ 0x00d8e7, 0x00, 0xff }, /* gpio15 */
+
+		{ 0x00da58, 0x00, 0x01 }, /* ts_in_src, serial */
+		{ 0x00da73, 0x01, 0xff }, /* ts0_aggre_mode */
+		{ 0x00da78, 0x47, 0xff }, /* ts0_sync_byte */
+		{ 0x00da4c, 0x01, 0xff }, /* ts0_en */
+		{ 0x00da5a, 0x1f, 0xff }, /* ts_fail_ignore */
+	};
+
+	dev_dbg(&d->udev->dev,
+			"%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
+			__func__, d->udev->speed, frame_size, packet_size);
+
+	/* init endpoints */
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = af9035_wr_reg_mask(d, tab[i].reg,
+				tab[i].val, tab[i].mask);
+
+		if (ret < 0)
+			goto err;
+	}
+
+	return 0;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+
 #if IS_ENABLED(CPTCFG_RC_CORE)
 static int af9035_rc_query(struct dvb_usb_device *d)
 {
@@ -1409,6 +1852,7 @@
 		struct usb_data_stream_properties *stream)
 {
 	struct dvb_usb_device *d = fe_to_d(fe);
+
 	dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, fe_to_adap(fe)->id);
 
 	if (d->udev->speed == USB_SPEED_FULL)
@@ -1486,7 +1930,9 @@
 	.i2c_algo = &af9035_i2c_algo,
 	.read_config = af9035_read_config,
 	.frontend_attach = af9035_frontend_attach,
+	.frontend_detach = af9035_frontend_detach,
 	.tuner_attach = af9035_tuner_attach,
+	.tuner_detach = af9035_tuner_detach,
 	.init = af9035_init,
 	.get_rc_config = af9035_get_rc_config,
 	.get_stream_config = af9035_get_stream_config,
@@ -1515,6 +1961,37 @@
 	},
 };
 
+static const struct dvb_usb_device_properties it930x_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct state),
+
+	.generic_bulk_ctrl_endpoint = 0x02,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.identify_state = af9035_identify_state,
+	.download_firmware = af9035_download_firmware,
+
+	.i2c_algo = &af9035_i2c_algo,
+	.read_config = af9035_read_config,
+	.frontend_attach = it930x_frontend_attach,
+	.frontend_detach = af9035_frontend_detach,
+	.tuner_attach = it930x_tuner_attach,
+	.tuner_detach = it930x_tuner_detach,
+	.init = it930x_init,
+	.get_stream_config = af9035_get_stream_config,
+
+	.get_adapter_count = af9035_get_adapter_count,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_BULK(0x84, 4, 816 * 188),
+		}, {
+			.stream = DVB_USB_STREAM_BULK(0x85, 4, 816 * 188),
+		},
+	},
+};
+
 static const struct usb_device_id af9035_id_table[] = {
 	/* AF9035 devices */
 	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035,
@@ -1568,17 +2045,21 @@
 	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
 		&af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2",
 							RC_MAP_IT913X_V1) },
+	/* IT930x devices */
+	{ DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303,
+		&it930x_props, "ITE 9303 Generic", NULL) },
 	/* XXX: that same ID [0ccd:0099] is used by af9015 driver too */
 	{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099,
-		&af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", NULL) },
+		&af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)",
+		NULL) },
 	{ DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a05,
 		&af9035_props, "Leadtek WinFast DTV Dongle Dual", NULL) },
 	{ DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xf900,
 		&af9035_props, "Hauppauge WinTV-MiniStick 2", NULL) },
 	{ DVB_USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_78E,
-		&af9035_props, "PCTV 78e", RC_MAP_IT913X_V1) },
+		&af9035_props, "PCTV AndroiDTV (78e)", RC_MAP_IT913X_V1) },
 	{ DVB_USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_79E,
-		&af9035_props, "PCTV 79e", RC_MAP_IT913X_V2) },
+		&af9035_props, "PCTV microStick (79e)", RC_MAP_IT913X_V2) },
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, af9035_id_table);
@@ -1603,3 +2084,4 @@
 MODULE_FIRMWARE(AF9035_FIRMWARE_AF9035);
 MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V1);
 MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V2);
+MODULE_FIRMWARE(AF9035_FIRMWARE_IT9303);
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h
index c21902f..416a97f 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.h
+++ b/drivers/media/usb/dvb-usb-v2/af9035.h
@@ -30,7 +30,9 @@
 #include "mxl5007t.h"
 #include "tda18218.h"
 #include "fc2580.h"
-#include "tuner_it913x.h"
+#include "it913x.h"
+#include "si2168.h"
+#include "si2157.h"
 
 struct reg_val {
 	u32 reg;
@@ -61,9 +63,12 @@
 	u16 chip_type;
 	u8 dual_mode:1;
 	u16 eeprom_addr;
+	u8 af9033_i2c_addr[2];
 	struct af9033_config af9033_config[2];
-
 	struct af9033_ops ops;
+	#define AF9035_I2C_CLIENT_MAX 4
+	struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX];
+	struct i2c_adapter *i2c_adapter_demod;
 };
 
 static const u32 clock_lut_af9035[] = {
@@ -97,6 +102,7 @@
 #define AF9035_FIRMWARE_AF9035 "dvb-usb-af9035-02.fw"
 #define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw"
 #define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw"
+#define AF9035_FIRMWARE_IT9303 "dvb-usb-it9303-01.fw"
 
 /*
  * eeprom is memory mapped as read only. Writing that memory mapped address
@@ -138,5 +144,7 @@
 #define CMD_FW_DL_BEGIN             0x24
 #define CMD_FW_DL_END               0x25
 #define CMD_FW_SCATTER_WR           0x29
+#define CMD_GENERIC_I2C_RD          0x2a
+#define CMD_GENERIC_I2C_WR          0x2b
 
 #endif
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index c60a454..8c5ec72 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -332,7 +332,6 @@
 };
 
 static struct tda18212_config anysee_tda18212_config = {
-	.i2c_address = (0xc0 >> 1),
 	.if_dvbt_6 = 4150,
 	.if_dvbt_7 = 4150,
 	.if_dvbt_8 = 4150,
@@ -340,7 +339,6 @@
 };
 
 static struct tda18212_config anysee_tda18212_config2 = {
-	.i2c_address = 0x60 /* (0xc0 >> 1) */,
 	.if_dvbt_6 = 3550,
 	.if_dvbt_7 = 3700,
 	.if_dvbt_8 = 4150,
@@ -632,6 +630,92 @@
 	return ret;
 }
 
+static int anysee_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr,
+		void *platform_data)
+{
+	int ret, num;
+	struct anysee_state *state = d_to_priv(d);
+	struct i2c_client *client;
+	struct i2c_adapter *adapter = &d->i2c_adap;
+	struct i2c_board_info board_info = {
+		.addr = addr,
+		.platform_data = platform_data,
+	};
+
+	strlcpy(board_info.type, type, I2C_NAME_SIZE);
+
+	/* find first free client */
+	for (num = 0; num < ANYSEE_I2C_CLIENT_MAX; num++) {
+		if (state->i2c_client[num] == NULL)
+			break;
+	}
+
+	dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
+
+	if (num == ANYSEE_I2C_CLIENT_MAX) {
+		dev_err(&d->udev->dev, "%s: I2C client out of index\n",
+				KBUILD_MODNAME);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	request_module(board_info.type);
+
+	/* register I2C device */
+	client = i2c_new_device(adapter, &board_info);
+	if (client == NULL || client->dev.driver == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	/* increase I2C driver usage count */
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	state->i2c_client[num] = client;
+	return 0;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+	return ret;
+}
+
+static void anysee_del_i2c_dev(struct dvb_usb_device *d)
+{
+	int num;
+	struct anysee_state *state = d_to_priv(d);
+	struct i2c_client *client;
+
+	/* find last used client */
+	num = ANYSEE_I2C_CLIENT_MAX;
+	while (num--) {
+		if (state->i2c_client[num] != NULL)
+			break;
+	}
+
+	dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num);
+
+	if (num == -1) {
+		dev_err(&d->udev->dev, "%s: I2C client out of index\n",
+				KBUILD_MODNAME);
+		goto err;
+	}
+
+	client = state->i2c_client[num];
+
+	/* decrease I2C driver usage count */
+	module_put(client->dev.driver->owner);
+
+	/* unregister I2C device */
+	i2c_unregister_device(client);
+
+	state->i2c_client[num] = NULL;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed\n", __func__);
+}
+
 static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	struct anysee_state *state = adap_to_priv(adap);
@@ -640,12 +724,12 @@
 	u8 tmp;
 	struct i2c_msg msg[2] = {
 		{
-			.addr = anysee_tda18212_config.i2c_address,
+			.addr = 0x60,
 			.flags = 0,
 			.len = 1,
 			.buf = "\x00",
 		}, {
-			.addr = anysee_tda18212_config.i2c_address,
+			.addr = 0x60,
 			.flags = I2C_M_RD,
 			.len = 1,
 			.buf = &tmp,
@@ -723,9 +807,11 @@
 		/* probe TDA18212 */
 		tmp = 0;
 		ret = i2c_transfer(&d->i2c_adap, msg, 2);
-		if (ret == 2 && tmp == 0xc7)
+		if (ret == 2 && tmp == 0xc7) {
 			dev_dbg(&d->udev->dev, "%s: TDA18212 found\n",
 					__func__);
+			state->has_tda18212 = true;
+		}
 		else
 			tmp = 0;
 
@@ -939,46 +1025,63 @@
 		 * fails attach old simple PLL. */
 
 		/* attach tuner */
-		fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
-				&anysee_tda18212_config);
+		if (state->has_tda18212) {
+			struct tda18212_config tda18212_config =
+					anysee_tda18212_config;
 
-		if (fe && adap->fe[1]) {
-			/* attach tuner for 2nd FE */
-			fe = dvb_attach(tda18212_attach, adap->fe[1],
-					&d->i2c_adap, &anysee_tda18212_config);
-			break;
-		} else if (fe) {
-			break;
-		}
+			tda18212_config.fe = adap->fe[0];
+			ret = anysee_add_i2c_dev(d, "tda18212", 0x60,
+					&tda18212_config);
+			if (ret)
+				goto err;
 
-		/* attach tuner */
-		fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1),
-				&d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+			/* copy tuner ops for 2nd FE as tuner is shared */
+			if (adap->fe[1]) {
+				adap->fe[1]->tuner_priv =
+						adap->fe[0]->tuner_priv;
+				memcpy(&adap->fe[1]->ops.tuner_ops,
+						&adap->fe[0]->ops.tuner_ops,
+						sizeof(struct dvb_tuner_ops));
+			}
 
-		if (fe && adap->fe[1]) {
-			/* attach tuner for 2nd FE */
-			fe = dvb_attach(dvb_pll_attach, adap->fe[1],
+			return 0;
+		} else {
+			/* attach tuner */
+			fe = dvb_attach(dvb_pll_attach, adap->fe[0],
 					(0xc0 >> 1), &d->i2c_adap,
 					DVB_PLL_SAMSUNG_DTOS403IH102A);
+
+			if (fe && adap->fe[1]) {
+				/* attach tuner for 2nd FE */
+				fe = dvb_attach(dvb_pll_attach, adap->fe[1],
+						(0xc0 >> 1), &d->i2c_adap,
+						DVB_PLL_SAMSUNG_DTOS403IH102A);
+			}
 		}
 
 		break;
 	case ANYSEE_HW_508TC: /* 18 */
 	case ANYSEE_HW_508PTC: /* 21 */
+	{
 		/* E7 TC */
 		/* E7 PTC */
+		struct tda18212_config tda18212_config = anysee_tda18212_config;
 
-		/* attach tuner */
-		fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
-				&anysee_tda18212_config);
+		tda18212_config.fe = adap->fe[0];
+		ret = anysee_add_i2c_dev(d, "tda18212", 0x60, &tda18212_config);
+		if (ret)
+			goto err;
 
-		if (fe) {
-			/* attach tuner for 2nd FE */
-			fe = dvb_attach(tda18212_attach, adap->fe[1],
-					&d->i2c_adap, &anysee_tda18212_config);
+		/* copy tuner ops for 2nd FE as tuner is shared */
+		if (adap->fe[1]) {
+			adap->fe[1]->tuner_priv = adap->fe[0]->tuner_priv;
+			memcpy(&adap->fe[1]->ops.tuner_ops,
+					&adap->fe[0]->ops.tuner_ops,
+					sizeof(struct dvb_tuner_ops));
 		}
 
-		break;
+		return 0;
+	}
 	case ANYSEE_HW_508S2: /* 19 */
 	case ANYSEE_HW_508PS2: /* 22 */
 		/* E7 S2 */
@@ -997,13 +1100,18 @@
 		break;
 
 	case ANYSEE_HW_508T2C: /* 20 */
+	{
 		/* E7 T2C */
+		struct tda18212_config tda18212_config =
+				anysee_tda18212_config2;
 
-		/* attach tuner */
-		fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
-				&anysee_tda18212_config2);
+		tda18212_config.fe = adap->fe[0];
+		ret = anysee_add_i2c_dev(d, "tda18212", 0x60, &tda18212_config);
+		if (ret)
+			goto err;
 
-		break;
+		return 0;
+	}
 	default:
 		fe = NULL;
 	}
@@ -1012,7 +1120,7 @@
 		ret = 0;
 	else
 		ret = -ENODEV;
-
+err:
 	return ret;
 }
 
@@ -1270,6 +1378,11 @@
 
 static void anysee_exit(struct dvb_usb_device *d)
 {
+	struct anysee_state *state = d_to_priv(d);
+
+	if (state->i2c_client[0])
+		anysee_del_i2c_dev(d);
+
 	return anysee_ci_release(d);
 }
 
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.h b/drivers/media/usb/dvb-usb-v2/anysee.h
index 8f426d9..3ca2bca 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.h
+++ b/drivers/media/usb/dvb-usb-v2/anysee.h
@@ -55,8 +55,11 @@
 	u8 buf[64];
 	u8 seq;
 	u8 hw; /* PCB ID */
+	#define ANYSEE_I2C_CLIENT_MAX 1
+	struct i2c_client *i2c_client[ANYSEE_I2C_CLIENT_MAX];
 	u8 fe_id:1; /* frondend ID */
 	u8 has_ci:1;
+	u8 has_tda18212:1;
 	u8 ci_attached:1;
 	struct dvb_ca_en50221 ci;
 	unsigned long ci_cam_ready; /* jiffies */
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
index 124b4ba..14e111e 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
@@ -214,6 +214,7 @@
  * @read_config: called to resolve device configuration
  * @read_mac_address: called to resolve adapter mac-address
  * @frontend_attach: called to attach the possible frontends
+ * @frontend_detach: called to detach the possible frontends
  * @tuner_attach: called to attach the possible tuners
  * @frontend_ctrl: called to power on/off active frontend
  * @streaming_ctrl: called to start/stop the usb streaming of adapter
@@ -254,7 +255,9 @@
 	int (*read_config) (struct dvb_usb_device *d);
 	int (*read_mac_address) (struct dvb_usb_adapter *, u8 []);
 	int (*frontend_attach) (struct dvb_usb_adapter *);
+	int (*frontend_detach)(struct dvb_usb_adapter *);
 	int (*tuner_attach) (struct dvb_usb_adapter *);
+	int (*tuner_detach)(struct dvb_usb_adapter *);
 	int (*frontend_ctrl) (struct dvb_frontend *, int);
 	int (*streaming_ctrl) (struct dvb_frontend *, int);
 	int (*init) (struct dvb_usb_device *);
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index 880a039..6d0c29f 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -21,7 +21,7 @@
 
 #include "dvb_usb_common.h"
 
-int dvb_usbv2_disable_rc_polling;
+static int dvb_usbv2_disable_rc_polling;
 module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644);
 MODULE_PARM_DESC(disable_rc_polling,
 		"disable remote control polling (default: 0)");
@@ -664,9 +664,10 @@
 
 static int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap)
 {
-	int i;
-	dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
-			adap->id);
+	int ret, i;
+	struct dvb_usb_device *d = adap_to_d(adap);
+
+	dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
 
 	for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
 		if (adap->fe[i]) {
@@ -675,6 +676,23 @@
 		}
 	}
 
+	if (d->props->tuner_detach) {
+		ret = d->props->tuner_detach(adap);
+		if (ret < 0) {
+			dev_dbg(&d->udev->dev, "%s: tuner_detach() failed=%d\n",
+					__func__, ret);
+		}
+	}
+
+	if (d->props->frontend_detach) {
+		ret = d->props->frontend_detach(adap);
+		if (ret < 0) {
+			dev_dbg(&d->udev->dev,
+					"%s: frontend_detach() failed=%d\n",
+					__func__, ret);
+		}
+	}
+
 	return 0;
 }
 
@@ -762,9 +780,9 @@
 
 	for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) {
 		if (d->adapter[i].props) {
-			dvb_usbv2_adapter_frontend_exit(&d->adapter[i]);
 			dvb_usbv2_adapter_dvb_exit(&d->adapter[i]);
 			dvb_usbv2_adapter_stream_exit(&d->adapter[i]);
+			dvb_usbv2_adapter_frontend_exit(&d->adapter[i]);
 		}
 	}
 
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
index 33ff97e..22bdce1 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
@@ -26,7 +26,7 @@
 {
 	int ret, actual_length;
 
-	if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint ||
+	if (!wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint ||
 			!d->props->generic_bulk_ctrl_endpoint_response) {
 		dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL);
 		return -EINVAL;
diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c
new file mode 100644
index 0000000..0b41401
--- /dev/null
+++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c
@@ -0,0 +1,460 @@
+/*
+ * Driver for DVBSky USB2.0 receiver
+ *
+ * Copyright (C) 2013 Max nibble <nibble.max@gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    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.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dvb_usb.h"
+#include "m88ds3103.h"
+#include "m88ts2022.h"
+
+#define DVBSKY_MSG_DELAY	0/*2000*/
+#define DVBSKY_BUF_LEN	64
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct dvbsky_state {
+	struct mutex stream_mutex;
+	u8 ibuf[DVBSKY_BUF_LEN];
+	u8 obuf[DVBSKY_BUF_LEN];
+	u8 last_lock;
+	struct i2c_client *i2c_client_tuner;
+
+	/* fe hook functions*/
+	int (*fe_set_voltage)(struct dvb_frontend *fe,
+		fe_sec_voltage_t voltage);
+	int (*fe_read_status)(struct dvb_frontend *fe,
+		fe_status_t *status);
+};
+
+static int dvbsky_usb_generic_rw(struct dvb_usb_device *d,
+		u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+	int ret;
+	struct dvbsky_state *state = d_to_priv(d);
+
+	mutex_lock(&d->usb_mutex);
+	if (wlen != 0)
+		memcpy(state->obuf, wbuf, wlen);
+
+	ret = dvb_usbv2_generic_rw_locked(d, state->obuf, wlen,
+			state->ibuf, rlen);
+
+	if (!ret && (rlen != 0))
+		memcpy(rbuf, state->ibuf, rlen);
+
+	mutex_unlock(&d->usb_mutex);
+	return ret;
+}
+
+static int dvbsky_stream_ctrl(struct dvb_usb_device *d, u8 onoff)
+{
+	struct dvbsky_state *state = d_to_priv(d);
+	int ret;
+	u8 obuf_pre[3] = { 0x37, 0, 0 };
+	u8 obuf_post[3] = { 0x36, 3, 0 };
+
+	mutex_lock(&state->stream_mutex);
+	ret = dvbsky_usb_generic_rw(d, obuf_pre, 3, NULL, 0);
+	if (!ret && onoff) {
+		msleep(20);
+		ret = dvbsky_usb_generic_rw(d, obuf_post, 3, NULL, 0);
+	}
+	mutex_unlock(&state->stream_mutex);
+	return ret;
+}
+
+static int dvbsky_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+	struct dvb_usb_device *d = fe_to_d(fe);
+
+	return dvbsky_stream_ctrl(d, (onoff == 0) ? 0 : 1);
+}
+
+/* GPIO */
+static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value)
+{
+	int ret;
+	u8 obuf[3], ibuf[2];
+
+	obuf[0] = 0x0e;
+	obuf[1] = gport;
+	obuf[2] = value;
+	ret = dvbsky_usb_generic_rw(d, obuf, 3, ibuf, 1);
+	if (ret)
+		dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+			KBUILD_MODNAME, __func__, ret);
+	return ret;
+}
+
+/* I2C */
+static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+	int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int ret = 0;
+	u8 ibuf[64], obuf[64];
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	if (num > 2) {
+		dev_err(&d->udev->dev,
+		"dvbsky_usb: too many i2c messages[%d] than 2.", num);
+		ret = -EOPNOTSUPP;
+		goto i2c_error;
+	}
+
+	if (num == 1) {
+		if (msg[0].len > 60) {
+			dev_err(&d->udev->dev,
+			"dvbsky_usb: too many i2c bytes[%d] than 60.",
+			msg[0].len);
+			ret = -EOPNOTSUPP;
+			goto i2c_error;
+		}
+		if (msg[0].flags & I2C_M_RD) {
+			/* single read */
+			obuf[0] = 0x09;
+			obuf[1] = 0;
+			obuf[2] = msg[0].len;
+			obuf[3] = msg[0].addr;
+			ret = dvbsky_usb_generic_rw(d, obuf, 4,
+					ibuf, msg[0].len + 1);
+			if (ret)
+				dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+					KBUILD_MODNAME, __func__, ret);
+			if (!ret)
+				memcpy(msg[0].buf, &ibuf[1], msg[0].len);
+		} else {
+			/* write */
+			obuf[0] = 0x08;
+			obuf[1] = msg[0].addr;
+			obuf[2] = msg[0].len;
+			memcpy(&obuf[3], msg[0].buf, msg[0].len);
+			ret = dvbsky_usb_generic_rw(d, obuf,
+					msg[0].len + 3, ibuf, 1);
+			if (ret)
+				dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+					KBUILD_MODNAME, __func__, ret);
+		}
+	} else {
+		if ((msg[0].len > 60) || (msg[1].len > 60)) {
+			dev_err(&d->udev->dev,
+			"dvbsky_usb: too many i2c bytes[w-%d][r-%d] than 60.",
+			msg[0].len, msg[1].len);
+			ret = -EOPNOTSUPP;
+			goto i2c_error;
+		}
+		/* write then read */
+		obuf[0] = 0x09;
+		obuf[1] = msg[0].len;
+		obuf[2] = msg[1].len;
+		obuf[3] = msg[0].addr;
+		memcpy(&obuf[4], msg[0].buf, msg[0].len);
+		ret = dvbsky_usb_generic_rw(d, obuf,
+			msg[0].len + 4, ibuf, msg[1].len + 1);
+		if (ret)
+			dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+				KBUILD_MODNAME, __func__, ret);
+
+		if (!ret)
+			memcpy(msg[1].buf, &ibuf[1], msg[1].len);
+	}
+i2c_error:
+	mutex_unlock(&d->i2c_mutex);
+	return (ret) ? ret : num;
+}
+
+static u32 dvbsky_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dvbsky_i2c_algo = {
+	.master_xfer   = dvbsky_i2c_xfer,
+	.functionality = dvbsky_i2c_func,
+};
+
+#if IS_ENABLED(CPTCFG_RC_CORE)
+static int dvbsky_rc_query(struct dvb_usb_device *d)
+{
+	u32 code = 0xffff, scancode;
+	u8 rc5_command, rc5_system;
+	u8 obuf[2], ibuf[2], toggle;
+	int ret;
+
+	obuf[0] = 0x10;
+	ret = dvbsky_usb_generic_rw(d, obuf, 1, ibuf, 2);
+	if (ret)
+		dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
+			KBUILD_MODNAME, __func__, ret);
+	if (ret == 0)
+		code = (ibuf[0] << 8) | ibuf[1];
+	if (code != 0xffff) {
+		dev_dbg(&d->udev->dev, "rc code: %x\n", code);
+		rc5_command = code & 0x3F;
+		rc5_system = (code & 0x7C0) >> 6;
+		toggle = (code & 0x800) ? 1 : 0;
+		scancode = rc5_system << 8 | rc5_command;
+		rc_keydown(d->rc_dev, RC_TYPE_RC5, scancode, toggle);
+	}
+	return 0;
+}
+
+static int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+	rc->allowed_protos = RC_BIT_RC5;
+	rc->query          = dvbsky_rc_query;
+	rc->interval       = 300;
+	return 0;
+}
+#else
+	#define dvbsky_get_rc_config NULL
+#endif
+
+static int dvbsky_usb_set_voltage(struct dvb_frontend *fe,
+	fe_sec_voltage_t voltage)
+{
+	struct dvb_usb_device *d = fe_to_d(fe);
+	struct dvbsky_state *state = d_to_priv(d);
+	u8 value;
+
+	if (voltage == SEC_VOLTAGE_OFF)
+		value = 0;
+	else
+		value = 1;
+	dvbsky_gpio_ctrl(d, 0x80, value);
+
+	return state->fe_set_voltage(fe, voltage);
+}
+
+static int dvbsky_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
+{
+	struct dvb_usb_device *d = adap_to_d(adap);
+	u8 obuf[] = { 0x1e, 0x00 };
+	u8 ibuf[6] = { 0 };
+	struct i2c_msg msg[] = {
+		{
+			.addr = 0x51,
+			.flags = 0,
+			.buf = obuf,
+			.len = 2,
+		}, {
+			.addr = 0x51,
+			.flags = I2C_M_RD,
+			.buf = ibuf,
+			.len = 6,
+		}
+	};
+
+	if (i2c_transfer(&d->i2c_adap, msg, 2) == 2)
+		memcpy(mac, ibuf, 6);
+
+	dev_info(&d->udev->dev, "dvbsky_usb MAC address=%pM\n", mac);
+
+	return 0;
+}
+
+static int dvbsky_usb_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct dvb_usb_device *d = fe_to_d(fe);
+	struct dvbsky_state *state = d_to_priv(d);
+	int ret;
+
+	ret = state->fe_read_status(fe, status);
+
+	/* it need resync slave fifo when signal change from unlock to lock.*/
+	if ((*status & FE_HAS_LOCK) && (!state->last_lock))
+		dvbsky_stream_ctrl(d, 1);
+
+	state->last_lock = (*status & FE_HAS_LOCK) ? 1 : 0;
+	return ret;
+}
+
+static const struct m88ds3103_config dvbsky_s960_m88ds3103_config = {
+	.i2c_addr = 0x68,
+	.clock = 27000000,
+	.i2c_wr_max = 33,
+	.clock_out = 0,
+	.ts_mode = M88DS3103_TS_CI,
+	.ts_clk = 16000,
+	.ts_clk_pol = 0,
+	.agc = 0x99,
+	.lnb_hv_pol = 1,
+	.lnb_en_pol = 1,
+};
+
+static int dvbsky_s960_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvbsky_state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	int ret = 0;
+	/* demod I2C adapter */
+	struct i2c_adapter *i2c_adapter;
+	struct i2c_client *client;
+	struct i2c_board_info info;
+	struct m88ts2022_config m88ts2022_config = {
+			.clock = 27000000,
+		};
+	memset(&info, 0, sizeof(struct i2c_board_info));
+
+	/* attach demod */
+	adap->fe[0] = dvb_attach(m88ds3103_attach,
+			&dvbsky_s960_m88ds3103_config,
+			&d->i2c_adap,
+			&i2c_adapter);
+	if (!adap->fe[0]) {
+		dev_err(&d->udev->dev, "dvbsky_s960_attach fail.\n");
+		ret = -ENODEV;
+		goto fail_attach;
+	}
+
+	/* attach tuner */
+	m88ts2022_config.fe = adap->fe[0];
+	strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+	info.addr = 0x60;
+	info.platform_data = &m88ts2022_config;
+	request_module("m88ts2022");
+	client = i2c_new_device(i2c_adapter, &info);
+	if (client == NULL || client->dev.driver == NULL) {
+		dvb_frontend_detach(adap->fe[0]);
+		ret = -ENODEV;
+		goto fail_attach;
+	}
+
+	if (!try_module_get(client->dev.driver->owner)) {
+		i2c_unregister_device(client);
+		dvb_frontend_detach(adap->fe[0]);
+		ret = -ENODEV;
+		goto fail_attach;
+	}
+
+	/* delegate signal strength measurement to tuner */
+	adap->fe[0]->ops.read_signal_strength =
+			adap->fe[0]->ops.tuner_ops.get_rf_strength;
+
+	/* hook fe: need to resync the slave fifo when signal locks. */
+	state->fe_read_status = adap->fe[0]->ops.read_status;
+	adap->fe[0]->ops.read_status = dvbsky_usb_read_status;
+
+	/* hook fe: LNB off/on is control by Cypress usb chip. */
+	state->fe_set_voltage = adap->fe[0]->ops.set_voltage;
+	adap->fe[0]->ops.set_voltage = dvbsky_usb_set_voltage;
+
+	state->i2c_client_tuner = client;
+
+fail_attach:
+	return ret;
+}
+
+static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name)
+{
+	dvbsky_gpio_ctrl(d, 0x04, 1);
+	msleep(20);
+	dvbsky_gpio_ctrl(d, 0x83, 0);
+	dvbsky_gpio_ctrl(d, 0xc0, 1);
+	msleep(100);
+	dvbsky_gpio_ctrl(d, 0x83, 1);
+	dvbsky_gpio_ctrl(d, 0xc0, 0);
+	msleep(50);
+
+	return WARM;
+}
+
+static int dvbsky_init(struct dvb_usb_device *d)
+{
+	struct dvbsky_state *state = d_to_priv(d);
+
+	/* use default interface */
+	/*
+	ret = usb_set_interface(d->udev, 0, 0);
+	if (ret)
+		return ret;
+	*/
+	mutex_init(&state->stream_mutex);
+
+	state->last_lock = 0;
+
+	return 0;
+}
+
+static void dvbsky_exit(struct dvb_usb_device *d)
+{
+	struct dvbsky_state *state = d_to_priv(d);
+	struct i2c_client *client;
+
+	client = state->i2c_client_tuner;
+	/* remove I2C tuner */
+	if (client) {
+		module_put(client->dev.driver->owner);
+		i2c_unregister_device(client);
+	}
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties dvbsky_s960_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct dvbsky_state),
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
+
+	.i2c_algo         = &dvbsky_i2c_algo,
+	.frontend_attach  = dvbsky_s960_attach,
+	.init             = dvbsky_init,
+	.get_rc_config    = dvbsky_get_rc_config,
+	.streaming_ctrl   = dvbsky_streaming_ctrl,
+	.identify_state	  = dvbsky_identify_state,
+	.exit             = dvbsky_exit,
+	.read_mac_address = dvbsky_read_mac_addr,
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
+		}
+	}
+};
+
+static const struct usb_device_id dvbsky_id_table[] = {
+	{ DVB_USB_DEVICE(0x0572, 0x6831,
+		&dvbsky_s960_props, "DVBSky S960/S860", RC_MAP_DVBSKY) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, dvbsky_id_table);
+
+static struct usb_driver dvbsky_usb_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = dvbsky_id_table,
+	.probe = dvb_usbv2_probe,
+	.disconnect = dvb_usbv2_disconnect,
+	.suspend = dvb_usbv2_suspend,
+	.resume = dvb_usbv2_resume,
+	.reset_resume = dvb_usbv2_reset_resume,
+	.no_dynamic_id = 1,
+	.soft_unbind = 1,
+};
+
+module_usb_driver(dvbsky_usb_driver);
+
+MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
+MODULE_DESCRIPTION("Driver for DVBSky USB");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index e332af7..9f2c545 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -1252,7 +1252,7 @@
 
 	/* Turn PID filter on the fly by module option */
 	if (pid_filter == 2) {
-		adap->pid_filtering  = 1;
+		adap->pid_filtering  = true;
 		adap->max_feed_count = 15;
 	}
 
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
index b8a707e..c3447ea 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -31,11 +31,11 @@
 MODULE_PARM_DESC(debug, "set debugging level "
 		 "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able)).");
 
-int dvb_usb_mxl111sf_isoc;
+static int dvb_usb_mxl111sf_isoc;
 module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
 MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
 
-int dvb_usb_mxl111sf_spi;
+static int dvb_usb_mxl111sf_spi;
 module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644);
 MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
 
@@ -43,7 +43,7 @@
 #define ANT_PATH_EXTERNAL 1
 #define ANT_PATH_INTERNAL 2
 
-int dvb_usb_mxl111sf_rfswitch =
+static int dvb_usb_mxl111sf_rfswitch =
 #if 0
 		ANT_PATH_AUTO;
 #else
@@ -887,7 +887,7 @@
 	return I2C_FUNC_I2C;
 }
 
-struct i2c_algorithm mxl111sf_i2c_algo = {
+static struct i2c_algorithm mxl111sf_i2c_algo = {
 	.master_xfer   = mxl111sf_i2c_xfer,
 	.functionality = mxl111sf_i2c_func,
 #ifdef NEED_ALGO_CONTROL
diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
index 819743f..25da066 100644
--- a/drivers/media/usb/dvb-usb/Kconfig
+++ b/drivers/media/usb/dvb-usb/Kconfig
@@ -137,7 +137,7 @@
 
 	  Medion MD95700 hybrid USB2.0 device.
 	  DViCO FusionHDTV (Bluebird) USB2.0 devices
-	  TechnoTrend TVStick CT2-4400
+	  TechnoTrend TVStick CT2-4400 and CT2-4650 CI devices
 
 config DVB_USB_M920X
 	tristate "Uli m920x DVB-T USB2.0 support"
diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c
index af176b6..3f4361e 100644
--- a/drivers/media/usb/dvb-usb/af9005.c
+++ b/drivers/media/usb/dvb-usb/af9005.c
@@ -30,7 +30,7 @@
 		 "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
 		 DVB_USB_DEBUG_STATUS);
 /* enable obnoxious led */
-bool dvb_usb_af9005_led = 1;
+bool dvb_usb_af9005_led = true;
 module_param_named(led, dvb_usb_af9005_led, bool, 0644);
 MODULE_PARM_DESC(led, "enable led (default: 1).");
 
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index 16bc579..356abb3 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -44,6 +44,7 @@
 #include "atbm8830.h"
 #include "si2168.h"
 #include "si2157.h"
+#include "sp2.h"
 
 /* Max transfer size done by I2C transfer functions */
 #define MAX_XFER_SIZE  80
@@ -175,7 +176,7 @@
 
 	for (i = 0; i < num; i++) {
 
-		if (d->udev->descriptor.idVendor == USB_VID_MEDION)
+		if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_MEDION)
 			switch (msg[i].addr) {
 			case 0x63:
 				cxusb_gpio_tuner(d, 0);
@@ -672,6 +673,70 @@
 	{ 0x0025, KEY_POWER },
 };
 
+static int cxusb_tt_ct2_4400_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+	u8 wbuf[2];
+	u8 rbuf[6];
+	int ret;
+	struct i2c_msg msg[] = {
+		{
+			.addr = 0x51,
+			.flags = 0,
+			.buf = wbuf,
+			.len = 2,
+		}, {
+			.addr = 0x51,
+			.flags = I2C_M_RD,
+			.buf = rbuf,
+			.len = 6,
+		}
+	};
+
+	wbuf[0] = 0x1e;
+	wbuf[1] = 0x00;
+	ret = cxusb_i2c_xfer(&d->i2c_adap, msg, 2);
+
+	if (ret == 2) {
+		memcpy(mac, rbuf, 6);
+		return 0;
+	} else {
+		if (ret < 0)
+			return ret;
+		return -EIO;
+	}
+}
+
+static int cxusb_tt_ct2_4650_ci_ctrl(void *priv, u8 read, int addr,
+					u8 data, int *mem)
+{
+	struct dvb_usb_device *d = priv;
+	u8 wbuf[3];
+	u8 rbuf[2];
+	int ret;
+
+	wbuf[0] = (addr >> 8) & 0xff;
+	wbuf[1] = addr & 0xff;
+
+	if (read) {
+		ret = cxusb_ctrl_msg(d, CMD_SP2_CI_READ, wbuf, 2, rbuf, 2);
+	} else {
+		wbuf[2] = data;
+		ret = cxusb_ctrl_msg(d, CMD_SP2_CI_WRITE, wbuf, 3, rbuf, 1);
+	}
+
+	if (ret)
+		goto err;
+
+	if (read)
+		*mem = rbuf[1];
+
+	return 0;
+err:
+	deb_info("%s: ci usb write returned %d\n", __func__, ret);
+	return ret;
+
+}
+
 static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
 {
 	static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x28 };
@@ -1350,9 +1415,12 @@
 	struct i2c_adapter *adapter;
 	struct i2c_client *client_demod;
 	struct i2c_client *client_tuner;
+	struct i2c_client *client_ci;
 	struct i2c_board_info info;
 	struct si2168_config si2168_config;
 	struct si2157_config si2157_config;
+	struct sp2_config sp2_config;
+	u8 o[2], i;
 
 	/* reset the tuner */
 	if (cxusb_tt_ct2_4400_gpio_tuner(d, 0) < 0) {
@@ -1369,6 +1437,7 @@
 	/* attach frontend */
 	si2168_config.i2c_adapter = &adapter;
 	si2168_config.fe = &adap->fe_adap[0].fe;
+	si2168_config.ts_mode = SI2168_TS_PARALLEL;
 	memset(&info, 0, sizeof(struct i2c_board_info));
 	strlcpy(info.type, "si2168", I2C_NAME_SIZE);
 	info.addr = 0x64;
@@ -1408,6 +1477,48 @@
 
 	st->i2c_client_tuner = client_tuner;
 
+	/* initialize CI */
+	if (d->udev->descriptor.idProduct ==
+		USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI) {
+
+		memcpy(o, "\xc0\x01", 2);
+		cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+		msleep(100);
+
+		memcpy(o, "\xc0\x00", 2);
+		cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+		msleep(100);
+
+		memset(&sp2_config, 0, sizeof(sp2_config));
+		sp2_config.dvb_adap = &adap->dvb_adap;
+		sp2_config.priv = d;
+		sp2_config.ci_control = cxusb_tt_ct2_4650_ci_ctrl;
+		memset(&info, 0, sizeof(struct i2c_board_info));
+		strlcpy(info.type, "sp2", I2C_NAME_SIZE);
+		info.addr = 0x40;
+		info.platform_data = &sp2_config;
+		request_module(info.type);
+		client_ci = i2c_new_device(&d->i2c_adap, &info);
+		if (client_ci == NULL || client_ci->dev.driver == NULL) {
+			module_put(client_tuner->dev.driver->owner);
+			i2c_unregister_device(client_tuner);
+			module_put(client_demod->dev.driver->owner);
+			i2c_unregister_device(client_demod);
+			return -ENODEV;
+		}
+		if (!try_module_get(client_ci->dev.driver->owner)) {
+			i2c_unregister_device(client_ci);
+			module_put(client_tuner->dev.driver->owner);
+			i2c_unregister_device(client_tuner);
+			module_put(client_demod->dev.driver->owner);
+			i2c_unregister_device(client_demod);
+			return -ENODEV;
+		}
+
+		st->i2c_client_ci = client_ci;
+
+	}
+
 	return 0;
 }
 
@@ -1537,6 +1648,13 @@
 	struct cxusb_state *st = d->priv;
 	struct i2c_client *client;
 
+	/* remove I2C client for CI */
+	client = st->i2c_client_ci;
+	if (client) {
+		module_put(client->dev.driver->owner);
+		i2c_unregister_device(client);
+	}
+
 	/* remove I2C client for tuner */
 	client = st->i2c_client_tuner;
 	if (client) {
@@ -1576,6 +1694,7 @@
 	{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
 	{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) },
 	{ USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_TVSTICK_CT2_4400) },
+	{ USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI) },
 	{}		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -2230,6 +2349,8 @@
 	.size_of_priv     = sizeof(struct cxusb_state),
 
 	.num_adapters = 1,
+	.read_mac_address = cxusb_tt_ct2_4400_read_mac_address,
+
 	.adapter = {
 		{
 		.num_frontends = 1,
@@ -2265,13 +2386,18 @@
 		.rc_interval    = 150,
 	},
 
-	.num_device_descs = 1,
+	.num_device_descs = 2,
 	.devices = {
 		{
 			"TechnoTrend TVStick CT2-4400",
 			{ NULL },
 			{ &cxusb_table[20], NULL },
 		},
+		{
+			"TechnoTrend TT-connect CT2-4650 CI",
+			{ NULL },
+			{ &cxusb_table[21], NULL },
+		},
 	}
 };
 
diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h
index 527ff79..29f3e2e 100644
--- a/drivers/media/usb/dvb-usb/cxusb.h
+++ b/drivers/media/usb/dvb-usb/cxusb.h
@@ -28,10 +28,14 @@
 #define CMD_ANALOG        0x50
 #define CMD_DIGITAL       0x51
 
+#define CMD_SP2_CI_WRITE  0x70
+#define CMD_SP2_CI_READ   0x71
+
 struct cxusb_state {
 	u8 gpio_write_state[3];
 	struct i2c_client *i2c_client_demod;
 	struct i2c_client *i2c_client_tuner;
+	struct i2c_client *i2c_client_ci;
 };
 
 #endif
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index ce47d3f..e1757b8 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -220,12 +220,21 @@
 };
 
 static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = {
-	60000, 30000,
-	1, 8, 3, 1, 0,
-	0, 0, 1, 1, 2,
-	(3 << 14) | (1 << 12) | (524 << 0),
-	0,
-	20452225,
+	.internal = 60000,
+	.sampling = 30000,
+	.pll_prediv = 1,
+	.pll_ratio = 8,
+	.pll_range = 3,
+	.pll_reset = 1,
+	.pll_bypass = 0,
+	.enable_refdiv = 0,
+	.bypclk_div = 0,
+	.IO_CLK_en_core = 1,
+	.ADClkSrc = 1,
+	.modulo = 2,
+	.sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+	.ifreq = 0,
+	.timf = 20452225,
 };
 
 static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = {
@@ -342,57 +351,57 @@
 
 /* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */
 static struct dibx000_agc_config xc3028_agc_config = {
-	BAND_VHF | BAND_UHF,       /* band_caps */
-
+	.band_caps = BAND_VHF | BAND_UHF,
 	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
 	 * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
 	 * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-	(0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
-	(3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
-
-	712,	/* inv_gain */
-	21,	/* time_stabiliz */
-
-	0,	/* alpha_level */
-	118,	/* thlock */
-
-	0,	/* wbd_inv */
-	2867,	/* wbd_ref */
-	0,	/* wbd_sel */
-	2,	/* wbd_alpha */
-
-	0,	/* agc1_max */
-	0,	/* agc1_min */
-	39718,	/* agc2_max */
-	9930,	/* agc2_min */
-	0,	/* agc1_pt1 */
-	0,	/* agc1_pt2 */
-	0,	/* agc1_pt3 */
-	0,	/* agc1_slope1 */
-	0,	/* agc1_slope2 */
-	0,	/* agc2_pt1 */
-	128,	/* agc2_pt2 */
-	29,	/* agc2_slope1 */
-	29,	/* agc2_slope2 */
-
-	17,	/* alpha_mant */
-	27,	/* alpha_exp */
-	23,	/* beta_mant */
-	51,	/* beta_exp */
-
-	1,	/* perform_agc_softsplit */
+	.setup = (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
+	.inv_gain = 712,
+	.time_stabiliz = 21,
+	.alpha_level = 0,
+	.thlock = 118,
+	.wbd_inv = 0,
+	.wbd_ref = 2867,
+	.wbd_sel = 0,
+	.wbd_alpha = 2,
+	.agc1_max = 0,
+	.agc1_min = 0,
+	.agc2_max = 39718,
+	.agc2_min = 9930,
+	.agc1_pt1 = 0,
+	.agc1_pt2 = 0,
+	.agc1_pt3 = 0,
+	.agc1_slope1 = 0,
+	.agc1_slope2 = 0,
+	.agc2_pt1 = 0,
+	.agc2_pt2 = 128,
+	.agc2_slope1 = 29,
+	.agc2_slope2 = 29,
+	.alpha_mant = 17,
+	.alpha_exp = 27,
+	.beta_mant = 23,
+	.beta_exp = 51,
+	.perform_agc_softsplit = 1,
 };
 
 /* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */
 static struct dibx000_bandwidth_config xc3028_bw_config = {
-	60000, 30000, /* internal, sampling */
-	1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */
-	0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc,
-			  modulo */
-	(3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
-	(1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
-	20452225, /* timf */
-	30000000, /* xtal_hz */
+	.internal = 60000,
+	.sampling = 30000,
+	.pll_prediv = 1,
+	.pll_ratio = 8,
+	.pll_range = 3,
+	.pll_reset = 1,
+	.pll_bypass = 0,
+	.enable_refdiv = 0,
+	.bypclk_div = 0,
+	.IO_CLK_en_core = 1,
+	.ADClkSrc = 1,
+	.modulo = 0,
+	.sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
+	.ifreq = (1 << 25) | 5816102,  /* ifreq = 5.200000 MHz */
+	.timf = 20452225,
+	.xtal_hz = 30000000,
 };
 
 static struct dib7000p_config stk7700ph_dib7700_xc3028_config = {
@@ -614,59 +623,55 @@
 };
 
 static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = {
-	BAND_UHF | BAND_VHF,
-
+	.band_caps = BAND_UHF | BAND_VHF,
 	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
 	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
-	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
-	| (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
-
-	712,
-	41,
-
-	0,
-	118,
-
-	0,
-	4095,
-	0,
-	0,
-
-	42598,
-	16384,
-	42598,
-	    0,
-
-	  0,
-	137,
-	255,
-
-	  0,
-	255,
-
-	0,
-	0,
-
-	 0,
-	41,
-
-	15,
-	25,
-
-	28,
-	48,
-
-	0,
+	.setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0),
+	.inv_gain = 712,
+	.time_stabiliz = 41,
+	.alpha_level = 0,
+	.thlock = 118,
+	.wbd_inv = 0,
+	.wbd_ref = 4095,
+	.wbd_sel = 0,
+	.wbd_alpha = 0,
+	.agc1_max = 42598,
+	.agc1_min = 16384,
+	.agc2_max = 42598,
+	.agc2_min = 0,
+	.agc1_pt1 = 0,
+	.agc1_pt2 = 137,
+	.agc1_pt3 = 255,
+	.agc1_slope1 = 0,
+	.agc1_slope2 = 255,
+	.agc2_pt1 = 0,
+	.agc2_pt2 = 0,
+	.agc2_slope1 = 0,
+	.agc2_slope2 = 41,
+	.alpha_mant = 15,
+	.alpha_exp = 25,
+	.beta_mant = 28,
+	.beta_exp = 48,
+	.perform_agc_softsplit = 0,
 };
 
 static struct dibx000_bandwidth_config stk7700p_pll_config = {
-	60000, 30000,
-	1, 8, 3, 1, 0,
-	0, 0, 1, 1, 0,
-	(3 << 14) | (1 << 12) | (524 << 0),
-	60258167,
-	20452225,
-	30000000,
+	.internal = 60000,
+	.sampling = 30000,
+	.pll_prediv = 1,
+	.pll_ratio = 8,
+	.pll_range = 3,
+	.pll_reset = 1,
+	.pll_bypass = 0,
+	.enable_refdiv = 0,
+	.bypclk_div = 0,
+	.IO_CLK_en_core = 1,
+	.ADClkSrc = 1,
+	.modulo = 0,
+	.sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+	.ifreq = 60258167,
+	.timf = 20452225,
+	.xtal_hz = 30000000,
 };
 
 static struct dib7000m_config stk7700p_dib7000m_config = {
@@ -758,45 +763,36 @@
 
 /* DIB7070 generic */
 static struct dibx000_agc_config dib7070_agc_config = {
-	BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+	.band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
 	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
 	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
-	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
-	| (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
-
-	600,
-	10,
-
-	0,
-	118,
-
-	0,
-	3530,
-	1,
-	5,
-
-	65535,
-		0,
-
-	65535,
-	0,
-
-	0,
-	40,
-	183,
-	206,
-	255,
-	72,
-	152,
-	88,
-	90,
-
-	17,
-	27,
-	23,
-	51,
-
-	0,
+	.setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+	.inv_gain = 600,
+	.time_stabiliz = 10,
+	.alpha_level = 0,
+	.thlock = 118,
+	.wbd_inv = 0,
+	.wbd_ref = 3530,
+	.wbd_sel = 1,
+	.wbd_alpha = 5,
+	.agc1_max = 65535,
+	.agc1_min = 0,
+	.agc2_max = 65535,
+	.agc2_min = 0,
+	.agc1_pt1 = 0,
+	.agc1_pt2 = 40,
+	.agc1_pt3 = 183,
+	.agc1_slope1 = 206,
+	.agc1_slope2 = 255,
+	.agc2_pt1 = 72,
+	.agc2_pt2 = 152,
+	.agc2_slope1 = 88,
+	.agc2_slope2 = 90,
+	.alpha_mant = 17,
+	.alpha_exp = 27,
+	.beta_mant = 23,
+	.beta_exp = 51,
+	.perform_agc_softsplit = 0,
 };
 
 static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
@@ -952,13 +948,22 @@
 }
 
 static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
-	60000, 15000,
-	1, 20, 3, 1, 0,
-	0, 0, 1, 1, 2,
-	(3 << 14) | (1 << 12) | (524 << 0),
-	(0 << 25) | 0,
-	20452225,
-	12000000,
+	.internal = 60000,
+	.sampling = 15000,
+	.pll_prediv = 1,
+	.pll_ratio = 20,
+	.pll_range = 3,
+	.pll_reset = 1,
+	.pll_bypass = 0,
+	.enable_refdiv = 0,
+	.bypclk_div = 0,
+	.IO_CLK_en_core = 1,
+	.ADClkSrc = 1,
+	.modulo = 2,
+	.sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+	.ifreq = (0 << 25) | 0,
+	.timf = 20452225,
+	.xtal_hz = 12000000,
 };
 
 static struct dib7000p_config dib7070p_dib7000p_config = {
@@ -1169,14 +1174,22 @@
 };
 
 static struct dibx000_bandwidth_config dib807x_bw_config_12_mhz = {
-	60000, 15000, /* internal, sampling*/
-	1, 20, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass*/
-	0, 0, 1, 1, 2, /* misc: refdiv, bypclk_div, IO_CLK_en_core,
-			  ADClkSrc, modulo */
-	(3 << 14) | (1 << 12) | (599 << 0), /* sad_cfg: refsel, sel, freq_15k*/
-	(0 << 25) | 0, /* ifreq = 0.000000 MHz*/
-	18179755, /* timf*/
-	12000000, /* xtal_hz*/
+	.internal = 60000,
+	.sampling = 15000,
+	.pll_prediv = 1,
+	.pll_ratio = 20,
+	.pll_range = 3,
+	.pll_reset = 1,
+	.pll_bypass = 0,
+	.enable_refdiv = 0,
+	.bypclk_div = 0,
+	.IO_CLK_en_core = 1,
+	.ADClkSrc = 1,
+	.modulo = 2,
+	.sad_cfg = (3 << 14) | (1 << 12) | (599 << 0),	/* sad_cfg: refsel, sel, freq_15k*/
+	.ifreq = (0 << 25) | 0,				/* ifreq = 0.000000 MHz*/
+	.timf = 18179755,
+	.xtal_hz = 12000000,
 };
 
 static struct dib8000_config dib807x_dib8000_config[2] = {
@@ -1921,13 +1934,22 @@
 };
 
 static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = {
-	108000, 13500,
-	1, 9, 1, 0, 0,
-	0, 0, 0, 0, 2,
-	(3 << 14) | (1 << 12) | (524 << 0),
-	(0 << 25) | 0,
-	20199729,
-	12000000,
+	.internal = 108000,
+	.sampling = 13500,
+	.pll_prediv = 1,
+	.pll_ratio = 9,
+	.pll_range = 1,
+	.pll_reset = 0,
+	.pll_bypass = 0,
+	.enable_refdiv = 0,
+	.bypclk_div = 0,
+	.IO_CLK_en_core = 0,
+	.ADClkSrc = 0,
+	.modulo = 2,
+	.sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+	.ifreq = (0 << 25) | 0,
+	.timf = 20199729,
+	.xtal_hz = 12000000,
 };
 
 static struct dib8000_config tfe8096p_dib8000_config = {
@@ -2724,13 +2746,22 @@
 };
 
 static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = {
-	60000, 15000,
-	1, 5, 0, 0, 0,
-	0, 0, 1, 1, 2,
-	(3 << 14) | (1 << 12) | (524 << 0),
-	(0 << 25) | 0,
-	20452225,
-	15000000,
+	.internal = 60000,
+	.sampling = 15000,
+	.pll_prediv = 1,
+	.pll_ratio = 5,
+	.pll_range = 0,
+	.pll_reset = 0,
+	.pll_bypass = 0,
+	.enable_refdiv = 0,
+	.bypclk_div = 0,
+	.IO_CLK_en_core = 1,
+	.ADClkSrc = 1,
+	.modulo = 2,
+	.sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+	.ifreq = (0 << 25) | 0,
+	.timf = 20452225,
+	.xtal_hz = 15000000,
 };
 
 static struct dib7000p_config nim7090_dib7000p_config = {
@@ -3498,14 +3529,22 @@
 };
 
 static struct dibx000_bandwidth_config stk7700p_xc4000_pll_config = {
-	60000, 30000,	/* internal, sampling */
-	1, 8, 3, 1, 0,	/* pll_cfg: prediv, ratio, range, reset, bypass */
-	0, 0, 1, 1, 0,	/* misc: refdiv, bypclk_div, IO_CLK_en_core, */
-			/* ADClkSrc, modulo */
-	(3 << 14) | (1 << 12) | 524,	/* sad_cfg: refsel, sel, freq_15k */
-	39370534,	/* ifreq */
-	20452225,	/* timf */
-	30000000	/* xtal */
+	.internal = 60000,
+	.sampling = 30000,
+	.pll_prediv = 1,
+	.pll_ratio = 8,
+	.pll_range = 3,
+	.pll_reset = 1,
+	.pll_bypass = 0,
+	.enable_refdiv = 0,
+	.bypclk_div = 0,
+	.IO_CLK_en_core = 1,
+	.ADClkSrc = 1,
+	.modulo = 0,
+	.sad_cfg = (3 << 14) | (1 << 12) | 524, /* sad_cfg: refsel, sel, freq_15k */
+	.ifreq = 39370534,
+	.timf = 20452225,
+	.xtal_hz = 30000000
 };
 
 /* FIXME: none of these inputs are validated yet */
diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c
index fb2b133..89b2e50 100644
--- a/drivers/media/usb/dvb-usb/dibusb-common.c
+++ b/drivers/media/usb/dvb-usb/dibusb-common.c
@@ -258,8 +258,8 @@
 
 int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap)
 {
-	if (adap->dev->udev->descriptor.idVendor  == USB_VID_LITEON &&
-			adap->dev->udev->descriptor.idProduct ==
+	if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON &&
+	    le16_to_cpu(adap->dev->udev->descriptor.idProduct) ==
 			USB_PID_LITEON_DVB_T_WARM) {
 		msleep(1000);
 	}
@@ -297,8 +297,8 @@
 	struct i2c_adapter *tun_i2c;
 
 	// First IF calibration for Liteon Sticks
-	if (adap->dev->udev->descriptor.idVendor  == USB_VID_LITEON &&
-		adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) {
+	if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_LITEON &&
+	    le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_LITEON_DVB_T_WARM) {
 
 		dibusb_read_eeprom_byte(adap->dev,0x7E,&a);
 		dibusb_read_eeprom_byte(adap->dev,0x7F,&b);
@@ -310,8 +310,8 @@
 		else
 			warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b);
 
-	} else if (adap->dev->udev->descriptor.idVendor  == USB_VID_DIBCOM &&
-		   adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) {
+	} else if (le16_to_cpu(adap->dev->udev->descriptor.idVendor) == USB_VID_DIBCOM &&
+		   le16_to_cpu(adap->dev->udev->descriptor.idProduct) == USB_PID_DIBCOM_MOD3001_WARM) {
 		u8 desc;
 		dibusb_read_eeprom_byte(adap->dev, 7, &desc);
 		if (desc == 2) {
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index 2add8c5..1a3df10 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -667,7 +667,7 @@
 				obuf[1] = (msg[j].addr << 1);
 				memcpy(obuf + 2, msg[j].buf, msg[j].len);
 				dw210x_op_rw(d->udev,
-						udev->descriptor.idProduct ==
+						le16_to_cpu(udev->descriptor.idProduct) ==
 						0x7500 ? 0x92 : 0x90, 0, 0,
 						obuf, msg[j].len + 2,
 						DW210X_WRITE_MSG);
@@ -1598,7 +1598,7 @@
 	u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
 	const struct firmware *fw;
 
-	switch (dev->descriptor.idProduct) {
+	switch (le16_to_cpu(dev->descriptor.idProduct)) {
 	case 0x2101:
 		ret = request_firmware(&fw, DW2101_FIRMWARE, &dev->dev);
 		if (ret != 0) {
@@ -1641,7 +1641,7 @@
 			ret = -EINVAL;
 		}
 		/* init registers */
-		switch (dev->descriptor.idProduct) {
+		switch (le16_to_cpu(dev->descriptor.idProduct)) {
 		case USB_PID_TEVII_S650:
 			dw2104_properties.rc.core.rc_codes = RC_MAP_TEVII_NEC;
 		case USB_PID_DW2104:
@@ -1901,14 +1901,14 @@
 	}
 };
 
-struct dvb_usb_device_properties *p1100;
+static struct dvb_usb_device_properties *p1100;
 static struct dvb_usb_device_description d1100 = {
 	"Prof 1100 USB ",
 	{&dw2102_table[PROF_1100], NULL},
 	{NULL},
 };
 
-struct dvb_usb_device_properties *s660;
+static struct dvb_usb_device_properties *s660;
 static struct dvb_usb_device_description d660 = {
 	"TeVii S660 USB",
 	{&dw2102_table[TEVII_S660], NULL},
@@ -1927,14 +1927,14 @@
 	{NULL},
 };
 
-struct dvb_usb_device_properties *p7500;
+static struct dvb_usb_device_properties *p7500;
 static struct dvb_usb_device_description d7500 = {
 	"Prof 7500 USB DVB-S2",
 	{&dw2102_table[PROF_7500], NULL},
 	{NULL},
 };
 
-struct dvb_usb_device_properties *s421;
+static struct dvb_usb_device_properties *s421;
 static struct dvb_usb_device_description d421 = {
 	"TeVii S421 PCI",
 	{&dw2102_table[TEVII_S421], NULL},
diff --git a/drivers/media/usb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c
index 16ba90a..14a2119 100644
--- a/drivers/media/usb/dvb-usb/opera1.c
+++ b/drivers/media/usb/dvb-usb/opera1.c
@@ -554,8 +554,8 @@
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
 
-	if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
-		udev->descriptor.idVendor == USB_VID_OPERA1 &&
+	if (le16_to_cpu(udev->descriptor.idProduct) == USB_PID_OPERA1_WARM &&
+	    le16_to_cpu(udev->descriptor.idVendor) == USB_VID_OPERA1 &&
 		opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
 	    ) {
 		return -EINVAL;
diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c
index bdfe896..d17618f 100644
--- a/drivers/media/usb/dvb-usb/pctv452e.c
+++ b/drivers/media/usb/dvb-usb/pctv452e.c
@@ -883,7 +883,7 @@
 	if (!a->fe_adap[0].fe)
 		return -ENODEV;
 	if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe,
-					&a->dev->i2c_adap)) == 0)
+					&a->dev->i2c_adap)) == NULL)
 		err("Cannot attach lnbp22\n");
 
 	id = a->dev->desc->warm_ids[0];
@@ -900,7 +900,7 @@
 	if (!a->fe_adap[0].fe)
 		return -ENODEV;
 	if (dvb_attach(stb6100_attach, a->fe_adap[0].fe, &stb6100_config,
-					&a->dev->i2c_adap) == 0) {
+					&a->dev->i2c_adap) == NULL) {
 		err("%s failed\n", __func__);
 		return -ENODEV;
 	}
@@ -965,7 +965,7 @@
 		  .cold_ids = { NULL, NULL }, /* this is a warm only device */
 		  .warm_ids = { &pctv452e_usb_table[0], NULL }
 		},
-		{ 0 },
+		{ NULL },
 	}
 };
 
@@ -1023,7 +1023,7 @@
 		  .cold_ids = { NULL, NULL },
 		  .warm_ids = { &pctv452e_usb_table[2], NULL }
 		},
-		{ 0 },
+		{ NULL },
 	}
 };
 
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index 12594a2..ddec55a 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -38,6 +38,7 @@
 	  module will be called em28xx-alsa
 
 config VIDEO_EM28XX_DVB
+	depends on !BACKPORT_KERNEL_3_4
 	tristate "DVB/ATSC Support for em28xx based TV cards"
 	depends on m
 	depends on VIDEO_EM28XX && DVB_CORE
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index e881ef7..957c7ae 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -268,7 +268,7 @@
 	nonblock = !!(substream->f_flags & O_NONBLOCK);
 	if (nonblock) {
 		if (!mutex_trylock(&dev->lock))
-		return -EAGAIN;
+			return -EAGAIN;
 	} else
 		mutex_lock(&dev->lock);
 
@@ -893,7 +893,7 @@
 	static int          devnr;
 	int		    err;
 
-	if (!dev->has_alsa_audio) {
+	if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) {
 		/* This device does not support the extension (in this case
 		   the device is expecting the snd-usb-audio module or
 		   doesn't have analog audio support at all) */
@@ -975,7 +975,7 @@
 	if (dev == NULL)
 		return 0;
 
-	if (!dev->has_alsa_audio) {
+	if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) {
 		/* This device does not support the extension (in this case
 		   the device is expecting the snd-usb-audio module or
 		   doesn't have analog audio support at all) */
@@ -1003,7 +1003,7 @@
 	if (dev == NULL)
 		return 0;
 
-	if (!dev->has_alsa_audio)
+	if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR)
 		return 0;
 
 	em28xx_info("Suspending audio extension");
@@ -1017,7 +1017,7 @@
 	if (dev == NULL)
 		return 0;
 
-	if (!dev->has_alsa_audio)
+	if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR)
 		return 0;
 
 	em28xx_info("Resuming audio extension");
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 9da812b..71fa51e 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2246,7 +2246,7 @@
 };
 EXPORT_SYMBOL_GPL(em28xx_boards);
 
-const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
+static const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
 /* table of devices that work with this driver */
 struct usb_device_id em28xx_id_table[] = {
@@ -2931,9 +2931,9 @@
 #if defined(CONFIG_MODULES) && defined(MODULE)
 	if (dev->has_video)
 		request_module("em28xx-v4l");
-	if (dev->has_audio_class)
+	if (dev->usb_audio_type == EM28XX_USB_AUDIO_CLASS)
 		request_module("snd-usb-audio");
-	else if (dev->has_alsa_audio)
+	else if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR)
 		request_module("em28xx-alsa");
 	if (dev->board.has_dvb)
 		request_module("em28xx-dvb");
@@ -3098,16 +3098,6 @@
 		}
 	}
 
-	if (dev->chip_id == CHIP_ID_EM2870 ||
-	    dev->chip_id == CHIP_ID_EM2874 ||
-	    dev->chip_id == CHIP_ID_EM28174 ||
-	    dev->chip_id == CHIP_ID_EM28178) {
-		/* Digital only device - don't load any alsa module */
-		dev->audio_mode.has_audio = false;
-		dev->has_audio_class = false;
-		dev->has_alsa_audio = false;
-	}
-
 	if (chip_name != default_chip_name)
 		printk(KERN_INFO DRIVER_NAME
 		       ": chip ID is %s\n", chip_name);
@@ -3190,7 +3180,7 @@
 	struct usb_device *udev;
 	struct em28xx *dev = NULL;
 	int retval;
-	bool has_audio = false, has_video = false, has_dvb = false;
+	bool has_vendor_audio = false, has_video = false, has_dvb = false;
 	int i, nr, try_bulk;
 	const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
 	char *speed;
@@ -3272,7 +3262,7 @@
 					break;
 				case 0x83:
 					if (usb_endpoint_xfer_isoc(e)) {
-						has_audio = true;
+						has_vendor_audio = true;
 					} else {
 						printk(KERN_INFO DRIVER_NAME
 						": error: skipping audio endpoint 0x83, because it uses bulk transfers !\n");
@@ -3328,7 +3318,7 @@
 		}
 	}
 
-	if (!(has_audio || has_video || has_dvb)) {
+	if (!(has_vendor_audio || has_video || has_dvb)) {
 		retval = -ENODEV;
 		goto err_free;
 	}
@@ -3375,26 +3365,27 @@
 	dev->devno = nr;
 	dev->model = id->driver_info;
 	dev->alt   = -1;
-	dev->is_audio_only = has_audio && !(has_video || has_dvb);
-	dev->has_alsa_audio = has_audio;
-	dev->audio_mode.has_audio = has_audio;
+	dev->is_audio_only = has_vendor_audio && !(has_video || has_dvb);
 	dev->has_video = has_video;
 	dev->ifnum = ifnum;
 
-	/* Checks if audio is provided by some interface */
+	if (has_vendor_audio) {
+		printk(KERN_INFO DRIVER_NAME ": Audio interface %i found %s\n",
+		       ifnum, "(Vendor Class)");
+		dev->usb_audio_type = EM28XX_USB_AUDIO_VENDOR;
+	}
+	/* Checks if audio is provided by a USB Audio Class interface */
 	for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
 		struct usb_interface *uif = udev->config->interface[i];
 		if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
-			dev->has_audio_class = 1;
+			if (has_vendor_audio)
+				em28xx_err("em28xx: device seems to have vendor AND usb audio class interfaces !\n"
+					   "\t\tThe vendor interface will be ignored. Please contact the developers <linux-media@vger.kernel.org>\n");
+			dev->usb_audio_type = EM28XX_USB_AUDIO_CLASS;
 			break;
 		}
 	}
 
-	if (has_audio)
-		printk(KERN_INFO DRIVER_NAME
-		       ": Audio interface %i found %s\n",
-		       ifnum,
-		       dev->has_audio_class ? "(USB Audio Class)" : "(Vendor Class)");
 	if (has_video)
 		printk(KERN_INFO DRIVER_NAME
 		       ": Video interface %i found:%s%s\n",
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 523d7e9..b5e52fe 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -279,7 +279,7 @@
 {
 	int ret;
 	u8 addr = (reg & 0x7f) | 0x80;
-	u16 val;
+	__le16 val;
 
 	ret = em28xx_is_ac97_ready(dev);
 	if (ret < 0)
@@ -433,7 +433,7 @@
 	int ret, i;
 	u8 xclk;
 
-	if (!dev->audio_mode.has_audio)
+	if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE)
 		return 0;
 
 	/* It is assumed that all devices use master volume for output.
@@ -505,37 +505,48 @@
 {
 	int vid1, vid2, feat, cfg;
 	u32 vid;
+	u8 i2s_samplerates;
 
-	if (!dev->audio_mode.has_audio)
+	if (dev->chip_id == CHIP_ID_EM2870 ||
+	    dev->chip_id == CHIP_ID_EM2874 ||
+	    dev->chip_id == CHIP_ID_EM28174 ||
+	    dev->chip_id == CHIP_ID_EM28178) {
+		/* Digital only device - don't load any alsa module */
+		dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
+		dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
 		return 0;
+	}
 
 	/* See how this device is configured */
 	cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
 	em28xx_info("Config register raw data: 0x%02x\n", cfg);
-	if (cfg < 0) {
-		/* Register read error?  */
-		cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
+	if (cfg < 0) { /* Register read error */
+		/* Be conservative */
+		dev->int_audio_type = EM28XX_INT_AUDIO_AC97;
 	} else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
 		/* The device doesn't have vendor audio at all */
-		dev->has_alsa_audio = false;
-		dev->audio_mode.has_audio = false;
+		dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
+		dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
 		return 0;
 	} else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+		dev->int_audio_type = EM28XX_INT_AUDIO_I2S;
 		if (dev->chip_id < CHIP_ID_EM2860 &&
 	            (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
 		    EM2820_CHIPCFG_I2S_1_SAMPRATE)
-			dev->audio_mode.i2s_samplerates = 1;
+			i2s_samplerates = 1;
 		else if (dev->chip_id >= CHIP_ID_EM2860 &&
 			 (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
 			 EM2860_CHIPCFG_I2S_5_SAMPRATES)
-			dev->audio_mode.i2s_samplerates = 5;
+			i2s_samplerates = 5;
 		else
-			dev->audio_mode.i2s_samplerates = 3;
+			i2s_samplerates = 3;
 		em28xx_info("I2S Audio (%d sample rate(s))\n",
-					       dev->audio_mode.i2s_samplerates);
+					       i2s_samplerates);
 		/* Skip the code that does AC97 vendor detection */
 		dev->audio_mode.ac97 = EM28XX_NO_AC97;
 		goto init_audio;
+	} else {
+		dev->int_audio_type = EM28XX_INT_AUDIO_AC97;
 	}
 
 	dev->audio_mode.ac97 = EM28XX_AC97_OTHER;
@@ -549,8 +560,9 @@
 		 */
 		em28xx_warn("AC97 chip type couldn't be determined\n");
 		dev->audio_mode.ac97 = EM28XX_NO_AC97;
-		dev->has_alsa_audio = false;
-		dev->audio_mode.has_audio = false;
+		if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR)
+			dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
+		dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
 		goto init_audio;
 	}
 
@@ -559,15 +571,12 @@
 		goto init_audio;
 
 	vid = vid1 << 16 | vid2;
-
-	dev->audio_mode.ac97_vendor_id = vid;
 	em28xx_warn("AC97 vendor ID = 0x%08x\n", vid);
 
 	feat = em28xx_read_ac97(dev, AC97_RESET);
 	if (feat < 0)
 		goto init_audio;
 
-	dev->audio_mode.ac97_feat = feat;
 	em28xx_warn("AC97 features = 0x%04x\n", feat);
 
 	/* Try to identify what audio processor we have */
@@ -586,8 +595,8 @@
 		em28xx_info("Empia 202 AC97 audio processor detected\n");
 		break;
 	case EM28XX_AC97_SIGMATEL:
-		em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n",
-			    dev->audio_mode.ac97_vendor_id & 0xff);
+		em28xx_info("Sigmatel audio processor detected (stac 97%02x)\n",
+			    vid & 0xff);
 		break;
 	case EM28XX_AC97_OTHER:
 		em28xx_warn("Unknown AC97 audio processor detected!\n");
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 3a3e243..9682c52 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -373,7 +373,6 @@
 };
 
 static struct tda18212_config kworld_ub435q_v3_config = {
-	.i2c_address	= 0x60,
 	.if_atsc_vsb	= 3600,
 	.if_atsc_qam	= 3600,
 };
@@ -856,7 +855,9 @@
 	.clock = 27000000,
 	.i2c_wr_max = 33,
 	.clock_out = 0,
-	.ts_mode = M88DS3103_TS_PARALLEL_16,
+	.ts_mode = M88DS3103_TS_PARALLEL,
+	.ts_clk = 16000,
+	.ts_clk_pol = 1,
 	.agc = 0x99,
 };
 
@@ -1435,6 +1436,15 @@
 		}
 		break;
 	case EM2874_BOARD_KWORLD_UB435Q_V3:
+	{
+		struct i2c_client *client;
+		struct i2c_adapter *adapter = &dev->i2c_adap[dev->def_i2c_bus];
+		struct i2c_board_info board_info = {
+			.type = "tda18212",
+			.addr = 0x60,
+			.platform_data = &kworld_ub435q_v3_config,
+		};
+
 		dvb->fe[0] = dvb_attach(lgdt3305_attach,
 					&em2874_lgdt3305_nogate_dev,
 					&dev->i2c_adap[dev->def_i2c_bus]);
@@ -1443,14 +1453,26 @@
 			goto out_free;
 		}
 
-		/* Attach the demodulator. */
-		if (!dvb_attach(tda18212_attach, dvb->fe[0],
-				&dev->i2c_adap[dev->def_i2c_bus],
-				&kworld_ub435q_v3_config)) {
-			result = -EINVAL;
+		/* attach tuner */
+		kworld_ub435q_v3_config.fe = dvb->fe[0];
+		request_module("tda18212");
+		client = i2c_new_device(adapter, &board_info);
+		if (client == NULL || client->dev.driver == NULL) {
+			dvb_frontend_detach(dvb->fe[0]);
+			result = -ENODEV;
 			goto out_free;
 		}
+
+		if (!try_module_get(client->dev.driver->owner)) {
+			i2c_unregister_device(client);
+			dvb_frontend_detach(dvb->fe[0]);
+			result = -ENODEV;
+			goto out_free;
+		}
+
+		dvb->i2c_client_tuner = client;
 		break;
+	}
 	case EM2874_BOARD_PCTV_HD_MINI_80E:
 		dvb->fe[0] = dvb_attach(drx39xxj_attach, &dev->i2c_adap[dev->def_i2c_bus]);
 		if (dvb->fe[0] != NULL) {
@@ -1533,6 +1555,7 @@
 			/* attach demod */
 			si2168_config.i2c_adapter = &adapter;
 			si2168_config.fe = &dvb->fe[0];
+			si2168_config.ts_mode = SI2168_TS_PARALLEL;
 			memset(&info, 0, sizeof(struct i2c_board_info));
 			strlcpy(info.type, "si2168", I2C_NAME_SIZE);
 			info.addr = 0x64;
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index ed843bd..581f6da 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -71,8 +71,7 @@
 	unsigned int last_readcount;
 	u64 rc_type;
 
-	/* i2c slave address of external device (if used) */
-	u16 i2c_dev_addr;
+	struct i2c_client *i2c_client;
 
 	int  (*get_key_i2c)(struct i2c_client *ir, enum rc_type *protocol, u32 *scancode);
 	int  (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
@@ -294,16 +293,11 @@
 
 static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
 {
-	struct em28xx *dev = ir->dev;
 	static u32 scancode;
 	enum rc_type protocol;
 	int rc;
-	struct i2c_client client;
 
-	client.adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
-	client.addr = ir->i2c_dev_addr;
-
-	rc = ir->get_key_i2c(&client, &protocol, &scancode);
+	rc = ir->get_key_i2c(ir->i2c_client, &protocol, &scancode);
 	if (rc < 0) {
 		dprintk("ir->get_key_i2c() failed: %d\n", rc);
 		return rc;
@@ -361,7 +355,7 @@
 {
 	struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work.work);
 
-	if (ir->i2c_dev_addr) /* external i2c device */
+	if (ir->i2c_client) /* external i2c device */
 		em28xx_i2c_ir_handle_key(ir);
 	else /* internal device */
 		em28xx_ir_handle_key(ir);
@@ -609,17 +603,17 @@
 static void em28xx_init_buttons(struct em28xx *dev)
 {
 	u8  i = 0, j = 0;
-	bool addr_new = 0;
+	bool addr_new = false;
 
 	dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL;
 	while (dev->board.buttons[i].role >= 0 &&
 			 dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) {
 		struct em28xx_button *button = &dev->board.buttons[i];
 		/* Check if polling address is already on the list */
-		addr_new = 1;
+		addr_new = true;
 		for (j = 0; j < dev->num_button_polling_addresses; j++) {
 			if (button->reg_r == dev->button_polling_addresses[j]) {
-				addr_new = 0;
+				addr_new = false;
 				break;
 			}
 		}
@@ -756,7 +750,13 @@
 			goto error;
 		}
 
-		ir->i2c_dev_addr = i2c_rc_dev_addr;
+		ir->i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+		if (!ir->i2c_client)
+			goto error;
+		ir->i2c_client->adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
+		ir->i2c_client->addr = i2c_rc_dev_addr;
+		ir->i2c_client->flags = 0;
+		/* NOTE: all other fields of i2c_client are unused */
 	} else {	/* internal device */
 		switch (dev->chip_id) {
 		case CHIP_ID_EM2860:
@@ -815,6 +815,7 @@
 	return 0;
 
 error:
+	kfree(ir->i2c_client);
 	dev->ir = NULL;
 	rc_free_device(rc);
 	kfree(ir);
@@ -841,6 +842,8 @@
 	if (ir->rc)
 		rc_unregister_device(ir->rc);
 
+	kfree(ir->i2c_client);
+
 	/* done */
 	kfree(ir);
 	dev->ir = NULL;
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index 6d7f657..34ee1e0 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -29,17 +29,6 @@
 #include "em28xx.h"
 #include "em28xx-v4l.h"
 
-static unsigned int vbibufs = 5;
-module_param(vbibufs, int, 0644);
-MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
-
-static unsigned int vbi_debug;
-module_param(vbi_debug, int, 0644);
-MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
-
-#define dprintk(level, fmt, arg...)	if (vbi_debug >= level) \
-	printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg)
-
 /* ------------------------------------------------------------------ */
 
 static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index e8e94ef..f35083c 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -435,7 +435,10 @@
 	em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
 
 	buf->vb.v4l2_buf.sequence = dev->v4l2->field_count++;
-	buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+	if (dev->v4l2->progressive)
+		buf->vb.v4l2_buf.field = V4L2_FIELD_NONE;
+	else
+		buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
 	v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
 
 	vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
@@ -478,7 +481,7 @@
 	lencopy = lencopy > remain ? remain : lencopy;
 
 	if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->length) {
-		em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+		em28xx_isocdbg("Overflow of %zu bytes past buffer end (1)\n",
 			      ((char *)startwrite + lencopy) -
 			      ((char *)buf->vb_buf + buf->length));
 		remain = (char *)buf->vb_buf + buf->length -
@@ -504,7 +507,7 @@
 
 		if ((char *)startwrite + lencopy > (char *)buf->vb_buf +
 		    buf->length) {
-			em28xx_isocdbg("Overflow of %zi bytes past buffer end"
+			em28xx_isocdbg("Overflow of %zu bytes past buffer end"
 				       "(2)\n",
 				       ((char *)startwrite + lencopy) -
 				       ((char *)buf->vb_buf + buf->length));
@@ -718,7 +721,7 @@
 	struct em28xx_buffer    *buf = dev->usb_ctl.vid_buf;
 	struct em28xx_dmaqueue  *dmaq = &dev->vidq;
 	struct em28xx_v4l2      *v4l2 = dev->v4l2;
-	bool frame_end = 0;
+	bool frame_end = false;
 
 	/* Check for header */
 	/* NOTE: at least with bulk transfers, only the first packet
@@ -994,13 +997,16 @@
 	}
 
 	spin_lock_irqsave(&dev->slock, flags);
+	if (dev->usb_ctl.vid_buf != NULL) {
+		vb2_buffer_done(&dev->usb_ctl.vid_buf->vb, VB2_BUF_STATE_ERROR);
+		dev->usb_ctl.vid_buf = NULL;
+	}
 	while (!list_empty(&vidq->active)) {
 		struct em28xx_buffer *buf;
 		buf = list_entry(vidq->active.next, struct em28xx_buffer, list);
 		list_del(&buf->list);
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
 	}
-	dev->usb_ctl.vid_buf = NULL;
 	spin_unlock_irqrestore(&dev->slock, flags);
 }
 
@@ -1021,13 +1027,16 @@
 	}
 
 	spin_lock_irqsave(&dev->slock, flags);
+	if (dev->usb_ctl.vbi_buf != NULL) {
+		vb2_buffer_done(&dev->usb_ctl.vbi_buf->vb, VB2_BUF_STATE_ERROR);
+		dev->usb_ctl.vbi_buf = NULL;
+	}
 	while (!list_empty(&vbiq->active)) {
 		struct em28xx_buffer *buf;
 		buf = list_entry(vbiq->active.next, struct em28xx_buffer, list);
 		list_del(&buf->list);
 		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
 	}
-	dev->usb_ctl.vbi_buf = NULL;
 	spin_unlock_irqrestore(&dev->slock, flags);
 }
 
@@ -1711,7 +1720,7 @@
 	else
 		cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
 
-	if (dev->audio_mode.has_audio)
+	if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE)
 		cap->device_caps |= V4L2_CAP_AUDIO;
 
 	if (dev->tuner_type != TUNER_ABSENT)
@@ -2296,7 +2305,7 @@
 	v4l2->v4l2_dev.ctrl_handler = hdl;
 
 	if (dev->board.is_webcam)
-		v4l2->progressive = 1;
+		v4l2->progressive = true;
 
 	/*
 	 * Default format, used for tvp5150 or saa711x output formats
@@ -2502,7 +2511,7 @@
 		v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_FREQUENCY);
 		v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_FREQUENCY);
 	}
-	if (!dev->audio_mode.has_audio) {
+	if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) {
 		v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_AUDIO);
 		v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_AUDIO);
 	}
@@ -2532,7 +2541,7 @@
 			v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_FREQUENCY);
 			v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_FREQUENCY);
 		}
-		if (!dev->audio_mode.has_audio) {
+		if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) {
 			v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_AUDIO);
 			v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_AUDIO);
 		}
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 4360338..a21a746 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -309,13 +309,18 @@
 
 struct em28xx_audio_mode {
 	enum em28xx_ac97_mode ac97;
+};
 
-	u16 ac97_feat;
-	u32 ac97_vendor_id;
+enum em28xx_int_audio_type {
+	EM28XX_INT_AUDIO_NONE = 0,
+	EM28XX_INT_AUDIO_AC97,
+	EM28XX_INT_AUDIO_I2S,
+};
 
-	unsigned int has_audio:1;
-
-	u8 i2s_samplerates;
+enum em28xx_usb_audio_type {
+	EM28XX_USB_AUDIO_NONE = 0,
+	EM28XX_USB_AUDIO_CLASS,
+	EM28XX_USB_AUDIO_VENDOR,
 };
 
 /* em28xx has two audio inputs: tuner and line in.
@@ -608,9 +613,9 @@
 	unsigned int is_em25xx:1;	/* em25xx/em276x/7x/8x family bridge */
 	unsigned char disconnected:1;	/* device has been diconnected */
 	unsigned int has_video:1;
-	unsigned int has_audio_class:1;
-	unsigned int has_alsa_audio:1;
 	unsigned int is_audio_only:1;
+	enum em28xx_int_audio_type int_audio_type;
+	enum em28xx_usb_audio_type usb_audio_type;
 
 	struct em28xx_board board;
 
diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c
index ece27ec..3f986e1 100644
--- a/drivers/media/usb/go7007/go7007-usb.c
+++ b/drivers/media/usb/go7007/go7007-usb.c
@@ -696,7 +696,7 @@
 				sizeof(status_reg), timeout);
 		if (r < 0)
 			break;
-		status_reg = le16_to_cpu(*((u16 *)go->usb_buf));
+		status_reg = le16_to_cpu(*((__le16 *)go->usb_buf));
 		if (!(status_reg & 0x0010))
 			break;
 		msleep(10);
@@ -751,7 +751,7 @@
 static void go7007_usb_readinterrupt_complete(struct urb *urb)
 {
 	struct go7007 *go = (struct go7007 *)urb->context;
-	u16 *regs = (u16 *)urb->transfer_buffer;
+	__le16 *regs = (__le16 *)urb->transfer_buffer;
 	int status = urb->status;
 
 	if (status) {
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index beab4d3..4e6ac0a 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -876,9 +876,8 @@
 		ep_tb[0].alt = gspca_dev->alt;
 		alt_idx = 1;
 	} else {
-
-	/* else, compute the minimum bandwidth
-	 * and build the endpoint table */
+		/* else, compute the minimum bandwidth
+		 * and build the endpoint table */
 		alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb);
 		if (alt_idx <= 0) {
 			pr_err("no transfer endpoint found\n");
diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h
index 948371b..827b27e 100644
--- a/drivers/media/usb/gspca/gspca.h
+++ b/drivers/media/usb/gspca/gspca.h
@@ -235,6 +235,6 @@
 int gspca_expo_autogain(struct gspca_dev *gspca_dev, int avg_lum,
 	int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee);
 int gspca_coarse_grained_expo_autogain(struct gspca_dev *gspca_dev,
-        int avg_lum, int desired_avg_lum, int deadzone);
+	int avg_lum, int desired_avg_lum, int deadzone);
 
 #endif /* GSPCAV2_H */
diff --git a/drivers/media/usb/gspca/kinect.c b/drivers/media/usb/gspca/kinect.c
index 45bc1f5..3cb30a3 100644
--- a/drivers/media/usb/gspca/kinect.c
+++ b/drivers/media/usb/gspca/kinect.c
@@ -51,9 +51,9 @@
 
 struct cam_hdr {
 	uint8_t magic[2];
-	uint16_t len;
-	uint16_t cmd;
-	uint16_t tag;
+	__le16 len;
+	__le16 cmd;
+	__le16 tag;
 };
 
 /* specific webcam descriptor */
@@ -188,9 +188,9 @@
 		       rhdr->tag, chdr->tag);
 		return -1;
 	}
-	if (cpu_to_le16(rhdr->len) != (actual_len/2)) {
+	if (le16_to_cpu(rhdr->len) != (actual_len/2)) {
 		pr_err("send_cmd: Bad len %04x != %04x\n",
-		       cpu_to_le16(rhdr->len), (int)(actual_len/2));
+		       le16_to_cpu(rhdr->len), (int)(actual_len/2));
 		return -1;
 	}
 
@@ -211,7 +211,7 @@
 			uint16_t data)
 {
 	uint16_t reply[2];
-	uint16_t cmd[2];
+	__le16 cmd[2];
 	int res;
 
 	cmd[0] = cpu_to_le16(reg);
diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
index 9a9ba02..236c890 100644
--- a/drivers/media/usb/gspca/sn9c20x.c
+++ b/drivers/media/usb/gspca/sn9c20x.c
@@ -1297,7 +1297,7 @@
 	s32 hue_coord, hue_index = 180 + hue;
 	u8 cmatrix[21];
 
-	memset(cmatrix, 0, sizeof cmatrix);
+	memset(cmatrix, 0, sizeof(cmatrix));
 	cmatrix[2] = (contrast * 0x25 / 0x100) + 0x26;
 	cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
 	cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
@@ -1787,8 +1787,9 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 	int i;
 	u8 value;
-	u8 i2c_init[9] =
-		{0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
+	u8 i2c_init[9] = {
+		0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03
+	};
 
 	for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
 		value = bridge_init[i][1];
@@ -2242,8 +2243,9 @@
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int avg_lum, is_jpeg;
-	static const u8 frame_header[] =
-		{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
+	static const u8 frame_header[] = {
+		0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96
+	};
 
 	is_jpeg = (sd->fmt & 0x03) == 0;
 	if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
index e60cbb3..f86cec0 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
@@ -259,7 +259,7 @@
 	fine = val % VV6410_CIF_LINELENGTH;
 	coarse = min(512, val / VV6410_CIF_LINELENGTH);
 
-	PDEBUG(D_CONF, "Set coarse exposure to %d, fine expsure to %d",
+	PDEBUG(D_CONF, "Set coarse exposure to %d, fine exposure to %d",
 	       coarse, fine);
 
 	err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8);
diff --git a/drivers/media/usb/hackrf/Kconfig b/drivers/media/usb/hackrf/Kconfig
new file mode 100644
index 0000000..972e76b
--- /dev/null
+++ b/drivers/media/usb/hackrf/Kconfig
@@ -0,0 +1,11 @@
+config USB_HACKRF
+	tristate "HackRF"
+	depends on m
+	depends on VIDEO_V4L2
+	select VIDEOBUF2_VMALLOC
+	---help---
+	  This is a video4linux2 driver for HackRF SDR device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hackrf
+
diff --git a/drivers/media/usb/hackrf/Makefile b/drivers/media/usb/hackrf/Makefile
new file mode 100644
index 0000000..7f88660
--- /dev/null
+++ b/drivers/media/usb/hackrf/Makefile
@@ -0,0 +1 @@
+obj-$(CPTCFG_USB_HACKRF)              += hackrf.o
diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
new file mode 100644
index 0000000..527e891
--- /dev/null
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -0,0 +1,1143 @@
+/*
+ * HackRF driver
+ *
+ * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    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/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-vmalloc.h>
+#include <linux/mm.h>
+
+/* HackRF USB API commands (from HackRF Library) */
+enum {
+	CMD_SET_TRANSCEIVER_MODE           = 0x01,
+	CMD_SAMPLE_RATE_SET                = 0x06,
+	CMD_BASEBAND_FILTER_BANDWIDTH_SET  = 0x07,
+	CMD_BOARD_ID_READ                  = 0x0e,
+	CMD_VERSION_STRING_READ            = 0x0f,
+	CMD_SET_FREQ                       = 0x10,
+	CMD_SET_LNA_GAIN                   = 0x13,
+	CMD_SET_VGA_GAIN                   = 0x14,
+};
+
+/*
+ *       bEndpointAddress     0x81  EP 1 IN
+ *         Transfer Type            Bulk
+ *       wMaxPacketSize     0x0200  1x 512 bytes
+ */
+#define MAX_BULK_BUFS            (6)
+#define BULK_BUFFER_SIZE         (128 * 512)
+
+static const struct v4l2_frequency_band bands_adc[] = {
+	{
+		.tuner = 0,
+		.type = V4L2_TUNER_ADC,
+		.index = 0,
+		.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+		.rangelow   =   200000,
+		.rangehigh  = 24000000,
+	},
+};
+
+static const struct v4l2_frequency_band bands_rf[] = {
+	{
+		.tuner = 1,
+		.type = V4L2_TUNER_RF,
+		.index = 0,
+		.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+		.rangelow   =          1,
+		.rangehigh  = 4294967294LL, /* max u32, hw goes over 7GHz */
+	},
+};
+
+/* stream formats */
+struct hackrf_format {
+	char	*name;
+	u32	pixelformat;
+	u32	buffersize;
+};
+
+/* format descriptions for capture and preview */
+static struct hackrf_format formats[] = {
+	{
+		.name		= "Complex S8",
+		.pixelformat	= V4L2_SDR_FMT_CS8,
+		.buffersize	= BULK_BUFFER_SIZE,
+	},
+};
+
+static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats);
+
+/* intermediate buffers with raw data from the USB device */
+struct hackrf_frame_buf {
+	struct vb2_buffer vb;   /* common v4l buffer stuff -- must be first */
+	struct list_head list;
+};
+
+struct hackrf_dev {
+#define POWER_ON           (1 << 1)
+#define URB_BUF            (1 << 2)
+#define USB_STATE_URB_BUF  (1 << 3)
+	unsigned long flags;
+
+	struct device *dev;
+	struct usb_device *udev;
+	struct video_device vdev;
+	struct v4l2_device v4l2_dev;
+
+	/* videobuf2 queue and queued buffers list */
+	struct vb2_queue vb_queue;
+	struct list_head queued_bufs;
+	spinlock_t queued_bufs_lock; /* Protects queued_bufs */
+	unsigned sequence;	     /* Buffer sequence counter */
+	unsigned int vb_full;        /* vb is full and packets dropped */
+
+	/* Note if taking both locks v4l2_lock must always be locked first! */
+	struct mutex v4l2_lock;      /* Protects everything else */
+	struct mutex vb_queue_lock;  /* Protects vb_queue */
+
+	struct urb     *urb_list[MAX_BULK_BUFS];
+	int            buf_num;
+	unsigned long  buf_size;
+	u8             *buf_list[MAX_BULK_BUFS];
+	dma_addr_t     dma_addr[MAX_BULK_BUFS];
+	int            urbs_initialized;
+	int            urbs_submitted;
+
+	/* USB control message buffer */
+	#define BUF_SIZE 24
+	u8 buf[BUF_SIZE];
+
+	/* Current configuration */
+	unsigned int f_adc;
+	unsigned int f_rf;
+	u32 pixelformat;
+	u32 buffersize;
+
+	/* Controls */
+	struct v4l2_ctrl_handler hdl;
+	struct v4l2_ctrl *bandwidth_auto;
+	struct v4l2_ctrl *bandwidth;
+	struct v4l2_ctrl *lna_gain;
+	struct v4l2_ctrl *if_gain;
+
+	/* Sample rate calc */
+	unsigned long jiffies_next;
+	unsigned int sample;
+	unsigned int sample_measured;
+};
+
+#define hackrf_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \
+	char *_direction; \
+	if (_t & USB_DIR_IN) \
+		_direction = "<<<"; \
+	else \
+		_direction = ">>>"; \
+	dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \
+			_t, _r, _v & 0xff, _v >> 8, _i & 0xff, \
+			_i >> 8, _l & 0xff, _l >> 8, _direction, _l, _b); \
+}
+
+/* execute firmware command */
+static int hackrf_ctrl_msg(struct hackrf_dev *dev, u8 request, u16 value,
+		u16 index, u8 *data, u16 size)
+{
+	int ret;
+	unsigned int pipe;
+	u8 requesttype;
+
+	switch (request) {
+	case CMD_SET_TRANSCEIVER_MODE:
+	case CMD_SET_FREQ:
+	case CMD_SAMPLE_RATE_SET:
+	case CMD_BASEBAND_FILTER_BANDWIDTH_SET:
+		pipe = usb_sndctrlpipe(dev->udev, 0);
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+		break;
+	case CMD_BOARD_ID_READ:
+	case CMD_VERSION_STRING_READ:
+	case CMD_SET_LNA_GAIN:
+	case CMD_SET_VGA_GAIN:
+		pipe = usb_rcvctrlpipe(dev->udev, 0);
+		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+		break;
+	default:
+		dev_err(dev->dev, "Unknown command %02x\n", request);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* write request */
+	if (!(requesttype & USB_DIR_IN))
+		memcpy(dev->buf, data, size);
+
+	ret = usb_control_msg(dev->udev, pipe, request, requesttype, value,
+			index, dev->buf, size, 1000);
+	hackrf_dbg_usb_control_msg(dev->dev, request, requesttype, value,
+			index, dev->buf, size);
+	if (ret < 0) {
+		dev_err(dev->dev, "usb_control_msg() failed %d request %02x\n",
+				ret, request);
+		goto err;
+	}
+
+	/* read request */
+	if (requesttype & USB_DIR_IN)
+		memcpy(data, dev->buf, size);
+
+	return 0;
+err:
+	return ret;
+}
+
+/* Private functions */
+static struct hackrf_frame_buf *hackrf_get_next_fill_buf(struct hackrf_dev *dev)
+{
+	unsigned long flags;
+	struct hackrf_frame_buf *buf = NULL;
+
+	spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+	if (list_empty(&dev->queued_bufs))
+		goto leave;
+
+	buf = list_entry(dev->queued_bufs.next, struct hackrf_frame_buf, list);
+	list_del(&buf->list);
+leave:
+	spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
+	return buf;
+}
+
+static unsigned int hackrf_convert_stream(struct hackrf_dev *dev,
+		void *dst, void *src, unsigned int src_len)
+{
+	memcpy(dst, src, src_len);
+
+	/* calculate sample rate and output it in 10 seconds intervals */
+	if (unlikely(time_is_before_jiffies(dev->jiffies_next))) {
+		#define MSECS 10000UL
+		unsigned int msecs = jiffies_to_msecs(jiffies -
+				dev->jiffies_next + msecs_to_jiffies(MSECS));
+		unsigned int samples = dev->sample - dev->sample_measured;
+
+		dev->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
+		dev->sample_measured = dev->sample;
+		dev_dbg(dev->dev, "slen=%u samples=%u msecs=%u sample rate=%lu\n",
+				src_len, samples, msecs,
+				samples * 1000UL / msecs);
+	}
+
+	/* total number of samples */
+	dev->sample += src_len / 2;
+
+	return src_len;
+}
+
+/*
+ * This gets called for the bulk stream pipe. This is done in interrupt
+ * time, so it has to be fast, not crash, and not stall. Neat.
+ */
+static void hackrf_urb_complete(struct urb *urb)
+{
+	struct hackrf_dev *dev = urb->context;
+	struct hackrf_frame_buf *fbuf;
+
+	dev_dbg_ratelimited(dev->dev, "status=%d length=%d/%d errors=%d\n",
+			urb->status, urb->actual_length,
+			urb->transfer_buffer_length, urb->error_count);
+
+	switch (urb->status) {
+	case 0:             /* success */
+	case -ETIMEDOUT:    /* NAK */
+		break;
+	case -ECONNRESET:   /* kill */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:            /* error */
+		dev_err_ratelimited(dev->dev, "URB failed %d\n", urb->status);
+		break;
+	}
+
+	if (likely(urb->actual_length > 0)) {
+		void *ptr;
+		unsigned int len;
+		/* get free framebuffer */
+		fbuf = hackrf_get_next_fill_buf(dev);
+		if (unlikely(fbuf == NULL)) {
+			dev->vb_full++;
+			dev_notice_ratelimited(dev->dev,
+					"videobuf is full, %d packets dropped\n",
+					dev->vb_full);
+			goto skip;
+		}
+
+		/* fill framebuffer */
+		ptr = vb2_plane_vaddr(&fbuf->vb, 0);
+		len = hackrf_convert_stream(dev, ptr, urb->transfer_buffer,
+				urb->actual_length);
+		vb2_set_plane_payload(&fbuf->vb, 0, len);
+		v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp);
+		fbuf->vb.v4l2_buf.sequence = dev->sequence++;
+		vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
+	}
+skip:
+	usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int hackrf_kill_urbs(struct hackrf_dev *dev)
+{
+	int i;
+
+	for (i = dev->urbs_submitted - 1; i >= 0; i--) {
+		dev_dbg(dev->dev, "kill urb=%d\n", i);
+		/* stop the URB */
+		usb_kill_urb(dev->urb_list[i]);
+	}
+	dev->urbs_submitted = 0;
+
+	return 0;
+}
+
+static int hackrf_submit_urbs(struct hackrf_dev *dev)
+{
+	int i, ret;
+
+	for (i = 0; i < dev->urbs_initialized; i++) {
+		dev_dbg(dev->dev, "submit urb=%d\n", i);
+		ret = usb_submit_urb(dev->urb_list[i], GFP_ATOMIC);
+		if (ret) {
+			dev_err(dev->dev, "Could not submit URB no. %d - get them all back\n",
+					i);
+			hackrf_kill_urbs(dev);
+			return ret;
+		}
+		dev->urbs_submitted++;
+	}
+
+	return 0;
+}
+
+static int hackrf_free_stream_bufs(struct hackrf_dev *dev)
+{
+	if (dev->flags & USB_STATE_URB_BUF) {
+		while (dev->buf_num) {
+			dev->buf_num--;
+			dev_dbg(dev->dev, "free buf=%d\n", dev->buf_num);
+			usb_free_coherent(dev->udev, dev->buf_size,
+					  dev->buf_list[dev->buf_num],
+					  dev->dma_addr[dev->buf_num]);
+		}
+	}
+	dev->flags &= ~USB_STATE_URB_BUF;
+
+	return 0;
+}
+
+static int hackrf_alloc_stream_bufs(struct hackrf_dev *dev)
+{
+	dev->buf_num = 0;
+	dev->buf_size = BULK_BUFFER_SIZE;
+
+	dev_dbg(dev->dev, "all in all I will use %u bytes for streaming\n",
+			MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+
+	for (dev->buf_num = 0; dev->buf_num < MAX_BULK_BUFS; dev->buf_num++) {
+		dev->buf_list[dev->buf_num] = usb_alloc_coherent(dev->udev,
+				BULK_BUFFER_SIZE, GFP_ATOMIC,
+				&dev->dma_addr[dev->buf_num]);
+		if (!dev->buf_list[dev->buf_num]) {
+			dev_dbg(dev->dev, "alloc buf=%d failed\n",
+					dev->buf_num);
+			hackrf_free_stream_bufs(dev);
+			return -ENOMEM;
+		}
+
+		dev_dbg(dev->dev, "alloc buf=%d %p (dma %llu)\n", dev->buf_num,
+				dev->buf_list[dev->buf_num],
+				(long long)dev->dma_addr[dev->buf_num]);
+		dev->flags |= USB_STATE_URB_BUF;
+	}
+
+	return 0;
+}
+
+static int hackrf_free_urbs(struct hackrf_dev *dev)
+{
+	int i;
+
+	hackrf_kill_urbs(dev);
+
+	for (i = dev->urbs_initialized - 1; i >= 0; i--) {
+		if (dev->urb_list[i]) {
+			dev_dbg(dev->dev, "free urb=%d\n", i);
+			/* free the URBs */
+			usb_free_urb(dev->urb_list[i]);
+		}
+	}
+	dev->urbs_initialized = 0;
+
+	return 0;
+}
+
+static int hackrf_alloc_urbs(struct hackrf_dev *dev)
+{
+	int i, j;
+
+	/* allocate the URBs */
+	for (i = 0; i < MAX_BULK_BUFS; i++) {
+		dev_dbg(dev->dev, "alloc urb=%d\n", i);
+		dev->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
+		if (!dev->urb_list[i]) {
+			dev_dbg(dev->dev, "failed\n");
+			for (j = 0; j < i; j++)
+				usb_free_urb(dev->urb_list[j]);
+			return -ENOMEM;
+		}
+		usb_fill_bulk_urb(dev->urb_list[i],
+				dev->udev,
+				usb_rcvbulkpipe(dev->udev, 0x81),
+				dev->buf_list[i],
+				BULK_BUFFER_SIZE,
+				hackrf_urb_complete, dev);
+
+		dev->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+		dev->urb_list[i]->transfer_dma = dev->dma_addr[i];
+		dev->urbs_initialized++;
+	}
+
+	return 0;
+}
+
+/* Must be called with vb_queue_lock hold */
+static void hackrf_cleanup_queued_bufs(struct hackrf_dev *dev)
+{
+	unsigned long flags;
+
+	dev_dbg(dev->dev, "\n");
+
+	spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+	while (!list_empty(&dev->queued_bufs)) {
+		struct hackrf_frame_buf *buf;
+
+		buf = list_entry(dev->queued_bufs.next,
+				struct hackrf_frame_buf, list);
+		list_del(&buf->list);
+		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+	}
+	spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
+}
+
+/* The user yanked out the cable... */
+static void hackrf_disconnect(struct usb_interface *intf)
+{
+	struct v4l2_device *v = usb_get_intfdata(intf);
+	struct hackrf_dev *dev = container_of(v, struct hackrf_dev, v4l2_dev);
+
+	dev_dbg(dev->dev, "\n");
+
+	mutex_lock(&dev->vb_queue_lock);
+	mutex_lock(&dev->v4l2_lock);
+	/* No need to keep the urbs around after disconnection */
+	dev->udev = NULL;
+	v4l2_device_disconnect(&dev->v4l2_dev);
+	video_unregister_device(&dev->vdev);
+	mutex_unlock(&dev->v4l2_lock);
+	mutex_unlock(&dev->vb_queue_lock);
+
+	v4l2_device_put(&dev->v4l2_dev);
+}
+
+/* Videobuf2 operations */
+static int hackrf_queue_setup(struct vb2_queue *vq,
+		const struct v4l2_format *fmt, unsigned int *nbuffers,
+		unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+
+	dev_dbg(dev->dev, "nbuffers=%d\n", *nbuffers);
+
+	/* Need at least 8 buffers */
+	if (vq->num_buffers + *nbuffers < 8)
+		*nbuffers = 8 - vq->num_buffers;
+	*nplanes = 1;
+	sizes[0] = PAGE_ALIGN(dev->buffersize);
+
+	dev_dbg(dev->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
+	return 0;
+}
+
+static void hackrf_buf_queue(struct vb2_buffer *vb)
+{
+	struct hackrf_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+	struct hackrf_frame_buf *buf =
+			container_of(vb, struct hackrf_frame_buf, vb);
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+	list_add_tail(&buf->list, &dev->queued_bufs);
+	spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
+}
+
+static int hackrf_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+	int ret;
+
+	dev_dbg(dev->dev, "\n");
+
+	if (!dev->udev)
+		return -ENODEV;
+
+	mutex_lock(&dev->v4l2_lock);
+
+	dev->sequence = 0;
+
+	set_bit(POWER_ON, &dev->flags);
+
+	ret = hackrf_alloc_stream_bufs(dev);
+	if (ret)
+		goto err;
+
+	ret = hackrf_alloc_urbs(dev);
+	if (ret)
+		goto err;
+
+	ret = hackrf_submit_urbs(dev);
+	if (ret)
+		goto err;
+
+	/* start hardware streaming */
+	ret = hackrf_ctrl_msg(dev, CMD_SET_TRANSCEIVER_MODE, 1, 0, NULL, 0);
+	if (ret)
+		goto err;
+
+	goto exit_mutex_unlock;
+err:
+	hackrf_kill_urbs(dev);
+	hackrf_free_urbs(dev);
+	hackrf_free_stream_bufs(dev);
+	clear_bit(POWER_ON, &dev->flags);
+
+	/* return all queued buffers to vb2 */
+	{
+		struct hackrf_frame_buf *buf, *tmp;
+
+		list_for_each_entry_safe(buf, tmp, &dev->queued_bufs, list) {
+			list_del(&buf->list);
+			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+		}
+	}
+
+exit_mutex_unlock:
+	mutex_unlock(&dev->v4l2_lock);
+
+	return ret;
+}
+
+static void hackrf_stop_streaming(struct vb2_queue *vq)
+{
+	struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+
+	dev_dbg(dev->dev, "\n");
+
+	mutex_lock(&dev->v4l2_lock);
+
+	/* stop hardware streaming */
+	hackrf_ctrl_msg(dev, CMD_SET_TRANSCEIVER_MODE, 0, 0, NULL, 0);
+
+	hackrf_kill_urbs(dev);
+	hackrf_free_urbs(dev);
+	hackrf_free_stream_bufs(dev);
+
+	hackrf_cleanup_queued_bufs(dev);
+
+	clear_bit(POWER_ON, &dev->flags);
+
+	mutex_unlock(&dev->v4l2_lock);
+}
+
+static struct vb2_ops hackrf_vb2_ops = {
+	.queue_setup            = hackrf_queue_setup,
+	.buf_queue              = hackrf_buf_queue,
+	.start_streaming        = hackrf_start_streaming,
+	.stop_streaming         = hackrf_stop_streaming,
+	.wait_prepare           = vb2_ops_wait_prepare,
+	.wait_finish            = vb2_ops_wait_finish,
+};
+
+static int hackrf_querycap(struct file *file, void *fh,
+		struct v4l2_capability *cap)
+{
+	struct hackrf_dev *dev = video_drvdata(file);
+
+	dev_dbg(dev->dev, "\n");
+
+	strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+	strlcpy(cap->card, dev->vdev.name, sizeof(cap->card));
+	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+	cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
+			V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+	return 0;
+}
+
+static int hackrf_s_fmt_sdr_cap(struct file *file, void *priv,
+		struct v4l2_format *f)
+{
+	struct hackrf_dev *dev = video_drvdata(file);
+	struct vb2_queue *q = &dev->vb_queue;
+	int i;
+
+	dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
+			(char *)&f->fmt.sdr.pixelformat);
+
+	if (vb2_is_busy(q))
+		return -EBUSY;
+
+	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (f->fmt.sdr.pixelformat == formats[i].pixelformat) {
+			dev->pixelformat = formats[i].pixelformat;
+			dev->buffersize = formats[i].buffersize;
+			f->fmt.sdr.buffersize = formats[i].buffersize;
+			return 0;
+		}
+	}
+
+	dev->pixelformat = formats[0].pixelformat;
+	dev->buffersize = formats[0].buffersize;
+	f->fmt.sdr.pixelformat = formats[0].pixelformat;
+	f->fmt.sdr.buffersize = formats[0].buffersize;
+
+	return 0;
+}
+
+static int hackrf_g_fmt_sdr_cap(struct file *file, void *priv,
+		struct v4l2_format *f)
+{
+	struct hackrf_dev *dev = video_drvdata(file);
+
+	dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
+			(char *)&dev->pixelformat);
+
+	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+	f->fmt.sdr.pixelformat = dev->pixelformat;
+	f->fmt.sdr.buffersize = dev->buffersize;
+
+	return 0;
+}
+
+static int hackrf_try_fmt_sdr_cap(struct file *file, void *priv,
+		struct v4l2_format *f)
+{
+	struct hackrf_dev *dev = video_drvdata(file);
+	int i;
+
+	dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
+			(char *)&f->fmt.sdr.pixelformat);
+
+	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
+			f->fmt.sdr.buffersize = formats[i].buffersize;
+			return 0;
+		}
+	}
+
+	f->fmt.sdr.pixelformat = formats[0].pixelformat;
+	f->fmt.sdr.buffersize = formats[0].buffersize;
+
+	return 0;
+}
+
+static int hackrf_enum_fmt_sdr_cap(struct file *file, void *priv,
+		struct v4l2_fmtdesc *f)
+{
+	struct hackrf_dev *dev = video_drvdata(file);
+
+	dev_dbg(dev->dev, "index=%d\n", f->index);
+
+	if (f->index >= NUM_FORMATS)
+		return -EINVAL;
+
+	strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+	f->pixelformat = formats[f->index].pixelformat;
+
+	return 0;
+}
+
+static int hackrf_s_tuner(struct file *file, void *priv,
+		const struct v4l2_tuner *v)
+{
+	struct hackrf_dev *dev = video_drvdata(file);
+	int ret;
+
+	dev_dbg(dev->dev, "index=%d\n", v->index);
+
+	if (v->index == 0)
+		ret = 0;
+	else if (v->index == 1)
+		ret = 0;
+	else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static int hackrf_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
+{
+	struct hackrf_dev *dev = video_drvdata(file);
+	int ret;
+
+	dev_dbg(dev->dev, "index=%d\n", v->index);
+
+	if (v->index == 0) {
+		strlcpy(v->name, "HackRF ADC", sizeof(v->name));
+		v->type = V4L2_TUNER_ADC;
+		v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+		v->rangelow  = bands_adc[0].rangelow;
+		v->rangehigh = bands_adc[0].rangehigh;
+		ret = 0;
+	} else if (v->index == 1) {
+		strlcpy(v->name, "HackRF RF", sizeof(v->name));
+		v->type = V4L2_TUNER_RF;
+		v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+		v->rangelow  = bands_rf[0].rangelow;
+		v->rangehigh = bands_rf[0].rangehigh;
+		ret = 0;
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int hackrf_s_frequency(struct file *file, void *priv,
+		const struct v4l2_frequency *f)
+{
+	struct hackrf_dev *dev = video_drvdata(file);
+	int ret;
+	unsigned int upper, lower;
+	u8 buf[8];
+
+	dev_dbg(dev->dev, "tuner=%d type=%d frequency=%u\n",
+			f->tuner, f->type, f->frequency);
+
+	if (f->tuner == 0) {
+		dev->f_adc = clamp_t(unsigned int, f->frequency,
+				bands_adc[0].rangelow, bands_adc[0].rangehigh);
+		dev_dbg(dev->dev, "ADC frequency=%u Hz\n", dev->f_adc);
+		upper = dev->f_adc;
+		lower = 1;
+		buf[0] = (upper >>  0) & 0xff;
+		buf[1] = (upper >>  8) & 0xff;
+		buf[2] = (upper >> 16) & 0xff;
+		buf[3] = (upper >> 24) & 0xff;
+		buf[4] = (lower >>  0) & 0xff;
+		buf[5] = (lower >>  8) & 0xff;
+		buf[6] = (lower >> 16) & 0xff;
+		buf[7] = (lower >> 24) & 0xff;
+		ret = hackrf_ctrl_msg(dev, CMD_SAMPLE_RATE_SET, 0, 0, buf, 8);
+	} else if (f->tuner == 1) {
+		dev->f_rf = clamp_t(unsigned int, f->frequency,
+				bands_rf[0].rangelow, bands_rf[0].rangehigh);
+		dev_dbg(dev->dev, "RF frequency=%u Hz\n", dev->f_rf);
+		upper = dev->f_rf / 1000000;
+		lower = dev->f_rf % 1000000;
+		buf[0] = (upper >>  0) & 0xff;
+		buf[1] = (upper >>  8) & 0xff;
+		buf[2] = (upper >> 16) & 0xff;
+		buf[3] = (upper >> 24) & 0xff;
+		buf[4] = (lower >>  0) & 0xff;
+		buf[5] = (lower >>  8) & 0xff;
+		buf[6] = (lower >> 16) & 0xff;
+		buf[7] = (lower >> 24) & 0xff;
+		ret = hackrf_ctrl_msg(dev, CMD_SET_FREQ, 0, 0, buf, 8);
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int hackrf_g_frequency(struct file *file, void *priv,
+		struct v4l2_frequency *f)
+{
+	struct hackrf_dev *dev = video_drvdata(file);
+	int ret;
+
+	dev_dbg(dev->dev, "tuner=%d type=%d\n", f->tuner, f->type);
+
+	if (f->tuner == 0) {
+		f->type = V4L2_TUNER_ADC;
+		f->frequency = dev->f_adc;
+		ret = 0;
+	} else if (f->tuner == 1) {
+		f->type = V4L2_TUNER_RF;
+		f->frequency = dev->f_rf;
+		ret = 0;
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int hackrf_enum_freq_bands(struct file *file, void *priv,
+		struct v4l2_frequency_band *band)
+{
+	struct hackrf_dev *dev = video_drvdata(file);
+	int ret;
+
+	dev_dbg(dev->dev, "tuner=%d type=%d index=%d\n",
+			band->tuner, band->type, band->index);
+
+	if (band->tuner == 0) {
+		if (band->index >= ARRAY_SIZE(bands_adc)) {
+			ret = -EINVAL;
+		} else {
+			*band = bands_adc[band->index];
+			ret = 0;
+		}
+	} else if (band->tuner == 1) {
+		if (band->index >= ARRAY_SIZE(bands_rf)) {
+			ret = -EINVAL;
+		} else {
+			*band = bands_rf[band->index];
+			ret = 0;
+		}
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct v4l2_ioctl_ops hackrf_ioctl_ops = {
+	.vidioc_querycap          = hackrf_querycap,
+
+	.vidioc_s_fmt_sdr_cap     = hackrf_s_fmt_sdr_cap,
+	.vidioc_g_fmt_sdr_cap     = hackrf_g_fmt_sdr_cap,
+	.vidioc_enum_fmt_sdr_cap  = hackrf_enum_fmt_sdr_cap,
+	.vidioc_try_fmt_sdr_cap   = hackrf_try_fmt_sdr_cap,
+
+	.vidioc_reqbufs           = vb2_ioctl_reqbufs,
+	.vidioc_create_bufs       = vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf       = vb2_ioctl_prepare_buf,
+	.vidioc_querybuf          = vb2_ioctl_querybuf,
+	.vidioc_qbuf              = vb2_ioctl_qbuf,
+	.vidioc_dqbuf             = vb2_ioctl_dqbuf,
+
+	.vidioc_streamon          = vb2_ioctl_streamon,
+	.vidioc_streamoff         = vb2_ioctl_streamoff,
+
+	.vidioc_s_tuner           = hackrf_s_tuner,
+	.vidioc_g_tuner           = hackrf_g_tuner,
+
+	.vidioc_s_frequency       = hackrf_s_frequency,
+	.vidioc_g_frequency       = hackrf_g_frequency,
+	.vidioc_enum_freq_bands   = hackrf_enum_freq_bands,
+
+	.vidioc_subscribe_event   = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+	.vidioc_log_status        = v4l2_ctrl_log_status,
+};
+
+static const struct v4l2_file_operations hackrf_fops = {
+	.owner                    = THIS_MODULE,
+	.open                     = v4l2_fh_open,
+	.release                  = vb2_fop_release,
+	.read                     = vb2_fop_read,
+	.poll                     = vb2_fop_poll,
+	.mmap                     = vb2_fop_mmap,
+	.unlocked_ioctl           = video_ioctl2,
+};
+
+static struct video_device hackrf_template = {
+	.name                     = "HackRF One",
+	.release                  = video_device_release_empty,
+	.fops                     = &hackrf_fops,
+	.ioctl_ops                = &hackrf_ioctl_ops,
+};
+
+static void hackrf_video_release(struct v4l2_device *v)
+{
+	struct hackrf_dev *dev = container_of(v, struct hackrf_dev, v4l2_dev);
+
+	v4l2_ctrl_handler_free(&dev->hdl);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	kfree(dev);
+}
+
+static int hackrf_set_bandwidth(struct hackrf_dev *dev)
+{
+	int ret, i;
+	u16 u16tmp, u16tmp2;
+	unsigned int bandwidth;
+
+	static const struct {
+		u32 freq;
+	} bandwidth_lut[] = {
+		{ 1750000}, /*  1.75 MHz */
+		{ 2500000}, /*  2.5  MHz */
+		{ 3500000}, /*  3.5  MHz */
+		{ 5000000}, /*  5    MHz */
+		{ 5500000}, /*  5.5  MHz */
+		{ 6000000}, /*  6    MHz */
+		{ 7000000}, /*  7    MHz */
+		{ 8000000}, /*  8    MHz */
+		{ 9000000}, /*  9    MHz */
+		{10000000}, /* 10    MHz */
+		{12000000}, /* 12    MHz */
+		{14000000}, /* 14    MHz */
+		{15000000}, /* 15    MHz */
+		{20000000}, /* 20    MHz */
+		{24000000}, /* 24    MHz */
+		{28000000}, /* 28    MHz */
+	};
+
+	dev_dbg(dev->dev, "bandwidth auto=%d->%d val=%d->%d f_adc=%u\n",
+			dev->bandwidth_auto->cur.val,
+			dev->bandwidth_auto->val, dev->bandwidth->cur.val,
+			dev->bandwidth->val, dev->f_adc);
+
+	if (dev->bandwidth_auto->val == true)
+		bandwidth = dev->f_adc;
+	else
+		bandwidth = dev->bandwidth->val;
+
+	for (i = 0; i < ARRAY_SIZE(bandwidth_lut); i++) {
+		if (bandwidth <= bandwidth_lut[i].freq) {
+			bandwidth = bandwidth_lut[i].freq;
+			break;
+		}
+	}
+
+	dev->bandwidth->val = bandwidth;
+	dev->bandwidth->cur.val = bandwidth;
+
+	dev_dbg(dev->dev, "bandwidth selected=%d\n", bandwidth_lut[i].freq);
+
+	u16tmp = 0;
+	u16tmp |= ((bandwidth >> 0) & 0xff) << 0;
+	u16tmp |= ((bandwidth >> 8) & 0xff) << 8;
+	u16tmp2 = 0;
+	u16tmp2 |= ((bandwidth >> 16) & 0xff) << 0;
+	u16tmp2 |= ((bandwidth >> 24) & 0xff) << 8;
+
+	ret = hackrf_ctrl_msg(dev, CMD_BASEBAND_FILTER_BANDWIDTH_SET,
+				u16tmp, u16tmp2, NULL, 0);
+	if (ret)
+		dev_dbg(dev->dev, "failed=%d\n", ret);
+
+	return ret;
+}
+
+static int hackrf_set_lna_gain(struct hackrf_dev *dev)
+{
+	int ret;
+	u8 u8tmp;
+
+	dev_dbg(dev->dev, "lna val=%d->%d\n",
+			dev->lna_gain->cur.val, dev->lna_gain->val);
+
+	ret = hackrf_ctrl_msg(dev, CMD_SET_LNA_GAIN, 0, dev->lna_gain->val,
+			&u8tmp, 1);
+	if (ret)
+		dev_dbg(dev->dev, "failed=%d\n", ret);
+
+	return ret;
+}
+
+static int hackrf_set_if_gain(struct hackrf_dev *dev)
+{
+	int ret;
+	u8 u8tmp;
+
+	dev_dbg(dev->dev, "val=%d->%d\n",
+			dev->if_gain->cur.val, dev->if_gain->val);
+
+	ret = hackrf_ctrl_msg(dev, CMD_SET_VGA_GAIN, 0, dev->if_gain->val,
+			&u8tmp, 1);
+	if (ret)
+		dev_dbg(dev->dev, "failed=%d\n", ret);
+
+	return ret;
+}
+
+static int hackrf_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct hackrf_dev *dev = container_of(ctrl->handler,
+			struct hackrf_dev, hdl);
+	int ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
+	case V4L2_CID_RF_TUNER_BANDWIDTH:
+		ret = hackrf_set_bandwidth(dev);
+		break;
+	case  V4L2_CID_RF_TUNER_LNA_GAIN:
+		ret = hackrf_set_lna_gain(dev);
+		break;
+	case  V4L2_CID_RF_TUNER_IF_GAIN:
+		ret = hackrf_set_if_gain(dev);
+		break;
+	default:
+		dev_dbg(dev->dev, "unknown ctrl: id=%d name=%s\n",
+				ctrl->id, ctrl->name);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops hackrf_ctrl_ops = {
+	.s_ctrl = hackrf_s_ctrl,
+};
+
+static int hackrf_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	struct hackrf_dev *dev;
+	int ret;
+	u8 u8tmp, buf[BUF_SIZE];
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL)
+		return -ENOMEM;
+
+	mutex_init(&dev->v4l2_lock);
+	mutex_init(&dev->vb_queue_lock);
+	spin_lock_init(&dev->queued_bufs_lock);
+	INIT_LIST_HEAD(&dev->queued_bufs);
+	dev->dev = &intf->dev;
+	dev->udev = interface_to_usbdev(intf);
+	dev->f_adc = bands_adc[0].rangelow;
+	dev->f_rf = bands_rf[0].rangelow;
+	dev->pixelformat = formats[0].pixelformat;
+	dev->buffersize = formats[0].buffersize;
+
+	/* Detect device */
+	ret = hackrf_ctrl_msg(dev, CMD_BOARD_ID_READ, 0, 0, &u8tmp, 1);
+	if (ret == 0)
+		ret = hackrf_ctrl_msg(dev, CMD_VERSION_STRING_READ, 0, 0,
+				buf, BUF_SIZE);
+	if (ret) {
+		dev_err(dev->dev, "Could not detect board\n");
+		goto err_free_mem;
+	}
+
+	buf[BUF_SIZE - 1] = '\0';
+
+	dev_info(dev->dev, "Board ID: %02x\n", u8tmp);
+	dev_info(dev->dev, "Firmware version: %s\n", buf);
+
+	/* Init videobuf2 queue structure */
+	dev->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
+	dev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+	dev->vb_queue.drv_priv = dev;
+	dev->vb_queue.buf_struct_size = sizeof(struct hackrf_frame_buf);
+	dev->vb_queue.ops = &hackrf_vb2_ops;
+	dev->vb_queue.mem_ops = &vb2_vmalloc_memops;
+	dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	ret = vb2_queue_init(&dev->vb_queue);
+	if (ret) {
+		dev_err(dev->dev, "Could not initialize vb2 queue\n");
+		goto err_free_mem;
+	}
+
+	/* Init video_device structure */
+	dev->vdev = hackrf_template;
+	dev->vdev.queue = &dev->vb_queue;
+	dev->vdev.queue->lock = &dev->vb_queue_lock;
+	video_set_drvdata(&dev->vdev, dev);
+
+	/* Register the v4l2_device structure */
+	dev->v4l2_dev.release = hackrf_video_release;
+	ret = v4l2_device_register(&intf->dev, &dev->v4l2_dev);
+	if (ret) {
+		dev_err(dev->dev, "Failed to register v4l2-device (%d)\n", ret);
+		goto err_free_mem;
+	}
+
+	/* Register controls */
+	v4l2_ctrl_handler_init(&dev->hdl, 4);
+	dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+			V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
+	dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+			V4L2_CID_RF_TUNER_BANDWIDTH,
+			1750000, 28000000, 50000, 1750000);
+	v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
+	dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+			V4L2_CID_RF_TUNER_LNA_GAIN, 0, 40, 8, 0);
+	dev->if_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+			V4L2_CID_RF_TUNER_IF_GAIN, 0, 62, 2, 0);
+	if (dev->hdl.error) {
+		ret = dev->hdl.error;
+		dev_err(dev->dev, "Could not initialize controls\n");
+		goto err_free_controls;
+	}
+
+	v4l2_ctrl_handler_setup(&dev->hdl);
+
+	dev->v4l2_dev.ctrl_handler = &dev->hdl;
+	dev->vdev.v4l2_dev = &dev->v4l2_dev;
+	dev->vdev.lock = &dev->v4l2_lock;
+
+	ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1);
+	if (ret) {
+		dev_err(dev->dev, "Failed to register as video device (%d)\n",
+				ret);
+		goto err_unregister_v4l2_dev;
+	}
+	dev_info(dev->dev, "Registered as %s\n",
+			video_device_node_name(&dev->vdev));
+	dev_notice(dev->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
+	return 0;
+
+err_free_controls:
+	v4l2_ctrl_handler_free(&dev->hdl);
+err_unregister_v4l2_dev:
+	v4l2_device_unregister(&dev->v4l2_dev);
+err_free_mem:
+	kfree(dev);
+	return ret;
+}
+
+/* USB device ID list */
+static struct usb_device_id hackrf_id_table[] = {
+	{ USB_DEVICE(0x1d50, 0x6089) }, /* HackRF One */
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, hackrf_id_table);
+
+/* USB subsystem interface */
+static struct usb_driver hackrf_driver = {
+	.name                     = KBUILD_MODNAME,
+	.probe                    = hackrf_probe,
+	.disconnect               = hackrf_disconnect,
+	.id_table                 = hackrf_id_table,
+};
+
+module_usb_driver(hackrf_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("HackRF");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/hdpvr/hdpvr-control.c b/drivers/media/usb/hdpvr/hdpvr-control.c
index 6053661..6e86032 100644
--- a/drivers/media/usb/hdpvr/hdpvr-control.c
+++ b/drivers/media/usb/hdpvr/hdpvr-control.c
@@ -59,13 +59,10 @@
 			      1000);
 
 #ifdef HDPVR_DEBUG
-	if (hdpvr_debug & MSG_INFO) {
-		char print_buf[15];
-		hex_dump_to_buffer(dev->usbc_buf, 5, 16, 1, print_buf,
-				   sizeof(print_buf), 0);
+	if (hdpvr_debug & MSG_INFO)
 		v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
-			 "get video info returned: %d, %s\n", ret, print_buf);
-	}
+			 "get video info returned: %d, %5ph\n", ret,
+			 dev->usbc_buf);
 #endif
 	mutex_unlock(&dev->usbc_mutex);
 
@@ -82,9 +79,6 @@
 
 int get_input_lines_info(struct hdpvr_device *dev)
 {
-#ifdef HDPVR_DEBUG
-	char print_buf[9];
-#endif
 	int ret, lines;
 
 	mutex_lock(&dev->usbc_mutex);
@@ -96,13 +90,10 @@
 			      1000);
 
 #ifdef HDPVR_DEBUG
-	if (hdpvr_debug & MSG_INFO) {
-		hex_dump_to_buffer(dev->usbc_buf, 3, 16, 1, print_buf,
-				   sizeof(print_buf), 0);
+	if (hdpvr_debug & MSG_INFO)
 		v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
-			 "get input lines info returned: %d, %s\n", ret,
-			 print_buf);
-	}
+			 "get input lines info returned: %d, %3ph\n", ret,
+			 dev->usbc_buf);
 #else
 	(void)ret;	/* suppress compiler warning */
 #endif
diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index c563896..42b4cdf 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -124,14 +124,6 @@
 	int ret, retval = -ENOMEM;
 	char request_type = 0x38, rcv_request = 0x81;
 	char *response;
-#ifdef HDPVR_DEBUG
-	size_t buf_size = 46;
-	char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL);
-	if (!print_buf) {
-		v4l2_err(&dev->v4l2_dev, "Out of memory\n");
-		return retval;
-	}
-#endif
 
 	mutex_lock(&dev->usbc_mutex);
 	ret = usb_control_msg(dev->udev,
@@ -147,11 +139,9 @@
 	}
 #ifdef HDPVR_DEBUG
 	else {
-		hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf,
-				   5*buf_size+1, 0);
 		v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
-			 "Status request returned, len %d: %s\n",
-			 ret, print_buf);
+			 "Status request returned, len %d: %46ph\n",
+			 ret, dev->usbc_buf);
 	}
 #endif
 
@@ -189,15 +179,13 @@
 
 	response = dev->usbc_buf+38;
 #ifdef HDPVR_DEBUG
-	hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0);
-	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n",
-		 print_buf);
+	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %8ph\n",
+		 response);
 #endif
 	challenge(response);
 #ifdef HDPVR_DEBUG
-	hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0);
-	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n",
-		 print_buf);
+	v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %8ph\n",
+		 response);
 #endif
 
 	msleep(100);
@@ -213,9 +201,6 @@
 	retval = ret != 8;
 unlock:
 	mutex_unlock(&dev->usbc_mutex);
-#ifdef HDPVR_DEBUG
-	kfree(print_buf);
-#endif
 	return retval;
 }
 
diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c
index 26b1334..efc761c 100644
--- a/drivers/media/usb/msi2500/msi2500.c
+++ b/drivers/media/usb/msi2500/msi2500.c
@@ -120,6 +120,7 @@
 };
 
 struct msi2500_state {
+	struct device *dev;
 	struct video_device vdev;
 	struct v4l2_device v4l2_dev;
 	struct v4l2_subdev *v4l2_subdev;
@@ -153,14 +154,13 @@
 	u32 next_sample; /* for track lost packets */
 	u32 sample; /* for sample rate calc */
 	unsigned long jiffies_next;
-	unsigned int sample_ctrl_bit[4];
 };
 
 /* Private functions */
 static struct msi2500_frame_buf *msi2500_get_next_fill_buf(
 		struct msi2500_state *s)
 {
-	unsigned long flags = 0;
+	unsigned long flags;
 	struct msi2500_frame_buf *buf = NULL;
 
 	spin_lock_irqsave(&s->queued_bufs_lock, flags);
@@ -269,7 +269,7 @@
 		sample[i] = src[3] << 24 | src[2] << 16 | src[1] << 8 |
 				src[0] << 0;
 		if (i == 0 && s->next_sample != sample[0]) {
-			dev_dbg_ratelimited(&s->udev->dev,
+			dev_dbg_ratelimited(s->dev,
 					"%d samples lost, %d %08x:%08x\n",
 					sample[0] - s->next_sample,
 					src_len, s->next_sample, sample[0]);
@@ -279,7 +279,7 @@
 		 * Dump all unknown 'garbage' data - maybe we will discover
 		 * someday if there is something rational...
 		 */
-		dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]);
+		dev_dbg_ratelimited(s->dev, "%*ph\n", 12, &src[4]);
 
 		src += 16; /* skip header */
 
@@ -322,8 +322,7 @@
 		}
 		case MSI2500_PIX_FMT_SDR_MSI2500_384: /* 384 x IQ samples */
 			/* Dump unknown 'garbage' data */
-			dev_dbg_ratelimited(&s->udev->dev,
-					"%*ph\n", 24, &src[1000]);
+			dev_dbg_ratelimited(s->dev, "%*ph\n", 24, &src[1000]);
 			memcpy(dst, src, 984);
 			src += 984 + 24;
 			dst += 984;
@@ -365,8 +364,7 @@
 
 		s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
 		s->sample = s->next_sample;
-		dev_dbg(&s->udev->dev,
-				"size=%u samples=%u msecs=%u sample rate=%lu\n",
+		dev_dbg(s->dev, "size=%u samples=%u msecs=%u sample rate=%lu\n",
 				src_len, samples, msecs,
 				samples * 1000UL / msecs);
 	}
@@ -387,19 +385,16 @@
 
 	if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET ||
 			urb->status == -ESHUTDOWN)) {
-		dev_dbg(&s->udev->dev, "URB (%p) unlinked %ssynchronuously\n",
+		dev_dbg(s->dev, "URB (%p) unlinked %ssynchronuously\n",
 				urb, urb->status == -ENOENT ? "" : "a");
 		return;
 	}
 
 	if (unlikely(urb->status != 0)) {
-		dev_dbg(&s->udev->dev,
-				"msi2500_isoc_handler() called with status %d\n",
-				urb->status);
+		dev_dbg(s->dev, "called with status %d\n", urb->status);
 		/* Give up after a number of contiguous errors */
 		if (++s->isoc_errors > MAX_ISOC_ERRORS)
-			dev_dbg(&s->udev->dev,
-					"Too many ISOC errors, bailing out\n");
+			dev_dbg(s->dev, "Too many ISOC errors, bailing out\n");
 		goto handler_end;
 	} else {
 		/* Reset ISOC error counter. We did get here, after all. */
@@ -413,7 +408,7 @@
 		/* Check frame error */
 		fstatus = urb->iso_frame_desc[i].status;
 		if (unlikely(fstatus)) {
-			dev_dbg_ratelimited(&s->udev->dev,
+			dev_dbg_ratelimited(s->dev,
 					"frame=%d/%d has error %d skipping\n",
 					i, urb->number_of_packets, fstatus);
 			continue;
@@ -430,7 +425,7 @@
 		fbuf = msi2500_get_next_fill_buf(s);
 		if (unlikely(fbuf == NULL)) {
 			s->vb_full++;
-			dev_dbg_ratelimited(&s->udev->dev,
+			dev_dbg_ratelimited(s->dev,
 					"videobuf is full, %d packets dropped\n",
 					s->vb_full);
 			continue;
@@ -446,22 +441,19 @@
 handler_end:
 	i = usb_submit_urb(urb, GFP_ATOMIC);
 	if (unlikely(i != 0))
-		dev_dbg(&s->udev->dev,
-				"Error (%d) re-submitting urb in msi2500_isoc_handler\n",
-				i);
+		dev_dbg(s->dev, "Error (%d) re-submitting urb\n", i);
 }
 
 static void msi2500_iso_stop(struct msi2500_state *s)
 {
 	int i;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	/* Unlinking ISOC buffers one by one */
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		if (s->urbs[i]) {
-			dev_dbg(&s->udev->dev, "Unlinking URB %p\n",
-					s->urbs[i]);
+			dev_dbg(s->dev, "Unlinking URB %p\n", s->urbs[i]);
 			usb_kill_urb(s->urbs[i]);
 		}
 	}
@@ -471,12 +463,12 @@
 {
 	int i;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	/* Freeing ISOC buffers one by one */
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		if (s->urbs[i]) {
-			dev_dbg(&s->udev->dev, "Freeing URB\n");
+			dev_dbg(s->dev, "Freeing URB\n");
 			if (s->urbs[i]->transfer_buffer) {
 				usb_free_coherent(s->udev,
 					s->urbs[i]->transfer_buffer_length,
@@ -492,7 +484,7 @@
 /* Both v4l2_lock and vb_queue_lock should be locked when calling this */
 static void msi2500_isoc_cleanup(struct msi2500_state *s)
 {
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	msi2500_iso_stop(s);
 	msi2500_iso_free(s);
@@ -501,14 +493,12 @@
 /* Both v4l2_lock and vb_queue_lock should be locked when calling this */
 static int msi2500_isoc_init(struct msi2500_state *s)
 {
-	struct usb_device *udev;
 	struct urb *urb;
 	int i, j, ret;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	s->isoc_errors = 0;
-	udev = s->udev;
 
 	ret = usb_set_interface(s->udev, 0, 1);
 	if (ret)
@@ -518,23 +508,22 @@
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
 		if (urb == NULL) {
-			dev_err(&s->udev->dev,
-					"Failed to allocate urb %d\n", i);
+			dev_err(s->dev, "Failed to allocate urb %d\n", i);
 			msi2500_isoc_cleanup(s);
 			return -ENOMEM;
 		}
 		s->urbs[i] = urb;
-		dev_dbg(&s->udev->dev, "Allocated URB at 0x%p\n", urb);
+		dev_dbg(s->dev, "Allocated URB at 0x%p\n", urb);
 
 		urb->interval = 1;
-		urb->dev = udev;
-		urb->pipe = usb_rcvisocpipe(udev, 0x81);
+		urb->dev = s->udev;
+		urb->pipe = usb_rcvisocpipe(s->udev, 0x81);
 		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-		urb->transfer_buffer = usb_alloc_coherent(udev, ISO_BUFFER_SIZE,
+		urb->transfer_buffer = usb_alloc_coherent(s->udev,
+				ISO_BUFFER_SIZE,
 				GFP_KERNEL, &urb->transfer_dma);
 		if (urb->transfer_buffer == NULL) {
-			dev_err(&s->udev->dev,
-					"Failed to allocate urb buffer %d\n",
+			dev_err(s->dev, "Failed to allocate urb buffer %d\n",
 					i);
 			msi2500_isoc_cleanup(s);
 			return -ENOMEM;
@@ -554,13 +543,12 @@
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		ret = usb_submit_urb(s->urbs[i], GFP_KERNEL);
 		if (ret) {
-			dev_err(&s->udev->dev,
-					"isoc_init() submit_urb %d failed with error %d\n",
+			dev_err(s->dev, "usb_submit_urb %d failed with error %d\n",
 					i, ret);
 			msi2500_isoc_cleanup(s);
 			return ret;
 		}
-		dev_dbg(&s->udev->dev, "URB 0x%p submitted.\n", s->urbs[i]);
+		dev_dbg(s->dev, "URB 0x%p submitted.\n", s->urbs[i]);
 	}
 
 	/* All is done... */
@@ -570,9 +558,9 @@
 /* Must be called with vb_queue_lock hold */
 static void msi2500_cleanup_queued_bufs(struct msi2500_state *s)
 {
-	unsigned long flags = 0;
+	unsigned long flags;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	spin_lock_irqsave(&s->queued_bufs_lock, flags);
 	while (!list_empty(&s->queued_bufs)) {
@@ -593,7 +581,7 @@
 	struct msi2500_state *s =
 			container_of(v, struct msi2500_state, v4l2_dev);
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	mutex_lock(&s->vb_queue_lock);
 	mutex_lock(&s->v4l2_lock);
@@ -613,7 +601,7 @@
 {
 	struct msi2500_state *s = video_drvdata(file);
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
 	strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
@@ -631,14 +619,13 @@
 {
 	struct msi2500_state *s = vb2_get_drv_priv(vq);
 
-	dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
+	dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers);
 
 	/* Absolute min and max number of buffers available for mmap() */
 	*nbuffers = clamp_t(unsigned int, *nbuffers, 8, 32);
 	*nplanes = 1;
 	sizes[0] = PAGE_ALIGN(s->buffersize);
-	dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
-			__func__, *nbuffers, sizes[0]);
+	dev_dbg(s->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
 	return 0;
 }
 
@@ -647,7 +634,7 @@
 	struct msi2500_state *s = vb2_get_drv_priv(vb->vb2_queue);
 	struct msi2500_frame_buf *buf =
 			container_of(vb, struct msi2500_frame_buf, vb);
-	unsigned long flags = 0;
+	unsigned long flags;
 
 	/* Check the device has not disconnected between prep and queuing */
 	if (unlikely(!s->udev)) {
@@ -665,16 +652,15 @@
 #define CMD_STOP_STREAMING     0x45
 #define CMD_READ_UNKNOW        0x48
 
-#define msi2500_dbg_usb_control_msg(_udev, _r, _t, _v, _i, _b, _l) { \
+#define msi2500_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \
 	char *_direction; \
 	if (_t & USB_DIR_IN) \
 		_direction = "<<<"; \
 	else \
 		_direction = ">>>"; \
-	dev_dbg(&_udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \
-			"%s %*ph\n",  __func__, _t, _r, _v & 0xff, _v >> 8, \
-			_i & 0xff, _i >> 8, _l & 0xff, _l >> 8, _direction, \
-			_l, _b); \
+	dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \
+			_t, _r, _v & 0xff, _v >> 8, _i & 0xff, _i >> 8, \
+			_l & 0xff, _l >> 8, _direction, _l, _b); \
 }
 
 static int msi2500_ctrl_msg(struct msi2500_state *s, u8 cmd, u32 data)
@@ -685,18 +671,16 @@
 	u16 value = (data >> 0) & 0xffff;
 	u16 index = (data >> 16) & 0xffff;
 
-	msi2500_dbg_usb_control_msg(s->udev,
+	msi2500_dbg_usb_control_msg(s->dev,
 			request, requesttype, value, index, NULL, 0);
-
 	ret = usb_control_msg(s->udev, usb_sndctrlpipe(s->udev, 0),
 			request, requesttype, value, index, NULL, 0, 2000);
-
 	if (ret)
-		dev_err(&s->udev->dev, "%s: failed %d, cmd %02x, data %04x\n",
-				__func__, ret, cmd, data);
+		dev_err(s->dev, "failed %d, cmd %02x, data %04x\n",
+				ret, cmd, data);
 
 	return ret;
-};
+}
 
 #define F_REF 24000000
 #define DIV_R_IN 2
@@ -785,8 +769,7 @@
 
 	for (div_r_out = 4; div_r_out < 16; div_r_out += 2) {
 		f_vco = f_sr * div_r_out * 12;
-		dev_dbg(&s->udev->dev, "%s: div_r_out=%d f_vco=%d\n",
-				__func__, div_r_out, f_vco);
+		dev_dbg(s->dev, "div_r_out=%d f_vco=%d\n", div_r_out, f_vco);
 		if (f_vco >= 202000000)
 			break;
 	}
@@ -800,10 +783,8 @@
 	reg3 |= ((fract >> 20) & 0x000001) << 15; /* [20] */
 	reg4 |= ((fract >>  0) & 0x0fffff) <<  8; /* [19:0] */
 
-	dev_dbg(&s->udev->dev,
-			"%s: f_sr=%d f_vco=%d div_n=%d div_m=%d div_r_out=%d reg3=%08x reg4=%08x\n",
-			__func__, f_sr, f_vco, div_n, div_m, div_r_out, reg3,
-			reg4);
+	dev_dbg(s->dev, "f_sr=%d f_vco=%d div_n=%d div_m=%d div_r_out=%d reg3=%08x reg4=%08x\n",
+			f_sr, f_vco, div_n, div_m, div_r_out, reg3, reg4);
 
 	ret = msi2500_ctrl_msg(s, CMD_WREG, 0x00608008);
 	if (ret)
@@ -838,14 +819,14 @@
 		goto err;
 err:
 	return ret;
-};
+}
 
 static int msi2500_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
 	struct msi2500_state *s = vb2_get_drv_priv(vq);
 	int ret;
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	if (!s->udev)
 		return -ENODEV;
@@ -873,7 +854,7 @@
 {
 	struct msi2500_state *s = vb2_get_drv_priv(vq);
 
-	dev_dbg(&s->udev->dev, "%s:\n", __func__);
+	dev_dbg(s->dev, "\n");
 
 	mutex_lock(&s->v4l2_lock);
 
@@ -909,7 +890,7 @@
 {
 	struct msi2500_state *s = video_drvdata(file);
 
-	dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, f->index);
+	dev_dbg(s->dev, "index=%d\n", f->index);
 
 	if (f->index >= s->num_formats)
 		return -EINVAL;
@@ -925,7 +906,7 @@
 {
 	struct msi2500_state *s = video_drvdata(file);
 
-	dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+	dev_dbg(s->dev, "pixelformat fourcc %4.4s\n",
 			(char *)&s->pixelformat);
 
 	f->fmt.sdr.pixelformat = s->pixelformat;
@@ -942,7 +923,7 @@
 	struct vb2_queue *q = &s->vb_queue;
 	int i;
 
-	dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+	dev_dbg(s->dev, "pixelformat fourcc %4.4s\n",
 			(char *)&f->fmt.sdr.pixelformat);
 
 	if (vb2_is_busy(q))
@@ -972,7 +953,7 @@
 	struct msi2500_state *s = video_drvdata(file);
 	int i;
 
-	dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+	dev_dbg(s->dev, "pixelformat fourcc %4.4s\n",
 			(char *)&f->fmt.sdr.pixelformat);
 
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
@@ -995,7 +976,7 @@
 	struct msi2500_state *s = video_drvdata(file);
 	int ret;
 
-	dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
+	dev_dbg(s->dev, "index=%d\n", v->index);
 
 	if (v->index == 0)
 		ret = 0;
@@ -1012,7 +993,7 @@
 	struct msi2500_state *s = video_drvdata(file);
 	int ret;
 
-	dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
+	dev_dbg(s->dev, "index=%d\n", v->index);
 
 	if (v->index == 0) {
 		strlcpy(v->name, "Mirics MSi2500", sizeof(v->name));
@@ -1036,8 +1017,7 @@
 	struct msi2500_state *s = video_drvdata(file);
 	int ret  = 0;
 
-	dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
-			__func__, f->tuner, f->type);
+	dev_dbg(s->dev, "tuner=%d type=%d\n", f->tuner, f->type);
 
 	if (f->tuner == 0) {
 		f->frequency = s->f_adc;
@@ -1058,15 +1038,14 @@
 	struct msi2500_state *s = video_drvdata(file);
 	int ret;
 
-	dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
-			__func__, f->tuner, f->type, f->frequency);
+	dev_dbg(s->dev, "tuner=%d type=%d frequency=%u\n",
+			f->tuner, f->type, f->frequency);
 
 	if (f->tuner == 0) {
 		s->f_adc = clamp_t(unsigned int, f->frequency,
 				bands[0].rangelow,
 				bands[0].rangehigh);
-		dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
-				__func__, s->f_adc);
+		dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc);
 		ret = msi2500_set_usb_adc(s);
 	} else if (f->tuner == 1) {
 		ret = v4l2_subdev_call(s->v4l2_subdev, tuner, s_frequency, f);
@@ -1083,8 +1062,8 @@
 	struct msi2500_state *s = video_drvdata(file);
 	int ret;
 
-	dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
-			__func__, band->tuner, band->type, band->index);
+	dev_dbg(s->dev, "tuner=%d type=%d index=%d\n",
+			band->tuner, band->type, band->index);
 
 	if (band->tuner == 0) {
 		if (band->index >= ARRAY_SIZE(bands)) {
@@ -1169,8 +1148,7 @@
 	u32 data;
 
 	list_for_each_entry(t, &m->transfers, transfer_list) {
-		dev_dbg(&s->udev->dev, "%s: msg=%*ph\n",
-				__func__, t->len, t->tx_buf);
+		dev_dbg(s->dev, "msg=%*ph\n", t->len, t->tx_buf);
 		data = 0x09; /* reg 9 is SPI adapter */
 		data |= ((u8 *)t->tx_buf)[0] << 8;
 		data |= ((u8 *)t->tx_buf)[1] << 16;
@@ -1186,8 +1164,7 @@
 static int msi2500_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct msi2500_state *s = NULL;
+	struct msi2500_state *s;
 	struct v4l2_subdev *sd;
 	struct spi_master *master;
 	int ret;
@@ -1200,7 +1177,7 @@
 
 	s = kzalloc(sizeof(struct msi2500_state), GFP_KERNEL);
 	if (s == NULL) {
-		pr_err("Could not allocate memory for msi2500_state\n");
+		dev_err(&intf->dev, "Could not allocate memory for state\n");
 		return -ENOMEM;
 	}
 
@@ -1208,12 +1185,13 @@
 	mutex_init(&s->vb_queue_lock);
 	spin_lock_init(&s->queued_bufs_lock);
 	INIT_LIST_HEAD(&s->queued_bufs);
-	s->udev = udev;
+	s->dev = &intf->dev;
+	s->udev = interface_to_usbdev(intf);
 	s->f_adc = bands[0].rangelow;
 	s->pixelformat = formats[0].pixelformat;
 	s->buffersize = formats[0].buffersize;
 	s->num_formats = NUM_FORMATS;
-	if (msi2500_emulated_fmt == false)
+	if (!msi2500_emulated_fmt)
 		s->num_formats -= 2;
 
 	/* Init videobuf2 queue structure */
@@ -1226,7 +1204,7 @@
 	s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
 	ret = vb2_queue_init(&s->vb_queue);
 	if (ret) {
-		dev_err(&s->udev->dev, "Could not initialize vb2 queue\n");
+		dev_err(s->dev, "Could not initialize vb2 queue\n");
 		goto err_free_mem;
 	}
 
@@ -1240,13 +1218,12 @@
 	s->v4l2_dev.release = msi2500_video_release;
 	ret = v4l2_device_register(&intf->dev, &s->v4l2_dev);
 	if (ret) {
-		dev_err(&s->udev->dev,
-				"Failed to register v4l2-device (%d)\n", ret);
+		dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret);
 		goto err_free_mem;
 	}
 
 	/* SPI master adapter */
-	master = spi_alloc_master(&s->udev->dev, 0);
+	master = spi_alloc_master(s->dev, 0);
 	if (master == NULL) {
 		ret = -ENOMEM;
 		goto err_unregister_v4l2_dev;
@@ -1267,7 +1244,7 @@
 	sd = v4l2_spi_new_subdev(&s->v4l2_dev, master, &board_info);
 	s->v4l2_subdev = sd;
 	if (sd == NULL) {
-		dev_err(&s->udev->dev, "cannot get v4l2 subdevice\n");
+		dev_err(s->dev, "cannot get v4l2 subdevice\n");
 		ret = -ENODEV;
 		goto err_unregister_master;
 	}
@@ -1276,7 +1253,7 @@
 	v4l2_ctrl_handler_init(&s->hdl, 0);
 	if (s->hdl.error) {
 		ret = s->hdl.error;
-		dev_err(&s->udev->dev, "Could not initialize controls\n");
+		dev_err(s->dev, "Could not initialize controls\n");
 		goto err_free_controls;
 	}
 
@@ -1289,16 +1266,13 @@
 
 	ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
 	if (ret) {
-		dev_err(&s->udev->dev,
-				"Failed to register as video device (%d)\n",
+		dev_err(s->dev, "Failed to register as video device (%d)\n",
 				ret);
 		goto err_unregister_v4l2_dev;
 	}
-	dev_info(&s->udev->dev, "Registered as %s\n",
+	dev_info(s->dev, "Registered as %s\n",
 			video_device_node_name(&s->vdev));
-	dev_notice(&s->udev->dev,
-			"%s: SDR API is still slightly experimental and functionality changes may follow\n",
-			KBUILD_MODNAME);
+	dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
 
 	return 0;
 
diff --git a/drivers/media/usb/pwc/pwc-v4l.c b/drivers/media/usb/pwc/pwc-v4l.c
index aa7449e..3d98798 100644
--- a/drivers/media/usb/pwc/pwc-v4l.c
+++ b/drivers/media/usb/pwc/pwc-v4l.c
@@ -52,7 +52,7 @@
 	custom_awb_speed, custom_awb_delay,
 	custom_save_user, custom_restore_user, custom_restore_factory };
 
-const char * const pwc_auto_whitebal_qmenu[] = {
+static const char * const pwc_auto_whitebal_qmenu[] = {
 	"Indoor (Incandescant Lighting) Mode",
 	"Outdoor (Sunlight) Mode",
 	"Indoor (Fluorescent Lighting) Mode",
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index 2c90186..ccc0009 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -2245,7 +2245,7 @@
 	}
 
 	atomic_set(&dev->num_channels, 0);
-	dev->pid = le16_to_cpu(id->idProduct);
+	dev->pid = id->idProduct;
 	dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
 	if (!dev->fw_data)
 		goto errorFWDATA1;
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index 1836a41..94e10b1 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -277,14 +277,14 @@
 		rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
 				  fw_buffer, fw->size, &dummy, 1000);
 
-		sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
+		sms_info("sent %zu(%d) bytes, rc %d", fw->size, dummy, rc);
 
 		kfree(fw_buffer);
 	} else {
 		sms_err("failed to allocate firmware buffer");
 		rc = -ENOMEM;
 	}
-	sms_info("read FW %s, size=%zd", fw_filename, fw->size);
+	sms_info("read FW %s, size=%zu", fw_filename, fw->size);
 
 	release_firmware(fw);
 
@@ -655,6 +655,8 @@
 		.driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD },
 	{ USB_DEVICE(0x3275, 0x0080),
 		.driver_info = SMS1XXX_BOARD_SIANO_RIO },
+	{ USB_DEVICE(0x2013, 0x0257),
+		.driver_info = SMS1XXX_BOARD_PCTV_77E },
 	{ } /* Terminating entry */
 	};
 
diff --git a/drivers/media/usb/ttusb-dec/ttusbdecfe.c b/drivers/media/usb/ttusb-dec/ttusbdecfe.c
index 5c45c9d..9c29552 100644
--- a/drivers/media/usb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/usb/ttusb-dec/ttusbdecfe.c
@@ -156,6 +156,9 @@
 		   0x00, 0x00, 0x00, 0x00,
 		   0x00, 0x00 };
 
+	if (cmd->msg_len > sizeof(b) - 4)
+		return -EINVAL;
+
 	memcpy(&b[4], cmd->msg, cmd->msg_len);
 
 	state->config->send_command(fe, 0x72,
diff --git a/drivers/media/usb/usbtv/Kconfig b/drivers/media/usb/usbtv/Kconfig
index cf55848..ca5b042 100644
--- a/drivers/media/usb/usbtv/Kconfig
+++ b/drivers/media/usb/usbtv/Kconfig
@@ -1,7 +1,8 @@
 config VIDEO_USBTV
         tristate "USBTV007 video capture support"
         depends on m
-        depends on VIDEO_V4L2
+        depends on VIDEO_V4L2 && SND
+        depends on SND_PCM
         select VIDEOBUF2_VMALLOC
 
         ---help---
diff --git a/drivers/media/usb/usbtv/Makefile b/drivers/media/usb/usbtv/Makefile
index c1c829f..925cbbd 100644
--- a/drivers/media/usb/usbtv/Makefile
+++ b/drivers/media/usb/usbtv/Makefile
@@ -1,4 +1,5 @@
 usbtv-y := usbtv-core.o \
-	usbtv-video.o
+	usbtv-video.o \
+	usbtv-audio.o
 
 obj-$(CPTCFG_VIDEO_USBTV) += usbtv.o
diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c
new file mode 100644
index 0000000..78c12d2
--- /dev/null
+++ b/drivers/media/usb/usbtv/usbtv-audio.c
@@ -0,0 +1,385 @@
+/*
+ * Fushicai USBTV007 Audio-Video Grabber Driver
+ *
+ * Product web site:
+ * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
+ *
+ * Copyright (c) 2013 Federico Simoncelli
+ * All rights reserved.
+ * No physical hardware was harmed running Windows during the
+ * reverse-engineering activity
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ */
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+#include <sound/pcm_params.h>
+
+#include "usbtv.h"
+
+static struct snd_pcm_hardware snd_usbtv_digital_hw = {
+	.info = SNDRV_PCM_INFO_BATCH |
+		SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rates = SNDRV_PCM_RATE_48000,
+	.rate_min = 48000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+	.period_bytes_min = 11059,
+	.period_bytes_max = 13516,
+	.periods_min = 2,
+	.periods_max = 98,
+	.buffer_bytes_max = 62720 * 8, /* value in usbaudio.c */
+};
+
+static int snd_usbtv_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct usbtv *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	chip->snd_substream = substream;
+	runtime->hw = snd_usbtv_digital_hw;
+
+	return 0;
+}
+
+static int snd_usbtv_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+	if (atomic_read(&chip->snd_stream)) {
+		atomic_set(&chip->snd_stream, 0);
+		schedule_work(&chip->snd_trigger);
+	}
+
+	return 0;
+}
+
+static int snd_usbtv_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *hw_params)
+{
+	int rv;
+	struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+	rv = snd_pcm_lib_malloc_pages(substream,
+		params_buffer_bytes(hw_params));
+
+	if (rv < 0) {
+		dev_warn(chip->dev, "pcm audio buffer allocation failure %i\n",
+			rv);
+		return rv;
+	}
+
+	return 0;
+}
+
+static int snd_usbtv_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_lib_free_pages(substream);
+	return 0;
+}
+
+static int snd_usbtv_prepare(struct snd_pcm_substream *substream)
+{
+	struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+	chip->snd_buffer_pos = 0;
+	chip->snd_period_pos = 0;
+
+	return 0;
+}
+
+static void usbtv_audio_urb_received(struct urb *urb)
+{
+	struct usbtv *chip = urb->context;
+	struct snd_pcm_substream *substream = chip->snd_substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	size_t i, frame_bytes, chunk_length, buffer_pos, period_pos;
+	int period_elapsed;
+	void *urb_current;
+
+	switch (urb->status) {
+	case 0:
+	case -ETIMEDOUT:
+		break;
+	case -ENOENT:
+	case -EPROTO:
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		return;
+	default:
+		dev_warn(chip->dev, "unknown audio urb status %i\n",
+			urb->status);
+	}
+
+	if (!atomic_read(&chip->snd_stream))
+		return;
+
+	frame_bytes = runtime->frame_bits >> 3;
+	chunk_length = USBTV_CHUNK / frame_bytes;
+
+	buffer_pos = chip->snd_buffer_pos;
+	period_pos = chip->snd_period_pos;
+	period_elapsed = 0;
+
+	for (i = 0; i < urb->actual_length; i += USBTV_CHUNK_SIZE) {
+		urb_current = urb->transfer_buffer + i + USBTV_AUDIO_HDRSIZE;
+
+		if (buffer_pos + chunk_length >= runtime->buffer_size) {
+			size_t cnt = (runtime->buffer_size - buffer_pos) *
+				frame_bytes;
+			memcpy(runtime->dma_area + buffer_pos * frame_bytes,
+				urb_current, cnt);
+			memcpy(runtime->dma_area, urb_current + cnt,
+				chunk_length * frame_bytes - cnt);
+		} else {
+			memcpy(runtime->dma_area + buffer_pos * frame_bytes,
+				urb_current, chunk_length * frame_bytes);
+		}
+
+		buffer_pos += chunk_length;
+		period_pos += chunk_length;
+
+		if (buffer_pos >= runtime->buffer_size)
+			buffer_pos -= runtime->buffer_size;
+
+		if (period_pos >= runtime->period_size) {
+			period_pos -= runtime->period_size;
+			period_elapsed = 1;
+		}
+	}
+
+	snd_pcm_stream_lock(substream);
+
+	chip->snd_buffer_pos = buffer_pos;
+	chip->snd_period_pos = period_pos;
+
+	snd_pcm_stream_unlock(substream);
+
+	if (period_elapsed)
+		snd_pcm_period_elapsed(substream);
+
+	usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int usbtv_audio_start(struct usbtv *chip)
+{
+	unsigned int pipe;
+	static const u16 setup[][2] = {
+		/* These seem to enable the device. */
+		{ USBTV_BASE + 0x0008, 0x0001 },
+		{ USBTV_BASE + 0x01d0, 0x00ff },
+		{ USBTV_BASE + 0x01d9, 0x0002 },
+
+		{ USBTV_BASE + 0x01da, 0x0013 },
+		{ USBTV_BASE + 0x01db, 0x0012 },
+		{ USBTV_BASE + 0x01e9, 0x0002 },
+		{ USBTV_BASE + 0x01ec, 0x006c },
+		{ USBTV_BASE + 0x0294, 0x0020 },
+		{ USBTV_BASE + 0x0255, 0x00cf },
+		{ USBTV_BASE + 0x0256, 0x0020 },
+		{ USBTV_BASE + 0x01eb, 0x0030 },
+		{ USBTV_BASE + 0x027d, 0x00a6 },
+		{ USBTV_BASE + 0x0280, 0x0011 },
+		{ USBTV_BASE + 0x0281, 0x0040 },
+		{ USBTV_BASE + 0x0282, 0x0011 },
+		{ USBTV_BASE + 0x0283, 0x0040 },
+		{ 0xf891, 0x0010 },
+
+		/* this sets the input from composite */
+		{ USBTV_BASE + 0x0284, 0x00aa },
+	};
+
+	chip->snd_bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (chip->snd_bulk_urb == NULL)
+		goto err_alloc_urb;
+
+	pipe = usb_rcvbulkpipe(chip->udev, USBTV_AUDIO_ENDP);
+
+	chip->snd_bulk_urb->transfer_buffer = kzalloc(
+		USBTV_AUDIO_URBSIZE, GFP_KERNEL);
+	if (chip->snd_bulk_urb->transfer_buffer == NULL)
+		goto err_transfer_buffer;
+
+	usb_fill_bulk_urb(chip->snd_bulk_urb, chip->udev, pipe,
+		chip->snd_bulk_urb->transfer_buffer, USBTV_AUDIO_URBSIZE,
+		usbtv_audio_urb_received, chip);
+
+	/* starting the stream */
+	usbtv_set_regs(chip, setup, ARRAY_SIZE(setup));
+
+	usb_clear_halt(chip->udev, pipe);
+	usb_submit_urb(chip->snd_bulk_urb, GFP_ATOMIC);
+
+	return 0;
+
+err_transfer_buffer:
+	usb_free_urb(chip->snd_bulk_urb);
+	chip->snd_bulk_urb = NULL;
+
+err_alloc_urb:
+	return -ENOMEM;
+}
+
+static int usbtv_audio_stop(struct usbtv *chip)
+{
+	static const u16 setup[][2] = {
+	/* The original windows driver sometimes sends also:
+	 *   { USBTV_BASE + 0x00a2, 0x0013 }
+	 * but it seems useless and its real effects are untested at
+	 * the moment.
+	 */
+		{ USBTV_BASE + 0x027d, 0x0000 },
+		{ USBTV_BASE + 0x0280, 0x0010 },
+		{ USBTV_BASE + 0x0282, 0x0010 },
+	};
+
+	if (chip->snd_bulk_urb) {
+		usb_kill_urb(chip->snd_bulk_urb);
+		kfree(chip->snd_bulk_urb->transfer_buffer);
+		usb_free_urb(chip->snd_bulk_urb);
+		chip->snd_bulk_urb = NULL;
+	}
+
+	usbtv_set_regs(chip, setup, ARRAY_SIZE(setup));
+
+	return 0;
+}
+
+void usbtv_audio_suspend(struct usbtv *usbtv)
+{
+	if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb)
+		usb_kill_urb(usbtv->snd_bulk_urb);
+}
+
+void usbtv_audio_resume(struct usbtv *usbtv)
+{
+	if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb)
+		usb_submit_urb(usbtv->snd_bulk_urb, GFP_ATOMIC);
+}
+
+static void snd_usbtv_trigger(struct work_struct *work)
+{
+	struct usbtv *chip = container_of(work, struct usbtv, snd_trigger);
+
+	if (atomic_read(&chip->snd_stream))
+		usbtv_audio_start(chip);
+	else
+		usbtv_audio_stop(chip);
+}
+
+static int snd_usbtv_card_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		atomic_set(&chip->snd_stream, 1);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		atomic_set(&chip->snd_stream, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	schedule_work(&chip->snd_trigger);
+
+	return 0;
+}
+
+static snd_pcm_uframes_t snd_usbtv_pointer(struct snd_pcm_substream *substream)
+{
+	struct usbtv *chip = snd_pcm_substream_chip(substream);
+
+	return chip->snd_buffer_pos;
+}
+
+static struct snd_pcm_ops snd_usbtv_pcm_ops = {
+	.open = snd_usbtv_pcm_open,
+	.close = snd_usbtv_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_usbtv_hw_params,
+	.hw_free = snd_usbtv_hw_free,
+	.prepare = snd_usbtv_prepare,
+	.trigger = snd_usbtv_card_trigger,
+	.pointer = snd_usbtv_pointer,
+};
+
+int usbtv_audio_init(struct usbtv *usbtv)
+{
+	int rv;
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+
+	INIT_WORK(&usbtv->snd_trigger, snd_usbtv_trigger);
+	atomic_set(&usbtv->snd_stream, 0);
+
+	rv = snd_card_new(&usbtv->udev->dev, SNDRV_DEFAULT_IDX1, "usbtv",
+		THIS_MODULE, 0, &card);
+	if (rv < 0)
+		return rv;
+
+	strlcpy(card->driver, usbtv->dev->driver->name, sizeof(card->driver));
+	strlcpy(card->shortname, "usbtv", sizeof(card->shortname));
+	snprintf(card->longname, sizeof(card->longname),
+		"USBTV Audio at bus %d device %d", usbtv->udev->bus->busnum,
+		usbtv->udev->devnum);
+
+	snd_card_set_dev(card, usbtv->dev);
+
+	usbtv->snd = card;
+
+	rv = snd_pcm_new(card, "USBTV Audio", 0, 0, 1, &pcm);
+	if (rv < 0)
+		goto err;
+
+	strlcpy(pcm->name, "USBTV Audio Input", sizeof(pcm->name));
+	pcm->info_flags = 0;
+	pcm->private_data = usbtv;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usbtv_pcm_ops);
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+		snd_dma_continuous_data(GFP_KERNEL), USBTV_AUDIO_BUFFER,
+		USBTV_AUDIO_BUFFER);
+
+	rv = snd_card_register(card);
+	if (rv)
+		goto err;
+
+	return 0;
+
+err:
+	usbtv->snd = NULL;
+	snd_card_free(card);
+
+	return rv;
+}
+
+void usbtv_audio_free(struct usbtv *usbtv)
+{
+	if (usbtv->snd && usbtv->udev) {
+		snd_card_free(usbtv->snd);
+		usbtv->snd = NULL;
+	}
+}
diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c
index 473fab8..29428be 100644
--- a/drivers/media/usb/usbtv/usbtv-core.c
+++ b/drivers/media/usb/usbtv/usbtv-core.c
@@ -1,5 +1,5 @@
 /*
- * Fushicai USBTV007 Video Grabber Driver
+ * Fushicai USBTV007 Audio-Video Grabber Driver
  *
  * Product web site:
  * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
@@ -84,12 +84,19 @@
 	if (ret < 0)
 		goto usbtv_video_fail;
 
+	ret = usbtv_audio_init(usbtv);
+	if (ret < 0)
+		goto usbtv_audio_fail;
+
 	/* for simplicity we exploit the v4l2_device reference counting */
 	v4l2_device_get(&usbtv->v4l2_dev);
 
-	dev_info(dev, "Fushicai USBTV007 Video Grabber\n");
+	dev_info(dev, "Fushicai USBTV007 Audio-Video Grabber\n");
 	return 0;
 
+usbtv_audio_fail:
+	usbtv_video_free(usbtv);
+
 usbtv_video_fail:
 	usb_set_intfdata(intf, NULL);
 	usb_put_dev(usbtv->udev);
@@ -101,11 +108,13 @@
 static void usbtv_disconnect(struct usb_interface *intf)
 {
 	struct usbtv *usbtv = usb_get_intfdata(intf);
+
 	usb_set_intfdata(intf, NULL);
 
 	if (!usbtv)
 		return;
 
+	usbtv_audio_free(usbtv);
 	usbtv_video_free(usbtv);
 
 	usb_put_dev(usbtv->udev);
@@ -122,8 +131,8 @@
 };
 MODULE_DEVICE_TABLE(usb, usbtv_id_table);
 
-MODULE_AUTHOR("Lubomir Rintel");
-MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver");
+MODULE_AUTHOR("Lubomir Rintel, Federico Simoncelli");
+MODULE_DESCRIPTION("Fushicai USBTV007 Audio-Video Grabber Driver");
 MODULE_LICENSE("Dual BSD/GPL");
 
 static struct usb_driver usbtv_usb_driver = {
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c
index 030c585..9d3525f 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -1,5 +1,5 @@
 /*
- * Fushicai USBTV007 Video Grabber Driver
+ * Fushicai USBTV007 Audio-Video Grabber Driver
  *
  * Product web site:
  * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
@@ -79,7 +79,6 @@
 		{ USBTV_BASE + 0x011f, 0x00f2 },
 		{ USBTV_BASE + 0x0127, 0x0060 },
 		{ USBTV_BASE + 0x00ae, 0x0010 },
-		{ USBTV_BASE + 0x0284, 0x00aa },
 		{ USBTV_BASE + 0x0239, 0x0060 },
 	};
 
@@ -88,7 +87,6 @@
 		{ USBTV_BASE + 0x011f, 0x00ff },
 		{ USBTV_BASE + 0x0127, 0x0060 },
 		{ USBTV_BASE + 0x00ae, 0x0030 },
-		{ USBTV_BASE + 0x0284, 0x0088 },
 		{ USBTV_BASE + 0x0239, 0x0060 },
 	};
 
@@ -225,7 +223,6 @@
 		{ USBTV_BASE + 0x0159, 0x0006 },
 		{ USBTV_BASE + 0x015d, 0x0000 },
 
-		{ USBTV_BASE + 0x0284, 0x0088 },
 		{ USBTV_BASE + 0x0003, 0x0004 },
 		{ USBTV_BASE + 0x0100, 0x00d3 },
 		{ USBTV_BASE + 0x0115, 0x0015 },
@@ -256,7 +253,7 @@
  * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels.
  * Therefore, we break down the chunk into two halves before copyting,
  * so that we can interleave a line if needed. */
-static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd)
+static void usbtv_chunk_to_vbuf(u32 *frame, __be32 *src, int chunk_no, int odd)
 {
 	int half;
 
@@ -266,6 +263,7 @@
 		int part_index = (line * 2 + !odd) * 3 + (part_no % 3);
 
 		u32 *dst = &frame[part_index * USBTV_CHUNK/2];
+
 		memcpy(dst, src, USBTV_CHUNK/2 * sizeof(*src));
 		src += USBTV_CHUNK/2;
 	}
@@ -274,7 +272,7 @@
 /* Called for each 256-byte image chunk.
  * First word identifies the chunk, followed by 240 words of image
  * data and padding. */
-static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
+static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk)
 {
 	int frame_id, odd, chunk_no;
 	u32 *frame;
@@ -365,7 +363,7 @@
 
 		for (offset = 0; USBTV_CHUNK_SIZE * offset < size; offset++)
 			usbtv_image_chunk(usbtv,
-				(u32 *)&data[USBTV_CHUNK_SIZE * offset]);
+				(__be32 *)&data[USBTV_CHUNK_SIZE * offset]);
 	}
 
 resubmit:
@@ -410,6 +408,7 @@
 	/* Cancel running transfers. */
 	for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) {
 		struct urb *ip = usbtv->isoc_urbs[i];
+
 		if (ip == NULL)
 			continue;
 		usb_kill_urb(ip);
@@ -434,6 +433,8 @@
 	int i;
 	int ret;
 
+	usbtv_audio_suspend(usbtv);
+
 	ret = usb_set_interface(usbtv->udev, 0, 0);
 	if (ret < 0)
 		return ret;
@@ -446,6 +447,8 @@
 	if (ret < 0)
 		return ret;
 
+	usbtv_audio_resume(usbtv);
+
 	for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) {
 		struct urb *ip;
 
@@ -559,6 +562,7 @@
 static int usbtv_s_input(struct file *file, void *priv, unsigned int i)
 {
 	struct usbtv *usbtv = video_drvdata(file);
+
 	return usbtv_select_input(usbtv, i);
 }
 
diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h
index cb1d388..9681195 100644
--- a/drivers/media/usb/usbtv/usbtv.h
+++ b/drivers/media/usb/usbtv/usbtv.h
@@ -1,5 +1,5 @@
 /*
- * Fushicai USBTV007 Video Grabber Driver
+ * Fushicai USBTV007 Audio-Video Grabber Driver
  *
  * Copyright (c) 2013 Lubomir Rintel
  * All rights reserved.
@@ -28,6 +28,7 @@
 
 /* Hardware. */
 #define USBTV_VIDEO_ENDP	0x81
+#define USBTV_AUDIO_ENDP	0x83
 #define USBTV_BASE		0xc000
 #define USBTV_REQUEST_REG	12
 
@@ -39,6 +40,10 @@
 #define USBTV_CHUNK_SIZE	256
 #define USBTV_CHUNK		240
 
+#define USBTV_AUDIO_URBSIZE	20480
+#define USBTV_AUDIO_HDRSIZE	4
+#define USBTV_AUDIO_BUFFER	65536
+
 /* Chunk header. */
 #define USBTV_MAGIC_OK(chunk)	((be32_to_cpu(chunk[0]) & 0xff000000) \
 							== 0x88000000)
@@ -91,9 +96,23 @@
 	int iso_size;
 	unsigned int sequence;
 	struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
+
+	/* audio */
+	struct snd_card *snd;
+	struct snd_pcm_substream *snd_substream;
+	atomic_t snd_stream;
+	struct work_struct snd_trigger;
+	struct urb *snd_bulk_urb;
+	size_t snd_buffer_pos;
+	size_t snd_period_pos;
 };
 
 int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size);
 
 int usbtv_video_init(struct usbtv *usbtv);
 void usbtv_video_free(struct usbtv *usbtv);
+
+int usbtv_audio_init(struct usbtv *usbtv);
+void usbtv_audio_free(struct usbtv *usbtv);
+void usbtv_audio_suspend(struct usbtv *usbtv);
+void usbtv_audio_resume(struct usbtv *usbtv);
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 0eb8210..3e59b28 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -309,9 +309,8 @@
 		.selector	= UVC_CT_PANTILT_RELATIVE_CONTROL,
 		.index		= 12,
 		.size		= 4,
-		.flags		= UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
-				| UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
-				| UVC_CTRL_FLAG_GET_DEF
+		.flags		= UVC_CTRL_FLAG_SET_CUR
+				| UVC_CTRL_FLAG_GET_RANGE
 				| UVC_CTRL_FLAG_AUTO_UPDATE,
 	},
 	{
@@ -391,6 +390,35 @@
 	data[2] = min((int)abs(value), 0xff);
 }
 
+static __s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
+	__u8 query, const __u8 *data)
+{
+	unsigned int first = mapping->offset / 8;
+	__s8 rel = (__s8)data[first];
+
+	switch (query) {
+	case UVC_GET_CUR:
+		return (rel == 0) ? 0 : (rel > 0 ? data[first+1]
+						 : -data[first+1]);
+	case UVC_GET_MIN:
+		return -data[first+1];
+	case UVC_GET_MAX:
+	case UVC_GET_RES:
+	case UVC_GET_DEF:
+	default:
+		return data[first+1];
+	}
+}
+
+static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
+	__s32 value, __u8 *data)
+{
+	unsigned int first = mapping->offset / 8;
+
+	data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
+	data[first+1] = min_t(int, abs(value), 0xff);
+}
+
 static struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	{
 		.id		= V4L2_CID_BRIGHTNESS,
@@ -677,6 +705,30 @@
 		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
 	},
 	{
+		.id		= V4L2_CID_PAN_SPEED,
+		.name		= "Pan (Speed)",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= UVC_CT_PANTILT_RELATIVE_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+		.get		= uvc_ctrl_get_rel_speed,
+		.set		= uvc_ctrl_set_rel_speed,
+	},
+	{
+		.id		= V4L2_CID_TILT_SPEED,
+		.name		= "Tilt (Speed)",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= UVC_CT_PANTILT_RELATIVE_CONTROL,
+		.size		= 16,
+		.offset		= 16,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+		.get		= uvc_ctrl_get_rel_speed,
+		.set		= uvc_ctrl_set_rel_speed,
+	},
+	{
 		.id		= V4L2_CID_PRIVACY,
 		.name		= "Privacy",
 		.entity		= UVC_GUID_UVC_CAMERA,
@@ -1795,7 +1847,7 @@
  * - Handle restore order (Auto-Exposure Mode should be restored before
  *   Exposure Time).
  */
-int uvc_ctrl_resume_device(struct uvc_device *dev)
+int uvc_ctrl_restore_values(struct uvc_device *dev)
 {
 	struct uvc_control *ctrl;
 	struct uvc_entity *entity;
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index ff57633..b578d68 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2000,7 +2000,7 @@
 		int ret = 0;
 
 		if (reset) {
-			ret = uvc_ctrl_resume_device(dev);
+			ret = uvc_ctrl_restore_values(dev);
 			if (ret < 0)
 				return ret;
 		}
@@ -2175,6 +2175,15 @@
 	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0 },
+	/* Logitech HD Pro Webcam C920 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x082d,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_RESTORE_CTRLS_ON_INIT },
 	/* Chicony CNF7129 (Asus EEE 100HE) */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2229,6 +2238,15 @@
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_DEF },
+	/* Dell XPS M1330 (OmniVision OV7670 webcam) */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x05a9,
+	  .idProduct		= 0x7670,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_DEF },
 	/* Apple Built-In iSight */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 378ae02..60a8e2c 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -318,6 +318,7 @@
 	stream->ctrl = probe;
 	stream->cur_format = format;
 	stream->cur_frame = frame;
+	stream->frame_size = fmt->fmt.pix.sizeimage;
 
 done:
 	mutex_unlock(&stream->mutex);
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 9144a2f..9ace520 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -1143,7 +1143,7 @@
 static void uvc_video_validate_buffer(const struct uvc_streaming *stream,
 				      struct uvc_buffer *buf)
 {
-	if (buf->length != buf->bytesused &&
+	if (stream->frame_size != buf->bytesused &&
 	    !(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED))
 		buf->error = 1;
 }
@@ -1463,7 +1463,7 @@
 
 	switch (dev->speed) {
 	case USB_SPEED_SUPER:
-		return ep->ss_ep_comp.wBytesPerInterval;
+		return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
 	case USB_SPEED_HIGH:
 		psize = usb_endpoint_maxp(&ep->desc);
 		return (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
@@ -1678,6 +1678,12 @@
 		}
 	}
 
+	/* The Logitech C920 temporarily forgets that it should not be adjusting
+	 * Exposure Absolute during init so restore controls to stored values.
+	 */
+	if (stream->dev->quirks & UVC_QUIRK_RESTORE_CTRLS_ON_INIT)
+		uvc_ctrl_restore_values(stream->dev);
+
 	return 0;
 }
 
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index b3deb4e..11b6b61 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -147,6 +147,7 @@
 #define UVC_QUIRK_FIX_BANDWIDTH		0x00000080
 #define UVC_QUIRK_PROBE_DEF		0x00000100
 #define UVC_QUIRK_RESTRICT_FRAME_RATE	0x00000200
+#define UVC_QUIRK_RESTORE_CTRLS_ON_INIT	0x00000400
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED		0x00000001
@@ -456,6 +457,8 @@
 	struct uvc_format *def_format;
 	struct uvc_format *cur_format;
 	struct uvc_frame *cur_frame;
+	size_t frame_size;
+
 	/* Protect access to ctrl, cur_format, cur_frame and hardware video
 	 * probe control.
 	 */
@@ -688,7 +691,7 @@
 		const struct uvc_control_mapping *mapping);
 extern int uvc_ctrl_init_device(struct uvc_device *dev);
 extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
-extern int uvc_ctrl_resume_device(struct uvc_device *dev);
+extern int uvc_ctrl_restore_values(struct uvc_device *dev);
 
 extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
 extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index a3bfec6..52d7b51 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -26,6 +26,16 @@
 
 	  When in doubt, say N.
 
+config VIDEO_PCI_SKELETON
+	tristate "Skeleton PCI V4L2 driver"
+	depends on m
+	depends on PCI && BUILD_DOCSRC
+	depends on VIDEO_V4L2 && VIDEOBUF2_CORE
+	depends on VIDEOBUF2_MEMOPS && VIDEOBUF2_DMA_CONTIG
+	---help---
+	  Enable build of the skeleton PCI driver, used as a reference
+	  when developing new drivers.
+
 # Used by drivers that need tuner.ko
 config VIDEO_TUNER
 	tristate
diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
index 9835f1c..f5d4f6f 100644
--- a/drivers/media/v4l2-core/tuner-core.c
+++ b/drivers/media/v4l2-core/tuner-core.c
@@ -601,7 +601,7 @@
 	t->name = "(tuner unset)";
 	t->type = UNSET;
 	t->audmode = V4L2_TUNER_MODE_STEREO;
-	t->standby = 1;
+	t->standby = true;
 	t->radio_freq = 87.5 * 16000;	/* Initial freq range */
 	t->tv_freq = 400 * 16; /* Sets freq to VHF High - needed for some PLL's to properly start */
 
@@ -1260,7 +1260,9 @@
 
 	tuner_dbg("suspend\n");
 
-	if (!t->standby && analog_ops->standby)
+	if (t->fe.ops.tuner_ops.suspend)
+		t->fe.ops.tuner_ops.suspend(&t->fe);
+	else if (!t->standby && analog_ops->standby)
 		analog_ops->standby(&t->fe);
 
 	return 0;
@@ -1273,7 +1275,9 @@
 
 	tuner_dbg("resume\n");
 
-	if (!t->standby)
+	if (t->fe.ops.tuner_ops.resume)
+		t->fe.ops.tuner_ops.resume(&t->fe);
+	else if (!t->standby)
 		if (set_mode(t, t->mode) == 0)
 			set_freq(t, 0);
 
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index f5d2dfd..46a938b 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -435,16 +435,13 @@
 	/* Bits that must be zero to be aligned */
 	unsigned int mask = ~((1 << align) - 1);
 
+	/* Clamp to aligned min and max */
+	x = clamp(x, (min + ~mask) & mask, max & mask);
+
 	/* Round to nearest aligned value */
 	if (align)
 		x = (x + (1 << (align - 1))) & mask;
 
-	/* Clamp to aligned value of min and max */
-	if (x < min)
-		x = (min + ~mask) & mask;
-	else if (x > max)
-		x = max & mask;
-
 	return x;
 }
 
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index cca6c2f..e502a5f 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -328,7 +328,7 @@
 	__u32			reserved;
 };
 
-static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
 				enum v4l2_memory memory)
 {
 	void __user *up_pln;
@@ -357,7 +357,7 @@
 	return 0;
 }
 
-static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
 				enum v4l2_memory memory)
 {
 	if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
@@ -427,7 +427,7 @@
 		 * by passing a very big num_planes value */
 		uplane = compat_alloc_user_space(num_planes *
 						sizeof(struct v4l2_plane));
-		kp->m.planes = uplane;
+		kp->m.planes = (__force struct v4l2_plane *)uplane;
 
 		while (--num_planes >= 0) {
 			ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
@@ -498,7 +498,7 @@
 		if (num_planes == 0)
 			return 0;
 
-		uplane = kp->m.planes;
+		uplane = (__force struct v4l2_plane __user *)kp->m.planes;
 		if (get_user(p, &up->m.planes))
 			return -EFAULT;
 		uplane32 = compat_ptr(p);
@@ -562,7 +562,7 @@
 		get_user(kp->flags, &up->flags) ||
 		copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
 			return -EFAULT;
-	kp->base = compat_ptr(tmp);
+	kp->base = (__force void *)compat_ptr(tmp);
 	return 0;
 }
 
@@ -667,11 +667,15 @@
 			n * sizeof(struct v4l2_ext_control32)))
 		return -EFAULT;
 	kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
-	kp->controls = kcontrols;
+	kp->controls = (__force struct v4l2_ext_control *)kcontrols;
 	while (--n >= 0) {
+		u32 id;
+
 		if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
 			return -EFAULT;
-		if (ctrl_is_pointer(kcontrols->id)) {
+		if (get_user(id, &kcontrols->id))
+			return -EFAULT;
+		if (ctrl_is_pointer(id)) {
 			void __user *s;
 
 			if (get_user(p, &ucontrols->string))
@@ -689,7 +693,8 @@
 static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
 {
 	struct v4l2_ext_control32 __user *ucontrols;
-	struct v4l2_ext_control __user *kcontrols = kp->controls;
+	struct v4l2_ext_control __user *kcontrols =
+		(__force struct v4l2_ext_control __user *)kp->controls;
 	int n = kp->count;
 	compat_caddr_t p;
 
@@ -711,11 +716,14 @@
 
 	while (--n >= 0) {
 		unsigned size = sizeof(*ucontrols);
+		u32 id;
 
+		if (get_user(id, &kcontrols->id))
+			return -EFAULT;
 		/* Do not modify the pointer when copying a pointer control.
 		   The contents of the pointer was changed, not the pointer
 		   itself. */
-		if (ctrl_is_pointer(kcontrols->id))
+		if (ctrl_is_pointer(id))
 			size -= sizeof(ucontrols->value64);
 		if (copy_in_user(ucontrols, kcontrols, size))
 			return -EFAULT;
@@ -770,7 +778,7 @@
 		get_user(tmp, &up->edid) ||
 		copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
 			return -EFAULT;
-	kp->edid = compat_ptr(tmp);
+	kp->edid = (__force u8 *)compat_ptr(tmp);
 	return 0;
 }
 
@@ -783,7 +791,7 @@
 		put_user(kp->start_block, &up->start_block) ||
 		put_user(kp->blocks, &up->blocks) ||
 		put_user(tmp, &up->edid) ||
-		copy_to_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+		copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
 			return -EFAULT;
 	return 0;
 }
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index f030d6a..8601214 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -796,6 +796,8 @@
 	case V4L2_CID_AUTO_FOCUS_STOP:		return "Auto Focus, Stop";
 	case V4L2_CID_AUTO_FOCUS_STATUS:	return "Auto Focus, Status";
 	case V4L2_CID_AUTO_FOCUS_RANGE:		return "Auto Focus, Range";
+	case V4L2_CID_PAN_SPEED:		return "Pan, Speed";
+	case V4L2_CID_TILT_SPEED:		return "Tilt, Speed";
 
 	/* FM Radio Modulator controls */
 	/* Keep the order of the 'case's the same as in v4l2-controls.h! */
@@ -859,6 +861,10 @@
 	case V4L2_CID_VBLANK:			return "Vertical Blanking";
 	case V4L2_CID_HBLANK:			return "Horizontal Blanking";
 	case V4L2_CID_ANALOGUE_GAIN:		return "Analogue Gain";
+	case V4L2_CID_TEST_PATTERN_RED:		return "Red Pixel Value";
+	case V4L2_CID_TEST_PATTERN_GREENR:	return "Green (Red) Pixel Value";
+	case V4L2_CID_TEST_PATTERN_BLUE:	return "Blue Pixel Value";
+	case V4L2_CID_TEST_PATTERN_GREENB:	return "Green (Blue) Pixel Value";
 
 	/* Image processing controls */
 	/* Keep the order of the 'case's the same as in v4l2-controls.h! */
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index ce1c9f5..b1d8dbb 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -164,7 +164,8 @@
 	    bt->width > cap->max_width ||
 	    bt->pixelclock < cap->min_pixelclock ||
 	    bt->pixelclock > cap->max_pixelclock ||
-	    (cap->standards && !(bt->standards & cap->standards)) ||
+	    (cap->standards && bt->standards &&
+	     !(bt->standards & cap->standards)) ||
 	    (bt->interlaced && !(caps & V4L2_DV_BT_CAP_INTERLACED)) ||
 	    (!bt->interlaced && !(caps & V4L2_DV_BT_CAP_PROGRESSIVE)))
 		return false;
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 24934b9..a47079b 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -562,7 +562,7 @@
 	pr_cont("class=0x%x, count=%d, error_idx=%d",
 			p->ctrl_class, p->count, p->error_idx);
 	for (i = 0; i < p->count; i++) {
-		if (p->controls[i].size)
+		if (!p->controls[i].size)
 			pr_cont(", id/val=0x%x/0x%x",
 				p->controls[i].id, p->controls[i].value);
 		else
@@ -1153,9 +1153,9 @@
 	switch (p->type) {
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
-		struct v4l2_clip *clips = p->fmt.win.clips;
+		struct v4l2_clip __user *clips = p->fmt.win.clips;
 		u32 clipcount = p->fmt.win.clipcount;
-		void *bitmap = p->fmt.win.bitmap;
+		void __user *bitmap = p->fmt.win.bitmap;
 
 		memset(&p->fmt, 0, sizeof(p->fmt));
 		p->fmt.win.clips = clips;
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index f1a7b33..f13b01e 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -501,11 +501,20 @@
 				      struct v4l2_subdev_format *source_fmt,
 				      struct v4l2_subdev_format *sink_fmt)
 {
+	/* The width, height and code must match. */
 	if (source_fmt->format.width != sink_fmt->format.width
 	    || source_fmt->format.height != sink_fmt->format.height
 	    || source_fmt->format.code != sink_fmt->format.code)
 		return -EINVAL;
 
+	/* The field order must match, or the sink field order must be NONE
+	 * to support interlaced hardware connected to bridges that support
+	 * progressive formats only.
+	 */
+	if (source_fmt->format.field != sink_fmt->format.field &&
+	    sink_fmt->format.field != V4L2_FIELD_NONE)
+		return -EINVAL;
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c
index fb5ee5d..b91a266 100644
--- a/drivers/media/v4l2-core/videobuf-core.c
+++ b/drivers/media/v4l2-core/videobuf-core.c
@@ -441,11 +441,6 @@
 	unsigned int size, count;
 	int retval;
 
-	if (req->count < 1) {
-		dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
-		return -EINVAL;
-	}
-
 	if (req->memory != V4L2_MEMORY_MMAP     &&
 	    req->memory != V4L2_MEMORY_USERPTR  &&
 	    req->memory != V4L2_MEMORY_OVERLAY) {
@@ -471,6 +466,12 @@
 		goto done;
 	}
 
+	if (req->count == 0) {
+		dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
+		retval = __videobuf_free(q);
+		goto done;
+	}
+
 	count = req->count;
 	if (count > VIDEO_MAX_FRAME)
 		count = VIDEO_MAX_FRAME;
diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
index 3c8cc02..3ff15f1 100644
--- a/drivers/media/v4l2-core/videobuf-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
@@ -253,9 +253,11 @@
 	return 0;
 out_free_pages:
 	while (i > 0) {
-		void *addr = page_address(dma->vaddr_pages[i]);
-		dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]);
+		void *addr;
+
 		i--;
+		addr = page_address(dma->vaddr_pages[i]);
+		dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]);
 	}
 	kfree(dma->dma_addr);
 	dma->dma_addr = NULL;
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index dfa0193..e9d733e 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -36,7 +36,7 @@
 #define dprintk(level, fmt, arg...)					      \
 	do {								      \
 		if (debug >= level)					      \
-			pr_debug("vb2: %s: " fmt, __func__, ## arg); \
+			pr_info("vb2: %s: " fmt, __func__, ## arg); \
 	} while (0)
 
 #ifdef CPTCFG_VIDEO_ADV_DEBUG
@@ -890,7 +890,9 @@
 		 * We already have buffers allocated, so first check if they
 		 * are not in use and can be freed.
 		 */
+		mutex_lock(&q->mmap_lock);
 		if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
+			mutex_unlock(&q->mmap_lock);
 			dprintk(1, "memory in use, cannot free\n");
 			return -EBUSY;
 		}
@@ -902,6 +904,7 @@
 		 */
 		__vb2_queue_cancel(q);
 		ret = __vb2_queue_free(q, q->num_buffers);
+		mutex_unlock(&q->mmap_lock);
 		if (ret)
 			return ret;
 
@@ -963,6 +966,7 @@
 		 */
 	}
 
+	mutex_lock(&q->mmap_lock);
 	q->num_buffers = allocated_buffers;
 
 	if (ret < 0) {
@@ -971,8 +975,10 @@
 		 * from q->num_buffers.
 		 */
 		__vb2_queue_free(q, allocated_buffers);
+		mutex_unlock(&q->mmap_lock);
 		return ret;
 	}
+	mutex_unlock(&q->mmap_lock);
 
 	/*
 	 * Return the number of successfully allocated buffers
@@ -1071,6 +1077,7 @@
 		 */
 	}
 
+	mutex_lock(&q->mmap_lock);
 	q->num_buffers += allocated_buffers;
 
 	if (ret < 0) {
@@ -1079,8 +1086,10 @@
 		 * from q->num_buffers.
 		 */
 		__vb2_queue_free(q, allocated_buffers);
+		mutex_unlock(&q->mmap_lock);
 		return -ENOMEM;
 	}
+	mutex_unlock(&q->mmap_lock);
 
 	/*
 	 * Return the number of successfully allocated buffers
@@ -1591,7 +1600,6 @@
 static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 {
 	struct vb2_queue *q = vb->vb2_queue;
-	struct rw_semaphore *mmap_sem;
 	int ret;
 
 	ret = __verify_length(vb, b);
@@ -1628,26 +1636,9 @@
 		ret = __qbuf_mmap(vb, b);
 		break;
 	case V4L2_MEMORY_USERPTR:
-		/*
-		 * In case of user pointer buffers vb2 allocators need to get
-		 * direct access to userspace pages. This requires getting
-		 * the mmap semaphore for read access in the current process
-		 * structure. The same semaphore is taken before calling mmap
-		 * operation, while both qbuf/prepare_buf and mmap are called
-		 * by the driver or v4l2 core with the driver's lock held.
-		 * To avoid an AB-BA deadlock (mmap_sem then driver's lock in
-		 * mmap and driver's lock then mmap_sem in qbuf/prepare_buf),
-		 * the videobuf2 core releases the driver's lock, takes
-		 * mmap_sem and then takes the driver's lock again.
-		 */
-		mmap_sem = &current->mm->mmap_sem;
-		call_void_qop(q, wait_prepare, q);
-		down_read(mmap_sem);
-		call_void_qop(q, wait_finish, q);
-
+		down_read(&current->mm->mmap_sem);
 		ret = __qbuf_userptr(vb, b);
-
-		up_read(mmap_sem);
+		up_read(&current->mm->mmap_sem);
 		break;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
 	case V4L2_MEMORY_DMABUF:
@@ -2522,7 +2513,9 @@
 		return -EINVAL;
 	}
 
+	mutex_lock(&q->mmap_lock);
 	ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
+	mutex_unlock(&q->mmap_lock);
 	if (ret)
 		return ret;
 
@@ -2541,6 +2534,7 @@
 	unsigned long off = pgoff << PAGE_SHIFT;
 	struct vb2_buffer *vb;
 	unsigned int buffer, plane;
+	void *vaddr;
 	int ret;
 
 	if (q->memory != V4L2_MEMORY_MMAP) {
@@ -2557,7 +2551,8 @@
 
 	vb = q->bufs[buffer];
 
-	return (unsigned long)vb2_plane_vaddr(vb, plane);
+	vaddr = vb2_plane_vaddr(vb, plane);
+	return vaddr ? (unsigned long)vaddr : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(vb2_get_unmapped_area);
 #endif
@@ -2704,6 +2699,7 @@
 	INIT_LIST_HEAD(&q->queued_list);
 	INIT_LIST_HEAD(&q->done_list);
 	spin_lock_init(&q->done_lock);
+	mutex_init(&q->mmap_lock);
 	init_waitqueue_head(&q->done_wq);
 
 	if (q->buf_struct_size == 0)
@@ -2725,7 +2721,9 @@
 {
 	__vb2_cleanup_fileio(q);
 	__vb2_queue_cancel(q);
+	mutex_lock(&q->mmap_lock);
 	__vb2_queue_free(q, q->num_buffers);
+	mutex_unlock(&q->mmap_lock);
 }
 EXPORT_SYMBOL_GPL(vb2_queue_release);
 
@@ -3003,6 +3001,12 @@
 		buf->queued = 0;
 		buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
 				 : vb2_plane_size(q->bufs[index], 0);
+		/* Compensate for data_offset on read in the multiplanar case. */
+		if (is_multiplanar && read &&
+		    fileio->b.m.planes[0].data_offset < buf->size) {
+			buf->pos = fileio->b.m.planes[0].data_offset;
+			buf->size -= buf->pos;
+		}
 	} else {
 		buf = &fileio->bufs[index];
 	}
@@ -3392,15 +3396,8 @@
 int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct video_device *vdev = video_devdata(file);
-	struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
-	int err;
 
-	if (lock && mutex_lock_interruptible(lock))
-		return -ERESTARTSYS;
-	err = vb2_mmap(vdev->queue, vma);
-	if (lock)
-		mutex_unlock(lock);
-	return err;
+	return vb2_mmap(vdev->queue, vma);
 }
 EXPORT_SYMBOL_GPL(vb2_fop_mmap);
 
@@ -3519,15 +3516,8 @@
 		unsigned long len, unsigned long pgoff, unsigned long flags)
 {
 	struct video_device *vdev = video_devdata(file);
-	struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
-	int ret;
 
-	if (lock && mutex_lock_interruptible(lock))
-		return -ERESTARTSYS;
-	ret = vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
-	if (lock)
-		mutex_unlock(lock);
-	return ret;
+	return vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags);
 }
 EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area);
 #endif
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 3dc0e7b..0607b55 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -22,6 +22,7 @@
 #source "drivers/net/ethernet/3com/Kconfig"
 #source "drivers/net/ethernet/adaptec/Kconfig"
 #source "drivers/net/ethernet/aeroflex/Kconfig"
+#source "drivers/net/ethernet/agere/Kconfig"
 #source "drivers/net/ethernet/allwinner/Kconfig"
 #source "drivers/net/ethernet/alteon/Kconfig"
 #source "drivers/net/ethernet/altera/Kconfig"
@@ -168,6 +169,7 @@
 #source "drivers/net/ethernet/packetengines/Kconfig"
 #source "drivers/net/ethernet/pasemi/Kconfig"
 #source "drivers/net/ethernet/qlogic/Kconfig"
+#source "drivers/net/ethernet/qualcomm/Kconfig"
 #source "drivers/net/ethernet/realtek/Kconfig"
 #source "drivers/net/ethernet/renesas/Kconfig"
 #source "drivers/net/ethernet/rdc/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index c1dd320..ef26a25 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -6,6 +6,7 @@
 #obj-$(CONFIG_NET_VENDOR_8390) += 8390/
 #obj-$(CONFIG_NET_VENDOR_ADAPTEC) += adaptec/
 #obj-$(CONFIG_GRETH) += aeroflex/
+#obj-$(CONFIG_NET_VENDOR_AGERE) += agere/
 #obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/
 #obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/
 #obj-$(CONFIG_ALTERA_TSE) += altera/
@@ -60,6 +61,7 @@
 #obj-$(CONFIG_NET_PACKET_ENGINE) += packetengines/
 #obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
 #obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
+#obj-$(CONFIG_NET_VENDOR_QUALCOMM) += qualcomm/
 #obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
 #obj-$(CONFIG_SH_ETH) += renesas/
 #obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 9ca24d3..276237c 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -137,6 +137,7 @@
 	tristate "Broadcom NetXtremeII 10Gb support"
 	depends on m
 	depends on PCI
+	depends on PTP_1588_CLOCK
 	depends on FW_LOADER
 	depends on ZLIB_INFLATE
 	depends on LIBCRC32C
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 05238de..f098a3f 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -427,7 +427,7 @@
 	}
 	return;
 error:
-	pr_warning("PHY: cannot reset MII transceiver isolate bit\n");
+	pr_warn("PHY: cannot reset MII transceiver isolate bit\n");
 }
 #else
 static inline void b44_wap54g10_workaround(struct b44 *bp)
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 875eb31..3099c28 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -319,4 +319,37 @@
 	  will be called i40evf.  MSI-X interrupt support is required
 	  for this driver to work correctly.
 
+config FM10K
+	depends on n
+	tristate "Intel(R) FM10000 Ethernet Switch Host Interface Support"
+	depends on m
+	default n
+	depends on PCI_MSI
+	depends on PTP_1588_CLOCK
+	---help---
+	  This driver supports Intel(R) FM10000 Ethernet Switch Host
+	  Interface.  For more information on how to identify your adapter,
+	  go to the Adapter & Driver ID Guide at:
+
+	  <http://support.intel.com/support/network/sb/CS-008441.htm>
+
+	  For general information and support, go to the Intel support
+	  website at:
+
+	  <http://support.intel.com>
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called fm10k.  MSI-X interrupt support is required
+
+config FM10K_VXLAN
+	bool "Virtual eXtensible Local Area Network Support"
+	default n
+	depends on FM10K && VXLAN && !(FM10K=y && VXLAN=m)
+	---help---
+	  This allows one to create VXLAN virtual interfaces that provide
+	  Layer 2 Networks over Layer 3 Networks. VXLAN is often used
+	  to tunnel virtual network infrastructure in virtualized environments.
+	  Say Y here if you want to use Virtual eXtensible Local Area Network
+	  (VXLAN) in the driver.
+
 endif # NET_VENDOR_INTEL
diff --git a/drivers/net/ethernet/intel/Makefile b/drivers/net/ethernet/intel/Makefile
index b372646..db53f4a 100644
--- a/drivers/net/ethernet/intel/Makefile
+++ b/drivers/net/ethernet/intel/Makefile
@@ -12,3 +12,4 @@
 #obj-$(CPTCFG_I40E) += i40e/
 #obj-$(CPTCFG_IXGB) += ixgb/
 #obj-$(CPTCFG_I40EVF) += i40evf/
+#obj-$(CPTCFG_FM10K) += fm10k/
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index b9964e5..5a2f5d0 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -2548,11 +2548,13 @@
 /**
  *  igb_set_eee_i350 - Enable/disable EEE support
  *  @hw: pointer to the HW structure
+ *  @adv1G: boolean flag enabling 1G EEE advertisement
+ *  @adv100m: boolean flag enabling 100M EEE advertisement
  *
  *  Enable/disable EEE based on setting in dev_spec structure.
  *
  **/
-s32 igb_set_eee_i350(struct e1000_hw *hw)
+s32 igb_set_eee_i350(struct e1000_hw *hw, bool adv1G, bool adv100M)
 {
 	u32 ipcnfg, eeer;
 
@@ -2566,7 +2568,16 @@
 	if (!(hw->dev_spec._82575.eee_disable)) {
 		u32 eee_su = rd32(E1000_EEE_SU);
 
-		ipcnfg |= (E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN);
+		if (adv100M)
+			ipcnfg |= E1000_IPCNFG_EEE_100M_AN;
+		else
+			ipcnfg &= ~E1000_IPCNFG_EEE_100M_AN;
+
+		if (adv1G)
+			ipcnfg |= E1000_IPCNFG_EEE_1G_AN;
+		else
+			ipcnfg &= ~E1000_IPCNFG_EEE_1G_AN;
+
 		eeer |= (E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN |
 			E1000_EEER_LPI_FC);
 
@@ -2593,11 +2604,13 @@
 /**
  *  igb_set_eee_i354 - Enable/disable EEE support
  *  @hw: pointer to the HW structure
+ *  @adv1G: boolean flag enabling 1G EEE advertisement
+ *  @adv100m: boolean flag enabling 100M EEE advertisement
  *
  *  Enable/disable EEE legacy mode based on setting in dev_spec structure.
  *
  **/
-s32 igb_set_eee_i354(struct e1000_hw *hw)
+s32 igb_set_eee_i354(struct e1000_hw *hw, bool adv1G, bool adv100M)
 {
 	struct e1000_phy_info *phy = &hw->phy;
 	s32 ret_val = 0;
@@ -2636,8 +2649,16 @@
 		if (ret_val)
 			goto out;
 
-		phy_data |= E1000_EEE_ADV_100_SUPPORTED |
-			    E1000_EEE_ADV_1000_SUPPORTED;
+		if (adv100M)
+			phy_data |= E1000_EEE_ADV_100_SUPPORTED;
+		else
+			phy_data &= ~E1000_EEE_ADV_100_SUPPORTED;
+
+		if (adv1G)
+			phy_data |= E1000_EEE_ADV_1000_SUPPORTED;
+		else
+			phy_data &= ~E1000_EEE_ADV_1000_SUPPORTED;
+
 		ret_val = igb_write_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
 						E1000_EEE_ADV_DEV_I354,
 						phy_data);
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h
index b407c55..2154aea 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.h
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.h
@@ -263,8 +263,8 @@
 void igb_vmdq_set_replication_pf(struct e1000_hw *, bool);
 u16 igb_rxpbs_adjust_82580(u32 data);
 s32 igb_read_emi_reg(struct e1000_hw *, u16 addr, u16 *data);
-s32 igb_set_eee_i350(struct e1000_hw *);
-s32 igb_set_eee_i354(struct e1000_hw *);
+s32 igb_set_eee_i350(struct e1000_hw *, bool adv1G, bool adv100M);
+s32 igb_set_eee_i354(struct e1000_hw *, bool adv1G, bool adv100M);
 s32 igb_get_eee_status_i354(struct e1000_hw *hw, bool *status);
 
 #define E1000_I2C_THERMAL_SENSOR_ADDR	0xF8
diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h
index a2f7ce4..e2fc272 100644
--- a/drivers/net/ethernet/intel/igb/e1000_hw.h
+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h
@@ -265,11 +265,6 @@
 	u64 b2ogprc;
 };
 
-struct e1000_phy_stats {
-	u32 idle_errors;
-	u32 receive_errors;
-};
-
 struct e1000_host_mng_dhcp_cookie {
 	u32 signature;
 	u8  status;
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 3c65800..9f13a86 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -403,7 +403,6 @@
 	struct e1000_hw hw;
 	struct e1000_hw_stats stats;
 	struct e1000_phy_info phy_info;
-	struct e1000_phy_stats phy_stats;
 
 	u32 test_icr;
 	struct igb_ring test_tx_ring;
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index e57b4ff..196b2bf 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -2689,6 +2689,7 @@
 	struct igb_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	struct ethtool_eee eee_curr;
+	bool adv1g_eee = true, adv100m_eee = true;
 	s32 ret_val;
 
 	if ((hw->mac.type < e1000_i350) ||
@@ -2715,12 +2716,14 @@
 			return -EINVAL;
 		}
 
-		if (edata->advertised &
-		    ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) {
+		if (!edata->advertised || (edata->advertised &
+		    ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL))) {
 			dev_err(&adapter->pdev->dev,
-				"EEE Advertisement supports only 100Tx and or 100T full duplex\n");
+				"EEE Advertisement supports only 100Tx and/or 100T full duplex\n");
 			return -EINVAL;
 		}
+		adv100m_eee = !!(edata->advertised & ADVERTISE_100_FULL);
+		adv1g_eee = !!(edata->advertised & ADVERTISE_1000_FULL);
 
 	} else if (!edata->eee_enabled) {
 		dev_err(&adapter->pdev->dev,
@@ -2732,10 +2735,6 @@
 	if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) {
 		hw->dev_spec._82575.eee_disable = !edata->eee_enabled;
 		adapter->flags |= IGB_FLAG_EEE;
-		if (hw->mac.type == e1000_i350)
-			igb_set_eee_i350(hw);
-		else
-			igb_set_eee_i354(hw);
 
 		/* reset link */
 		if (netif_running(netdev))
@@ -2744,6 +2743,17 @@
 			igb_reset(adapter);
 	}
 
+	if (hw->mac.type == e1000_i354)
+		ret_val = igb_set_eee_i354(hw, adv1g_eee, adv100m_eee);
+	else
+		ret_val = igb_set_eee_i350(hw, adv1g_eee, adv100m_eee);
+
+	if (ret_val) {
+		dev_err(&adapter->pdev->dev,
+			"Problem setting EEE advertisement options\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) */
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 5c9455c..18d60a2 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -58,7 +58,7 @@
 
 #define MAJ 5
 #define MIN 2
-#define BUILD 13
+#define BUILD 15
 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
 __stringify(BUILD) "-k"
 char igb_driver_name[] = "igb";
@@ -2034,10 +2034,10 @@
 		case e1000_i350:
 		case e1000_i210:
 		case e1000_i211:
-			igb_set_eee_i350(hw);
+			igb_set_eee_i350(hw, true, true);
 			break;
 		case e1000_i354:
-			igb_set_eee_i354(hw);
+			igb_set_eee_i354(hw, true, true);
 			break;
 		default:
 			break;
@@ -2647,7 +2647,7 @@
 		case e1000_i210:
 		case e1000_i211:
 			/* Enable EEE for internal copper PHY devices */
-			err = igb_set_eee_i350(hw);
+			err = igb_set_eee_i350(hw, true, true);
 			if ((!err) &&
 			    (!hw->dev_spec._82575.eee_disable)) {
 				adapter->eee_advert =
@@ -2658,7 +2658,7 @@
 		case e1000_i354:
 			if ((rd32(E1000_CTRL_EXT) &
 			    E1000_CTRL_EXT_LINK_MODE_SGMII)) {
-				err = igb_set_eee_i354(hw);
+				err = igb_set_eee_i354(hw, true, true);
 				if ((!err) &&
 					(!hw->dev_spec._82575.eee_disable)) {
 					adapter->eee_advert =
@@ -4842,6 +4842,41 @@
 	tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
 }
 
+static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
+{
+	struct net_device *netdev = tx_ring->netdev;
+
+	netif_stop_subqueue(netdev, tx_ring->queue_index);
+
+	/* Herbert's original patch had:
+	 *  smp_mb__after_netif_stop_queue();
+	 * but since that doesn't exist yet, just open code it.
+	 */
+	smp_mb();
+
+	/* We need to check again in a case another CPU has just
+	 * made room available.
+	 */
+	if (igb_desc_unused(tx_ring) < size)
+		return -EBUSY;
+
+	/* A reprieve! */
+	netif_wake_subqueue(netdev, tx_ring->queue_index);
+
+	u64_stats_update_begin(&tx_ring->tx_syncp2);
+	tx_ring->tx_stats.restart_queue2++;
+	u64_stats_update_end(&tx_ring->tx_syncp2);
+
+	return 0;
+}
+
+static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
+{
+	if (igb_desc_unused(tx_ring) >= size)
+		return 0;
+	return __igb_maybe_stop_tx(tx_ring, size);
+}
+
 static void igb_tx_map(struct igb_ring *tx_ring,
 		       struct igb_tx_buffer *first,
 		       const u8 hdr_len)
@@ -4944,13 +4979,20 @@
 
 	tx_ring->next_to_use = i;
 
-	writel(i, tx_ring->tail);
+	/* Make sure there is space in the ring for the next send. */
+	igb_maybe_stop_tx(tx_ring, DESC_NEEDED);
 
-	/* we need this if more than one processor can write to our tail
-	 * at a time, it synchronizes IO on IA64/Altix systems
-	 */
-	mmiowb();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0)
+	if (netif_xmit_stopped(txring_txq(tx_ring)) || !skb->xmit_more)
+#endif
+	{
+		writel(i, tx_ring->tail);
 
+		/* we need this if more than one processor can write to our tail
+		 * at a time, it synchronizes IO on IA64/Altix systems
+		 */
+		mmiowb();
+	}
 	return;
 
 dma_error:
@@ -4970,41 +5012,6 @@
 	tx_ring->next_to_use = i;
 }
 
-static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
-{
-	struct net_device *netdev = tx_ring->netdev;
-
-	netif_stop_subqueue(netdev, tx_ring->queue_index);
-
-	/* Herbert's original patch had:
-	 *  smp_mb__after_netif_stop_queue();
-	 * but since that doesn't exist yet, just open code it.
-	 */
-	smp_mb();
-
-	/* We need to check again in a case another CPU has just
-	 * made room available.
-	 */
-	if (igb_desc_unused(tx_ring) < size)
-		return -EBUSY;
-
-	/* A reprieve! */
-	netif_wake_subqueue(netdev, tx_ring->queue_index);
-
-	u64_stats_update_begin(&tx_ring->tx_syncp2);
-	tx_ring->tx_stats.restart_queue2++;
-	u64_stats_update_end(&tx_ring->tx_syncp2);
-
-	return 0;
-}
-
-static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
-{
-	if (igb_desc_unused(tx_ring) >= size)
-		return 0;
-	return __igb_maybe_stop_tx(tx_ring, size);
-}
-
 netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
 				struct igb_ring *tx_ring)
 {
@@ -5075,9 +5082,6 @@
 
 	igb_tx_map(tx_ring, first, hdr_len);
 
-	/* Make sure there is space in the ring for the next send. */
-	igb_maybe_stop_tx(tx_ring, DESC_NEEDED);
-
 	return NETDEV_TX_OK;
 
 out_drop:
@@ -5234,14 +5238,11 @@
 	struct e1000_hw *hw = &adapter->hw;
 	struct pci_dev *pdev = adapter->pdev;
 	u32 reg, mpc;
-	u16 phy_tmp;
 	int i;
 	u64 bytes, packets;
 	unsigned int start;
 	u64 _bytes, _packets;
 
-#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
-
 	/* Prevent stats update while adapter is being reset, or if the pci
 	 * connection is down.
 	 */
@@ -5402,15 +5403,6 @@
 
 	/* Tx Dropped needs to be maintained elsewhere */
 
-	/* Phy Stats */
-	if (hw->phy.media_type == e1000_media_type_copper) {
-		if ((adapter->link_speed == SPEED_1000) &&
-		   (!igb_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) {
-			phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
-			adapter->phy_stats.idle_errors += phy_tmp;
-		}
-	}
-
 	/* Management Stats */
 	adapter->stats.mgptc += rd32(E1000_MGTPTC);
 	adapter->stats.mgprc += rd32(E1000_MGTPRC);
@@ -6414,7 +6406,7 @@
 		total_packets += tx_buffer->gso_segs;
 
 		/* free the skb */
-		dev_kfree_skb_any(tx_buffer->skb);
+		dev_consume_skb_any(tx_buffer->skb);
 
 		/* unmap skb header data */
 		dma_unmap_single(tx_ring->dev,
@@ -6585,11 +6577,10 @@
 	/* flip page offset to other buffer */
 	rx_buffer->page_offset ^= IGB_RX_BUFSZ;
 
-	/* since we are the only owner of the page and we need to
-	 * increment it, just set the value to 2 in order to avoid
-	 * an unnecessary locked operation
+	/* Even if we own the page, we are not allowed to use atomic_set()
+	 * This would break get_page_unless_zero() users.
 	 */
-	atomic_set(&page->_count, 2);
+	atomic_inc(&page->_count);
 #else
 	/* move offset up to the next cache line */
 	rx_buffer->page_offset += truesize;
@@ -6797,113 +6788,6 @@
 }
 
 /**
- *  igb_get_headlen - determine size of header for LRO/GRO
- *  @data: pointer to the start of the headers
- *  @max_len: total length of section to find headers in
- *
- *  This function is meant to determine the length of headers that will
- *  be recognized by hardware for LRO, and GRO offloads.  The main
- *  motivation of doing this is to only perform one pull for IPv4 TCP
- *  packets so that we can do basic things like calculating the gso_size
- *  based on the average data per packet.
- **/
-static unsigned int igb_get_headlen(unsigned char *data,
-				    unsigned int max_len)
-{
-	union {
-		unsigned char *network;
-		/* l2 headers */
-		struct ethhdr *eth;
-		struct vlan_hdr *vlan;
-		/* l3 headers */
-		struct iphdr *ipv4;
-		struct ipv6hdr *ipv6;
-	} hdr;
-	__be16 protocol;
-	u8 nexthdr = 0;	/* default to not TCP */
-	u8 hlen;
-
-	/* this should never happen, but better safe than sorry */
-	if (max_len < ETH_HLEN)
-		return max_len;
-
-	/* initialize network frame pointer */
-	hdr.network = data;
-
-	/* set first protocol and move network header forward */
-	protocol = hdr.eth->h_proto;
-	hdr.network += ETH_HLEN;
-
-	/* handle any vlan tag if present */
-	if (protocol == htons(ETH_P_8021Q)) {
-		if ((hdr.network - data) > (max_len - VLAN_HLEN))
-			return max_len;
-
-		protocol = hdr.vlan->h_vlan_encapsulated_proto;
-		hdr.network += VLAN_HLEN;
-	}
-
-	/* handle L3 protocols */
-	if (protocol == htons(ETH_P_IP)) {
-		if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
-			return max_len;
-
-		/* access ihl as a u8 to avoid unaligned access on ia64 */
-		hlen = (hdr.network[0] & 0x0F) << 2;
-
-		/* verify hlen meets minimum size requirements */
-		if (hlen < sizeof(struct iphdr))
-			return hdr.network - data;
-
-		/* record next protocol if header is present */
-		if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
-			nexthdr = hdr.ipv4->protocol;
-	} else if (protocol == htons(ETH_P_IPV6)) {
-		if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
-			return max_len;
-
-		/* record next protocol */
-		nexthdr = hdr.ipv6->nexthdr;
-		hlen = sizeof(struct ipv6hdr);
-	} else {
-		return hdr.network - data;
-	}
-
-	/* relocate pointer to start of L4 header */
-	hdr.network += hlen;
-
-	/* finally sort out TCP */
-	if (nexthdr == IPPROTO_TCP) {
-		if ((hdr.network - data) > (max_len - sizeof(struct tcphdr)))
-			return max_len;
-
-		/* access doff as a u8 to avoid unaligned access on ia64 */
-		hlen = (hdr.network[12] & 0xF0) >> 2;
-
-		/* verify hlen meets minimum size requirements */
-		if (hlen < sizeof(struct tcphdr))
-			return hdr.network - data;
-
-		hdr.network += hlen;
-	} else if (nexthdr == IPPROTO_UDP) {
-		if ((hdr.network - data) > (max_len - sizeof(struct udphdr)))
-			return max_len;
-
-		hdr.network += sizeof(struct udphdr);
-	}
-
-	/* If everything has gone correctly hdr.network should be the
-	 * data section of the packet and will be the end of the header.
-	 * If not then it probably represents the end of the last recognized
-	 * header.
-	 */
-	if ((hdr.network - data) < max_len)
-		return hdr.network - data;
-	else
-		return max_len;
-}
-
-/**
  *  igb_pull_tail - igb specific version of skb_pull_tail
  *  @rx_ring: rx descriptor ring packet is being transacted on
  *  @rx_desc: pointer to the EOP Rx descriptor
@@ -6947,7 +6831,7 @@
 	/* we need the header to contain the greater of either ETH_HLEN or
 	 * 60 bytes if the skb->len is less than 60 for skb_pad.
 	 */
-	pull_len = igb_get_headlen(va, IGB_RX_HDR_LEN);
+	pull_len = eth_get_headlen(va, IGB_RX_HDR_LEN);
 
 	/* align pull length to size of long to optimize memcpy performance */
 	skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c
index 9e6a124..07e0b88 100644
--- a/drivers/net/ieee802154/mrf24j40.c
+++ b/drivers/net/ieee802154/mrf24j40.c
@@ -323,8 +323,8 @@
 #ifdef DEBUG
 	print_hex_dump(KERN_DEBUG, "mrf24j40 rx: ",
 		DUMP_PREFIX_OFFSET, 16, 1, data, *len, 0);
-	printk(KERN_DEBUG "mrf24j40 rx: lqi: %02hhx rssi: %02hhx\n",
-		lqi_rssi[0], lqi_rssi[1]);
+	pr_debug("mrf24j40 rx: lqi: %02hhx rssi: %02hhx\n",
+		 lqi_rssi[0], lqi_rssi[1]);
 #endif
 
 out:
@@ -385,7 +385,7 @@
 static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level)
 {
 	/* TODO: */
-	printk(KERN_WARNING "mrf24j40: ed not implemented\n");
+	pr_warn("mrf24j40: ed not implemented\n");
 	*level = 0;
 	return 0;
 }
@@ -412,6 +412,7 @@
 	struct mrf24j40 *devrec = dev->priv;
 	u8 val;
 	int ret;
+
 	dev_dbg(printdev(devrec), "stop\n");
 
 	ret = read_short_reg(devrec, REG_INTCON, &val);
@@ -419,8 +420,6 @@
 		return;
 	val |= 0x1|0x8; /* Set TXNIE and RXIE. Disable Interrupts */
 	write_short_reg(devrec, REG_INTCON, val);
-
-	return;
 }
 
 static int mrf24j40_set_channel(struct ieee802154_dev *dev,
@@ -465,6 +464,7 @@
 	if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
 		/* Short Addr */
 		u8 addrh, addrl;
+
 		addrh = le16_to_cpu(filt->short_addr) >> 8 & 0xff;
 		addrl = le16_to_cpu(filt->short_addr) & 0xff;
 
@@ -483,16 +483,17 @@
 			write_short_reg(devrec, REG_EADR0 + i, addr[i]);
 
 #ifdef DEBUG
-		printk(KERN_DEBUG "Set long addr to: ");
+		pr_debug("Set long addr to: ");
 		for (i = 0; i < 8; i++)
-			printk("%02hhx ", addr[7 - i]);
-		printk(KERN_DEBUG "\n");
+			pr_debug("%02hhx ", addr[7 - i]);
+		pr_debug("\n");
 #endif
 	}
 
 	if (changed & IEEE802515_AFILT_PANID_CHANGED) {
 		/* PAN ID */
 		u8 panidl, panidh;
+
 		panidh = le16_to_cpu(filt->pan_id) >> 8 & 0xff;
 		panidl = le16_to_cpu(filt->pan_id) & 0xff;
 		write_short_reg(devrec, REG_PANIDH, panidh);
@@ -701,7 +702,7 @@
 	int ret = -ENOMEM;
 	struct mrf24j40 *devrec;
 
-	printk(KERN_INFO "mrf24j40: probe(). IRQ: %d\n", spi->irq);
+	dev_info(&spi->dev, "probe(). IRQ: %d\n", spi->irq);
 
 	devrec = devm_kzalloc(&spi->dev, sizeof(struct mrf24j40), GFP_KERNEL);
 	if (!devrec)
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 53fbadd..d8bc646 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -69,8 +69,9 @@
 // reawaken network queue this soon after stopping; else watchdog barks
 #define TX_TIMEOUT_JIFFIES	(5*HZ)
 
-// throttle rx/tx briefly after some faults, so khubd might disconnect()
-// us (it polls at HZ/4 usually) before we report too many false errors.
+/* throttle rx/tx briefly after some faults, so hub_wq might disconnect()
+ * us (it polls at HZ/4 usually) before we report too many false errors.
+ */
 #define THROTTLE_JIFFIES	(HZ/8)
 
 // between wakeups
@@ -595,9 +596,9 @@
 			  "rx shutdown, code %d\n", urb_status);
 		goto block;
 
-	/* we get controller i/o faults during khubd disconnect() delays.
+	/* we get controller i/o faults during hub_wq disconnect() delays.
 	 * throttle down resubmits, to avoid log floods; just temporarily,
-	 * so we still recover when the fault isn't a khubd delay.
+	 * so we still recover when the fault isn't a hub_wq delay.
 	 */
 	case -EPROTO:
 	case -ETIME:
@@ -1187,8 +1188,9 @@
 		case -ESHUTDOWN:		// hardware gone
 			break;
 
-		// like rx, tx gets controller i/o faults during khubd delays
-		// and so it uses the same throttling mechanism.
+		/* like rx, tx gets controller i/o faults during hub_wq
+		 * delays and so it uses the same throttling mechanism.
+		 */
 		case -EPROTO:
 		case -ETIME:
 		case -EILSEQ:
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index bbdb770..c937dac 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -27,6 +27,15 @@
 	  Say Y, if you want to debug atheros wireless drivers.
 	  Right now only ath9k makes use of this.
 
+config ATH_TRACEPOINTS
+	depends on !BACKPORT_KERNEL_3_1
+       bool "Atheros wireless tracing"
+       depends on ATH_DEBUG
+       depends on EVENT_TRACING
+       ---help---
+         This option enables tracepoints for atheros wireless drivers.
+	 Currently, ath9k makes use of this facility.
+
 config ATH_REG_DYNAMIC_USER_REG_HINTS
 	bool "Atheros dynamic user regulatory hints"
 	depends on CFG80211_CERTIFICATION_ONUS
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile
index f255246..53ab383 100644
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
@@ -17,4 +17,8 @@
 		dfs_pri_detector.o
 
 ath-$(CPTCFG_ATH_DEBUG) += debug.o
+ath-$(CPTCFG_ATH_TRACEPOINTS) += trace.o
+
 ccflags-y += -D__CHECK_ENDIAN__
+
+CFLAGS_trace.o := -I$(src)
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 2380248..91c1893 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -234,6 +234,7 @@
  *	AR9462.
  * @ATH_DBG_DFS: radar datection
  * @ATH_DBG_WOW: Wake on Wireless
+ * @ATH_DBG_DYNACK: dynack handling
  * @ATH_DBG_ANY: enable all debugging
  *
  * The debug level is used to control the amount and type of debugging output
@@ -261,10 +262,13 @@
 	ATH_DBG_MCI		= 0x00008000,
 	ATH_DBG_DFS		= 0x00010000,
 	ATH_DBG_WOW		= 0x00020000,
+	ATH_DBG_CHAN_CTX	= 0x00040000,
+	ATH_DBG_DYNACK		= 0x00080000,
 	ATH_DBG_ANY		= 0xffffffff
 };
 
 #define ATH_DBG_DEFAULT (ATH_DBG_FATAL)
+#define ATH_DBG_MAX_LEN 512
 
 #ifdef CPTCFG_ATH_DEBUG
 
diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig
index 489bf8b..5d5195d 100644
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -26,13 +26,15 @@
 
 config ATH10K_DEBUGFS
 	bool "Atheros ath10k debugfs support"
-	depends on ATH10K
+	depends on ATH10K && DEBUG_FS
+	depends on RELAY
 	---help---
 	  Enabled debugfs support
 
 	  If unsure, say Y to make it easier to debug problems.
 
 config ATH10K_TRACING
+	depends on !BACKPORT_KERNEL_3_4
 	bool "Atheros ath10k tracing support"
 	depends on ATH10K
 	depends on EVENT_TRACING
diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index 2110a5c..49fab91 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -10,6 +10,8 @@
 		 wmi.o \
 		 bmi.o
 
+ath10k_core-$(CPTCFG_ATH10K_DEBUGFS) += spectral.o
+ath10k_core-$(CPTCFG_NL80211_TESTMODE) += testmode.o
 ath10k_core-$(CPTCFG_ATH10K_TRACING) += trace.o
 
 obj-$(CPTCFG_ATH10K_PCI) += ath10k_pci.o
diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c
index 17d221a..3d29b08 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.c
+++ b/drivers/net/wireless/ath/ath10k/bmi.c
@@ -22,7 +22,7 @@
 
 void ath10k_bmi_start(struct ath10k *ar)
 {
-	ath10k_dbg(ATH10K_DBG_BMI, "bmi start\n");
+	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
 
 	ar->bmi.done_sent = false;
 }
@@ -33,10 +33,10 @@
 	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
 	int ret;
 
-	ath10k_dbg(ATH10K_DBG_BMI, "bmi done\n");
+	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi done\n");
 
 	if (ar->bmi.done_sent) {
-		ath10k_dbg(ATH10K_DBG_BMI, "bmi skipped\n");
+		ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi skipped\n");
 		return 0;
 	}
 
@@ -45,7 +45,7 @@
 
 	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
 	if (ret) {
-		ath10k_warn("unable to write to the device: %d\n", ret);
+		ath10k_warn(ar, "unable to write to the device: %d\n", ret);
 		return ret;
 	}
 
@@ -61,10 +61,10 @@
 	u32 resplen = sizeof(resp.get_target_info);
 	int ret;
 
-	ath10k_dbg(ATH10K_DBG_BMI, "bmi get target info\n");
+	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info\n");
 
 	if (ar->bmi.done_sent) {
-		ath10k_warn("BMI Get Target Info Command disallowed\n");
+		ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
 		return -EBUSY;
 	}
 
@@ -72,12 +72,12 @@
 
 	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
 	if (ret) {
-		ath10k_warn("unable to get target info from device\n");
+		ath10k_warn(ar, "unable to get target info from device\n");
 		return ret;
 	}
 
 	if (resplen < sizeof(resp.get_target_info)) {
-		ath10k_warn("invalid get_target_info response length (%d)\n",
+		ath10k_warn(ar, "invalid get_target_info response length (%d)\n",
 			    resplen);
 		return -EIO;
 	}
@@ -97,11 +97,11 @@
 	u32 rxlen;
 	int ret;
 
-	ath10k_dbg(ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
 		   address, length);
 
 	if (ar->bmi.done_sent) {
-		ath10k_warn("command disallowed\n");
+		ath10k_warn(ar, "command disallowed\n");
 		return -EBUSY;
 	}
 
@@ -115,7 +115,7 @@
 		ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
 						  &resp, &rxlen);
 		if (ret) {
-			ath10k_warn("unable to read from the device (%d)\n",
+			ath10k_warn(ar, "unable to read from the device (%d)\n",
 				    ret);
 			return ret;
 		}
@@ -137,11 +137,11 @@
 	u32 txlen;
 	int ret;
 
-	ath10k_dbg(ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
 		   address, length);
 
 	if (ar->bmi.done_sent) {
-		ath10k_warn("command disallowed\n");
+		ath10k_warn(ar, "command disallowed\n");
 		return -EBUSY;
 	}
 
@@ -159,7 +159,7 @@
 		ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
 						  NULL, NULL);
 		if (ret) {
-			ath10k_warn("unable to write to the device (%d)\n",
+			ath10k_warn(ar, "unable to write to the device (%d)\n",
 				    ret);
 			return ret;
 		}
@@ -183,11 +183,11 @@
 	u32 resplen = sizeof(resp.execute);
 	int ret;
 
-	ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
+	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
 		   address, param);
 
 	if (ar->bmi.done_sent) {
-		ath10k_warn("command disallowed\n");
+		ath10k_warn(ar, "command disallowed\n");
 		return -EBUSY;
 	}
 
@@ -197,19 +197,19 @@
 
 	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
 	if (ret) {
-		ath10k_warn("unable to read from the device\n");
+		ath10k_warn(ar, "unable to read from the device\n");
 		return ret;
 	}
 
 	if (resplen < sizeof(resp.execute)) {
-		ath10k_warn("invalid execute response length (%d)\n",
+		ath10k_warn(ar, "invalid execute response length (%d)\n",
 			    resplen);
 		return -EIO;
 	}
 
 	*result = __le32_to_cpu(resp.execute.result);
 
-	ath10k_dbg(ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
+	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
 
 	return 0;
 }
@@ -221,11 +221,11 @@
 	u32 txlen;
 	int ret;
 
-	ath10k_dbg(ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n",
 		   buffer, length);
 
 	if (ar->bmi.done_sent) {
-		ath10k_warn("command disallowed\n");
+		ath10k_warn(ar, "command disallowed\n");
 		return -EBUSY;
 	}
 
@@ -241,7 +241,7 @@
 		ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
 						  NULL, NULL);
 		if (ret) {
-			ath10k_warn("unable to write to the device\n");
+			ath10k_warn(ar, "unable to write to the device\n");
 			return ret;
 		}
 
@@ -258,11 +258,11 @@
 	u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
 	int ret;
 
-	ath10k_dbg(ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
+	ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
 		   address);
 
 	if (ar->bmi.done_sent) {
-		ath10k_warn("command disallowed\n");
+		ath10k_warn(ar, "command disallowed\n");
 		return -EBUSY;
 	}
 
@@ -271,7 +271,7 @@
 
 	ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
 	if (ret) {
-		ath10k_warn("unable to Start LZ Stream to the device\n");
+		ath10k_warn(ar, "unable to Start LZ Stream to the device\n");
 		return ret;
 	}
 
@@ -286,7 +286,7 @@
 	u32 trailer_len = length - head_len;
 	int ret;
 
-	ath10k_dbg(ATH10K_DBG_BMI,
+	ath10k_dbg(ar, ATH10K_DBG_BMI,
 		   "bmi fast download address 0x%x buffer 0x%p length %d\n",
 		   address, buffer, length);
 
diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h
index 111ab70..31a9906 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.h
+++ b/drivers/net/wireless/ath/ath10k/bmi.h
@@ -177,7 +177,6 @@
 	u32 type;
 };
 
-
 /* in msec */
 #define BMI_COMMUNICATION_TIMEOUT_HZ (1*HZ)
 
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 4333107..101cadb 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -260,7 +260,6 @@
 	ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IS_ADDRESS, mask);
 }
 
-
 /*
  * Guts of ath10k_ce_send, used by both ath10k_ce_send and
  * ath10k_ce_sendlist_send.
@@ -284,13 +283,9 @@
 	int ret = 0;
 
 	if (nbytes > ce_state->src_sz_max)
-		ath10k_warn("%s: send more we can (nbytes: %d, max: %d)\n",
+		ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n",
 			    __func__, nbytes, ce_state->src_sz_max);
 
-	ret = ath10k_pci_wake(ar);
-	if (ret)
-		return ret;
-
 	if (unlikely(CE_RING_DELTA(nentries_mask,
 				   write_index, sw_index - 1) <= 0)) {
 		ret = -ENOSR;
@@ -325,7 +320,6 @@
 
 	src_ring->write_index = write_index;
 exit:
-	ath10k_pci_sleep(ar);
 	return ret;
 }
 
@@ -390,49 +384,56 @@
 	return delta;
 }
 
-int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
-			       void *per_recv_context,
-			       u32 buffer)
+int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe)
 {
-	struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
-	u32 ctrl_addr = ce_state->ctrl_addr;
-	struct ath10k *ar = ce_state->ar;
+	struct ath10k *ar = pipe->ar;
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	struct ath10k_ce_ring *dest_ring = pipe->dest_ring;
 	unsigned int nentries_mask = dest_ring->nentries_mask;
-	unsigned int write_index;
-	unsigned int sw_index;
+	unsigned int write_index = dest_ring->write_index;
+	unsigned int sw_index = dest_ring->sw_index;
+
+	lockdep_assert_held(&ar_pci->ce_lock);
+
+	return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1);
+}
+
+int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
+{
+	struct ath10k *ar = pipe->ar;
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	struct ath10k_ce_ring *dest_ring = pipe->dest_ring;
+	unsigned int nentries_mask = dest_ring->nentries_mask;
+	unsigned int write_index = dest_ring->write_index;
+	unsigned int sw_index = dest_ring->sw_index;
+	struct ce_desc *base = dest_ring->base_addr_owner_space;
+	struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index);
+	u32 ctrl_addr = pipe->ctrl_addr;
+
+	lockdep_assert_held(&ar_pci->ce_lock);
+
+	if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0)
+		return -EIO;
+
+	desc->addr = __cpu_to_le32(paddr);
+	desc->nbytes = 0;
+
+	dest_ring->per_transfer_context[write_index] = ctx;
+	write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
+	ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index);
+	dest_ring->write_index = write_index;
+
+	return 0;
+}
+
+int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
+{
+	struct ath10k *ar = pipe->ar;
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	int ret;
 
 	spin_lock_bh(&ar_pci->ce_lock);
-	write_index = dest_ring->write_index;
-	sw_index = dest_ring->sw_index;
-
-	ret = ath10k_pci_wake(ar);
-	if (ret)
-		goto out;
-
-	if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) {
-		struct ce_desc *base = dest_ring->base_addr_owner_space;
-		struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index);
-
-		/* Update destination descriptor */
-		desc->addr    = __cpu_to_le32(buffer);
-		desc->nbytes = 0;
-
-		dest_ring->per_transfer_context[write_index] =
-							per_recv_context;
-
-		/* Update Destination Ring Write Index */
-		write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
-		ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index);
-		dest_ring->write_index = write_index;
-		ret = 0;
-	} else {
-		ret = -EIO;
-	}
-	ath10k_pci_sleep(ar);
-
-out:
+	ret = __ath10k_ce_rx_post_buf(pipe, ctx, paddr);
 	spin_unlock_bh(&ar_pci->ce_lock);
 
 	return ret;
@@ -588,7 +589,6 @@
 	unsigned int sw_index = src_ring->sw_index;
 	struct ce_desc *sdesc, *sbase;
 	unsigned int read_index;
-	int ret;
 
 	if (src_ring->hw_index == sw_index) {
 		/*
@@ -599,18 +599,12 @@
 		 * value of the HW index has become stale.
 		 */
 
-		ret = ath10k_pci_wake(ar);
-		if (ret)
-			return ret;
-
 		read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
 		if (read_index == 0xffffffff)
 			return -ENODEV;
 
 		read_index &= nentries_mask;
 		src_ring->hw_index = read_index;
-
-		ath10k_pci_sleep(ar);
 	}
 
 	read_index = src_ring->hw_index;
@@ -731,11 +725,6 @@
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
 	u32 ctrl_addr = ce_state->ctrl_addr;
-	int ret;
-
-	ret = ath10k_pci_wake(ar);
-	if (ret)
-		return;
 
 	spin_lock_bh(&ar_pci->ce_lock);
 
@@ -760,7 +749,6 @@
 	ath10k_ce_engine_int_status_clear(ar, ctrl_addr, CE_WATERMARK_MASK);
 
 	spin_unlock_bh(&ar_pci->ce_lock);
-	ath10k_pci_sleep(ar);
 }
 
 /*
@@ -771,13 +759,9 @@
 
 void ath10k_ce_per_engine_service_any(struct ath10k *ar)
 {
-	int ce_id, ret;
+	int ce_id;
 	u32 intr_summary;
 
-	ret = ath10k_pci_wake(ar);
-	if (ret)
-		return;
-
 	intr_summary = CE_INTERRUPT_SUMMARY(ar);
 
 	for (ce_id = 0; intr_summary && (ce_id < CE_COUNT); ce_id++) {
@@ -789,8 +773,6 @@
 
 		ath10k_ce_per_engine_service(ar, ce_id);
 	}
-
-	ath10k_pci_sleep(ar);
 }
 
 /*
@@ -800,16 +782,11 @@
  *
  * Called with ce_lock held.
  */
-static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
-						int disable_copy_compl_intr)
+static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state)
 {
 	u32 ctrl_addr = ce_state->ctrl_addr;
 	struct ath10k *ar = ce_state->ar;
-	int ret;
-
-	ret = ath10k_pci_wake(ar);
-	if (ret)
-		return;
+	bool disable_copy_compl_intr = ce_state->attr_flags & CE_ATTR_DIS_INTR;
 
 	if ((!disable_copy_compl_intr) &&
 	    (ce_state->send_cb || ce_state->recv_cb))
@@ -818,17 +795,11 @@
 		ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
 
 	ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
-
-	ath10k_pci_sleep(ar);
 }
 
 int ath10k_ce_disable_interrupts(struct ath10k *ar)
 {
-	int ce_id, ret;
-
-	ret = ath10k_pci_wake(ar);
-	if (ret)
-		return ret;
+	int ce_id;
 
 	for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
 		u32 ctrl_addr = ath10k_ce_base_address(ce_id);
@@ -838,34 +809,16 @@
 		ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
 	}
 
-	ath10k_pci_sleep(ar);
-
 	return 0;
 }
 
-void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
-				void (*send_cb)(struct ath10k_ce_pipe *),
-				int disable_interrupts)
+void ath10k_ce_enable_interrupts(struct ath10k *ar)
 {
-	struct ath10k *ar = ce_state->ar;
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	int ce_id;
 
-	spin_lock_bh(&ar_pci->ce_lock);
-	ce_state->send_cb = send_cb;
-	ath10k_ce_per_engine_handler_adjust(ce_state, disable_interrupts);
-	spin_unlock_bh(&ar_pci->ce_lock);
-}
-
-void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
-				void (*recv_cb)(struct ath10k_ce_pipe *))
-{
-	struct ath10k *ar = ce_state->ar;
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
-	spin_lock_bh(&ar_pci->ce_lock);
-	ce_state->recv_cb = recv_cb;
-	ath10k_ce_per_engine_handler_adjust(ce_state, 0);
-	spin_unlock_bh(&ar_pci->ce_lock);
+	for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
+		ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]);
 }
 
 static int ath10k_ce_init_src_ring(struct ath10k *ar,
@@ -898,7 +851,7 @@
 	ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0);
 	ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries);
 
-	ath10k_dbg(ATH10K_DBG_BOOT,
+	ath10k_dbg(ar, ATH10K_DBG_BOOT,
 		   "boot init ce src ring id %d entries %d base_addr %p\n",
 		   ce_id, nentries, src_ring->base_addr_owner_space);
 
@@ -932,7 +885,7 @@
 	ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0);
 	ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries);
 
-	ath10k_dbg(ATH10K_DBG_BOOT,
+	ath10k_dbg(ar, ATH10K_DBG_BOOT,
 		   "boot ce dest ring id %d entries %d base_addr %p\n",
 		   ce_id, nentries, dest_ring->base_addr_owner_space);
 
@@ -1067,7 +1020,9 @@
  * initialized by software/firmware.
  */
 int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
-			const struct ce_attr *attr)
+			const struct ce_attr *attr,
+			void (*send_cb)(struct ath10k_ce_pipe *),
+			void (*recv_cb)(struct ath10k_ce_pipe *))
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
@@ -1084,39 +1039,37 @@
 	BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
 		     (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
 
-	ret = ath10k_pci_wake(ar);
-	if (ret)
-		return ret;
-
 	spin_lock_bh(&ar_pci->ce_lock);
 	ce_state->ar = ar;
 	ce_state->id = ce_id;
 	ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
 	ce_state->attr_flags = attr->flags;
 	ce_state->src_sz_max = attr->src_sz_max;
+	if (attr->src_nentries)
+		ce_state->send_cb = send_cb;
+	if (attr->dest_nentries)
+		ce_state->recv_cb = recv_cb;
 	spin_unlock_bh(&ar_pci->ce_lock);
 
 	if (attr->src_nentries) {
 		ret = ath10k_ce_init_src_ring(ar, ce_id, attr);
 		if (ret) {
-			ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n",
+			ath10k_err(ar, "Failed to initialize CE src ring for ID: %d (%d)\n",
 				   ce_id, ret);
-			goto out;
+			return ret;
 		}
 	}
 
 	if (attr->dest_nentries) {
 		ret = ath10k_ce_init_dest_ring(ar, ce_id, attr);
 		if (ret) {
-			ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n",
+			ath10k_err(ar, "Failed to initialize CE dest ring for ID: %d (%d)\n",
 				   ce_id, ret);
-			goto out;
+			return ret;
 		}
 	}
 
-out:
-	ath10k_pci_sleep(ar);
-	return ret;
+	return 0;
 }
 
 static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id)
@@ -1140,16 +1093,8 @@
 
 void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id)
 {
-	int ret;
-
-	ret = ath10k_pci_wake(ar);
-	if (ret)
-		return;
-
 	ath10k_ce_deinit_src_ring(ar, ce_id);
 	ath10k_ce_deinit_dest_ring(ar, ce_id);
-
-	ath10k_pci_sleep(ar);
 }
 
 int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
@@ -1163,7 +1108,7 @@
 		ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr);
 		if (IS_ERR(ce_state->src_ring)) {
 			ret = PTR_ERR(ce_state->src_ring);
-			ath10k_err("failed to allocate copy engine source ring %d: %d\n",
+			ath10k_err(ar, "failed to allocate copy engine source ring %d: %d\n",
 				   ce_id, ret);
 			ce_state->src_ring = NULL;
 			return ret;
@@ -1175,7 +1120,7 @@
 								attr);
 		if (IS_ERR(ce_state->dest_ring)) {
 			ret = PTR_ERR(ce_state->dest_ring);
-			ath10k_err("failed to allocate copy engine destination ring %d: %d\n",
+			ath10k_err(ar, "failed to allocate copy engine destination ring %d: %d\n",
 				   ce_id, ret);
 			ce_state->dest_ring = NULL;
 			return ret;
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 7a5a36f..329b734 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -20,7 +20,6 @@
 
 #include "hif.h"
 
-
 /* Maximum number of Copy Engine's supported */
 #define CE_COUNT_MAX 8
 #define CE_HTT_H2T_MSG_SRC_NENTRIES 4096
@@ -37,7 +36,6 @@
 
 struct ath10k_ce_pipe;
 
-
 #define CE_DESC_FLAGS_GATHER         (1 << 0)
 #define CE_DESC_FLAGS_BYTE_SWAP      (1 << 1)
 #define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC
@@ -162,30 +160,13 @@
 
 void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe);
 
-void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
-				void (*send_cb)(struct ath10k_ce_pipe *),
-				int disable_interrupts);
-
 int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe);
 
 /*==================Recv=======================*/
 
-/*
- * Make a buffer available to receive. The buffer must be at least of a
- * minimal size appropriate for this copy engine (src_sz_max attribute).
- *   ce                    - which copy engine to use
- *   per_transfer_recv_context  - context passed back to caller's recv_cb
- *   buffer                     - address of buffer in CE space
- * Returns 0 on success; otherwise an error status.
- *
- * Implemenation note: Pushes a buffer to Dest ring.
- */
-int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
-			       void *per_transfer_recv_context,
-			       u32 buffer);
-
-void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
-				void (*recv_cb)(struct ath10k_ce_pipe *));
+int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe);
+int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
+int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
 
 /* recv flags */
 /* Data is byte-swapped */
@@ -206,18 +187,20 @@
  * Pops 1 completed send buffer from Source ring.
  */
 int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
-			   void **per_transfer_contextp,
-			   u32 *bufferp,
-			   unsigned int *nbytesp,
-			   unsigned int *transfer_idp);
+				  void **per_transfer_contextp,
+				  u32 *bufferp,
+				  unsigned int *nbytesp,
+				  unsigned int *transfer_idp);
 
 /*==================CE Engine Initialization=======================*/
 
 int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
-			const struct ce_attr *attr);
+			const struct ce_attr *attr,
+			void (*send_cb)(struct ath10k_ce_pipe *),
+			void (*recv_cb)(struct ath10k_ce_pipe *));
 void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
 int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
-			  const struct ce_attr *attr);
+			 const struct ce_attr *attr);
 void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
 
 /*==================CE Engine Shutdown=======================*/
@@ -245,6 +228,7 @@
 void ath10k_ce_per_engine_service_any(struct ath10k *ar);
 void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
 int ath10k_ce_disable_interrupts(struct ath10k *ar);
+void ath10k_ce_enable_interrupts(struct ath10k *ar);
 
 /* ce_attr.flags values */
 /* Use NonSnooping PCIe accesses? */
@@ -397,7 +381,6 @@
 #define DST_WATERMARK_HIGH_RESET		0
 #define DST_WATERMARK_ADDRESS			0x0050
 
-
 static inline u32 ath10k_ce_base_address(unsigned int ce_id)
 {
 	return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id;
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 4b81cf6..cee18c8 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -26,6 +26,7 @@
 #include "bmi.h"
 #include "debug.h"
 #include "htt.h"
+#include "testmode.h"
 
 unsigned int ath10k_debug_mask;
 static bool uart_print;
@@ -53,7 +54,7 @@
 
 static void ath10k_send_suspend_complete(struct ath10k *ar)
 {
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n");
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n");
 
 	complete(&ar->target_suspend);
 }
@@ -67,14 +68,14 @@
 	ret = ath10k_bmi_write32(ar, hi_app_host_interest,
 				 HTC_PROTOCOL_VERSION);
 	if (ret) {
-		ath10k_err("settings HTC version failed\n");
+		ath10k_err(ar, "settings HTC version failed\n");
 		return ret;
 	}
 
 	/* set the firmware mode to STA/IBSS/AP */
 	ret = ath10k_bmi_read32(ar, hi_option_flag, &param_host);
 	if (ret) {
-		ath10k_err("setting firmware mode (1/2) failed\n");
+		ath10k_err(ar, "setting firmware mode (1/2) failed\n");
 		return ret;
 	}
 
@@ -93,14 +94,14 @@
 
 	ret = ath10k_bmi_write32(ar, hi_option_flag, param_host);
 	if (ret) {
-		ath10k_err("setting firmware mode (2/2) failed\n");
+		ath10k_err(ar, "setting firmware mode (2/2) failed\n");
 		return ret;
 	}
 
 	/* We do all byte-swapping on the host */
 	ret = ath10k_bmi_write32(ar, hi_be, 0);
 	if (ret) {
-		ath10k_err("setting host CPU BE mode failed\n");
+		ath10k_err(ar, "setting host CPU BE mode failed\n");
 		return ret;
 	}
 
@@ -108,7 +109,7 @@
 	ret = ath10k_bmi_write32(ar, hi_fw_swap, 0);
 
 	if (ret) {
-		ath10k_err("setting FW data/desc swap flags failed\n");
+		ath10k_err(ar, "setting FW data/desc swap flags failed\n");
 		return ret;
 	}
 
@@ -146,11 +147,12 @@
 
 	ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr);
 	if (ret) {
-		ath10k_err("could not read board ext data addr (%d)\n", ret);
+		ath10k_err(ar, "could not read board ext data addr (%d)\n",
+			   ret);
 		return ret;
 	}
 
-	ath10k_dbg(ATH10K_DBG_BOOT,
+	ath10k_dbg(ar, ATH10K_DBG_BOOT,
 		   "boot push board extended data addr 0x%x\n",
 		   board_ext_data_addr);
 
@@ -158,7 +160,7 @@
 		return 0;
 
 	if (ar->board_len != (board_data_size + board_ext_data_size)) {
-		ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n",
+		ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n",
 			   ar->board_len, board_data_size, board_ext_data_size);
 		return -EINVAL;
 	}
@@ -167,14 +169,15 @@
 				      ar->board_data + board_data_size,
 				      board_ext_data_size);
 	if (ret) {
-		ath10k_err("could not write board ext data (%d)\n", ret);
+		ath10k_err(ar, "could not write board ext data (%d)\n", ret);
 		return ret;
 	}
 
 	ret = ath10k_bmi_write32(ar, hi_board_ext_data_config,
 				 (board_ext_data_size << 16) | 1);
 	if (ret) {
-		ath10k_err("could not write board ext data bit (%d)\n", ret);
+		ath10k_err(ar, "could not write board ext data bit (%d)\n",
+			   ret);
 		return ret;
 	}
 
@@ -189,13 +192,13 @@
 
 	ret = ath10k_push_board_ext_data(ar);
 	if (ret) {
-		ath10k_err("could not push board ext data (%d)\n", ret);
+		ath10k_err(ar, "could not push board ext data (%d)\n", ret);
 		goto exit;
 	}
 
 	ret = ath10k_bmi_read32(ar, hi_board_data, &address);
 	if (ret) {
-		ath10k_err("could not read board data addr (%d)\n", ret);
+		ath10k_err(ar, "could not read board data addr (%d)\n", ret);
 		goto exit;
 	}
 
@@ -203,13 +206,13 @@
 				      min_t(u32, board_data_size,
 					    ar->board_len));
 	if (ret) {
-		ath10k_err("could not write board data (%d)\n", ret);
+		ath10k_err(ar, "could not write board data (%d)\n", ret);
 		goto exit;
 	}
 
 	ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1);
 	if (ret) {
-		ath10k_err("could not write board data bit (%d)\n", ret);
+		ath10k_err(ar, "could not write board data bit (%d)\n", ret);
 		goto exit;
 	}
 
@@ -225,51 +228,72 @@
 	/* OTP is optional */
 
 	if (!ar->otp_data || !ar->otp_len) {
-		ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
+		ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
 			    ar->otp_data, ar->otp_len);
 		return 0;
 	}
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
 		   address, ar->otp_len);
 
 	ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);
 	if (ret) {
-		ath10k_err("could not write otp (%d)\n", ret);
+		ath10k_err(ar, "could not write otp (%d)\n", ret);
 		return ret;
 	}
 
 	ret = ath10k_bmi_execute(ar, address, 0, &result);
 	if (ret) {
-		ath10k_err("could not execute otp (%d)\n", ret);
+		ath10k_err(ar, "could not execute otp (%d)\n", ret);
 		return ret;
 	}
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
 
 	if (result != 0) {
-		ath10k_err("otp calibration failed: %d", result);
+		ath10k_err(ar, "otp calibration failed: %d", result);
 		return -EINVAL;
 	}
 
 	return 0;
 }
 
-static int ath10k_download_fw(struct ath10k *ar)
+static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode)
 {
-	u32 address;
+	u32 address, data_len;
+	const char *mode_name;
+	const void *data;
 	int ret;
 
 	address = ar->hw_params.patch_load_addr;
 
-	ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data,
-				       ar->firmware_len);
-	if (ret) {
-		ath10k_err("could not write fw (%d)\n", ret);
-		goto exit;
+	switch (mode) {
+	case ATH10K_FIRMWARE_MODE_NORMAL:
+		data = ar->firmware_data;
+		data_len = ar->firmware_len;
+		mode_name = "normal";
+		break;
+	case ATH10K_FIRMWARE_MODE_UTF:
+		data = ar->testmode.utf->data;
+		data_len = ar->testmode.utf->size;
+		mode_name = "utf";
+		break;
+	default:
+		ath10k_err(ar, "unknown firmware mode: %d\n", mode);
+		return -EINVAL;
 	}
 
-exit:
+	ath10k_dbg(ar, ATH10K_DBG_BOOT,
+		   "boot uploading firmware image %p len %d mode %s\n",
+		   data, data_len, mode_name);
+
+	ret = ath10k_bmi_fast_download(ar, address, data, data_len);
+	if (ret) {
+		ath10k_err(ar, "failed to download %s firmware: %d\n",
+			   mode_name, ret);
+		return ret;
+	}
+
 	return ret;
 }
 
@@ -302,12 +326,12 @@
 	int ret = 0;
 
 	if (ar->hw_params.fw.fw == NULL) {
-		ath10k_err("firmware file not defined\n");
+		ath10k_err(ar, "firmware file not defined\n");
 		return -EINVAL;
 	}
 
 	if (ar->hw_params.fw.board == NULL) {
-		ath10k_err("board data file not defined");
+		ath10k_err(ar, "board data file not defined");
 		return -EINVAL;
 	}
 
@@ -316,7 +340,7 @@
 					 ar->hw_params.fw.board);
 	if (IS_ERR(ar->board)) {
 		ret = PTR_ERR(ar->board);
-		ath10k_err("could not fetch board data (%d)\n", ret);
+		ath10k_err(ar, "could not fetch board data (%d)\n", ret);
 		goto err;
 	}
 
@@ -328,7 +352,7 @@
 					    ar->hw_params.fw.fw);
 	if (IS_ERR(ar->firmware)) {
 		ret = PTR_ERR(ar->firmware);
-		ath10k_err("could not fetch firmware (%d)\n", ret);
+		ath10k_err(ar, "could not fetch firmware (%d)\n", ret);
 		goto err;
 	}
 
@@ -344,7 +368,7 @@
 				       ar->hw_params.fw.otp);
 	if (IS_ERR(ar->otp)) {
 		ret = PTR_ERR(ar->otp);
-		ath10k_err("could not fetch otp (%d)\n", ret);
+		ath10k_err(ar, "could not fetch otp (%d)\n", ret);
 		goto err;
 	}
 
@@ -369,7 +393,7 @@
 	/* first fetch the firmware file (firmware-*.bin) */
 	ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
 	if (IS_ERR(ar->firmware)) {
-		ath10k_err("could not fetch firmware file '%s/%s': %ld\n",
+		ath10k_err(ar, "could not fetch firmware file '%s/%s': %ld\n",
 			   ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware));
 		return PTR_ERR(ar->firmware);
 	}
@@ -381,14 +405,14 @@
 	magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
 
 	if (len < magic_len) {
-		ath10k_err("firmware file '%s/%s' too small to contain magic: %zu\n",
+		ath10k_err(ar, "firmware file '%s/%s' too small to contain magic: %zu\n",
 			   ar->hw_params.fw.dir, name, len);
 		ret = -EINVAL;
 		goto err;
 	}
 
 	if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
-		ath10k_err("invalid firmware magic\n");
+		ath10k_err(ar, "invalid firmware magic\n");
 		ret = -EINVAL;
 		goto err;
 	}
@@ -410,7 +434,7 @@
 		data += sizeof(*hdr);
 
 		if (len < ie_len) {
-			ath10k_err("invalid length for FW IE %d (%zu < %zu)\n",
+			ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n",
 				   ie_id, len, ie_len);
 			ret = -EINVAL;
 			goto err;
@@ -424,7 +448,7 @@
 			memcpy(ar->hw->wiphy->fw_version, data, ie_len);
 			ar->hw->wiphy->fw_version[ie_len] = '\0';
 
-			ath10k_dbg(ATH10K_DBG_BOOT,
+			ath10k_dbg(ar, ATH10K_DBG_BOOT,
 				   "found fw version %s\n",
 				    ar->hw->wiphy->fw_version);
 			break;
@@ -434,11 +458,11 @@
 
 			timestamp = (__le32 *)data;
 
-			ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n",
+			ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw timestamp %d\n",
 				   le32_to_cpup(timestamp));
 			break;
 		case ATH10K_FW_IE_FEATURES:
-			ath10k_dbg(ATH10K_DBG_BOOT,
+			ath10k_dbg(ar, ATH10K_DBG_BOOT,
 				   "found firmware features ie (%zd B)\n",
 				   ie_len);
 
@@ -450,19 +474,19 @@
 					break;
 
 				if (data[index] & (1 << bit)) {
-					ath10k_dbg(ATH10K_DBG_BOOT,
+					ath10k_dbg(ar, ATH10K_DBG_BOOT,
 						   "Enabling feature bit: %i\n",
 						   i);
 					__set_bit(i, ar->fw_features);
 				}
 			}
 
-			ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
+			ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "",
 					ar->fw_features,
 					sizeof(ar->fw_features));
 			break;
 		case ATH10K_FW_IE_FW_IMAGE:
-			ath10k_dbg(ATH10K_DBG_BOOT,
+			ath10k_dbg(ar, ATH10K_DBG_BOOT,
 				   "found fw image ie (%zd B)\n",
 				   ie_len);
 
@@ -471,7 +495,7 @@
 
 			break;
 		case ATH10K_FW_IE_OTP_IMAGE:
-			ath10k_dbg(ATH10K_DBG_BOOT,
+			ath10k_dbg(ar, ATH10K_DBG_BOOT,
 				   "found otp image ie (%zd B)\n",
 				   ie_len);
 
@@ -480,7 +504,7 @@
 
 			break;
 		default:
-			ath10k_warn("Unknown FW IE: %u\n",
+			ath10k_warn(ar, "Unknown FW IE: %u\n",
 				    le32_to_cpu(hdr->id));
 			break;
 		}
@@ -493,15 +517,22 @@
 	}
 
 	if (!ar->firmware_data || !ar->firmware_len) {
-		ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
+		ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
 			    ar->hw_params.fw.dir, name);
 		ret = -ENOMEDIUM;
 		goto err;
 	}
 
+	if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) &&
+	    !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+		ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well");
+		ret = -EINVAL;
+		goto err;
+	}
+
 	/* now fetch the board file */
 	if (ar->hw_params.fw.board == NULL) {
-		ath10k_err("board data file not defined");
+		ath10k_err(ar, "board data file not defined");
 		ret = -EINVAL;
 		goto err;
 	}
@@ -511,7 +542,7 @@
 					 ar->hw_params.fw.board);
 	if (IS_ERR(ar->board)) {
 		ret = PTR_ERR(ar->board);
-		ath10k_err("could not fetch board data '%s/%s' (%d)\n",
+		ath10k_err(ar, "could not fetch board data '%s/%s' (%d)\n",
 			   ar->hw_params.fw.dir, ar->hw_params.fw.board,
 			   ret);
 		goto err;
@@ -531,45 +562,53 @@
 {
 	int ret;
 
+	ar->fw_api = 3;
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+
+	ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE);
+	if (ret == 0)
+		goto success;
+
 	ar->fw_api = 2;
-	ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
 
 	ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE);
 	if (ret == 0)
 		goto success;
 
 	ar->fw_api = 1;
-	ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
 
 	ret = ath10k_core_fetch_firmware_api_1(ar);
 	if (ret)
 		return ret;
 
 success:
-	ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
 
 	return 0;
 }
 
-static int ath10k_init_download_firmware(struct ath10k *ar)
+static int ath10k_init_download_firmware(struct ath10k *ar,
+					 enum ath10k_firmware_mode mode)
 {
 	int ret;
 
 	ret = ath10k_download_board_data(ar);
 	if (ret) {
-		ath10k_err("failed to download board data: %d\n", ret);
+		ath10k_err(ar, "failed to download board data: %d\n", ret);
 		return ret;
 	}
 
 	ret = ath10k_download_and_run_otp(ar);
 	if (ret) {
-		ath10k_err("failed to run otp: %d\n", ret);
+		ath10k_err(ar, "failed to run otp: %d\n", ret);
 		return ret;
 	}
 
-	ret = ath10k_download_fw(ar);
+	ret = ath10k_download_fw(ar, mode);
 	if (ret) {
-		ath10k_err("failed to download firmware: %d\n", ret);
+		ath10k_err(ar, "failed to download firmware: %d\n", ret);
 		return ret;
 	}
 
@@ -586,7 +625,7 @@
 	 */
 	ret = ath10k_bmi_write32(ar, hi_serial_enable, 0);
 	if (ret) {
-		ath10k_warn("could not disable UART prints (%d)\n", ret);
+		ath10k_warn(ar, "could not disable UART prints (%d)\n", ret);
 		return ret;
 	}
 
@@ -595,24 +634,24 @@
 
 	ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7);
 	if (ret) {
-		ath10k_warn("could not enable UART prints (%d)\n", ret);
+		ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
 		return ret;
 	}
 
 	ret = ath10k_bmi_write32(ar, hi_serial_enable, 1);
 	if (ret) {
-		ath10k_warn("could not enable UART prints (%d)\n", ret);
+		ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
 		return ret;
 	}
 
 	/* Set the UART baud rate to 19200. */
 	ret = ath10k_bmi_write32(ar, hi_desired_baud_rate, 19200);
 	if (ret) {
-		ath10k_warn("could not set the baud rate (%d)\n", ret);
+		ath10k_warn(ar, "could not set the baud rate (%d)\n", ret);
 		return ret;
 	}
 
-	ath10k_info("UART prints enabled\n");
+	ath10k_info(ar, "UART prints enabled\n");
 	return 0;
 }
 
@@ -629,14 +668,14 @@
 	}
 
 	if (i == ARRAY_SIZE(ath10k_hw_params_list)) {
-		ath10k_err("Unsupported hardware version: 0x%x\n",
+		ath10k_err(ar, "Unsupported hardware version: 0x%x\n",
 			   ar->target_version);
 		return -EINVAL;
 	}
 
 	ar->hw_params = *hw_params;
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",
 		   ar->hw_params.name, ar->target_version);
 
 	return 0;
@@ -651,14 +690,14 @@
 	switch (ar->state) {
 	case ATH10K_STATE_ON:
 		ar->state = ATH10K_STATE_RESTARTING;
-		del_timer_sync(&ar->scan.timeout);
-		ath10k_reset_scan((unsigned long)ar);
+		ath10k_hif_stop(ar);
+		ath10k_scan_finish(ar);
 		ieee80211_restart_hw(ar->hw);
 		break;
 	case ATH10K_STATE_OFF:
 		/* this can happen if driver is being unloaded
 		 * or if the crash happens during FW probing */
-		ath10k_warn("cannot restart a device that hasn't been started\n");
+		ath10k_warn(ar, "cannot restart a device that hasn't been started\n");
 		break;
 	case ATH10K_STATE_RESTARTING:
 		/* hw restart might be requested from multiple places */
@@ -667,14 +706,17 @@
 		ar->state = ATH10K_STATE_WEDGED;
 		/* fall through */
 	case ATH10K_STATE_WEDGED:
-		ath10k_warn("device is wedged, will not restart\n");
+		ath10k_warn(ar, "device is wedged, will not restart\n");
+		break;
+	case ATH10K_STATE_UTF:
+		ath10k_warn(ar, "firmware restart in UTF mode not supported\n");
 		break;
 	}
 
 	mutex_unlock(&ar->conf_mutex);
 }
 
-int ath10k_core_start(struct ath10k *ar)
+int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
 {
 	int status;
 
@@ -687,7 +729,7 @@
 		goto err;
 	}
 
-	status = ath10k_init_download_firmware(ar);
+	status = ath10k_init_download_firmware(ar, mode);
 	if (status)
 		goto err;
 
@@ -700,7 +742,7 @@
 
 	status = ath10k_htc_init(ar);
 	if (status) {
-		ath10k_err("could not init HTC (%d)\n", status);
+		ath10k_err(ar, "could not init HTC (%d)\n", status);
 		goto err;
 	}
 
@@ -710,90 +752,98 @@
 
 	status = ath10k_wmi_attach(ar);
 	if (status) {
-		ath10k_err("WMI attach failed: %d\n", status);
+		ath10k_err(ar, "WMI attach failed: %d\n", status);
 		goto err;
 	}
 
 	status = ath10k_htt_init(ar);
 	if (status) {
-		ath10k_err("failed to init htt: %d\n", status);
+		ath10k_err(ar, "failed to init htt: %d\n", status);
 		goto err_wmi_detach;
 	}
 
 	status = ath10k_htt_tx_alloc(&ar->htt);
 	if (status) {
-		ath10k_err("failed to alloc htt tx: %d\n", status);
+		ath10k_err(ar, "failed to alloc htt tx: %d\n", status);
 		goto err_wmi_detach;
 	}
 
 	status = ath10k_htt_rx_alloc(&ar->htt);
 	if (status) {
-		ath10k_err("failed to alloc htt rx: %d\n", status);
+		ath10k_err(ar, "failed to alloc htt rx: %d\n", status);
 		goto err_htt_tx_detach;
 	}
 
 	status = ath10k_hif_start(ar);
 	if (status) {
-		ath10k_err("could not start HIF: %d\n", status);
+		ath10k_err(ar, "could not start HIF: %d\n", status);
 		goto err_htt_rx_detach;
 	}
 
 	status = ath10k_htc_wait_target(&ar->htc);
 	if (status) {
-		ath10k_err("failed to connect to HTC: %d\n", status);
+		ath10k_err(ar, "failed to connect to HTC: %d\n", status);
 		goto err_hif_stop;
 	}
 
-	status = ath10k_htt_connect(&ar->htt);
-	if (status) {
-		ath10k_err("failed to connect htt (%d)\n", status);
-		goto err_hif_stop;
+	if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
+		status = ath10k_htt_connect(&ar->htt);
+		if (status) {
+			ath10k_err(ar, "failed to connect htt (%d)\n", status);
+			goto err_hif_stop;
+		}
 	}
 
 	status = ath10k_wmi_connect(ar);
 	if (status) {
-		ath10k_err("could not connect wmi: %d\n", status);
+		ath10k_err(ar, "could not connect wmi: %d\n", status);
 		goto err_hif_stop;
 	}
 
 	status = ath10k_htc_start(&ar->htc);
 	if (status) {
-		ath10k_err("failed to start htc: %d\n", status);
+		ath10k_err(ar, "failed to start htc: %d\n", status);
 		goto err_hif_stop;
 	}
 
-	status = ath10k_wmi_wait_for_service_ready(ar);
-	if (status <= 0) {
-		ath10k_warn("wmi service ready event not received");
-		status = -ETIMEDOUT;
-		goto err_htc_stop;
+	if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
+		status = ath10k_wmi_wait_for_service_ready(ar);
+		if (status <= 0) {
+			ath10k_warn(ar, "wmi service ready event not received");
+			status = -ETIMEDOUT;
+			goto err_hif_stop;
+		}
 	}
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n",
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n",
 		   ar->hw->wiphy->fw_version);
 
 	status = ath10k_wmi_cmd_init(ar);
 	if (status) {
-		ath10k_err("could not send WMI init command (%d)\n", status);
-		goto err_htc_stop;
+		ath10k_err(ar, "could not send WMI init command (%d)\n",
+			   status);
+		goto err_hif_stop;
 	}
 
 	status = ath10k_wmi_wait_for_unified_ready(ar);
 	if (status <= 0) {
-		ath10k_err("wmi unified ready event not received\n");
+		ath10k_err(ar, "wmi unified ready event not received\n");
 		status = -ETIMEDOUT;
-		goto err_htc_stop;
+		goto err_hif_stop;
 	}
 
-	status = ath10k_htt_setup(&ar->htt);
-	if (status) {
-		ath10k_err("failed to setup htt: %d\n", status);
-		goto err_htc_stop;
+	/* we don't care about HTT in UTF mode */
+	if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
+		status = ath10k_htt_setup(&ar->htt);
+		if (status) {
+			ath10k_err(ar, "failed to setup htt: %d\n", status);
+			goto err_hif_stop;
+		}
 	}
 
 	status = ath10k_debug_start(ar);
 	if (status)
-		goto err_htc_stop;
+		goto err_hif_stop;
 
 	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
 		ar->free_vdev_map = (1 << TARGET_10X_NUM_VDEVS) - 1;
@@ -802,28 +852,8 @@
 
 	INIT_LIST_HEAD(&ar->arvifs);
 
-	if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) {
-		ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
-			    ar->hw_params.name,
-			    ar->target_version,
-			    ar->chip_id,
-			    ar->hw->wiphy->fw_version,
-			    ar->fw_api,
-			    ar->htt.target_version_major,
-			    ar->htt.target_version_minor);
-		ath10k_info("debug %d debugfs %d tracing %d dfs %d\n",
-			    config_enabled(CPTCFG_ATH10K_DEBUG),
-			    config_enabled(CPTCFG_ATH10K_DEBUGFS),
-			    config_enabled(CPTCFG_ATH10K_TRACING),
-			    config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED));
-	}
-
-	__set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags);
-
 	return 0;
 
-err_htc_stop:
-	ath10k_htc_stop(&ar->htc);
 err_hif_stop:
 	ath10k_hif_stop(ar);
 err_htt_rx_detach:
@@ -845,14 +875,14 @@
 
 	ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt);
 	if (ret) {
-		ath10k_warn("could not suspend target (%d)\n", ret);
+		ath10k_warn(ar, "could not suspend target (%d)\n", ret);
 		return ret;
 	}
 
 	ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
 
 	if (ret == 0) {
-		ath10k_warn("suspend timed out - target pause event never came\n");
+		ath10k_warn(ar, "suspend timed out - target pause event never came\n");
 		return -ETIMEDOUT;
 	}
 
@@ -864,11 +894,11 @@
 	lockdep_assert_held(&ar->conf_mutex);
 
 	/* try to suspend target */
-	if (ar->state != ATH10K_STATE_RESTARTING)
+	if (ar->state != ATH10K_STATE_RESTARTING &&
+	    ar->state != ATH10K_STATE_UTF)
 		ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
 
 	ath10k_debug_stop(ar);
-	ath10k_htc_stop(&ar->htc);
 	ath10k_hif_stop(ar);
 	ath10k_htt_tx_free(&ar->htt);
 	ath10k_htt_rx_free(&ar->htt);
@@ -887,14 +917,14 @@
 
 	ret = ath10k_hif_power_up(ar);
 	if (ret) {
-		ath10k_err("could not start pci hif (%d)\n", ret);
+		ath10k_err(ar, "could not start pci hif (%d)\n", ret);
 		return ret;
 	}
 
 	memset(&target_info, 0, sizeof(target_info));
 	ret = ath10k_bmi_get_target_info(ar, &target_info);
 	if (ret) {
-		ath10k_err("could not get target info (%d)\n", ret);
+		ath10k_err(ar, "could not get target info (%d)\n", ret);
 		ath10k_hif_power_down(ar);
 		return ret;
 	}
@@ -904,29 +934,30 @@
 
 	ret = ath10k_init_hw_params(ar);
 	if (ret) {
-		ath10k_err("could not get hw params (%d)\n", ret);
+		ath10k_err(ar, "could not get hw params (%d)\n", ret);
 		ath10k_hif_power_down(ar);
 		return ret;
 	}
 
 	ret = ath10k_core_fetch_firmware_files(ar);
 	if (ret) {
-		ath10k_err("could not fetch firmware files (%d)\n", ret);
+		ath10k_err(ar, "could not fetch firmware files (%d)\n", ret);
 		ath10k_hif_power_down(ar);
 		return ret;
 	}
 
 	mutex_lock(&ar->conf_mutex);
 
-	ret = ath10k_core_start(ar);
+	ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
 	if (ret) {
-		ath10k_err("could not init core (%d)\n", ret);
+		ath10k_err(ar, "could not init core (%d)\n", ret);
 		ath10k_core_free_firmware_files(ar);
 		ath10k_hif_power_down(ar);
 		mutex_unlock(&ar->conf_mutex);
 		return ret;
 	}
 
+	ath10k_print_driver_info(ar);
 	ath10k_core_stop(ar);
 
 	mutex_unlock(&ar->conf_mutex);
@@ -939,7 +970,7 @@
 {
 	u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV);
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
 		   ar->chip_id, hw_revision);
 
 	/* Check that we are not using hw1.0 (some of them have same pci id
@@ -947,7 +978,7 @@
 	 * due to missing hw1.0 workarounds. */
 	switch (hw_revision) {
 	case QCA988X_HW_1_0_CHIP_ID_REV:
-		ath10k_err("ERROR: qca988x hw1.0 is not supported\n");
+		ath10k_err(ar, "ERROR: qca988x hw1.0 is not supported\n");
 		return -EOPNOTSUPP;
 
 	case QCA988X_HW_2_0_CHIP_ID_REV:
@@ -955,7 +986,7 @@
 		return 0;
 
 	default:
-		ath10k_warn("Warning: hardware revision unknown (0x%x), expect problems\n",
+		ath10k_warn(ar, "Warning: hardware revision unknown (0x%x), expect problems\n",
 			    ar->chip_id);
 		return 0;
 	}
@@ -970,25 +1001,33 @@
 
 	status = ath10k_core_probe_fw(ar);
 	if (status) {
-		ath10k_err("could not probe fw (%d)\n", status);
+		ath10k_err(ar, "could not probe fw (%d)\n", status);
 		goto err;
 	}
 
 	status = ath10k_mac_register(ar);
 	if (status) {
-		ath10k_err("could not register to mac80211 (%d)\n", status);
+		ath10k_err(ar, "could not register to mac80211 (%d)\n", status);
 		goto err_release_fw;
 	}
 
-	status = ath10k_debug_create(ar);
+	status = ath10k_debug_register(ar);
 	if (status) {
-		ath10k_err("unable to initialize debugfs\n");
+		ath10k_err(ar, "unable to initialize debugfs\n");
 		goto err_unregister_mac;
 	}
 
+	status = ath10k_spectral_create(ar);
+	if (status) {
+		ath10k_err(ar, "failed to initialize spectral\n");
+		goto err_debug_destroy;
+	}
+
 	set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags);
 	return;
 
+err_debug_destroy:
+	ath10k_debug_destroy(ar);
 err_unregister_mac:
 	ath10k_mac_unregister(ar);
 err_release_fw:
@@ -1008,7 +1047,7 @@
 
 	status = ath10k_core_check_chip_id(ar);
 	if (status) {
-		ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id);
+		ath10k_err(ar, "Unsupported chip id 0x%08x\n", ar->chip_id);
 		return status;
 	}
 
@@ -1025,23 +1064,32 @@
 	if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
 		return;
 
+	/* Stop spectral before unregistering from mac80211 to remove the
+	 * relayfs debugfs file cleanly. Otherwise the parent debugfs tree
+	 * would be already be free'd recursively, leading to a double free.
+	 */
+	ath10k_spectral_destroy(ar);
+
 	/* We must unregister from mac80211 before we stop HTC and HIF.
 	 * Otherwise we will fail to submit commands to FW and mac80211 will be
 	 * unhappy about callback failures. */
 	ath10k_mac_unregister(ar);
 
+	ath10k_testmode_destroy(ar);
+
 	ath10k_core_free_firmware_files(ar);
 
-	ath10k_debug_destroy(ar);
+	ath10k_debug_unregister(ar);
 }
 EXPORT_SYMBOL(ath10k_core_unregister);
 
-struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
+struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
 				  const struct ath10k_hif_ops *hif_ops)
 {
 	struct ath10k *ar;
+	int ret;
 
-	ar = ath10k_mac_create();
+	ar = ath10k_mac_create(priv_size);
 	if (!ar)
 		return NULL;
 
@@ -1051,7 +1099,6 @@
 	ar->p2p = !!ath10k_p2p;
 	ar->dev = dev;
 
-	ar->hif.priv = hif_priv;
 	ar->hif.ops = hif_ops;
 
 	init_completion(&ar->scan.started);
@@ -1062,11 +1109,11 @@
 	init_completion(&ar->install_key_done);
 	init_completion(&ar->vdev_setup_done);
 
-	setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar);
+	INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
 
 	ar->workqueue = create_singlethread_workqueue("ath10k_wq");
 	if (!ar->workqueue)
-		goto err_wq;
+		goto err_free_mac;
 
 	mutex_init(&ar->conf_mutex);
 	spin_lock_init(&ar->data_lock);
@@ -1084,10 +1131,18 @@
 	INIT_WORK(&ar->register_work, ath10k_core_register_work);
 	INIT_WORK(&ar->restart_work, ath10k_core_restart);
 
+	ret = ath10k_debug_create(ar);
+	if (ret)
+		goto err_free_wq;
+
 	return ar;
 
-err_wq:
+err_free_wq:
+	destroy_workqueue(ar->workqueue);
+
+err_free_mac:
 	ath10k_mac_destroy(ar);
+
 	return NULL;
 }
 EXPORT_SYMBOL(ath10k_core_create);
@@ -1097,6 +1152,7 @@
 	flush_workqueue(ar->workqueue);
 	destroy_workqueue(ar->workqueue);
 
+	ath10k_debug_destroy(ar);
 	ath10k_mac_destroy(ar);
 }
 EXPORT_SYMBOL(ath10k_core_destroy);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 8155912..9a4ace1 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -22,6 +22,8 @@
 #include <linux/if_ether.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/uuid.h>
+#include <linux/time.h>
 
 #include "htt.h"
 #include "htc.h"
@@ -31,6 +33,7 @@
 #include "../ath.h"
 #include "../regd.h"
 #include "../dfs_pattern_detector.h"
+#include "spectral.h"
 
 #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -237,6 +240,7 @@
 
 	bool is_started;
 	bool is_up;
+	bool spectral_enabled;
 	u32 aid;
 	u8 bssid[ETH_ALEN];
 
@@ -276,11 +280,20 @@
 	struct ath10k_vif *arvif;
 };
 
+/* used for crash-dump storage, protected by data-lock */
+struct ath10k_fw_crash_data {
+	bool crashed_since_read;
+
+	uuid_le uuid;
+	struct timespec timestamp;
+	__le32 registers[REG_DUMP_COUNT_QCA988X];
+};
+
 struct ath10k_debug {
 	struct dentry *debugfs_phy;
 
 	struct ath10k_target_stats target_stats;
-	u32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE];
+	DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_MAX);
 
 	struct completion event_stats_compl;
 
@@ -293,6 +306,8 @@
 
 	u8 htt_max_amsdu;
 	u8 htt_max_ampdu;
+
+	struct ath10k_fw_crash_data *fw_crash_data;
 };
 
 enum ath10k_state {
@@ -315,6 +330,17 @@
 	 * prevents completion timeouts and makes the driver more responsive to
 	 * userspace commands. This is also prevents recursive recovery. */
 	ATH10K_STATE_WEDGED,
+
+	/* factory tests */
+	ATH10K_STATE_UTF,
+};
+
+enum ath10k_firmware_mode {
+	/* the default mode, standard 802.11 functionality */
+	ATH10K_FIRMWARE_MODE_NORMAL,
+
+	/* factory tests etc */
+	ATH10K_FIRMWARE_MODE_UTF,
 };
 
 enum ath10k_fw_features {
@@ -330,6 +356,11 @@
 	/* Firmware does not support P2P */
 	ATH10K_FW_FEATURE_NO_P2P = 3,
 
+	/* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature bit
+	 * is required to be set as well.
+	 */
+	ATH10K_FW_FEATURE_WMI_10_2 = 4,
+
 	/* keep last */
 	ATH10K_FW_FEATURE_COUNT,
 };
@@ -337,10 +368,32 @@
 enum ath10k_dev_flags {
 	/* Indicates that ath10k device is during CAC phase of DFS */
 	ATH10K_CAC_RUNNING,
-	ATH10K_FLAG_FIRST_BOOT_DONE,
 	ATH10K_FLAG_CORE_REGISTERED,
 };
 
+enum ath10k_scan_state {
+	ATH10K_SCAN_IDLE,
+	ATH10K_SCAN_STARTING,
+	ATH10K_SCAN_RUNNING,
+	ATH10K_SCAN_ABORTING,
+};
+
+static inline const char *ath10k_scan_state_str(enum ath10k_scan_state state)
+{
+	switch (state) {
+	case ATH10K_SCAN_IDLE:
+		return "idle";
+	case ATH10K_SCAN_STARTING:
+		return "starting";
+	case ATH10K_SCAN_RUNNING:
+		return "running";
+	case ATH10K_SCAN_ABORTING:
+		return "aborting";
+	}
+
+	return "unknown";
+}
+
 struct ath10k {
 	struct ath_common ath_common;
 	struct ieee80211_hw *hw;
@@ -368,7 +421,6 @@
 	bool p2p;
 
 	struct {
-		void *priv;
 		const struct ath10k_hif_ops *ops;
 	} hif;
 
@@ -410,10 +462,9 @@
 		struct completion started;
 		struct completion completed;
 		struct completion on_channel;
-		struct timer_list timeout;
+		struct delayed_work timeout;
+		enum ath10k_scan_state state;
 		bool is_roc;
-		bool in_progress;
-		bool aborting;
 		int vdev_id;
 		int roc_freq;
 	} scan;
@@ -432,7 +483,6 @@
 	struct cfg80211_chan_def chandef;
 
 	int free_vdev_map;
-	bool promisc;
 	bool monitor;
 	int monitor_vdev_id;
 	bool monitor_started;
@@ -494,13 +544,34 @@
 #ifdef CPTCFG_ATH10K_DEBUGFS
 	struct ath10k_debug debug;
 #endif
+
+	struct {
+		/* relay(fs) channel for spectral scan */
+		struct rchan *rfs_chan_spec_scan;
+
+		/* spectral_mode and spec_config are protected by conf_mutex */
+		enum ath10k_spectral_mode mode;
+		struct ath10k_spec_scan config;
+	} spectral;
+
+	struct {
+		/* protected by conf_mutex */
+		const struct firmware *utf;
+		DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT);
+
+		/* protected by data_lock */
+		bool utf_monitor;
+	} testmode;
+
+	/* must be last */
+	u8 drv_priv[0] __aligned(sizeof(void *));
 };
 
-struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
+struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
 				  const struct ath10k_hif_ops *hif_ops);
 void ath10k_core_destroy(struct ath10k *ar);
 
-int ath10k_core_start(struct ath10k *ar);
+int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode);
 int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
 void ath10k_core_stop(struct ath10k *ar);
 int ath10k_core_register(struct ath10k *ar, u32 chip_id);
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index ad1a36c..a01096e 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -17,6 +17,9 @@
 
 #include <linux/module.h>
 #include <linux/debugfs.h>
+#include <linux/version.h>
+#include <linux/vermagic.h>
+#include <linux/vmalloc.h>
 
 #include "core.h"
 #include "debug.h"
@@ -24,25 +27,86 @@
 /* ms */
 #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
 
-static int ath10k_printk(const char *level, const char *fmt, ...)
-{
-	struct va_format vaf;
-	va_list args;
-	int rtn;
+#define ATH10K_FW_CRASH_DUMP_VERSION 1
 
-	va_start(args, fmt);
+/**
+ * enum ath10k_fw_crash_dump_type - types of data in the dump file
+ * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
+ */
+enum ath10k_fw_crash_dump_type {
+	ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
 
-	vaf.fmt = fmt;
-	vaf.va = &args;
+	ATH10K_FW_CRASH_DUMP_MAX,
+};
 
-	rtn = printk("%sath10k: %pV", level, &vaf);
+struct ath10k_tlv_dump_data {
+	/* see ath10k_fw_crash_dump_type above */
+	__le32 type;
 
-	va_end(args);
+	/* in bytes */
+	__le32 tlv_len;
 
-	return rtn;
-}
+	/* pad to 32-bit boundaries as needed */
+	u8 tlv_data[];
+} __packed;
 
-int ath10k_info(const char *fmt, ...)
+struct ath10k_dump_file_data {
+	/* dump file information */
+
+	/* "ATH10K-FW-DUMP" */
+	char df_magic[16];
+
+	__le32 len;
+
+	/* file dump version */
+	__le32 version;
+
+	/* some info we can get from ath10k struct that might help */
+
+	u8 uuid[16];
+
+	__le32 chip_id;
+
+	/* 0 for now, in place for later hardware */
+	__le32 bus_type;
+
+	__le32 target_version;
+	__le32 fw_version_major;
+	__le32 fw_version_minor;
+	__le32 fw_version_release;
+	__le32 fw_version_build;
+	__le32 phy_capability;
+	__le32 hw_min_tx_power;
+	__le32 hw_max_tx_power;
+	__le32 ht_cap_info;
+	__le32 vht_cap_info;
+	__le32 num_rf_chains;
+
+	/* firmware version string */
+	char fw_ver[ETHTOOL_FWVERS_LEN];
+
+	/* Kernel related information */
+
+	/* time-of-day stamp */
+	__le64 tv_sec;
+
+	/* time-of-day stamp, nano-seconds */
+	__le64 tv_nsec;
+
+	/* LINUX_VERSION_CODE */
+	__le32 kernel_ver_code;
+
+	/* VERMAGIC_STRING */
+	char kernel_ver[64];
+
+	/* room for growth w/out changing binary format */
+	u8 unused[128];
+
+	/* struct ath10k_tlv_dump_data + more */
+	u8 data[0];
+} __packed;
+
+int ath10k_info(struct ath10k *ar, const char *fmt, ...)
 {
 	struct va_format vaf = {
 		.fmt = fmt,
@@ -52,15 +116,34 @@
 
 	va_start(args, fmt);
 	vaf.va = &args;
-	ret = ath10k_printk(KERN_INFO, "%pV", &vaf);
-	trace_ath10k_log_info(&vaf);
+	ret = dev_info(ar->dev, "%pV", &vaf);
+	trace_ath10k_log_info(ar, &vaf);
 	va_end(args);
 
 	return ret;
 }
 EXPORT_SYMBOL(ath10k_info);
 
-int ath10k_err(const char *fmt, ...)
+void ath10k_print_driver_info(struct ath10k *ar)
+{
+	ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
+		    ar->hw_params.name,
+		    ar->target_version,
+		    ar->chip_id,
+		    ar->hw->wiphy->fw_version,
+		    ar->fw_api,
+		    ar->htt.target_version_major,
+		    ar->htt.target_version_minor);
+	ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
+		    config_enabled(CPTCFG_ATH10K_DEBUG),
+		    config_enabled(CPTCFG_ATH10K_DEBUGFS),
+		    config_enabled(CPTCFG_ATH10K_TRACING),
+		    config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED),
+		    config_enabled(CPTCFG_NL80211_TESTMODE));
+}
+EXPORT_SYMBOL(ath10k_print_driver_info);
+
+int ath10k_err(struct ath10k *ar, const char *fmt, ...)
 {
 	struct va_format vaf = {
 		.fmt = fmt,
@@ -70,33 +153,29 @@
 
 	va_start(args, fmt);
 	vaf.va = &args;
-	ret = ath10k_printk(KERN_ERR, "%pV", &vaf);
-	trace_ath10k_log_err(&vaf);
+	ret = dev_err(ar->dev, "%pV", &vaf);
+	trace_ath10k_log_err(ar, &vaf);
 	va_end(args);
 
 	return ret;
 }
 EXPORT_SYMBOL(ath10k_err);
 
-int ath10k_warn(const char *fmt, ...)
+int ath10k_warn(struct ath10k *ar, const char *fmt, ...)
 {
 	struct va_format vaf = {
 		.fmt = fmt,
 	};
 	va_list args;
-	int ret = 0;
 
 	va_start(args, fmt);
 	vaf.va = &args;
-
-	if (net_ratelimit())
-		ret = ath10k_printk(KERN_WARNING, "%pV", &vaf);
-
-	trace_ath10k_log_warn(&vaf);
+	dev_warn_ratelimited(ar->dev, "%pV", &vaf);
+	trace_ath10k_log_warn(ar, &vaf);
 
 	va_end(args);
 
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(ath10k_warn);
 
@@ -115,9 +194,10 @@
 {
 	struct ath10k *ar = file->private_data;
 	char *buf;
-	unsigned int len = 0, buf_len = 1500;
-	const char *status;
+	unsigned int len = 0, buf_len = 4096;
+	const char *name;
 	ssize_t ret_cnt;
+	bool enabled;
 	int i;
 
 	buf = kzalloc(buf_len, GFP_KERNEL);
@@ -129,15 +209,22 @@
 	if (len > buf_len)
 		len = buf_len;
 
-	for (i = 0; i < WMI_SERVICE_LAST; i++) {
-		if (WMI_SERVICE_IS_ENABLED(ar->debug.wmi_service_bitmap, i))
-			status = "enabled";
-		else
-			status = "disabled";
+	for (i = 0; i < WMI_SERVICE_MAX; i++) {
+		enabled = test_bit(i, ar->debug.wmi_service_bitmap);
+		name = wmi_service_name(i);
+
+		if (!name) {
+			if (enabled)
+				len += scnprintf(buf + len, buf_len - len,
+						 "%-40s %s (bit %d)\n",
+						 "unknown", "enabled", i);
+
+			continue;
+		}
 
 		len += scnprintf(buf + len, buf_len - len,
-				 "0x%02x - %20s - %s\n",
-				 i, wmi_service_name(i), status);
+				 "%-40s %s\n",
+				 name, enabled ? "enabled" : "-");
 	}
 
 	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
@@ -309,7 +396,7 @@
 
 	ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
 	if (ret) {
-		ath10k_warn("could not request stats (%d)\n", ret);
+		ath10k_warn(ar, "could not request stats (%d)\n", ret);
 		goto exit;
 	}
 
@@ -478,16 +565,35 @@
 	.llseek = default_llseek,
 };
 
+/* This is a clean assert crash in firmware. */
+static int ath10k_debug_fw_assert(struct ath10k *ar)
+{
+	struct wmi_vdev_install_key_cmd *cmd;
+	struct sk_buff *skb;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + 16);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_vdev_install_key_cmd *)skb->data;
+	memset(cmd, 0, sizeof(*cmd));
+
+	/* big enough number so that firmware asserts */
+	cmd->vdev_id = __cpu_to_le32(0x7ffe);
+
+	return ath10k_wmi_cmd_send(ar, skb,
+				   ar->wmi.cmd->vdev_install_key_cmdid);
+}
+
 static ssize_t ath10k_read_simulate_fw_crash(struct file *file,
 					     char __user *user_buf,
 					     size_t count, loff_t *ppos)
 {
-	const char buf[] = "To simulate firmware crash write one of the"
-			   " keywords to this file:\n `soft` - this will send"
-			   " WMI_FORCE_FW_HANG_ASSERT to firmware if FW"
-			   " supports that command.\n `hard` - this will send"
-			   " to firmware command with illegal parameters"
-			   " causing firmware crash.\n";
+	const char buf[] =
+		"To simulate firmware crash write one of the keywords to this file:\n"
+		"`soft` - this will send WMI_FORCE_FW_HANG_ASSERT to firmware if FW supports that command.\n"
+		"`hard` - this will send to firmware command with illegal parameters causing firmware crash.\n"
+		"`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n";
 
 	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
 }
@@ -527,19 +633,26 @@
 	}
 
 	if (!strcmp(buf, "soft")) {
-		ath10k_info("simulating soft firmware crash\n");
+		ath10k_info(ar, "simulating soft firmware crash\n");
 		ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
 	} else if (!strcmp(buf, "hard")) {
-		ath10k_info("simulating hard firmware crash\n");
-		ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1,
-					ar->wmi.vdev_param->rts_threshold, 0);
+		ath10k_info(ar, "simulating hard firmware crash\n");
+		/* 0x7fff is vdev id, and it is always out of range for all
+		 * firmware variants in order to force a firmware crash.
+		 */
+		ret = ath10k_wmi_vdev_set_param(ar, 0x7fff,
+						ar->wmi.vdev_param->rts_threshold,
+						0);
+	} else if (!strcmp(buf, "assert")) {
+		ath10k_info(ar, "simulating firmware assert crash\n");
+		ret = ath10k_debug_fw_assert(ar);
 	} else {
 		ret = -EINVAL;
 		goto exit;
 	}
 
 	if (ret) {
-		ath10k_warn("failed to simulate firmware crash: %d\n", ret);
+		ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret);
 		goto exit;
 	}
 
@@ -577,6 +690,138 @@
 	.llseek = default_llseek,
 };
 
+struct ath10k_fw_crash_data *
+ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
+{
+	struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
+
+	lockdep_assert_held(&ar->data_lock);
+
+	crash_data->crashed_since_read = true;
+	uuid_le_gen(&crash_data->uuid);
+	getnstimeofday(&crash_data->timestamp);
+
+	return crash_data;
+}
+EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data);
+
+static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+{
+	struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
+	struct ath10k_dump_file_data *dump_data;
+	struct ath10k_tlv_dump_data *dump_tlv;
+	int hdr_len = sizeof(*dump_data);
+	unsigned int len, sofar = 0;
+	unsigned char *buf;
+
+	len = hdr_len;
+	len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+
+	sofar += hdr_len;
+
+	/* This is going to get big when we start dumping FW RAM and such,
+	 * so go ahead and use vmalloc.
+	 */
+	buf = vzalloc(len);
+	if (!buf)
+		return NULL;
+
+	spin_lock_bh(&ar->data_lock);
+
+	if (!crash_data->crashed_since_read) {
+		spin_unlock_bh(&ar->data_lock);
+		vfree(buf);
+		return NULL;
+	}
+
+	dump_data = (struct ath10k_dump_file_data *)(buf);
+	strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP",
+		sizeof(dump_data->df_magic));
+	dump_data->len = cpu_to_le32(len);
+
+	dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION);
+
+	memcpy(dump_data->uuid, &crash_data->uuid, sizeof(dump_data->uuid));
+	dump_data->chip_id = cpu_to_le32(ar->chip_id);
+	dump_data->bus_type = cpu_to_le32(0);
+	dump_data->target_version = cpu_to_le32(ar->target_version);
+	dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major);
+	dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor);
+	dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release);
+	dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build);
+	dump_data->phy_capability = cpu_to_le32(ar->phy_capability);
+	dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power);
+	dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power);
+	dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info);
+	dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info);
+	dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
+
+	strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
+		sizeof(dump_data->fw_ver));
+
+	dump_data->kernel_ver_code = cpu_to_le32(LINUX_VERSION_CODE);
+	strlcpy(dump_data->kernel_ver, VERMAGIC_STRING,
+		sizeof(dump_data->kernel_ver));
+
+	dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec);
+	dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec);
+
+	/* Gather crash-dump */
+	dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+	dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS);
+	dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers));
+	memcpy(dump_tlv->tlv_data, &crash_data->registers,
+	       sizeof(crash_data->registers));
+	sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+
+	ar->debug.fw_crash_data->crashed_since_read = false;
+
+	spin_unlock_bh(&ar->data_lock);
+
+	return dump_data;
+}
+
+static int ath10k_fw_crash_dump_open(struct inode *inode, struct file *file)
+{
+	struct ath10k *ar = inode->i_private;
+	struct ath10k_dump_file_data *dump;
+
+	dump = ath10k_build_dump_file(ar);
+	if (!dump)
+		return -ENODATA;
+
+	file->private_data = dump;
+
+	return 0;
+}
+
+static ssize_t ath10k_fw_crash_dump_read(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct ath10k_dump_file_data *dump_file = file->private_data;
+
+	return simple_read_from_buffer(user_buf, count, ppos,
+				       dump_file,
+				       le32_to_cpu(dump_file->len));
+}
+
+static int ath10k_fw_crash_dump_release(struct inode *inode,
+					struct file *file)
+{
+	vfree(file->private_data);
+
+	return 0;
+}
+
+static const struct file_operations fops_fw_crash_dump = {
+	.open = ath10k_fw_crash_dump_open,
+	.read = ath10k_fw_crash_dump_read,
+	.release = ath10k_fw_crash_dump_release,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
 static int ath10k_debug_htt_stats_req(struct ath10k *ar)
 {
 	u64 cookie;
@@ -596,7 +841,7 @@
 	ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,
 				       cookie);
 	if (ret) {
-		ath10k_warn("failed to send htt stats request: %d\n", ret);
+		ath10k_warn(ar, "failed to send htt stats request: %d\n", ret);
 		return ret;
 	}
 
@@ -619,8 +864,8 @@
 }
 
 static ssize_t ath10k_read_htt_stats_mask(struct file *file,
-					    char __user *user_buf,
-					    size_t count, loff_t *ppos)
+					  char __user *user_buf,
+					  size_t count, loff_t *ppos)
 {
 	struct ath10k *ar = file->private_data;
 	char buf[32];
@@ -632,8 +877,8 @@
 }
 
 static ssize_t ath10k_write_htt_stats_mask(struct file *file,
-					     const char __user *user_buf,
-					     size_t count, loff_t *ppos)
+					   const char __user *user_buf,
+					   size_t count, loff_t *ppos)
 {
 	struct ath10k *ar = file->private_data;
 	unsigned long mask;
@@ -738,8 +983,8 @@
 };
 
 static ssize_t ath10k_read_fw_dbglog(struct file *file,
-					    char __user *user_buf,
-					    size_t count, loff_t *ppos)
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
 {
 	struct ath10k *ar = file->private_data;
 	unsigned int len;
@@ -770,7 +1015,7 @@
 	if (ar->state == ATH10K_STATE_ON) {
 		ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
 		if (ret) {
-			ath10k_warn("dbglog cfg failed from debugfs: %d\n",
+			ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n",
 				    ret);
 			goto exit;
 		}
@@ -801,13 +1046,14 @@
 	ret = ath10k_debug_htt_stats_req(ar);
 	if (ret)
 		/* continue normally anyway, this isn't serious */
-		ath10k_warn("failed to start htt stats workqueue: %d\n", ret);
+		ath10k_warn(ar, "failed to start htt stats workqueue: %d\n",
+			    ret);
 
 	if (ar->debug.fw_dbglog_mask) {
 		ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
 		if (ret)
 			/* not serious */
-			ath10k_warn("failed to enable dbglog during start: %d",
+			ath10k_warn(ar, "failed to enable dbglog during start: %d",
 				    ret);
 	}
 
@@ -910,11 +1156,29 @@
 
 int ath10k_debug_create(struct ath10k *ar)
 {
+	ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
+	if (!ar->debug.fw_crash_data)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void ath10k_debug_destroy(struct ath10k *ar)
+{
+	vfree(ar->debug.fw_crash_data);
+	ar->debug.fw_crash_data = NULL;
+}
+
+int ath10k_debug_register(struct ath10k *ar)
+{
 	ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
 						   ar->hw->wiphy->debugfsdir);
+	if (IS_ERR_OR_NULL(ar->debug.debugfs_phy)) {
+		if (IS_ERR(ar->debug.debugfs_phy))
+			return PTR_ERR(ar->debug.debugfs_phy);
 
-	if (!ar->debug.debugfs_phy)
 		return -ENOMEM;
+	}
 
 	INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
 			  ath10k_debug_htt_stats_dwork);
@@ -930,6 +1194,9 @@
 	debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_simulate_fw_crash);
 
+	debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
+			    ar, &fops_fw_crash_dump);
+
 	debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
 			    ar, &fops_chip_id);
 
@@ -960,7 +1227,7 @@
 	return 0;
 }
 
-void ath10k_debug_destroy(struct ath10k *ar)
+void ath10k_debug_unregister(struct ath10k *ar)
 {
 	cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
 }
@@ -968,7 +1235,8 @@
 #endif /* CPTCFG_ATH10K_DEBUGFS */
 
 #ifdef CPTCFG_ATH10K_DEBUG
-void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
+void ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask,
+		const char *fmt, ...)
 {
 	struct va_format vaf;
 	va_list args;
@@ -979,27 +1247,28 @@
 	vaf.va = &args;
 
 	if (ath10k_debug_mask & mask)
-		ath10k_printk(KERN_DEBUG, "%pV", &vaf);
+		dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf);
 
-	trace_ath10k_log_dbg(mask, &vaf);
+	trace_ath10k_log_dbg(ar, mask, &vaf);
 
 	va_end(args);
 }
 EXPORT_SYMBOL(ath10k_dbg);
 
-void ath10k_dbg_dump(enum ath10k_debug_mask mask,
+void ath10k_dbg_dump(struct ath10k *ar,
+		     enum ath10k_debug_mask mask,
 		     const char *msg, const char *prefix,
 		     const void *buf, size_t len)
 {
 	if (ath10k_debug_mask & mask) {
 		if (msg)
-			ath10k_dbg(mask, "%s\n", msg);
+			ath10k_dbg(ar, mask, "%s\n", msg);
 
 		print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
 	}
 
 	/* tracing code doesn't like null strings :/ */
-	trace_ath10k_log_dbg_dump(msg ? msg : "", prefix ? prefix : "",
+	trace_ath10k_log_dbg_dump(ar, msg ? msg : "", prefix ? prefix : "",
 				  buf, len);
 }
 EXPORT_SYMBOL(ath10k_dbg_dump);
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 50f43b5..9573b44 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -34,25 +34,33 @@
 	ATH10K_DBG_DATA		= 0x00000200,
 	ATH10K_DBG_BMI		= 0x00000400,
 	ATH10K_DBG_REGULATORY	= 0x00000800,
+	ATH10K_DBG_TESTMODE	= 0x00001000,
 	ATH10K_DBG_ANY		= 0xffffffff,
 };
 
 extern unsigned int ath10k_debug_mask;
 
-__printf(1, 2) int ath10k_info(const char *fmt, ...);
-__printf(1, 2) int ath10k_err(const char *fmt, ...);
-__printf(1, 2) int ath10k_warn(const char *fmt, ...);
+__printf(2, 3) int ath10k_info(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) int ath10k_err(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) int ath10k_warn(struct ath10k *ar, const char *fmt, ...);
+void ath10k_print_driver_info(struct ath10k *ar);
 
 #ifdef CPTCFG_ATH10K_DEBUGFS
 int ath10k_debug_start(struct ath10k *ar);
 void ath10k_debug_stop(struct ath10k *ar);
 int ath10k_debug_create(struct ath10k *ar);
 void ath10k_debug_destroy(struct ath10k *ar);
+int ath10k_debug_register(struct ath10k *ar);
+void ath10k_debug_unregister(struct ath10k *ar);
 void ath10k_debug_read_service_map(struct ath10k *ar,
 				   void *service_map,
 				   size_t map_size);
 void ath10k_debug_read_target_stats(struct ath10k *ar,
 				    struct wmi_stats_event *ev);
+struct ath10k_fw_crash_data *
+ath10k_debug_get_new_fw_crash_data(struct ath10k *ar);
+
+void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
 
 #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
 
@@ -75,6 +83,15 @@
 {
 }
 
+static inline int ath10k_debug_register(struct ath10k *ar)
+{
+	return 0;
+}
+
+static inline void ath10k_debug_unregister(struct ath10k *ar)
+{
+}
+
 static inline void ath10k_debug_read_service_map(struct ath10k *ar,
 						 void *service_map,
 						 size_t map_size)
@@ -86,25 +103,40 @@
 {
 }
 
+static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
+					   int len)
+{
+}
+
+static inline struct ath10k_fw_crash_data *
+ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
+{
+	return NULL;
+}
+
 #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
 
 #endif /* CPTCFG_ATH10K_DEBUGFS */
 
 #ifdef CPTCFG_ATH10K_DEBUG
-__printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask,
+__printf(3, 4) void ath10k_dbg(struct ath10k *ar,
+			       enum ath10k_debug_mask mask,
 			       const char *fmt, ...);
-void ath10k_dbg_dump(enum ath10k_debug_mask mask,
+void ath10k_dbg_dump(struct ath10k *ar,
+		     enum ath10k_debug_mask mask,
 		     const char *msg, const char *prefix,
 		     const void *buf, size_t len);
 #else /* CPTCFG_ATH10K_DEBUG */
 
-static inline int ath10k_dbg(enum ath10k_debug_mask dbg_mask,
+static inline int ath10k_dbg(struct ath10k *ar,
+			     enum ath10k_debug_mask dbg_mask,
 			     const char *fmt, ...)
 {
 	return 0;
 }
 
-static inline void ath10k_dbg_dump(enum ath10k_debug_mask mask,
+static inline void ath10k_dbg_dump(struct ath10k *ar,
+				   enum ath10k_debug_mask mask,
 				   const char *msg, const char *prefix,
 				   const void *buf, size_t len)
 {
diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
index 2ac7bea..62323fe 100644
--- a/drivers/net/wireless/ath/ath10k/hif.h
+++ b/drivers/net/wireless/ath/ath10k/hif.h
@@ -91,7 +91,6 @@
 	int (*resume)(struct ath10k *ar);
 };
 
-
 static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
 				   struct ath10k_hif_sg_item *items,
 				   int n_items)
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 5fdc40d..676bd4e 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -45,10 +45,8 @@
 	struct ath10k_skb_cb *skb_cb;
 
 	skb = dev_alloc_skb(ATH10K_HTC_CONTROL_BUFFER_SIZE);
-	if (!skb) {
-		ath10k_warn("Unable to allocate ctrl skb\n");
+	if (!skb)
 		return NULL;
-	}
 
 	skb_reserve(skb, 20); /* FIXME: why 20 bytes? */
 	WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
@@ -56,7 +54,7 @@
 	skb_cb = ATH10K_SKB_CB(skb);
 	memset(skb_cb, 0, sizeof(*skb_cb));
 
-	ath10k_dbg(ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb);
+	ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb);
 	return skb;
 }
 
@@ -72,13 +70,15 @@
 static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
 					    struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__,
+	struct ath10k *ar = ep->htc->ar;
+
+	ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__,
 		   ep->eid, skb);
 
 	ath10k_htc_restore_tx_skb(ep->htc, skb);
 
 	if (!ep->ep_ops.ep_tx_complete) {
-		ath10k_warn("no tx handler for eid %d\n", ep->eid);
+		ath10k_warn(ar, "no tx handler for eid %d\n", ep->eid);
 		dev_kfree_skb_any(skb);
 		return;
 	}
@@ -89,12 +89,14 @@
 /* assumes tx_lock is held */
 static bool ath10k_htc_ep_need_credit_update(struct ath10k_htc_ep *ep)
 {
+	struct ath10k *ar = ep->htc->ar;
+
 	if (!ep->tx_credit_flow_enabled)
 		return false;
 	if (ep->tx_credits >= ep->tx_credits_per_max_message)
 		return false;
 
-	ath10k_dbg(ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
+	ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
 		   ep->eid);
 	return true;
 }
@@ -123,6 +125,7 @@
 		    enum ath10k_htc_ep_id eid,
 		    struct sk_buff *skb)
 {
+	struct ath10k *ar = htc->ar;
 	struct ath10k_htc_ep *ep = &htc->endpoint[eid];
 	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
 	struct ath10k_hif_sg_item sg_item;
@@ -134,18 +137,10 @@
 		return -ECOMM;
 
 	if (eid >= ATH10K_HTC_EP_COUNT) {
-		ath10k_warn("Invalid endpoint id: %d\n", eid);
+		ath10k_warn(ar, "Invalid endpoint id: %d\n", eid);
 		return -ENOENT;
 	}
 
-	/* FIXME: This looks ugly, can we fix it? */
-	spin_lock_bh(&htc->tx_lock);
-	if (htc->stopped) {
-		spin_unlock_bh(&htc->tx_lock);
-		return -ESHUTDOWN;
-	}
-	spin_unlock_bh(&htc->tx_lock);
-
 	skb_push(skb, sizeof(struct ath10k_htc_hdr));
 
 	if (ep->tx_credit_flow_enabled) {
@@ -157,7 +152,7 @@
 			goto err_pull;
 		}
 		ep->tx_credits -= credits;
-		ath10k_dbg(ATH10K_DBG_HTC,
+		ath10k_dbg(ar, ATH10K_DBG_HTC,
 			   "htc ep %d consumed %d credits (total %d)\n",
 			   eid, credits, ep->tx_credits);
 		spin_unlock_bh(&htc->tx_lock);
@@ -188,7 +183,7 @@
 	if (ep->tx_credit_flow_enabled) {
 		spin_lock_bh(&htc->tx_lock);
 		ep->tx_credits += credits;
-		ath10k_dbg(ATH10K_DBG_HTC,
+		ath10k_dbg(ar, ATH10K_DBG_HTC,
 			   "htc ep %d reverted %d credits back (total %d)\n",
 			   eid, credits, ep->tx_credits);
 		spin_unlock_bh(&htc->tx_lock);
@@ -227,11 +222,12 @@
 				 int len,
 				 enum ath10k_htc_ep_id eid)
 {
+	struct ath10k *ar = htc->ar;
 	struct ath10k_htc_ep *ep;
 	int i, n_reports;
 
 	if (len % sizeof(*report))
-		ath10k_warn("Uneven credit report len %d", len);
+		ath10k_warn(ar, "Uneven credit report len %d", len);
 
 	n_reports = len / sizeof(*report);
 
@@ -243,7 +239,7 @@
 		ep = &htc->endpoint[report->eid];
 		ep->tx_credits += report->credits;
 
-		ath10k_dbg(ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
+		ath10k_dbg(ar, ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
 			   report->eid, report->credits, ep->tx_credits);
 
 		if (ep->ep_ops.ep_tx_credits) {
@@ -260,6 +256,7 @@
 				      int length,
 				      enum ath10k_htc_ep_id src_eid)
 {
+	struct ath10k *ar = htc->ar;
 	int status = 0;
 	struct ath10k_htc_record *record;
 	u8 *orig_buffer;
@@ -279,7 +276,7 @@
 
 		if (record->hdr.len > length) {
 			/* no room left in buffer for record */
-			ath10k_warn("Invalid record length: %d\n",
+			ath10k_warn(ar, "Invalid record length: %d\n",
 				    record->hdr.len);
 			status = -EINVAL;
 			break;
@@ -289,7 +286,7 @@
 		case ATH10K_HTC_RECORD_CREDITS:
 			len = sizeof(struct ath10k_htc_credit_report);
 			if (record->hdr.len < len) {
-				ath10k_warn("Credit report too long\n");
+				ath10k_warn(ar, "Credit report too long\n");
 				status = -EINVAL;
 				break;
 			}
@@ -299,7 +296,7 @@
 							 src_eid);
 			break;
 		default:
-			ath10k_warn("Unhandled record: id:%d length:%d\n",
+			ath10k_warn(ar, "Unhandled record: id:%d length:%d\n",
 				    record->hdr.id, record->hdr.len);
 			break;
 		}
@@ -313,7 +310,7 @@
 	}
 
 	if (status)
-		ath10k_dbg_dump(ATH10K_DBG_HTC, "htc rx bad trailer", "",
+		ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc rx bad trailer", "",
 				orig_buffer, orig_length);
 
 	return status;
@@ -339,8 +336,8 @@
 	eid = hdr->eid;
 
 	if (eid >= ATH10K_HTC_EP_COUNT) {
-		ath10k_warn("HTC Rx: invalid eid %d\n", eid);
-		ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad header", "",
+		ath10k_warn(ar, "HTC Rx: invalid eid %d\n", eid);
+		ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad header", "",
 				hdr, sizeof(*hdr));
 		status = -EINVAL;
 		goto out;
@@ -360,19 +357,19 @@
 	payload_len = __le16_to_cpu(hdr->len);
 
 	if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) {
-		ath10k_warn("HTC rx frame too long, len: %zu\n",
+		ath10k_warn(ar, "HTC rx frame too long, len: %zu\n",
 			    payload_len + sizeof(*hdr));
-		ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len", "",
+		ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "",
 				hdr, sizeof(*hdr));
 		status = -EINVAL;
 		goto out;
 	}
 
 	if (skb->len < payload_len) {
-		ath10k_dbg(ATH10K_DBG_HTC,
+		ath10k_dbg(ar, ATH10K_DBG_HTC,
 			   "HTC Rx: insufficient length, got %d, expected %d\n",
 			   skb->len, payload_len);
-		ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len",
+		ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len",
 				"", hdr, sizeof(*hdr));
 		status = -EINVAL;
 		goto out;
@@ -388,7 +385,7 @@
 
 		if ((trailer_len < min_len) ||
 		    (trailer_len > payload_len)) {
-			ath10k_warn("Invalid trailer length: %d\n",
+			ath10k_warn(ar, "Invalid trailer length: %d\n",
 				    trailer_len);
 			status = -EPROTO;
 			goto out;
@@ -421,7 +418,7 @@
 				 * this is a fatal error, target should not be
 				 * sending unsolicited messages on the ep 0
 				 */
-				ath10k_warn("HTC rx ctrl still processing\n");
+				ath10k_warn(ar, "HTC rx ctrl still processing\n");
 				status = -EINVAL;
 				complete(&htc->ctl_resp);
 				goto out;
@@ -442,7 +439,7 @@
 		goto out;
 	}
 
-	ath10k_dbg(ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n",
+	ath10k_dbg(ar, ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n",
 		   eid, skb);
 	ep->ep_ops.ep_rx_complete(ar, skb);
 
@@ -459,7 +456,7 @@
 {
 	/* This is unexpected. FW is not supposed to send regular rx on this
 	 * endpoint. */
-	ath10k_warn("unexpected htc rx\n");
+	ath10k_warn(ar, "unexpected htc rx\n");
 	kfree_skb(skb);
 }
 
@@ -546,6 +543,7 @@
 
 int ath10k_htc_wait_target(struct ath10k_htc *htc)
 {
+	struct ath10k *ar = htc->ar;
 	int i, status = 0;
 	struct ath10k_htc_svc_conn_req conn_req;
 	struct ath10k_htc_svc_conn_resp conn_resp;
@@ -563,25 +561,25 @@
 		 * iomap writes unmasking PCI CE irqs aren't propagated
 		 * properly in KVM PCI-passthrough sometimes.
 		 */
-		ath10k_warn("failed to receive control response completion, polling..\n");
+		ath10k_warn(ar, "failed to receive control response completion, polling..\n");
 
 		for (i = 0; i < CE_COUNT; i++)
 			ath10k_hif_send_complete_check(htc->ar, i, 1);
 
 		status = wait_for_completion_timeout(&htc->ctl_resp,
-					ATH10K_HTC_WAIT_TIMEOUT_HZ);
+						     ATH10K_HTC_WAIT_TIMEOUT_HZ);
 
 		if (status == 0)
 			status = -ETIMEDOUT;
 	}
 
 	if (status < 0) {
-		ath10k_err("ctl_resp never came in (%d)\n", status);
+		ath10k_err(ar, "ctl_resp never came in (%d)\n", status);
 		return status;
 	}
 
 	if (htc->control_resp_len < sizeof(msg->hdr) + sizeof(msg->ready)) {
-		ath10k_err("Invalid HTC ready msg len:%d\n",
+		ath10k_err(ar, "Invalid HTC ready msg len:%d\n",
 			   htc->control_resp_len);
 		return -ECOMM;
 	}
@@ -592,21 +590,21 @@
 	credit_size  = __le16_to_cpu(msg->ready.credit_size);
 
 	if (message_id != ATH10K_HTC_MSG_READY_ID) {
-		ath10k_err("Invalid HTC ready msg: 0x%x\n", message_id);
+		ath10k_err(ar, "Invalid HTC ready msg: 0x%x\n", message_id);
 		return -ECOMM;
 	}
 
 	htc->total_transmit_credits = credit_count;
 	htc->target_credit_size = credit_size;
 
-	ath10k_dbg(ATH10K_DBG_HTC,
+	ath10k_dbg(ar, ATH10K_DBG_HTC,
 		   "Target ready! transmit resources: %d size:%d\n",
 		   htc->total_transmit_credits,
 		   htc->target_credit_size);
 
 	if ((htc->total_transmit_credits == 0) ||
 	    (htc->target_credit_size == 0)) {
-		ath10k_err("Invalid credit size received\n");
+		ath10k_err(ar, "Invalid credit size received\n");
 		return -ECOMM;
 	}
 
@@ -623,7 +621,8 @@
 	/* connect fake service */
 	status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp);
 	if (status) {
-		ath10k_err("could not connect to htc service (%d)\n", status);
+		ath10k_err(ar, "could not connect to htc service (%d)\n",
+			   status);
 		return status;
 	}
 
@@ -634,6 +633,7 @@
 			       struct ath10k_htc_svc_conn_req *conn_req,
 			       struct ath10k_htc_svc_conn_resp *conn_resp)
 {
+	struct ath10k *ar = htc->ar;
 	struct ath10k_htc_msg *msg;
 	struct ath10k_htc_conn_svc *req_msg;
 	struct ath10k_htc_conn_svc_response resp_msg_dummy;
@@ -659,13 +659,13 @@
 	tx_alloc = ath10k_htc_get_credit_allocation(htc,
 						    conn_req->service_id);
 	if (!tx_alloc)
-		ath10k_dbg(ATH10K_DBG_BOOT,
+		ath10k_dbg(ar, ATH10K_DBG_BOOT,
 			   "boot htc service %s does not allocate target credits\n",
 			   htc_service_name(conn_req->service_id));
 
 	skb = ath10k_htc_build_tx_ctrl_skb(htc->ar);
 	if (!skb) {
-		ath10k_err("Failed to allocate HTC packet\n");
+		ath10k_err(ar, "Failed to allocate HTC packet\n");
 		return -ENOMEM;
 	}
 
@@ -703,7 +703,7 @@
 	if (status <= 0) {
 		if (status == 0)
 			status = -ETIMEDOUT;
-		ath10k_err("Service connect timeout: %d\n", status);
+		ath10k_err(ar, "Service connect timeout: %d\n", status);
 		return status;
 	}
 
@@ -716,11 +716,11 @@
 	if ((message_id != ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID) ||
 	    (htc->control_resp_len < sizeof(msg->hdr) +
 	     sizeof(msg->connect_service_response))) {
-		ath10k_err("Invalid resp message ID 0x%x", message_id);
+		ath10k_err(ar, "Invalid resp message ID 0x%x", message_id);
 		return -EPROTO;
 	}
 
-	ath10k_dbg(ATH10K_DBG_HTC,
+	ath10k_dbg(ar, ATH10K_DBG_HTC,
 		   "HTC Service %s connect response: status: 0x%x, assigned ep: 0x%x\n",
 		   htc_service_name(service_id),
 		   resp_msg->status, resp_msg->eid);
@@ -729,7 +729,7 @@
 
 	/* check response status */
 	if (resp_msg->status != ATH10K_HTC_CONN_SVC_STATUS_SUCCESS) {
-		ath10k_err("HTC Service %s connect request failed: 0x%x)\n",
+		ath10k_err(ar, "HTC Service %s connect request failed: 0x%x)\n",
 			   htc_service_name(service_id),
 			   resp_msg->status);
 		return -EPROTO;
@@ -780,18 +780,18 @@
 	if (status)
 		return status;
 
-	ath10k_dbg(ATH10K_DBG_BOOT,
+	ath10k_dbg(ar, ATH10K_DBG_BOOT,
 		   "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n",
 		   htc_service_name(ep->service_id), ep->ul_pipe_id,
 		   ep->dl_pipe_id, ep->eid);
 
-	ath10k_dbg(ATH10K_DBG_BOOT,
+	ath10k_dbg(ar, ATH10K_DBG_BOOT,
 		   "boot htc ep %d ul polled %d dl polled %d\n",
 		   ep->eid, ep->ul_is_polled, ep->dl_is_polled);
 
 	if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) {
 		ep->tx_credit_flow_enabled = false;
-		ath10k_dbg(ATH10K_DBG_BOOT,
+		ath10k_dbg(ar, ATH10K_DBG_BOOT,
 			   "boot htc service '%s' eid %d TX flow control disabled\n",
 			   htc_service_name(ep->service_id), assigned_eid);
 	}
@@ -799,27 +799,26 @@
 	return status;
 }
 
-struct sk_buff *ath10k_htc_alloc_skb(int size)
+struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size)
 {
 	struct sk_buff *skb;
 
 	skb = dev_alloc_skb(size + sizeof(struct ath10k_htc_hdr));
-	if (!skb) {
-		ath10k_warn("could not allocate HTC tx skb\n");
+	if (!skb)
 		return NULL;
-	}
 
 	skb_reserve(skb, sizeof(struct ath10k_htc_hdr));
 
 	/* FW/HTC requires 4-byte aligned streams */
 	if (!IS_ALIGNED((unsigned long)skb->data, 4))
-		ath10k_warn("Unaligned HTC tx skb\n");
+		ath10k_warn(ar, "Unaligned HTC tx skb\n");
 
 	return skb;
 }
 
 int ath10k_htc_start(struct ath10k_htc *htc)
 {
+	struct ath10k *ar = htc->ar;
 	struct sk_buff *skb;
 	int status = 0;
 	struct ath10k_htc_msg *msg;
@@ -835,7 +834,7 @@
 	msg->hdr.message_id =
 		__cpu_to_le16(ATH10K_HTC_MSG_SETUP_COMPLETE_EX_ID);
 
-	ath10k_dbg(ATH10K_DBG_HTC, "HTC is using TX credit flow control\n");
+	ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC is using TX credit flow control\n");
 
 	status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb);
 	if (status) {
@@ -846,13 +845,6 @@
 	return 0;
 }
 
-void ath10k_htc_stop(struct ath10k_htc *htc)
-{
-	spin_lock_bh(&htc->tx_lock);
-	htc->stopped = true;
-	spin_unlock_bh(&htc->tx_lock);
-}
-
 /* registered target arrival callback from the HIF layer */
 int ath10k_htc_init(struct ath10k *ar)
 {
@@ -862,7 +854,6 @@
 
 	spin_lock_init(&htc->tx_lock);
 
-	htc->stopped = false;
 	ath10k_htc_reset_endpoint_states(htc);
 
 	/* setup HIF layer callbacks */
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index 4716d33..527179c 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -214,7 +214,6 @@
 	struct ath10k_htc_record trailer[0];
 } __packed __aligned(4);
 
-
 /*******************/
 /* Host-side stuff */
 /*******************/
@@ -332,7 +331,7 @@
 	struct ath10k *ar;
 	struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT];
 
-	/* protects endpoint and stopped fields */
+	/* protects endpoints */
 	spinlock_t tx_lock;
 
 	struct ath10k_htc_ops htc_ops;
@@ -345,8 +344,6 @@
 	int total_transmit_credits;
 	struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT];
 	int target_credit_size;
-
-	bool stopped;
 };
 
 int ath10k_htc_init(struct ath10k *ar);
@@ -357,7 +354,6 @@
 			       struct ath10k_htc_svc_conn_resp *conn_resp);
 int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
 		    struct sk_buff *packet);
-void ath10k_htc_stop(struct ath10k_htc *htc);
-struct sk_buff *ath10k_htc_alloc_skb(int size);
+struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
 
 #endif
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 19c12cc..56cb4ac 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -74,12 +74,14 @@
 
 static int ath10k_htt_verify_version(struct ath10k_htt *htt)
 {
-	ath10k_dbg(ATH10K_DBG_BOOT, "htt target version %d.%d\n",
+	struct ath10k *ar = htt->ar;
+
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt target version %d.%d\n",
 		   htt->target_version_major, htt->target_version_minor);
 
 	if (htt->target_version_major != 2 &&
 	    htt->target_version_major != 3) {
-		ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n",
+		ath10k_err(ar, "unsupported htt major version %d. supported versions are 2 and 3\n",
 			   htt->target_version_major);
 		return -ENOTSUPP;
 	}
@@ -89,6 +91,7 @@
 
 int ath10k_htt_setup(struct ath10k_htt *htt)
 {
+	struct ath10k *ar = htt->ar;
 	int status;
 
 	init_completion(&htt->target_version_received);
@@ -98,9 +101,9 @@
 		return status;
 
 	status = wait_for_completion_timeout(&htt->target_version_received,
-						HTT_TARGET_VERSION_TIMEOUT_HZ);
+					     HTT_TARGET_VERSION_TIMEOUT_HZ);
 	if (status <= 0) {
-		ath10k_warn("htt version request timed out\n");
+		ath10k_warn(ar, "htt version request timed out\n");
 		return -ETIMEDOUT;
 	}
 
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 6c93f38..3b44217 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -265,7 +265,6 @@
 
 /*=== target -> host messages ===============================================*/
 
-
 enum htt_t2h_msg_type {
 	HTT_T2H_MSG_TYPE_VERSION_CONF		= 0x0,
 	HTT_T2H_MSG_TYPE_RX_IND			= 0x1,
@@ -1032,6 +1031,7 @@
 {
 	return (void *)item + sizeof(*item) + roundup(item->length, 4);
 }
+
 /*
  * host -> target FRAG DESCRIPTOR/MSDU_EXT DESC bank
  *
@@ -1148,7 +1148,6 @@
 	};
 } __packed;
 
-
 /*** host side structures follow ***/
 
 struct htt_tx_done {
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 80cdac1..60d40a0 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -42,7 +42,6 @@
 /* when under memory pressure rx ring refill may fail and needs a retry */
 #define HTT_RX_RING_REFILL_RETRY_MS 50
 
-
 static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb);
 static void ath10k_htt_txrx_compl_task(unsigned long ptr);
 
@@ -133,7 +132,7 @@
 	dma_addr_t paddr;
 	int ret = 0, idx;
 
-	idx = __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr));
+	idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr);
 	while (num > 0) {
 		skb = dev_alloc_skb(HTT_RX_BUF_SIZE + HTT_RX_DESC_ALIGN);
 		if (!skb) {
@@ -171,7 +170,7 @@
 	}
 
 fail:
-	*(htt->rx_ring.alloc_idx.vaddr) = __cpu_to_le32(idx);
+	*htt->rx_ring.alloc_idx.vaddr = __cpu_to_le32(idx);
 	return ret;
 }
 
@@ -223,6 +222,7 @@
 static void ath10k_htt_rx_ring_refill_retry(unsigned long arg)
 {
 	struct ath10k_htt *htt = (struct ath10k_htt *)arg;
+
 	ath10k_htt_rx_msdu_buff_replenish(htt);
 }
 
@@ -271,13 +271,14 @@
 
 static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
 {
+	struct ath10k *ar = htt->ar;
 	int idx;
 	struct sk_buff *msdu;
 
 	lockdep_assert_held(&htt->rx_ring.lock);
 
 	if (htt->rx_ring.fill_cnt == 0) {
-		ath10k_warn("tried to pop sk_buff from an empty rx ring\n");
+		ath10k_warn(ar, "tried to pop sk_buff from an empty rx ring\n");
 		return NULL;
 	}
 
@@ -311,14 +312,15 @@
 				   struct sk_buff **tail_msdu,
 				   u32 *attention)
 {
+	struct ath10k *ar = htt->ar;
 	int msdu_len, msdu_chaining = 0;
-	struct sk_buff *msdu;
+	struct sk_buff *msdu, *next;
 	struct htt_rx_desc *rx_desc;
 
 	lockdep_assert_held(&htt->rx_ring.lock);
 
 	if (htt->rx_confused) {
-		ath10k_warn("htt is confused. refusing rx\n");
+		ath10k_warn(ar, "htt is confused. refusing rx\n");
 		return -1;
 	}
 
@@ -331,7 +333,7 @@
 				 msdu->len + skb_tailroom(msdu),
 				 DMA_FROM_DEVICE);
 
-		ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
+		ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
 				msdu->data, msdu->len + skb_tailroom(msdu));
 
 		rx_desc = (struct htt_rx_desc *)msdu->data;
@@ -354,7 +356,7 @@
 			ath10k_htt_rx_free_msdu_chain(*head_msdu);
 			*head_msdu = NULL;
 			msdu = NULL;
-			ath10k_err("htt rx stopped. cannot recover\n");
+			ath10k_err(ar, "htt rx stopped. cannot recover\n");
 			htt->rx_confused = true;
 			break;
 		}
@@ -429,7 +431,7 @@
 					 next->len + skb_tailroom(next),
 					 DMA_FROM_DEVICE);
 
-			ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL,
+			ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL,
 					"htt rx chained: ", next->data,
 					next->len + skb_tailroom(next));
 
@@ -448,11 +450,11 @@
 		if (last_msdu) {
 			msdu->next = NULL;
 			break;
-		} else {
-			struct sk_buff *next = ath10k_htt_rx_netbuf_pop(htt);
-			msdu->next = next;
-			msdu = next;
 		}
+
+		next = ath10k_htt_rx_netbuf_pop(htt);
+		msdu->next = next;
+		msdu = next;
 	}
 	*tail_msdu = msdu;
 
@@ -478,18 +480,21 @@
 static void ath10k_htt_rx_replenish_task(unsigned long ptr)
 {
 	struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
+
 	ath10k_htt_rx_msdu_buff_replenish(htt);
 }
 
 int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
 {
+	struct ath10k *ar = htt->ar;
 	dma_addr_t paddr;
 	void *vaddr;
+	size_t size;
 	struct timer_list *timer = &htt->rx_ring.refill_retry_timer;
 
 	htt->rx_ring.size = ath10k_htt_rx_ring_size(htt);
 	if (!is_power_of_2(htt->rx_ring.size)) {
-		ath10k_warn("htt rx ring size is not power of 2\n");
+		ath10k_warn(ar, "htt rx ring size is not power of 2\n");
 		return -EINVAL;
 	}
 
@@ -512,9 +517,9 @@
 	if (!htt->rx_ring.netbufs_ring)
 		goto err_netbuf;
 
-	vaddr = dma_alloc_coherent(htt->ar->dev,
-		   (htt->rx_ring.size * sizeof(htt->rx_ring.paddrs_ring)),
-		   &paddr, GFP_DMA);
+	size = htt->rx_ring.size * sizeof(htt->rx_ring.paddrs_ring);
+
+	vaddr = dma_alloc_coherent(htt->ar->dev, size, &paddr, GFP_DMA);
 	if (!vaddr)
 		goto err_dma_ring;
 
@@ -550,7 +555,7 @@
 	tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task,
 		     (unsigned long)htt);
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
 		   htt->rx_ring.size, htt->rx_ring.fill_level);
 	return 0;
 
@@ -572,7 +577,8 @@
 	return -ENOMEM;
 }
 
-static int ath10k_htt_rx_crypto_param_len(enum htt_rx_mpdu_encrypt_type type)
+static int ath10k_htt_rx_crypto_param_len(struct ath10k *ar,
+					  enum htt_rx_mpdu_encrypt_type type)
 {
 	switch (type) {
 	case HTT_RX_MPDU_ENCRYPT_WEP40:
@@ -588,11 +594,12 @@
 		return 0;
 	}
 
-	ath10k_warn("unknown encryption type %d\n", type);
+	ath10k_warn(ar, "unknown encryption type %d\n", type);
 	return 0;
 }
 
-static int ath10k_htt_rx_crypto_tail_len(enum htt_rx_mpdu_encrypt_type type)
+static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
+					 enum htt_rx_mpdu_encrypt_type type)
 {
 	switch (type) {
 	case HTT_RX_MPDU_ENCRYPT_NONE:
@@ -608,7 +615,7 @@
 		return 8;
 	}
 
-	ath10k_warn("unknown encryption type %d\n", type);
+	ath10k_warn(ar, "unknown encryption type %d\n", type);
 	return 0;
 }
 
@@ -620,19 +627,21 @@
 
 	rxd = (void *)skb->data - sizeof(*rxd);
 	fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
-			RX_MSDU_START_INFO1_DECAP_FORMAT);
+		 RX_MSDU_START_INFO1_DECAP_FORMAT);
 
 	if (fmt == RX_MSDU_DECAP_RAW)
 		return (void *)skb->data;
-	else
-		return (void *)skb->data - RX_HTT_HDR_STATUS_LEN;
+
+	return (void *)skb->data - RX_HTT_HDR_STATUS_LEN;
 }
 
 /* This function only applies for first msdu in an msdu chain */
 static bool ath10k_htt_rx_hdr_is_amsdu(struct ieee80211_hdr *hdr)
 {
+	u8 *qc;
+
 	if (ieee80211_is_data_qos(hdr->frame_control)) {
-		u8 *qc = ieee80211_get_qos_ctl(hdr);
+		qc = ieee80211_get_qos_ctl(hdr);
 		if (qc[0] & 0x80)
 			return true;
 	}
@@ -819,19 +828,55 @@
 	return true;
 }
 
+static const char * const tid_to_ac[] = {
+	"BE",
+	"BK",
+	"BK",
+	"BE",
+	"VI",
+	"VI",
+	"VO",
+	"VO",
+};
+
+static char *ath10k_get_tid(struct ieee80211_hdr *hdr, char *out, size_t size)
+{
+	u8 *qc;
+	int tid;
+
+	if (!ieee80211_is_data_qos(hdr->frame_control))
+		return "";
+
+	qc = ieee80211_get_qos_ctl(hdr);
+	tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+	if (tid < 8)
+		snprintf(out, size, "tid %d (%s)", tid, tid_to_ac[tid]);
+	else
+		snprintf(out, size, "tid %d", tid);
+
+	return out;
+}
+
 static void ath10k_process_rx(struct ath10k *ar,
 			      struct ieee80211_rx_status *rx_status,
 			      struct sk_buff *skb)
 {
 	struct ieee80211_rx_status *status;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	char tid[32];
 
 	status = IEEE80211_SKB_RXCB(skb);
 	*status = *rx_status;
 
-	ath10k_dbg(ATH10K_DBG_DATA,
-		   "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %imic-err %i\n",
+	ath10k_dbg(ar, ATH10K_DBG_DATA,
+		   "rx skb %p len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
 		   skb,
 		   skb->len,
+		   ieee80211_get_SA(hdr),
+		   ath10k_get_tid(hdr, tid, sizeof(tid)),
+		   is_multicast_ether_addr(ieee80211_get_DA(hdr)) ?
+							"mcast" : "ucast",
+		   (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4,
 		   status->flag == 0 ? "legacy" : "",
 		   status->flag & RX_FLAG_HT ? "ht" : "",
 		   status->flag & RX_FLAG_VHT ? "vht" : "",
@@ -843,8 +888,9 @@
 		   status->freq,
 		   status->band, status->flag,
 		   !!(status->flag & RX_FLAG_FAILED_FCS_CRC),
-		   !!(status->flag & RX_FLAG_MMIC_ERROR));
-	ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
+		   !!(status->flag & RX_FLAG_MMIC_ERROR),
+		   !!(status->flag & RX_FLAG_AMSDU_MORE));
+	ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
 			skb->data, skb->len);
 
 	ieee80211_rx(ar->hw, skb);
@@ -860,18 +906,19 @@
 				struct ieee80211_rx_status *rx_status,
 				struct sk_buff *skb_in)
 {
+	struct ath10k *ar = htt->ar;
 	struct htt_rx_desc *rxd;
 	struct sk_buff *skb = skb_in;
 	struct sk_buff *first;
 	enum rx_msdu_decap_format fmt;
 	enum htt_rx_mpdu_encrypt_type enctype;
 	struct ieee80211_hdr *hdr;
-	u8 hdr_buf[64], addr[ETH_ALEN], *qos;
+	u8 hdr_buf[64], da[ETH_ALEN], sa[ETH_ALEN], *qos;
 	unsigned int hdr_len;
 
 	rxd = (void *)skb->data - sizeof(*rxd);
 	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
-			RX_MPDU_START_INFO0_ENCRYPT_TYPE);
+		     RX_MPDU_START_INFO0_ENCRYPT_TYPE);
 
 	hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status;
 	hdr_len = ieee80211_hdrlen(hdr->frame_control);
@@ -893,8 +940,8 @@
 		/* First frame in an A-MSDU chain has more decapped data. */
 		if (skb == first) {
 			len = round_up(ieee80211_hdrlen(hdr->frame_control), 4);
-			len += round_up(ath10k_htt_rx_crypto_param_len(enctype),
-					4);
+			len += round_up(ath10k_htt_rx_crypto_param_len(ar,
+						enctype), 4);
 			decap_hdr += len;
 		}
 
@@ -904,10 +951,11 @@
 			skb_trim(skb, skb->len - FCS_LEN);
 			break;
 		case RX_MSDU_DECAP_NATIVE_WIFI:
-			/* pull decapped header and copy DA */
+			/* pull decapped header and copy SA & DA */
 			hdr = (struct ieee80211_hdr *)skb->data;
 			hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
-			memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN);
+			ether_addr_copy(da, ieee80211_get_DA(hdr));
+			ether_addr_copy(sa, ieee80211_get_SA(hdr));
 			skb_pull(skb, hdr_len);
 
 			/* push original 802.11 header */
@@ -921,8 +969,11 @@
 			qos = ieee80211_get_qos_ctl(hdr);
 			qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
 
-			/* original 802.11 header has a different DA */
-			memcpy(ieee80211_get_DA(hdr), addr, ETH_ALEN);
+			/* original 802.11 header has a different DA and in
+			 * case of 4addr it may also have different SA
+			 */
+			ether_addr_copy(ieee80211_get_DA(hdr), da);
+			ether_addr_copy(ieee80211_get_SA(hdr), sa);
 			break;
 		case RX_MSDU_DECAP_ETHERNET2_DIX:
 			/* strip ethernet header and insert decapped 802.11
@@ -965,6 +1016,7 @@
 			       struct ieee80211_rx_status *rx_status,
 			       struct sk_buff *skb)
 {
+	struct ath10k *ar = htt->ar;
 	struct htt_rx_desc *rxd;
 	struct ieee80211_hdr *hdr;
 	enum rx_msdu_decap_format fmt;
@@ -974,16 +1026,16 @@
 
 	/* This shouldn't happen. If it does than it may be a FW bug. */
 	if (skb->next) {
-		ath10k_warn("htt rx received chained non A-MSDU frame\n");
+		ath10k_warn(ar, "htt rx received chained non A-MSDU frame\n");
 		ath10k_htt_rx_free_msdu_chain(skb->next);
 		skb->next = NULL;
 	}
 
 	rxd = (void *)skb->data - sizeof(*rxd);
 	fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
-			RX_MSDU_START_INFO1_DECAP_FORMAT);
+		 RX_MSDU_START_INFO1_DECAP_FORMAT);
 	enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
-			RX_MPDU_START_INFO0_ENCRYPT_TYPE);
+		     RX_MPDU_START_INFO0_ENCRYPT_TYPE);
 	hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status;
 	hdr_len = ieee80211_hdrlen(hdr->frame_control);
 
@@ -1011,7 +1063,8 @@
 
 		rfc1042 = hdr;
 		rfc1042 += roundup(hdr_len, 4);
-		rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(enctype), 4);
+		rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(ar,
+					enctype), 4);
 
 		skb_pull(skb, sizeof(struct ethhdr));
 		memcpy(skb_push(skb, sizeof(struct rfc1042_hdr)),
@@ -1120,27 +1173,29 @@
 					bool channel_set,
 					u32 attention)
 {
+	struct ath10k *ar = htt->ar;
+
 	if (head->len == 0) {
-		ath10k_dbg(ATH10K_DBG_HTT,
+		ath10k_dbg(ar, ATH10K_DBG_HTT,
 			   "htt rx dropping due to zero-len\n");
 		return false;
 	}
 
 	if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) {
-		ath10k_dbg(ATH10K_DBG_HTT,
+		ath10k_dbg(ar, ATH10K_DBG_HTT,
 			   "htt rx dropping due to decrypt-err\n");
 		return false;
 	}
 
 	if (!channel_set) {
-		ath10k_warn("no channel configured; ignoring frame!\n");
+		ath10k_warn(ar, "no channel configured; ignoring frame!\n");
 		return false;
 	}
 
 	/* Skip mgmt frames while we handle this in WMI */
 	if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL ||
 	    attention & RX_ATTENTION_FLAGS_MGMT_TYPE) {
-		ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
+		ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
 		return false;
 	}
 
@@ -1148,14 +1203,14 @@
 	    status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
 	    status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
 	    !htt->ar->monitor_started) {
-		ath10k_dbg(ATH10K_DBG_HTT,
+		ath10k_dbg(ar, ATH10K_DBG_HTT,
 			   "htt rx ignoring frame w/ status %d\n",
 			   status);
 		return false;
 	}
 
 	if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
-		ath10k_dbg(ATH10K_DBG_HTT,
+		ath10k_dbg(ar, ATH10K_DBG_HTT,
 			   "htt rx CAC running\n");
 		return false;
 	}
@@ -1166,6 +1221,7 @@
 static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 				  struct htt_rx_indication *rx)
 {
+	struct ath10k *ar = htt->ar;
 	struct ieee80211_rx_status *rx_status = &htt->rx_status;
 	struct htt_rx_indication_mpdu_range *mpdu_ranges;
 	struct htt_rx_desc *rxd;
@@ -1211,7 +1267,7 @@
 				      rx_status);
 	}
 
-	ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
+	ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
 			rx, sizeof(*rx) +
 			(sizeof(struct htt_rx_indication_mpdu_range) *
 				num_mpdu_ranges));
@@ -1233,7 +1289,7 @@
 						      &attention);
 
 			if (ret < 0) {
-				ath10k_warn("failed to pop amsdu from htt rx ring %d\n",
+				ath10k_warn(ar, "failed to pop amsdu from htt rx ring %d\n",
 					    ret);
 				ath10k_htt_rx_free_msdu_chain(msdu_head);
 				continue;
@@ -1280,8 +1336,9 @@
 }
 
 static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
-				struct htt_rx_fragment_indication *frag)
+				       struct htt_rx_fragment_indication *frag)
 {
+	struct ath10k *ar = htt->ar;
 	struct sk_buff *msdu_head, *msdu_tail;
 	enum htt_rx_mpdu_encrypt_type enctype;
 	struct htt_rx_desc *rxd;
@@ -1308,10 +1365,10 @@
 				      &attention);
 	spin_unlock_bh(&htt->rx_ring.lock);
 
-	ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
+	ath10k_dbg(ar, ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
 
 	if (ret) {
-		ath10k_warn("failed to pop amsdu from httr rx ring for fragmented rx %d\n",
+		ath10k_warn(ar, "failed to pop amsdu from httr rx ring for fragmented rx %d\n",
 			    ret);
 		ath10k_htt_rx_free_msdu_chain(msdu_head);
 		return;
@@ -1325,10 +1382,10 @@
 	tkip_mic_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR);
 	decrypt_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR);
 	fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
-			RX_MSDU_START_INFO1_DECAP_FORMAT);
+		 RX_MSDU_START_INFO1_DECAP_FORMAT);
 
 	if (fmt != RX_MSDU_DECAP_RAW) {
-		ath10k_warn("we dont support non-raw fragmented rx yet\n");
+		ath10k_warn(ar, "we dont support non-raw fragmented rx yet\n");
 		dev_kfree_skb_any(msdu_head);
 		goto end;
 	}
@@ -1340,17 +1397,17 @@
 	msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head);
 
 	if (tkip_mic_err)
-		ath10k_warn("tkip mic error\n");
+		ath10k_warn(ar, "tkip mic error\n");
 
 	if (decrypt_err) {
-		ath10k_warn("decryption err in fragmented rx\n");
+		ath10k_warn(ar, "decryption err in fragmented rx\n");
 		dev_kfree_skb_any(msdu_head);
 		goto end;
 	}
 
 	if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) {
 		hdrlen = ieee80211_hdrlen(hdr->frame_control);
-		paramlen = ath10k_htt_rx_crypto_param_len(enctype);
+		paramlen = ath10k_htt_rx_crypto_param_len(ar, enctype);
 
 		/* It is more efficient to move the header than the payload */
 		memmove((void *)msdu_head->data + paramlen,
@@ -1364,7 +1421,7 @@
 	trim  = 4;
 
 	/* remove crypto trailer */
-	trim += ath10k_htt_rx_crypto_tail_len(enctype);
+	trim += ath10k_htt_rx_crypto_tail_len(ar, enctype);
 
 	/* last fragment of TKIP frags has MIC */
 	if (!ieee80211_has_morefrags(hdr->frame_control) &&
@@ -1372,20 +1429,20 @@
 		trim += 8;
 
 	if (trim > msdu_head->len) {
-		ath10k_warn("htt rx fragment: trailer longer than the frame itself? drop\n");
+		ath10k_warn(ar, "htt rx fragment: trailer longer than the frame itself? drop\n");
 		dev_kfree_skb_any(msdu_head);
 		goto end;
 	}
 
 	skb_trim(msdu_head, msdu_head->len - trim);
 
-	ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
+	ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
 			msdu_head->data, msdu_head->len);
 	ath10k_process_rx(htt->ar, rx_status, msdu_head);
 
 end:
 	if (fw_desc_len > 0) {
-		ath10k_dbg(ATH10K_DBG_HTT,
+		ath10k_dbg(ar, ATH10K_DBG_HTT,
 			   "expecting more fragmented rx in one indication %d\n",
 			   fw_desc_len);
 	}
@@ -1415,12 +1472,12 @@
 		tx_done.discard = true;
 		break;
 	default:
-		ath10k_warn("unhandled tx completion status %d\n", status);
+		ath10k_warn(ar, "unhandled tx completion status %d\n", status);
 		tx_done.discard = true;
 		break;
 	}
 
-	ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
 		   resp->data_tx_completion.num_msdus);
 
 	for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
@@ -1441,14 +1498,14 @@
 	tid = MS(info0, HTT_RX_BA_INFO0_TID);
 	peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID);
 
-	ath10k_dbg(ATH10K_DBG_HTT,
+	ath10k_dbg(ar, ATH10K_DBG_HTT,
 		   "htt rx addba tid %hu peer_id %hu size %hhu\n",
 		   tid, peer_id, ev->window_size);
 
 	spin_lock_bh(&ar->data_lock);
 	peer = ath10k_peer_find_by_id(ar, peer_id);
 	if (!peer) {
-		ath10k_warn("received addba event for invalid peer_id: %hu\n",
+		ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n",
 			    peer_id);
 		spin_unlock_bh(&ar->data_lock);
 		return;
@@ -1456,13 +1513,13 @@
 
 	arvif = ath10k_get_arvif(ar, peer->vdev_id);
 	if (!arvif) {
-		ath10k_warn("received addba event for invalid vdev_id: %u\n",
+		ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n",
 			    peer->vdev_id);
 		spin_unlock_bh(&ar->data_lock);
 		return;
 	}
 
-	ath10k_dbg(ATH10K_DBG_HTT,
+	ath10k_dbg(ar, ATH10K_DBG_HTT,
 		   "htt rx start rx ba session sta %pM tid %hu size %hhu\n",
 		   peer->addr, tid, ev->window_size);
 
@@ -1481,14 +1538,14 @@
 	tid = MS(info0, HTT_RX_BA_INFO0_TID);
 	peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID);
 
-	ath10k_dbg(ATH10K_DBG_HTT,
+	ath10k_dbg(ar, ATH10K_DBG_HTT,
 		   "htt rx delba tid %hu peer_id %hu\n",
 		   tid, peer_id);
 
 	spin_lock_bh(&ar->data_lock);
 	peer = ath10k_peer_find_by_id(ar, peer_id);
 	if (!peer) {
-		ath10k_warn("received addba event for invalid peer_id: %hu\n",
+		ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n",
 			    peer_id);
 		spin_unlock_bh(&ar->data_lock);
 		return;
@@ -1496,13 +1553,13 @@
 
 	arvif = ath10k_get_arvif(ar, peer->vdev_id);
 	if (!arvif) {
-		ath10k_warn("received addba event for invalid vdev_id: %u\n",
+		ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n",
 			    peer->vdev_id);
 		spin_unlock_bh(&ar->data_lock);
 		return;
 	}
 
-	ath10k_dbg(ATH10K_DBG_HTT,
+	ath10k_dbg(ar, ATH10K_DBG_HTT,
 		   "htt rx stop rx ba session sta %pM tid %hu\n",
 		   peer->addr, tid);
 
@@ -1517,9 +1574,9 @@
 
 	/* confirm alignment */
 	if (!IS_ALIGNED((unsigned long)skb->data, 4))
-		ath10k_warn("unaligned htt message, expect trouble\n");
+		ath10k_warn(ar, "unaligned htt message, expect trouble\n");
 
-	ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
+	ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
 		   resp->hdr.msg_type);
 	switch (resp->hdr.msg_type) {
 	case HTT_T2H_MSG_TYPE_VERSION_CONF: {
@@ -1583,7 +1640,7 @@
 		struct ath10k *ar = htt->ar;
 		struct htt_security_indication *ev = &resp->security_indication;
 
-		ath10k_dbg(ATH10K_DBG_HTT,
+		ath10k_dbg(ar, ATH10K_DBG_HTT,
 			   "sec ind peer_id %d unicast %d type %d\n",
 			  __le16_to_cpu(ev->peer_id),
 			  !!(ev->flags & HTT_SECURITY_IS_UNICAST),
@@ -1592,7 +1649,7 @@
 		break;
 	}
 	case HTT_T2H_MSG_TYPE_RX_FRAG_IND: {
-		ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
+		ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
 				skb->data, skb->len);
 		ath10k_htt_rx_frag_handler(htt, &resp->rx_frag_ind);
 		break;
@@ -1601,7 +1658,7 @@
 		/* FIX THIS */
 		break;
 	case HTT_T2H_MSG_TYPE_STATS_CONF:
-		trace_ath10k_htt_stats(skb->data, skb->len);
+		trace_ath10k_htt_stats(ar, skb->data, skb->len);
 		break;
 	case HTT_T2H_MSG_TYPE_TX_INSPECT_IND:
 		/* Firmware can return tx frames if it's unable to fully
@@ -1609,7 +1666,7 @@
 		 * sends all tx frames as already inspected so this shouldn't
 		 * happen unless fw has a bug.
 		 */
-		ath10k_warn("received an unexpected htt tx inspect event\n");
+		ath10k_warn(ar, "received an unexpected htt tx inspect event\n");
 		break;
 	case HTT_T2H_MSG_TYPE_RX_ADDBA:
 		ath10k_htt_rx_addba(ar, resp);
@@ -1624,9 +1681,9 @@
 		break;
 	}
 	default:
-		ath10k_dbg(ATH10K_DBG_HTT, "htt event (%d) not handled\n",
+		ath10k_dbg(ar, ATH10K_DBG_HTT, "htt event (%d) not handled\n",
 			   resp->hdr.msg_type);
-		ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
+		ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
 				skb->data, skb->len);
 		break;
 	};
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 8b27bfc..bd87a35 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -58,6 +58,7 @@
 
 int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt)
 {
+	struct ath10k *ar = htt->ar;
 	int msdu_id;
 
 	lockdep_assert_held(&htt->tx_lock);
@@ -67,24 +68,29 @@
 	if (msdu_id == htt->max_num_pending_tx)
 		return -ENOBUFS;
 
-	ath10k_dbg(ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id);
+	ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id);
 	__set_bit(msdu_id, htt->used_msdu_ids);
 	return msdu_id;
 }
 
 void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
 {
+	struct ath10k *ar = htt->ar;
+
 	lockdep_assert_held(&htt->tx_lock);
 
 	if (!test_bit(msdu_id, htt->used_msdu_ids))
-		ath10k_warn("trying to free unallocated msdu_id %d\n", msdu_id);
+		ath10k_warn(ar, "trying to free unallocated msdu_id %d\n",
+			    msdu_id);
 
-	ath10k_dbg(ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id);
+	ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id);
 	__clear_bit(msdu_id, htt->used_msdu_ids);
 }
 
 int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
 {
+	struct ath10k *ar = htt->ar;
+
 	spin_lock_init(&htt->tx_lock);
 	init_waitqueue_head(&htt->empty_tx_wq);
 
@@ -93,7 +99,7 @@
 	else
 		htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC;
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
 		   htt->max_num_pending_tx);
 
 	htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) *
@@ -122,6 +128,7 @@
 
 static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt)
 {
+	struct ath10k *ar = htt->ar;
 	struct htt_tx_done tx_done = {0};
 	int msdu_id;
 
@@ -130,7 +137,7 @@
 		if (!test_bit(msdu_id, htt->used_msdu_ids))
 			continue;
 
-		ath10k_dbg(ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
+		ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
 			   msdu_id);
 
 		tx_done.discard = 1;
@@ -147,7 +154,6 @@
 	kfree(htt->pending_tx);
 	kfree(htt->used_msdu_ids);
 	dma_pool_destroy(htt->tx_pool);
-	return;
 }
 
 void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
@@ -157,6 +163,7 @@
 
 int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
 {
+	struct ath10k *ar = htt->ar;
 	struct sk_buff *skb;
 	struct htt_cmd *cmd;
 	int len = 0;
@@ -165,7 +172,7 @@
 	len += sizeof(cmd->hdr);
 	len += sizeof(cmd->ver_req);
 
-	skb = ath10k_htc_alloc_skb(len);
+	skb = ath10k_htc_alloc_skb(ar, len);
 	if (!skb)
 		return -ENOMEM;
 
@@ -184,6 +191,7 @@
 
 int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
 {
+	struct ath10k *ar = htt->ar;
 	struct htt_stats_req *req;
 	struct sk_buff *skb;
 	struct htt_cmd *cmd;
@@ -192,7 +200,7 @@
 	len += sizeof(cmd->hdr);
 	len += sizeof(cmd->stats_req);
 
-	skb = ath10k_htc_alloc_skb(len);
+	skb = ath10k_htc_alloc_skb(ar, len);
 	if (!skb)
 		return -ENOMEM;
 
@@ -214,7 +222,8 @@
 
 	ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
 	if (ret) {
-		ath10k_warn("failed to send htt type stats request: %d", ret);
+		ath10k_warn(ar, "failed to send htt type stats request: %d",
+			    ret);
 		dev_kfree_skb_any(skb);
 		return ret;
 	}
@@ -224,6 +233,7 @@
 
 int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
 {
+	struct ath10k *ar = htt->ar;
 	struct sk_buff *skb;
 	struct htt_cmd *cmd;
 	struct htt_rx_ring_setup_ring *ring;
@@ -242,7 +252,7 @@
 
 	len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup.hdr)
 	    + (sizeof(*ring) * num_rx_ring);
-	skb = ath10k_htc_alloc_skb(len);
+	skb = ath10k_htc_alloc_skb(ar, len);
 	if (!skb)
 		return -ENOMEM;
 
@@ -311,6 +321,7 @@
 				u8 max_subfrms_ampdu,
 				u8 max_subfrms_amsdu)
 {
+	struct ath10k *ar = htt->ar;
 	struct htt_aggr_conf *aggr_conf;
 	struct sk_buff *skb;
 	struct htt_cmd *cmd;
@@ -328,7 +339,7 @@
 	len = sizeof(cmd->hdr);
 	len += sizeof(cmd->aggr_conf);
 
-	skb = ath10k_htc_alloc_skb(len);
+	skb = ath10k_htc_alloc_skb(ar, len);
 	if (!skb)
 		return -ENOMEM;
 
@@ -340,7 +351,7 @@
 	aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu;
 	aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu;
 
-	ath10k_dbg(ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d",
+	ath10k_dbg(ar, ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d",
 		   aggr_conf->max_num_amsdu_subframes,
 		   aggr_conf->max_num_ampdu_subframes);
 
@@ -355,7 +366,8 @@
 
 int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 {
-	struct device *dev = htt->ar->dev;
+	struct ath10k *ar = htt->ar;
+	struct device *dev = ar->dev;
 	struct sk_buff *txdesc = NULL;
 	struct htt_cmd *cmd;
 	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
@@ -364,7 +376,6 @@
 	int msdu_id = -1;
 	int res;
 
-
 	res = ath10k_htt_tx_inc_pending(htt);
 	if (res)
 		goto err;
@@ -382,7 +393,7 @@
 	htt->pending_tx[msdu_id] = msdu;
 	spin_unlock_bh(&htt->tx_lock);
 
-	txdesc = ath10k_htc_alloc_skb(len);
+	txdesc = ath10k_htc_alloc_skb(ar, len);
 	if (!txdesc) {
 		res = -ENOMEM;
 		goto err_free_msdu_id;
@@ -429,7 +440,8 @@
 
 int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 {
-	struct device *dev = htt->ar->dev;
+	struct ath10k *ar = htt->ar;
+	struct device *dev = ar->dev;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
 	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
 	struct ath10k_hif_sg_item sg_items[2];
@@ -545,11 +557,11 @@
 	skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
 	skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
 
-	ath10k_dbg(ATH10K_DBG_HTT,
+	ath10k_dbg(ar, ATH10K_DBG_HTT,
 		   "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n",
 		   flags0, flags1, msdu->len, msdu_id, frags_paddr,
 		   (u32)skb_cb->paddr, vdev_id, tid);
-	ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
+	ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
 			msdu->data, msdu->len);
 
 	sg_items[0].transfer_id = 0;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 007e855..3cf5702 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -28,16 +28,21 @@
 #define QCA988X_HW_2_0_CHIP_ID_REV	0x2
 #define QCA988X_HW_2_0_FW_DIR		"ath10k/QCA988X/hw2.0"
 #define QCA988X_HW_2_0_FW_FILE		"firmware.bin"
-#define QCA988X_HW_2_0_FW_2_FILE	"firmware-2.bin"
+#define QCA988X_HW_2_0_FW_3_FILE	"firmware-3.bin"
 #define QCA988X_HW_2_0_OTP_FILE		"otp.bin"
 #define QCA988X_HW_2_0_BOARD_DATA_FILE	"board.bin"
 #define QCA988X_HW_2_0_PATCH_LOAD_ADDR	0x1234
 
 #define ATH10K_FW_API2_FILE		"firmware-2.bin"
+#define ATH10K_FW_API3_FILE		"firmware-3.bin"
+
+#define ATH10K_FW_UTF_FILE		"utf.bin"
 
 /* includes also the null byte */
 #define ATH10K_FIRMWARE_MAGIC               "QCA-ATH10K"
 
+#define REG_DUMP_COUNT_QCA988X 60
+
 struct ath10k_fw_ie {
 	__le32 id;
 	__le32 len;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index f0853d1..d381d5f 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -26,6 +26,7 @@
 #include "wmi.h"
 #include "htt.h"
 #include "txrx.h"
+#include "testmode.h"
 
 /**********/
 /* Crypto */
@@ -36,6 +37,7 @@
 			   enum set_key_cmd cmd,
 			   const u8 *macaddr)
 {
+	struct ath10k *ar = arvif->ar;
 	struct wmi_vdev_install_key_arg arg = {
 		.vdev_id = arvif->vdev_id,
 		.key_idx = key->keyidx,
@@ -73,7 +75,7 @@
 			arg.key_flags = WMI_KEY_PAIRWISE;
 		break;
 	default:
-		ath10k_warn("cipher %d is not supported\n", key->cipher);
+		ath10k_warn(ar, "cipher %d is not supported\n", key->cipher);
 		return -EOPNOTSUPP;
 	}
 
@@ -168,7 +170,7 @@
 			first_errno = ret;
 
 		if (ret)
-			ath10k_warn("failed to remove peer wep key %d: %d\n",
+			ath10k_warn(ar, "failed to remove peer wep key %d: %d\n",
 				    i, ret);
 
 		peer->keys[i] = NULL;
@@ -197,7 +199,7 @@
 		list_for_each_entry(peer, &ar->peers, list) {
 			for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
 				if (peer->keys[i] == key) {
-					memcpy(addr, peer->addr, ETH_ALEN);
+					ether_addr_copy(addr, peer->addr);
 					peer->keys[i] = NULL;
 					break;
 				}
@@ -216,14 +218,13 @@
 			first_errno = ret;
 
 		if (ret)
-			ath10k_warn("failed to remove key for %pM: %d\n",
+			ath10k_warn(ar, "failed to remove key for %pM: %d\n",
 				    addr, ret);
 	}
 
 	return first_errno;
 }
 
-
 /*********************/
 /* General utilities */
 /*********************/
@@ -327,14 +328,14 @@
 
 	ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
 	if (ret) {
-		ath10k_warn("failed to create wmi peer %pM on vdev %i: %i\n",
+		ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
 			    addr, vdev_id, ret);
 		return ret;
 	}
 
 	ret = ath10k_wait_for_peer_created(ar, vdev_id, addr);
 	if (ret) {
-		ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n",
+		ath10k_warn(ar, "failed to wait for created wmi peer %pM on vdev %i: %i\n",
 			    addr, vdev_id, ret);
 		return ret;
 	}
@@ -355,7 +356,7 @@
 	ret = ath10k_wmi_pdev_set_param(ar, param,
 					ATH10K_KICKOUT_THRESHOLD);
 	if (ret) {
-		ath10k_warn("failed to set kickout threshold on vdev %i: %d\n",
+		ath10k_warn(ar, "failed to set kickout threshold on vdev %i: %d\n",
 			    arvif->vdev_id, ret);
 		return ret;
 	}
@@ -364,7 +365,7 @@
 	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
 					ATH10K_KEEPALIVE_MIN_IDLE);
 	if (ret) {
-		ath10k_warn("failed to set keepalive minimum idle time on vdev %i: %d\n",
+		ath10k_warn(ar, "failed to set keepalive minimum idle time on vdev %i: %d\n",
 			    arvif->vdev_id, ret);
 		return ret;
 	}
@@ -373,7 +374,7 @@
 	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
 					ATH10K_KEEPALIVE_MAX_IDLE);
 	if (ret) {
-		ath10k_warn("failed to set keepalive maximum idle time on vdev %i: %d\n",
+		ath10k_warn(ar, "failed to set keepalive maximum idle time on vdev %i: %d\n",
 			    arvif->vdev_id, ret);
 		return ret;
 	}
@@ -382,7 +383,7 @@
 	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
 					ATH10K_KEEPALIVE_MAX_UNRESPONSIVE);
 	if (ret) {
-		ath10k_warn("failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
+		ath10k_warn(ar, "failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
 			    arvif->vdev_id, ret);
 		return ret;
 	}
@@ -449,7 +450,7 @@
 		if (peer->vdev_id != vdev_id)
 			continue;
 
-		ath10k_warn("removing stale peer %pM from vdev_id %d\n",
+		ath10k_warn(ar, "removing stale peer %pM from vdev_id %d\n",
 			    peer->addr, vdev_id);
 
 		list_del(&peer->list);
@@ -492,19 +493,6 @@
 	return 0;
 }
 
-static bool ath10k_monitor_is_enabled(struct ath10k *ar)
-{
-	lockdep_assert_held(&ar->conf_mutex);
-
-	ath10k_dbg(ATH10K_DBG_MAC,
-		   "mac monitor refs: promisc %d monitor %d cac %d\n",
-		   ar->promisc, ar->monitor,
-		   test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags));
-
-	return ar->promisc || ar->monitor ||
-	       test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
-}
-
 static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
 {
 	struct cfg80211_chan_def *chandef = &ar->chandef;
@@ -531,35 +519,35 @@
 
 	ret = ath10k_wmi_vdev_start(ar, &arg);
 	if (ret) {
-		ath10k_warn("failed to request monitor vdev %i start: %d\n",
+		ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n",
 			    vdev_id, ret);
 		return ret;
 	}
 
 	ret = ath10k_vdev_setup_sync(ar);
 	if (ret) {
-		ath10k_warn("failed to synchronize setup for monitor vdev %i: %d\n",
+		ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i: %d\n",
 			    vdev_id, ret);
 		return ret;
 	}
 
 	ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr);
 	if (ret) {
-		ath10k_warn("failed to put up monitor vdev %i: %d\n",
+		ath10k_warn(ar, "failed to put up monitor vdev %i: %d\n",
 			    vdev_id, ret);
 		goto vdev_stop;
 	}
 
 	ar->monitor_vdev_id = vdev_id;
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i started\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i started\n",
 		   ar->monitor_vdev_id);
 	return 0;
 
 vdev_stop:
 	ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
 	if (ret)
-		ath10k_warn("failed to stop monitor vdev %i after start failure: %d\n",
+		ath10k_warn(ar, "failed to stop monitor vdev %i after start failure: %d\n",
 			    ar->monitor_vdev_id, ret);
 
 	return ret;
@@ -573,20 +561,20 @@
 
 	ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id);
 	if (ret)
-		ath10k_warn("failed to put down monitor vdev %i: %d\n",
+		ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n",
 			    ar->monitor_vdev_id, ret);
 
 	ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
 	if (ret)
-		ath10k_warn("failed to to request monitor vdev %i stop: %d\n",
+		ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n",
 			    ar->monitor_vdev_id, ret);
 
 	ret = ath10k_vdev_setup_sync(ar);
 	if (ret)
-		ath10k_warn("failed to synchronise monitor vdev %i: %d\n",
+		ath10k_warn(ar, "failed to synchronise monitor vdev %i: %d\n",
 			    ar->monitor_vdev_id, ret);
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
 		   ar->monitor_vdev_id);
 	return ret;
 }
@@ -597,35 +585,29 @@
 
 	lockdep_assert_held(&ar->conf_mutex);
 
-	bit = ffs(ar->free_vdev_map);
-	if (bit == 0) {
-		ath10k_warn("failed to find free vdev id for monitor vdev\n");
+	if (ar->free_vdev_map == 0) {
+		ath10k_warn(ar, "failed to find free vdev id for monitor vdev\n");
 		return -ENOMEM;
 	}
 
+	bit = ffs(ar->free_vdev_map);
+
 	ar->monitor_vdev_id = bit - 1;
-	ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
 
 	ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id,
 				     WMI_VDEV_TYPE_MONITOR,
 				     0, ar->mac_addr);
 	if (ret) {
-		ath10k_warn("failed to request monitor vdev %i creation: %d\n",
+		ath10k_warn(ar, "failed to request monitor vdev %i creation: %d\n",
 			    ar->monitor_vdev_id, ret);
-		goto vdev_fail;
+		return ret;
 	}
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
+	ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
 		   ar->monitor_vdev_id);
 
 	return 0;
-
-vdev_fail:
-	/*
-	 * Restore the ID to the global map.
-	 */
-	ar->free_vdev_map |= 1 << (ar->monitor_vdev_id);
-	return ret;
 }
 
 static int ath10k_monitor_vdev_delete(struct ath10k *ar)
@@ -636,14 +618,14 @@
 
 	ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id);
 	if (ret) {
-		ath10k_warn("failed to request wmi monitor vdev %i removal: %d\n",
+		ath10k_warn(ar, "failed to request wmi monitor vdev %i removal: %d\n",
 			    ar->monitor_vdev_id, ret);
 		return ret;
 	}
 
-	ar->free_vdev_map |= 1 << (ar->monitor_vdev_id);
+	ar->free_vdev_map |= 1 << ar->monitor_vdev_id;
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
 		   ar->monitor_vdev_id);
 	return ret;
 }
@@ -654,63 +636,70 @@
 
 	lockdep_assert_held(&ar->conf_mutex);
 
-	if (!ath10k_monitor_is_enabled(ar)) {
-		ath10k_warn("trying to start monitor with no references\n");
-		return 0;
-	}
-
-	if (ar->monitor_started) {
-		ath10k_dbg(ATH10K_DBG_MAC, "mac monitor already started\n");
-		return 0;
-	}
-
 	ret = ath10k_monitor_vdev_create(ar);
 	if (ret) {
-		ath10k_warn("failed to create monitor vdev: %d\n", ret);
+		ath10k_warn(ar, "failed to create monitor vdev: %d\n", ret);
 		return ret;
 	}
 
 	ret = ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);
 	if (ret) {
-		ath10k_warn("failed to start monitor vdev: %d\n", ret);
+		ath10k_warn(ar, "failed to start monitor vdev: %d\n", ret);
 		ath10k_monitor_vdev_delete(ar);
 		return ret;
 	}
 
 	ar->monitor_started = true;
-	ath10k_dbg(ATH10K_DBG_MAC, "mac monitor started\n");
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor started\n");
 
 	return 0;
 }
 
-static void ath10k_monitor_stop(struct ath10k *ar)
+static int ath10k_monitor_stop(struct ath10k *ar)
 {
 	int ret;
 
 	lockdep_assert_held(&ar->conf_mutex);
 
-	if (ath10k_monitor_is_enabled(ar)) {
-		ath10k_dbg(ATH10K_DBG_MAC,
-			   "mac monitor will be stopped later\n");
-		return;
-	}
-
-	if (!ar->monitor_started) {
-		ath10k_dbg(ATH10K_DBG_MAC,
-			   "mac monitor probably failed to start earlier\n");
-		return;
-	}
-
 	ret = ath10k_monitor_vdev_stop(ar);
-	if (ret)
-		ath10k_warn("failed to stop monitor vdev: %d\n", ret);
+	if (ret) {
+		ath10k_warn(ar, "failed to stop monitor vdev: %d\n", ret);
+		return ret;
+	}
 
 	ret = ath10k_monitor_vdev_delete(ar);
-	if (ret)
-		ath10k_warn("failed to delete monitor vdev: %d\n", ret);
+	if (ret) {
+		ath10k_warn(ar, "failed to delete monitor vdev: %d\n", ret);
+		return ret;
+	}
 
 	ar->monitor_started = false;
-	ath10k_dbg(ATH10K_DBG_MAC, "mac monitor stopped\n");
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopped\n");
+
+	return 0;
+}
+
+static int ath10k_monitor_recalc(struct ath10k *ar)
+{
+	bool should_start;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	should_start = ar->monitor ||
+		       ar->filter_flags & FIF_PROMISC_IN_BSS ||
+		       test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+
+	ath10k_dbg(ar, ATH10K_DBG_MAC,
+		   "mac monitor recalc started? %d should? %d\n",
+		   ar->monitor_started, should_start);
+
+	if (should_start == ar->monitor_started)
+		return 0;
+
+	if (should_start)
+		return ath10k_monitor_start(ar);
+
+	return ath10k_monitor_stop(ar);
 }
 
 static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
@@ -741,14 +730,14 @@
 
 	set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
 
-	ret = ath10k_monitor_start(ar);
+	ret = ath10k_monitor_recalc(ar);
 	if (ret) {
-		ath10k_warn("failed to start monitor (cac): %d\n", ret);
+		ath10k_warn(ar, "failed to start monitor (cac): %d\n", ret);
 		clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
 		return ret;
 	}
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",
 		   ar->monitor_vdev_id);
 
 	return 0;
@@ -765,7 +754,7 @@
 	clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
 	ath10k_monitor_stop(ar);
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n");
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac finished\n");
 
 	return 0;
 }
@@ -791,12 +780,12 @@
 		 * radiation is not allowed, make this channel DFS_UNAVAILABLE
 		 * by indicating that radar was detected.
 		 */
-		ath10k_warn("failed to start CAC: %d\n", ret);
+		ath10k_warn(ar, "failed to start CAC: %d\n", ret);
 		ieee80211_radar_detected(ar->hw);
 	}
 }
 
-static int ath10k_vdev_start(struct ath10k_vif *arvif)
+static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart)
 {
 	struct ath10k *ar = arvif->ar;
 	struct cfg80211_chan_def *chandef = &ar->chandef;
@@ -833,21 +822,25 @@
 		arg.ssid_len = arvif->vif->bss_conf.ssid_len;
 	}
 
-	ath10k_dbg(ATH10K_DBG_MAC,
+	ath10k_dbg(ar, ATH10K_DBG_MAC,
 		   "mac vdev %d start center_freq %d phymode %s\n",
 		   arg.vdev_id, arg.channel.freq,
 		   ath10k_wmi_phymode_str(arg.channel.mode));
 
-	ret = ath10k_wmi_vdev_start(ar, &arg);
+	if (restart)
+		ret = ath10k_wmi_vdev_restart(ar, &arg);
+	else
+		ret = ath10k_wmi_vdev_start(ar, &arg);
+
 	if (ret) {
-		ath10k_warn("failed to start WMI vdev %i: %d\n",
+		ath10k_warn(ar, "failed to start WMI vdev %i: %d\n",
 			    arg.vdev_id, ret);
 		return ret;
 	}
 
 	ret = ath10k_vdev_setup_sync(ar);
 	if (ret) {
-		ath10k_warn("failed to synchronise setup for vdev %i: %d\n",
+		ath10k_warn(ar, "failed to synchronise setup for vdev %i: %d\n",
 			    arg.vdev_id, ret);
 		return ret;
 	}
@@ -858,6 +851,16 @@
 	return ret;
 }
 
+static int ath10k_vdev_start(struct ath10k_vif *arvif)
+{
+	return ath10k_vdev_start_restart(arvif, false);
+}
+
+static int ath10k_vdev_restart(struct ath10k_vif *arvif)
+{
+	return ath10k_vdev_start_restart(arvif, true);
+}
+
 static int ath10k_vdev_stop(struct ath10k_vif *arvif)
 {
 	struct ath10k *ar = arvif->ar;
@@ -869,14 +872,14 @@
 
 	ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
 	if (ret) {
-		ath10k_warn("failed to stop WMI vdev %i: %d\n",
+		ath10k_warn(ar, "failed to stop WMI vdev %i: %d\n",
 			    arvif->vdev_id, ret);
 		return ret;
 	}
 
 	ret = ath10k_vdev_setup_sync(ar);
 	if (ret) {
-		ath10k_warn("failed to syncronise setup for vdev %i: %d\n",
+		ath10k_warn(ar, "failed to syncronise setup for vdev %i: %d\n",
 			    arvif->vdev_id, ret);
 		return ret;
 	}
@@ -892,8 +895,9 @@
 }
 
 static void ath10k_control_beaconing(struct ath10k_vif *arvif,
-				struct ieee80211_bss_conf *info)
+				     struct ieee80211_bss_conf *info)
 {
+	struct ath10k *ar = arvif->ar;
 	int ret = 0;
 
 	lockdep_assert_held(&arvif->ar->conf_mutex);
@@ -926,12 +930,12 @@
 		return;
 
 	arvif->aid = 0;
-	memcpy(arvif->bssid, info->bssid, ETH_ALEN);
+	ether_addr_copy(arvif->bssid, info->bssid);
 
 	ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
 				 arvif->bssid);
 	if (ret) {
-		ath10k_warn("failed to bring up vdev %d: %i\n",
+		ath10k_warn(ar, "failed to bring up vdev %d: %i\n",
 			    arvif->vdev_id, ret);
 		ath10k_vdev_stop(arvif);
 		return;
@@ -940,13 +944,14 @@
 	arvif->is_started = true;
 	arvif->is_up = true;
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
 }
 
 static void ath10k_control_ibss(struct ath10k_vif *arvif,
 				struct ieee80211_bss_conf *info,
 				const u8 self_peer[ETH_ALEN])
 {
+	struct ath10k *ar = arvif->ar;
 	u32 vdev_param;
 	int ret = 0;
 
@@ -955,7 +960,7 @@
 	if (!info->ibss_joined) {
 		ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer);
 		if (ret)
-			ath10k_warn("failed to delete IBSS self peer %pM for vdev %d: %d\n",
+			ath10k_warn(ar, "failed to delete IBSS self peer %pM for vdev %d: %d\n",
 				    self_peer, arvif->vdev_id, ret);
 
 		if (is_zero_ether_addr(arvif->bssid))
@@ -964,7 +969,7 @@
 		ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
 					 arvif->bssid);
 		if (ret) {
-			ath10k_warn("failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
+			ath10k_warn(ar, "failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
 				    arvif->bssid, arvif->vdev_id, ret);
 			return;
 		}
@@ -976,7 +981,7 @@
 
 	ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer);
 	if (ret) {
-		ath10k_warn("failed to create IBSS self peer %pM for vdev %d: %d\n",
+		ath10k_warn(ar, "failed to create IBSS self peer %pM for vdev %d: %d\n",
 			    self_peer, arvif->vdev_id, ret);
 		return;
 	}
@@ -985,7 +990,7 @@
 	ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param,
 					ATH10K_DEFAULT_ATIM);
 	if (ret)
-		ath10k_warn("failed to set IBSS ATIM for vdev %d: %d\n",
+		ath10k_warn(ar, "failed to set IBSS ATIM for vdev %d: %d\n",
 			    arvif->vdev_id, ret);
 }
 
@@ -1012,7 +1017,7 @@
 		ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
 						  conf->dynamic_ps_timeout);
 		if (ret) {
-			ath10k_warn("failed to set inactivity time for vdev %d: %i\n",
+			ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n",
 				    arvif->vdev_id, ret);
 			return ret;
 		}
@@ -1020,12 +1025,12 @@
 		psmode = WMI_STA_PS_MODE_DISABLED;
 	}
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
 		   arvif->vdev_id, psmode ? "enable" : "disable");
 
 	ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode);
 	if (ret) {
-		ath10k_warn("failed to set PS Mode %d for vdev %d: %d\n",
+		ath10k_warn(ar, "failed to set PS Mode %d for vdev %d: %d\n",
 			    psmode, arvif->vdev_id, ret);
 		return ret;
 	}
@@ -1045,7 +1050,7 @@
 {
 	lockdep_assert_held(&ar->conf_mutex);
 
-	memcpy(arg->addr, sta->addr, ETH_ALEN);
+	ether_addr_copy(arg->addr, sta->addr);
 	arg->vdev_id = arvif->vdev_id;
 	arg->peer_aid = sta->aid;
 	arg->peer_flags |= WMI_PEER_AUTH;
@@ -1100,21 +1105,21 @@
 		ies = rcu_dereference(bss->ies);
 
 		wpaie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
-				WLAN_OUI_TYPE_MICROSOFT_WPA,
-				ies->data,
-				ies->len);
+						WLAN_OUI_TYPE_MICROSOFT_WPA,
+						ies->data,
+						ies->len);
 		rcu_read_unlock();
 		cfg80211_put_bss(ar->hw->wiphy, bss);
 	}
 
 	/* FIXME: base on RSN IE/WPA IE is a correct idea? */
 	if (rsnie || wpaie) {
-		ath10k_dbg(ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
+		ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
 		arg->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
 	}
 
 	if (wpaie) {
-		ath10k_dbg(ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
+		ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
 		arg->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
 	}
 }
@@ -1152,6 +1157,7 @@
 {
 	const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
 	int i, n;
+	u32 stbc;
 
 	lockdep_assert_held(&ar->conf_mutex);
 
@@ -1188,7 +1194,6 @@
 	}
 
 	if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) {
-		u32 stbc;
 		stbc = ht_cap->cap & IEEE80211_HT_CAP_RX_STBC;
 		stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT;
 		stbc = stbc << WMI_RC_RX_STBC_FLAG_S;
@@ -1223,7 +1228,7 @@
 		arg->peer_num_spatial_streams = sta->rx_nss;
 	}
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
 		   arg->addr,
 		   arg->peer_ht_rates.num_rates,
 		   arg->peer_num_spatial_streams);
@@ -1240,7 +1245,7 @@
 	lockdep_assert_held(&ar->conf_mutex);
 
 	if (sta->wme && sta->uapsd_queues) {
-		ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
 			   sta->uapsd_queues, sta->max_sp);
 
 		if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
@@ -1256,7 +1261,6 @@
 			uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN |
 				 WMI_AP_PS_UAPSD_AC0_TRIGGER_EN;
 
-
 		if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)
 			max_sp = sta->max_sp;
 
@@ -1265,7 +1269,7 @@
 						 WMI_AP_PS_PEER_PARAM_UAPSD,
 						 uapsd);
 		if (ret) {
-			ath10k_warn("failed to set ap ps peer param uapsd for vdev %i: %d\n",
+			ath10k_warn(ar, "failed to set ap ps peer param uapsd for vdev %i: %d\n",
 				    arvif->vdev_id, ret);
 			return ret;
 		}
@@ -1275,7 +1279,7 @@
 						 WMI_AP_PS_PEER_PARAM_MAX_SP,
 						 max_sp);
 		if (ret) {
-			ath10k_warn("failed to set ap ps peer param max sp for vdev %i: %d\n",
+			ath10k_warn(ar, "failed to set ap ps peer param max sp for vdev %i: %d\n",
 				    arvif->vdev_id, ret);
 			return ret;
 		}
@@ -1285,9 +1289,10 @@
 		   sta->listen_interval - mac80211 patch required.
 		   Currently use 10 seconds */
 		ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr,
-					WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10);
+						 WMI_AP_PS_PEER_PARAM_AGEOUT_TIME,
+						 10);
 		if (ret) {
-			ath10k_warn("failed to set ap ps peer param ageout time for vdev %i: %d\n",
+			ath10k_warn(ar, "failed to set ap ps peer param ageout time for vdev %i: %d\n",
 				    arvif->vdev_id, ret);
 			return ret;
 		}
@@ -1309,7 +1314,6 @@
 	arg->peer_flags |= WMI_PEER_VHT;
 	arg->peer_vht_caps = vht_cap->cap;
 
-
 	ampdu_factor = (vht_cap->cap &
 			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
 		       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
@@ -1334,7 +1338,7 @@
 	arg->peer_vht_rates.tx_mcs_set =
 		__le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
 		   sta->addr, arg->peer_max_mpdu, arg->peer_flags);
 }
 
@@ -1407,7 +1411,7 @@
 		break;
 	}
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac peer %pM phymode %s\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM phymode %s\n",
 		   sta->addr, ath10k_wmi_phymode_str(phymode));
 
 	arg->peer_phymode = phymode;
@@ -1480,7 +1484,7 @@
 
 	ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
 	if (!ap_sta) {
-		ath10k_warn("failed to find station entry for bss %pM vdev %i\n",
+		ath10k_warn(ar, "failed to find station entry for bss %pM vdev %i\n",
 			    bss_conf->bssid, arvif->vdev_id);
 		rcu_read_unlock();
 		return;
@@ -1493,7 +1497,7 @@
 	ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
 					bss_conf, &peer_arg);
 	if (ret) {
-		ath10k_warn("failed to prepare peer assoc for %pM vdev %i: %d\n",
+		ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n",
 			    bss_conf->bssid, arvif->vdev_id, ret);
 		rcu_read_unlock();
 		return;
@@ -1503,28 +1507,28 @@
 
 	ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
 	if (ret) {
-		ath10k_warn("failed to run peer assoc for %pM vdev %i: %d\n",
+		ath10k_warn(ar, "failed to run peer assoc for %pM vdev %i: %d\n",
 			    bss_conf->bssid, arvif->vdev_id, ret);
 		return;
 	}
 
 	ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap);
 	if (ret) {
-		ath10k_warn("failed to setup peer SMPS for vdev %i: %d\n",
+		ath10k_warn(ar, "failed to setup peer SMPS for vdev %i: %d\n",
 			    arvif->vdev_id, ret);
 		return;
 	}
 
-	ath10k_dbg(ATH10K_DBG_MAC,
+	ath10k_dbg(ar, ATH10K_DBG_MAC,
 		   "mac vdev %d up (associated) bssid %pM aid %d\n",
 		   arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
 
 	arvif->aid = bss_conf->aid;
-	memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN);
+	ether_addr_copy(arvif->bssid, bss_conf->bssid);
 
 	ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
 	if (ret) {
-		ath10k_warn("failed to set vdev %d up: %d\n",
+		ath10k_warn(ar, "failed to set vdev %d up: %d\n",
 			    arvif->vdev_id, ret);
 		return;
 	}
@@ -1550,7 +1554,7 @@
 	 * No idea why this happens, even though VDEV-DOWN is supposed
 	 * to be analogous to link down, so just stop the VDEV.
 	 */
-	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
 		   arvif->vdev_id);
 
 	/* FIXME: check return value */
@@ -1563,7 +1567,7 @@
 	 * interfaces as it expects there is no rx when no interface is
 	 * running.
 	 */
-	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
 
 	/* FIXME: why don't we print error if wmi call fails? */
 	ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
@@ -1584,7 +1588,7 @@
 
 	ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
 	if (ret) {
-		ath10k_warn("failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
+		ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
 			    sta->addr, arvif->vdev_id, ret);
 		return ret;
 	}
@@ -1592,23 +1596,23 @@
 	peer_arg.peer_reassoc = reassoc;
 	ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
 	if (ret) {
-		ath10k_warn("failed to run peer assoc for STA %pM vdev %i: %d\n",
+		ath10k_warn(ar, "failed to run peer assoc for STA %pM vdev %i: %d\n",
 			    sta->addr, arvif->vdev_id, ret);
 		return ret;
 	}
 
 	ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
 	if (ret) {
-		ath10k_warn("failed to setup peer SMPS for vdev %d: %d\n",
+		ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
 			    arvif->vdev_id, ret);
 		return ret;
 	}
 
-	if (!sta->wme) {
+	if (!sta->wme && !reassoc) {
 		arvif->num_legacy_stations++;
 		ret  = ath10k_recalc_rtscts_prot(arvif);
 		if (ret) {
-			ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+			ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
 				    arvif->vdev_id, ret);
 			return ret;
 		}
@@ -1616,14 +1620,14 @@
 
 	ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
 	if (ret) {
-		ath10k_warn("failed to install peer wep keys for vdev %i: %d\n",
+		ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
 			    arvif->vdev_id, ret);
 		return ret;
 	}
 
 	ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
 	if (ret) {
-		ath10k_warn("failed to set qos params for STA %pM for vdev %i: %d\n",
+		ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
 			    sta->addr, arvif->vdev_id, ret);
 		return ret;
 	}
@@ -1642,7 +1646,7 @@
 		arvif->num_legacy_stations--;
 		ret = ath10k_recalc_rtscts_prot(arvif);
 		if (ret) {
-			ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+			ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
 				    arvif->vdev_id, ret);
 			return ret;
 		}
@@ -1650,7 +1654,7 @@
 
 	ret = ath10k_clear_peer_keys(arvif, sta->addr);
 	if (ret) {
-		ath10k_warn("failed to clear all peer wep keys for vdev %i: %d\n",
+		ath10k_warn(ar, "failed to clear all peer wep keys for vdev %i: %d\n",
 			    arvif->vdev_id, ret);
 		return ret;
 	}
@@ -1742,7 +1746,7 @@
 			if (WARN_ON_ONCE(ch->mode == MODE_UNKNOWN))
 				continue;
 
-			ath10k_dbg(ATH10K_DBG_WMI,
+			ath10k_dbg(ar, ATH10K_DBG_WMI,
 				   "mac channel [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n",
 				    ch - arg.channels, arg.n_channels,
 				   ch->freq, ch->max_power, ch->max_reg_power,
@@ -1785,7 +1789,7 @@
 
 	ret = ath10k_update_channel_list(ar);
 	if (ret)
-		ath10k_warn("failed to update channel list: %d\n", ret);
+		ath10k_warn(ar, "failed to update channel list: %d\n", ret);
 
 	regpair = ar->ath_common.regulatory.regpair;
 
@@ -1806,7 +1810,7 @@
 					    regpair->reg_5ghz_ctl,
 					    wmi_dfs_reg);
 	if (ret)
-		ath10k_warn("failed to set pdev regdomain: %d\n", ret);
+		ath10k_warn(ar, "failed to set pdev regdomain: %d\n", ret);
 }
 
 static void ath10k_reg_notifier(struct wiphy *wiphy,
@@ -1819,12 +1823,12 @@
 	ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory);
 
 	if (config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
-		ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
+		ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
 			   request->dfs_region);
 		result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector,
 							  request->dfs_region);
 		if (!result)
-			ath10k_warn("DFS region 0x%X not supported, will trigger radar for every pulse\n",
+			ath10k_warn(ar, "DFS region 0x%X not supported, will trigger radar for every pulse\n",
 				    request->dfs_region);
 	}
 
@@ -1852,16 +1856,15 @@
 	return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
 }
 
-static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar,
-				  struct ieee80211_tx_info *info)
+static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
 {
-	if (info->control.vif)
-		return ath10k_vif_to_arvif(info->control.vif)->vdev_id;
+	if (vif)
+		return ath10k_vif_to_arvif(vif)->vdev_id;
 
 	if (ar->monitor_started)
 		return ar->monitor_vdev_id;
 
-	ath10k_warn("failed to resolve vdev id\n");
+	ath10k_warn(ar, "failed to resolve vdev id\n");
 	return 0;
 }
 
@@ -1897,6 +1900,7 @@
 {
 	struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
 						wep_key_work);
+	struct ath10k *ar = arvif->ar;
 	int ret, keyidx = arvif->def_wep_key_newidx;
 
 	mutex_lock(&arvif->ar->conf_mutex);
@@ -1907,7 +1911,7 @@
 	if (arvif->def_wep_key_idx == keyidx)
 		goto unlock;
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
 		   arvif->vdev_id, keyidx);
 
 	ret = ath10k_wmi_vdev_set_param(arvif->ar,
@@ -1915,7 +1919,7 @@
 					arvif->ar->wmi.vdev_param->def_keyid,
 					keyidx);
 	if (ret) {
-		ath10k_warn("failed to update wep key index for vdev %d: %d\n",
+		ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n",
 			    arvif->vdev_id,
 			    ret);
 		goto unlock;
@@ -1995,7 +1999,7 @@
 			     ar->fw_features)) {
 			if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >=
 			    ATH10K_MAX_NUM_MGMT_PENDING) {
-				ath10k_warn("reached WMI management tranmist queue limit\n");
+				ath10k_warn(ar, "reached WMI management transmit queue limit\n");
 				ret = -EBUSY;
 				goto exit;
 			}
@@ -2019,7 +2023,8 @@
 
 exit:
 	if (ret) {
-		ath10k_warn("failed to transmit packet, dropping: %d\n", ret);
+		ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
+			    ret);
 		ieee80211_free_txskb(ar->hw, skb);
 	}
 }
@@ -2061,7 +2066,7 @@
 
 		mutex_lock(&ar->conf_mutex);
 
-		ath10k_dbg(ATH10K_DBG_MAC, "mac offchannel skb %p\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %p\n",
 			   skb);
 
 		hdr = (struct ieee80211_hdr *)skb->data;
@@ -2074,13 +2079,13 @@
 
 		if (peer)
 			/* FIXME: should this use ath10k_warn()? */
-			ath10k_dbg(ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n",
+			ath10k_dbg(ar, ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n",
 				   peer_addr, vdev_id);
 
 		if (!peer) {
 			ret = ath10k_peer_create(ar, vdev_id, peer_addr);
 			if (ret)
-				ath10k_warn("failed to create peer %pM on vdev %d: %d\n",
+				ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n",
 					    peer_addr, vdev_id, ret);
 		}
 
@@ -2094,13 +2099,13 @@
 		ret = wait_for_completion_timeout(&ar->offchan_tx_completed,
 						  3 * HZ);
 		if (ret <= 0)
-			ath10k_warn("timed out waiting for offchannel skb %p\n",
+			ath10k_warn(ar, "timed out waiting for offchannel skb %p\n",
 				    skb);
 
 		if (!peer) {
 			ret = ath10k_peer_delete(ar, vdev_id, peer_addr);
 			if (ret)
-				ath10k_warn("failed to delete peer %pM on vdev %d: %d\n",
+				ath10k_warn(ar, "failed to delete peer %pM on vdev %d: %d\n",
 					    peer_addr, vdev_id, ret);
 		}
 
@@ -2134,7 +2139,7 @@
 
 		ret = ath10k_wmi_mgmt_tx(ar, skb);
 		if (ret) {
-			ath10k_warn("failed to transmit management frame via WMI: %d\n",
+			ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n",
 				    ret);
 			ieee80211_free_txskb(ar->hw, skb);
 		}
@@ -2145,34 +2150,40 @@
 /* Scanning */
 /************/
 
-/*
- * This gets called if we dont get a heart-beat during scan.
- * This may indicate the FW has hung and we need to abort the
- * scan manually to prevent cancel_hw_scan() from deadlocking
- */
-void ath10k_reset_scan(unsigned long ptr)
+void __ath10k_scan_finish(struct ath10k *ar)
 {
-	struct ath10k *ar = (struct ath10k *)ptr;
+	lockdep_assert_held(&ar->data_lock);
 
-	spin_lock_bh(&ar->data_lock);
-	if (!ar->scan.in_progress) {
-		spin_unlock_bh(&ar->data_lock);
-		return;
+	switch (ar->scan.state) {
+	case ATH10K_SCAN_IDLE:
+		break;
+	case ATH10K_SCAN_RUNNING:
+	case ATH10K_SCAN_ABORTING:
+		if (ar->scan.is_roc)
+			ieee80211_remain_on_channel_expired(ar->hw);
+		else
+			ieee80211_scan_completed(ar->hw,
+						 (ar->scan.state ==
+						  ATH10K_SCAN_ABORTING));
+		/* fall through */
+	case ATH10K_SCAN_STARTING:
+		ar->scan.state = ATH10K_SCAN_IDLE;
+		ar->scan_channel = NULL;
+		ath10k_offchan_tx_purge(ar);
+		cancel_delayed_work(&ar->scan.timeout);
+		complete_all(&ar->scan.completed);
+		break;
 	}
+}
 
-	ath10k_warn("scan timed out, firmware problem?\n");
-
-	if (ar->scan.is_roc)
-		ieee80211_remain_on_channel_expired(ar->hw);
-	else
-		ieee80211_scan_completed(ar->hw, 1 /* aborted */);
-
-	ar->scan.in_progress = false;
-	complete_all(&ar->scan.completed);
+void ath10k_scan_finish(struct ath10k *ar)
+{
+	spin_lock_bh(&ar->data_lock);
+	__ath10k_scan_finish(ar);
 	spin_unlock_bh(&ar->data_lock);
 }
 
-static int ath10k_abort_scan(struct ath10k *ar)
+static int ath10k_scan_stop(struct ath10k *ar)
 {
 	struct wmi_stop_scan_arg arg = {
 		.req_id = 1, /* FIXME */
@@ -2183,49 +2194,81 @@
 
 	lockdep_assert_held(&ar->conf_mutex);
 
-	del_timer_sync(&ar->scan.timeout);
-
-	spin_lock_bh(&ar->data_lock);
-	if (!ar->scan.in_progress) {
-		spin_unlock_bh(&ar->data_lock);
-		return 0;
-	}
-
-	ar->scan.aborting = true;
-	spin_unlock_bh(&ar->data_lock);
-
 	ret = ath10k_wmi_stop_scan(ar, &arg);
 	if (ret) {
-		ath10k_warn("failed to stop wmi scan: %d\n", ret);
-		spin_lock_bh(&ar->data_lock);
-		ar->scan.in_progress = false;
-		ath10k_offchan_tx_purge(ar);
-		spin_unlock_bh(&ar->data_lock);
-		return -EIO;
+		ath10k_warn(ar, "failed to stop wmi scan: %d\n", ret);
+		goto out;
 	}
 
 	ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ);
-	if (ret == 0)
-		ath10k_warn("timed out while waiting for scan to stop\n");
-
-	/* scan completion may be done right after we timeout here, so let's
-	 * check the in_progress and tell mac80211 scan is completed. if we
-	 * don't do that and FW fails to send us scan completion indication
-	 * then userspace won't be able to scan anymore */
-	ret = 0;
-
-	spin_lock_bh(&ar->data_lock);
-	if (ar->scan.in_progress) {
-		ath10k_warn("failed to stop scan, it's still in progress\n");
-		ar->scan.in_progress = false;
-		ath10k_offchan_tx_purge(ar);
+	if (ret == 0) {
+		ath10k_warn(ar, "failed to receive scan abortion completion: timed out\n");
 		ret = -ETIMEDOUT;
+	} else if (ret > 0) {
+		ret = 0;
 	}
+
+out:
+	/* Scan state should be updated upon scan completion but in case
+	 * firmware fails to deliver the event (for whatever reason) it is
+	 * desired to clean up scan state anyway. Firmware may have just
+	 * dropped the scan completion event delivery due to transport pipe
+	 * being overflown with data and/or it can recover on its own before
+	 * next scan request is submitted.
+	 */
+	spin_lock_bh(&ar->data_lock);
+	if (ar->scan.state != ATH10K_SCAN_IDLE)
+		__ath10k_scan_finish(ar);
 	spin_unlock_bh(&ar->data_lock);
 
 	return ret;
 }
 
+static void ath10k_scan_abort(struct ath10k *ar)
+{
+	int ret;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	spin_lock_bh(&ar->data_lock);
+
+	switch (ar->scan.state) {
+	case ATH10K_SCAN_IDLE:
+		/* This can happen if timeout worker kicked in and called
+		 * abortion while scan completion was being processed.
+		 */
+		break;
+	case ATH10K_SCAN_STARTING:
+	case ATH10K_SCAN_ABORTING:
+		ath10k_warn(ar, "refusing scan abortion due to invalid scan state: %s (%d)\n",
+			    ath10k_scan_state_str(ar->scan.state),
+			    ar->scan.state);
+		break;
+	case ATH10K_SCAN_RUNNING:
+		ar->scan.state = ATH10K_SCAN_ABORTING;
+		spin_unlock_bh(&ar->data_lock);
+
+		ret = ath10k_scan_stop(ar);
+		if (ret)
+			ath10k_warn(ar, "failed to abort scan: %d\n", ret);
+
+		spin_lock_bh(&ar->data_lock);
+		break;
+	}
+
+	spin_unlock_bh(&ar->data_lock);
+}
+
+void ath10k_scan_timeout_work(struct work_struct *work)
+{
+	struct ath10k *ar = container_of(work, struct ath10k,
+					 scan.timeout.work);
+
+	mutex_lock(&ar->conf_mutex);
+	ath10k_scan_abort(ar);
+	mutex_unlock(&ar->conf_mutex);
+}
+
 static int ath10k_start_scan(struct ath10k *ar,
 			     const struct wmi_start_scan_arg *arg)
 {
@@ -2239,17 +2282,16 @@
 
 	ret = wait_for_completion_timeout(&ar->scan.started, 1*HZ);
 	if (ret == 0) {
-		ath10k_abort_scan(ar);
-		return ret;
+		ret = ath10k_scan_stop(ar);
+		if (ret)
+			ath10k_warn(ar, "failed to stop scan: %d\n", ret);
+
+		return -ETIMEDOUT;
 	}
 
-	/* the scan can complete earlier, before we even
-	 * start the timer. in that case the timer handler
-	 * checks ar->scan.in_progress and bails out if its
-	 * false. Add a 200ms margin to account event/command
-	 * processing. */
-	mod_timer(&ar->scan.timeout, jiffies +
-		  msecs_to_jiffies(arg->max_scan_time+200));
+	/* Add a 200ms margin to account for event/command processing */
+	ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
+				     msecs_to_jiffies(arg->max_scan_time+200));
 	return 0;
 }
 
@@ -2269,11 +2311,11 @@
 
 	/* We should disable CCK RATE due to P2P */
 	if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
-		ath10k_dbg(ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
 
 	ATH10K_SKB_CB(skb)->htt.is_offchan = false;
 	ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
-	ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, info);
+	ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
 
 	/* it makes no sense to process injected frames like that */
 	if (vif && vif->type != NL80211_IFTYPE_MONITOR) {
@@ -2289,7 +2331,8 @@
 		ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;
 		spin_unlock_bh(&ar->data_lock);
 
-		ath10k_dbg(ATH10K_DBG_MAC, "queued offchannel skb %p\n", skb);
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
+			   skb);
 
 		skb_queue_tail(&ar->offchan_tx_queue, skb);
 		ieee80211_queue_work(hw, &ar->offchan_tx_work);
@@ -2318,15 +2361,16 @@
 
 	lockdep_assert_held(&ar->conf_mutex);
 
-	if (ath10k_monitor_is_enabled(ar)) {
-		clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
-		ar->promisc = false;
-		ar->monitor = false;
-		ath10k_monitor_stop(ar);
-	}
+	clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+	ar->filter_flags = 0;
+	ar->monitor = false;
 
-	del_timer_sync(&ar->scan.timeout);
-	ath10k_reset_scan((unsigned long)ar);
+	if (ar->monitor_started)
+		ath10k_monitor_stop(ar);
+
+	ar->monitor_started = false;
+
+	ath10k_scan_finish(ar);
 	ath10k_peer_cleanup_all(ar);
 	ath10k_core_stop(ar);
 	ath10k_hif_power_down(ar);
@@ -2380,7 +2424,7 @@
 	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->tx_chain_mask,
 					tx_ant);
 	if (ret) {
-		ath10k_warn("failed to set tx-chainmask: %d, req 0x%x\n",
+		ath10k_warn(ar, "failed to set tx-chainmask: %d, req 0x%x\n",
 			    ret, tx_ant);
 		return ret;
 	}
@@ -2388,7 +2432,7 @@
 	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rx_chain_mask,
 					rx_ant);
 	if (ret) {
-		ath10k_warn("failed to set rx-chainmask: %d, req 0x%x\n",
+		ath10k_warn(ar, "failed to set rx-chainmask: %d, req 0x%x\n",
 			    ret, rx_ant);
 		return ret;
 	}
@@ -2435,29 +2479,32 @@
 		WARN_ON(1);
 		ret = -EINVAL;
 		goto err;
+	case ATH10K_STATE_UTF:
+		ret = -EBUSY;
+		goto err;
 	}
 
 	ret = ath10k_hif_power_up(ar);
 	if (ret) {
-		ath10k_err("Could not init hif: %d\n", ret);
+		ath10k_err(ar, "Could not init hif: %d\n", ret);
 		goto err_off;
 	}
 
-	ret = ath10k_core_start(ar);
+	ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
 	if (ret) {
-		ath10k_err("Could not init core: %d\n", ret);
+		ath10k_err(ar, "Could not init core: %d\n", ret);
 		goto err_power_down;
 	}
 
 	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1);
 	if (ret) {
-		ath10k_warn("failed to enable PMF QOS: %d\n", ret);
+		ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret);
 		goto err_core_stop;
 	}
 
 	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1);
 	if (ret) {
-		ath10k_warn("failed to enable dynamic BW: %d\n", ret);
+		ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret);
 		goto err_core_stop;
 	}
 
@@ -2477,7 +2524,7 @@
 	ret = ath10k_wmi_pdev_set_param(ar,
 					ar->wmi.pdev_param->arp_ac_override, 0);
 	if (ret) {
-		ath10k_warn("failed to set arp ac override parameter: %d\n",
+		ath10k_warn(ar, "failed to set arp ac override parameter: %d\n",
 			    ret);
 		goto err_core_stop;
 	}
@@ -2485,6 +2532,8 @@
 	ar->num_started_vdevs = 0;
 	ath10k_regd_update(ar);
 
+	ath10k_spectral_start(ar);
+
 	mutex_unlock(&ar->conf_mutex);
 	return 0;
 
@@ -2515,6 +2564,7 @@
 	}
 	mutex_unlock(&ar->conf_mutex);
 
+	cancel_delayed_work_sync(&ar->scan.timeout);
 	cancel_work_sync(&ar->restart_work);
 }
 
@@ -2528,7 +2578,7 @@
 	list_for_each_entry(arvif, &ar->arvifs, list) {
 		ret = ath10k_mac_vif_setup_ps(arvif);
 		if (ret) {
-			ath10k_warn("failed to setup powersave: %d\n", ret);
+			ath10k_warn(ar, "failed to setup powersave: %d\n", ret);
 			break;
 		}
 	}
@@ -2566,7 +2616,7 @@
 
 	lockdep_assert_held(&ar->conf_mutex);
 
-	ath10k_dbg(ATH10K_DBG_MAC,
+	ath10k_dbg(ar, ATH10K_DBG_MAC,
 		   "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n",
 		   ar->chandef.chan->center_freq,
 		   ar->chandef.center_freq1,
@@ -2576,24 +2626,27 @@
 	/* First stop monitor interface. Some FW versions crash if there's a
 	 * lone monitor interface. */
 	if (ar->monitor_started)
-		ath10k_monitor_vdev_stop(ar);
+		ath10k_monitor_stop(ar);
 
 	list_for_each_entry(arvif, &ar->arvifs, list) {
 		if (!arvif->is_started)
 			continue;
 
+		if (!arvif->is_up)
+			continue;
+
 		if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
 			continue;
 
-		ret = ath10k_vdev_stop(arvif);
+		ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
 		if (ret) {
-			ath10k_warn("failed to stop vdev %d: %d\n",
+			ath10k_warn(ar, "failed to down vdev %d: %d\n",
 				    arvif->vdev_id, ret);
 			continue;
 		}
 	}
 
-	/* all vdevs are now stopped - now attempt to restart them */
+	/* all vdevs are downed now - attempt to restart and re-up them */
 
 	list_for_each_entry(arvif, &ar->arvifs, list) {
 		if (!arvif->is_started)
@@ -2602,9 +2655,9 @@
 		if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
 			continue;
 
-		ret = ath10k_vdev_start(arvif);
+		ret = ath10k_vdev_restart(arvif);
 		if (ret) {
-			ath10k_warn("failed to start vdev %d: %d\n",
+			ath10k_warn(ar, "failed to restart vdev %d: %d\n",
 				    arvif->vdev_id, ret);
 			continue;
 		}
@@ -2615,14 +2668,13 @@
 		ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
 					 arvif->bssid);
 		if (ret) {
-			ath10k_warn("failed to bring vdev up %d: %d\n",
+			ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
 				    arvif->vdev_id, ret);
 			continue;
 		}
 	}
 
-	if (ath10k_monitor_is_enabled(ar))
-		ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);
+	ath10k_monitor_recalc(ar);
 }
 
 static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
@@ -2635,7 +2687,7 @@
 	mutex_lock(&ar->conf_mutex);
 
 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-		ath10k_dbg(ATH10K_DBG_MAC,
+		ath10k_dbg(ar, ATH10K_DBG_MAC,
 			   "mac config channel %dMHz flags 0x%x radar %d\n",
 			   conf->chandef.chan->center_freq,
 			   conf->chandef.chan->flags,
@@ -2655,21 +2707,21 @@
 	}
 
 	if (changed & IEEE80211_CONF_CHANGE_POWER) {
-		ath10k_dbg(ATH10K_DBG_MAC, "mac config power %d\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac config power %d\n",
 			   hw->conf.power_level);
 
 		param = ar->wmi.pdev_param->txpower_limit2g;
 		ret = ath10k_wmi_pdev_set_param(ar, param,
 						hw->conf.power_level * 2);
 		if (ret)
-			ath10k_warn("failed to set 2g txpower %d: %d\n",
+			ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
 				    hw->conf.power_level, ret);
 
 		param = ar->wmi.pdev_param->txpower_limit5g;
 		ret = ath10k_wmi_pdev_set_param(ar, param,
 						hw->conf.power_level * 2);
 		if (ret)
-			ath10k_warn("failed to set 5g txpower %d: %d\n",
+			ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
 				    hw->conf.power_level, ret);
 	}
 
@@ -2677,19 +2729,10 @@
 		ath10k_config_ps(ar);
 
 	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
-		if (conf->flags & IEEE80211_CONF_MONITOR && !ar->monitor) {
-			ar->monitor = true;
-			ret = ath10k_monitor_start(ar);
-			if (ret) {
-				ath10k_warn("failed to start monitor (config): %d\n",
-					    ret);
-				ar->monitor = false;
-			}
-		} else if (!(conf->flags & IEEE80211_CONF_MONITOR) &&
-			   ar->monitor) {
-			ar->monitor = false;
-			ath10k_monitor_stop(ar);
-		}
+		ar->monitor = conf->flags & IEEE80211_CONF_MONITOR;
+		ret = ath10k_monitor_recalc(ar);
+		if (ret)
+			ath10k_warn(ar, "failed to recalc monitor: %d\n", ret);
 	}
 
 	mutex_unlock(&ar->conf_mutex);
@@ -2724,11 +2767,12 @@
 	INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work);
 	INIT_LIST_HEAD(&arvif->list);
 
-	bit = ffs(ar->free_vdev_map);
-	if (bit == 0) {
+	if (ar->free_vdev_map == 0) {
+		ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n");
 		ret = -EBUSY;
 		goto err;
 	}
+	bit = ffs(ar->free_vdev_map);
 
 	arvif->vdev_id = bit - 1;
 	arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
@@ -2760,25 +2804,25 @@
 		break;
 	}
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
 		   arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype);
 
 	ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
 				     arvif->vdev_subtype, vif->addr);
 	if (ret) {
-		ath10k_warn("failed to create WMI vdev %i: %d\n",
+		ath10k_warn(ar, "failed to create WMI vdev %i: %d\n",
 			    arvif->vdev_id, ret);
 		goto err;
 	}
 
-	ar->free_vdev_map &= ~BIT(arvif->vdev_id);
+	ar->free_vdev_map &= ~(1 << arvif->vdev_id);
 	list_add(&arvif->list, &ar->arvifs);
 
 	vdev_param = ar->wmi.vdev_param->def_keyid;
 	ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
 					arvif->def_wep_key_idx);
 	if (ret) {
-		ath10k_warn("failed to set vdev %i default key id: %d\n",
+		ath10k_warn(ar, "failed to set vdev %i default key id: %d\n",
 			    arvif->vdev_id, ret);
 		goto err_vdev_delete;
 	}
@@ -2788,7 +2832,7 @@
 					ATH10K_HW_TXRX_NATIVE_WIFI);
 	/* 10.X firmware does not support this VDEV parameter. Do not warn */
 	if (ret && ret != -EOPNOTSUPP) {
-		ath10k_warn("failed to set vdev %i TX encapsulation: %d\n",
+		ath10k_warn(ar, "failed to set vdev %i TX encapsulation: %d\n",
 			    arvif->vdev_id, ret);
 		goto err_vdev_delete;
 	}
@@ -2796,14 +2840,14 @@
 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
 		ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
 		if (ret) {
-			ath10k_warn("failed to create vdev %i peer for AP: %d\n",
+			ath10k_warn(ar, "failed to create vdev %i peer for AP: %d\n",
 				    arvif->vdev_id, ret);
 			goto err_vdev_delete;
 		}
 
 		ret = ath10k_mac_set_kickout(arvif);
 		if (ret) {
-			ath10k_warn("failed to set vdev %i kickout parameters: %d\n",
+			ath10k_warn(ar, "failed to set vdev %i kickout parameters: %d\n",
 				    arvif->vdev_id, ret);
 			goto err_peer_delete;
 		}
@@ -2815,7 +2859,7 @@
 		ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
 						  param, value);
 		if (ret) {
-			ath10k_warn("failed to set vdev %i RX wake policy: %d\n",
+			ath10k_warn(ar, "failed to set vdev %i RX wake policy: %d\n",
 				    arvif->vdev_id, ret);
 			goto err_peer_delete;
 		}
@@ -2825,7 +2869,7 @@
 		ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
 						  param, value);
 		if (ret) {
-			ath10k_warn("failed to set vdev %i TX wake thresh: %d\n",
+			ath10k_warn(ar, "failed to set vdev %i TX wake thresh: %d\n",
 				    arvif->vdev_id, ret);
 			goto err_peer_delete;
 		}
@@ -2835,7 +2879,7 @@
 		ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
 						  param, value);
 		if (ret) {
-			ath10k_warn("failed to set vdev %i PSPOLL count: %d\n",
+			ath10k_warn(ar, "failed to set vdev %i PSPOLL count: %d\n",
 				    arvif->vdev_id, ret);
 			goto err_peer_delete;
 		}
@@ -2843,14 +2887,14 @@
 
 	ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold);
 	if (ret) {
-		ath10k_warn("failed to set rts threshold for vdev %d: %d\n",
+		ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n",
 			    arvif->vdev_id, ret);
 		goto err_peer_delete;
 	}
 
 	ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold);
 	if (ret) {
-		ath10k_warn("failed to set frag threshold for vdev %d: %d\n",
+		ath10k_warn(ar, "failed to set frag threshold for vdev %d: %d\n",
 			    arvif->vdev_id, ret);
 		goto err_peer_delete;
 	}
@@ -2864,7 +2908,7 @@
 
 err_vdev_delete:
 	ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
-	ar->free_vdev_map &= ~BIT(arvif->vdev_id);
+	ar->free_vdev_map |= 1 << arvif->vdev_id;
 	list_del(&arvif->list);
 
 err:
@@ -2892,26 +2936,32 @@
 		dev_kfree_skb_any(arvif->beacon);
 		arvif->beacon = NULL;
 	}
+
 	spin_unlock_bh(&ar->data_lock);
 
-	ar->free_vdev_map |= 1 << (arvif->vdev_id);
+	ret = ath10k_spectral_vif_stop(arvif);
+	if (ret)
+		ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n",
+			    arvif->vdev_id, ret);
+
+	ar->free_vdev_map |= 1 << arvif->vdev_id;
 	list_del(&arvif->list);
 
 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
 		ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr);
 		if (ret)
-			ath10k_warn("failed to remove peer for AP vdev %i: %d\n",
+			ath10k_warn(ar, "failed to remove peer for AP vdev %i: %d\n",
 				    arvif->vdev_id, ret);
 
 		kfree(arvif->u.ap.noa_data);
 	}
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n",
 		   arvif->vdev_id);
 
 	ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
 	if (ret)
-		ath10k_warn("failed to delete WMI vdev %i: %d\n",
+		ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n",
 			    arvif->vdev_id, ret);
 
 	ath10k_peer_cleanup(ar, arvif->vdev_id);
@@ -2946,18 +2996,9 @@
 	*total_flags &= SUPPORTED_FILTERS;
 	ar->filter_flags = *total_flags;
 
-	if (ar->filter_flags & FIF_PROMISC_IN_BSS && !ar->promisc) {
-		ar->promisc = true;
-		ret = ath10k_monitor_start(ar);
-		if (ret) {
-			ath10k_warn("failed to start monitor (promisc): %d\n",
-				    ret);
-			ar->promisc = false;
-		}
-	} else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && ar->promisc) {
-		ar->promisc = false;
-		ath10k_monitor_stop(ar);
-	}
+	ret = ath10k_monitor_recalc(ar);
+	if (ret)
+		ath10k_warn(ar, "failed to recalc montior: %d\n", ret);
 
 	mutex_unlock(&ar->conf_mutex);
 }
@@ -2970,7 +3011,7 @@
 	struct ath10k *ar = hw->priv;
 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 	int ret = 0;
-	u32 vdev_param, pdev_param;
+	u32 vdev_param, pdev_param, slottime, preamble;
 
 	mutex_lock(&ar->conf_mutex);
 
@@ -2982,17 +3023,17 @@
 		vdev_param = ar->wmi.vdev_param->beacon_interval;
 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
 						arvif->beacon_interval);
-		ath10k_dbg(ATH10K_DBG_MAC,
+		ath10k_dbg(ar, ATH10K_DBG_MAC,
 			   "mac vdev %d beacon_interval %d\n",
 			   arvif->vdev_id, arvif->beacon_interval);
 
 		if (ret)
-			ath10k_warn("failed to set beacon interval for vdev %d: %i\n",
+			ath10k_warn(ar, "failed to set beacon interval for vdev %d: %i\n",
 				    arvif->vdev_id, ret);
 	}
 
 	if (changed & BSS_CHANGED_BEACON) {
-		ath10k_dbg(ATH10K_DBG_MAC,
+		ath10k_dbg(ar, ATH10K_DBG_MAC,
 			   "vdev %d set beacon tx mode to staggered\n",
 			   arvif->vdev_id);
 
@@ -3000,14 +3041,14 @@
 		ret = ath10k_wmi_pdev_set_param(ar, pdev_param,
 						WMI_BEACON_STAGGERED_MODE);
 		if (ret)
-			ath10k_warn("failed to set beacon mode for vdev %d: %i\n",
+			ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n",
 				    arvif->vdev_id, ret);
 	}
 
 	if (changed & BSS_CHANGED_BEACON_INFO) {
 		arvif->dtim_period = info->dtim_period;
 
-		ath10k_dbg(ATH10K_DBG_MAC,
+		ath10k_dbg(ar, ATH10K_DBG_MAC,
 			   "mac vdev %d dtim_period %d\n",
 			   arvif->vdev_id, arvif->dtim_period);
 
@@ -3015,7 +3056,7 @@
 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
 						arvif->dtim_period);
 		if (ret)
-			ath10k_warn("failed to set dtim period for vdev %d: %i\n",
+			ath10k_warn(ar, "failed to set dtim period for vdev %d: %i\n",
 				    arvif->vdev_id, ret);
 	}
 
@@ -3034,14 +3075,14 @@
 	if (changed & BSS_CHANGED_BSSID &&
 	    vif->type != NL80211_IFTYPE_AP) {
 		if (!is_zero_ether_addr(info->bssid)) {
-			ath10k_dbg(ATH10K_DBG_MAC,
+			ath10k_dbg(ar, ATH10K_DBG_MAC,
 				   "mac vdev %d create peer %pM\n",
 				   arvif->vdev_id, info->bssid);
 
 			ret = ath10k_peer_create(ar, arvif->vdev_id,
 						 info->bssid);
 			if (ret)
-				ath10k_warn("failed to add peer %pM for vdev %d when changing bssid: %i\n",
+				ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n",
 					    info->bssid, arvif->vdev_id, ret);
 
 			if (vif->type == NL80211_IFTYPE_STATION) {
@@ -3049,15 +3090,15 @@
 				 * this is never erased as we it for crypto key
 				 * clearing; this is FW requirement
 				 */
-				memcpy(arvif->bssid, info->bssid, ETH_ALEN);
+				ether_addr_copy(arvif->bssid, info->bssid);
 
-				ath10k_dbg(ATH10K_DBG_MAC,
+				ath10k_dbg(ar, ATH10K_DBG_MAC,
 					   "mac vdev %d start %pM\n",
 					   arvif->vdev_id, info->bssid);
 
 				ret = ath10k_vdev_start(arvif);
 				if (ret) {
-					ath10k_warn("failed to start vdev %i: %d\n",
+					ath10k_warn(ar, "failed to start vdev %i: %d\n",
 						    arvif->vdev_id, ret);
 					goto exit;
 				}
@@ -3081,42 +3122,40 @@
 
 	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
 		arvif->use_cts_prot = info->use_cts_prot;
-		ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
 			   arvif->vdev_id, info->use_cts_prot);
 
 		ret = ath10k_recalc_rtscts_prot(arvif);
 		if (ret)
-			ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+			ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
 				    arvif->vdev_id, ret);
 	}
 
 	if (changed & BSS_CHANGED_ERP_SLOT) {
-		u32 slottime;
 		if (info->use_short_slot)
 			slottime = WMI_VDEV_SLOT_TIME_SHORT; /* 9us */
 
 		else
 			slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */
 
-		ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
 			   arvif->vdev_id, slottime);
 
 		vdev_param = ar->wmi.vdev_param->slot_time;
 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
 						slottime);
 		if (ret)
-			ath10k_warn("failed to set erp slot for vdev %d: %i\n",
+			ath10k_warn(ar, "failed to set erp slot for vdev %d: %i\n",
 				    arvif->vdev_id, ret);
 	}
 
 	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
-		u32 preamble;
 		if (info->use_short_preamble)
 			preamble = WMI_VDEV_PREAMBLE_SHORT;
 		else
 			preamble = WMI_VDEV_PREAMBLE_LONG;
 
-		ath10k_dbg(ATH10K_DBG_MAC,
+		ath10k_dbg(ar, ATH10K_DBG_MAC,
 			   "mac vdev %d preamble %dn",
 			   arvif->vdev_id, preamble);
 
@@ -3124,13 +3163,21 @@
 		ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
 						preamble);
 		if (ret)
-			ath10k_warn("failed to set preamble for vdev %d: %i\n",
+			ath10k_warn(ar, "failed to set preamble for vdev %d: %i\n",
 				    arvif->vdev_id, ret);
 	}
 
 	if (changed & BSS_CHANGED_ASSOC) {
-		if (info->assoc)
+		if (info->assoc) {
+			/* Workaround: Make sure monitor vdev is not running
+			 * when associating to prevent some firmware revisions
+			 * (e.g. 10.1 and 10.2) from crashing.
+			 */
+			if (ar->monitor_started)
+				ath10k_monitor_stop(ar);
 			ath10k_bss_assoc(hw, vif, info);
+			ath10k_monitor_recalc(ar);
+		}
 	}
 
 exit:
@@ -3151,20 +3198,26 @@
 	mutex_lock(&ar->conf_mutex);
 
 	spin_lock_bh(&ar->data_lock);
-	if (ar->scan.in_progress) {
-		spin_unlock_bh(&ar->data_lock);
+	switch (ar->scan.state) {
+	case ATH10K_SCAN_IDLE:
+		reinit_completion(&ar->scan.started);
+		reinit_completion(&ar->scan.completed);
+		ar->scan.state = ATH10K_SCAN_STARTING;
+		ar->scan.is_roc = false;
+		ar->scan.vdev_id = arvif->vdev_id;
+		ret = 0;
+		break;
+	case ATH10K_SCAN_STARTING:
+	case ATH10K_SCAN_RUNNING:
+	case ATH10K_SCAN_ABORTING:
 		ret = -EBUSY;
-		goto exit;
+		break;
 	}
-
-	reinit_completion(&ar->scan.started);
-	reinit_completion(&ar->scan.completed);
-	ar->scan.in_progress = true;
-	ar->scan.aborting = false;
-	ar->scan.is_roc = false;
-	ar->scan.vdev_id = arvif->vdev_id;
 	spin_unlock_bh(&ar->data_lock);
 
+	if (ret)
+		goto exit;
+
 	memset(&arg, 0, sizeof(arg));
 	ath10k_wmi_start_scan_init(ar, &arg);
 	arg.vdev_id = arvif->vdev_id;
@@ -3196,9 +3249,9 @@
 
 	ret = ath10k_start_scan(ar, &arg);
 	if (ret) {
-		ath10k_warn("failed to start hw scan: %d\n", ret);
+		ath10k_warn(ar, "failed to start hw scan: %d\n", ret);
 		spin_lock_bh(&ar->data_lock);
-		ar->scan.in_progress = false;
+		ar->scan.state = ATH10K_SCAN_IDLE;
 		spin_unlock_bh(&ar->data_lock);
 	}
 
@@ -3211,14 +3264,10 @@
 				  struct ieee80211_vif *vif)
 {
 	struct ath10k *ar = hw->priv;
-	int ret;
 
 	mutex_lock(&ar->conf_mutex);
-	ret = ath10k_abort_scan(ar);
-	if (ret) {
-		ath10k_warn("failed to abort scan: %d\n", ret);
-		ieee80211_scan_completed(hw, 1 /* aborted */);
-	}
+	cancel_delayed_work_sync(&ar->scan.timeout);
+	ath10k_scan_abort(ar);
 	mutex_unlock(&ar->conf_mutex);
 }
 
@@ -3256,7 +3305,7 @@
 	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
 					key->keyidx);
 	if (ret)
-		ath10k_warn("failed to set vdev %i group key as default key: %d\n",
+		ath10k_warn(ar, "failed to set vdev %i group key as default key: %d\n",
 			    arvif->vdev_id, ret);
 }
 
@@ -3294,7 +3343,7 @@
 
 	if (!peer) {
 		if (cmd == SET_KEY) {
-			ath10k_warn("failed to install key for non-existent peer %pM\n",
+			ath10k_warn(ar, "failed to install key for non-existent peer %pM\n",
 				    peer_addr);
 			ret = -EOPNOTSUPP;
 			goto exit;
@@ -3317,7 +3366,7 @@
 
 	ret = ath10k_install_key(arvif, key, cmd, peer_addr);
 	if (ret) {
-		ath10k_warn("failed to install key for vdev %i peer %pM: %d\n",
+		ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n",
 			    arvif->vdev_id, peer_addr, ret);
 		goto exit;
 	}
@@ -3332,7 +3381,7 @@
 		peer->keys[key->keyidx] = NULL;
 	else if (peer == NULL)
 		/* impossible unless FW goes crazy */
-		ath10k_warn("Peer %pM disappeared!\n", peer_addr);
+		ath10k_warn(ar, "Peer %pM disappeared!\n", peer_addr);
 	spin_unlock_bh(&ar->data_lock);
 
 exit:
@@ -3368,45 +3417,45 @@
 	mutex_lock(&ar->conf_mutex);
 
 	if (changed & IEEE80211_RC_BW_CHANGED) {
-		ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
 			   sta->addr, bw);
 
 		err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
 						WMI_PEER_CHAN_WIDTH, bw);
 		if (err)
-			ath10k_warn("failed to update STA %pM peer bw %d: %d\n",
+			ath10k_warn(ar, "failed to update STA %pM peer bw %d: %d\n",
 				    sta->addr, bw, err);
 	}
 
 	if (changed & IEEE80211_RC_NSS_CHANGED) {
-		ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
 			   sta->addr, nss);
 
 		err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
 						WMI_PEER_NSS, nss);
 		if (err)
-			ath10k_warn("failed to update STA %pM nss %d: %d\n",
+			ath10k_warn(ar, "failed to update STA %pM nss %d: %d\n",
 				    sta->addr, nss, err);
 	}
 
 	if (changed & IEEE80211_RC_SMPS_CHANGED) {
-		ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
 			   sta->addr, smps);
 
 		err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
 						WMI_PEER_SMPS_STATE, smps);
 		if (err)
-			ath10k_warn("failed to update STA %pM smps %d: %d\n",
+			ath10k_warn(ar, "failed to update STA %pM smps %d: %d\n",
 				    sta->addr, smps, err);
 	}
 
 	if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
-		ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
 			   sta->addr);
 
 		err = ath10k_station_assoc(ar, arvif, sta, true);
 		if (err)
-			ath10k_warn("failed to reassociate station: %pM\n",
+			ath10k_warn(ar, "failed to reassociate station: %pM\n",
 				    sta->addr);
 	}
 
@@ -3451,31 +3500,31 @@
 			max_num_peers = TARGET_NUM_PEERS;
 
 		if (ar->num_peers >= max_num_peers) {
-			ath10k_warn("number of peers exceeded: peers number %d (max peers %d)\n",
+			ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n",
 				    ar->num_peers, max_num_peers);
 			ret = -ENOBUFS;
 			goto exit;
 		}
 
-		ath10k_dbg(ATH10K_DBG_MAC,
+		ath10k_dbg(ar, ATH10K_DBG_MAC,
 			   "mac vdev %d peer create %pM (new sta) num_peers %d\n",
 			   arvif->vdev_id, sta->addr, ar->num_peers);
 
 		ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
 		if (ret)
-			ath10k_warn("failed to add peer %pM for vdev %d when adding a new sta: %i\n",
+			ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
 	} else if ((old_state == IEEE80211_STA_NONE &&
 		    new_state == IEEE80211_STA_NOTEXIST)) {
 		/*
 		 * Existing station deletion.
 		 */
-		ath10k_dbg(ATH10K_DBG_MAC,
+		ath10k_dbg(ar, ATH10K_DBG_MAC,
 			   "mac vdev %d peer delete %pM (sta gone)\n",
 			   arvif->vdev_id, sta->addr);
 		ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
 		if (ret)
-			ath10k_warn("failed to delete peer %pM for vdev %d: %i\n",
+			ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
 
 		if (vif->type == NL80211_IFTYPE_STATION)
@@ -3487,12 +3536,12 @@
 		/*
 		 * New association.
 		 */
-		ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM associated\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n",
 			   sta->addr);
 
 		ret = ath10k_station_assoc(ar, arvif, sta, false);
 		if (ret)
-			ath10k_warn("failed to associate station %pM for vdev %i: %i\n",
+			ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
 	} else if (old_state == IEEE80211_STA_ASSOC &&
 		   new_state == IEEE80211_STA_AUTH &&
@@ -3501,12 +3550,12 @@
 		/*
 		 * Disassociation.
 		 */
-		ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
 			   sta->addr);
 
 		ret = ath10k_station_disassoc(ar, arvif, sta);
 		if (ret)
-			ath10k_warn("failed to disassociate station: %pM vdev %i: %i\n",
+			ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n",
 				    sta->addr, arvif->vdev_id, ret);
 	}
 exit:
@@ -3515,7 +3564,7 @@
 }
 
 static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
-				 u16 ac, bool enable)
+				u16 ac, bool enable)
 {
 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 	u32 value = 0;
@@ -3554,7 +3603,7 @@
 					  WMI_STA_PS_PARAM_UAPSD,
 					  arvif->u.sta.uapsd);
 	if (ret) {
-		ath10k_warn("failed to set uapsd params: %d\n", ret);
+		ath10k_warn(ar, "failed to set uapsd params: %d\n", ret);
 		goto exit;
 	}
 
@@ -3567,7 +3616,7 @@
 					  WMI_STA_PS_PARAM_RX_WAKE_POLICY,
 					  value);
 	if (ret)
-		ath10k_warn("failed to set rx wake param: %d\n", ret);
+		ath10k_warn(ar, "failed to set rx wake param: %d\n", ret);
 
 exit:
 	return ret;
@@ -3617,13 +3666,13 @@
 	/* FIXME: FW accepts wmm params per hw, not per vif */
 	ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params);
 	if (ret) {
-		ath10k_warn("failed to set wmm params: %d\n", ret);
+		ath10k_warn(ar, "failed to set wmm params: %d\n", ret);
 		goto exit;
 	}
 
 	ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
 	if (ret)
-		ath10k_warn("failed to set sta uapsd: %d\n", ret);
+		ath10k_warn(ar, "failed to set sta uapsd: %d\n", ret);
 
 exit:
 	mutex_unlock(&ar->conf_mutex);
@@ -3641,27 +3690,33 @@
 	struct ath10k *ar = hw->priv;
 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 	struct wmi_start_scan_arg arg;
-	int ret;
+	int ret = 0;
 
 	mutex_lock(&ar->conf_mutex);
 
 	spin_lock_bh(&ar->data_lock);
-	if (ar->scan.in_progress) {
-		spin_unlock_bh(&ar->data_lock);
+	switch (ar->scan.state) {
+	case ATH10K_SCAN_IDLE:
+		reinit_completion(&ar->scan.started);
+		reinit_completion(&ar->scan.completed);
+		reinit_completion(&ar->scan.on_channel);
+		ar->scan.state = ATH10K_SCAN_STARTING;
+		ar->scan.is_roc = true;
+		ar->scan.vdev_id = arvif->vdev_id;
+		ar->scan.roc_freq = chan->center_freq;
+		ret = 0;
+		break;
+	case ATH10K_SCAN_STARTING:
+	case ATH10K_SCAN_RUNNING:
+	case ATH10K_SCAN_ABORTING:
 		ret = -EBUSY;
-		goto exit;
+		break;
 	}
-
-	reinit_completion(&ar->scan.started);
-	reinit_completion(&ar->scan.completed);
-	reinit_completion(&ar->scan.on_channel);
-	ar->scan.in_progress = true;
-	ar->scan.aborting = false;
-	ar->scan.is_roc = true;
-	ar->scan.vdev_id = arvif->vdev_id;
-	ar->scan.roc_freq = chan->center_freq;
 	spin_unlock_bh(&ar->data_lock);
 
+	if (ret)
+		goto exit;
+
 	memset(&arg, 0, sizeof(arg));
 	ath10k_wmi_start_scan_init(ar, &arg);
 	arg.vdev_id = arvif->vdev_id;
@@ -3676,17 +3731,21 @@
 
 	ret = ath10k_start_scan(ar, &arg);
 	if (ret) {
-		ath10k_warn("failed to start roc scan: %d\n", ret);
+		ath10k_warn(ar, "failed to start roc scan: %d\n", ret);
 		spin_lock_bh(&ar->data_lock);
-		ar->scan.in_progress = false;
+		ar->scan.state = ATH10K_SCAN_IDLE;
 		spin_unlock_bh(&ar->data_lock);
 		goto exit;
 	}
 
 	ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ);
 	if (ret == 0) {
-		ath10k_warn("failed to switch to channel for roc scan\n");
-		ath10k_abort_scan(ar);
+		ath10k_warn(ar, "failed to switch to channel for roc scan\n");
+
+		ret = ath10k_scan_stop(ar);
+		if (ret)
+			ath10k_warn(ar, "failed to stop scan: %d\n", ret);
+
 		ret = -ETIMEDOUT;
 		goto exit;
 	}
@@ -3702,7 +3761,8 @@
 	struct ath10k *ar = hw->priv;
 
 	mutex_lock(&ar->conf_mutex);
-	ath10k_abort_scan(ar);
+	cancel_delayed_work_sync(&ar->scan.timeout);
+	ath10k_scan_abort(ar);
 	mutex_unlock(&ar->conf_mutex);
 
 	return 0;
@@ -3721,12 +3781,12 @@
 
 	mutex_lock(&ar->conf_mutex);
 	list_for_each_entry(arvif, &ar->arvifs, list) {
-		ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
 			   arvif->vdev_id, value);
 
 		ret = ath10k_mac_set_rts(arvif, value);
 		if (ret) {
-			ath10k_warn("failed to set rts threshold for vdev %d: %d\n",
+			ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n",
 				    arvif->vdev_id, ret);
 			break;
 		}
@@ -3744,12 +3804,12 @@
 
 	mutex_lock(&ar->conf_mutex);
 	list_for_each_entry(arvif, &ar->arvifs, list) {
-		ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
 			   arvif->vdev_id, value);
 
 		ret = ath10k_mac_set_rts(arvif, value);
 		if (ret) {
-			ath10k_warn("failed to set fragmentation threshold for vdev %d: %d\n",
+			ath10k_warn(ar, "failed to set fragmentation threshold for vdev %d: %d\n",
 				    arvif->vdev_id, ret);
 			break;
 		}
@@ -3789,7 +3849,7 @@
 		}), ATH10K_FLUSH_TIMEOUT_HZ);
 
 	if (ret <= 0 || skip)
-		ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n",
+		ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %i\n",
 			    skip, ar->state, ret);
 
 skip:
@@ -3824,7 +3884,7 @@
 
 	ret = ath10k_hif_suspend(ar);
 	if (ret) {
-		ath10k_warn("failed to suspend hif: %d\n", ret);
+		ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
 		goto resume;
 	}
 
@@ -3833,7 +3893,7 @@
 resume:
 	ret = ath10k_wmi_pdev_resume_target(ar);
 	if (ret)
-		ath10k_warn("failed to resume target: %d\n", ret);
+		ath10k_warn(ar, "failed to resume target: %d\n", ret);
 
 	ret = 1;
 exit:
@@ -3850,14 +3910,14 @@
 
 	ret = ath10k_hif_resume(ar);
 	if (ret) {
-		ath10k_warn("failed to resume hif: %d\n", ret);
+		ath10k_warn(ar, "failed to resume hif: %d\n", ret);
 		ret = 1;
 		goto exit;
 	}
 
 	ret = ath10k_wmi_pdev_resume_target(ar);
 	if (ret) {
-		ath10k_warn("failed to resume target: %d\n", ret);
+		ath10k_warn(ar, "failed to resume target: %d\n", ret);
 		ret = 1;
 		goto exit;
 	}
@@ -3878,7 +3938,7 @@
 	/* If device failed to restart it will be in a different state, e.g.
 	 * ATH10K_STATE_WEDGED */
 	if (ar->state == ATH10K_STATE_RESTARTED) {
-		ath10k_info("device successfully recovered\n");
+		ath10k_info(ar, "device successfully recovered\n");
 		ar->state = ATH10K_STATE_ON;
 	}
 
@@ -4005,8 +4065,8 @@
 			continue;
 		else if (mask->control[band].ht_mcs[i] == 0x00)
 			break;
-		else
-			return false;
+
+		return false;
 	}
 
 	ht_nss = i;
@@ -4017,8 +4077,8 @@
 			continue;
 		else if (mask->control[band].vht_mcs[i] == 0x0000)
 			break;
-		else
-			return false;
+
+		return false;
 	}
 
 	vht_nss = i;
@@ -4075,7 +4135,8 @@
 }
 
 static bool
-ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
+ath10k_bitrate_mask_rate(struct ath10k *ar,
+			 const struct cfg80211_bitrate_mask *mask,
 			 enum ieee80211_band band,
 			 u8 *fixed_rate,
 			 u8 *fixed_nss)
@@ -4133,7 +4194,7 @@
 	nss <<= 4;
 	pream <<= 6;
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
 		   pream, nss, rate);
 
 	*fixed_rate = pream | nss | rate;
@@ -4141,7 +4202,8 @@
 	return true;
 }
 
-static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask,
+static bool ath10k_get_fixed_rate_nss(struct ath10k *ar,
+				      const struct cfg80211_bitrate_mask *mask,
 				      enum ieee80211_band band,
 				      u8 *fixed_rate,
 				      u8 *fixed_nss)
@@ -4151,7 +4213,7 @@
 		return true;
 
 	/* Next Check single rate is set */
-	return ath10k_bitrate_mask_rate(mask, band, fixed_rate, fixed_nss);
+	return ath10k_bitrate_mask_rate(ar, mask, band, fixed_rate, fixed_nss);
 }
 
 static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
@@ -4171,16 +4233,16 @@
 		goto exit;
 
 	if (fixed_rate == WMI_FIXED_RATE_NONE)
-		ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
 
 	if (force_sgi)
-		ath10k_dbg(ATH10K_DBG_MAC, "mac force sgi\n");
+		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac force sgi\n");
 
 	vdev_param = ar->wmi.vdev_param->fixed_rate;
 	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
 					vdev_param, fixed_rate);
 	if (ret) {
-		ath10k_warn("failed to set fixed rate param 0x%02x: %d\n",
+		ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n",
 			    fixed_rate, ret);
 		ret = -EINVAL;
 		goto exit;
@@ -4193,7 +4255,7 @@
 					vdev_param, fixed_nss);
 
 	if (ret) {
-		ath10k_warn("failed to set fixed nss param %d: %d\n",
+		ath10k_warn(ar, "failed to set fixed nss param %d: %d\n",
 			    fixed_nss, ret);
 		ret = -EINVAL;
 		goto exit;
@@ -4206,7 +4268,7 @@
 					force_sgi);
 
 	if (ret) {
-		ath10k_warn("failed to set sgi param %d: %d\n",
+		ath10k_warn(ar, "failed to set sgi param %d: %d\n",
 			    force_sgi, ret);
 		ret = -EINVAL;
 		goto exit;
@@ -4235,14 +4297,14 @@
 		return -EINVAL;
 
 	if (!ath10k_default_bitrate_mask(ar, band, mask)) {
-		if (!ath10k_get_fixed_rate_nss(mask, band,
+		if (!ath10k_get_fixed_rate_nss(ar, mask, band,
 					       &fixed_rate,
 					       &fixed_nss))
 			return -EINVAL;
 	}
 
 	if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) {
-		ath10k_warn("failed to force SGI usage for default rate settings\n");
+		ath10k_warn(ar, "failed to force SGI usage for default rate settings\n");
 		return -EINVAL;
 	}
 
@@ -4261,7 +4323,7 @@
 
 	spin_lock_bh(&ar->data_lock);
 
-	ath10k_dbg(ATH10K_DBG_MAC,
+	ath10k_dbg(ar, ATH10K_DBG_MAC,
 		   "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
 		   sta->addr, changed, sta->bandwidth, sta->rx_nss,
 		   sta->smps_mode);
@@ -4280,7 +4342,7 @@
 			bw = WMI_PEER_CHWIDTH_80MHZ;
 			break;
 		case IEEE80211_STA_RX_BW_160:
-			ath10k_warn("Invalid bandwith %d in rc update for %pM\n",
+			ath10k_warn(ar, "Invalid bandwith %d in rc update for %pM\n",
 				    sta->bandwidth, sta->addr);
 			bw = WMI_PEER_CHWIDTH_20MHZ;
 			break;
@@ -4307,7 +4369,7 @@
 			smps = WMI_PEER_SMPS_DYNAMIC;
 			break;
 		case IEEE80211_SMPS_NUM_MODES:
-			ath10k_warn("Invalid smps %d in sta rc update for %pM\n",
+			ath10k_warn(ar, "Invalid smps %d in sta rc update for %pM\n",
 				    sta->smps_mode, sta->addr);
 			smps = WMI_PEER_SMPS_PS_NONE;
 			break;
@@ -4339,9 +4401,10 @@
 			       struct ieee80211_sta *sta, u16 tid, u16 *ssn,
 			       u8 buf_size)
 {
+	struct ath10k *ar = hw->priv;
 	struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 
-	ath10k_dbg(ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
 		   arvif->vdev_id, sta->addr, tid, action);
 
 	switch (action) {
@@ -4393,6 +4456,9 @@
 	.sta_rc_update			= ath10k_sta_rc_update,
 	.get_tsf			= ath10k_get_tsf,
 	.ampdu_action			= ath10k_ampdu_action,
+
+	CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
+
 #ifdef CONFIG_PM
 	.suspend			= ath10k_suspend,
 	.resume				= ath10k_resume,
@@ -4489,12 +4555,12 @@
 #define ath10k_g_rates (ath10k_rates + 0)
 #define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates))
 
-struct ath10k *ath10k_mac_create(void)
+struct ath10k *ath10k_mac_create(size_t priv_size)
 {
 	struct ieee80211_hw *hw;
 	struct ath10k *ar;
 
-	hw = ieee80211_alloc_hw(sizeof(struct ath10k), &ath10k_ops);
+	hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, &ath10k_ops);
 	if (!hw)
 		return NULL;
 
@@ -4644,7 +4710,6 @@
 	return ht_cap;
 }
 
-
 static void ath10k_get_arvif_iter(void *data, u8 *mac,
 				  struct ieee80211_vif *vif)
 {
@@ -4669,7 +4734,7 @@
 						   ath10k_get_arvif_iter,
 						   &arvif_iter);
 	if (!arvif_iter.arvif) {
-		ath10k_warn("No VIF found for vdev %d\n", vdev_id);
+		ath10k_warn(ar, "No VIF found for vdev %d\n", vdev_id);
 		return NULL;
 	}
 
@@ -4759,7 +4824,6 @@
 			IEEE80211_HW_MFP_CAPABLE |
 			IEEE80211_HW_REPORTS_TX_ACK_STATUS |
 			IEEE80211_HW_HAS_RATE_CONTROL |
-			IEEE80211_HW_SUPPORTS_STATIC_SMPS |
 			IEEE80211_HW_AP_LINK_PS |
 			IEEE80211_HW_SPECTRUM_MGMT;
 
@@ -4767,8 +4831,10 @@
 	 * bytes is used for padding/alignment if necessary. */
 	ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4;
 
+	ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
+
 	if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
-		ar->hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
+		ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS;
 
 	if (ar->ht_cap_info & WMI_HT_CAP_ENABLED) {
 		ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
@@ -4815,19 +4881,19 @@
 							     NL80211_DFS_UNSET);
 
 		if (!ar->dfs_detector)
-			ath10k_warn("failed to initialise DFS pattern detector\n");
+			ath10k_warn(ar, "failed to initialise DFS pattern detector\n");
 	}
 
 	ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
 			    ath10k_reg_notifier);
 	if (ret) {
-		ath10k_err("failed to initialise regulatory: %i\n", ret);
+		ath10k_err(ar, "failed to initialise regulatory: %i\n", ret);
 		goto err_free;
 	}
 
 	ret = ieee80211_register_hw(ar->hw);
 	if (ret) {
-		ath10k_err("failed to register ieee80211: %d\n", ret);
+		ath10k_err(ar, "failed to register ieee80211: %d\n", ret);
 		goto err_free;
 	}
 
diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
index ef4f843..6c80eea 100644
--- a/drivers/net/wireless/ath/ath10k/mac.h
+++ b/drivers/net/wireless/ath/ath10k/mac.h
@@ -26,12 +26,14 @@
 	int ret;
 };
 
-struct ath10k *ath10k_mac_create(void);
+struct ath10k *ath10k_mac_create(size_t priv_size);
 void ath10k_mac_destroy(struct ath10k *ar);
 int ath10k_mac_register(struct ath10k *ar);
 void ath10k_mac_unregister(struct ath10k *ar);
 struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id);
-void ath10k_reset_scan(unsigned long ptr);
+void __ath10k_scan_finish(struct ath10k *ar);
+void ath10k_scan_finish(struct ath10k *ar);
+void ath10k_scan_timeout_work(struct work_struct *work);
 void ath10k_offchan_tx_purge(struct ath10k *ar);
 void ath10k_offchan_tx_work(struct work_struct *work);
 void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar);
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 3376963..59e0ea8 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -44,13 +44,9 @@
 	ATH10K_PCI_RESET_WARM_ONLY = 1,
 };
 
-static unsigned int ath10k_pci_target_ps;
 static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO;
 static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO;
 
-module_param_named(target_ps, ath10k_pci_target_ps, uint, 0644);
-MODULE_PARM_DESC(target_ps, "Enable ath10k Target (SoC) PS option");
-
 module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644);
 MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)");
 
@@ -68,13 +64,7 @@
 	{0}
 };
 
-static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
-				       u32 *data);
-
-static int ath10k_pci_post_rx(struct ath10k *ar);
-static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
-					     int num);
-static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
+static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
 static int ath10k_pci_cold_reset(struct ath10k *ar);
 static int ath10k_pci_warm_reset(struct ath10k *ar);
 static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
@@ -156,79 +146,175 @@
 static const struct ce_pipe_config target_ce_config_wlan[] = {
 	/* CE0: host->target HTC control and raw streams */
 	{
-		.pipenum = 0,
-		.pipedir = PIPEDIR_OUT,
-		.nentries = 32,
-		.nbytes_max = 256,
-		.flags = CE_ATTR_FLAGS,
-		.reserved = 0,
+		.pipenum = __cpu_to_le32(0),
+		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
+		.nentries = __cpu_to_le32(32),
+		.nbytes_max = __cpu_to_le32(256),
+		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
+		.reserved = __cpu_to_le32(0),
 	},
 
 	/* CE1: target->host HTT + HTC control */
 	{
-		.pipenum = 1,
-		.pipedir = PIPEDIR_IN,
-		.nentries = 32,
-		.nbytes_max = 512,
-		.flags = CE_ATTR_FLAGS,
-		.reserved = 0,
+		.pipenum = __cpu_to_le32(1),
+		.pipedir = __cpu_to_le32(PIPEDIR_IN),
+		.nentries = __cpu_to_le32(32),
+		.nbytes_max = __cpu_to_le32(512),
+		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
+		.reserved = __cpu_to_le32(0),
 	},
 
 	/* CE2: target->host WMI */
 	{
-		.pipenum = 2,
-		.pipedir = PIPEDIR_IN,
-		.nentries = 32,
-		.nbytes_max = 2048,
-		.flags = CE_ATTR_FLAGS,
-		.reserved = 0,
+		.pipenum = __cpu_to_le32(2),
+		.pipedir = __cpu_to_le32(PIPEDIR_IN),
+		.nentries = __cpu_to_le32(32),
+		.nbytes_max = __cpu_to_le32(2048),
+		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
+		.reserved = __cpu_to_le32(0),
 	},
 
 	/* CE3: host->target WMI */
 	{
-		.pipenum = 3,
-		.pipedir = PIPEDIR_OUT,
-		.nentries = 32,
-		.nbytes_max = 2048,
-		.flags = CE_ATTR_FLAGS,
-		.reserved = 0,
+		.pipenum = __cpu_to_le32(3),
+		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
+		.nentries = __cpu_to_le32(32),
+		.nbytes_max = __cpu_to_le32(2048),
+		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
+		.reserved = __cpu_to_le32(0),
 	},
 
 	/* CE4: host->target HTT */
 	{
-		.pipenum = 4,
-		.pipedir = PIPEDIR_OUT,
-		.nentries = 256,
-		.nbytes_max = 256,
-		.flags = CE_ATTR_FLAGS,
-		.reserved = 0,
+		.pipenum = __cpu_to_le32(4),
+		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
+		.nentries = __cpu_to_le32(256),
+		.nbytes_max = __cpu_to_le32(256),
+		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
+		.reserved = __cpu_to_le32(0),
 	},
 
 	/* NB: 50% of src nentries, since tx has 2 frags */
 
 	/* CE5: unused */
 	{
-		.pipenum = 5,
-		.pipedir = PIPEDIR_OUT,
-		.nentries = 32,
-		.nbytes_max = 2048,
-		.flags = CE_ATTR_FLAGS,
-		.reserved = 0,
+		.pipenum = __cpu_to_le32(5),
+		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
+		.nentries = __cpu_to_le32(32),
+		.nbytes_max = __cpu_to_le32(2048),
+		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
+		.reserved = __cpu_to_le32(0),
 	},
 
 	/* CE6: Reserved for target autonomous hif_memcpy */
 	{
-		.pipenum = 6,
-		.pipedir = PIPEDIR_INOUT,
-		.nentries = 32,
-		.nbytes_max = 4096,
-		.flags = CE_ATTR_FLAGS,
-		.reserved = 0,
+		.pipenum = __cpu_to_le32(6),
+		.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
+		.nentries = __cpu_to_le32(32),
+		.nbytes_max = __cpu_to_le32(4096),
+		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
+		.reserved = __cpu_to_le32(0),
 	},
 
 	/* CE7 used only by Host */
 };
 
+/*
+ * Map from service/endpoint to Copy Engine.
+ * This table is derived from the CE_PCI TABLE, above.
+ * It is passed to the Target at startup for use by firmware.
+ */
+static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
+		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
+		__cpu_to_le32(3),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
+		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
+		__cpu_to_le32(2),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
+		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
+		__cpu_to_le32(3),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
+		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
+		__cpu_to_le32(2),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
+		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
+		__cpu_to_le32(3),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
+		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
+		__cpu_to_le32(2),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
+		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
+		__cpu_to_le32(3),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
+		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
+		__cpu_to_le32(2),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
+		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
+		__cpu_to_le32(3),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
+		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
+		__cpu_to_le32(2),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
+		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
+		__cpu_to_le32(0),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
+		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
+		__cpu_to_le32(1),
+	},
+	{ /* not used */
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
+		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
+		__cpu_to_le32(0),
+	},
+	{ /* not used */
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
+		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
+		__cpu_to_le32(1),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
+		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
+		__cpu_to_le32(4),
+	},
+	{
+		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
+		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
+		__cpu_to_le32(1),
+	},
+
+	/* (Additions here) */
+
+	{ /* must be last */
+		__cpu_to_le32(0),
+		__cpu_to_le32(0),
+		__cpu_to_le32(0),
+	},
+};
+
 static bool ath10k_pci_irq_pending(struct ath10k *ar)
 {
 	u32 cause;
@@ -254,8 +340,8 @@
 
 	/* IMPORTANT: this extra read transaction is required to
 	 * flush the posted write buffer. */
-	(void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
-				 PCIE_INTR_ENABLE_ADDRESS);
+	(void)ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+				PCIE_INTR_ENABLE_ADDRESS);
 }
 
 static void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
@@ -266,48 +352,116 @@
 
 	/* IMPORTANT: this extra read transaction is required to
 	 * flush the posted write buffer. */
-	(void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
-				 PCIE_INTR_ENABLE_ADDRESS);
+	(void)ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+				PCIE_INTR_ENABLE_ADDRESS);
 }
 
-static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg)
+static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar)
 {
-	struct ath10k *ar = arg;
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-	if (ar_pci->num_msi_intrs == 0) {
-		if (!ath10k_pci_irq_pending(ar))
-			return IRQ_NONE;
+	if (ar_pci->num_msi_intrs > 1)
+		return "msi-x";
 
-		ath10k_pci_disable_and_clear_legacy_irq(ar);
-	}
+	if (ar_pci->num_msi_intrs == 1)
+		return "msi";
 
-	tasklet_schedule(&ar_pci->early_irq_tasklet);
-
-	return IRQ_HANDLED;
+	return "legacy";
 }
 
-static int ath10k_pci_request_early_irq(struct ath10k *ar)
+static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe)
 {
+	struct ath10k *ar = pipe->hif_ce_state;
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
+	struct sk_buff *skb;
+	dma_addr_t paddr;
 	int ret;
 
-	/* Regardless whether MSI-X/MSI/legacy irqs have been set up the first
-	 * interrupt from irq vector is triggered in all cases for FW
-	 * indication/errors */
-	ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler,
-			  IRQF_SHARED, "ath10k_pci (early)", ar);
+	lockdep_assert_held(&ar_pci->ce_lock);
+
+	skb = dev_alloc_skb(pipe->buf_sz);
+	if (!skb)
+		return -ENOMEM;
+
+	WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
+
+	paddr = dma_map_single(ar->dev, skb->data,
+			       skb->len + skb_tailroom(skb),
+			       DMA_FROM_DEVICE);
+	if (unlikely(dma_mapping_error(ar->dev, paddr))) {
+		ath10k_warn(ar, "failed to dma map pci rx buf\n");
+		dev_kfree_skb_any(skb);
+		return -EIO;
+	}
+
+	ATH10K_SKB_CB(skb)->paddr = paddr;
+
+	ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr);
 	if (ret) {
-		ath10k_warn("failed to request early irq: %d\n", ret);
+		ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret);
+		dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb),
+				 DMA_FROM_DEVICE);
+		dev_kfree_skb_any(skb);
 		return ret;
 	}
 
 	return 0;
 }
 
-static void ath10k_pci_free_early_irq(struct ath10k *ar)
+static void __ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
 {
-	free_irq(ath10k_pci_priv(ar)->pdev->irq, ar);
+	struct ath10k *ar = pipe->hif_ce_state;
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
+	int ret, num;
+
+	lockdep_assert_held(&ar_pci->ce_lock);
+
+	if (pipe->buf_sz == 0)
+		return;
+
+	if (!ce_pipe->dest_ring)
+		return;
+
+	num = __ath10k_ce_rx_num_free_bufs(ce_pipe);
+	while (num--) {
+		ret = __ath10k_pci_rx_post_buf(pipe);
+		if (ret) {
+			ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret);
+			mod_timer(&ar_pci->rx_post_retry, jiffies +
+				  ATH10K_PCI_RX_POST_RETRY_MS);
+			break;
+		}
+	}
+}
+
+static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
+{
+	struct ath10k *ar = pipe->hif_ce_state;
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+	spin_lock_bh(&ar_pci->ce_lock);
+	__ath10k_pci_rx_post_pipe(pipe);
+	spin_unlock_bh(&ar_pci->ce_lock);
+}
+
+static void ath10k_pci_rx_post(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	int i;
+
+	spin_lock_bh(&ar_pci->ce_lock);
+	for (i = 0; i < CE_COUNT; i++)
+		__ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]);
+	spin_unlock_bh(&ar_pci->ce_lock);
+}
+
+static void ath10k_pci_rx_replenish_retry(unsigned long ptr)
+{
+	struct ath10k *ar = (void *)ptr;
+
+	ath10k_pci_rx_post(ar);
 }
 
 /*
@@ -331,25 +485,6 @@
 	void *data_buf = NULL;
 	int i;
 
-	/*
-	 * This code cannot handle reads to non-memory space. Redirect to the
-	 * register read fn but preserve the multi word read capability of
-	 * this fn
-	 */
-	if (address < DRAM_BASE_ADDRESS) {
-		if (!IS_ALIGNED(address, 4) ||
-		    !IS_ALIGNED((unsigned long)data, 4))
-			return -EIO;
-
-		while ((nbytes >= 4) &&  ((ret = ath10k_pci_diag_read_access(
-					   ar, address, (u32 *)data)) == 0)) {
-			nbytes -= sizeof(u32);
-			address += sizeof(u32);
-			data += sizeof(u32);
-		}
-		return ret;
-	}
-
 	ce_diag = ar_pci->ce_diag;
 
 	/*
@@ -376,7 +511,7 @@
 		nbytes = min_t(unsigned int, remaining_bytes,
 			       DIAG_TRANSFER_LIMIT);
 
-		ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, ce_data);
+		ret = ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data);
 		if (ret != 0)
 			goto done;
 
@@ -389,13 +524,11 @@
 		 * convert it from Target CPU virtual address space
 		 * to CE address space
 		 */
-		ath10k_pci_wake(ar);
 		address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem,
 						     address);
-		ath10k_pci_sleep(ar);
 
 		ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0,
-				 0);
+				     0);
 		if (ret)
 			goto done;
 
@@ -415,7 +548,7 @@
 			goto done;
 		}
 
-		if (buf != (u32) address) {
+		if (buf != (u32)address) {
 			ret = -EIO;
 			goto done;
 		}
@@ -448,15 +581,10 @@
 	}
 
 done:
-	if (ret == 0) {
-		/* Copy data from allocated DMA buf to caller's buf */
-		WARN_ON_ONCE(orig_nbytes & 3);
-		for (i = 0; i < orig_nbytes / sizeof(__le32); i++) {
-			((u32 *)data)[i] =
-				__le32_to_cpu(((__le32 *)data_buf)[i]);
-		}
-	} else
-		ath10k_warn("failed to read diag value at 0x%x: %d\n",
+	if (ret == 0)
+		memcpy(data, data_buf, orig_nbytes);
+	else
+		ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n",
 			    address, ret);
 
 	if (data_buf)
@@ -466,20 +594,45 @@
 	return ret;
 }
 
-/* Read 4-byte aligned data from Target memory or register */
-static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
-				       u32 *data)
+static int ath10k_pci_diag_read32(struct ath10k *ar, u32 address, u32 *value)
 {
-	/* Assume range doesn't cross this boundary */
-	if (address >= DRAM_BASE_ADDRESS)
-		return ath10k_pci_diag_read_mem(ar, address, data, sizeof(u32));
+	__le32 val = 0;
+	int ret;
 
-	ath10k_pci_wake(ar);
-	*data = ath10k_pci_read32(ar, address);
-	ath10k_pci_sleep(ar);
+	ret = ath10k_pci_diag_read_mem(ar, address, &val, sizeof(val));
+	*value = __le32_to_cpu(val);
+
+	return ret;
+}
+
+static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest,
+				     u32 src, u32 len)
+{
+	u32 host_addr, addr;
+	int ret;
+
+	host_addr = host_interest_item_address(src);
+
+	ret = ath10k_pci_diag_read32(ar, host_addr, &addr);
+	if (ret != 0) {
+		ath10k_warn(ar, "failed to get memcpy hi address for firmware address %d: %d\n",
+			    src, ret);
+		return ret;
+	}
+
+	ret = ath10k_pci_diag_read_mem(ar, addr, dest, len);
+	if (ret != 0) {
+		ath10k_warn(ar, "failed to memcpy firmware memory from %d (%d B): %d\n",
+			    addr, len, ret);
+		return ret;
+	}
+
 	return 0;
 }
 
+#define ath10k_pci_diag_read_hi(ar, dest, src, len)		\
+	__ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len)
+
 static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
 				     const void *data, int nbytes)
 {
@@ -514,9 +667,7 @@
 	}
 
 	/* Copy caller's data to allocated DMA buf */
-	WARN_ON_ONCE(orig_nbytes & 3);
-	for (i = 0; i < orig_nbytes / sizeof(__le32); i++)
-		((__le32 *)data_buf)[i] = __cpu_to_le32(((u32 *)data)[i]);
+	memcpy(data_buf, data, orig_nbytes);
 
 	/*
 	 * The address supplied by the caller is in the
@@ -528,9 +679,7 @@
 	 * to
 	 *    CE address space
 	 */
-	ath10k_pci_wake(ar);
 	address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address);
-	ath10k_pci_sleep(ar);
 
 	remaining_bytes = orig_nbytes;
 	ce_data = ce_data_base;
@@ -539,7 +688,7 @@
 		nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT);
 
 		/* Set up to receive directly into Target(!) address */
-		ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, address);
+		ret = ath10k_ce_rx_post_buf(ce_diag, NULL, address);
 		if (ret != 0)
 			goto done;
 
@@ -547,7 +696,7 @@
 		 * Request CE to send caller-supplied data that
 		 * was copied to bounce buffer to Target(!) address.
 		 */
-		ret = ath10k_ce_send(ce_diag, NULL, (u32) ce_data,
+		ret = ath10k_ce_send(ce_diag, NULL, (u32)ce_data,
 				     nbytes, 0, 0);
 		if (ret != 0)
 			goto done;
@@ -608,66 +757,34 @@
 	}
 
 	if (ret != 0)
-		ath10k_warn("failed to write diag value at 0x%x: %d\n",
+		ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n",
 			    address, ret);
 
 	return ret;
 }
 
-/* Write 4B data to Target memory or register */
-static int ath10k_pci_diag_write_access(struct ath10k *ar, u32 address,
-					u32 data)
+static int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value)
 {
-	/* Assume range doesn't cross this boundary */
-	if (address >= DRAM_BASE_ADDRESS)
-		return ath10k_pci_diag_write_mem(ar, address, &data,
-						 sizeof(u32));
+	__le32 val = __cpu_to_le32(value);
 
-	ath10k_pci_wake(ar);
-	ath10k_pci_write32(ar, address, data);
-	ath10k_pci_sleep(ar);
-	return 0;
+	return ath10k_pci_diag_write_mem(ar, address, &val, sizeof(val));
 }
 
-static bool ath10k_pci_target_is_awake(struct ath10k *ar)
+static bool ath10k_pci_is_awake(struct ath10k *ar)
 {
-	void __iomem *mem = ath10k_pci_priv(ar)->mem;
-	u32 val;
-	val = ioread32(mem + PCIE_LOCAL_BASE_ADDRESS +
-		       RTC_STATE_ADDRESS);
-	return (RTC_STATE_V_GET(val) == RTC_STATE_V_ON);
+	u32 val = ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS);
+
+	return RTC_STATE_V_GET(val) == RTC_STATE_V_ON;
 }
 
-int ath10k_do_pci_wake(struct ath10k *ar)
+static int ath10k_pci_wake_wait(struct ath10k *ar)
 {
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	void __iomem *pci_addr = ar_pci->mem;
 	int tot_delay = 0;
 	int curr_delay = 5;
 
-	if (atomic_read(&ar_pci->keep_awake_count) == 0) {
-		/* Force AWAKE */
-		iowrite32(PCIE_SOC_WAKE_V_MASK,
-			  pci_addr + PCIE_LOCAL_BASE_ADDRESS +
-			  PCIE_SOC_WAKE_ADDRESS);
-	}
-	atomic_inc(&ar_pci->keep_awake_count);
-
-	if (ar_pci->verified_awake)
-		return 0;
-
-	for (;;) {
-		if (ath10k_pci_target_is_awake(ar)) {
-			ar_pci->verified_awake = true;
+	while (tot_delay < PCIE_WAKE_TIMEOUT) {
+		if (ath10k_pci_is_awake(ar))
 			return 0;
-		}
-
-		if (tot_delay > PCIE_WAKE_TIMEOUT) {
-			ath10k_warn("target took longer %d us to wake up (awake count %d)\n",
-				    PCIE_WAKE_TIMEOUT,
-				    atomic_read(&ar_pci->keep_awake_count));
-			return -ETIMEDOUT;
-		}
 
 		udelay(curr_delay);
 		tot_delay += curr_delay;
@@ -675,20 +792,21 @@
 		if (curr_delay < 50)
 			curr_delay += 5;
 	}
+
+	return -ETIMEDOUT;
 }
 
-void ath10k_do_pci_sleep(struct ath10k *ar)
+static int ath10k_pci_wake(struct ath10k *ar)
 {
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	void __iomem *pci_addr = ar_pci->mem;
+	ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
+			       PCIE_SOC_WAKE_V_MASK);
+	return ath10k_pci_wake_wait(ar);
+}
 
-	if (atomic_dec_and_test(&ar_pci->keep_awake_count)) {
-		/* Allow sleep */
-		ar_pci->verified_awake = false;
-		iowrite32(PCIE_SOC_WAKE_RESET,
-			  pci_addr + PCIE_LOCAL_BASE_ADDRESS +
-			  PCIE_SOC_WAKE_ADDRESS);
-	}
+static void ath10k_pci_sleep(struct ath10k *ar)
+{
+	ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
+			       PCIE_SOC_WAKE_RESET);
 }
 
 /* Called by lower (CE) layer when a send to Target completes. */
@@ -726,19 +844,17 @@
 	unsigned int nbytes, max_nbytes;
 	unsigned int transfer_id;
 	unsigned int flags;
-	int err, num_replenish = 0;
 
 	while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
 					     &ce_data, &nbytes, &transfer_id,
 					     &flags) == 0) {
-		num_replenish++;
 		skb = transfer_context;
 		max_nbytes = skb->len + skb_tailroom(skb);
 		dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
 				 max_nbytes, DMA_FROM_DEVICE);
 
 		if (unlikely(max_nbytes < nbytes)) {
-			ath10k_warn("rxed more than expected (nbytes %d, max %d)",
+			ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)",
 				    nbytes, max_nbytes);
 			dev_kfree_skb_any(skb);
 			continue;
@@ -748,12 +864,7 @@
 		cb->rx_completion(ar, skb, pipe_info->pipe_num);
 	}
 
-	err = ath10k_pci_post_rx_pipe(pipe_info, num_replenish);
-	if (unlikely(err)) {
-		/* FIXME: retry */
-		ath10k_warn("failed to replenish CE rx ring %d (%d bufs): %d\n",
-			    pipe_info->pipe_num, num_replenish, err);
-	}
+	ath10k_pci_rx_post_pipe(pipe_info);
 }
 
 static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
@@ -781,10 +892,10 @@
 	}
 
 	for (i = 0; i < n_items - 1; i++) {
-		ath10k_dbg(ATH10K_DBG_PCI,
+		ath10k_dbg(ar, ATH10K_DBG_PCI,
 			   "pci tx item %d paddr 0x%08x len %d n_items %d\n",
 			   i, items[i].paddr, items[i].len, n_items);
-		ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
+		ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ",
 				items[i].vaddr, items[i].len);
 
 		err = ath10k_ce_send_nolock(ce_pipe,
@@ -799,10 +910,10 @@
 
 	/* `i` is equal to `n_items -1` after for() */
 
-	ath10k_dbg(ATH10K_DBG_PCI,
+	ath10k_dbg(ar, ATH10K_DBG_PCI,
 		   "pci tx item %d paddr 0x%08x len %d n_items %d\n",
 		   i, items[i].paddr, items[i].len, n_items);
-	ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
+	ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ",
 			items[i].vaddr, items[i].len);
 
 	err = ath10k_ce_send_nolock(ce_pipe,
@@ -829,52 +940,64 @@
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-	ath10k_dbg(ATH10K_DBG_PCI, "pci hif get free queue number\n");
+	ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get free queue number\n");
 
 	return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
 }
 
-static void ath10k_pci_hif_dump_area(struct ath10k *ar)
+static void ath10k_pci_dump_registers(struct ath10k *ar,
+				      struct ath10k_fw_crash_data *crash_data)
 {
-	u32 reg_dump_area = 0;
-	u32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
-	u32 host_addr;
-	int ret;
-	u32 i;
+	__le32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
+	int i, ret;
 
-	ath10k_err("firmware crashed!\n");
-	ath10k_err("hardware name %s version 0x%x\n",
-		   ar->hw_params.name, ar->target_version);
-	ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version);
+	lockdep_assert_held(&ar->data_lock);
 
-	host_addr = host_interest_item_address(HI_ITEM(hi_failure_state));
-	ret = ath10k_pci_diag_read_mem(ar, host_addr,
-				       &reg_dump_area, sizeof(u32));
+	ret = ath10k_pci_diag_read_hi(ar, &reg_dump_values[0],
+				      hi_failure_state,
+				      REG_DUMP_COUNT_QCA988X * sizeof(__le32));
 	if (ret) {
-		ath10k_err("failed to read FW dump area address: %d\n", ret);
-		return;
-	}
-
-	ath10k_err("target register Dump Location: 0x%08X\n", reg_dump_area);
-
-	ret = ath10k_pci_diag_read_mem(ar, reg_dump_area,
-				       &reg_dump_values[0],
-				       REG_DUMP_COUNT_QCA988X * sizeof(u32));
-	if (ret != 0) {
-		ath10k_err("failed to read FW dump area: %d\n", ret);
+		ath10k_err(ar, "failed to read firmware dump area: %d\n", ret);
 		return;
 	}
 
 	BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4);
 
-	ath10k_err("target Register Dump\n");
+	ath10k_err(ar, "firmware register dump:\n");
 	for (i = 0; i < REG_DUMP_COUNT_QCA988X; i += 4)
-		ath10k_err("[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n",
+		ath10k_err(ar, "[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n",
 			   i,
-			   reg_dump_values[i],
-			   reg_dump_values[i + 1],
-			   reg_dump_values[i + 2],
-			   reg_dump_values[i + 3]);
+			   __le32_to_cpu(reg_dump_values[i]),
+			   __le32_to_cpu(reg_dump_values[i + 1]),
+			   __le32_to_cpu(reg_dump_values[i + 2]),
+			   __le32_to_cpu(reg_dump_values[i + 3]));
+
+	if (!crash_data)
+		return;
+
+	for (i = 0; i < REG_DUMP_COUNT_QCA988X; i++)
+		crash_data->registers[i] = reg_dump_values[i];
+}
+
+static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
+{
+	struct ath10k_fw_crash_data *crash_data;
+	char uuid[50];
+
+	spin_lock_bh(&ar->data_lock);
+
+	crash_data = ath10k_debug_get_new_fw_crash_data(ar);
+
+	if (crash_data)
+		scnprintf(uuid, sizeof(uuid), "%pUl", &crash_data->uuid);
+	else
+		scnprintf(uuid, sizeof(uuid), "n/a");
+
+	ath10k_err(ar, "firmware crashed! (uuid %s)\n", uuid);
+	ath10k_print_driver_info(ar);
+	ath10k_pci_dump_registers(ar, crash_data);
+
+	spin_unlock_bh(&ar->data_lock);
 
 	queue_work(ar->workqueue, &ar->restart_work);
 }
@@ -882,7 +1005,7 @@
 static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
 					       int force)
 {
-	ath10k_dbg(ATH10K_DBG_PCI, "pci hif send complete check\n");
+	ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n");
 
 	if (!force) {
 		int resources;
@@ -910,43 +1033,12 @@
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-	ath10k_dbg(ATH10K_DBG_PCI, "pci hif set callbacks\n");
+	ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif set callbacks\n");
 
 	memcpy(&ar_pci->msg_callbacks_current, callbacks,
 	       sizeof(ar_pci->msg_callbacks_current));
 }
 
-static int ath10k_pci_setup_ce_irq(struct ath10k *ar)
-{
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	const struct ce_attr *attr;
-	struct ath10k_pci_pipe *pipe_info;
-	int pipe_num, disable_interrupts;
-
-	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
-		pipe_info = &ar_pci->pipe_info[pipe_num];
-
-		/* Handle Diagnostic CE specially */
-		if (pipe_info->ce_hdl == ar_pci->ce_diag)
-			continue;
-
-		attr = &host_ce_config_wlan[pipe_num];
-
-		if (attr->src_nentries) {
-			disable_interrupts = attr->flags & CE_ATTR_DIS_INTR;
-			ath10k_ce_send_cb_register(pipe_info->ce_hdl,
-						   ath10k_pci_ce_send_done,
-						   disable_interrupts);
-		}
-
-		if (attr->dest_nentries)
-			ath10k_ce_recv_cb_register(pipe_info->ce_hdl,
-						   ath10k_pci_ce_recv_data);
-	}
-
-	return 0;
-}
-
 static void ath10k_pci_kill_tasklet(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -954,82 +1046,72 @@
 
 	tasklet_kill(&ar_pci->intr_tq);
 	tasklet_kill(&ar_pci->msi_fw_err);
-	tasklet_kill(&ar_pci->early_irq_tasklet);
 
 	for (i = 0; i < CE_COUNT; i++)
 		tasklet_kill(&ar_pci->pipe_info[i].intr);
+
+	del_timer_sync(&ar_pci->rx_post_retry);
 }
 
-/* TODO - temporary mapping while we have too few CE's */
 static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,
 					      u16 service_id, u8 *ul_pipe,
 					      u8 *dl_pipe, int *ul_is_polled,
 					      int *dl_is_polled)
 {
-	int ret = 0;
+	const struct service_to_pipe *entry;
+	bool ul_set = false, dl_set = false;
+	int i;
 
-	ath10k_dbg(ATH10K_DBG_PCI, "pci hif map service\n");
+	ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n");
 
 	/* polling for received messages not supported */
 	*dl_is_polled = 0;
 
-	switch (service_id) {
-	case ATH10K_HTC_SVC_ID_HTT_DATA_MSG:
-		/*
-		 * Host->target HTT gets its own pipe, so it can be polled
-		 * while other pipes are interrupt driven.
-		 */
-		*ul_pipe = 4;
-		/*
-		 * Use the same target->host pipe for HTC ctrl, HTC raw
-		 * streams, and HTT.
-		 */
-		*dl_pipe = 1;
-		break;
+	for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
+		entry = &target_service_to_ce_map_wlan[i];
 
-	case ATH10K_HTC_SVC_ID_RSVD_CTRL:
-	case ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS:
-		/*
-		 * Note: HTC_RAW_STREAMS_SVC is currently unused, and
-		 * HTC_CTRL_RSVD_SVC could share the same pipe as the
-		 * WMI services.  So, if another CE is needed, change
-		 * this to *ul_pipe = 3, which frees up CE 0.
-		 */
-		/* *ul_pipe = 3; */
-		*ul_pipe = 0;
-		*dl_pipe = 1;
-		break;
+		if (__le32_to_cpu(entry->service_id) != service_id)
+			continue;
 
-	case ATH10K_HTC_SVC_ID_WMI_DATA_BK:
-	case ATH10K_HTC_SVC_ID_WMI_DATA_BE:
-	case ATH10K_HTC_SVC_ID_WMI_DATA_VI:
-	case ATH10K_HTC_SVC_ID_WMI_DATA_VO:
-
-	case ATH10K_HTC_SVC_ID_WMI_CONTROL:
-		*ul_pipe = 3;
-		*dl_pipe = 2;
-		break;
-
-		/* pipe 5 unused   */
-		/* pipe 6 reserved */
-		/* pipe 7 reserved */
-
-	default:
-		ret = -1;
-		break;
+		switch (__le32_to_cpu(entry->pipedir)) {
+		case PIPEDIR_NONE:
+			break;
+		case PIPEDIR_IN:
+			WARN_ON(dl_set);
+			*dl_pipe = __le32_to_cpu(entry->pipenum);
+			dl_set = true;
+			break;
+		case PIPEDIR_OUT:
+			WARN_ON(ul_set);
+			*ul_pipe = __le32_to_cpu(entry->pipenum);
+			ul_set = true;
+			break;
+		case PIPEDIR_INOUT:
+			WARN_ON(dl_set);
+			WARN_ON(ul_set);
+			*dl_pipe = __le32_to_cpu(entry->pipenum);
+			*ul_pipe = __le32_to_cpu(entry->pipenum);
+			dl_set = true;
+			ul_set = true;
+			break;
+		}
 	}
+
+	if (WARN_ON(!ul_set || !dl_set))
+		return -ENOENT;
+
 	*ul_is_polled =
 		(host_ce_config_wlan[*ul_pipe].flags & CE_ATTR_DIS_INTR) != 0;
 
-	return ret;
+	return 0;
 }
 
 static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
-						u8 *ul_pipe, u8 *dl_pipe)
+					    u8 *ul_pipe, u8 *dl_pipe)
 {
 	int ul_is_polled, dl_is_polled;
 
-	ath10k_dbg(ATH10K_DBG_PCI, "pci hif get default pipe\n");
+	ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n");
 
 	(void)ath10k_pci_hif_map_service_to_pipe(ar,
 						 ATH10K_HTC_SVC_ID_RSVD_CTRL,
@@ -1039,141 +1121,34 @@
 						 &dl_is_polled);
 }
 
-static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
-				   int num)
+static void ath10k_pci_irq_disable(struct ath10k *ar)
 {
-	struct ath10k *ar = pipe_info->hif_ce_state;
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	struct ath10k_ce_pipe *ce_state = pipe_info->ce_hdl;
-	struct sk_buff *skb;
-	dma_addr_t ce_data;
-	int i, ret = 0;
+	int i;
 
-	if (pipe_info->buf_sz == 0)
-		return 0;
+	ath10k_ce_disable_interrupts(ar);
+	ath10k_pci_disable_and_clear_legacy_irq(ar);
+	/* FIXME: How to mask all MSI interrupts? */
 
-	for (i = 0; i < num; i++) {
-		skb = dev_alloc_skb(pipe_info->buf_sz);
-		if (!skb) {
-			ath10k_warn("failed to allocate skbuff for pipe %d\n",
-				    num);
-			ret = -ENOMEM;
-			goto err;
-		}
-
-		WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
-
-		ce_data = dma_map_single(ar->dev, skb->data,
-					 skb->len + skb_tailroom(skb),
-					 DMA_FROM_DEVICE);
-
-		if (unlikely(dma_mapping_error(ar->dev, ce_data))) {
-			ath10k_warn("failed to DMA map sk_buff\n");
-			dev_kfree_skb_any(skb);
-			ret = -EIO;
-			goto err;
-		}
-
-		ATH10K_SKB_CB(skb)->paddr = ce_data;
-
-		pci_dma_sync_single_for_device(ar_pci->pdev, ce_data,
-					       pipe_info->buf_sz,
-					       PCI_DMA_FROMDEVICE);
-
-		ret = ath10k_ce_recv_buf_enqueue(ce_state, (void *)skb,
-						 ce_data);
-		if (ret) {
-			ath10k_warn("failed to enqueue to pipe %d: %d\n",
-				    num, ret);
-			goto err;
-		}
-	}
-
-	return ret;
-
-err:
-	ath10k_pci_rx_pipe_cleanup(pipe_info);
-	return ret;
+	for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
+		synchronize_irq(ar_pci->pdev->irq + i);
 }
 
-static int ath10k_pci_post_rx(struct ath10k *ar)
+static void ath10k_pci_irq_enable(struct ath10k *ar)
 {
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	struct ath10k_pci_pipe *pipe_info;
-	const struct ce_attr *attr;
-	int pipe_num, ret = 0;
-
-	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
-		pipe_info = &ar_pci->pipe_info[pipe_num];
-		attr = &host_ce_config_wlan[pipe_num];
-
-		if (attr->dest_nentries == 0)
-			continue;
-
-		ret = ath10k_pci_post_rx_pipe(pipe_info,
-					      attr->dest_nentries - 1);
-		if (ret) {
-			ath10k_warn("failed to post RX buffer for pipe %d: %d\n",
-				    pipe_num, ret);
-
-			for (; pipe_num >= 0; pipe_num--) {
-				pipe_info = &ar_pci->pipe_info[pipe_num];
-				ath10k_pci_rx_pipe_cleanup(pipe_info);
-			}
-			return ret;
-		}
-	}
-
-	return 0;
+	ath10k_ce_enable_interrupts(ar);
+	ath10k_pci_enable_legacy_irq(ar);
+	/* FIXME: How to unmask all MSI interrupts? */
 }
 
 static int ath10k_pci_hif_start(struct ath10k *ar)
 {
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	int ret, ret_early;
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n");
+	ath10k_pci_irq_enable(ar);
+	ath10k_pci_rx_post(ar);
 
-	ath10k_pci_free_early_irq(ar);
-	ath10k_pci_kill_tasklet(ar);
-
-	ret = ath10k_pci_request_irq(ar);
-	if (ret) {
-		ath10k_warn("failed to post RX buffers for all pipes: %d\n",
-			    ret);
-		goto err_early_irq;
-	}
-
-	ret = ath10k_pci_setup_ce_irq(ar);
-	if (ret) {
-		ath10k_warn("failed to setup CE interrupts: %d\n", ret);
-		goto err_stop;
-	}
-
-	/* Post buffers once to start things off. */
-	ret = ath10k_pci_post_rx(ar);
-	if (ret) {
-		ath10k_warn("failed to post RX buffers for all pipes: %d\n",
-			    ret);
-		goto err_stop;
-	}
-
-	ar_pci->started = 1;
 	return 0;
-
-err_stop:
-	ath10k_ce_disable_interrupts(ar);
-	ath10k_pci_free_irq(ar);
-	ath10k_pci_kill_tasklet(ar);
-err_early_irq:
-	/* Though there should be no interrupts (device was reset)
-	 * power_down() expects the early IRQ to be installed as per the
-	 * driver lifecycle. */
-	ret_early = ath10k_pci_request_early_irq(ar);
-	if (ret_early)
-		ath10k_warn("failed to re-enable early irq: %d\n", ret_early);
-
-	return ret;
 }
 
 static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
@@ -1193,10 +1168,6 @@
 
 	ar = pipe_info->hif_ce_state;
 	ar_pci = ath10k_pci_priv(ar);
-
-	if (!ar_pci->started)
-		return;
-
 	ce_hdl = pipe_info->ce_hdl;
 
 	while (ath10k_ce_revoke_recv_next(ce_hdl, (void **)&netbuf,
@@ -1227,10 +1198,6 @@
 
 	ar = pipe_info->hif_ce_state;
 	ar_pci = ath10k_pci_priv(ar);
-
-	if (!ar_pci->started)
-		return;
-
 	ce_hdl = pipe_info->ce_hdl;
 
 	while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf,
@@ -1275,41 +1242,31 @@
 		ath10k_ce_deinit_pipe(ar, i);
 }
 
+static void ath10k_pci_flush(struct ath10k *ar)
+{
+	ath10k_pci_kill_tasklet(ar);
+	ath10k_pci_buffer_cleanup(ar);
+}
+
 static void ath10k_pci_hif_stop(struct ath10k *ar)
 {
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	int ret;
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n");
-
-	if (WARN_ON(!ar_pci->started))
-		return;
-
-	ret = ath10k_ce_disable_interrupts(ar);
-	if (ret)
-		ath10k_warn("failed to disable CE interrupts: %d\n", ret);
-
-	ath10k_pci_free_irq(ar);
-	ath10k_pci_kill_tasklet(ar);
-
-	ret = ath10k_pci_request_early_irq(ar);
-	if (ret)
-		ath10k_warn("failed to re-enable early irq: %d\n", ret);
-
-	/* At this point, asynchronous threads are stopped, the target should
-	 * not DMA nor interrupt. We process the leftovers and then free
-	 * everything else up. */
-
-	ath10k_pci_buffer_cleanup(ar);
-
-	/* Make the sure the device won't access any structures on the host by
-	 * resetting it. The device was fed with PCI CE ringbuffer
-	 * configuration during init. If ringbuffers are freed and the device
-	 * were to access them this could lead to memory corruption on the
-	 * host. */
+	/* Most likely the device has HTT Rx ring configured. The only way to
+	 * prevent the device from accessing (and possible corrupting) host
+	 * memory is to reset the chip now.
+	 *
+	 * There's also no known way of masking MSI interrupts on the device.
+	 * For ranged MSI the CE-related interrupts can be masked. However
+	 * regardless how many MSI interrupts are assigned the first one
+	 * is always used for firmware indications (crashes) and cannot be
+	 * masked. To prevent the device from asserting the interrupt reset it
+	 * before proceeding with cleanup.
+	 */
 	ath10k_pci_warm_reset(ar);
 
-	ar_pci->started = 0;
+	ath10k_pci_irq_disable(ar);
+	ath10k_pci_flush(ar);
 }
 
 static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
@@ -1360,7 +1317,7 @@
 		xfer.wait_for_resp = true;
 		xfer.resp_len = 0;
 
-		ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr);
+		ath10k_ce_rx_post_buf(ce_rx, &xfer, resp_paddr);
 	}
 
 	ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0);
@@ -1418,6 +1375,7 @@
 
 static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
 {
+	struct ath10k *ar = ce_state->ar;
 	struct bmi_xfer *xfer;
 	u32 ce_data;
 	unsigned int nbytes;
@@ -1429,7 +1387,7 @@
 		return;
 
 	if (!xfer->wait_for_resp) {
-		ath10k_warn("unexpected: BMI data received; ignoring\n");
+		ath10k_warn(ar, "unexpected: BMI data received; ignoring\n");
 		return;
 	}
 
@@ -1457,129 +1415,17 @@
 }
 
 /*
- * Map from service/endpoint to Copy Engine.
- * This table is derived from the CE_PCI TABLE, above.
- * It is passed to the Target at startup for use by firmware.
- */
-static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
-	{
-		 ATH10K_HTC_SVC_ID_WMI_DATA_VO,
-		 PIPEDIR_OUT,		/* out = UL = host -> target */
-		 3,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_WMI_DATA_VO,
-		 PIPEDIR_IN,		/* in = DL = target -> host */
-		 2,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_WMI_DATA_BK,
-		 PIPEDIR_OUT,		/* out = UL = host -> target */
-		 3,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_WMI_DATA_BK,
-		 PIPEDIR_IN,		/* in = DL = target -> host */
-		 2,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_WMI_DATA_BE,
-		 PIPEDIR_OUT,		/* out = UL = host -> target */
-		 3,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_WMI_DATA_BE,
-		 PIPEDIR_IN,		/* in = DL = target -> host */
-		 2,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_WMI_DATA_VI,
-		 PIPEDIR_OUT,		/* out = UL = host -> target */
-		 3,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_WMI_DATA_VI,
-		 PIPEDIR_IN,		/* in = DL = target -> host */
-		 2,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_WMI_CONTROL,
-		 PIPEDIR_OUT,		/* out = UL = host -> target */
-		 3,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_WMI_CONTROL,
-		 PIPEDIR_IN,		/* in = DL = target -> host */
-		 2,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_RSVD_CTRL,
-		 PIPEDIR_OUT,		/* out = UL = host -> target */
-		 0,		/* could be moved to 3 (share with WMI) */
-	},
-	{
-		 ATH10K_HTC_SVC_ID_RSVD_CTRL,
-		 PIPEDIR_IN,		/* in = DL = target -> host */
-		 1,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS,	/* not currently used */
-		 PIPEDIR_OUT,		/* out = UL = host -> target */
-		 0,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS,	/* not currently used */
-		 PIPEDIR_IN,		/* in = DL = target -> host */
-		 1,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_HTT_DATA_MSG,
-		 PIPEDIR_OUT,		/* out = UL = host -> target */
-		 4,
-	},
-	{
-		 ATH10K_HTC_SVC_ID_HTT_DATA_MSG,
-		 PIPEDIR_IN,		/* in = DL = target -> host */
-		 1,
-	},
-
-	/* (Additions here) */
-
-	{				/* Must be last */
-		 0,
-		 0,
-		 0,
-	},
-};
-
-/*
  * Send an interrupt to the device to wake up the Target CPU
  * so it has an opportunity to notice any changed state.
  */
 static int ath10k_pci_wake_target_cpu(struct ath10k *ar)
 {
-	int ret;
-	u32 core_ctrl;
+	u32 addr, val;
 
-	ret = ath10k_pci_diag_read_access(ar, SOC_CORE_BASE_ADDRESS |
-					      CORE_CTRL_ADDRESS,
-					  &core_ctrl);
-	if (ret) {
-		ath10k_warn("failed to read core_ctrl: %d\n", ret);
-		return ret;
-	}
-
-	/* A_INUM_FIRMWARE interrupt to Target CPU */
-	core_ctrl |= CORE_CTRL_CPU_INTR_MASK;
-
-	ret = ath10k_pci_diag_write_access(ar, SOC_CORE_BASE_ADDRESS |
-					       CORE_CTRL_ADDRESS,
-					   core_ctrl);
-	if (ret) {
-		ath10k_warn("failed to set target CPU interrupt mask: %d\n",
-			    ret);
-		return ret;
-	}
+	addr = SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS;
+	val = ath10k_pci_read32(ar, addr);
+	val |= CORE_CTRL_CPU_INTR_MASK;
+	ath10k_pci_write32(ar, addr, val);
 
 	return 0;
 }
@@ -1602,92 +1448,92 @@
 		host_interest_item_address(HI_ITEM(hi_interconnect_state));
 
 	/* Supply Target-side CE configuration */
-	ret = ath10k_pci_diag_read_access(ar, interconnect_targ_addr,
-					  &pcie_state_targ_addr);
+	ret = ath10k_pci_diag_read32(ar, interconnect_targ_addr,
+				     &pcie_state_targ_addr);
 	if (ret != 0) {
-		ath10k_err("Failed to get pcie state addr: %d\n", ret);
+		ath10k_err(ar, "Failed to get pcie state addr: %d\n", ret);
 		return ret;
 	}
 
 	if (pcie_state_targ_addr == 0) {
 		ret = -EIO;
-		ath10k_err("Invalid pcie state addr\n");
+		ath10k_err(ar, "Invalid pcie state addr\n");
 		return ret;
 	}
 
-	ret = ath10k_pci_diag_read_access(ar, pcie_state_targ_addr +
+	ret = ath10k_pci_diag_read32(ar, (pcie_state_targ_addr +
 					  offsetof(struct pcie_state,
-						   pipe_cfg_addr),
-					  &pipe_cfg_targ_addr);
+						   pipe_cfg_addr)),
+				     &pipe_cfg_targ_addr);
 	if (ret != 0) {
-		ath10k_err("Failed to get pipe cfg addr: %d\n", ret);
+		ath10k_err(ar, "Failed to get pipe cfg addr: %d\n", ret);
 		return ret;
 	}
 
 	if (pipe_cfg_targ_addr == 0) {
 		ret = -EIO;
-		ath10k_err("Invalid pipe cfg addr\n");
+		ath10k_err(ar, "Invalid pipe cfg addr\n");
 		return ret;
 	}
 
 	ret = ath10k_pci_diag_write_mem(ar, pipe_cfg_targ_addr,
-				 target_ce_config_wlan,
-				 sizeof(target_ce_config_wlan));
+					target_ce_config_wlan,
+					sizeof(target_ce_config_wlan));
 
 	if (ret != 0) {
-		ath10k_err("Failed to write pipe cfg: %d\n", ret);
+		ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret);
 		return ret;
 	}
 
-	ret = ath10k_pci_diag_read_access(ar, pcie_state_targ_addr +
+	ret = ath10k_pci_diag_read32(ar, (pcie_state_targ_addr +
 					  offsetof(struct pcie_state,
-						   svc_to_pipe_map),
-					  &svc_to_pipe_map);
+						   svc_to_pipe_map)),
+				     &svc_to_pipe_map);
 	if (ret != 0) {
-		ath10k_err("Failed to get svc/pipe map: %d\n", ret);
+		ath10k_err(ar, "Failed to get svc/pipe map: %d\n", ret);
 		return ret;
 	}
 
 	if (svc_to_pipe_map == 0) {
 		ret = -EIO;
-		ath10k_err("Invalid svc_to_pipe map\n");
+		ath10k_err(ar, "Invalid svc_to_pipe map\n");
 		return ret;
 	}
 
 	ret = ath10k_pci_diag_write_mem(ar, svc_to_pipe_map,
-				 target_service_to_ce_map_wlan,
-				 sizeof(target_service_to_ce_map_wlan));
+					target_service_to_ce_map_wlan,
+					sizeof(target_service_to_ce_map_wlan));
 	if (ret != 0) {
-		ath10k_err("Failed to write svc/pipe map: %d\n", ret);
+		ath10k_err(ar, "Failed to write svc/pipe map: %d\n", ret);
 		return ret;
 	}
 
-	ret = ath10k_pci_diag_read_access(ar, pcie_state_targ_addr +
+	ret = ath10k_pci_diag_read32(ar, (pcie_state_targ_addr +
 					  offsetof(struct pcie_state,
-						   config_flags),
-					  &pcie_config_flags);
+						   config_flags)),
+				     &pcie_config_flags);
 	if (ret != 0) {
-		ath10k_err("Failed to get pcie config_flags: %d\n", ret);
+		ath10k_err(ar, "Failed to get pcie config_flags: %d\n", ret);
 		return ret;
 	}
 
 	pcie_config_flags &= ~PCIE_CONFIG_FLAG_ENABLE_L1;
 
-	ret = ath10k_pci_diag_write_mem(ar, pcie_state_targ_addr +
-				 offsetof(struct pcie_state, config_flags),
-				 &pcie_config_flags,
-				 sizeof(pcie_config_flags));
+	ret = ath10k_pci_diag_write32(ar, (pcie_state_targ_addr +
+					   offsetof(struct pcie_state,
+						    config_flags)),
+				      pcie_config_flags);
 	if (ret != 0) {
-		ath10k_err("Failed to write pcie config_flags: %d\n", ret);
+		ath10k_err(ar, "Failed to write pcie config_flags: %d\n", ret);
 		return ret;
 	}
 
 	/* configure early allocation */
 	ealloc_targ_addr = host_interest_item_address(HI_ITEM(hi_early_alloc));
 
-	ret = ath10k_pci_diag_read_access(ar, ealloc_targ_addr, &ealloc_value);
+	ret = ath10k_pci_diag_read32(ar, ealloc_targ_addr, &ealloc_value);
 	if (ret != 0) {
-		ath10k_err("Faile to get early alloc val: %d\n", ret);
+		ath10k_err(ar, "Faile to get early alloc val: %d\n", ret);
 		return ret;
 	}
 
@@ -1697,26 +1543,26 @@
 	ealloc_value |= ((1 << HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) &
 			 HI_EARLY_ALLOC_IRAM_BANKS_MASK);
 
-	ret = ath10k_pci_diag_write_access(ar, ealloc_targ_addr, ealloc_value);
+	ret = ath10k_pci_diag_write32(ar, ealloc_targ_addr, ealloc_value);
 	if (ret != 0) {
-		ath10k_err("Failed to set early alloc val: %d\n", ret);
+		ath10k_err(ar, "Failed to set early alloc val: %d\n", ret);
 		return ret;
 	}
 
 	/* Tell Target to proceed with initialization */
 	flag2_targ_addr = host_interest_item_address(HI_ITEM(hi_option_flag2));
 
-	ret = ath10k_pci_diag_read_access(ar, flag2_targ_addr, &flag2_value);
+	ret = ath10k_pci_diag_read32(ar, flag2_targ_addr, &flag2_value);
 	if (ret != 0) {
-		ath10k_err("Failed to get option val: %d\n", ret);
+		ath10k_err(ar, "Failed to get option val: %d\n", ret);
 		return ret;
 	}
 
 	flag2_value |= HI_OPTION_EARLY_CFG_DONE;
 
-	ret = ath10k_pci_diag_write_access(ar, flag2_targ_addr, flag2_value);
+	ret = ath10k_pci_diag_write32(ar, flag2_targ_addr, flag2_value);
 	if (ret != 0) {
-		ath10k_err("Failed to set option val: %d\n", ret);
+		ath10k_err(ar, "Failed to set option val: %d\n", ret);
 		return ret;
 	}
 
@@ -1730,7 +1576,7 @@
 	for (i = 0; i < CE_COUNT; i++) {
 		ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
 		if (ret) {
-			ath10k_err("failed to allocate copy engine pipe %d: %d\n",
+			ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
 				   i, ret);
 			return ret;
 		}
@@ -1761,9 +1607,11 @@
 		pipe_info->hif_ce_state = ar;
 		attr = &host_ce_config_wlan[pipe_num];
 
-		ret = ath10k_ce_init_pipe(ar, pipe_num, attr);
+		ret = ath10k_ce_init_pipe(ar, pipe_num, attr,
+					  ath10k_pci_ce_send_done,
+					  ath10k_pci_ce_recv_data);
 		if (ret) {
-			ath10k_err("failed to initialize copy engine pipe %d: %d\n",
+			ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",
 				   pipe_num, ret);
 			return ret;
 		}
@@ -1777,38 +1625,25 @@
 			continue;
 		}
 
-		pipe_info->buf_sz = (size_t) (attr->src_sz_max);
+		pipe_info->buf_sz = (size_t)(attr->src_sz_max);
 	}
 
 	return 0;
 }
 
-static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
+static bool ath10k_pci_has_fw_crashed(struct ath10k *ar)
 {
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	u32 fw_indicator;
+	return ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS) &
+	       FW_IND_EVENT_PENDING;
+}
 
-	ath10k_pci_wake(ar);
+static void ath10k_pci_fw_crashed_clear(struct ath10k *ar)
+{
+	u32 val;
 
-	fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
-
-	if (fw_indicator & FW_IND_EVENT_PENDING) {
-		/* ACK: clear Target-side pending event */
-		ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
-				   fw_indicator & ~FW_IND_EVENT_PENDING);
-
-		if (ar_pci->started) {
-			ath10k_pci_hif_dump_area(ar);
-		} else {
-			/*
-			 * Probable Target failure before we're prepared
-			 * to handle it.  Generally unexpected.
-			 */
-			ath10k_warn("early firmware event indicated\n");
-		}
-	}
-
-	ath10k_pci_sleep(ar);
+	val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
+	val &= ~FW_IND_EVENT_PENDING;
+	ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val);
 }
 
 /* this function effectively clears target memory controller assert line */
@@ -1833,25 +1668,19 @@
 
 static int ath10k_pci_warm_reset(struct ath10k *ar)
 {
-	int ret = 0;
 	u32 val;
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n");
-
-	ret = ath10k_do_pci_wake(ar);
-	if (ret) {
-		ath10k_err("failed to wake up target: %d\n", ret);
-		return ret;
-	}
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n");
 
 	/* debug */
 	val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
 				PCIE_INTR_CAUSE_ADDRESS);
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n",
+		   val);
 
 	val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
 				CPU_INTR_ADDRESS);
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
 		   val);
 
 	/* disable pending irqs */
@@ -1894,11 +1723,12 @@
 	/* debug */
 	val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
 				PCIE_INTR_CAUSE_ADDRESS);
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n",
+		   val);
 
 	val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
 				CPU_INTR_ADDRESS);
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
 		   val);
 
 	/* CPU warm reset */
@@ -1909,20 +1739,18 @@
 
 	val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
 				SOC_RESET_CONTROL_ADDRESS);
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val);
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n",
+		   val);
 
 	msleep(100);
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n");
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset complete\n");
 
-	ath10k_do_pci_sleep(ar);
-	return ret;
+	return 0;
 }
 
 static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
 {
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	const char *irq_mode;
 	int ret;
 
 	/*
@@ -1941,80 +1769,39 @@
 		ret = ath10k_pci_warm_reset(ar);
 
 	if (ret) {
-		ath10k_err("failed to reset target: %d\n", ret);
+		ath10k_err(ar, "failed to reset target: %d\n", ret);
 		goto err;
 	}
 
-	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
-		/* Force AWAKE forever */
-		ath10k_do_pci_wake(ar);
-
 	ret = ath10k_pci_ce_init(ar);
 	if (ret) {
-		ath10k_err("failed to initialize CE: %d\n", ret);
-		goto err_ps;
-	}
-
-	ret = ath10k_ce_disable_interrupts(ar);
-	if (ret) {
-		ath10k_err("failed to disable CE interrupts: %d\n", ret);
-		goto err_ce;
-	}
-
-	ret = ath10k_pci_init_irq(ar);
-	if (ret) {
-		ath10k_err("failed to init irqs: %d\n", ret);
-		goto err_ce;
-	}
-
-	ret = ath10k_pci_request_early_irq(ar);
-	if (ret) {
-		ath10k_err("failed to request early irq: %d\n", ret);
-		goto err_deinit_irq;
+		ath10k_err(ar, "failed to initialize CE: %d\n", ret);
+		goto err;
 	}
 
 	ret = ath10k_pci_wait_for_target_init(ar);
 	if (ret) {
-		ath10k_err("failed to wait for target to init: %d\n", ret);
-		goto err_free_early_irq;
+		ath10k_err(ar, "failed to wait for target to init: %d\n", ret);
+		goto err_ce;
 	}
 
 	ret = ath10k_pci_init_config(ar);
 	if (ret) {
-		ath10k_err("failed to setup init config: %d\n", ret);
-		goto err_free_early_irq;
+		ath10k_err(ar, "failed to setup init config: %d\n", ret);
+		goto err_ce;
 	}
 
 	ret = ath10k_pci_wake_target_cpu(ar);
 	if (ret) {
-		ath10k_err("could not wake up target CPU: %d\n", ret);
-		goto err_free_early_irq;
+		ath10k_err(ar, "could not wake up target CPU: %d\n", ret);
+		goto err_ce;
 	}
 
-	if (ar_pci->num_msi_intrs > 1)
-		irq_mode = "MSI-X";
-	else if (ar_pci->num_msi_intrs == 1)
-		irq_mode = "MSI";
-	else
-		irq_mode = "legacy";
-
-	if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
-		ath10k_info("pci irq %s irq_mode %d reset_mode %d\n",
-			    irq_mode, ath10k_pci_irq_mode,
-			    ath10k_pci_reset_mode);
-
 	return 0;
 
-err_free_early_irq:
-	ath10k_pci_free_early_irq(ar);
-err_deinit_irq:
-	ath10k_pci_deinit_irq(ar);
 err_ce:
 	ath10k_pci_ce_deinit(ar);
 	ath10k_pci_warm_reset(ar);
-err_ps:
-	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
-		ath10k_do_pci_sleep(ar);
 err:
 	return ret;
 }
@@ -2034,7 +1821,7 @@
 		if (ret == 0)
 			break;
 
-		ath10k_warn("failed to warm reset (attempt %d out of %d): %d\n",
+		ath10k_warn(ar, "failed to warm reset (attempt %d out of %d): %d\n",
 			    i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret);
 	}
 
@@ -2045,7 +1832,7 @@
 {
 	int ret;
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power up\n");
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n");
 
 	/*
 	 * Hardware CUS232 version 2 has some issues with cold reset and the
@@ -2057,17 +1844,17 @@
 	 */
 	ret = ath10k_pci_hif_power_up_warm(ar);
 	if (ret) {
-		ath10k_warn("failed to power up target using warm reset: %d\n",
+		ath10k_warn(ar, "failed to power up target using warm reset: %d\n",
 			    ret);
 
 		if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY)
 			return ret;
 
-		ath10k_warn("trying cold reset\n");
+		ath10k_warn(ar, "trying cold reset\n");
 
 		ret = __ath10k_pci_hif_power_up(ar, true);
 		if (ret) {
-			ath10k_err("failed to power up target using cold reset too (%d)\n",
+			ath10k_err(ar, "failed to power up target using cold reset too (%d)\n",
 				   ret);
 			return ret;
 		}
@@ -2078,18 +1865,9 @@
 
 static void ath10k_pci_hif_power_down(struct ath10k *ar)
 {
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n");
-
-	ath10k_pci_free_early_irq(ar);
-	ath10k_pci_kill_tasklet(ar);
-	ath10k_pci_deinit_irq(ar);
-	ath10k_pci_ce_deinit(ar);
 	ath10k_pci_warm_reset(ar);
-
-	if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
-		ath10k_do_pci_sleep(ar);
 }
 
 #ifdef CONFIG_PM
@@ -2171,7 +1949,13 @@
 {
 	struct ath10k *ar = (struct ath10k *)data;
 
-	ath10k_pci_fw_interrupt_handler(ar);
+	if (!ath10k_pci_has_fw_crashed(ar)) {
+		ath10k_warn(ar, "received unsolicited fw crash interrupt\n");
+		return;
+	}
+
+	ath10k_pci_fw_crashed_clear(ar);
+	ath10k_pci_fw_crashed_dump(ar);
 }
 
 /*
@@ -2185,7 +1969,8 @@
 	int ce_id = irq - ar_pci->pdev->irq - MSI_ASSIGN_CE_INITIAL;
 
 	if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_pci->pipe_info)) {
-		ath10k_warn("unexpected/invalid irq %d ce_id %d\n", irq, ce_id);
+		ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,
+			    ce_id);
 		return IRQ_HANDLED;
 	}
 
@@ -2232,36 +2017,17 @@
 	return IRQ_HANDLED;
 }
 
-static void ath10k_pci_early_irq_tasklet(unsigned long data)
-{
-	struct ath10k *ar = (struct ath10k *)data;
-	u32 fw_ind;
-	int ret;
-
-	ret = ath10k_pci_wake(ar);
-	if (ret) {
-		ath10k_warn("failed to wake target in early irq tasklet: %d\n",
-			    ret);
-		return;
-	}
-
-	fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
-	if (fw_ind & FW_IND_EVENT_PENDING) {
-		ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
-				   fw_ind & ~FW_IND_EVENT_PENDING);
-		ath10k_pci_hif_dump_area(ar);
-	}
-
-	ath10k_pci_sleep(ar);
-	ath10k_pci_enable_legacy_irq(ar);
-}
-
 static void ath10k_pci_tasklet(unsigned long data)
 {
 	struct ath10k *ar = (struct ath10k *)data;
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-	ath10k_pci_fw_interrupt_handler(ar); /* FIXME: Handle FW error */
+	if (ath10k_pci_has_fw_crashed(ar)) {
+		ath10k_pci_fw_crashed_clear(ar);
+		ath10k_pci_fw_crashed_dump(ar);
+		return;
+	}
+
 	ath10k_ce_per_engine_service_any(ar);
 
 	/* Re-enable legacy irq that was disabled in the irq handler */
@@ -2278,7 +2044,7 @@
 			  ath10k_pci_msi_fw_handler,
 			  IRQF_SHARED, "ath10k_pci", ar);
 	if (ret) {
-		ath10k_warn("failed to request MSI-X fw irq %d: %d\n",
+		ath10k_warn(ar, "failed to request MSI-X fw irq %d: %d\n",
 			    ar_pci->pdev->irq + MSI_ASSIGN_FW, ret);
 		return ret;
 	}
@@ -2288,7 +2054,7 @@
 				  ath10k_pci_per_engine_handler,
 				  IRQF_SHARED, "ath10k_pci", ar);
 		if (ret) {
-			ath10k_warn("failed to request MSI-X ce irq %d: %d\n",
+			ath10k_warn(ar, "failed to request MSI-X ce irq %d: %d\n",
 				    ar_pci->pdev->irq + i, ret);
 
 			for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--)
@@ -2311,7 +2077,7 @@
 			  ath10k_pci_interrupt_handler,
 			  IRQF_SHARED, "ath10k_pci", ar);
 	if (ret) {
-		ath10k_warn("failed to request MSI irq %d: %d\n",
+		ath10k_warn(ar, "failed to request MSI irq %d: %d\n",
 			    ar_pci->pdev->irq, ret);
 		return ret;
 	}
@@ -2328,7 +2094,7 @@
 			  ath10k_pci_interrupt_handler,
 			  IRQF_SHARED, "ath10k_pci", ar);
 	if (ret) {
-		ath10k_warn("failed to request legacy irq %d: %d\n",
+		ath10k_warn(ar, "failed to request legacy irq %d: %d\n",
 			    ar_pci->pdev->irq, ret);
 		return ret;
 	}
@@ -2349,7 +2115,7 @@
 		return ath10k_pci_request_irq_msix(ar);
 	}
 
-	ath10k_warn("unknown irq configuration upon request\n");
+	ath10k_warn(ar, "unknown irq configuration upon request\n");
 	return -EINVAL;
 }
 
@@ -2372,8 +2138,6 @@
 	tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
 	tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
 		     (unsigned long)ar);
-	tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet,
-		     (unsigned long)ar);
 
 	for (i = 0; i < CE_COUNT; i++) {
 		ar_pci->pipe_info[i].ar_pci = ar_pci;
@@ -2385,21 +2149,19 @@
 static int ath10k_pci_init_irq(struct ath10k *ar)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-	bool msix_supported = test_bit(ATH10K_PCI_FEATURE_MSI_X,
-				       ar_pci->features);
 	int ret;
 
 	ath10k_pci_init_irq_tasklets(ar);
 
-	if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO &&
-	    !test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
-		ath10k_info("limiting irq mode to: %d\n", ath10k_pci_irq_mode);
+	if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO)
+		ath10k_info(ar, "limiting irq mode to: %d\n",
+			    ath10k_pci_irq_mode);
 
 	/* Try MSI-X */
-	if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) {
+	if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) {
 		ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
 		ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
-							 ar_pci->num_msi_intrs);
+					   ar_pci->num_msi_intrs);
 		if (ret > 0)
 			return 0;
 
@@ -2426,34 +2188,16 @@
 	 * synchronization checking. */
 	ar_pci->num_msi_intrs = 0;
 
-	ret = ath10k_pci_wake(ar);
-	if (ret) {
-		ath10k_warn("failed to wake target: %d\n", ret);
-		return ret;
-	}
-
 	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
 			   PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
-	ath10k_pci_sleep(ar);
 
 	return 0;
 }
 
-static int ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
+static void ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
 {
-	int ret;
-
-	ret = ath10k_pci_wake(ar);
-	if (ret) {
-		ath10k_warn("failed to wake target: %d\n", ret);
-		return ret;
-	}
-
 	ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
 			   0);
-	ath10k_pci_sleep(ar);
-
-	return 0;
 }
 
 static int ath10k_pci_deinit_irq(struct ath10k *ar)
@@ -2462,7 +2206,8 @@
 
 	switch (ar_pci->num_msi_intrs) {
 	case 0:
-		return ath10k_pci_deinit_irq_legacy(ar);
+		ath10k_pci_deinit_irq_legacy(ar);
+		return 0;
 	case 1:
 		/* fall-through */
 	case MSI_NUM_REQUEST:
@@ -2472,7 +2217,7 @@
 		pci_disable_msi(ar_pci->pdev);
 	}
 
-	ath10k_warn("unknown irq configuration upon deinit\n");
+	ath10k_warn(ar, "unknown irq configuration upon deinit\n");
 	return -EINVAL;
 }
 
@@ -2480,23 +2225,17 @@
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 	unsigned long timeout;
-	int ret;
 	u32 val;
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n");
-
-	ret = ath10k_pci_wake(ar);
-	if (ret) {
-		ath10k_err("failed to wake up target for init: %d\n", ret);
-		return ret;
-	}
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot waiting target to initialise\n");
 
 	timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT);
 
 	do {
 		val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
 
-		ath10k_dbg(ATH10K_DBG_BOOT, "boot target indicator %x\n", val);
+		ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target indicator %x\n",
+			   val);
 
 		/* target should never return this */
 		if (val == 0xffffffff)
@@ -2511,55 +2250,42 @@
 
 		if (ar_pci->num_msi_intrs == 0)
 			/* Fix potential race by repeating CORE_BASE writes */
-			ath10k_pci_soc_write32(ar, PCIE_INTR_ENABLE_ADDRESS,
-					       PCIE_INTR_FIRMWARE_MASK |
-					       PCIE_INTR_CE_MASK_ALL);
+			ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+					   PCIE_INTR_ENABLE_ADDRESS,
+					   PCIE_INTR_FIRMWARE_MASK |
+					   PCIE_INTR_CE_MASK_ALL);
 
 		mdelay(10);
 	} while (time_before(jiffies, timeout));
 
 	if (val == 0xffffffff) {
-		ath10k_err("failed to read device register, device is gone\n");
-		ret = -EIO;
-		goto out;
+		ath10k_err(ar, "failed to read device register, device is gone\n");
+		return -EIO;
 	}
 
 	if (val & FW_IND_EVENT_PENDING) {
-		ath10k_warn("device has crashed during init\n");
-		ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
-				   val & ~FW_IND_EVENT_PENDING);
-		ath10k_pci_hif_dump_area(ar);
-		ret = -ECOMM;
-		goto out;
+		ath10k_warn(ar, "device has crashed during init\n");
+		ath10k_pci_fw_crashed_clear(ar);
+		ath10k_pci_fw_crashed_dump(ar);
+		return -ECOMM;
 	}
 
 	if (!(val & FW_IND_INITIALIZED)) {
-		ath10k_err("failed to receive initialized event from target: %08x\n",
+		ath10k_err(ar, "failed to receive initialized event from target: %08x\n",
 			   val);
-		ret = -ETIMEDOUT;
-		goto out;
+		return -ETIMEDOUT;
 	}
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n");
-
-out:
-	ath10k_pci_sleep(ar);
-	return ret;
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target initialised\n");
+	return 0;
 }
 
 static int ath10k_pci_cold_reset(struct ath10k *ar)
 {
-	int i, ret;
+	int i;
 	u32 val;
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n");
-
-	ret = ath10k_do_pci_wake(ar);
-	if (ret) {
-		ath10k_err("failed to wake up target: %d\n",
-			   ret);
-		return ret;
-	}
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n");
 
 	/* Put Target, including PCIe, into RESET. */
 	val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS);
@@ -2584,169 +2310,199 @@
 		msleep(1);
 	}
 
-	ath10k_do_pci_sleep(ar);
-
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n");
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n");
 
 	return 0;
 }
 
-static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
+static int ath10k_pci_claim(struct ath10k *ar)
 {
-	int i;
-
-	for (i = 0; i < ATH10K_PCI_FEATURE_COUNT; i++) {
-		if (!test_bit(i, ar_pci->features))
-			continue;
-
-		switch (i) {
-		case ATH10K_PCI_FEATURE_MSI_X:
-			ath10k_dbg(ATH10K_DBG_BOOT, "device supports MSI-X\n");
-			break;
-		case ATH10K_PCI_FEATURE_SOC_POWER_SAVE:
-			ath10k_dbg(ATH10K_DBG_BOOT, "QCA98XX SoC power save enabled\n");
-			break;
-		}
-	}
-}
-
-static int ath10k_pci_probe(struct pci_dev *pdev,
-			    const struct pci_device_id *pci_dev)
-{
-	void __iomem *mem;
-	int ret = 0;
-	struct ath10k *ar;
-	struct ath10k_pci *ar_pci;
-	u32 lcr_val, chip_id;
-
-	ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n");
-
-	ar_pci = kzalloc(sizeof(*ar_pci), GFP_KERNEL);
-	if (ar_pci == NULL)
-		return -ENOMEM;
-
-	ar_pci->pdev = pdev;
-	ar_pci->dev = &pdev->dev;
-
-	switch (pci_dev->device) {
-	case QCA988X_2_0_DEVICE_ID:
-		set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features);
-		break;
-	default:
-		ret = -ENODEV;
-		ath10k_err("Unknown device ID: %d\n", pci_dev->device);
-		goto err_ar_pci;
-	}
-
-	if (ath10k_pci_target_ps)
-		set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features);
-
-	ath10k_pci_dump_features(ar_pci);
-
-	ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops);
-	if (!ar) {
-		ath10k_err("failed to create driver core\n");
-		ret = -EINVAL;
-		goto err_ar_pci;
-	}
-
-	ar_pci->ar = ar;
-	atomic_set(&ar_pci->keep_awake_count, 0);
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	struct pci_dev *pdev = ar_pci->pdev;
+	u32 lcr_val;
+	int ret;
 
 	pci_set_drvdata(pdev, ar);
 
 	ret = pci_enable_device(pdev);
 	if (ret) {
-		ath10k_err("failed to enable PCI device: %d\n", ret);
-		goto err_ar;
+		ath10k_err(ar, "failed to enable pci device: %d\n", ret);
+		return ret;
 	}
 
-	/* Request MMIO resources */
 	ret = pci_request_region(pdev, BAR_NUM, "ath");
 	if (ret) {
-		ath10k_err("failed to request MMIO region: %d\n", ret);
+		ath10k_err(ar, "failed to request region BAR%d: %d\n", BAR_NUM,
+			   ret);
 		goto err_device;
 	}
 
-	/*
-	 * Target structures have a limit of 32 bit DMA pointers.
-	 * DMA pointers can be wider than 32 bits by default on some systems.
-	 */
+	/* Target expects 32 bit DMA. Enforce it. */
 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 	if (ret) {
-		ath10k_err("failed to set DMA mask to 32-bit: %d\n", ret);
+		ath10k_err(ar, "failed to set dma mask to 32-bit: %d\n", ret);
 		goto err_region;
 	}
 
 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
 	if (ret) {
-		ath10k_err("failed to set consistent DMA mask to 32-bit\n");
+		ath10k_err(ar, "failed to set consistent dma mask to 32-bit: %d\n",
+			   ret);
 		goto err_region;
 	}
 
-	/* Set bus master bit in PCI_COMMAND to enable DMA */
 	pci_set_master(pdev);
 
-	/*
-	 * Temporary FIX: disable ASPM
-	 * Will be removed after the OTP is programmed
-	 */
+	/* Workaround: Disable ASPM */
 	pci_read_config_dword(pdev, 0x80, &lcr_val);
 	pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00));
 
 	/* Arrange for access to Target SoC registers. */
-	mem = pci_iomap(pdev, BAR_NUM, 0);
-	if (!mem) {
-		ath10k_err("failed to perform IOMAP for BAR%d\n", BAR_NUM);
+	ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0);
+	if (!ar_pci->mem) {
+		ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM);
 		ret = -EIO;
 		goto err_master;
 	}
 
-	ar_pci->mem = mem;
+	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
+	return 0;
+
+err_master:
+	pci_clear_master(pdev);
+
+err_region:
+	pci_release_region(pdev, BAR_NUM);
+
+err_device:
+	pci_disable_device(pdev);
+
+	return ret;
+}
+
+static void ath10k_pci_release(struct ath10k *ar)
+{
+	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+	struct pci_dev *pdev = ar_pci->pdev;
+
+	pci_iounmap(pdev, ar_pci->mem);
+	pci_release_region(pdev, BAR_NUM);
+	pci_clear_master(pdev);
+	pci_disable_device(pdev);
+}
+
+static int ath10k_pci_probe(struct pci_dev *pdev,
+			    const struct pci_device_id *pci_dev)
+{
+	int ret = 0;
+	struct ath10k *ar;
+	struct ath10k_pci *ar_pci;
+	u32 chip_id;
+
+	ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev,
+				&ath10k_pci_hif_ops);
+	if (!ar) {
+		dev_err(&pdev->dev, "failed to allocate core\n");
+		return -ENOMEM;
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_PCI, "pci probe\n");
+
+	ar_pci = ath10k_pci_priv(ar);
+	ar_pci->pdev = pdev;
+	ar_pci->dev = &pdev->dev;
+	ar_pci->ar = ar;
 
 	spin_lock_init(&ar_pci->ce_lock);
+	setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
+		    (unsigned long)ar);
 
-	ret = ath10k_do_pci_wake(ar);
+	ret = ath10k_pci_claim(ar);
 	if (ret) {
-		ath10k_err("Failed to get chip id: %d\n", ret);
-		goto err_iomap;
+		ath10k_err(ar, "failed to claim device: %d\n", ret);
+		goto err_core_destroy;
+	}
+
+	ret = ath10k_pci_wake(ar);
+	if (ret) {
+		ath10k_err(ar, "failed to wake up: %d\n", ret);
+		goto err_release;
 	}
 
 	chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
-
-	ath10k_do_pci_sleep(ar);
+	if (chip_id == 0xffffffff) {
+		ath10k_err(ar, "failed to get chip id\n");
+		goto err_sleep;
+	}
 
 	ret = ath10k_pci_alloc_ce(ar);
 	if (ret) {
-		ath10k_err("failed to allocate copy engine pipes: %d\n", ret);
-		goto err_iomap;
+		ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
+			   ret);
+		goto err_sleep;
 	}
 
-	ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
+	ath10k_pci_ce_deinit(ar);
+
+	ret = ath10k_ce_disable_interrupts(ar);
+	if (ret) {
+		ath10k_err(ar, "failed to disable copy engine interrupts: %d\n",
+			   ret);
+		goto err_free_ce;
+	}
+
+	/* Workaround: There's no known way to mask all possible interrupts via
+	 * device CSR. The only way to make sure device doesn't assert
+	 * interrupts is to reset it. Interrupts are then disabled on host
+	 * after handlers are registered.
+	 */
+	ath10k_pci_warm_reset(ar);
+
+	ret = ath10k_pci_init_irq(ar);
+	if (ret) {
+		ath10k_err(ar, "failed to init irqs: %d\n", ret);
+		goto err_free_ce;
+	}
+
+	ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
+		    ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs,
+		    ath10k_pci_irq_mode, ath10k_pci_reset_mode);
+
+	ret = ath10k_pci_request_irq(ar);
+	if (ret) {
+		ath10k_warn(ar, "failed to request irqs: %d\n", ret);
+		goto err_deinit_irq;
+	}
+
+	/* This shouldn't race as the device has been reset above. */
+	ath10k_pci_irq_disable(ar);
 
 	ret = ath10k_core_register(ar, chip_id);
 	if (ret) {
-		ath10k_err("failed to register driver core: %d\n", ret);
-		goto err_free_ce;
+		ath10k_err(ar, "failed to register driver core: %d\n", ret);
+		goto err_free_irq;
 	}
 
 	return 0;
 
+err_free_irq:
+	ath10k_pci_free_irq(ar);
+	ath10k_pci_kill_tasklet(ar);
+
+err_deinit_irq:
+	ath10k_pci_deinit_irq(ar);
+
 err_free_ce:
 	ath10k_pci_free_ce(ar);
-err_iomap:
-	pci_iounmap(pdev, mem);
-err_master:
-	pci_clear_master(pdev);
-err_region:
-	pci_release_region(pdev, BAR_NUM);
-err_device:
-	pci_disable_device(pdev);
-err_ar:
+
+err_sleep:
+	ath10k_pci_sleep(ar);
+
+err_release:
+	ath10k_pci_release(ar);
+
+err_core_destroy:
 	ath10k_core_destroy(ar);
-err_ar_pci:
-	/* call HIF PCI free here */
-	kfree(ar_pci);
 
 	return ret;
 }
@@ -2756,7 +2512,7 @@
 	struct ath10k *ar = pci_get_drvdata(pdev);
 	struct ath10k_pci *ar_pci;
 
-	ath10k_dbg(ATH10K_DBG_PCI, "pci remove\n");
+	ath10k_dbg(ar, ATH10K_DBG_PCI, "pci remove\n");
 
 	if (!ar)
 		return;
@@ -2767,15 +2523,14 @@
 		return;
 
 	ath10k_core_unregister(ar);
+	ath10k_pci_free_irq(ar);
+	ath10k_pci_kill_tasklet(ar);
+	ath10k_pci_deinit_irq(ar);
+	ath10k_pci_ce_deinit(ar);
 	ath10k_pci_free_ce(ar);
-
-	pci_iounmap(pdev, ar_pci->mem);
-	pci_release_region(pdev, BAR_NUM);
-	pci_clear_master(pdev);
-	pci_disable_device(pdev);
-
+	ath10k_pci_sleep(ar);
+	ath10k_pci_release(ar);
 	ath10k_core_destroy(ar);
-	kfree(ar_pci);
 }
 
 MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table);
@@ -2793,7 +2548,8 @@
 
 	ret = pci_register_driver(&ath10k_pci_driver);
 	if (ret)
-		ath10k_err("failed to register PCI driver: %d\n", ret);
+		printk(KERN_ERR "failed to register ath10k pci driver: %d\n",
+		       ret);
 
 	return ret;
 }
@@ -2809,5 +2565,5 @@
 MODULE_AUTHOR("Qualcomm Atheros");
 MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_3_FILE);
 MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index 9401292..cf36511 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -23,9 +23,6 @@
 #include "hw.h"
 #include "ce.h"
 
-/* FW dump area */
-#define REG_DUMP_COUNT_QCA988X 60
-
 /*
  * maximum number of bytes that can be handled atomically by DiagRead/DiagWrite
  */
@@ -103,12 +100,12 @@
  * NOTE: Structure is shared between Host software and Target firmware!
  */
 struct ce_pipe_config {
-	u32 pipenum;
-	u32 pipedir;
-	u32 nentries;
-	u32 nbytes_max;
-	u32 flags;
-	u32 reserved;
+	__le32 pipenum;
+	__le32 pipedir;
+	__le32 nentries;
+	__le32 nbytes_max;
+	__le32 flags;
+	__le32 reserved;
 };
 
 /*
@@ -130,17 +127,9 @@
 
 /* Establish a mapping between a service/direction and a pipe. */
 struct service_to_pipe {
-	u32 service_id;
-	u32 pipedir;
-	u32 pipenum;
-};
-
-enum ath10k_pci_features {
-	ATH10K_PCI_FEATURE_MSI_X		= 0,
-	ATH10K_PCI_FEATURE_SOC_POWER_SAVE	= 1,
-
-	/* keep last */
-	ATH10K_PCI_FEATURE_COUNT
+	__le32 service_id;
+	__le32 pipedir;
+	__le32 pipenum;
 };
 
 /* Per-pipe state. */
@@ -169,8 +158,6 @@
 	struct ath10k *ar;
 	void __iomem *mem;
 
-	DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT);
-
 	/*
 	 * Number of MSI interrupts granted, 0 --> using legacy PCI line
 	 * interrupts.
@@ -179,12 +166,6 @@
 
 	struct tasklet_struct intr_tq;
 	struct tasklet_struct msi_fw_err;
-	struct tasklet_struct early_irq_tasklet;
-
-	int started;
-
-	atomic_t keep_awake_count;
-	bool verified_awake;
 
 	struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
 
@@ -198,27 +179,15 @@
 
 	/* Map CE id to ce_state */
 	struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
+	struct timer_list rx_post_retry;
 };
 
 static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
 {
-	return ar->hif.priv;
+	return (struct ath10k_pci *)ar->drv_priv;
 }
 
-static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
-{
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
-	return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
-}
-
-static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
-{
-	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
-	iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
-}
-
+#define ATH10K_PCI_RX_POST_RETRY_MS 50
 #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */
 #define PCIE_WAKE_TIMEOUT 5000	/* 5ms */
 
@@ -242,35 +211,17 @@
 /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
 #define DIAG_ACCESS_CE_TIMEOUT_MS 10
 
-/*
- * This API allows the Host to access Target registers directly
- * and relatively efficiently over PCIe.
- * This allows the Host to avoid extra overhead associated with
- * sending a message to firmware and waiting for a response message
- * from firmware, as is done on other interconnects.
+/* Target exposes its registers for direct access. However before host can
+ * access them it needs to make sure the target is awake (ath10k_pci_wake,
+ * ath10k_pci_wake_wait, ath10k_pci_is_awake). Once target is awake it won't go
+ * to sleep unless host tells it to (ath10k_pci_sleep).
  *
- * Yet there is some complexity with direct accesses because the
- * Target's power state is not known a priori. The Host must issue
- * special PCIe reads/writes in order to explicitly wake the Target
- * and to verify that it is awake and will remain awake.
+ * If host tries to access target registers without waking it up it can
+ * scribble over host memory.
  *
- * Usage:
- *
- *   Use ath10k_pci_read32 and ath10k_pci_write32 to access Target space.
- *   These calls must be bracketed by ath10k_pci_wake and
- *   ath10k_pci_sleep.  A single BEGIN/END pair is adequate for
- *   multiple READ/WRITE operations.
- *
- *   Use ath10k_pci_wake to put the Target in a state in
- *   which it is legal for the Host to directly access it. This
- *   may involve waking the Target from a low power state, which
- *   may take up to 2Ms!
- *
- *   Use ath10k_pci_sleep to tell the Target that as far as
- *   this code path is concerned, it no longer needs to remain
- *   directly accessible.  BEGIN/END is under a reference counter;
- *   multiple code paths may issue BEGIN/END on a single targid.
+ * If target is asleep waking it up may take up to even 2ms.
  */
+
 static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
 				      u32 value)
 {
@@ -296,25 +247,18 @@
 	ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val);
 }
 
-int ath10k_do_pci_wake(struct ath10k *ar);
-void ath10k_do_pci_sleep(struct ath10k *ar);
-
-static inline int ath10k_pci_wake(struct ath10k *ar)
+static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-	if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
-		return ath10k_do_pci_wake(ar);
-
-	return 0;
+	return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
 }
 
-static inline void ath10k_pci_sleep(struct ath10k *ar)
+static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-	if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
-		ath10k_do_pci_sleep(ar);
+	iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
 }
 
 #endif /* _PCI_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h
index 1c584c4..e1ffdd5 100644
--- a/drivers/net/wireless/ath/ath10k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath10k/rx_desc.h
@@ -839,7 +839,6 @@
  *		Reserved: HW should fill with 0, FW should ignore.
 */
 
-
 #define RX_PPDU_END_FLAGS_PHY_ERR             (1 << 0)
 #define RX_PPDU_END_FLAGS_RX_LOCATION         (1 << 1)
 #define RX_PPDU_END_FLAGS_TXBF_H_INFO         (1 << 2)
diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c
new file mode 100644
index 0000000..f45b90f
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/spectral.c
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/relay.h>
+#include "core.h"
+#include "debug.h"
+
+static void send_fft_sample(struct ath10k *ar,
+			    const struct fft_sample_tlv *fft_sample_tlv)
+{
+	int length;
+
+	if (!ar->spectral.rfs_chan_spec_scan)
+		return;
+
+	length = __be16_to_cpu(fft_sample_tlv->length) +
+		 sizeof(*fft_sample_tlv);
+	relay_write(ar->spectral.rfs_chan_spec_scan, fft_sample_tlv, length);
+}
+
+static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len,
+			   u8 *data)
+{
+	int dc_pos;
+	u8 max_exp;
+
+	dc_pos = bin_len / 2;
+
+	/* peak index outside of bins */
+	if (dc_pos < max_index || -dc_pos >= max_index)
+		return 0;
+
+	for (max_exp = 0; max_exp < 8; max_exp++) {
+		if (data[dc_pos + max_index] == (max_magnitude >> max_exp))
+			break;
+	}
+
+	/* max_exp not found */
+	if (data[dc_pos + max_index] != (max_magnitude >> max_exp))
+		return 0;
+
+	return max_exp;
+}
+
+int ath10k_spectral_process_fft(struct ath10k *ar,
+				struct wmi_single_phyerr_rx_event *event,
+				struct phyerr_fft_report *fftr,
+				size_t bin_len, u64 tsf)
+{
+	struct fft_sample_ath10k *fft_sample;
+	u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS];
+	u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag;
+	u32 reg0, reg1, nf_list1, nf_list2;
+	u8 chain_idx, *bins;
+	int dc_pos;
+
+	fft_sample = (struct fft_sample_ath10k *)&buf;
+
+	if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS)
+		return -EINVAL;
+
+	reg0 = __le32_to_cpu(fftr->reg0);
+	reg1 = __le32_to_cpu(fftr->reg1);
+
+	length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + bin_len;
+	fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH10K;
+	fft_sample->tlv.length = __cpu_to_be16(length);
+
+	/* TODO: there might be a reason why the hardware reports 20/40/80 MHz,
+	 * but the results/plots suggest that its actually 22/44/88 MHz.
+	 */
+	switch (event->hdr.chan_width_mhz) {
+	case 20:
+		fft_sample->chan_width_mhz = 22;
+		break;
+	case 40:
+		fft_sample->chan_width_mhz = 44;
+		break;
+	case 80:
+		/* TODO: As experiments with an analogue sender and various
+		 * configuaritions (fft-sizes of 64/128/256 and 20/40/80 Mhz)
+		 * show, the particular configuration of 80 MHz/64 bins does
+		 * not match with the other smaples at all. Until the reason
+		 * for that is found, don't report these samples.
+		 */
+		if (bin_len == 64)
+			return -EINVAL;
+		fft_sample->chan_width_mhz = 88;
+		break;
+	default:
+		fft_sample->chan_width_mhz = event->hdr.chan_width_mhz;
+	}
+
+	fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB);
+	fft_sample->avgpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB);
+
+	peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
+	fft_sample->max_magnitude = __cpu_to_be16(peak_mag);
+	fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX);
+	fft_sample->rssi = event->hdr.rssi_combined;
+
+	total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB);
+	base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB);
+	fft_sample->total_gain_db = __cpu_to_be16(total_gain_db);
+	fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db);
+
+	freq1 = __le16_to_cpu(event->hdr.freq1);
+	freq2 = __le16_to_cpu(event->hdr.freq2);
+	fft_sample->freq1 = __cpu_to_be16(freq1);
+	fft_sample->freq2 = __cpu_to_be16(freq2);
+
+	nf_list1 = __le32_to_cpu(event->hdr.nf_list_1);
+	nf_list2 = __le32_to_cpu(event->hdr.nf_list_2);
+	chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX);
+
+	switch (chain_idx) {
+	case 0:
+		fft_sample->noise = __cpu_to_be16(nf_list1 & 0xffffu);
+		break;
+	case 1:
+		fft_sample->noise = __cpu_to_be16((nf_list1 >> 16) & 0xffffu);
+		break;
+	case 2:
+		fft_sample->noise = __cpu_to_be16(nf_list2 & 0xffffu);
+		break;
+	case 3:
+		fft_sample->noise = __cpu_to_be16((nf_list2 >> 16) & 0xffffu);
+		break;
+	}
+
+	bins = (u8 *)fftr;
+	bins += sizeof(*fftr);
+
+	fft_sample->tsf = __cpu_to_be64(tsf);
+
+	/* max_exp has been directly reported by previous hardware (ath9k),
+	 * maybe its possible to get it by other means?
+	 */
+	fft_sample->max_exp = get_max_exp(fft_sample->max_index, peak_mag,
+					  bin_len, bins);
+
+	memcpy(fft_sample->data, bins, bin_len);
+
+	/* DC value (value in the middle) is the blind spot of the spectral
+	 * sample and invalid, interpolate it.
+	 */
+	dc_pos = bin_len / 2;
+	fft_sample->data[dc_pos] = (fft_sample->data[dc_pos + 1] +
+				    fft_sample->data[dc_pos - 1]) / 2;
+
+	send_fft_sample(ar, &fft_sample->tlv);
+
+	return 0;
+}
+
+static struct ath10k_vif *ath10k_get_spectral_vdev(struct ath10k *ar)
+{
+	struct ath10k_vif *arvif;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	if (list_empty(&ar->arvifs))
+		return NULL;
+
+	/* if there already is a vif doing spectral, return that. */
+	list_for_each_entry(arvif, &ar->arvifs, list)
+		if (arvif->spectral_enabled)
+			return arvif;
+
+	/* otherwise, return the first vif. */
+	return list_first_entry(&ar->arvifs, typeof(*arvif), list);
+}
+
+static int ath10k_spectral_scan_trigger(struct ath10k *ar)
+{
+	struct ath10k_vif *arvif;
+	int res;
+	int vdev_id;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	arvif = ath10k_get_spectral_vdev(ar);
+	if (!arvif)
+		return -ENODEV;
+	vdev_id = arvif->vdev_id;
+
+	if (ar->spectral.mode == SPECTRAL_DISABLED)
+		return 0;
+
+	res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
+					      WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
+					      WMI_SPECTRAL_ENABLE_CMD_ENABLE);
+	if (res < 0)
+		return res;
+
+	res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
+					      WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
+					      WMI_SPECTRAL_ENABLE_CMD_ENABLE);
+	if (res < 0)
+		return res;
+
+	return 0;
+}
+
+static int ath10k_spectral_scan_config(struct ath10k *ar,
+				       enum ath10k_spectral_mode mode)
+{
+	struct wmi_vdev_spectral_conf_arg arg;
+	struct ath10k_vif *arvif;
+	int vdev_id, count, res = 0;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	arvif = ath10k_get_spectral_vdev(ar);
+	if (!arvif)
+		return -ENODEV;
+
+	vdev_id = arvif->vdev_id;
+
+	arvif->spectral_enabled = (mode != SPECTRAL_DISABLED);
+	ar->spectral.mode = mode;
+
+	res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
+					      WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
+					      WMI_SPECTRAL_ENABLE_CMD_DISABLE);
+	if (res < 0) {
+		ath10k_warn(ar, "failed to enable spectral scan: %d\n", res);
+		return res;
+	}
+
+	if (mode == SPECTRAL_DISABLED)
+		return 0;
+
+	if (mode == SPECTRAL_BACKGROUND)
+		count = WMI_SPECTRAL_COUNT_DEFAULT;
+	else
+		count = max_t(u8, 1, ar->spectral.config.count);
+
+	arg.vdev_id = vdev_id;
+	arg.scan_count = count;
+	arg.scan_period = WMI_SPECTRAL_PERIOD_DEFAULT;
+	arg.scan_priority = WMI_SPECTRAL_PRIORITY_DEFAULT;
+	arg.scan_fft_size = ar->spectral.config.fft_size;
+	arg.scan_gc_ena = WMI_SPECTRAL_GC_ENA_DEFAULT;
+	arg.scan_restart_ena = WMI_SPECTRAL_RESTART_ENA_DEFAULT;
+	arg.scan_noise_floor_ref = WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
+	arg.scan_init_delay = WMI_SPECTRAL_INIT_DELAY_DEFAULT;
+	arg.scan_nb_tone_thr = WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
+	arg.scan_str_bin_thr = WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
+	arg.scan_wb_rpt_mode = WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
+	arg.scan_rssi_rpt_mode = WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
+	arg.scan_rssi_thr = WMI_SPECTRAL_RSSI_THR_DEFAULT;
+	arg.scan_pwr_format = WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
+	arg.scan_rpt_mode = WMI_SPECTRAL_RPT_MODE_DEFAULT;
+	arg.scan_bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
+	arg.scan_dbm_adj = WMI_SPECTRAL_DBM_ADJ_DEFAULT;
+	arg.scan_chn_mask = WMI_SPECTRAL_CHN_MASK_DEFAULT;
+
+	res = ath10k_wmi_vdev_spectral_conf(ar, &arg);
+	if (res < 0) {
+		ath10k_warn(ar, "failed to configure spectral scan: %d\n", res);
+		return res;
+	}
+
+	return 0;
+}
+
+static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	char *mode = "";
+	unsigned int len;
+	enum ath10k_spectral_mode spectral_mode;
+
+	mutex_lock(&ar->conf_mutex);
+	spectral_mode = ar->spectral.mode;
+	mutex_unlock(&ar->conf_mutex);
+
+	switch (spectral_mode) {
+	case SPECTRAL_DISABLED:
+		mode = "disable";
+		break;
+	case SPECTRAL_BACKGROUND:
+		mode = "background";
+		break;
+	case SPECTRAL_MANUAL:
+		mode = "manual";
+		break;
+	}
+
+	len = strlen(mode);
+	return simple_read_from_buffer(user_buf, count, ppos, mode, len);
+}
+
+static ssize_t write_file_spec_scan_ctl(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	char buf[32];
+	ssize_t len;
+	int res;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (strncmp("trigger", buf, 7) == 0) {
+		if (ar->spectral.mode == SPECTRAL_MANUAL ||
+		    ar->spectral.mode == SPECTRAL_BACKGROUND) {
+			/* reset the configuration to adopt possibly changed
+			 * debugfs parameters
+			 */
+			res = ath10k_spectral_scan_config(ar,
+							  ar->spectral.mode);
+			if (res < 0) {
+				ath10k_warn(ar, "failed to reconfigure spectral scan: %d\n",
+					    res);
+			}
+			res = ath10k_spectral_scan_trigger(ar);
+			if (res < 0) {
+				ath10k_warn(ar, "failed to trigger spectral scan: %d\n",
+					    res);
+			}
+		} else {
+			res = -EINVAL;
+		}
+	} else if (strncmp("background", buf, 9) == 0) {
+		res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND);
+	} else if (strncmp("manual", buf, 6) == 0) {
+		res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL);
+	} else if (strncmp("disable", buf, 7) == 0) {
+		res = ath10k_spectral_scan_config(ar, SPECTRAL_DISABLED);
+	} else {
+		res = -EINVAL;
+	}
+
+	mutex_unlock(&ar->conf_mutex);
+
+	if (res < 0)
+		return res;
+
+	return count;
+}
+
+static const struct file_operations fops_spec_scan_ctl = {
+	.read = read_file_spec_scan_ctl,
+	.write = write_file_spec_scan_ctl,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_count(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	char buf[32];
+	unsigned int len;
+	u8 spectral_count;
+
+	mutex_lock(&ar->conf_mutex);
+	spectral_count = ar->spectral.config.count;
+	mutex_unlock(&ar->conf_mutex);
+
+	len = sprintf(buf, "%d\n", spectral_count);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_count(struct file *file,
+					 const char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	unsigned long val;
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	if (val < 0 || val > 255)
+		return -EINVAL;
+
+	mutex_lock(&ar->conf_mutex);
+	ar->spectral.config.count = val;
+	mutex_unlock(&ar->conf_mutex);
+
+	return count;
+}
+
+static const struct file_operations fops_spectral_count = {
+	.read = read_file_spectral_count,
+	.write = write_file_spectral_count,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_bins(struct file *file,
+				       char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	char buf[32];
+	unsigned int len, bins, fft_size, bin_scale;
+
+	mutex_lock(&ar->conf_mutex);
+
+	fft_size = ar->spectral.config.fft_size;
+	bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
+	bins = 1 << (fft_size - bin_scale);
+
+	mutex_unlock(&ar->conf_mutex);
+
+	len = sprintf(buf, "%d\n", bins);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_bins(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct ath10k *ar = file->private_data;
+	unsigned long val;
+	char buf[32];
+	ssize_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	if (kstrtoul(buf, 0, &val))
+		return -EINVAL;
+
+	if (val < 64 || val > SPECTRAL_ATH10K_MAX_NUM_BINS)
+		return -EINVAL;
+
+	if (!is_power_of_2(val))
+		return -EINVAL;
+
+	mutex_lock(&ar->conf_mutex);
+	ar->spectral.config.fft_size = ilog2(val);
+	ar->spectral.config.fft_size += WMI_SPECTRAL_BIN_SCALE_DEFAULT;
+	mutex_unlock(&ar->conf_mutex);
+
+	return count;
+}
+
+static const struct file_operations fops_spectral_bins = {
+	.read = read_file_spectral_bins,
+	.write = write_file_spectral_bins,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+static struct dentry *create_buf_file_handler(const char *filename,
+					      struct dentry *parent,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
+					      umode_t mode,
+#else
+					      int mode,
+#endif
+					      struct rchan_buf *buf,
+					      int *is_global)
+{
+	struct dentry *buf_file;
+
+	buf_file = debugfs_create_file(filename, mode, parent, buf,
+				       &relay_file_operations);
+	*is_global = 1;
+	return buf_file;
+}
+
+static int remove_buf_file_handler(struct dentry *dentry)
+{
+	debugfs_remove(dentry);
+
+	return 0;
+}
+
+static struct rchan_callbacks rfs_spec_scan_cb = {
+	.create_buf_file = create_buf_file_handler,
+	.remove_buf_file = remove_buf_file_handler,
+};
+
+int ath10k_spectral_start(struct ath10k *ar)
+{
+	struct ath10k_vif *arvif;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	list_for_each_entry(arvif, &ar->arvifs, list)
+		arvif->spectral_enabled = 0;
+
+	ar->spectral.mode = SPECTRAL_DISABLED;
+	ar->spectral.config.count = WMI_SPECTRAL_COUNT_DEFAULT;
+	ar->spectral.config.fft_size = WMI_SPECTRAL_FFT_SIZE_DEFAULT;
+
+	return 0;
+}
+
+int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
+{
+	if (!arvif->spectral_enabled)
+		return 0;
+
+	return ath10k_spectral_scan_config(arvif->ar, SPECTRAL_DISABLED);
+}
+
+int ath10k_spectral_create(struct ath10k *ar)
+{
+	ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan",
+						     ar->debug.debugfs_phy,
+						     1024, 256,
+						     &rfs_spec_scan_cb, NULL);
+	debugfs_create_file("spectral_scan_ctl",
+			    S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar,
+			    &fops_spec_scan_ctl);
+	debugfs_create_file("spectral_count",
+			    S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar,
+			    &fops_spectral_count);
+	debugfs_create_file("spectral_bins",
+			    S_IRUSR | S_IWUSR,
+			    ar->debug.debugfs_phy, ar,
+			    &fops_spectral_bins);
+
+	return 0;
+}
+
+void ath10k_spectral_destroy(struct ath10k *ar)
+{
+	if (ar->spectral.rfs_chan_spec_scan) {
+		relay_close(ar->spectral.rfs_chan_spec_scan);
+		ar->spectral.rfs_chan_spec_scan = NULL;
+	}
+}
diff --git a/drivers/net/wireless/ath/ath10k/spectral.h b/drivers/net/wireless/ath/ath10k/spectral.h
new file mode 100644
index 0000000..ee20232
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/spectral.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SPECTRAL_H
+#define SPECTRAL_H
+
+#include "../spectral_common.h"
+
+/**
+ * struct ath10k_spec_scan - parameters for Atheros spectral scan
+ *
+ * @count: number of scan results requested for manual mode
+ * @fft_size: number of bins to be requested = 2^(fft_size - bin_scale)
+ */
+struct ath10k_spec_scan {
+	u8 count;
+	u8 fft_size;
+};
+
+/* enum ath10k_spectral_mode:
+ *
+ * @SPECTRAL_DISABLED: spectral mode is disabled
+ * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
+ *	something else.
+ * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
+ *	is performed manually.
+ */
+enum ath10k_spectral_mode {
+	SPECTRAL_DISABLED = 0,
+	SPECTRAL_BACKGROUND,
+	SPECTRAL_MANUAL,
+};
+
+#ifdef CPTCFG_ATH10K_DEBUGFS
+
+int ath10k_spectral_process_fft(struct ath10k *ar,
+				struct wmi_single_phyerr_rx_event *event,
+				struct phyerr_fft_report *fftr,
+				size_t bin_len, u64 tsf);
+int ath10k_spectral_start(struct ath10k *ar);
+int ath10k_spectral_vif_stop(struct ath10k_vif *arvif);
+int ath10k_spectral_create(struct ath10k *ar);
+void ath10k_spectral_destroy(struct ath10k *ar);
+
+#else
+
+static inline int
+ath10k_spectral_process_fft(struct ath10k *ar,
+			    struct wmi_single_phyerr_rx_event *event,
+			    struct phyerr_fft_report *fftr,
+			    size_t bin_len, u64 tsf)
+{
+	return 0;
+}
+
+static inline int ath10k_spectral_start(struct ath10k *ar)
+{
+	return 0;
+}
+
+static inline int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
+{
+	return 0;
+}
+
+static inline int ath10k_spectral_create(struct ath10k *ar)
+{
+	return 0;
+}
+
+static inline void ath10k_spectral_destroy(struct ath10k *ar)
+{
+}
+
+#endif /* CPTCFG_ATH10K_DEBUGFS */
+
+#endif /* SPECTRAL_H */
diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h
index be7ba1e..9d0ae30 100644
--- a/drivers/net/wireless/ath/ath10k/targaddrs.h
+++ b/drivers/net/wireless/ath/ath10k/targaddrs.h
@@ -284,7 +284,6 @@
 #define HI_OPTION_ALL_FW_SUBMODE_MASK  0xFF00
 #define HI_OPTION_ALL_FW_SUBMODE_SHIFT 0x8
 
-
 /* hi_option_flag2 options */
 #define HI_OPTION_OFFLOAD_AMSDU     0x01
 #define HI_OPTION_DFS_SUPPORT       0x02 /* Enable DFS support */
diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c
new file mode 100644
index 0000000..483db9c
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/testmode.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "testmode.h"
+
+#include <net/netlink.h>
+#include <linux/firmware.h>
+
+#include "debug.h"
+#include "wmi.h"
+#include "hif.h"
+#include "hw.h"
+
+#include "testmode_i.h"
+
+static const struct nla_policy ath10k_tm_policy[ATH10K_TM_ATTR_MAX + 1] = {
+	[ATH10K_TM_ATTR_CMD]		= { .type = NLA_U32 },
+	[ATH10K_TM_ATTR_DATA]		= { .type = NLA_BINARY,
+					    .len = ATH10K_TM_DATA_MAX_LEN },
+	[ATH10K_TM_ATTR_WMI_CMDID]	= { .type = NLA_U32 },
+	[ATH10K_TM_ATTR_VERSION_MAJOR]	= { .type = NLA_U32 },
+	[ATH10K_TM_ATTR_VERSION_MINOR]	= { .type = NLA_U32 },
+};
+
+/* Returns true if callee consumes the skb and the skb should be discarded.
+ * Returns false if skb is not used. Does not sleep.
+ */
+bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb)
+{
+	struct sk_buff *nl_skb;
+	bool consumed;
+	int ret;
+
+	ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
+		   "testmode event wmi cmd_id %d skb %p skb->len %d\n",
+		   cmd_id, skb, skb->len);
+
+	ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
+
+	spin_lock_bh(&ar->data_lock);
+
+	if (!ar->testmode.utf_monitor) {
+		consumed = false;
+		goto out;
+	}
+
+	/* Only testmode.c should be handling events from utf firmware,
+	 * otherwise all sort of problems will arise as mac80211 operations
+	 * are not initialised.
+	 */
+	consumed = true;
+
+	nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
+						   2 * sizeof(u32) + skb->len,
+						   GFP_ATOMIC);
+	if (!nl_skb) {
+		ath10k_warn(ar,
+			    "failed to allocate skb for testmode wmi event\n");
+		goto out;
+	}
+
+	ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_WMI);
+	if (ret) {
+		ath10k_warn(ar,
+			    "failed to to put testmode wmi event cmd attribute: %d\n",
+			    ret);
+		kfree_skb(nl_skb);
+		goto out;
+	}
+
+	ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id);
+	if (ret) {
+		ath10k_warn(ar,
+			    "failed to to put testmode wmi even cmd_id: %d\n",
+			    ret);
+		kfree_skb(nl_skb);
+		goto out;
+	}
+
+	ret = nla_put(nl_skb, ATH10K_TM_ATTR_DATA, skb->len, skb->data);
+	if (ret) {
+		ath10k_warn(ar,
+			    "failed to copy skb to testmode wmi event: %d\n",
+			    ret);
+		kfree_skb(nl_skb);
+		goto out;
+	}
+
+	cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
+
+out:
+	spin_unlock_bh(&ar->data_lock);
+
+	return consumed;
+}
+
+static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
+{
+	struct sk_buff *skb;
+	int ret;
+
+	ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
+		   "testmode cmd get version_major %d version_minor %d\n",
+		   ATH10K_TESTMODE_VERSION_MAJOR,
+		   ATH10K_TESTMODE_VERSION_MINOR);
+
+	skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,
+						nla_total_size(sizeof(u32)));
+	if (!skb)
+		return -ENOMEM;
+
+	ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MAJOR,
+			  ATH10K_TESTMODE_VERSION_MAJOR);
+	if (ret) {
+		kfree_skb(skb);
+		return ret;
+	}
+
+	ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MINOR,
+			  ATH10K_TESTMODE_VERSION_MINOR);
+	if (ret) {
+		kfree_skb(skb);
+		return ret;
+	}
+
+	return cfg80211_testmode_reply(skb);
+}
+
+static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
+{
+	char filename[100];
+	int ret;
+
+	ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n");
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (ar->state == ATH10K_STATE_UTF) {
+		ret = -EALREADY;
+		goto err;
+	}
+
+	/* start utf only when the driver is not in use  */
+	if (ar->state != ATH10K_STATE_OFF) {
+		ret = -EBUSY;
+		goto err;
+	}
+
+	if (WARN_ON(ar->testmode.utf != NULL)) {
+		/* utf image is already downloaded, it shouldn't be */
+		ret = -EEXIST;
+		goto err;
+	}
+
+	snprintf(filename, sizeof(filename), "%s/%s",
+		 ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
+
+	/* load utf firmware image */
+	ret = request_firmware(&ar->testmode.utf, filename, ar->dev);
+	if (ret) {
+		ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
+			    filename, ret);
+		goto err;
+	}
+
+	spin_lock_bh(&ar->data_lock);
+
+	ar->testmode.utf_monitor = true;
+
+	spin_unlock_bh(&ar->data_lock);
+
+	BUILD_BUG_ON(sizeof(ar->fw_features) !=
+		     sizeof(ar->testmode.orig_fw_features));
+
+	memcpy(ar->testmode.orig_fw_features, ar->fw_features,
+	       sizeof(ar->fw_features));
+
+	/* utf.bin firmware image does not advertise firmware features. Do
+	 * an ugly hack where we force the firmware features so that wmi.c
+	 * will use the correct WMI interface.
+	 */
+	memset(ar->fw_features, 0, sizeof(ar->fw_features));
+	__set_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features);
+
+	ret = ath10k_hif_power_up(ar);
+	if (ret) {
+		ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret);
+		ar->state = ATH10K_STATE_OFF;
+		goto err_fw_features;
+	}
+
+	ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF);
+	if (ret) {
+		ath10k_err(ar, "failed to start core (testmode): %d\n", ret);
+		ar->state = ATH10K_STATE_OFF;
+		goto err_power_down;
+	}
+
+	ar->state = ATH10K_STATE_UTF;
+
+	ath10k_info(ar, "UTF firmware started\n");
+
+	mutex_unlock(&ar->conf_mutex);
+
+	return 0;
+
+err_power_down:
+	ath10k_hif_power_down(ar);
+
+err_fw_features:
+	/* return the original firmware features */
+	memcpy(ar->fw_features, ar->testmode.orig_fw_features,
+	       sizeof(ar->fw_features));
+
+	release_firmware(ar->testmode.utf);
+	ar->testmode.utf = NULL;
+
+err:
+	mutex_unlock(&ar->conf_mutex);
+
+	return ret;
+}
+
+static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
+{
+	lockdep_assert_held(&ar->conf_mutex);
+
+	ath10k_core_stop(ar);
+	ath10k_hif_power_down(ar);
+
+	spin_lock_bh(&ar->data_lock);
+
+	ar->testmode.utf_monitor = false;
+
+	spin_unlock_bh(&ar->data_lock);
+
+	/* return the original firmware features */
+	memcpy(ar->fw_features, ar->testmode.orig_fw_features,
+	       sizeof(ar->fw_features));
+
+	release_firmware(ar->testmode.utf);
+	ar->testmode.utf = NULL;
+
+	ar->state = ATH10K_STATE_OFF;
+}
+
+static int ath10k_tm_cmd_utf_stop(struct ath10k *ar, struct nlattr *tb[])
+{
+	int ret;
+
+	ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf stop\n");
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (ar->state != ATH10K_STATE_UTF) {
+		ret = -ENETDOWN;
+		goto out;
+	}
+
+	__ath10k_tm_cmd_utf_stop(ar);
+
+	ret = 0;
+
+	ath10k_info(ar, "UTF firmware stopped\n");
+
+out:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+static int ath10k_tm_cmd_wmi(struct ath10k *ar, struct nlattr *tb[])
+{
+	struct sk_buff *skb;
+	int ret, buf_len;
+	u32 cmd_id;
+	void *buf;
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (ar->state != ATH10K_STATE_UTF) {
+		ret = -ENETDOWN;
+		goto out;
+	}
+
+	if (!tb[ATH10K_TM_ATTR_DATA]) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (!tb[ATH10K_TM_ATTR_WMI_CMDID]) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	buf = nla_data(tb[ATH10K_TM_ATTR_DATA]);
+	buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]);
+	cmd_id = nla_get_u32(tb[ATH10K_TM_ATTR_WMI_CMDID]);
+
+	ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
+		   "testmode cmd wmi cmd_id %d buf %p buf_len %d\n",
+		   cmd_id, buf, buf_len);
+
+	ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len);
+
+	skb = ath10k_wmi_alloc_skb(ar, buf_len);
+	if (!skb) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memcpy(skb->data, buf, buf_len);
+
+	ret = ath10k_wmi_cmd_send(ar, skb, cmd_id);
+	if (ret) {
+		ath10k_warn(ar, "failed to transmit wmi command (testmode): %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = 0;
+
+out:
+	mutex_unlock(&ar->conf_mutex);
+	return ret;
+}
+
+int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		  void *data, int len)
+{
+	struct ath10k *ar = hw->priv;
+	struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1];
+	int ret;
+
+	ret = nla_parse(tb, ATH10K_TM_ATTR_MAX, data, len,
+			ath10k_tm_policy);
+	if (ret)
+		return ret;
+
+	if (!tb[ATH10K_TM_ATTR_CMD])
+		return -EINVAL;
+
+	switch (nla_get_u32(tb[ATH10K_TM_ATTR_CMD])) {
+	case ATH10K_TM_CMD_GET_VERSION:
+		return ath10k_tm_cmd_get_version(ar, tb);
+	case ATH10K_TM_CMD_UTF_START:
+		return ath10k_tm_cmd_utf_start(ar, tb);
+	case ATH10K_TM_CMD_UTF_STOP:
+		return ath10k_tm_cmd_utf_stop(ar, tb);
+	case ATH10K_TM_CMD_WMI:
+		return ath10k_tm_cmd_wmi(ar, tb);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+void ath10k_testmode_destroy(struct ath10k *ar)
+{
+	mutex_lock(&ar->conf_mutex);
+
+	if (ar->state != ATH10K_STATE_UTF) {
+		/* utf firmware is not running, nothing to do */
+		goto out;
+	}
+
+	__ath10k_tm_cmd_utf_stop(ar);
+
+out:
+	mutex_unlock(&ar->conf_mutex);
+}
diff --git a/drivers/net/wireless/ath/ath10k/testmode.h b/drivers/net/wireless/ath/ath10k/testmode.h
new file mode 100644
index 0000000..81e30a8
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/testmode.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+
+#ifdef CPTCFG_NL80211_TESTMODE
+
+void ath10k_testmode_destroy(struct ath10k *ar);
+
+bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb);
+int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		  void *data, int len);
+
+#else
+
+static inline void ath10k_testmode_destroy(struct ath10k *ar)
+{
+}
+
+static inline bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id,
+				       struct sk_buff *skb)
+{
+	return false;
+}
+
+static inline int ath10k_tm_cmd(struct ieee80211_hw *hw,
+				struct ieee80211_vif *vif,
+				void *data, int len)
+{
+	return 0;
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath10k/testmode_i.h b/drivers/net/wireless/ath/ath10k/testmode_i.h
new file mode 100644
index 0000000..ba81bf6
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/testmode_i.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* "API" level of the ath10k testmode interface. Bump it after every
+ * incompatible interface change.
+ */
+#define ATH10K_TESTMODE_VERSION_MAJOR 1
+
+/* Bump this after every _compatible_ interface change, for example
+ * addition of a new command or an attribute.
+ */
+#define ATH10K_TESTMODE_VERSION_MINOR 0
+
+#define ATH10K_TM_DATA_MAX_LEN		5000
+
+enum ath10k_tm_attr {
+	__ATH10K_TM_ATTR_INVALID	= 0,
+	ATH10K_TM_ATTR_CMD		= 1,
+	ATH10K_TM_ATTR_DATA		= 2,
+	ATH10K_TM_ATTR_WMI_CMDID	= 3,
+	ATH10K_TM_ATTR_VERSION_MAJOR	= 4,
+	ATH10K_TM_ATTR_VERSION_MINOR	= 5,
+
+	/* keep last */
+	__ATH10K_TM_ATTR_AFTER_LAST,
+	ATH10K_TM_ATTR_MAX		= __ATH10K_TM_ATTR_AFTER_LAST - 1,
+};
+
+/* All ath10k testmode interface commands specified in
+ * ATH10K_TM_ATTR_CMD
+ */
+enum ath10k_tm_cmd {
+	/* Returns the supported ath10k testmode interface version in
+	 * ATH10K_TM_ATTR_VERSION. Always guaranteed to work. User space
+	 * uses this to verify it's using the correct version of the
+	 * testmode interface
+	 */
+	ATH10K_TM_CMD_GET_VERSION = 0,
+
+	/* Boots the UTF firmware, the netdev interface must be down at the
+	 * time.
+	 */
+	ATH10K_TM_CMD_UTF_START = 1,
+
+	/* Shuts down the UTF firmware and puts the driver back into OFF
+	 * state.
+	 */
+	ATH10K_TM_CMD_UTF_STOP = 2,
+
+	/* The command used to transmit a WMI command to the firmware and
+	 * the event to receive WMI events from the firmware. Without
+	 * struct wmi_cmd_hdr header, only the WMI payload. Command id is
+	 * provided with ATH10K_TM_ATTR_WMI_CMDID and payload in
+	 * ATH10K_TM_ATTR_DATA.
+	 */
+	ATH10K_TM_CMD_WMI = 3,
+};
diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h
index 0eda756..31fe5cd 100644
--- a/drivers/net/wireless/ath/ath10k/trace.h
+++ b/drivers/net/wireless/ath/ath10k/trace.h
@@ -18,6 +18,7 @@
 #if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
 
 #include <linux/tracepoint.h>
+#include "core.h"
 
 #define _TRACE_H_
 
@@ -39,59 +40,79 @@
 #define ATH10K_MSG_MAX 200
 
 DECLARE_EVENT_CLASS(ath10k_log_event,
-	TP_PROTO(struct va_format *vaf),
-	TP_ARGS(vaf),
+	TP_PROTO(struct ath10k *ar, struct va_format *vaf),
+	TP_ARGS(ar, vaf),
 	TP_STRUCT__entry(
+		__string(device, dev_name(ar->dev))
+		__string(driver, dev_driver_string(ar->dev))
 		__dynamic_array(char, msg, ATH10K_MSG_MAX)
 	),
 	TP_fast_assign(
+		__assign_str(device, dev_name(ar->dev));
+		__assign_str(driver, dev_driver_string(ar->dev));
 		WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
 				       ATH10K_MSG_MAX,
 				       vaf->fmt,
 				       *vaf->va) >= ATH10K_MSG_MAX);
 	),
-	TP_printk("%s", __get_str(msg))
+	TP_printk(
+		"%s %s %s",
+		__get_str(driver),
+		__get_str(device),
+		__get_str(msg)
+	)
 );
 
 DEFINE_EVENT(ath10k_log_event, ath10k_log_err,
-	     TP_PROTO(struct va_format *vaf),
-	     TP_ARGS(vaf)
+	     TP_PROTO(struct ath10k *ar, struct va_format *vaf),
+	     TP_ARGS(ar, vaf)
 );
 
 DEFINE_EVENT(ath10k_log_event, ath10k_log_warn,
-	     TP_PROTO(struct va_format *vaf),
-	     TP_ARGS(vaf)
+	     TP_PROTO(struct ath10k *ar, struct va_format *vaf),
+	     TP_ARGS(ar, vaf)
 );
 
 DEFINE_EVENT(ath10k_log_event, ath10k_log_info,
-	     TP_PROTO(struct va_format *vaf),
-	     TP_ARGS(vaf)
+	     TP_PROTO(struct ath10k *ar, struct va_format *vaf),
+	     TP_ARGS(ar, vaf)
 );
 
 TRACE_EVENT(ath10k_log_dbg,
-	TP_PROTO(unsigned int level, struct va_format *vaf),
-	TP_ARGS(level, vaf),
+	TP_PROTO(struct ath10k *ar, unsigned int level, struct va_format *vaf),
+	TP_ARGS(ar, level, vaf),
 	TP_STRUCT__entry(
+		__string(device, dev_name(ar->dev))
+		__string(driver, dev_driver_string(ar->dev))
 		__field(unsigned int, level)
 		__dynamic_array(char, msg, ATH10K_MSG_MAX)
 	),
 	TP_fast_assign(
+		__assign_str(device, dev_name(ar->dev));
+		__assign_str(driver, dev_driver_string(ar->dev));
 		__entry->level = level;
 		WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
 				       ATH10K_MSG_MAX,
 				       vaf->fmt,
 				       *vaf->va) >= ATH10K_MSG_MAX);
 	),
-	TP_printk("%s", __get_str(msg))
+	TP_printk(
+		"%s %s %s",
+		__get_str(driver),
+		__get_str(device),
+		__get_str(msg)
+	)
 );
 
 TRACE_EVENT(ath10k_log_dbg_dump,
-	TP_PROTO(const char *msg, const char *prefix,
+	TP_PROTO(struct ath10k *ar, const char *msg, const char *prefix,
 		 const void *buf, size_t buf_len),
 
-	TP_ARGS(msg, prefix, buf, buf_len),
+	TP_ARGS(ar, msg, prefix, buf, buf_len),
 
 	TP_STRUCT__entry(
+		__string(device, dev_name(ar->dev))
+		__string(driver, dev_driver_string(ar->dev))
 		__string(msg, msg)
 		__string(prefix, prefix)
 		__field(size_t, buf_len)
@@ -99,6 +120,8 @@
 	),
 
 	TP_fast_assign(
+		__assign_str(device, dev_name(ar->dev));
+		__assign_str(driver, dev_driver_string(ar->dev));
 		__assign_str(msg, msg);
 		__assign_str(prefix, prefix);
 		__entry->buf_len = buf_len;
@@ -106,16 +129,22 @@
 	),
 
 	TP_printk(
-		"%s/%s\n", __get_str(prefix), __get_str(msg)
+		"%s %s %s/%s\n",
+		__get_str(driver),
+		__get_str(device),
+		__get_str(prefix),
+		__get_str(msg)
 	)
 );
 
 TRACE_EVENT(ath10k_wmi_cmd,
-	TP_PROTO(int id, void *buf, size_t buf_len, int ret),
+	TP_PROTO(struct ath10k *ar, int id, void *buf, size_t buf_len, int ret),
 
-	TP_ARGS(id, buf, buf_len, ret),
+	TP_ARGS(ar, id, buf, buf_len, ret),
 
 	TP_STRUCT__entry(
+		__string(device, dev_name(ar->dev))
+		__string(driver, dev_driver_string(ar->dev))
 		__field(unsigned int, id)
 		__field(size_t, buf_len)
 		__dynamic_array(u8, buf, buf_len)
@@ -123,6 +152,8 @@
 	),
 
 	TP_fast_assign(
+		__assign_str(device, dev_name(ar->dev));
+		__assign_str(driver, dev_driver_string(ar->dev));
 		__entry->id = id;
 		__entry->buf_len = buf_len;
 		__entry->ret = ret;
@@ -130,7 +161,9 @@
 	),
 
 	TP_printk(
-		"id %d len %zu ret %d",
+		"%s %s id %d len %zu ret %d",
+		__get_str(driver),
+		__get_str(device),
 		__entry->id,
 		__entry->buf_len,
 		__entry->ret
@@ -138,67 +171,85 @@
 );
 
 TRACE_EVENT(ath10k_wmi_event,
-	TP_PROTO(int id, void *buf, size_t buf_len),
+	TP_PROTO(struct ath10k *ar, int id, void *buf, size_t buf_len),
 
-	TP_ARGS(id, buf, buf_len),
+	TP_ARGS(ar, id, buf, buf_len),
 
 	TP_STRUCT__entry(
+		__string(device, dev_name(ar->dev))
+		__string(driver, dev_driver_string(ar->dev))
 		__field(unsigned int, id)
 		__field(size_t, buf_len)
 		__dynamic_array(u8, buf, buf_len)
 	),
 
 	TP_fast_assign(
+		__assign_str(device, dev_name(ar->dev));
+		__assign_str(driver, dev_driver_string(ar->dev));
 		__entry->id = id;
 		__entry->buf_len = buf_len;
 		memcpy(__get_dynamic_array(buf), buf, buf_len);
 	),
 
 	TP_printk(
-		"id %d len %zu",
+		"%s %s id %d len %zu",
+		__get_str(driver),
+		__get_str(device),
 		__entry->id,
 		__entry->buf_len
 	)
 );
 
 TRACE_EVENT(ath10k_htt_stats,
-	TP_PROTO(void *buf, size_t buf_len),
+	TP_PROTO(struct ath10k *ar, void *buf, size_t buf_len),
 
-	TP_ARGS(buf, buf_len),
+	TP_ARGS(ar, buf, buf_len),
 
 	TP_STRUCT__entry(
+		__string(device, dev_name(ar->dev))
+		__string(driver, dev_driver_string(ar->dev))
 		__field(size_t, buf_len)
 		__dynamic_array(u8, buf, buf_len)
 	),
 
 	TP_fast_assign(
+		__assign_str(device, dev_name(ar->dev));
+		__assign_str(driver, dev_driver_string(ar->dev));
 		__entry->buf_len = buf_len;
 		memcpy(__get_dynamic_array(buf), buf, buf_len);
 	),
 
 	TP_printk(
-		"len %zu",
+		"%s %s len %zu",
+		__get_str(driver),
+		__get_str(device),
 		__entry->buf_len
 	)
 );
 
 TRACE_EVENT(ath10k_wmi_dbglog,
-	TP_PROTO(void *buf, size_t buf_len),
+	TP_PROTO(struct ath10k *ar, void *buf, size_t buf_len),
 
-	TP_ARGS(buf, buf_len),
+	TP_ARGS(ar, buf, buf_len),
 
 	TP_STRUCT__entry(
+		__string(device, dev_name(ar->dev))
+		__string(driver, dev_driver_string(ar->dev))
 		__field(size_t, buf_len)
 		__dynamic_array(u8, buf, buf_len)
 	),
 
 	TP_fast_assign(
+		__assign_str(device, dev_name(ar->dev));
+		__assign_str(driver, dev_driver_string(ar->dev));
 		__entry->buf_len = buf_len;
 		memcpy(__get_dynamic_array(buf), buf, buf_len);
 	),
 
 	TP_printk(
-		"len %zu",
+		"%s %s len %zu",
+		__get_str(driver),
+		__get_str(device),
 		__entry->buf_len
 	)
 );
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index f4fa22d..a0cbc21 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -32,14 +32,14 @@
 	 * offchan_tx_skb. */
 	spin_lock_bh(&ar->data_lock);
 	if (ar->offchan_tx_skb != skb) {
-		ath10k_warn("completed old offchannel frame\n");
+		ath10k_warn(ar, "completed old offchannel frame\n");
 		goto out;
 	}
 
 	complete(&ar->offchan_tx_completed);
 	ar->offchan_tx_skb = NULL; /* just for sanity */
 
-	ath10k_dbg(ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb);
+	ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb);
 out:
 	spin_unlock_bh(&ar->data_lock);
 }
@@ -47,18 +47,19 @@
 void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
 			  const struct htt_tx_done *tx_done)
 {
-	struct device *dev = htt->ar->dev;
+	struct ath10k *ar = htt->ar;
+	struct device *dev = ar->dev;
 	struct ieee80211_tx_info *info;
 	struct ath10k_skb_cb *skb_cb;
 	struct sk_buff *msdu;
 
 	lockdep_assert_held(&htt->tx_lock);
 
-	ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
 		   tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
 
 	if (tx_done->msdu_id >= htt->max_num_pending_tx) {
-		ath10k_warn("warning: msdu_id %d too big, ignoring\n",
+		ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n",
 			    tx_done->msdu_id);
 		return;
 	}
@@ -177,12 +178,12 @@
 			goto exit;
 
 		peer->vdev_id = ev->vdev_id;
-		memcpy(peer->addr, ev->addr, ETH_ALEN);
+		ether_addr_copy(peer->addr, ev->addr);
 		list_add(&peer->list, &ar->peers);
 		wake_up(&ar->peer_mapping_wq);
 	}
 
-	ath10k_dbg(ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
 		   ev->vdev_id, ev->addr, ev->peer_id);
 
 	set_bit(ev->peer_id, peer->peer_ids);
@@ -199,12 +200,12 @@
 	spin_lock_bh(&ar->data_lock);
 	peer = ath10k_peer_find_by_id(ar, ev->peer_id);
 	if (!peer) {
-		ath10k_warn("peer-unmap-event: unknown peer id %d\n",
+		ath10k_warn(ar, "peer-unmap-event: unknown peer id %d\n",
 			    ev->peer_id);
 		goto exit;
 	}
 
-	ath10k_dbg(ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
 		   peer->vdev_id, peer->addr, ev->peer_id);
 
 	clear_bit(ev->peer_id, peer->peer_ids);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index a0fbc3e..bd23ca6 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -23,6 +23,7 @@
 #include "debug.h"
 #include "wmi.h"
 #include "mac.h"
+#include "testmode.h"
 
 /* MAIN WMI cmd track */
 static struct wmi_cmd_map wmi_cmd_map = {
@@ -487,9 +488,131 @@
 	.burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE,
 };
 
+/* firmware 10.2 specific mappings */
+static struct wmi_cmd_map wmi_10_2_cmd_map = {
+	.init_cmdid = WMI_10_2_INIT_CMDID,
+	.start_scan_cmdid = WMI_10_2_START_SCAN_CMDID,
+	.stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID,
+	.scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID,
+	.scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED,
+	.pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
+	.pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID,
+	.pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID,
+	.pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
+	.pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
+	.pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
+	.pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
+	.pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
+	.pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
+	.pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+	.pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
+	.pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
+	.vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID,
+	.vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID,
+	.vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID,
+	.vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
+	.vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID,
+	.vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID,
+	.vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID,
+	.vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID,
+	.vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID,
+	.peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID,
+	.peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID,
+	.peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID,
+	.peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID,
+	.peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID,
+	.peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
+	.peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
+	.peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID,
+	.bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID,
+	.pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID,
+	.bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
+	.bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID,
+	.prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
+	.mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID,
+	.prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
+	.addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
+	.addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID,
+	.addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID,
+	.delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID,
+	.addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID,
+	.send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID,
+	.sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID,
+	.sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
+	.sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID,
+	.pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID,
+	.pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID,
+	.roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE,
+	.roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
+	.roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD,
+	.roam_scan_rssi_change_threshold =
+				WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+	.roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE,
+	.ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
+	.ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
+	.ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD,
+	.p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
+	.p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
+	.p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE,
+	.p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
+	.p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
+	.ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID,
+	.ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
+	.peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
+	.wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
+	.wlan_profile_set_hist_intvl_cmdid =
+				WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+	.wlan_profile_get_profile_data_cmdid =
+				WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+	.wlan_profile_enable_profile_id_cmdid =
+				WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+	.wlan_profile_list_profile_id_cmdid =
+				WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+	.pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID,
+	.pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID,
+	.add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID,
+	.rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID,
+	.wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
+	.wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
+	.wow_enable_disable_wake_event_cmdid =
+				WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+	.wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID,
+	.wow_hostwakeup_from_sleep_cmdid =
+				WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+	.rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID,
+	.rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID,
+	.vdev_spectral_scan_configure_cmdid =
+				WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
+	.vdev_spectral_scan_enable_cmdid =
+				WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
+	.request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID,
+	.set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED,
+	.network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED,
+	.gtk_offload_cmdid = WMI_CMD_UNSUPPORTED,
+	.csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED,
+	.csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED,
+	.chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED,
+	.peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED,
+	.peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED,
+	.sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED,
+	.sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED,
+	.sta_keepalive_cmd = WMI_CMD_UNSUPPORTED,
+	.echo_cmdid = WMI_10_2_ECHO_CMDID,
+	.pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID,
+	.dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID,
+	.pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID,
+	.pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED,
+	.vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
+	.vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
+	.force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED,
+	.gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,
+	.gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
+};
+
 int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
 {
 	int ret;
+
 	ret = wait_for_completion_timeout(&ar->wmi.service_ready,
 					  WMI_SERVICE_READY_TIMEOUT_HZ);
 	return ret;
@@ -498,23 +621,24 @@
 int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar)
 {
 	int ret;
+
 	ret = wait_for_completion_timeout(&ar->wmi.unified_ready,
 					  WMI_UNIFIED_READY_TIMEOUT_HZ);
 	return ret;
 }
 
-static struct sk_buff *ath10k_wmi_alloc_skb(u32 len)
+struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len)
 {
 	struct sk_buff *skb;
 	u32 round_len = roundup(len, 4);
 
-	skb = ath10k_htc_alloc_skb(WMI_SKB_HEADROOM + round_len);
+	skb = ath10k_htc_alloc_skb(ar, WMI_SKB_HEADROOM + round_len);
 	if (!skb)
 		return NULL;
 
 	skb_reserve(skb, WMI_SKB_HEADROOM);
 	if (!IS_ALIGNED((unsigned long)skb->data, 4))
-		ath10k_warn("Unaligned WMI skb\n");
+		ath10k_warn(ar, "Unaligned WMI skb\n");
 
 	skb_put(skb, round_len);
 	memset(skb->data, 0, round_len);
@@ -545,7 +669,7 @@
 
 	memset(skb_cb, 0, sizeof(*skb_cb));
 	ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb);
-	trace_ath10k_wmi_cmd(cmd_id, skb->data, skb->len, ret);
+	trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len, ret);
 
 	if (ret)
 		goto err_pull;
@@ -604,15 +728,14 @@
 	wake_up(&ar->wmi.tx_credits_wq);
 }
 
-static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
-			       u32 cmd_id)
+int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
 {
 	int ret = -EOPNOTSUPP;
 
 	might_sleep();
 
 	if (cmd_id == WMI_CMD_UNSUPPORTED) {
-		ath10k_warn("wmi command %d is not supported by firmware\n",
+		ath10k_warn(ar, "wmi command %d is not supported by firmware\n",
 			    cmd_id);
 		return ret;
 	}
@@ -660,7 +783,7 @@
 
 	len = round_up(len, 4);
 
-	wmi_skb = ath10k_wmi_alloc_skb(len);
+	wmi_skb = ath10k_wmi_alloc_skb(ar, len);
 	if (!wmi_skb)
 		return -ENOMEM;
 
@@ -671,10 +794,10 @@
 	cmd->hdr.tx_power = 0;
 	cmd->hdr.buf_len = __cpu_to_le32(buf_len);
 
-	memcpy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr), ETH_ALEN);
+	ether_addr_copy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr));
 	memcpy(cmd->buf, skb->data, skb->len);
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
 		   wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE,
 		   fc & IEEE80211_FCTL_STYPE);
 
@@ -690,6 +813,130 @@
 	return ret;
 }
 
+static void ath10k_wmi_event_scan_started(struct ath10k *ar)
+{
+	lockdep_assert_held(&ar->data_lock);
+
+	switch (ar->scan.state) {
+	case ATH10K_SCAN_IDLE:
+	case ATH10K_SCAN_RUNNING:
+	case ATH10K_SCAN_ABORTING:
+		ath10k_warn(ar, "received scan started event in an invalid scan state: %s (%d)\n",
+			    ath10k_scan_state_str(ar->scan.state),
+			    ar->scan.state);
+		break;
+	case ATH10K_SCAN_STARTING:
+		ar->scan.state = ATH10K_SCAN_RUNNING;
+
+		if (ar->scan.is_roc)
+			ieee80211_ready_on_channel(ar->hw);
+
+		complete(&ar->scan.started);
+		break;
+	}
+}
+
+static void ath10k_wmi_event_scan_completed(struct ath10k *ar)
+{
+	lockdep_assert_held(&ar->data_lock);
+
+	switch (ar->scan.state) {
+	case ATH10K_SCAN_IDLE:
+	case ATH10K_SCAN_STARTING:
+		/* One suspected reason scan can be completed while starting is
+		 * if firmware fails to deliver all scan events to the host,
+		 * e.g. when transport pipe is full. This has been observed
+		 * with spectral scan phyerr events starving wmi transport
+		 * pipe. In such case the "scan completed" event should be (and
+		 * is) ignored by the host as it may be just firmware's scan
+		 * state machine recovering.
+		 */
+		ath10k_warn(ar, "received scan completed event in an invalid scan state: %s (%d)\n",
+			    ath10k_scan_state_str(ar->scan.state),
+			    ar->scan.state);
+		break;
+	case ATH10K_SCAN_RUNNING:
+	case ATH10K_SCAN_ABORTING:
+		__ath10k_scan_finish(ar);
+		break;
+	}
+}
+
+static void ath10k_wmi_event_scan_bss_chan(struct ath10k *ar)
+{
+	lockdep_assert_held(&ar->data_lock);
+
+	switch (ar->scan.state) {
+	case ATH10K_SCAN_IDLE:
+	case ATH10K_SCAN_STARTING:
+		ath10k_warn(ar, "received scan bss chan event in an invalid scan state: %s (%d)\n",
+			    ath10k_scan_state_str(ar->scan.state),
+			    ar->scan.state);
+		break;
+	case ATH10K_SCAN_RUNNING:
+	case ATH10K_SCAN_ABORTING:
+		ar->scan_channel = NULL;
+		break;
+	}
+}
+
+static void ath10k_wmi_event_scan_foreign_chan(struct ath10k *ar, u32 freq)
+{
+	lockdep_assert_held(&ar->data_lock);
+
+	switch (ar->scan.state) {
+	case ATH10K_SCAN_IDLE:
+	case ATH10K_SCAN_STARTING:
+		ath10k_warn(ar, "received scan foreign chan event in an invalid scan state: %s (%d)\n",
+			    ath10k_scan_state_str(ar->scan.state),
+			    ar->scan.state);
+		break;
+	case ATH10K_SCAN_RUNNING:
+	case ATH10K_SCAN_ABORTING:
+		ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
+
+		if (ar->scan.is_roc && ar->scan.roc_freq == freq)
+			complete(&ar->scan.on_channel);
+		break;
+	}
+}
+
+static const char *
+ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type,
+			       enum wmi_scan_completion_reason reason)
+{
+	switch (type) {
+	case WMI_SCAN_EVENT_STARTED:
+		return "started";
+	case WMI_SCAN_EVENT_COMPLETED:
+		switch (reason) {
+		case WMI_SCAN_REASON_COMPLETED:
+			return "completed";
+		case WMI_SCAN_REASON_CANCELLED:
+			return "completed [cancelled]";
+		case WMI_SCAN_REASON_PREEMPTED:
+			return "completed [preempted]";
+		case WMI_SCAN_REASON_TIMEDOUT:
+			return "completed [timedout]";
+		case WMI_SCAN_REASON_MAX:
+			break;
+		}
+		return "completed [unknown]";
+	case WMI_SCAN_EVENT_BSS_CHANNEL:
+		return "bss channel";
+	case WMI_SCAN_EVENT_FOREIGN_CHANNEL:
+		return "foreign channel";
+	case WMI_SCAN_EVENT_DEQUEUED:
+		return "dequeued";
+	case WMI_SCAN_EVENT_PREEMPTED:
+		return "preempted";
+	case WMI_SCAN_EVENT_START_FAILED:
+		return "start failed";
+	default:
+		return "unknown";
+	}
+}
+
 static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data;
@@ -707,81 +954,32 @@
 	scan_id    = __le32_to_cpu(event->scan_id);
 	vdev_id    = __le32_to_cpu(event->vdev_id);
 
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENTID\n");
-	ath10k_dbg(ATH10K_DBG_WMI,
-		   "scan event type %d reason %d freq %d req_id %d "
-		   "scan_id %d vdev_id %d\n",
-		   event_type, reason, freq, req_id, scan_id, vdev_id);
-
 	spin_lock_bh(&ar->data_lock);
 
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
+		   "scan event %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n",
+		   ath10k_wmi_event_scan_type_str(event_type, reason),
+		   event_type, reason, freq, req_id, scan_id, vdev_id,
+		   ath10k_scan_state_str(ar->scan.state), ar->scan.state);
+
 	switch (event_type) {
 	case WMI_SCAN_EVENT_STARTED:
-		ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_STARTED\n");
-		if (ar->scan.in_progress && ar->scan.is_roc)
-			ieee80211_ready_on_channel(ar->hw);
-
-		complete(&ar->scan.started);
+		ath10k_wmi_event_scan_started(ar);
 		break;
 	case WMI_SCAN_EVENT_COMPLETED:
-		ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_COMPLETED\n");
-		switch (reason) {
-		case WMI_SCAN_REASON_COMPLETED:
-			ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_COMPLETED\n");
-			break;
-		case WMI_SCAN_REASON_CANCELLED:
-			ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_CANCELED\n");
-			break;
-		case WMI_SCAN_REASON_PREEMPTED:
-			ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_PREEMPTED\n");
-			break;
-		case WMI_SCAN_REASON_TIMEDOUT:
-			ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_TIMEDOUT\n");
-			break;
-		default:
-			break;
-		}
-
-		ar->scan_channel = NULL;
-		if (!ar->scan.in_progress) {
-			ath10k_warn("no scan requested, ignoring\n");
-			break;
-		}
-
-		if (ar->scan.is_roc) {
-			ath10k_offchan_tx_purge(ar);
-
-			if (!ar->scan.aborting)
-				ieee80211_remain_on_channel_expired(ar->hw);
-		} else {
-			ieee80211_scan_completed(ar->hw, ar->scan.aborting);
-		}
-
-		del_timer(&ar->scan.timeout);
-		complete_all(&ar->scan.completed);
-		ar->scan.in_progress = false;
+		ath10k_wmi_event_scan_completed(ar);
 		break;
 	case WMI_SCAN_EVENT_BSS_CHANNEL:
-		ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_BSS_CHANNEL\n");
-		ar->scan_channel = NULL;
+		ath10k_wmi_event_scan_bss_chan(ar);
 		break;
 	case WMI_SCAN_EVENT_FOREIGN_CHANNEL:
-		ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_FOREIGN_CHANNEL\n");
-		ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
-		if (ar->scan.in_progress && ar->scan.is_roc &&
-		    ar->scan.roc_freq == freq) {
-			complete(&ar->scan.on_channel);
-		}
-		break;
-	case WMI_SCAN_EVENT_DEQUEUED:
-		ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_DEQUEUED\n");
-		break;
-	case WMI_SCAN_EVENT_PREEMPTED:
-		ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_PREEMPTED\n");
+		ath10k_wmi_event_scan_foreign_chan(ar, freq);
 		break;
 	case WMI_SCAN_EVENT_START_FAILED:
-		ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_START_FAILED\n");
+		ath10k_warn(ar, "received scan start failure event\n");
 		break;
+	case WMI_SCAN_EVENT_DEQUEUED:
+	case WMI_SCAN_EVENT_PREEMPTED:
 	default:
 		break;
 	}
@@ -911,7 +1109,7 @@
 
 	memset(status, 0, sizeof(*status));
 
-	ath10k_dbg(ATH10K_DBG_MGMT,
+	ath10k_dbg(ar, ATH10K_DBG_MGMT,
 		   "event mgmt rx status %08x\n", rx_status);
 
 	if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) {
@@ -947,9 +1145,9 @@
 
 		if (phy_mode == MODE_11B &&
 		    status->band == IEEE80211_BAND_5GHZ)
-			ath10k_dbg(ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
+			ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
 	} else {
-		ath10k_warn("using (unreliable) phy_mode to extract band for mgmt rx\n");
+		ath10k_warn(ar, "using (unreliable) phy_mode to extract band for mgmt rx\n");
 		status->band = phy_mode_to_band(phy_mode);
 	}
 
@@ -979,12 +1177,12 @@
 		}
 	}
 
-	ath10k_dbg(ATH10K_DBG_MGMT,
+	ath10k_dbg(ar, ATH10K_DBG_MGMT,
 		   "event mgmt rx skb %p len %d ftype %02x stype %02x\n",
 		   skb, skb->len,
 		   fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE);
 
-	ath10k_dbg(ATH10K_DBG_MGMT,
+	ath10k_dbg(ar, ATH10K_DBG_MGMT,
 		   "event mgmt rx freq %d band %d snr %d, rate_idx %d\n",
 		   status->freq, status->band, status->signal,
 		   status->rate_idx);
@@ -1034,21 +1232,26 @@
 	rx_clear_count = __le32_to_cpu(ev->rx_clear_count);
 	cycle_count = __le32_to_cpu(ev->cycle_count);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n",
 		   err_code, freq, cmd_flags, noise_floor, rx_clear_count,
 		   cycle_count);
 
 	spin_lock_bh(&ar->data_lock);
 
-	if (!ar->scan.in_progress) {
-		ath10k_warn("chan info event without a scan request?\n");
+	switch (ar->scan.state) {
+	case ATH10K_SCAN_IDLE:
+	case ATH10K_SCAN_STARTING:
+		ath10k_warn(ar, "received chan info event without a scan request, ignoring\n");
 		goto exit;
+	case ATH10K_SCAN_RUNNING:
+	case ATH10K_SCAN_ABORTING:
+		break;
 	}
 
 	idx = freq_to_idx(ar, freq);
 	if (idx >= ARRAY_SIZE(ar->survey)) {
-		ath10k_warn("chan info: invalid frequency %d (idx %d out of bounds)\n",
+		ath10k_warn(ar, "chan info: invalid frequency %d (idx %d out of bounds)\n",
 			    freq, idx);
 		goto exit;
 	}
@@ -1079,15 +1282,15 @@
 
 static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
 }
 
 static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
 		   skb->len);
 
-	trace_ath10k_wmi_dbglog(skb->data, skb->len);
+	trace_ath10k_wmi_dbglog(ar, skb->data, skb->len);
 
 	return 0;
 }
@@ -1097,7 +1300,7 @@
 {
 	struct wmi_stats_event *ev = (struct wmi_stats_event *)skb->data;
 
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
 
 	ath10k_debug_read_target_stats(ar, ev);
 }
@@ -1107,7 +1310,7 @@
 {
 	struct wmi_vdev_start_response_event *ev;
 
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
 
 	ev = (struct wmi_vdev_start_response_event *)skb->data;
 
@@ -1120,7 +1323,7 @@
 static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
 					  struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n");
 	complete(&ar->vdev_setup_done);
 }
 
@@ -1132,14 +1335,14 @@
 
 	ev = (struct wmi_peer_sta_kickout_event *)skb->data;
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
 		   ev->peer_macaddr.addr);
 
 	rcu_read_lock();
 
 	sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL);
 	if (!sta) {
-		ath10k_warn("Spurious quick kickout for STA %pM\n",
+		ath10k_warn(ar, "Spurious quick kickout for STA %pM\n",
 			    ev->peer_macaddr.addr);
 		goto exit;
 	}
@@ -1183,6 +1386,8 @@
 	struct ieee80211_tim_ie *tim;
 	u8 *ies, *ie;
 	u8 ie_len, pvm_len;
+	__le32 t;
+	u32 v;
 
 	/* if next SWBA has no tim_changed the tim_bitmap is garbage.
 	 * we must copy the bitmap upon change and reuse it later */
@@ -1193,8 +1398,8 @@
 			     sizeof(bcn_info->tim_info.tim_bitmap));
 
 		for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) {
-			__le32 t = bcn_info->tim_info.tim_bitmap[i / 4];
-			u32 v = __le32_to_cpu(t);
+			t = bcn_info->tim_info.tim_bitmap[i / 4];
+			v = __le32_to_cpu(t);
 			arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF;
 		}
 
@@ -1216,7 +1421,7 @@
 				    (u8 *)skb_tail_pointer(bcn) - ies);
 	if (!ie) {
 		if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
-			ath10k_warn("no tim ie found;\n");
+			ath10k_warn(ar, "no tim ie found;\n");
 		return;
 	}
 
@@ -1236,12 +1441,12 @@
 			ie_len += expand_size;
 			pvm_len += expand_size;
 		} else {
-			ath10k_warn("tim expansion failed\n");
+			ath10k_warn(ar, "tim expansion failed\n");
 		}
 	}
 
 	if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) {
-		ath10k_warn("tim pvm length is too great (%d)\n", pvm_len);
+		ath10k_warn(ar, "tim pvm length is too great (%d)\n", pvm_len);
 		return;
 	}
 
@@ -1255,7 +1460,7 @@
 			ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
 	}
 
-	ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
 		   tim->dtim_count, tim->dtim_period,
 		   tim->bitmap_ctrl, pvm_len);
 }
@@ -1310,7 +1515,6 @@
 	u8 opp_ps_info = noa->ctwindow_oppps;
 	bool opps_enabled = !!(opp_ps_info & WMI_P2P_OPPPS_ENABLE_BIT);
 
-
 	if (!noa_descriptors && !opps_enabled)
 		return len;
 
@@ -1333,7 +1537,7 @@
 	if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
 		return;
 
-	ath10k_dbg(ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
+	ath10k_dbg(ar, ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
 	if (noa->changed & WMI_P2P_NOA_CHANGED_BIT) {
 		new_len = ath10k_p2p_calc_noa_ie_len(noa);
 		if (!new_len)
@@ -1367,7 +1571,6 @@
 	kfree(old_data);
 }
 
-
 static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
 {
 	struct wmi_host_swba_event *ev;
@@ -1381,7 +1584,7 @@
 	ev = (struct wmi_host_swba_event *)skb->data;
 	map = __le32_to_cpu(ev->vdev_map);
 
-	ath10k_dbg(ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
+	ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
 		   ev->vdev_map);
 
 	for (; map; map >>= 1, vdev_id++) {
@@ -1391,13 +1594,13 @@
 		i++;
 
 		if (i >= WMI_MAX_AP_VDEV) {
-			ath10k_warn("swba has corrupted vdev map\n");
+			ath10k_warn(ar, "swba has corrupted vdev map\n");
 			break;
 		}
 
 		bcn_info = &ev->bcn_info[i];
 
-		ath10k_dbg(ATH10K_DBG_MGMT,
+		ath10k_dbg(ar, ATH10K_DBG_MGMT,
 			   "mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n",
 			   i,
 			   __le32_to_cpu(bcn_info->tim_info.tim_len),
@@ -1411,7 +1614,8 @@
 
 		arvif = ath10k_get_arvif(ar, vdev_id);
 		if (arvif == NULL) {
-			ath10k_warn("no vif for vdev_id %d found\n", vdev_id);
+			ath10k_warn(ar, "no vif for vdev_id %d found\n",
+				    vdev_id);
 			continue;
 		}
 
@@ -1428,7 +1632,7 @@
 
 		bcn = ieee80211_beacon_get(ar->hw, arvif->vif);
 		if (!bcn) {
-			ath10k_warn("could not get mac80211 beacon\n");
+			ath10k_warn(ar, "could not get mac80211 beacon\n");
 			continue;
 		}
 
@@ -1440,7 +1644,7 @@
 
 		if (arvif->beacon) {
 			if (!arvif->beacon_sent)
-				ath10k_warn("SWBA overrun on vdev %d\n",
+				ath10k_warn(ar, "SWBA overrun on vdev %d\n",
 					    arvif->vdev_id);
 
 			dma_unmap_single(arvif->ar->dev,
@@ -1456,7 +1660,7 @@
 		ret = dma_mapping_error(arvif->ar->dev,
 					ATH10K_SKB_CB(bcn)->paddr);
 		if (ret) {
-			ath10k_warn("failed to map beacon: %d\n", ret);
+			ath10k_warn(ar, "failed to map beacon: %d\n", ret);
 			dev_kfree_skb_any(bcn);
 			goto skip;
 		}
@@ -1473,7 +1677,7 @@
 static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar,
 					       struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
 }
 
 static void ath10k_dfs_radar_report(struct ath10k *ar,
@@ -1489,20 +1693,20 @@
 	reg0 = __le32_to_cpu(rr->reg0);
 	reg1 = __le32_to_cpu(rr->reg1);
 
-	ath10k_dbg(ATH10K_DBG_REGULATORY,
+	ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
 		   "wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n",
 		   MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP),
 		   MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH),
 		   MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN),
 		   MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF));
-	ath10k_dbg(ATH10K_DBG_REGULATORY,
+	ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
 		   "wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n",
 		   MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK),
 		   MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX),
 		   MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID),
 		   MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN),
 		   MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK));
-	ath10k_dbg(ATH10K_DBG_REGULATORY,
+	ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
 		   "wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n",
 		   MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET),
 		   MS(reg1, RADAR_REPORT_REG1_PULSE_DUR));
@@ -1529,25 +1733,25 @@
 	pe.width = width;
 	pe.rssi = rssi;
 
-	ath10k_dbg(ATH10K_DBG_REGULATORY,
+	ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
 		   "dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n",
 		   pe.freq, pe.width, pe.rssi, pe.ts);
 
 	ATH10K_DFS_STAT_INC(ar, pulses_detected);
 
 	if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) {
-		ath10k_dbg(ATH10K_DBG_REGULATORY,
+		ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
 			   "dfs no pulse pattern detected, yet\n");
 		return;
 	}
 
-	ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n");
+	ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n");
 	ATH10K_DFS_STAT_INC(ar, radar_detected);
 
 	/* Control radar events reporting in debugfs file
 	   dfs_block_radar_events */
 	if (ar->dfs_block_radar_events) {
-		ath10k_info("DFS Radar detected, but ignored as requested\n");
+		ath10k_info(ar, "DFS Radar detected, but ignored as requested\n");
 		return;
 	}
 
@@ -1566,13 +1770,13 @@
 	reg1 = __le32_to_cpu(fftr->reg1);
 	rssi = event->hdr.rssi_combined;
 
-	ath10k_dbg(ATH10K_DBG_REGULATORY,
+	ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
 		   "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n",
 		   MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB),
 		   MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB),
 		   MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX),
 		   MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX));
-	ath10k_dbg(ATH10K_DBG_REGULATORY,
+	ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
 		   "wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n",
 		   MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB),
 		   MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB),
@@ -1584,7 +1788,7 @@
 	/* false event detection */
 	if (rssi == DFS_RSSI_POSSIBLY_FALSE &&
 	    peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) {
-		ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
+		ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
 		ATH10K_DFS_STAT_INC(ar, pulses_discarded);
 		return -EINVAL;
 	}
@@ -1603,7 +1807,7 @@
 	u8 *tlv_buf;
 
 	buf_len = __le32_to_cpu(event->hdr.buf_len);
-	ath10k_dbg(ATH10K_DBG_REGULATORY,
+	ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
 		   "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n",
 		   event->hdr.phy_err_code, event->hdr.rssi_combined,
 		   __le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len);
@@ -1616,21 +1820,22 @@
 
 	while (i < buf_len) {
 		if (i + sizeof(*tlv) > buf_len) {
-			ath10k_warn("too short buf for tlv header (%d)\n", i);
+			ath10k_warn(ar, "too short buf for tlv header (%d)\n",
+				    i);
 			return;
 		}
 
 		tlv = (struct phyerr_tlv *)&event->bufp[i];
 		tlv_len = __le16_to_cpu(tlv->len);
 		tlv_buf = &event->bufp[i + sizeof(*tlv)];
-		ath10k_dbg(ATH10K_DBG_REGULATORY,
+		ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
 			   "wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n",
 			   tlv_len, tlv->tag, tlv->sig);
 
 		switch (tlv->tag) {
 		case PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY:
 			if (i + sizeof(*tlv) + sizeof(*rr) > buf_len) {
-				ath10k_warn("too short radar pulse summary (%d)\n",
+				ath10k_warn(ar, "too short radar pulse summary (%d)\n",
 					    i);
 				return;
 			}
@@ -1640,7 +1845,8 @@
 			break;
 		case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
 			if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) {
-				ath10k_warn("too short fft report (%d)\n", i);
+				ath10k_warn(ar, "too short fft report (%d)\n",
+					    i);
 				return;
 			}
 
@@ -1655,11 +1861,59 @@
 	}
 }
 
-static void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
-				struct wmi_single_phyerr_rx_event *event,
-				u64 tsf)
+static void
+ath10k_wmi_event_spectral_scan(struct ath10k *ar,
+			       struct wmi_single_phyerr_rx_event *event,
+			       u64 tsf)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi event spectral scan\n");
+	int buf_len, tlv_len, res, i = 0;
+	struct phyerr_tlv *tlv;
+	u8 *tlv_buf;
+	struct phyerr_fft_report *fftr;
+	size_t fftr_len;
+
+	buf_len = __le32_to_cpu(event->hdr.buf_len);
+
+	while (i < buf_len) {
+		if (i + sizeof(*tlv) > buf_len) {
+			ath10k_warn(ar, "failed to parse phyerr tlv header at byte %d\n",
+				    i);
+			return;
+		}
+
+		tlv = (struct phyerr_tlv *)&event->bufp[i];
+		tlv_len = __le16_to_cpu(tlv->len);
+		tlv_buf = &event->bufp[i + sizeof(*tlv)];
+
+		if (i + sizeof(*tlv) + tlv_len > buf_len) {
+			ath10k_warn(ar, "failed to parse phyerr tlv payload at byte %d\n",
+				    i);
+			return;
+		}
+
+		switch (tlv->tag) {
+		case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
+			if (sizeof(*fftr) > tlv_len) {
+				ath10k_warn(ar, "failed to parse fft report at byte %d\n",
+					    i);
+				return;
+			}
+
+			fftr_len = tlv_len - sizeof(*fftr);
+			fftr = (struct phyerr_fft_report *)tlv_buf;
+			res = ath10k_spectral_process_fft(ar, event,
+							  fftr, fftr_len,
+							  tsf);
+			if (res < 0) {
+				ath10k_warn(ar, "failed to process fft report: %d\n",
+					    res);
+				return;
+			}
+			break;
+		}
+
+		i += sizeof(*tlv) + tlv_len;
+	}
 }
 
 static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
@@ -1674,7 +1928,7 @@
 
 	/* Check if combined event available */
 	if (left_len < sizeof(*comb_event)) {
-		ath10k_warn("wmi phyerr combined event wrong len\n");
+		ath10k_warn(ar, "wmi phyerr combined event wrong len\n");
 		return;
 	}
 
@@ -1688,7 +1942,7 @@
 	tsf <<= 32;
 	tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi event phyerr count %d tsf64 0x%llX\n",
 		   count, tsf);
 
@@ -1696,7 +1950,8 @@
 	for (i = 0; i < count; i++) {
 		/* Check if we can read event header */
 		if (left_len < sizeof(*event)) {
-			ath10k_warn("single event (%d) wrong head len\n", i);
+			ath10k_warn(ar, "single event (%d) wrong head len\n",
+				    i);
 			return;
 		}
 
@@ -1706,7 +1961,7 @@
 		phy_err_code = event->hdr.phy_err_code;
 
 		if (left_len < buf_len) {
-			ath10k_warn("single event (%d) wrong buf len\n", i);
+			ath10k_warn(ar, "single event (%d) wrong buf len\n", i);
 			return;
 		}
 
@@ -1733,13 +1988,13 @@
 
 static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
 }
 
 static void ath10k_wmi_event_profile_match(struct ath10k *ar,
-				    struct sk_buff *skb)
+					   struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n");
 }
 
 static void ath10k_wmi_event_debug_print(struct ath10k *ar,
@@ -1764,7 +2019,7 @@
 	}
 
 	if (i == sizeof(buf) - 1)
-		ath10k_warn("wmi debug print truncated: %d\n", skb->len);
+		ath10k_warn(ar, "wmi debug print truncated: %d\n", skb->len);
 
 	/* for some reason the debug prints end with \n, remove that */
 	if (skb->data[i - 1] == '\n')
@@ -1773,112 +2028,112 @@
 	/* the last byte is always reserved for the null character */
 	buf[i] = '\0';
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);
 }
 
 static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n");
 }
 
 static void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar,
 					       struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n");
 }
 
 static void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
-					     struct sk_buff *skb)
+						    struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n");
 }
 
 static void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
-					     struct sk_buff *skb)
+						    struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n");
 }
 
 static void ath10k_wmi_event_rtt_error_report(struct ath10k *ar,
 					      struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n");
 }
 
 static void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar,
 					     struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
 }
 
 static void ath10k_wmi_event_dcs_interference(struct ath10k *ar,
 					      struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
 }
 
 static void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar,
 					     struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
 }
 
 static void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar,
 					   struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
 }
 
 static void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar,
-					 struct sk_buff *skb)
+						struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n");
 }
 
 static void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar,
 					    struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n");
 }
 
 static void ath10k_wmi_event_delba_complete(struct ath10k *ar,
 					    struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n");
 }
 
 static void ath10k_wmi_event_addba_complete(struct ath10k *ar,
 					    struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n");
 }
 
 static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
-						struct sk_buff *skb)
+						       struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
 }
 
 static void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar,
 					     struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n");
 }
 
 static void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar,
 					      struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n");
 }
 
 static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar,
 					     struct sk_buff *skb)
 {
-	ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
 }
 
 static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
-				      u32 num_units, u32 unit_len)
+				     u32 num_units, u32 unit_len)
 {
 	dma_addr_t paddr;
 	u32 pool_size;
@@ -1894,7 +2149,7 @@
 							   &paddr,
 							   GFP_ATOMIC);
 	if (!ar->wmi.mem_chunks[idx].vaddr) {
-		ath10k_warn("failed to allocate memory chunk\n");
+		ath10k_warn(ar, "failed to allocate memory chunk\n");
 		return -ENOMEM;
 	}
 
@@ -1912,9 +2167,10 @@
 					      struct sk_buff *skb)
 {
 	struct wmi_service_ready_event *ev = (void *)skb->data;
+	DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {};
 
 	if (skb->len < sizeof(*ev)) {
-		ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
+		ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
 			    skb->len, sizeof(*ev));
 		return;
 	}
@@ -1937,7 +2193,7 @@
 		set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features);
 
 	if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
-		ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
+		ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
 			    ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
 		ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
 	}
@@ -1945,8 +2201,10 @@
 	ar->ath_common.regulatory.current_rd =
 		__le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
 
-	ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap,
-				      sizeof(ev->wmi_service_bitmap));
+	wmi_main_svc_map(ev->wmi_service_bitmap, svc_bmap);
+	ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
+	ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
+			ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
 
 	if (strlen(ar->hw->wiphy->fw_version) == 0) {
 		snprintf(ar->hw->wiphy->fw_version,
@@ -1960,11 +2218,11 @@
 
 	/* FIXME: it probably should be better to support this */
 	if (__le32_to_cpu(ev->num_mem_reqs) > 0) {
-		ath10k_warn("target requested %d memory chunks; ignoring\n",
+		ath10k_warn(ar, "target requested %d memory chunks; ignoring\n",
 			    __le32_to_cpu(ev->num_mem_reqs));
 	}
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
 		   __le32_to_cpu(ev->sw_version),
 		   __le32_to_cpu(ev->sw_version_1),
@@ -1986,9 +2244,10 @@
 	u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
 	int ret;
 	struct wmi_service_ready_event_10x *ev = (void *)skb->data;
+	DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {};
 
 	if (skb->len < sizeof(*ev)) {
-		ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
+		ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
 			    skb->len, sizeof(*ev));
 		return;
 	}
@@ -2004,7 +2263,7 @@
 	ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
 
 	if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
-		ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
+		ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
 			    ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
 		ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
 	}
@@ -2012,8 +2271,10 @@
 	ar->ath_common.regulatory.current_rd =
 		__le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
 
-	ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap,
-				      sizeof(ev->wmi_service_bitmap));
+	wmi_10x_svc_map(ev->wmi_service_bitmap, svc_bmap);
+	ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
+	ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
+			ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
 
 	if (strlen(ar->hw->wiphy->fw_version) == 0) {
 		snprintf(ar->hw->wiphy->fw_version,
@@ -2026,7 +2287,7 @@
 	num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs);
 
 	if (num_mem_reqs > ATH10K_MAX_MEM_REQS) {
-		ath10k_warn("requested memory chunks number (%d) exceeds the limit\n",
+		ath10k_warn(ar, "requested memory chunks number (%d) exceeds the limit\n",
 			    num_mem_reqs);
 		return;
 	}
@@ -2034,7 +2295,7 @@
 	if (!num_mem_reqs)
 		goto exit;
 
-	ath10k_dbg(ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
 		   num_mem_reqs);
 
 	for (i = 0; i < num_mem_reqs; ++i) {
@@ -2052,7 +2313,7 @@
 		else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS)
 			num_units = TARGET_10X_NUM_VDEVS + 1;
 
-		ath10k_dbg(ATH10K_DBG_WMI,
+		ath10k_dbg(ar, ATH10K_DBG_WMI,
 			   "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n",
 			   req_id,
 			   __le32_to_cpu(ev->mem_reqs[i].num_units),
@@ -2067,7 +2328,7 @@
 	}
 
 exit:
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
 		   __le32_to_cpu(ev->sw_version),
 		   __le32_to_cpu(ev->abi_version),
@@ -2089,9 +2350,9 @@
 	if (WARN_ON(skb->len < sizeof(*ev)))
 		return -EINVAL;
 
-	memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN);
+	ether_addr_copy(ar->mac_addr, ev->mac_addr.addr);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n",
 		   __le32_to_cpu(ev->sw_version),
 		   __le32_to_cpu(ev->abi_version),
@@ -2113,7 +2374,7 @@
 	if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
 		return;
 
-	trace_ath10k_wmi_event(id, skb->data, skb->len);
+	trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
 
 	switch (id) {
 	case WMI_MGMT_RX_EVENTID:
@@ -2211,7 +2472,7 @@
 		ath10k_wmi_ready_event_rx(ar, skb);
 		break;
 	default:
-		ath10k_warn("Unknown eventid: %d\n", id);
+		ath10k_warn(ar, "Unknown eventid: %d\n", id);
 		break;
 	}
 
@@ -2222,6 +2483,7 @@
 {
 	struct wmi_cmd_hdr *cmd_hdr;
 	enum wmi_10x_event_id id;
+	bool consumed;
 
 	cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
 	id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
@@ -2229,7 +2491,19 @@
 	if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
 		return;
 
-	trace_ath10k_wmi_event(id, skb->data, skb->len);
+	trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
+
+	consumed = ath10k_tm_event_wmi(ar, id, skb);
+
+	/* Ready event must be handled normally also in UTF mode so that we
+	 * know the UTF firmware has booted, others we are just bypass WMI
+	 * events to testmode.
+	 */
+	if (consumed && id != WMI_10X_READY_EVENTID) {
+		ath10k_dbg(ar, ATH10K_DBG_WMI,
+			   "wmi testmode consumed 0x%x\n", id);
+		goto out;
+	}
 
 	switch (id) {
 	case WMI_10X_MGMT_RX_EVENTID:
@@ -2317,28 +2591,156 @@
 	case WMI_10X_READY_EVENTID:
 		ath10k_wmi_ready_event_rx(ar, skb);
 		break;
+	case WMI_10X_PDEV_UTF_EVENTID:
+		/* ignore utf events */
+		break;
 	default:
-		ath10k_warn("Unknown eventid: %d\n", id);
+		ath10k_warn(ar, "Unknown eventid: %d\n", id);
+		break;
+	}
+
+out:
+	dev_kfree_skb(skb);
+}
+
+static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb)
+{
+	struct wmi_cmd_hdr *cmd_hdr;
+	enum wmi_10_2_event_id id;
+
+	cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
+	id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
+
+	if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
+		return;
+
+	trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
+
+	switch (id) {
+	case WMI_10_2_MGMT_RX_EVENTID:
+		ath10k_wmi_event_mgmt_rx(ar, skb);
+		/* mgmt_rx() owns the skb now! */
+		return;
+	case WMI_10_2_SCAN_EVENTID:
+		ath10k_wmi_event_scan(ar, skb);
+		break;
+	case WMI_10_2_CHAN_INFO_EVENTID:
+		ath10k_wmi_event_chan_info(ar, skb);
+		break;
+	case WMI_10_2_ECHO_EVENTID:
+		ath10k_wmi_event_echo(ar, skb);
+		break;
+	case WMI_10_2_DEBUG_MESG_EVENTID:
+		ath10k_wmi_event_debug_mesg(ar, skb);
+		break;
+	case WMI_10_2_UPDATE_STATS_EVENTID:
+		ath10k_wmi_event_update_stats(ar, skb);
+		break;
+	case WMI_10_2_VDEV_START_RESP_EVENTID:
+		ath10k_wmi_event_vdev_start_resp(ar, skb);
+		break;
+	case WMI_10_2_VDEV_STOPPED_EVENTID:
+		ath10k_wmi_event_vdev_stopped(ar, skb);
+		break;
+	case WMI_10_2_PEER_STA_KICKOUT_EVENTID:
+		ath10k_wmi_event_peer_sta_kickout(ar, skb);
+		break;
+	case WMI_10_2_HOST_SWBA_EVENTID:
+		ath10k_wmi_event_host_swba(ar, skb);
+		break;
+	case WMI_10_2_TBTTOFFSET_UPDATE_EVENTID:
+		ath10k_wmi_event_tbttoffset_update(ar, skb);
+		break;
+	case WMI_10_2_PHYERR_EVENTID:
+		ath10k_wmi_event_phyerr(ar, skb);
+		break;
+	case WMI_10_2_ROAM_EVENTID:
+		ath10k_wmi_event_roam(ar, skb);
+		break;
+	case WMI_10_2_PROFILE_MATCH:
+		ath10k_wmi_event_profile_match(ar, skb);
+		break;
+	case WMI_10_2_DEBUG_PRINT_EVENTID:
+		ath10k_wmi_event_debug_print(ar, skb);
+		break;
+	case WMI_10_2_PDEV_QVIT_EVENTID:
+		ath10k_wmi_event_pdev_qvit(ar, skb);
+		break;
+	case WMI_10_2_WLAN_PROFILE_DATA_EVENTID:
+		ath10k_wmi_event_wlan_profile_data(ar, skb);
+		break;
+	case WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID:
+		ath10k_wmi_event_rtt_measurement_report(ar, skb);
+		break;
+	case WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID:
+		ath10k_wmi_event_tsf_measurement_report(ar, skb);
+		break;
+	case WMI_10_2_RTT_ERROR_REPORT_EVENTID:
+		ath10k_wmi_event_rtt_error_report(ar, skb);
+		break;
+	case WMI_10_2_WOW_WAKEUP_HOST_EVENTID:
+		ath10k_wmi_event_wow_wakeup_host(ar, skb);
+		break;
+	case WMI_10_2_DCS_INTERFERENCE_EVENTID:
+		ath10k_wmi_event_dcs_interference(ar, skb);
+		break;
+	case WMI_10_2_PDEV_TPC_CONFIG_EVENTID:
+		ath10k_wmi_event_pdev_tpc_config(ar, skb);
+		break;
+	case WMI_10_2_INST_RSSI_STATS_EVENTID:
+		ath10k_wmi_event_inst_rssi_stats(ar, skb);
+		break;
+	case WMI_10_2_VDEV_STANDBY_REQ_EVENTID:
+		ath10k_wmi_event_vdev_standby_req(ar, skb);
+		break;
+	case WMI_10_2_VDEV_RESUME_REQ_EVENTID:
+		ath10k_wmi_event_vdev_resume_req(ar, skb);
+		break;
+	case WMI_10_2_SERVICE_READY_EVENTID:
+		ath10k_wmi_10x_service_ready_event_rx(ar, skb);
+		break;
+	case WMI_10_2_READY_EVENTID:
+		ath10k_wmi_ready_event_rx(ar, skb);
+		break;
+	case WMI_10_2_RTT_KEEPALIVE_EVENTID:
+	case WMI_10_2_GPIO_INPUT_EVENTID:
+	case WMI_10_2_PEER_RATECODE_LIST_EVENTID:
+	case WMI_10_2_GENERIC_BUFFER_EVENTID:
+	case WMI_10_2_MCAST_BUF_RELEASE_EVENTID:
+	case WMI_10_2_MCAST_LIST_AGEOUT_EVENTID:
+	case WMI_10_2_WDS_PEER_EVENTID:
+		ath10k_dbg(ar, ATH10K_DBG_WMI,
+			   "received event id %d not implemented\n", id);
+		break;
+	default:
+		ath10k_warn(ar, "Unknown eventid: %d\n", id);
 		break;
 	}
 
 	dev_kfree_skb(skb);
 }
 
-
 static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
 {
-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-		ath10k_wmi_10x_process_rx(ar, skb);
-	else
+	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+			ath10k_wmi_10_2_process_rx(ar, skb);
+		else
+			ath10k_wmi_10x_process_rx(ar, skb);
+	} else {
 		ath10k_wmi_main_process_rx(ar, skb);
+	}
 }
 
 /* WMI Initialization functions */
 int ath10k_wmi_attach(struct ath10k *ar)
 {
 	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-		ar->wmi.cmd = &wmi_10x_cmd_map;
+		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+			ar->wmi.cmd = &wmi_10_2_cmd_map;
+		else
+			ar->wmi.cmd = &wmi_10x_cmd_map;
+
 		ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
 		ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
 	} else {
@@ -2388,7 +2790,7 @@
 
 	status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp);
 	if (status) {
-		ath10k_warn("failed to connect to WMI CONTROL service status: %d\n",
+		ath10k_warn(ar, "failed to connect to WMI CONTROL service status: %d\n",
 			    status);
 		return status;
 	}
@@ -2404,7 +2806,7 @@
 	struct wmi_pdev_set_regdomain_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -2415,7 +2817,7 @@
 	cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g);
 	cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n",
 		   rd, rd2g, rd5g, ctl2g, ctl5g);
 
@@ -2431,7 +2833,7 @@
 	struct wmi_pdev_set_regdomain_cmd_10x *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -2443,7 +2845,7 @@
 	cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g);
 	cmd->dfs_domain = __cpu_to_le32(dfs_reg);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n",
 		   rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg);
 
@@ -2473,7 +2875,7 @@
 	if (arg->passive)
 		return -EINVAL;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -2491,7 +2893,7 @@
 	cmd->chan.reg_classid       = arg->reg_class_id;
 	cmd->chan.antenna_max       = arg->max_antenna_gain;
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi set channel mode %d freq %d\n",
 		   arg->mode, arg->freq);
 
@@ -2504,7 +2906,7 @@
 	struct wmi_pdev_suspend_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -2518,7 +2920,7 @@
 {
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(0);
+	skb = ath10k_wmi_alloc_skb(ar, 0);
 	if (skb == NULL)
 		return -ENOMEM;
 
@@ -2531,11 +2933,12 @@
 	struct sk_buff *skb;
 
 	if (id == WMI_PDEV_PARAM_UNSUPPORTED) {
-		ath10k_warn("pdev param %d not supported by firmware\n", id);
+		ath10k_warn(ar, "pdev param %d not supported by firmware\n",
+			    id);
 		return -EOPNOTSUPP;
 	}
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -2543,7 +2946,7 @@
 	cmd->param_id    = __cpu_to_le32(id);
 	cmd->param_value = __cpu_to_le32(value);
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",
 		   id, value);
 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
 }
@@ -2610,7 +3013,7 @@
 	len = sizeof(*cmd) +
 	      (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
 
-	buf = ath10k_wmi_alloc_skb(len);
+	buf = ath10k_wmi_alloc_skb(ar, len);
 	if (!buf)
 		return -ENOMEM;
 
@@ -2621,7 +3024,7 @@
 		goto out;
 	}
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
 		   ar->wmi.num_mem_chunks);
 
 	cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
@@ -2634,7 +3037,7 @@
 		cmd->host_mem_chunks[i].req_id =
 			__cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
 
-		ath10k_dbg(ATH10K_DBG_WMI,
+		ath10k_dbg(ar, ATH10K_DBG_WMI,
 			   "wmi chunk %d len %d requested, addr 0x%llx\n",
 			   i,
 			   ar->wmi.mem_chunks[i].len,
@@ -2643,7 +3046,7 @@
 out:
 	memcpy(&cmd->resource_config, &config, sizeof(config));
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi init\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n");
 	return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
 }
 
@@ -2701,7 +3104,7 @@
 	len = sizeof(*cmd) +
 	      (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
 
-	buf = ath10k_wmi_alloc_skb(len);
+	buf = ath10k_wmi_alloc_skb(ar, len);
 	if (!buf)
 		return -ENOMEM;
 
@@ -2712,7 +3115,7 @@
 		goto out;
 	}
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
 		   ar->wmi.num_mem_chunks);
 
 	cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
@@ -2725,7 +3128,7 @@
 		cmd->host_mem_chunks[i].req_id =
 			__cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
 
-		ath10k_dbg(ATH10K_DBG_WMI,
+		ath10k_dbg(ar, ATH10K_DBG_WMI,
 			   "wmi chunk %d len %d requested, addr 0x%llx\n",
 			   i,
 			   ar->wmi.mem_chunks[i].len,
@@ -2734,7 +3137,98 @@
 out:
 	memcpy(&cmd->resource_config, &config, sizeof(config));
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi init 10x\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n");
+	return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
+}
+
+static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
+{
+	struct wmi_init_cmd_10_2 *cmd;
+	struct sk_buff *buf;
+	struct wmi_resource_config_10x config = {};
+	u32 len, val;
+	int i;
+
+	config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
+	config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
+	config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
+	config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
+	config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT);
+	config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
+	config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
+	config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+	config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+	config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+	config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI);
+	config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE);
+
+	config.scan_max_pending_reqs =
+		__cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS);
+
+	config.bmiss_offload_max_vdev =
+		__cpu_to_le32(TARGET_10X_BMISS_OFFLOAD_MAX_VDEV);
+
+	config.roam_offload_max_vdev =
+		__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_VDEV);
+
+	config.roam_offload_max_ap_profiles =
+		__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES);
+
+	config.num_mcast_groups = __cpu_to_le32(TARGET_10X_NUM_MCAST_GROUPS);
+	config.num_mcast_table_elems =
+		__cpu_to_le32(TARGET_10X_NUM_MCAST_TABLE_ELEMS);
+
+	config.mcast2ucast_mode = __cpu_to_le32(TARGET_10X_MCAST2UCAST_MODE);
+	config.tx_dbg_log_size = __cpu_to_le32(TARGET_10X_TX_DBG_LOG_SIZE);
+	config.num_wds_entries = __cpu_to_le32(TARGET_10X_NUM_WDS_ENTRIES);
+	config.dma_burst_size = __cpu_to_le32(TARGET_10X_DMA_BURST_SIZE);
+	config.mac_aggr_delim = __cpu_to_le32(TARGET_10X_MAC_AGGR_DELIM);
+
+	val = TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK;
+	config.rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(val);
+
+	config.vow_config = __cpu_to_le32(TARGET_10X_VOW_CONFIG);
+
+	config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC);
+	config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES);
+
+	len = sizeof(*cmd) +
+	      (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
+
+	buf = ath10k_wmi_alloc_skb(ar, len);
+	if (!buf)
+		return -ENOMEM;
+
+	cmd = (struct wmi_init_cmd_10_2 *)buf->data;
+
+	if (ar->wmi.num_mem_chunks == 0) {
+		cmd->num_host_mem_chunks = 0;
+		goto out;
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
+		   ar->wmi.num_mem_chunks);
+
+	cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
+
+	for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
+		cmd->host_mem_chunks[i].ptr =
+			__cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
+		cmd->host_mem_chunks[i].size =
+			__cpu_to_le32(ar->wmi.mem_chunks[i].len);
+		cmd->host_mem_chunks[i].req_id =
+			__cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
+
+		ath10k_dbg(ar, ATH10K_DBG_WMI,
+			   "wmi chunk %d len %d requested, addr 0x%llx\n",
+			   i,
+			   ar->wmi.mem_chunks[i].len,
+			   (unsigned long long)ar->wmi.mem_chunks[i].paddr);
+	}
+out:
+	memcpy(&cmd->resource_config.common, &config, sizeof(config));
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n");
 	return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
 }
 
@@ -2742,10 +3236,14 @@
 {
 	int ret;
 
-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-		ret = ath10k_wmi_10x_cmd_init(ar);
-	else
+	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+			ret = ath10k_wmi_10_2_cmd_init(ar);
+		else
+			ret = ath10k_wmi_10x_cmd_init(ar);
+	} else {
 		ret = ath10k_wmi_main_cmd_init(ar);
+	}
 
 	return ret;
 }
@@ -2822,7 +3320,7 @@
 	if (len < 0)
 		return len; /* len contains error code here */
 
-	skb = ath10k_wmi_alloc_skb(len);
+	skb = ath10k_wmi_alloc_skb(ar, len);
 	if (!skb)
 		return -ENOMEM;
 
@@ -2865,8 +3363,8 @@
 		channels->num_chan = __cpu_to_le32(arg->n_channels);
 
 		for (i = 0; i < arg->n_channels; i++)
-			channels->channel_list[i] =
-				__cpu_to_le32(arg->channels[i]);
+			channels->channel_list[i].freq =
+				__cpu_to_le16(arg->channels[i]);
 
 		off += sizeof(*channels);
 		off += sizeof(__le32) * arg->n_channels;
@@ -2918,7 +3416,7 @@
 		return -EINVAL;
 	}
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi start scan\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n");
 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid);
 }
 
@@ -2960,7 +3458,7 @@
 	if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF)
 		return -EINVAL;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -2976,7 +3474,7 @@
 	cmd->scan_id     = __cpu_to_le32(scan_id);
 	cmd->scan_req_id = __cpu_to_le32(req_id);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi stop scan reqid %d req_type %d vdev/scan_id %d\n",
 		   arg->req_id, arg->req_type, arg->u.scan_id);
 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid);
@@ -2990,7 +3488,7 @@
 	struct wmi_vdev_create_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -2998,9 +3496,9 @@
 	cmd->vdev_id      = __cpu_to_le32(vdev_id);
 	cmd->vdev_type    = __cpu_to_le32(type);
 	cmd->vdev_subtype = __cpu_to_le32(subtype);
-	memcpy(cmd->vdev_macaddr.addr, macaddr, ETH_ALEN);
+	ether_addr_copy(cmd->vdev_macaddr.addr, macaddr);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "WMI vdev create: id %d type %d subtype %d macaddr %pM\n",
 		   vdev_id, type, subtype, macaddr);
 
@@ -3012,22 +3510,23 @@
 	struct wmi_vdev_delete_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
 	cmd = (struct wmi_vdev_delete_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "WMI vdev delete id %d\n", vdev_id);
 
 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid);
 }
 
-static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,
-				const struct wmi_vdev_start_request_arg *arg,
-				u32 cmd_id)
+static int
+ath10k_wmi_vdev_start_restart(struct ath10k *ar,
+			      const struct wmi_vdev_start_request_arg *arg,
+			      u32 cmd_id)
 {
 	struct wmi_vdev_start_request_cmd *cmd;
 	struct sk_buff *skb;
@@ -3052,7 +3551,7 @@
 	else
 		return -EINVAL; /* should not happen, we already check cmd_id */
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -3090,9 +3589,9 @@
 	cmd->chan.reg_classid = arg->channel.reg_class_id;
 	cmd->chan.antenna_max = arg->channel.max_antenna_gain;
 
-	ath10k_dbg(ATH10K_DBG_WMI,
-		   "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, "
-		   "ch_flags: 0x%0X, max_power: %d\n", cmdname, arg->vdev_id,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
+		   "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, ch_flags: 0x%0X, max_power: %d\n",
+		   cmdname, arg->vdev_id,
 		   flags, arg->channel.freq, arg->channel.mode,
 		   cmd->chan.flags, arg->channel.max_power);
 
@@ -3108,7 +3607,7 @@
 }
 
 int ath10k_wmi_vdev_restart(struct ath10k *ar,
-		     const struct wmi_vdev_start_request_arg *arg)
+			    const struct wmi_vdev_start_request_arg *arg)
 {
 	u32 cmd_id = ar->wmi.cmd->vdev_restart_request_cmdid;
 
@@ -3120,14 +3619,14 @@
 	struct wmi_vdev_stop_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
 	cmd = (struct wmi_vdev_stop_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id);
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id);
 
 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid);
 }
@@ -3137,16 +3636,16 @@
 	struct wmi_vdev_up_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
 	cmd = (struct wmi_vdev_up_cmd *)skb->data;
 	cmd->vdev_id       = __cpu_to_le32(vdev_id);
 	cmd->vdev_assoc_id = __cpu_to_le32(aid);
-	memcpy(&cmd->vdev_bssid.addr, bssid, ETH_ALEN);
+	ether_addr_copy(cmd->vdev_bssid.addr, bssid);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n",
 		   vdev_id, aid, bssid);
 
@@ -3158,14 +3657,14 @@
 	struct wmi_vdev_down_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
 	cmd = (struct wmi_vdev_down_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi mgmt vdev down id 0x%x\n", vdev_id);
 
 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid);
@@ -3178,13 +3677,13 @@
 	struct sk_buff *skb;
 
 	if (param_id == WMI_VDEV_PARAM_UNSUPPORTED) {
-		ath10k_dbg(ATH10K_DBG_WMI,
+		ath10k_dbg(ar, ATH10K_DBG_WMI,
 			   "vdev param %d not supported by firmware\n",
 			    param_id);
 		return -EOPNOTSUPP;
 	}
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -3193,7 +3692,7 @@
 	cmd->param_id    = __cpu_to_le32(param_id);
 	cmd->param_value = __cpu_to_le32(param_value);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi vdev id 0x%x set param %d value %d\n",
 		   vdev_id, param_id, param_value);
 
@@ -3211,7 +3710,7 @@
 	if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL)
 		return -EINVAL;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->key_len);
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + arg->key_len);
 	if (!skb)
 		return -ENOMEM;
 
@@ -3225,32 +3724,88 @@
 	cmd->key_rxmic_len = __cpu_to_le32(arg->key_rxmic_len);
 
 	if (arg->macaddr)
-		memcpy(cmd->peer_macaddr.addr, arg->macaddr, ETH_ALEN);
+		ether_addr_copy(cmd->peer_macaddr.addr, arg->macaddr);
 	if (arg->key_data)
 		memcpy(cmd->key_data, arg->key_data, arg->key_len);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi vdev install key idx %d cipher %d len %d\n",
 		   arg->key_idx, arg->key_cipher, arg->key_len);
 	return ath10k_wmi_cmd_send(ar, skb,
 				   ar->wmi.cmd->vdev_install_key_cmdid);
 }
 
+int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
+				  const struct wmi_vdev_spectral_conf_arg *arg)
+{
+	struct wmi_vdev_spectral_conf_cmd *cmd;
+	struct sk_buff *skb;
+	u32 cmdid;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_vdev_spectral_conf_cmd *)skb->data;
+	cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+	cmd->scan_count = __cpu_to_le32(arg->scan_count);
+	cmd->scan_period = __cpu_to_le32(arg->scan_period);
+	cmd->scan_priority = __cpu_to_le32(arg->scan_priority);
+	cmd->scan_fft_size = __cpu_to_le32(arg->scan_fft_size);
+	cmd->scan_gc_ena = __cpu_to_le32(arg->scan_gc_ena);
+	cmd->scan_restart_ena = __cpu_to_le32(arg->scan_restart_ena);
+	cmd->scan_noise_floor_ref = __cpu_to_le32(arg->scan_noise_floor_ref);
+	cmd->scan_init_delay = __cpu_to_le32(arg->scan_init_delay);
+	cmd->scan_nb_tone_thr = __cpu_to_le32(arg->scan_nb_tone_thr);
+	cmd->scan_str_bin_thr = __cpu_to_le32(arg->scan_str_bin_thr);
+	cmd->scan_wb_rpt_mode = __cpu_to_le32(arg->scan_wb_rpt_mode);
+	cmd->scan_rssi_rpt_mode = __cpu_to_le32(arg->scan_rssi_rpt_mode);
+	cmd->scan_rssi_thr = __cpu_to_le32(arg->scan_rssi_thr);
+	cmd->scan_pwr_format = __cpu_to_le32(arg->scan_pwr_format);
+	cmd->scan_rpt_mode = __cpu_to_le32(arg->scan_rpt_mode);
+	cmd->scan_bin_scale = __cpu_to_le32(arg->scan_bin_scale);
+	cmd->scan_dbm_adj = __cpu_to_le32(arg->scan_dbm_adj);
+	cmd->scan_chn_mask = __cpu_to_le32(arg->scan_chn_mask);
+
+	cmdid = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid;
+	return ath10k_wmi_cmd_send(ar, skb, cmdid);
+}
+
+int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
+				    u32 enable)
+{
+	struct wmi_vdev_spectral_enable_cmd *cmd;
+	struct sk_buff *skb;
+	u32 cmdid;
+
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_vdev_spectral_enable_cmd *)skb->data;
+	cmd->vdev_id = __cpu_to_le32(vdev_id);
+	cmd->trigger_cmd = __cpu_to_le32(trigger);
+	cmd->enable_cmd = __cpu_to_le32(enable);
+
+	cmdid = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid;
+	return ath10k_wmi_cmd_send(ar, skb, cmdid);
+}
+
 int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
 			   const u8 peer_addr[ETH_ALEN])
 {
 	struct wmi_peer_create_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
 	cmd = (struct wmi_peer_create_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
-	memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
+	ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi peer create vdev_id %d peer_addr %pM\n",
 		   vdev_id, peer_addr);
 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid);
@@ -3262,15 +3817,15 @@
 	struct wmi_peer_delete_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
 	cmd = (struct wmi_peer_delete_cmd *)skb->data;
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
-	memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
+	ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi peer delete vdev_id %d peer_addr %pM\n",
 		   vdev_id, peer_addr);
 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid);
@@ -3282,16 +3837,16 @@
 	struct wmi_peer_flush_tids_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
 	cmd = (struct wmi_peer_flush_tids_cmd *)skb->data;
 	cmd->vdev_id         = __cpu_to_le32(vdev_id);
 	cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap);
-	memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
+	ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi peer flush vdev_id %d peer_addr %pM tids %08x\n",
 		   vdev_id, peer_addr, tid_bitmap);
 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid);
@@ -3304,7 +3859,7 @@
 	struct wmi_peer_set_param_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -3312,9 +3867,9 @@
 	cmd->vdev_id     = __cpu_to_le32(vdev_id);
 	cmd->param_id    = __cpu_to_le32(param_id);
 	cmd->param_value = __cpu_to_le32(param_value);
-	memcpy(&cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
+	ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi vdev %d peer 0x%pM set param %d value %d\n",
 		   vdev_id, peer_addr, param_id, param_value);
 
@@ -3327,7 +3882,7 @@
 	struct wmi_sta_powersave_mode_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -3335,7 +3890,7 @@
 	cmd->vdev_id     = __cpu_to_le32(vdev_id);
 	cmd->sta_ps_mode = __cpu_to_le32(psmode);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi set powersave id 0x%x mode %d\n",
 		   vdev_id, psmode);
 
@@ -3350,7 +3905,7 @@
 	struct wmi_sta_powersave_param_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -3359,7 +3914,7 @@
 	cmd->param_id    = __cpu_to_le32(param_id);
 	cmd->param_value = __cpu_to_le32(value);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi sta ps param vdev_id 0x%x param %d value %d\n",
 		   vdev_id, param_id, value);
 	return ath10k_wmi_cmd_send(ar, skb,
@@ -3375,7 +3930,7 @@
 	if (!mac)
 		return -EINVAL;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -3383,9 +3938,9 @@
 	cmd->vdev_id = __cpu_to_le32(vdev_id);
 	cmd->param_id = __cpu_to_le32(param_id);
 	cmd->param_value = __cpu_to_le32(value);
-	memcpy(&cmd->peer_macaddr, mac, ETH_ALEN);
+	ether_addr_copy(cmd->peer_macaddr.addr, mac);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n",
 		   vdev_id, param_id, value, mac);
 
@@ -3405,7 +3960,7 @@
 
 	len = sizeof(*cmd) + arg->n_channels * sizeof(struct wmi_channel);
 
-	skb = ath10k_wmi_alloc_skb(len);
+	skb = ath10k_wmi_alloc_skb(ar, len);
 	if (!skb)
 		return -EINVAL;
 
@@ -3447,24 +4002,12 @@
 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
 }
 
-int ath10k_wmi_peer_assoc(struct ath10k *ar,
-			  const struct wmi_peer_assoc_complete_arg *arg)
+static void
+ath10k_wmi_peer_assoc_fill(struct ath10k *ar, void *buf,
+			   const struct wmi_peer_assoc_complete_arg *arg)
 {
-	struct wmi_peer_assoc_complete_cmd *cmd;
-	struct sk_buff *skb;
+	struct wmi_common_peer_assoc_complete_cmd *cmd = buf;
 
-	if (arg->peer_mpdu_density > 16)
-		return -EINVAL;
-	if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
-		return -EINVAL;
-	if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
-		return -EINVAL;
-
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
-	if (!skb)
-		return -ENOMEM;
-
-	cmd = (struct wmi_peer_assoc_complete_cmd *)skb->data;
 	cmd->vdev_id            = __cpu_to_le32(arg->vdev_id);
 	cmd->peer_new_assoc     = __cpu_to_le32(arg->peer_reassoc ? 0 : 1);
 	cmd->peer_associd       = __cpu_to_le32(arg->peer_aid);
@@ -3479,7 +4022,7 @@
 	cmd->peer_vht_caps      = __cpu_to_le32(arg->peer_vht_caps);
 	cmd->peer_phymode       = __cpu_to_le32(arg->peer_phymode);
 
-	memcpy(cmd->peer_macaddr.addr, arg->addr, ETH_ALEN);
+	ether_addr_copy(cmd->peer_macaddr.addr, arg->addr);
 
 	cmd->peer_legacy_rates.num_rates =
 		__cpu_to_le32(arg->peer_legacy_rates.num_rates);
@@ -3499,8 +4042,80 @@
 		__cpu_to_le32(arg->peer_vht_rates.tx_max_rate);
 	cmd->peer_vht_rates.tx_mcs_set =
 		__cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);
+}
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+static void
+ath10k_wmi_peer_assoc_fill_main(struct ath10k *ar, void *buf,
+				const struct wmi_peer_assoc_complete_arg *arg)
+{
+	struct wmi_main_peer_assoc_complete_cmd *cmd = buf;
+
+	ath10k_wmi_peer_assoc_fill(ar, buf, arg);
+	memset(cmd->peer_ht_info, 0, sizeof(cmd->peer_ht_info));
+}
+
+static void
+ath10k_wmi_peer_assoc_fill_10_1(struct ath10k *ar, void *buf,
+				const struct wmi_peer_assoc_complete_arg *arg)
+{
+	ath10k_wmi_peer_assoc_fill(ar, buf, arg);
+}
+
+static void
+ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf,
+				const struct wmi_peer_assoc_complete_arg *arg)
+{
+	struct wmi_10_2_peer_assoc_complete_cmd *cmd = buf;
+	int max_mcs, max_nss;
+	u32 info0;
+
+	/* TODO: Is using max values okay with firmware? */
+	max_mcs = 0xf;
+	max_nss = 0xf;
+
+	info0 = SM(max_mcs, WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX) |
+		SM(max_nss, WMI_PEER_ASSOC_INFO0_MAX_NSS);
+
+	ath10k_wmi_peer_assoc_fill(ar, buf, arg);
+	cmd->info0 = __cpu_to_le32(info0);
+}
+
+int ath10k_wmi_peer_assoc(struct ath10k *ar,
+			  const struct wmi_peer_assoc_complete_arg *arg)
+{
+	struct sk_buff *skb;
+	int len;
+
+	if (arg->peer_mpdu_density > 16)
+		return -EINVAL;
+	if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
+		return -EINVAL;
+	if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
+		return -EINVAL;
+
+	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+			len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd);
+		else
+			len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd);
+	} else {
+		len = sizeof(struct wmi_main_peer_assoc_complete_cmd);
+	}
+
+	skb = ath10k_wmi_alloc_skb(ar, len);
+	if (!skb)
+		return -ENOMEM;
+
+	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+			ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
+		else
+			ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg);
+	} else {
+		ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg);
+	}
+
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi peer assoc vdev %d addr %pM (%s)\n",
 		   arg->vdev_id, arg->addr,
 		   arg->peer_reassoc ? "reassociate" : "new");
@@ -3518,7 +4133,7 @@
 	int ret;
 	u16 fc;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -3532,6 +4147,7 @@
 	cmd->msdu_id = 0;
 	cmd->frame_control = __cpu_to_le32(fc);
 	cmd->flags = 0;
+	cmd->antenna_mask = __cpu_to_le32(WMI_BCN_TX_REF_DEF_ANTENNA);
 
 	if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
 		cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
@@ -3560,12 +4176,12 @@
 }
 
 int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
-			const struct wmi_pdev_set_wmm_params_arg *arg)
+				   const struct wmi_pdev_set_wmm_params_arg *arg)
 {
 	struct wmi_pdev_set_wmm_params *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -3575,7 +4191,7 @@
 	ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vi, &arg->ac_vi);
 	ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo);
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set wmm params\n");
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set wmm params\n");
 	return ath10k_wmi_cmd_send(ar, skb,
 				   ar->wmi.cmd->pdev_set_wmm_params_cmdid);
 }
@@ -3585,14 +4201,14 @@
 	struct wmi_request_stats_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
 	cmd = (struct wmi_request_stats_cmd *)skb->data;
 	cmd->stats_id = __cpu_to_le32(stats_id);
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
 }
 
@@ -3602,7 +4218,7 @@
 	struct wmi_force_fw_hang_cmd *cmd;
 	struct sk_buff *skb;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -3610,7 +4226,7 @@
 	cmd->type = __cpu_to_le32(type);
 	cmd->delay_ms = __cpu_to_le32(delay_ms);
 
-	ath10k_dbg(ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
+	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
 		   type, delay_ms);
 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
 }
@@ -3621,7 +4237,7 @@
 	struct sk_buff *skb;
 	u32 cfg;
 
-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
 	if (!skb)
 		return -ENOMEM;
 
@@ -3642,7 +4258,7 @@
 	cmd->config_enable = __cpu_to_le32(cfg);
 	cmd->config_valid = __cpu_to_le32(ATH10K_DBGLOG_CFG_LOG_LVL_MASK);
 
-	ath10k_dbg(ATH10K_DBG_WMI,
+	ath10k_dbg(ar, ATH10K_DBG_WMI,
 		   "wmi dbglog cfg modules %08x %08x config %08x %08x\n",
 		   __le32_to_cpu(cmd->module_enable),
 		   __le32_to_cpu(cmd->module_valid),
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index e93df2c..86f5ebc 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -73,119 +73,280 @@
 #define HTC_PROTOCOL_VERSION    0x0002
 #define WMI_PROTOCOL_VERSION    0x0002
 
-enum wmi_service_id {
-	WMI_SERVICE_BEACON_OFFLOAD = 0,   /* beacon offload */
-	WMI_SERVICE_SCAN_OFFLOAD,	  /* scan offload */
-	WMI_SERVICE_ROAM_OFFLOAD,	  /* roam offload */
-	WMI_SERVICE_BCN_MISS_OFFLOAD,     /* beacon miss offload */
-	WMI_SERVICE_STA_PWRSAVE,	  /* fake sleep + basic power save */
-	WMI_SERVICE_STA_ADVANCED_PWRSAVE, /* uapsd, pspoll, force sleep */
-	WMI_SERVICE_AP_UAPSD,		  /* uapsd on AP */
-	WMI_SERVICE_AP_DFS,		  /* DFS on AP */
-	WMI_SERVICE_11AC,		  /* supports 11ac */
-	WMI_SERVICE_BLOCKACK,	/* Supports triggering ADDBA/DELBA from host*/
-	WMI_SERVICE_PHYERR,		  /* PHY error */
-	WMI_SERVICE_BCN_FILTER,		  /* Beacon filter support */
-	WMI_SERVICE_RTT,		  /* RTT (round trip time) support */
-	WMI_SERVICE_RATECTRL,		  /* Rate-control */
-	WMI_SERVICE_WOW,		  /* WOW Support */
-	WMI_SERVICE_RATECTRL_CACHE,       /* Rate-control caching */
-	WMI_SERVICE_IRAM_TIDS,            /* TIDs in IRAM */
-	WMI_SERVICE_ARPNS_OFFLOAD,	  /* ARP NS Offload support */
-	WMI_SERVICE_NLO,		  /* Network list offload service */
-	WMI_SERVICE_GTK_OFFLOAD,	  /* GTK offload */
-	WMI_SERVICE_SCAN_SCH,		  /* Scan Scheduler Service */
-	WMI_SERVICE_CSA_OFFLOAD,	  /* CSA offload service */
-	WMI_SERVICE_CHATTER,		  /* Chatter service */
-	WMI_SERVICE_COEX_FREQAVOID,	  /* FW report freq range to avoid */
-	WMI_SERVICE_PACKET_POWER_SAVE,	  /* packet power save service */
-	WMI_SERVICE_FORCE_FW_HANG,        /* To test fw recovery mechanism */
-	WMI_SERVICE_GPIO,                 /* GPIO service */
-	WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, /* Modulated DTIM support */
-	WMI_STA_UAPSD_BASIC_AUTO_TRIG,    /* UAPSD AC Trigger Generation  */
-	WMI_STA_UAPSD_VAR_AUTO_TRIG,      /* -do- */
-	WMI_SERVICE_STA_KEEP_ALIVE,       /* STA keep alive mechanism support */
-	WMI_SERVICE_TX_ENCAP,             /* Packet type for TX encapsulation */
+enum wmi_service {
+	WMI_SERVICE_BEACON_OFFLOAD = 0,
+	WMI_SERVICE_SCAN_OFFLOAD,
+	WMI_SERVICE_ROAM_OFFLOAD,
+	WMI_SERVICE_BCN_MISS_OFFLOAD,
+	WMI_SERVICE_STA_PWRSAVE,
+	WMI_SERVICE_STA_ADVANCED_PWRSAVE,
+	WMI_SERVICE_AP_UAPSD,
+	WMI_SERVICE_AP_DFS,
+	WMI_SERVICE_11AC,
+	WMI_SERVICE_BLOCKACK,
+	WMI_SERVICE_PHYERR,
+	WMI_SERVICE_BCN_FILTER,
+	WMI_SERVICE_RTT,
+	WMI_SERVICE_RATECTRL,
+	WMI_SERVICE_WOW,
+	WMI_SERVICE_RATECTRL_CACHE,
+	WMI_SERVICE_IRAM_TIDS,
+	WMI_SERVICE_ARPNS_OFFLOAD,
+	WMI_SERVICE_NLO,
+	WMI_SERVICE_GTK_OFFLOAD,
+	WMI_SERVICE_SCAN_SCH,
+	WMI_SERVICE_CSA_OFFLOAD,
+	WMI_SERVICE_CHATTER,
+	WMI_SERVICE_COEX_FREQAVOID,
+	WMI_SERVICE_PACKET_POWER_SAVE,
+	WMI_SERVICE_FORCE_FW_HANG,
+	WMI_SERVICE_GPIO,
+	WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+	WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+	WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+	WMI_SERVICE_STA_KEEP_ALIVE,
+	WMI_SERVICE_TX_ENCAP,
+	WMI_SERVICE_BURST,
+	WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+	WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT,
 
-	WMI_SERVICE_LAST,
-	WMI_MAX_SERVICE = 64		  /* max service */
+	/* keep last */
+	WMI_SERVICE_MAX,
+};
+
+enum wmi_10x_service {
+	WMI_10X_SERVICE_BEACON_OFFLOAD = 0,
+	WMI_10X_SERVICE_SCAN_OFFLOAD,
+	WMI_10X_SERVICE_ROAM_OFFLOAD,
+	WMI_10X_SERVICE_BCN_MISS_OFFLOAD,
+	WMI_10X_SERVICE_STA_PWRSAVE,
+	WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE,
+	WMI_10X_SERVICE_AP_UAPSD,
+	WMI_10X_SERVICE_AP_DFS,
+	WMI_10X_SERVICE_11AC,
+	WMI_10X_SERVICE_BLOCKACK,
+	WMI_10X_SERVICE_PHYERR,
+	WMI_10X_SERVICE_BCN_FILTER,
+	WMI_10X_SERVICE_RTT,
+	WMI_10X_SERVICE_RATECTRL,
+	WMI_10X_SERVICE_WOW,
+	WMI_10X_SERVICE_RATECTRL_CACHE,
+	WMI_10X_SERVICE_IRAM_TIDS,
+	WMI_10X_SERVICE_BURST,
+
+	/* introduced in 10.2 */
+	WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+	WMI_10X_SERVICE_FORCE_FW_HANG,
+	WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+};
+
+enum wmi_main_service {
+	WMI_MAIN_SERVICE_BEACON_OFFLOAD = 0,
+	WMI_MAIN_SERVICE_SCAN_OFFLOAD,
+	WMI_MAIN_SERVICE_ROAM_OFFLOAD,
+	WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD,
+	WMI_MAIN_SERVICE_STA_PWRSAVE,
+	WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE,
+	WMI_MAIN_SERVICE_AP_UAPSD,
+	WMI_MAIN_SERVICE_AP_DFS,
+	WMI_MAIN_SERVICE_11AC,
+	WMI_MAIN_SERVICE_BLOCKACK,
+	WMI_MAIN_SERVICE_PHYERR,
+	WMI_MAIN_SERVICE_BCN_FILTER,
+	WMI_MAIN_SERVICE_RTT,
+	WMI_MAIN_SERVICE_RATECTRL,
+	WMI_MAIN_SERVICE_WOW,
+	WMI_MAIN_SERVICE_RATECTRL_CACHE,
+	WMI_MAIN_SERVICE_IRAM_TIDS,
+	WMI_MAIN_SERVICE_ARPNS_OFFLOAD,
+	WMI_MAIN_SERVICE_NLO,
+	WMI_MAIN_SERVICE_GTK_OFFLOAD,
+	WMI_MAIN_SERVICE_SCAN_SCH,
+	WMI_MAIN_SERVICE_CSA_OFFLOAD,
+	WMI_MAIN_SERVICE_CHATTER,
+	WMI_MAIN_SERVICE_COEX_FREQAVOID,
+	WMI_MAIN_SERVICE_PACKET_POWER_SAVE,
+	WMI_MAIN_SERVICE_FORCE_FW_HANG,
+	WMI_MAIN_SERVICE_GPIO,
+	WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+	WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+	WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+	WMI_MAIN_SERVICE_STA_KEEP_ALIVE,
+	WMI_MAIN_SERVICE_TX_ENCAP,
 };
 
 static inline char *wmi_service_name(int service_id)
 {
+#define SVCSTR(x) case x: return #x
+
 	switch (service_id) {
-	case WMI_SERVICE_BEACON_OFFLOAD:
-		return "BEACON_OFFLOAD";
-	case WMI_SERVICE_SCAN_OFFLOAD:
-		return "SCAN_OFFLOAD";
-	case WMI_SERVICE_ROAM_OFFLOAD:
-		return "ROAM_OFFLOAD";
-	case WMI_SERVICE_BCN_MISS_OFFLOAD:
-		return "BCN_MISS_OFFLOAD";
-	case WMI_SERVICE_STA_PWRSAVE:
-		return "STA_PWRSAVE";
-	case WMI_SERVICE_STA_ADVANCED_PWRSAVE:
-		return "STA_ADVANCED_PWRSAVE";
-	case WMI_SERVICE_AP_UAPSD:
-		return "AP_UAPSD";
-	case WMI_SERVICE_AP_DFS:
-		return "AP_DFS";
-	case WMI_SERVICE_11AC:
-		return "11AC";
-	case WMI_SERVICE_BLOCKACK:
-		return "BLOCKACK";
-	case WMI_SERVICE_PHYERR:
-		return "PHYERR";
-	case WMI_SERVICE_BCN_FILTER:
-		return "BCN_FILTER";
-	case WMI_SERVICE_RTT:
-		return "RTT";
-	case WMI_SERVICE_RATECTRL:
-		return "RATECTRL";
-	case WMI_SERVICE_WOW:
-		return "WOW";
-	case WMI_SERVICE_RATECTRL_CACHE:
-		return "RATECTRL CACHE";
-	case WMI_SERVICE_IRAM_TIDS:
-		return "IRAM TIDS";
-	case WMI_SERVICE_ARPNS_OFFLOAD:
-		return "ARPNS_OFFLOAD";
-	case WMI_SERVICE_NLO:
-		return "NLO";
-	case WMI_SERVICE_GTK_OFFLOAD:
-		return "GTK_OFFLOAD";
-	case WMI_SERVICE_SCAN_SCH:
-		return "SCAN_SCH";
-	case WMI_SERVICE_CSA_OFFLOAD:
-		return "CSA_OFFLOAD";
-	case WMI_SERVICE_CHATTER:
-		return "CHATTER";
-	case WMI_SERVICE_COEX_FREQAVOID:
-		return "COEX_FREQAVOID";
-	case WMI_SERVICE_PACKET_POWER_SAVE:
-		return "PACKET_POWER_SAVE";
-	case WMI_SERVICE_FORCE_FW_HANG:
-		return "FORCE FW HANG";
-	case WMI_SERVICE_GPIO:
-		return "GPIO";
-	case WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM:
-		return "MODULATED DTIM";
-	case WMI_STA_UAPSD_BASIC_AUTO_TRIG:
-		return "BASIC UAPSD";
-	case WMI_STA_UAPSD_VAR_AUTO_TRIG:
-		return "VAR UAPSD";
-	case WMI_SERVICE_STA_KEEP_ALIVE:
-		return "STA KEEP ALIVE";
-	case WMI_SERVICE_TX_ENCAP:
-		return "TX ENCAP";
+	SVCSTR(WMI_SERVICE_BEACON_OFFLOAD);
+	SVCSTR(WMI_SERVICE_SCAN_OFFLOAD);
+	SVCSTR(WMI_SERVICE_ROAM_OFFLOAD);
+	SVCSTR(WMI_SERVICE_BCN_MISS_OFFLOAD);
+	SVCSTR(WMI_SERVICE_STA_PWRSAVE);
+	SVCSTR(WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+	SVCSTR(WMI_SERVICE_AP_UAPSD);
+	SVCSTR(WMI_SERVICE_AP_DFS);
+	SVCSTR(WMI_SERVICE_11AC);
+	SVCSTR(WMI_SERVICE_BLOCKACK);
+	SVCSTR(WMI_SERVICE_PHYERR);
+	SVCSTR(WMI_SERVICE_BCN_FILTER);
+	SVCSTR(WMI_SERVICE_RTT);
+	SVCSTR(WMI_SERVICE_RATECTRL);
+	SVCSTR(WMI_SERVICE_WOW);
+	SVCSTR(WMI_SERVICE_RATECTRL_CACHE);
+	SVCSTR(WMI_SERVICE_IRAM_TIDS);
+	SVCSTR(WMI_SERVICE_ARPNS_OFFLOAD);
+	SVCSTR(WMI_SERVICE_NLO);
+	SVCSTR(WMI_SERVICE_GTK_OFFLOAD);
+	SVCSTR(WMI_SERVICE_SCAN_SCH);
+	SVCSTR(WMI_SERVICE_CSA_OFFLOAD);
+	SVCSTR(WMI_SERVICE_CHATTER);
+	SVCSTR(WMI_SERVICE_COEX_FREQAVOID);
+	SVCSTR(WMI_SERVICE_PACKET_POWER_SAVE);
+	SVCSTR(WMI_SERVICE_FORCE_FW_HANG);
+	SVCSTR(WMI_SERVICE_GPIO);
+	SVCSTR(WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM);
+	SVCSTR(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG);
+	SVCSTR(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG);
+	SVCSTR(WMI_SERVICE_STA_KEEP_ALIVE);
+	SVCSTR(WMI_SERVICE_TX_ENCAP);
+	SVCSTR(WMI_SERVICE_BURST);
+	SVCSTR(WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
+	SVCSTR(WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
 	default:
-		return "UNKNOWN SERVICE\n";
+		return NULL;
 	}
+
+#undef SVCSTR
 }
 
+#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \
+	(__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
+	 BIT((svc_id)%(sizeof(u32))))
 
-#define WMI_SERVICE_BM_SIZE \
-	((WMI_MAX_SERVICE + sizeof(u32) - 1)/sizeof(u32))
+#define SVCMAP(x, y) \
+	do { \
+		if (WMI_SERVICE_IS_ENABLED((in), (x))) \
+			__set_bit(y, out); \
+	} while (0)
+
+static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out)
+{
+	SVCMAP(WMI_10X_SERVICE_BEACON_OFFLOAD,
+	       WMI_SERVICE_BEACON_OFFLOAD);
+	SVCMAP(WMI_10X_SERVICE_SCAN_OFFLOAD,
+	       WMI_SERVICE_SCAN_OFFLOAD);
+	SVCMAP(WMI_10X_SERVICE_ROAM_OFFLOAD,
+	       WMI_SERVICE_ROAM_OFFLOAD);
+	SVCMAP(WMI_10X_SERVICE_BCN_MISS_OFFLOAD,
+	       WMI_SERVICE_BCN_MISS_OFFLOAD);
+	SVCMAP(WMI_10X_SERVICE_STA_PWRSAVE,
+	       WMI_SERVICE_STA_PWRSAVE);
+	SVCMAP(WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE,
+	       WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+	SVCMAP(WMI_10X_SERVICE_AP_UAPSD,
+	       WMI_SERVICE_AP_UAPSD);
+	SVCMAP(WMI_10X_SERVICE_AP_DFS,
+	       WMI_SERVICE_AP_DFS);
+	SVCMAP(WMI_10X_SERVICE_11AC,
+	       WMI_SERVICE_11AC);
+	SVCMAP(WMI_10X_SERVICE_BLOCKACK,
+	       WMI_SERVICE_BLOCKACK);
+	SVCMAP(WMI_10X_SERVICE_PHYERR,
+	       WMI_SERVICE_PHYERR);
+	SVCMAP(WMI_10X_SERVICE_BCN_FILTER,
+	       WMI_SERVICE_BCN_FILTER);
+	SVCMAP(WMI_10X_SERVICE_RTT,
+	       WMI_SERVICE_RTT);
+	SVCMAP(WMI_10X_SERVICE_RATECTRL,
+	       WMI_SERVICE_RATECTRL);
+	SVCMAP(WMI_10X_SERVICE_WOW,
+	       WMI_SERVICE_WOW);
+	SVCMAP(WMI_10X_SERVICE_RATECTRL_CACHE,
+	       WMI_SERVICE_RATECTRL_CACHE);
+	SVCMAP(WMI_10X_SERVICE_IRAM_TIDS,
+	       WMI_SERVICE_IRAM_TIDS);
+	SVCMAP(WMI_10X_SERVICE_BURST,
+	       WMI_SERVICE_BURST);
+	SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+	       WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
+	SVCMAP(WMI_10X_SERVICE_FORCE_FW_HANG,
+	       WMI_SERVICE_FORCE_FW_HANG);
+	SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+	       WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
+}
+
+static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out)
+{
+	SVCMAP(WMI_MAIN_SERVICE_BEACON_OFFLOAD,
+	       WMI_SERVICE_BEACON_OFFLOAD);
+	SVCMAP(WMI_MAIN_SERVICE_SCAN_OFFLOAD,
+	       WMI_SERVICE_SCAN_OFFLOAD);
+	SVCMAP(WMI_MAIN_SERVICE_ROAM_OFFLOAD,
+	       WMI_SERVICE_ROAM_OFFLOAD);
+	SVCMAP(WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD,
+	       WMI_SERVICE_BCN_MISS_OFFLOAD);
+	SVCMAP(WMI_MAIN_SERVICE_STA_PWRSAVE,
+	       WMI_SERVICE_STA_PWRSAVE);
+	SVCMAP(WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE,
+	       WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+	SVCMAP(WMI_MAIN_SERVICE_AP_UAPSD,
+	       WMI_SERVICE_AP_UAPSD);
+	SVCMAP(WMI_MAIN_SERVICE_AP_DFS,
+	       WMI_SERVICE_AP_DFS);
+	SVCMAP(WMI_MAIN_SERVICE_11AC,
+	       WMI_SERVICE_11AC);
+	SVCMAP(WMI_MAIN_SERVICE_BLOCKACK,
+	       WMI_SERVICE_BLOCKACK);
+	SVCMAP(WMI_MAIN_SERVICE_PHYERR,
+	       WMI_SERVICE_PHYERR);
+	SVCMAP(WMI_MAIN_SERVICE_BCN_FILTER,
+	       WMI_SERVICE_BCN_FILTER);
+	SVCMAP(WMI_MAIN_SERVICE_RTT,
+	       WMI_SERVICE_RTT);
+	SVCMAP(WMI_MAIN_SERVICE_RATECTRL,
+	       WMI_SERVICE_RATECTRL);
+	SVCMAP(WMI_MAIN_SERVICE_WOW,
+	       WMI_SERVICE_WOW);
+	SVCMAP(WMI_MAIN_SERVICE_RATECTRL_CACHE,
+	       WMI_SERVICE_RATECTRL_CACHE);
+	SVCMAP(WMI_MAIN_SERVICE_IRAM_TIDS,
+	       WMI_SERVICE_IRAM_TIDS);
+	SVCMAP(WMI_MAIN_SERVICE_ARPNS_OFFLOAD,
+	       WMI_SERVICE_ARPNS_OFFLOAD);
+	SVCMAP(WMI_MAIN_SERVICE_NLO,
+	       WMI_SERVICE_NLO);
+	SVCMAP(WMI_MAIN_SERVICE_GTK_OFFLOAD,
+	       WMI_SERVICE_GTK_OFFLOAD);
+	SVCMAP(WMI_MAIN_SERVICE_SCAN_SCH,
+	       WMI_SERVICE_SCAN_SCH);
+	SVCMAP(WMI_MAIN_SERVICE_CSA_OFFLOAD,
+	       WMI_SERVICE_CSA_OFFLOAD);
+	SVCMAP(WMI_MAIN_SERVICE_CHATTER,
+	       WMI_SERVICE_CHATTER);
+	SVCMAP(WMI_MAIN_SERVICE_COEX_FREQAVOID,
+	       WMI_SERVICE_COEX_FREQAVOID);
+	SVCMAP(WMI_MAIN_SERVICE_PACKET_POWER_SAVE,
+	       WMI_SERVICE_PACKET_POWER_SAVE);
+	SVCMAP(WMI_MAIN_SERVICE_FORCE_FW_HANG,
+	       WMI_SERVICE_FORCE_FW_HANG);
+	SVCMAP(WMI_MAIN_SERVICE_GPIO,
+	       WMI_SERVICE_GPIO);
+	SVCMAP(WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+	       WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM);
+	SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+	       WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG);
+	SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+	       WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG);
+	SVCMAP(WMI_MAIN_SERVICE_STA_KEEP_ALIVE,
+	       WMI_SERVICE_STA_KEEP_ALIVE);
+	SVCMAP(WMI_MAIN_SERVICE_TX_ENCAP,
+	       WMI_SERVICE_TX_ENCAP);
+}
+
+#undef SVCMAP
 
 /* 2 word representation of MAC addr */
 struct wmi_mac_addr {
@@ -803,6 +964,159 @@
 	WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID-1,
 };
 
+enum wmi_10_2_cmd_id {
+	WMI_10_2_START_CMDID = 0x9000,
+	WMI_10_2_END_CMDID = 0x9FFF,
+	WMI_10_2_INIT_CMDID,
+	WMI_10_2_START_SCAN_CMDID = WMI_10_2_START_CMDID,
+	WMI_10_2_STOP_SCAN_CMDID,
+	WMI_10_2_SCAN_CHAN_LIST_CMDID,
+	WMI_10_2_ECHO_CMDID,
+	WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
+	WMI_10_2_PDEV_SET_CHANNEL_CMDID,
+	WMI_10_2_PDEV_SET_PARAM_CMDID,
+	WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
+	WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
+	WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
+	WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
+	WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
+	WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
+	WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
+	WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+	WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
+	WMI_10_2_VDEV_CREATE_CMDID,
+	WMI_10_2_VDEV_DELETE_CMDID,
+	WMI_10_2_VDEV_START_REQUEST_CMDID,
+	WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
+	WMI_10_2_VDEV_UP_CMDID,
+	WMI_10_2_VDEV_STOP_CMDID,
+	WMI_10_2_VDEV_DOWN_CMDID,
+	WMI_10_2_VDEV_STANDBY_RESPONSE_CMDID,
+	WMI_10_2_VDEV_RESUME_RESPONSE_CMDID,
+	WMI_10_2_VDEV_SET_PARAM_CMDID,
+	WMI_10_2_VDEV_INSTALL_KEY_CMDID,
+	WMI_10_2_VDEV_SET_DSCP_TID_MAP_CMDID,
+	WMI_10_2_PEER_CREATE_CMDID,
+	WMI_10_2_PEER_DELETE_CMDID,
+	WMI_10_2_PEER_FLUSH_TIDS_CMDID,
+	WMI_10_2_PEER_SET_PARAM_CMDID,
+	WMI_10_2_PEER_ASSOC_CMDID,
+	WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
+	WMI_10_2_PEER_UPDATE_WDS_ENTRY_CMDID,
+	WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
+	WMI_10_2_PEER_MCAST_GROUP_CMDID,
+	WMI_10_2_BCN_TX_CMDID,
+	WMI_10_2_BCN_PRB_TMPL_CMDID,
+	WMI_10_2_BCN_FILTER_RX_CMDID,
+	WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
+	WMI_10_2_MGMT_TX_CMDID,
+	WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
+	WMI_10_2_ADDBA_SEND_CMDID,
+	WMI_10_2_ADDBA_STATUS_CMDID,
+	WMI_10_2_DELBA_SEND_CMDID,
+	WMI_10_2_ADDBA_SET_RESP_CMDID,
+	WMI_10_2_SEND_SINGLEAMSDU_CMDID,
+	WMI_10_2_STA_POWERSAVE_MODE_CMDID,
+	WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
+	WMI_10_2_STA_MIMO_PS_MODE_CMDID,
+	WMI_10_2_DBGLOG_CFG_CMDID,
+	WMI_10_2_PDEV_DFS_ENABLE_CMDID,
+	WMI_10_2_PDEV_DFS_DISABLE_CMDID,
+	WMI_10_2_PDEV_QVIT_CMDID,
+	WMI_10_2_ROAM_SCAN_MODE,
+	WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
+	WMI_10_2_ROAM_SCAN_PERIOD,
+	WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+	WMI_10_2_ROAM_AP_PROFILE,
+	WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
+	WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
+	WMI_10_2_OFL_SCAN_PERIOD,
+	WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
+	WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
+	WMI_10_2_P2P_GO_SET_BEACON_IE,
+	WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
+	WMI_10_2_AP_PS_PEER_PARAM_CMDID,
+	WMI_10_2_AP_PS_PEER_UAPSD_COEX_CMDID,
+	WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
+	WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
+	WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+	WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+	WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+	WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+	WMI_10_2_PDEV_SUSPEND_CMDID,
+	WMI_10_2_PDEV_RESUME_CMDID,
+	WMI_10_2_ADD_BCN_FILTER_CMDID,
+	WMI_10_2_RMV_BCN_FILTER_CMDID,
+	WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
+	WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
+	WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+	WMI_10_2_WOW_ENABLE_CMDID,
+	WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+	WMI_10_2_RTT_MEASREQ_CMDID,
+	WMI_10_2_RTT_TSF_CMDID,
+	WMI_10_2_RTT_KEEPALIVE_CMDID,
+	WMI_10_2_PDEV_SEND_BCN_CMDID,
+	WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
+	WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
+	WMI_10_2_REQUEST_STATS_CMDID,
+	WMI_10_2_GPIO_CONFIG_CMDID,
+	WMI_10_2_GPIO_OUTPUT_CMDID,
+	WMI_10_2_VDEV_RATEMASK_CMDID,
+	WMI_10_2_PDEV_SMART_ANT_ENABLE_CMDID,
+	WMI_10_2_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID,
+	WMI_10_2_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID,
+	WMI_10_2_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID,
+	WMI_10_2_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID,
+	WMI_10_2_FORCE_FW_HANG_CMDID,
+	WMI_10_2_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID,
+	WMI_10_2_PDEV_SET_CTL_TABLE_CMDID,
+	WMI_10_2_PDEV_SET_MIMOGAIN_TABLE_CMDID,
+	WMI_10_2_PDEV_RATEPWR_TABLE_CMDID,
+	WMI_10_2_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID,
+	WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1,
+};
+
+enum wmi_10_2_event_id {
+	WMI_10_2_SERVICE_READY_EVENTID = 0x8000,
+	WMI_10_2_READY_EVENTID,
+	WMI_10_2_DEBUG_MESG_EVENTID,
+	WMI_10_2_START_EVENTID = 0x9000,
+	WMI_10_2_END_EVENTID = 0x9FFF,
+	WMI_10_2_SCAN_EVENTID = WMI_10_2_START_EVENTID,
+	WMI_10_2_ECHO_EVENTID,
+	WMI_10_2_UPDATE_STATS_EVENTID,
+	WMI_10_2_INST_RSSI_STATS_EVENTID,
+	WMI_10_2_VDEV_START_RESP_EVENTID,
+	WMI_10_2_VDEV_STANDBY_REQ_EVENTID,
+	WMI_10_2_VDEV_RESUME_REQ_EVENTID,
+	WMI_10_2_VDEV_STOPPED_EVENTID,
+	WMI_10_2_PEER_STA_KICKOUT_EVENTID,
+	WMI_10_2_HOST_SWBA_EVENTID,
+	WMI_10_2_TBTTOFFSET_UPDATE_EVENTID,
+	WMI_10_2_MGMT_RX_EVENTID,
+	WMI_10_2_CHAN_INFO_EVENTID,
+	WMI_10_2_PHYERR_EVENTID,
+	WMI_10_2_ROAM_EVENTID,
+	WMI_10_2_PROFILE_MATCH,
+	WMI_10_2_DEBUG_PRINT_EVENTID,
+	WMI_10_2_PDEV_QVIT_EVENTID,
+	WMI_10_2_WLAN_PROFILE_DATA_EVENTID,
+	WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID,
+	WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID,
+	WMI_10_2_RTT_ERROR_REPORT_EVENTID,
+	WMI_10_2_RTT_KEEPALIVE_EVENTID,
+	WMI_10_2_WOW_WAKEUP_HOST_EVENTID,
+	WMI_10_2_DCS_INTERFERENCE_EVENTID,
+	WMI_10_2_PDEV_TPC_CONFIG_EVENTID,
+	WMI_10_2_GPIO_INPUT_EVENTID,
+	WMI_10_2_PEER_RATECODE_LIST_EVENTID,
+	WMI_10_2_GENERIC_BUFFER_EVENTID,
+	WMI_10_2_MCAST_BUF_RELEASE_EVENTID,
+	WMI_10_2_MCAST_LIST_AGEOUT_EVENTID,
+	WMI_10_2_WDS_PEER_EVENTID,
+	WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1,
+};
+
 enum wmi_phy_mode {
 	MODE_11A        = 0,   /* 11a Mode */
 	MODE_11G        = 1,   /* 11b/g Mode */
@@ -955,7 +1269,6 @@
 				WMI_HT_CAP_RX_STBC       | \
 				WMI_HT_CAP_LDPC)
 
-
 /*
  * WMI_VHT_CAP_* these maps to ieee 802.11ac vht capability information
  * field. The fields not defined here are not supported, or reserved.
@@ -1076,10 +1389,6 @@
 	__le32 num_units;
 } __packed;
 
-#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \
-	((((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
-	(1 << ((svc_id)%(sizeof(u32))))) != 0)
-
 /*
  * The following struct holds optional payload for
  * wmi_service_ready_event,e.g., 11ac pass some of the
@@ -1093,7 +1402,7 @@
 	__le32 phy_capability;
 	/* Maximum number of frag table entries that SW will populate less 1 */
 	__le32 max_frag_entry;
-	__le32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE];
+	__le32 wmi_service_bitmap[16];
 	__le32 num_rf_chains;
 	/*
 	 * The following field is only valid for service type
@@ -1132,7 +1441,7 @@
 
 	/* Maximum number of frag table entries that SW will populate less 1 */
 	__le32 max_frag_entry;
-	__le32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE];
+	__le32 wmi_service_bitmap[16];
 	__le32 num_rf_chains;
 
 	/*
@@ -1161,7 +1470,6 @@
 	struct wlan_host_mem_req mem_reqs[1];
 } __packed;
 
-
 #define WMI_SERVICE_READY_TIMEOUT_HZ (5*HZ)
 #define WMI_UNIFIED_READY_TIMEOUT_HZ (5*HZ)
 
@@ -1551,6 +1859,16 @@
 	__le32 max_frag_entries;
 } __packed;
 
+struct wmi_resource_config_10_2 {
+	struct wmi_resource_config_10x common;
+	__le32 max_peer_ext_stats;
+	__le32 smart_ant_cap; /* 0-disable, 1-enable */
+	__le32 bk_min_free;
+	__le32 be_min_free;
+	__le32 vi_min_free;
+	__le32 vo_min_free;
+	__le32 rx_batchmode; /* 0-disable, 1-enable */
+} __packed;
 
 #define NUM_UNITS_IS_NUM_VDEVS   0x1
 #define NUM_UNITS_IS_NUM_PEERS   0x2
@@ -1588,11 +1906,28 @@
 	struct host_memory_chunk host_mem_chunks[1];
 } __packed;
 
+struct wmi_init_cmd_10_2 {
+	struct wmi_resource_config_10_2 resource_config;
+	__le32 num_host_mem_chunks;
+
+	/*
+	 * variable number of host memory chunks.
+	 * This should be the last element in the structure
+	 */
+	struct host_memory_chunk host_mem_chunks[1];
+} __packed;
+
+struct wmi_chan_list_entry {
+	__le16 freq;
+	u8 phy_mode; /* valid for 10.2 only */
+	u8 reserved;
+} __packed;
+
 /* TLV for channel list */
 struct wmi_chan_list {
 	__le32 tag; /* WMI_CHAN_LIST_TAG */
 	__le32 num_chan;
-	__le32 channel_list[0];
+	struct wmi_chan_list_entry channel_list[0];
 } __packed;
 
 struct wmi_bssid_list {
@@ -1788,7 +2123,6 @@
 	 */
 } __packed;
 
-
 struct wmi_ssid_arg {
 	int len;
 	const u8 *ssid;
@@ -1821,7 +2155,7 @@
 	u32 n_bssids;
 
 	u8 ie[WLAN_SCAN_PARAMS_MAX_IE_LEN];
-	u32 channels[64];
+	u16 channels[64];
 	struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID];
 	struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID];
 };
@@ -1849,7 +2183,6 @@
 /* WMI_SCAN_CLASS_MASK must be the same value as IEEE80211_SCAN_CLASS_MASK */
 #define WMI_SCAN_CLASS_MASK 0xFF000000
 
-
 enum wmi_stop_scan_type {
 	WMI_SCAN_STOP_ONE	= 0x00000000, /* stop by scan_id */
 	WMI_SCAN_STOP_VDEV_ALL	= 0x01000000, /* stop by vdev_id */
@@ -2034,7 +2367,6 @@
 	__le32 nf_list_1;
 	__le32 nf_list_2;
 
-
 	/* Length of the frame */
 	__le32 buf_len;
 } __packed;
@@ -2067,6 +2399,7 @@
 #define PHYERR_TLV_SIG				0xBB
 #define PHYERR_TLV_TAG_SEARCH_FFT_REPORT	0xFB
 #define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY	0xF8
+#define PHYERR_TLV_TAG_SPECTRAL_SUMMARY_REPORT	0xF9
 
 struct phyerr_radar_report {
 	__le32 reg0; /* RADAR_REPORT_REG0_* */
@@ -2135,7 +2468,6 @@
 #define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_MASK	0x000000FF
 #define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_LSB	0
 
-
 struct phyerr_tlv {
 	__le16 len;
 	u8 tag;
@@ -2166,7 +2498,6 @@
 	__le32 value;
 } __packed;
 
-
 struct wmi_pdev_set_regdomain_cmd {
 	__le32 reg_domain;
 	__le32 reg_domain_2G;
@@ -2215,7 +2546,6 @@
 	__le32 enabled;
 } __packed;
 
-
 /*
  * 802.11g protection mode.
  */
@@ -2515,6 +2845,19 @@
 	WMI_10X_PDEV_PARAM_BURST_DUR,
 	/* Set Bursting Enable*/
 	WMI_10X_PDEV_PARAM_BURST_ENABLE,
+
+	/* following are available as of firmware 10.2 */
+	WMI_10X_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA,
+	WMI_10X_PDEV_PARAM_IGMPMLD_OVERRIDE,
+	WMI_10X_PDEV_PARAM_IGMPMLD_TID,
+	WMI_10X_PDEV_PARAM_ANTENNA_GAIN,
+	WMI_10X_PDEV_PARAM_RX_DECAP_MODE,
+	WMI_10X_PDEV_PARAM_RX_FILTER,
+	WMI_10X_PDEV_PARAM_SET_MCAST_TO_UCAST_TID,
+	WMI_10X_PDEV_PARAM_PROXY_STA_MODE,
+	WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_MODE,
+	WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_BUFFER,
+	WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER,
 };
 
 struct wmi_pdev_set_param_cmd {
@@ -3387,6 +3730,14 @@
 	WMI_10X_VDEV_PARAM_ENABLE_RTSCTS,
 
 	WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
+
+	/* following are available as of firmware 10.2 */
+	WMI_10X_VDEV_PARAM_TX_ENCAP_TYPE,
+	WMI_10X_VDEV_PARAM_CABQ_MAXDUR,
+	WMI_10X_VDEV_PARAM_MFPTEST_SET,
+	WMI_10X_VDEV_PARAM_RTS_FIXED_RATE,
+	WMI_10X_VDEV_PARAM_VHT_SGIMASK,
+	WMI_10X_VDEV_PARAM_VHT80_RATEMASK,
 };
 
 /* slot time long */
@@ -3444,6 +3795,98 @@
 /* unsupported VDEV combination */
 #define WMI_INIFIED_VDEV_START_RESPONSE_NOT_SUPPORTED	0x2
 
+/* TODO: please add more comments if you have in-depth information */
+struct wmi_vdev_spectral_conf_cmd {
+	__le32 vdev_id;
+
+	/* number of fft samples to send (0 for infinite) */
+	__le32 scan_count;
+	__le32 scan_period;
+	__le32 scan_priority;
+
+	/* number of bins in the FFT: 2^(fft_size - bin_scale) */
+	__le32 scan_fft_size;
+	__le32 scan_gc_ena;
+	__le32 scan_restart_ena;
+	__le32 scan_noise_floor_ref;
+	__le32 scan_init_delay;
+	__le32 scan_nb_tone_thr;
+	__le32 scan_str_bin_thr;
+	__le32 scan_wb_rpt_mode;
+	__le32 scan_rssi_rpt_mode;
+	__le32 scan_rssi_thr;
+	__le32 scan_pwr_format;
+
+	/* rpt_mode: Format of FFT report to software for spectral scan
+	 * triggered FFTs:
+	 *	0: No FFT report (only spectral scan summary report)
+	 *	1: 2-dword summary of metrics for each completed FFT + spectral
+	 *	   scan	summary report
+	 *	2: 2-dword summary of metrics for each completed FFT +
+	 *	   1x- oversampled bins(in-band) per FFT + spectral scan summary
+	 *	   report
+	 *	3: 2-dword summary of metrics for each completed FFT +
+	 *	   2x- oversampled bins	(all) per FFT + spectral scan summary
+	 */
+	__le32 scan_rpt_mode;
+	__le32 scan_bin_scale;
+	__le32 scan_dbm_adj;
+	__le32 scan_chn_mask;
+} __packed;
+
+struct wmi_vdev_spectral_conf_arg {
+	u32 vdev_id;
+	u32 scan_count;
+	u32 scan_period;
+	u32 scan_priority;
+	u32 scan_fft_size;
+	u32 scan_gc_ena;
+	u32 scan_restart_ena;
+	u32 scan_noise_floor_ref;
+	u32 scan_init_delay;
+	u32 scan_nb_tone_thr;
+	u32 scan_str_bin_thr;
+	u32 scan_wb_rpt_mode;
+	u32 scan_rssi_rpt_mode;
+	u32 scan_rssi_thr;
+	u32 scan_pwr_format;
+	u32 scan_rpt_mode;
+	u32 scan_bin_scale;
+	u32 scan_dbm_adj;
+	u32 scan_chn_mask;
+};
+
+#define WMI_SPECTRAL_ENABLE_DEFAULT              0
+#define WMI_SPECTRAL_COUNT_DEFAULT               0
+#define WMI_SPECTRAL_PERIOD_DEFAULT             35
+#define WMI_SPECTRAL_PRIORITY_DEFAULT            1
+#define WMI_SPECTRAL_FFT_SIZE_DEFAULT            7
+#define WMI_SPECTRAL_GC_ENA_DEFAULT              1
+#define WMI_SPECTRAL_RESTART_ENA_DEFAULT         0
+#define WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT   -96
+#define WMI_SPECTRAL_INIT_DELAY_DEFAULT         80
+#define WMI_SPECTRAL_NB_TONE_THR_DEFAULT        12
+#define WMI_SPECTRAL_STR_BIN_THR_DEFAULT         8
+#define WMI_SPECTRAL_WB_RPT_MODE_DEFAULT         0
+#define WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT       0
+#define WMI_SPECTRAL_RSSI_THR_DEFAULT         0xf0
+#define WMI_SPECTRAL_PWR_FORMAT_DEFAULT          0
+#define WMI_SPECTRAL_RPT_MODE_DEFAULT            2
+#define WMI_SPECTRAL_BIN_SCALE_DEFAULT           1
+#define WMI_SPECTRAL_DBM_ADJ_DEFAULT             1
+#define WMI_SPECTRAL_CHN_MASK_DEFAULT            1
+
+struct wmi_vdev_spectral_enable_cmd {
+	__le32 vdev_id;
+	__le32 trigger_cmd;
+	__le32 enable_cmd;
+} __packed;
+
+#define WMI_SPECTRAL_TRIGGER_CMD_TRIGGER  1
+#define WMI_SPECTRAL_TRIGGER_CMD_CLEAR    2
+#define WMI_SPECTRAL_ENABLE_CMD_ENABLE    1
+#define WMI_SPECTRAL_ENABLE_CMD_DISABLE   2
+
 /* Beacon processing related command and event structures */
 struct wmi_bcn_tx_hdr {
 	__le32 vdev_id;
@@ -3470,6 +3913,11 @@
 	WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2,
 };
 
+/* TODO: It is unclear why "no antenna" works while any other seemingly valid
+ * chainmask yields no beacons on the air at all.
+ */
+#define WMI_BCN_TX_REF_DEF_ANTENNA 0
+
 struct wmi_bcn_tx_ref_cmd {
 	__le32 vdev_id;
 	__le32 data_len;
@@ -3481,6 +3929,8 @@
 	__le32 frame_control;
 	/* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */
 	__le32 flags;
+	/* introduced in 10.2 */
+	__le32 antenna_mask;
 } __packed;
 
 /* Beacon filter */
@@ -3833,7 +4283,6 @@
 	__le32 tbttoffset_list[WMI_MAX_AP_VDEV];
 } __packed;
 
-
 struct wmi_peer_create_cmd {
 	__le32 vdev_id;
 	struct wmi_mac_addr peer_macaddr;
@@ -4053,7 +4502,7 @@
 /* Maximum listen interval supported by hw in units of beacon interval */
 #define ATH10K_MAX_HW_LISTEN_INTERVAL 5
 
-struct wmi_peer_assoc_complete_cmd {
+struct wmi_common_peer_assoc_complete_cmd {
 	struct wmi_mac_addr peer_macaddr;
 	__le32 vdev_id;
 	__le32 peer_new_assoc; /* 1=assoc, 0=reassoc */
@@ -4071,11 +4520,30 @@
 	__le32 peer_vht_caps;
 	__le32 peer_phymode;
 	struct wmi_vht_rate_set peer_vht_rates;
+};
+
+struct wmi_main_peer_assoc_complete_cmd {
+	struct wmi_common_peer_assoc_complete_cmd cmd;
+
 	/* HT Operation Element of the peer. Five bytes packed in 2
 	 *  INT32 array and filled from lsb to msb. */
 	__le32 peer_ht_info[2];
 } __packed;
 
+struct wmi_10_1_peer_assoc_complete_cmd {
+	struct wmi_common_peer_assoc_complete_cmd cmd;
+} __packed;
+
+#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_LSB 0
+#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_MASK 0x0f
+#define WMI_PEER_ASSOC_INFO0_MAX_NSS_LSB 4
+#define WMI_PEER_ASSOC_INFO0_MAX_NSS_MASK 0xf0
+
+struct wmi_10_2_peer_assoc_complete_cmd {
+	struct wmi_common_peer_assoc_complete_cmd cmd;
+	__le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
+} __packed;
+
 struct wmi_peer_assoc_complete_arg {
 	u8 addr[ETH_ALEN];
 	u32 vdev_id;
@@ -4260,6 +4728,10 @@
 int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
 
 int ath10k_wmi_connect(struct ath10k *ar);
+
+struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
+int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
+
 int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
 				const struct wmi_channel_arg *);
 int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
@@ -4290,12 +4762,16 @@
 			      u32 param_id, u32 param_value);
 int ath10k_wmi_vdev_install_key(struct ath10k *ar,
 				const struct wmi_vdev_install_key_arg *arg);
+int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
+				  const struct wmi_vdev_spectral_conf_arg *arg);
+int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
+				    u32 enable);
 int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
-		    const u8 peer_addr[ETH_ALEN]);
+			   const u8 peer_addr[ETH_ALEN]);
 int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
-		    const u8 peer_addr[ETH_ALEN]);
+			   const u8 peer_addr[ETH_ALEN]);
 int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
-		   const u8 peer_addr[ETH_ALEN], u32 tid_bitmap);
+			  const u8 peer_addr[ETH_ALEN], u32 tid_bitmap);
 int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
 			      const u8 *peer_addr,
 			      enum wmi_peer_param param_id, u32 param_value);
@@ -4312,7 +4788,7 @@
 			      const struct wmi_scan_chan_list_arg *arg);
 int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif);
 int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
-			const struct wmi_pdev_set_wmm_params_arg *arg);
+				   const struct wmi_pdev_set_wmm_params_arg *arg);
 int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
 int ath10k_wmi_force_fw_hang(struct ath10k *ar,
 			     enum wmi_force_fw_hang_type type, u32 delay_ms);
diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig
index 7a8b3ef..614737b 100644
--- a/drivers/net/wireless/ath/ath5k/Kconfig
+++ b/drivers/net/wireless/ath/ath5k/Kconfig
@@ -1,14 +1,13 @@
 config ATH5K
 	tristate "Atheros 5xxx wireless cards support"
 	depends on m
-	depends on (PCI || ATHEROS_AR231X) && MAC80211
+	depends on PCI && MAC80211
 	select ATH_COMMON
 	select MAC80211_LEDS
 	select BACKPORT_LEDS_CLASS
 	select BACKPORT_NEW_LEDS
 	select BACKPORT_AVERAGE
-	select ATH5K_AHB if (ATHEROS_AR231X && !PCI)
-	select ATH5K_PCI if (!ATHEROS_AR231X && PCI)
+	select ATH5K_PCI
 	---help---
 	  This module adds support for wireless adapters based on
 	  Atheros 5xxx chipset.
@@ -53,16 +52,9 @@
 
 	  If unsure, say N.
 
-config ATH5K_AHB
-	bool "Atheros 5xxx AHB bus support"
-	depends on (ATHEROS_AR231X && !PCI)
-	---help---
-	  This adds support for WiSoC type chipsets of the 5xxx Atheros
-	  family.
-
 config ATH5K_PCI
 	bool "Atheros 5xxx PCI bus support"
-	depends on (!ATHEROS_AR231X && PCI)
+	depends on PCI
 	---help---
 	  This adds support for PCI type chipsets of the 5xxx Atheros
 	  family.
diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile
index 32a0f67..3c9c2ac 100644
--- a/drivers/net/wireless/ath/ath5k/Makefile
+++ b/drivers/net/wireless/ath/ath5k/Makefile
@@ -17,6 +17,5 @@
 ath5k-y				+= sysfs.o
 ath5k-y				+= mac80211-ops.o
 ath5k-$(CPTCFG_ATH5K_DEBUG)	+= debug.o
-ath5k-$(CPTCFG_ATH5K_AHB)	+= ahb.o
 ath5k-$(CPTCFG_ATH5K_PCI)	+= pci.o
 obj-$(CPTCFG_ATH5K)		+= ath5k.o
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
deleted file mode 100644
index 79bffe1..0000000
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
- * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
- * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/nl80211.h>
-#include <linux/platform_device.h>
-#include <linux/etherdevice.h>
-#include <linux/export.h>
-#include <ar231x_platform.h>
-#include "ath5k.h"
-#include "debug.h"
-#include "base.h"
-#include "reg.h"
-
-/* return bus cachesize in 4B word units */
-static void ath5k_ahb_read_cachesize(struct ath_common *common, int *csz)
-{
-	*csz = L1_CACHE_BYTES >> 2;
-}
-
-static bool
-ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
-{
-	struct ath5k_hw *ah = common->priv;
-	struct platform_device *pdev = to_platform_device(ah->dev);
-	struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
-	u16 *eeprom, *eeprom_end;
-
-	eeprom = (u16 *) bcfg->radio;
-	eeprom_end = ((void *) bcfg->config) + BOARD_CONFIG_BUFSZ;
-
-	eeprom += off;
-	if (eeprom > eeprom_end)
-		return false;
-
-	*data = *eeprom;
-	return true;
-}
-
-int ath5k_hw_read_srev(struct ath5k_hw *ah)
-{
-	struct platform_device *pdev = to_platform_device(ah->dev);
-	struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
-	ah->ah_mac_srev = bcfg->devid;
-	return 0;
-}
-
-static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
-{
-	struct platform_device *pdev = to_platform_device(ah->dev);
-	struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
-	u8 *cfg_mac;
-
-	if (to_platform_device(ah->dev)->id == 0)
-		cfg_mac = bcfg->config->wlan0_mac;
-	else
-		cfg_mac = bcfg->config->wlan1_mac;
-
-	memcpy(mac, cfg_mac, ETH_ALEN);
-	return 0;
-}
-
-static const struct ath_bus_ops ath_ahb_bus_ops = {
-	.ath_bus_type = ATH_AHB,
-	.read_cachesize = ath5k_ahb_read_cachesize,
-	.eeprom_read = ath5k_ahb_eeprom_read,
-	.eeprom_read_mac = ath5k_ahb_eeprom_read_mac,
-};
-
-/*Initialization*/
-static int ath_ahb_probe(struct platform_device *pdev)
-{
-	struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
-	struct ath5k_hw *ah;
-	struct ieee80211_hw *hw;
-	struct resource *res;
-	void __iomem *mem;
-	int irq;
-	int ret = 0;
-	u32 reg;
-
-	if (!dev_get_platdata(&pdev->dev)) {
-		dev_err(&pdev->dev, "no platform data specified\n");
-		ret = -EINVAL;
-		goto err_out;
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL) {
-		dev_err(&pdev->dev, "no memory resource found\n");
-		ret = -ENXIO;
-		goto err_out;
-	}
-
-	mem = ioremap_nocache(res->start, resource_size(res));
-	if (mem == NULL) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -ENOMEM;
-		goto err_out;
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (res == NULL) {
-		dev_err(&pdev->dev, "no IRQ resource found\n");
-		ret = -ENXIO;
-		goto err_iounmap;
-	}
-
-	irq = res->start;
-
-	hw = ieee80211_alloc_hw(sizeof(struct ath5k_hw), &ath5k_hw_ops);
-	if (hw == NULL) {
-		dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
-		ret = -ENOMEM;
-		goto err_iounmap;
-	}
-
-	ah = hw->priv;
-	ah->hw = hw;
-	ah->dev = &pdev->dev;
-	ah->iobase = mem;
-	ah->irq = irq;
-	ah->devid = bcfg->devid;
-
-	if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
-		/* Enable WMAC AHB arbitration */
-		reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
-		reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN;
-		iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
-
-		/* Enable global WMAC swapping */
-		reg = ioread32((void __iomem *) AR5K_AR2315_BYTESWAP);
-		reg |= AR5K_AR2315_BYTESWAP_WMAC;
-		iowrite32(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
-	} else {
-		/* Enable WMAC DMA access (assuming 5312 or 231x*/
-		/* TODO: check other platforms */
-		reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
-		if (to_platform_device(ah->dev)->id == 0)
-			reg |= AR5K_AR5312_ENABLE_WLAN0;
-		else
-			reg |= AR5K_AR5312_ENABLE_WLAN1;
-		iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
-
-		/*
-		 * On a dual-band AR5312, the multiband radio is only
-		 * used as pass-through. Disable 2 GHz support in the
-		 * driver for it
-		 */
-		if (to_platform_device(ah->dev)->id == 0 &&
-		    (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) ==
-		     (BD_WLAN1 | BD_WLAN0))
-			ah->ah_capabilities.cap_needs_2GHz_ovr = true;
-		else
-			ah->ah_capabilities.cap_needs_2GHz_ovr = false;
-	}
-
-	ret = ath5k_init_ah(ah, &ath_ahb_bus_ops);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
-		ret = -ENODEV;
-		goto err_free_hw;
-	}
-
-	platform_set_drvdata(pdev, hw);
-
-	return 0;
-
- err_free_hw:
-	ieee80211_free_hw(hw);
- err_iounmap:
-        iounmap(mem);
- err_out:
-	return ret;
-}
-
-static int ath_ahb_remove(struct platform_device *pdev)
-{
-	struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
-	struct ieee80211_hw *hw = platform_get_drvdata(pdev);
-	struct ath5k_hw *ah;
-	u32 reg;
-
-	if (!hw)
-		return 0;
-
-	ah = hw->priv;
-
-	if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
-		/* Disable WMAC AHB arbitration */
-		reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
-		reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN;
-		iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
-	} else {
-		/*Stop DMA access */
-		reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
-		if (to_platform_device(ah->dev)->id == 0)
-			reg &= ~AR5K_AR5312_ENABLE_WLAN0;
-		else
-			reg &= ~AR5K_AR5312_ENABLE_WLAN1;
-		iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
-	}
-
-	ath5k_deinit_ah(ah);
-	iounmap(ah->iobase);
-	ieee80211_free_hw(hw);
-
-	return 0;
-}
-
-static struct platform_driver ath_ahb_driver = {
-	.probe      = ath_ahb_probe,
-	.remove     = ath_ahb_remove,
-	.driver		= {
-		.name	= "ar231x-wmac",
-		.owner	= THIS_MODULE,
-	},
-};
-
-module_platform_driver(ath_ahb_driver);
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 1054f19..e43e883 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1647,32 +1647,6 @@
 	return &(ath5k_hw_common(ah)->regulatory);
 }
 
-#ifdef CONFIG_ATHEROS_AR231X
-#define AR5K_AR2315_PCI_BASE	((void __iomem *)0xb0100000)
-
-static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg)
-{
-	/* On AR2315 and AR2317 the PCI clock domain registers
-	 * are outside of the WMAC register space */
-	if (unlikely((reg >= 0x4000) && (reg < 0x5000) &&
-	    (ah->ah_mac_srev >= AR5K_SREV_AR2315_R6)))
-		return AR5K_AR2315_PCI_BASE + reg;
-
-	return ah->iobase + reg;
-}
-
-static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
-{
-	return ioread32(ath5k_ahb_reg(ah, reg));
-}
-
-static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
-{
-	iowrite32(val, ath5k_ahb_reg(ah, reg));
-}
-
-#else
-
 static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
 {
 	return ioread32(ah->iobase + reg);
@@ -1683,8 +1657,6 @@
 	iowrite32(val, ah->iobase + reg);
 }
 
-#endif
-
 static inline enum ath_bus_type ath5k_get_bus_type(struct ath5k_hw *ah)
 {
 	return ath5k_hw_common(ah)->bus_ops->ath_bus_type;
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index 7106547..66b6366 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -351,8 +351,7 @@
 {
 	__set_bit(ATH_STAT_INVALID, ah->status);
 
-	if (ah->ah_rf_banks != NULL)
-		kfree(ah->ah_rf_banks);
+	kfree(ah->ah_rf_banks);
 
 	ath5k_eeprom_detach(ah);
 
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 2975efc..3f5fae0 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -99,15 +99,6 @@
 
 /* Known SREVs */
 static const struct ath5k_srev_name srev_names[] = {
-#ifdef CONFIG_ATHEROS_AR231X
-	{ "5312",	AR5K_VERSION_MAC,	AR5K_SREV_AR5312_R2 },
-	{ "5312",	AR5K_VERSION_MAC,	AR5K_SREV_AR5312_R7 },
-	{ "2313",	AR5K_VERSION_MAC,	AR5K_SREV_AR2313_R8 },
-	{ "2315",	AR5K_VERSION_MAC,	AR5K_SREV_AR2315_R6 },
-	{ "2315",	AR5K_VERSION_MAC,	AR5K_SREV_AR2315_R7 },
-	{ "2317",	AR5K_VERSION_MAC,	AR5K_SREV_AR2317_R1 },
-	{ "2317",	AR5K_VERSION_MAC,	AR5K_SREV_AR2317_R2 },
-#else
 	{ "5210",	AR5K_VERSION_MAC,	AR5K_SREV_AR5210 },
 	{ "5311",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311 },
 	{ "5311A",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311A },
@@ -126,7 +117,6 @@
 	{ "5418",	AR5K_VERSION_MAC,	AR5K_SREV_AR5418 },
 	{ "2425",	AR5K_VERSION_MAC,	AR5K_SREV_AR2425 },
 	{ "2417",	AR5K_VERSION_MAC,	AR5K_SREV_AR2417 },
-#endif
 	{ "xxxxx",	AR5K_VERSION_MAC,	AR5K_SREV_UNKNOWN },
 	{ "5110",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5110 },
 	{ "5111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5111 },
@@ -142,10 +132,6 @@
 	{ "5413",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5413 },
 	{ "5424",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5424 },
 	{ "5133",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5133 },
-#ifdef CONFIG_ATHEROS_AR231X
-	{ "2316",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2316 },
-	{ "2317",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2317 },
-#endif
 	{ "xxxxx",	AR5K_VERSION_RAD,	AR5K_SREV_UNKNOWN },
 };
 
@@ -1423,7 +1409,7 @@
 		break;
 	}
 
-	if (rxs->rate_idx >= 0 && rs->rs_rate ==
+	if (rs->rs_rate ==
 	    ah->sbands[ah->curchan->band].bitrates[rxs->rate_idx].hw_value_short)
 		rxs->flag |= RX_FLAG_SHORTPRE;
 
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index b8d031a..c70782e 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -62,9 +62,11 @@
 
 #include <linux/export.h>
 #include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
 
 #include <linux/seq_file.h>
 #include <linux/list.h>
+#include <linux/vmalloc.h>
 #include "debug.h"
 #include "ath5k.h"
 #include "reg.h"
@@ -894,6 +896,100 @@
 	.llseek = default_llseek,
 };
 
+/* debugfs: eeprom */
+
+struct eeprom_private {
+	u16 *buf;
+	int len;
+};
+
+static int open_file_eeprom(struct inode *inode, struct file *file)
+{
+	struct eeprom_private *ep;
+	struct ath5k_hw *ah = inode->i_private;
+	bool res;
+	int i, ret;
+	u32 eesize;
+	u16 val, *buf;
+
+	/* Get eeprom size */
+
+	res = ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_UPPER, &val);
+	if (!res)
+		return -EACCES;
+
+	if (val == 0) {
+		eesize = AR5K_EEPROM_INFO_MAX + AR5K_EEPROM_INFO_BASE;
+	} else {
+		eesize = (val & AR5K_EEPROM_SIZE_UPPER_MASK) <<
+			AR5K_EEPROM_SIZE_ENDLOC_SHIFT;
+		ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_LOWER, &val);
+		eesize = eesize | val;
+	}
+
+	if (eesize > 4096)
+		return -EINVAL;
+
+	/* Create buffer and read in eeprom */
+
+	buf = vmalloc(eesize);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	for (i = 0; i < eesize; ++i) {
+		AR5K_EEPROM_READ(i, val);
+		buf[i] = val;
+	}
+
+	/* Create private struct and assign to file */
+
+	ep = kmalloc(sizeof(*ep), GFP_KERNEL);
+	if (!ep) {
+		ret = -ENOMEM;
+		goto freebuf;
+	}
+
+	ep->buf = buf;
+	ep->len = i;
+
+	file->private_data = (void *)ep;
+
+	return 0;
+
+freebuf:
+	vfree(buf);
+err:
+	return ret;
+
+}
+
+static ssize_t read_file_eeprom(struct file *file, char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	struct eeprom_private *ep = file->private_data;
+
+	return simple_read_from_buffer(user_buf, count, ppos, ep->buf, ep->len);
+}
+
+static int release_file_eeprom(struct inode *inode, struct file *file)
+{
+	struct eeprom_private *ep = file->private_data;
+
+	vfree(ep->buf);
+	kfree(ep);
+
+	return 0;
+}
+
+static const struct file_operations fops_eeprom = {
+	.open = open_file_eeprom,
+	.read = read_file_eeprom,
+	.release = release_file_eeprom,
+	.owner = THIS_MODULE,
+};
+
 
 void
 ath5k_debug_init_device(struct ath5k_hw *ah)
@@ -921,6 +1017,8 @@
 
 	debugfs_create_file("misc", S_IRUSR, phydir, ah, &fops_misc);
 
+	debugfs_create_file("eeprom", S_IRUSR, phydir, ah, &fops_eeprom);
+
 	debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, ah,
 			    &fops_frameerrors);
 
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index 48a6a69..0beb7e7 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -130,6 +130,7 @@
 
 	led->ah = ah;
 	strncpy(led->name, name, sizeof(led->name));
+	led->name[sizeof(led->name)-1] = 0;
 	led->led_dev.name = led->name;
 	led->led_dev.default_trigger = trigger;
 	led->led_dev.brightness_set = ath5k_led_brightness_set;
@@ -162,20 +163,14 @@
 {
 	int ret = 0;
 	struct ieee80211_hw *hw = ah->hw;
-#ifndef CONFIG_ATHEROS_AR231X
 	struct pci_dev *pdev = ah->pdev;
-#endif
 	char name[ATH5K_LED_MAX_NAME_LEN + 1];
 	const struct pci_device_id *match;
 
 	if (!ah->pdev)
 		return 0;
 
-#ifdef CONFIG_ATHEROS_AR231X
-	match = NULL;
-#else
 	match = pci_match_id(&ath5k_led_devices[0], pdev);
-#endif
 	if (match) {
 		__set_bit(ATH_STAT_LEDSOFT, ah->status);
 		ah->led_pin = ATH_PIN(match->driver_data);
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index b65c38f..ab2709a 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -704,7 +704,7 @@
  * reset.
  */
 static void
-ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
+ath5k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
 {
 	struct ath5k_hw *ah = hw->priv;
 
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index fbc42f4..04d3c2e 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -717,6 +717,7 @@
 		memcpy(ie + 2, vif->ssid, vif->ssid_len);
 		memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
 		bss = cfg80211_inform_bss(ar->wiphy, chan,
+					  CFG80211_BSS_FTYPE_UNKNOWN,
 					  bssid, 0, cap_val, 100,
 					  ie, 2 + vif->ssid_len + beacon_ie_len,
 					  0, GFP_KERNEL);
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index fffd523..6e473fa 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -1049,7 +1049,7 @@
 			ar->hw.reserved_ram_size = le32_to_cpup(val);
 
 			ath6kl_dbg(ATH6KL_DBG_BOOT,
-				   "found reserved ram size ie 0x%d\n",
+				   "found reserved ram size ie %d\n",
 				   ar->hw.reserved_ram_size);
 			break;
 		case ATH6KL_FW_IE_CAPABILITIES:
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 21516bc..933aef0 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -225,7 +225,7 @@
 	ret = ath6kl_hif_diag_write32(ar, address, value);
 
 	if (ret) {
-		ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
+		ath6kl_err("failed to write 0x%x during diagnose window to 0x%x\n",
 			   address, value);
 		return ret;
 	}
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 339d89f..eab0ab9 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -1400,6 +1400,7 @@
 	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))},
 	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))},
 	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x2))},
 	{},
 };
 
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index 3245a0e..af439e7 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -1231,26 +1231,7 @@
 #endif
 };
 
-static int ath6kl_usb_init(void)
-{
-	int ret;
-
-	ret = usb_register(&ath6kl_usb_driver);
-	if (ret) {
-		ath6kl_err("usb registration failed: %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
-static void ath6kl_usb_exit(void)
-{
-	usb_deregister(&ath6kl_usb_driver);
-}
-
-module_init(ath6kl_usb_init);
-module_exit(ath6kl_usb_exit);
+module_usb_driver(ath6kl_usb_driver);
 
 MODULE_AUTHOR("Atheros Communications, Inc.");
 MODULE_DESCRIPTION("Driver support for Atheros AR600x USB devices");
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 94df345..b921005 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -619,8 +619,7 @@
 		   dlen, freq, vif->probe_req_report);
 
 	if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
-		cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0,
-				 GFP_ATOMIC);
+		cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
 
 	return 0;
 }
@@ -659,7 +658,7 @@
 		return -EINVAL;
 	}
 	ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
-	cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0, GFP_ATOMIC);
+	cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
 
 	return 0;
 }
@@ -1093,7 +1092,6 @@
 	u8 *buf;
 	struct ieee80211_channel *channel;
 	struct ath6kl *ar = wmi->parent_dev;
-	struct ieee80211_mgmt *mgmt;
 	struct cfg80211_bss *bss;
 
 	if (len <= sizeof(struct wmi_bss_info_hdr2))
@@ -1139,39 +1137,15 @@
 		}
 	}
 
-	/*
-	 * In theory, use of cfg80211_inform_bss() would be more natural here
-	 * since we do not have the full frame. However, at least for now,
-	 * cfg80211 can only distinguish Beacon and Probe Response frames from
-	 * each other when using cfg80211_inform_bss_frame(), so let's build a
-	 * fake IEEE 802.11 header to be able to take benefit of this.
-	 */
-	mgmt = kmalloc(24 + len, GFP_ATOMIC);
-	if (mgmt == NULL)
-		return -EINVAL;
-
-	if (bih->frame_type == BEACON_FTYPE) {
-		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-						  IEEE80211_STYPE_BEACON);
-		memset(mgmt->da, 0xff, ETH_ALEN);
-	} else {
-		struct net_device *dev = vif->ndev;
-
-		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-						  IEEE80211_STYPE_PROBE_RESP);
-		memcpy(mgmt->da, dev->dev_addr, ETH_ALEN);
-	}
-	mgmt->duration = cpu_to_le16(0);
-	memcpy(mgmt->sa, bih->bssid, ETH_ALEN);
-	memcpy(mgmt->bssid, bih->bssid, ETH_ALEN);
-	mgmt->seq_ctrl = cpu_to_le16(0);
-
-	memcpy(&mgmt->u.beacon, buf, len);
-
-	bss = cfg80211_inform_bss_frame(ar->wiphy, channel, mgmt,
-					24 + len, (bih->snr - 95) * 100,
-					GFP_ATOMIC);
-	kfree(mgmt);
+	bss = cfg80211_inform_bss(ar->wiphy, channel,
+				  bih->frame_type == BEACON_FTYPE ?
+					CFG80211_BSS_FTYPE_BEACON :
+					CFG80211_BSS_FTYPE_PRESP,
+				  bih->bssid, get_unaligned_le64((__le64 *)buf),
+				  get_unaligned_le16(((__le16 *)buf) + 5),
+				  get_unaligned_le16(((__le16 *)buf) + 4),
+				  buf + 8 + 2 + 2, len - 8 - 2 - 2,
+				  (bih->snr - 95) * 100, GFP_ATOMIC);
 	if (bss == NULL)
 		return -ENOMEM;
 	cfg80211_put_bss(ar->wiphy, bss);
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index 8284bca..1acecc2 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -95,6 +95,15 @@
 	  developed. At this point enabling this option won't do anything
 	  except increase code size.
 
+config ATH9K_DYNACK
+	bool "Atheros ath9k ACK timeout estimation algorithm (EXPERIMENTAL)"
+	depends on ATH9K
+	default n
+	---help---
+	  This option enables ath9k dynamic ACK timeout estimation algorithm
+	  based on ACK frame RX timestamp, TX frame timestamp and frame
+	  duration
+
 config ATH9K_TX99
 	bool "Atheros ath9k TX99 testing support"
 	depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS
@@ -133,6 +142,15 @@
 	  seconds. Turn off to save power, but enable it if you have
 	  a platform that can toggle the RF-Kill GPIO.
 
+config ATH9K_CHANNEL_CONTEXT
+       bool "Channel Context support"
+       depends on ATH9K
+       default n
+       ---help---
+         This option enables channel context support in ath9k, which is needed
+	 for multi-channel concurrency. Enable this if P2P PowerSave support
+	 is required.
+
 config ATH9K_HTC
        tristate "Atheros HTC based wireless cards support"
        depends on m
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index ce77a1d..ccee747 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -49,6 +49,9 @@
 
 ath9k_hw-$(CPTCFG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
 					   ar9003_mci.o
+
+ath9k_hw-$(CPTCFG_ATH9K_DYNACK) += dynack.o
+
 obj-$(CPTCFG_ATH9K_HW) += ath9k_hw.o
 
 obj-$(CPTCFG_ATH9K_COMMON) += ath9k_common.o
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index 00fb8ba..b72d0be 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -1004,9 +1004,11 @@
 	case ATH9K_ANI_FIRSTEP_LEVEL:{
 		u32 level = param;
 
-		value = level;
+		value = level * 2;
 		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
 			      AR_PHY_FIND_SIG_FIRSTEP, value);
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
+			      AR_PHY_FIND_SIG_FIRSTEP_LOW, value);
 
 		if (level != aniState->firstepLevel) {
 			ath_dbg(common, ANI,
@@ -1040,9 +1042,8 @@
 		REG_RMW_FIELD(ah, AR_PHY_TIMING5,
 			      AR_PHY_TIMING5_CYCPWR_THR1, value);
 
-		if (IS_CHAN_HT40(ah->curchan))
-			REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
-				      AR_PHY_EXT_TIMING5_CYCPWR_THR1, value);
+		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+				  AR_PHY_EXT_TIMING5_CYCPWR_THR1, value - 1);
 
 		if (level != aniState->spurImmunityLevel) {
 			ath_dbg(common, ANI,
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index 59af9f9..2a93519 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -384,6 +384,24 @@
 	return 0;
 }
 
+static int ar9002_hw_get_duration(struct ath_hw *ah, const void *ds, int index)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	switch (index) {
+	case 0:
+		return MS(ACCESS_ONCE(ads->ds_ctl4), AR_PacketDur0);
+	case 1:
+		return MS(ACCESS_ONCE(ads->ds_ctl4), AR_PacketDur1);
+	case 2:
+		return MS(ACCESS_ONCE(ads->ds_ctl5), AR_PacketDur2);
+	case 3:
+		return MS(ACCESS_ONCE(ads->ds_ctl5), AR_PacketDur3);
+	default:
+		return -1;
+	}
+}
+
 void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
 			  u32 size, u32 flags)
 {
@@ -406,4 +424,5 @@
 	ops->get_isr = ar9002_hw_get_isr;
 	ops->set_txdesc = ar9002_set_txdesc;
 	ops->proc_txdesc = ar9002_hw_proc_txdesc;
+	ops->get_duration = ar9002_hw_get_duration;
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 71e38e8..057b165 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -431,6 +431,24 @@
 	return 0;
 }
 
+static int ar9003_hw_get_duration(struct ath_hw *ah, const void *ds, int index)
+{
+	const struct ar9003_txc *adc = ds;
+
+	switch (index) {
+	case 0:
+		return MS(ACCESS_ONCE(adc->ctl15), AR_PacketDur0);
+	case 1:
+		return MS(ACCESS_ONCE(adc->ctl15), AR_PacketDur1);
+	case 2:
+		return MS(ACCESS_ONCE(adc->ctl16), AR_PacketDur2);
+	case 3:
+		return MS(ACCESS_ONCE(adc->ctl16), AR_PacketDur3);
+	default:
+		return 0;
+	}
+}
+
 void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
 {
 	struct ath_hw_ops *ops = ath9k_hw_ops(hw);
@@ -440,6 +458,7 @@
 	ops->get_isr = ar9003_hw_get_isr;
 	ops->set_txdesc = ar9003_set_txdesc;
 	ops->proc_txdesc = ar9003_hw_proc_txdesc;
+	ops->get_duration = ar9003_hw_get_duration;
 }
 
 void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 5218913..fbe3059 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -517,6 +517,23 @@
 	ar9003_hw_spur_mitigate_ofdm(ah, chan);
 }
 
+static u32 ar9003_hw_compute_pll_control_soc(struct ath_hw *ah,
+					     struct ath9k_channel *chan)
+{
+	u32 pll;
+
+	pll = SM(0x5, AR_RTC_9300_SOC_PLL_REFDIV);
+
+	if (chan && IS_CHAN_HALF_RATE(chan))
+		pll |= SM(0x1, AR_RTC_9300_SOC_PLL_CLKSEL);
+	else if (chan && IS_CHAN_QUARTER_RATE(chan))
+		pll |= SM(0x2, AR_RTC_9300_SOC_PLL_CLKSEL);
+
+	pll |= SM(0x2c, AR_RTC_9300_SOC_PLL_DIV_INT);
+
+	return pll;
+}
+
 static u32 ar9003_hw_compute_pll_control(struct ath_hw *ah,
 					 struct ath9k_channel *chan)
 {
@@ -1781,7 +1798,12 @@
 
 	priv_ops->rf_set_freq = ar9003_hw_set_channel;
 	priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate;
-	priv_ops->compute_pll_control = ar9003_hw_compute_pll_control;
+
+	if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah))
+		priv_ops->compute_pll_control = ar9003_hw_compute_pll_control_soc;
+	else
+		priv_ops->compute_pll_control = ar9003_hw_compute_pll_control;
+
 	priv_ops->set_channel_regs = ar9003_hw_set_channel_regs;
 	priv_ops->init_bb = ar9003_hw_init_bb;
 	priv_ops->process_ini = ar9003_hw_process_ini;
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index aa8c543..4581876 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -31,6 +31,7 @@
 #include "spectral.h"
 
 struct ath_node;
+struct ath_vif;
 
 extern struct ieee80211_ops ath9k_ops;
 extern int ath9k_modparam_nohwcrypt;
@@ -273,6 +274,9 @@
 	struct ath_rx_rate_stats rx_rate_stats;
 #endif
 	u8 key_idx[4];
+
+	u32 ackto;
+	struct list_head list;
 };
 
 struct ath_tx_control {
@@ -290,7 +294,6 @@
  *  (axq_qnum).
  */
 struct ath_tx {
-	u16 seq_no;
 	u32 txqsetup;
 	spinlock_t txbuflock;
 	struct list_head txbuf;
@@ -313,7 +316,6 @@
 	bool discard_next;
 	u32 *rxlink;
 	u32 num_pkts;
-	unsigned int rxfilter;
 	struct list_head rxbuf;
 	struct ath_descdma rxdma;
 	struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
@@ -324,6 +326,10 @@
 	u32 ampdu_ref;
 };
 
+/*******************/
+/* Channel Context */
+/*******************/
+
 struct ath_chanctx {
 	struct cfg80211_chan_def chandef;
 	struct list_head vifs;
@@ -345,6 +351,10 @@
 	bool active;
 	bool assigned;
 	bool switch_after_beacon;
+
+	short nvifs;
+	short nvifs_assigned;
+	unsigned int rxfilter;
 };
 
 enum ath_chanctx_event {
@@ -354,7 +364,9 @@
 	ATH_CHANCTX_EVENT_BEACON_RECEIVED,
 	ATH_CHANCTX_EVENT_ASSOC,
 	ATH_CHANCTX_EVENT_SWITCH,
+	ATH_CHANCTX_EVENT_ASSIGN,
 	ATH_CHANCTX_EVENT_UNASSIGN,
+	ATH_CHANCTX_EVENT_CHANGE,
 	ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL,
 };
 
@@ -369,6 +381,9 @@
 struct ath_chanctx_sched {
 	bool beacon_pending;
 	bool offchannel_pending;
+	bool wait_switch;
+	bool force_noa_update;
+	bool extend_absence;
 	enum ath_chanctx_state state;
 	u8 beacon_miss;
 
@@ -403,38 +418,130 @@
 	int roc_duration;
 	int duration;
 };
+
+#define case_rtn_string(val) case val: return #val
+
 #define ath_for_each_chanctx(_sc, _ctx)                             \
 	for (ctx = &sc->chanctx[0];                                 \
 	     ctx <= &sc->chanctx[ARRAY_SIZE(sc->chanctx) - 1];      \
 	     ctx++)
 
-void ath9k_fill_chanctx_ops(void);
-void ath9k_chanctx_force_active(struct ieee80211_hw *hw,
-				struct ieee80211_vif *vif);
+void ath_chanctx_init(struct ath_softc *sc);
+void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
+			     struct cfg80211_chan_def *chandef);
+
+#ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
+
 static inline struct ath_chanctx *
 ath_chanctx_get(struct ieee80211_chanctx_conf *ctx)
 {
 	struct ath_chanctx **ptr = (void *) ctx->drv_priv;
 	return *ptr;
 }
-void ath_chanctx_init(struct ath_softc *sc);
-void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
-			     struct cfg80211_chan_def *chandef);
-void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
-			struct cfg80211_chan_def *chandef);
+
+bool ath9k_is_chanctx_enabled(void);
+void ath9k_fill_chanctx_ops(void);
+void ath9k_init_channel_context(struct ath_softc *sc);
+void ath9k_offchannel_init(struct ath_softc *sc);
+void ath9k_deinit_channel_context(struct ath_softc *sc);
+int ath9k_init_p2p(struct ath_softc *sc);
+void ath9k_deinit_p2p(struct ath_softc *sc);
+void ath9k_p2p_remove_vif(struct ath_softc *sc,
+			  struct ieee80211_vif *vif);
+void ath9k_p2p_beacon_sync(struct ath_softc *sc);
+void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
+				struct ieee80211_vif *vif);
+void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+			  struct sk_buff *skb);
+void ath9k_p2p_ps_timer(void *priv);
+void ath9k_chanctx_wake_queues(struct ath_softc *sc, struct ath_chanctx *ctx);
+void ath9k_chanctx_stop_queues(struct ath_softc *sc, struct ath_chanctx *ctx);
 void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx);
-void ath_offchannel_timer(unsigned long data);
-void ath_offchannel_channel_change(struct ath_softc *sc);
-void ath_chanctx_offchan_switch(struct ath_softc *sc,
-				struct ieee80211_channel *chan);
-struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc,
-					      bool active);
+
+void ath_chanctx_beacon_recv_ev(struct ath_softc *sc,
+				enum ath_chanctx_event ev);
+void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+				enum ath_chanctx_event ev);
 void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
 		       enum ath_chanctx_event ev);
-void ath_chanctx_timer(unsigned long data);
+void ath_chanctx_set_next(struct ath_softc *sc, bool force);
+void ath_offchannel_next(struct ath_softc *sc);
+void ath_scan_complete(struct ath_softc *sc, bool abort);
+void ath_roc_complete(struct ath_softc *sc, bool abort);
+
+#else
+
+static inline bool ath9k_is_chanctx_enabled(void)
+{
+	return false;
+}
+static inline void ath9k_fill_chanctx_ops(void)
+{
+}
+static inline void ath9k_init_channel_context(struct ath_softc *sc)
+{
+}
+static inline void ath9k_offchannel_init(struct ath_softc *sc)
+{
+}
+static inline void ath9k_deinit_channel_context(struct ath_softc *sc)
+{
+}
+static inline void ath_chanctx_beacon_recv_ev(struct ath_softc *sc,
+					      enum ath_chanctx_event ev)
+{
+}
+static inline void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+					      enum ath_chanctx_event ev)
+{
+}
+static inline void ath_chanctx_event(struct ath_softc *sc,
+				     struct ieee80211_vif *vif,
+				     enum ath_chanctx_event ev)
+{
+}
+static inline int ath9k_init_p2p(struct ath_softc *sc)
+{
+	return 0;
+}
+static inline void ath9k_deinit_p2p(struct ath_softc *sc)
+{
+}
+static inline void ath9k_p2p_remove_vif(struct ath_softc *sc,
+					struct ieee80211_vif *vif)
+{
+}
+static inline void ath9k_p2p_beacon_sync(struct ath_softc *sc)
+{
+}
+static inline void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
+					      struct ieee80211_vif *vif)
+{
+}
+static inline void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+					struct sk_buff *skb)
+{
+}
+static inline void ath9k_p2p_ps_timer(struct ath_softc *sc)
+{
+}
+static inline void ath9k_chanctx_wake_queues(struct ath_softc *sc,
+					     struct ath_chanctx *ctx)
+{
+}
+static inline void ath9k_chanctx_stop_queues(struct ath_softc *sc,
+					     struct ath_chanctx *ctx)
+{
+}
+static inline void ath_chanctx_check_active(struct ath_softc *sc,
+					    struct ath_chanctx *ctx)
+{
+}
+
+#endif /* CPTCFG_ATH9K_CHANNEL_CONTEXT */
 
 int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan);
-int ath_startrecv(struct ath_softc *sc);
+void ath_startrecv(struct ath_softc *sc);
 bool ath_stoprecv(struct ath_softc *sc);
 u32 ath_calcrxfilter(struct ath_softc *sc);
 int ath_rx_init(struct ath_softc *sc, int nbufs);
@@ -455,6 +562,7 @@
 int ath_txq_update(struct ath_softc *sc, int qnum,
 		   struct ath9k_tx_queue_info *q);
 void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop);
+void ath_assign_seq(struct ath_common *common, struct sk_buff *skb);
 int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 		 struct ath_tx_control *txctl);
 void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -479,9 +587,18 @@
 /* VIFs */
 /********/
 
+#define P2P_DEFAULT_CTWIN 10
+
 struct ath_vif {
 	struct list_head list;
 
+	u16 seq_no;
+
+	/* BSS info */
+	u8 bssid[ETH_ALEN];
+	u16 aid;
+	bool assoc;
+
 	struct ieee80211_vif *vif;
 	struct ath_node mcast_node;
 	int av_bslot;
@@ -497,8 +614,10 @@
 	u32 offchannel_start;
 	u32 offchannel_duration;
 
-	u32 periodic_noa_start;
-	u32 periodic_noa_duration;
+	/* These are used for both periodic and one-shot */
+	u32 noa_start;
+	u32 noa_duration;
+	bool periodic_noa;
 };
 
 struct ath9k_vif_iter_data {
@@ -583,7 +702,6 @@
 #define ATH_PAPRD_TIMEOUT         100 /* msecs */
 #define ATH_PLL_WORK_INTERVAL     100
 
-void ath_chanctx_work(struct work_struct *work);
 void ath_tx_complete_poll_work(struct work_struct *work);
 void ath_reset_work(struct work_struct *work);
 bool ath_hw_check(struct ath_softc *sc);
@@ -597,8 +715,6 @@
 void ath_update_survey_nf(struct ath_softc *sc, int channel);
 void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
 void ath_ps_full_sleep(unsigned long data);
-void ath9k_p2p_ps_timer(void *priv);
-void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif);
 void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
 
 /**********/
@@ -849,12 +965,17 @@
 	struct mutex mutex;
 	struct work_struct paprd_work;
 	struct work_struct hw_reset_work;
-	struct work_struct chanctx_work;
 	struct completion paprd_complete;
 	wait_queue_head_t tx_wait;
 
+#ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
+	struct work_struct chanctx_work;
 	struct ath_gen_timer *p2p_ps_timer;
 	struct ath_vif *p2p_ps_vif;
+	struct ath_chanctx_sched sched;
+	struct ath_offchannel offchannel;
+	struct ath_chanctx *next_chan;
+#endif
 
 	unsigned long driver_data;
 
@@ -865,7 +986,6 @@
 	bool ps_enabled;
 	bool ps_idle;
 	short nbcnvifs;
-	short nvifs;
 	unsigned long ps_usecount;
 
 	struct ath_rx rx;
@@ -875,10 +995,7 @@
 	struct cfg80211_chan_def cur_chandef;
 	struct ath_chanctx chanctx[ATH9K_NUM_CHANCTX];
 	struct ath_chanctx *cur_chan;
-	struct ath_chanctx *next_chan;
 	spinlock_t chan_lock;
-	struct ath_offchannel offchannel;
-	struct ath_chanctx_sched sched;
 
 #ifdef CPTCFG_MAC80211_LEDS
 	bool led_registered;
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index eaf8f05..ecb783b 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -108,55 +108,6 @@
 	ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
 }
 
-static void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
-				 struct sk_buff *skb)
-{
-	static const u8 noa_ie_hdr[] = {
-		WLAN_EID_VENDOR_SPECIFIC,	/* type */
-		0,				/* length */
-		0x50, 0x6f, 0x9a,		/* WFA OUI */
-		0x09,				/* P2P subtype */
-		0x0c,				/* Notice of Absence */
-		0x00,				/* LSB of little-endian len */
-		0x00,				/* MSB of little-endian len */
-	};
-
-	struct ieee80211_p2p_noa_attr *noa;
-	int noa_len, noa_desc, i = 0;
-	u8 *hdr;
-
-	if (!avp->offchannel_duration && !avp->periodic_noa_duration)
-		return;
-
-	noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration;
-	noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
-
-	hdr = skb_put(skb, sizeof(noa_ie_hdr));
-	memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr));
-	hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2;
-	hdr[7] = noa_len;
-
-	noa = (void *) skb_put(skb, noa_len);
-	memset(noa, 0, noa_len);
-
-	noa->index = avp->noa_index;
-	if (avp->periodic_noa_duration) {
-		u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
-
-		noa->desc[i].count = 255;
-		noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start);
-		noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration);
-		noa->desc[i].interval = cpu_to_le32(interval);
-		i++;
-	}
-
-	if (avp->offchannel_duration) {
-		noa->desc[i].count = 1;
-		noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start);
-		noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration);
-	}
-}
-
 static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
 					     struct ieee80211_vif *vif)
 {
@@ -193,16 +144,8 @@
 	mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust;
 
 	info = IEEE80211_SKB_CB(skb);
-	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-		/*
-		 * TODO: make sure the seq# gets assigned properly (vs. other
-		 * TX frames)
-		 */
-		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-		sc->tx.seq_no += 0x10;
-		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-		hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
-	}
+
+	ath_assign_seq(common, skb);
 
 	if (vif->p2p)
 		ath9k_beacon_add_noa(sc, avp, skb);
@@ -232,7 +175,7 @@
 	spin_unlock_bh(&cabq->axq_lock);
 
 	if (skb && cabq_depth) {
-		if (sc->nvifs > 1) {
+		if (sc->cur_chan->nvifs > 1) {
 			ath_dbg(common, BEACON,
 				"Flushing previous cabq traffic\n");
 			ath_draintxq(sc, cabq);
@@ -427,9 +370,10 @@
 
 	/* EDMA devices check that in the tx completion function. */
 	if (!edma) {
-		if (sc->sched.beacon_pending)
-			ath_chanctx_event(sc, NULL,
+		if (ath9k_is_chanctx_enabled()) {
+			ath_chanctx_beacon_sent_ev(sc,
 					  ATH_CHANCTX_EVENT_BEACON_SENT);
+		}
 
 		if (ath9k_csa_is_finished(sc, vif))
 			return;
@@ -438,7 +382,10 @@
 	if (!vif || !vif->bss_conf.enable_beacon)
 		return;
 
-	ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
+	if (ath9k_is_chanctx_enabled()) {
+		ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
+	}
+
 	bf = ath9k_beacon_generate(sc->hw, vif);
 
 	if (sc->beacon.bmisscnt != 0) {
@@ -559,6 +506,18 @@
 				      struct ieee80211_vif *vif)
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath_vif *avp = (void *)vif->drv_priv;
+
+	if (ath9k_is_chanctx_enabled()) {
+		/*
+		 * If the VIF is not present in the current channel context,
+		 * then we can't do the usual opmode checks. Allow the
+		 * beacon config for the VIF to be updated in this case and
+		 * return immediately.
+		 */
+		if (sc->cur_chan != avp->chanctx)
+			return true;
+	}
 
 	if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
 		if ((vif->type != NL80211_IFTYPE_AP) ||
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index ba214eb..696152b 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -83,8 +83,6 @@
 	if (hw->conf.radar_enabled) {
 		u32 rxfilter;
 
-		/* set HW specific DFS configuration */
-		ath9k_hw_set_radar_params(ah);
 		rxfilter = ath9k_hw_getrxfilter(ah);
 		rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
 				ATH9K_RX_FILTER_PHYERR;
@@ -101,202 +99,6 @@
 	return 0;
 }
 
-static bool
-ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
-			      bool powersave)
-{
-	struct ieee80211_vif *vif = avp->vif;
-	struct ieee80211_sta *sta = NULL;
-	struct ieee80211_hdr_3addr *nullfunc;
-	struct ath_tx_control txctl;
-	struct sk_buff *skb;
-	int band = sc->cur_chan->chandef.chan->band;
-
-	switch (vif->type) {
-	case NL80211_IFTYPE_STATION:
-		if (!vif->bss_conf.assoc)
-			return false;
-
-		skb = ieee80211_nullfunc_get(sc->hw, vif);
-		if (!skb)
-			return false;
-
-		nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
-		if (powersave)
-			nullfunc->frame_control |=
-				cpu_to_le16(IEEE80211_FCTL_PM);
-
-		skb_set_queue_mapping(skb, IEEE80211_AC_VO);
-		if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
-			dev_kfree_skb_any(skb);
-			return false;
-		}
-		break;
-	default:
-		return false;
-	}
-
-	memset(&txctl, 0, sizeof(txctl));
-	txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
-	txctl.sta = sta;
-	txctl.force_channel = true;
-	if (ath_tx_start(sc->hw, skb, &txctl)) {
-		ieee80211_free_txskb(sc->hw, skb);
-		return false;
-	}
-
-	return true;
-}
-
-void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
-{
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	struct ath_vif *avp;
-	bool active = false;
-	u8 n_active = 0;
-
-	if (!ctx)
-		return;
-
-	list_for_each_entry(avp, &ctx->vifs, list) {
-		struct ieee80211_vif *vif = avp->vif;
-
-		switch (vif->type) {
-		case NL80211_IFTYPE_P2P_CLIENT:
-		case NL80211_IFTYPE_STATION:
-			if (vif->bss_conf.assoc)
-				active = true;
-			break;
-		default:
-			active = true;
-			break;
-		}
-	}
-	ctx->active = active;
-
-	ath_for_each_chanctx(sc, ctx) {
-		if (!ctx->assigned || list_empty(&ctx->vifs))
-			continue;
-		n_active++;
-	}
-
-	if (n_active <= 1) {
-		clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags);
-		return;
-	}
-	if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
-		return;
-	ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
-}
-
-static bool
-ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave)
-{
-	struct ath_vif *avp;
-	bool sent = false;
-
-	rcu_read_lock();
-	list_for_each_entry(avp, &sc->cur_chan->vifs, list) {
-		if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave))
-			sent = true;
-	}
-	rcu_read_unlock();
-
-	return sent;
-}
-
-static bool ath_chanctx_defer_switch(struct ath_softc *sc)
-{
-	if (sc->cur_chan == &sc->offchannel.chan)
-		return false;
-
-	switch (sc->sched.state) {
-	case ATH_CHANCTX_STATE_SWITCH:
-		return false;
-	case ATH_CHANCTX_STATE_IDLE:
-		if (!sc->cur_chan->switch_after_beacon)
-			return false;
-
-		sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
-		break;
-	default:
-		break;
-	}
-
-	return true;
-}
-
-static void ath_chanctx_set_next(struct ath_softc *sc, bool force)
-{
-	struct timespec ts;
-	bool measure_time = false;
-	bool send_ps = false;
-
-	spin_lock_bh(&sc->chan_lock);
-	if (!sc->next_chan) {
-		spin_unlock_bh(&sc->chan_lock);
-		return;
-	}
-
-	if (!force && ath_chanctx_defer_switch(sc)) {
-		spin_unlock_bh(&sc->chan_lock);
-		return;
-	}
-
-	if (sc->cur_chan != sc->next_chan) {
-		sc->cur_chan->stopped = true;
-		spin_unlock_bh(&sc->chan_lock);
-
-		if (sc->next_chan == &sc->offchannel.chan) {
-			getrawmonotonic(&ts);
-			measure_time = true;
-		}
-		__ath9k_flush(sc->hw, ~0, true);
-
-		if (ath_chanctx_send_ps_frame(sc, true))
-			__ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
-
-		send_ps = true;
-		spin_lock_bh(&sc->chan_lock);
-
-		if (sc->cur_chan != &sc->offchannel.chan) {
-			getrawmonotonic(&sc->cur_chan->tsf_ts);
-			sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
-		}
-	}
-	sc->cur_chan = sc->next_chan;
-	sc->cur_chan->stopped = false;
-	sc->next_chan = NULL;
-	sc->sched.offchannel_duration = 0;
-	if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE)
-		sc->sched.state = ATH_CHANCTX_STATE_IDLE;
-
-	spin_unlock_bh(&sc->chan_lock);
-
-	if (sc->sc_ah->chip_fullsleep ||
-	    memcmp(&sc->cur_chandef, &sc->cur_chan->chandef,
-		   sizeof(sc->cur_chandef))) {
-		ath_set_channel(sc);
-		if (measure_time)
-			sc->sched.channel_switch_time =
-				ath9k_hw_get_tsf_offset(&ts, NULL);
-	}
-	if (send_ps)
-		ath_chanctx_send_ps_frame(sc, false);
-
-	ath_offchannel_channel_change(sc);
-	ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH);
-}
-
-void ath_chanctx_work(struct work_struct *work)
-{
-	struct ath_softc *sc = container_of(work, struct ath_softc,
-					    chanctx_work);
-	mutex_lock(&sc->mutex);
-	ath_chanctx_set_next(sc, false);
-	mutex_unlock(&sc->mutex);
-}
-
 void ath_chanctx_init(struct ath_softc *sc)
 {
 	struct ath_chanctx *ctx;
@@ -318,76 +120,12 @@
 		for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
 			INIT_LIST_HEAD(&ctx->acq[j]);
 	}
-	ctx = &sc->offchannel.chan;
-	cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
-	INIT_LIST_HEAD(&ctx->vifs);
-	ctx->txpower = ATH_TXPOWER_MAX;
-	for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
-		INIT_LIST_HEAD(&ctx->acq[j]);
-	sc->offchannel.chan.offchannel = true;
-
-}
-
-void ath9k_chanctx_force_active(struct ieee80211_hw *hw,
-				struct ieee80211_vif *vif)
-{
-	struct ath_softc *sc = hw->priv;
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
-	bool changed = false;
-
-	if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
-		return;
-
-	if (!avp->chanctx)
-		return;
-
-	mutex_lock(&sc->mutex);
-
-	spin_lock_bh(&sc->chan_lock);
-	if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
-		sc->next_chan = avp->chanctx;
-		changed = true;
-	}
-	sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
-	spin_unlock_bh(&sc->chan_lock);
-
-	if (changed)
-		ath_chanctx_set_next(sc, true);
-
-	mutex_unlock(&sc->mutex);
-}
-
-void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
-			struct cfg80211_chan_def *chandef)
-{
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
-	spin_lock_bh(&sc->chan_lock);
-
-	if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) &&
-	    (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) {
-		sc->sched.offchannel_pending = true;
-		spin_unlock_bh(&sc->chan_lock);
-		return;
-	}
-
-	sc->next_chan = ctx;
-	if (chandef)
-		ctx->chandef = *chandef;
-
-	if (sc->next_chan == &sc->offchannel.chan) {
-		sc->sched.offchannel_duration =
-			TU_TO_USEC(sc->offchannel.duration) +
-			sc->sched.channel_switch_time;
-	}
-	spin_unlock_bh(&sc->chan_lock);
-	ieee80211_queue_work(sc->hw, &sc->chanctx_work);
 }
 
 void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
 			     struct cfg80211_chan_def *chandef)
 {
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	bool cur_chan;
 
 	spin_lock_bh(&sc->chan_lock);
@@ -396,37 +134,110 @@
 	cur_chan = sc->cur_chan == ctx;
 	spin_unlock_bh(&sc->chan_lock);
 
-	if (!cur_chan)
+	if (!cur_chan) {
+		ath_dbg(common, CHAN_CTX,
+			"Current context differs from the new context\n");
 		return;
+	}
 
 	ath_set_channel(sc);
 }
 
-struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active)
+#ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
+
+/**********************************************************/
+/* Functions to handle the channel context state machine. */
+/**********************************************************/
+
+static const char *offchannel_state_string(enum ath_offchannel_state state)
 {
-	struct ath_chanctx *ctx;
+	switch (state) {
+		case_rtn_string(ATH_OFFCHANNEL_IDLE);
+		case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND);
+		case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT);
+		case_rtn_string(ATH_OFFCHANNEL_SUSPEND);
+		case_rtn_string(ATH_OFFCHANNEL_ROC_START);
+		case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT);
+		case_rtn_string(ATH_OFFCHANNEL_ROC_DONE);
+	default:
+		return "unknown";
+	}
+}
+
+static const char *chanctx_event_string(enum ath_chanctx_event ev)
+{
+	switch (ev) {
+		case_rtn_string(ATH_CHANCTX_EVENT_BEACON_PREPARE);
+		case_rtn_string(ATH_CHANCTX_EVENT_BEACON_SENT);
+		case_rtn_string(ATH_CHANCTX_EVENT_TSF_TIMER);
+		case_rtn_string(ATH_CHANCTX_EVENT_BEACON_RECEIVED);
+		case_rtn_string(ATH_CHANCTX_EVENT_ASSOC);
+		case_rtn_string(ATH_CHANCTX_EVENT_SWITCH);
+		case_rtn_string(ATH_CHANCTX_EVENT_ASSIGN);
+		case_rtn_string(ATH_CHANCTX_EVENT_UNASSIGN);
+		case_rtn_string(ATH_CHANCTX_EVENT_CHANGE);
+		case_rtn_string(ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
+	default:
+		return "unknown";
+	}
+}
+
+static const char *chanctx_state_string(enum ath_chanctx_state state)
+{
+	switch (state) {
+		case_rtn_string(ATH_CHANCTX_STATE_IDLE);
+		case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_BEACON);
+		case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_TIMER);
+		case_rtn_string(ATH_CHANCTX_STATE_SWITCH);
+		case_rtn_string(ATH_CHANCTX_STATE_FORCE_ACTIVE);
+	default:
+		return "unknown";
+	}
+}
+
+void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath_vif *avp;
+	bool active = false;
+	u8 n_active = 0;
+
+	if (!ctx)
+		return;
+
+	list_for_each_entry(avp, &ctx->vifs, list) {
+		struct ieee80211_vif *vif = avp->vif;
+
+		switch (vif->type) {
+		case NL80211_IFTYPE_P2P_CLIENT:
+		case NL80211_IFTYPE_STATION:
+			if (avp->assoc)
+				active = true;
+			break;
+		default:
+			active = true;
+			break;
+		}
+	}
+	ctx->active = active;
 
 	ath_for_each_chanctx(sc, ctx) {
 		if (!ctx->assigned || list_empty(&ctx->vifs))
 			continue;
-		if (active && !ctx->active)
-			continue;
-
-		if (ctx->switch_after_beacon)
-			return ctx;
+		n_active++;
 	}
 
-	return &sc->chanctx[0];
-}
+	if (n_active <= 1) {
+		clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags);
+		return;
+	}
+	if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+		return;
 
-void ath_chanctx_offchan_switch(struct ath_softc *sc,
-				struct ieee80211_channel *chan)
-{
-	struct cfg80211_chan_def chandef;
-
-	cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
-
-	ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef);
+	if (ath9k_is_chanctx_enabled()) {
+		ath_chanctx_event(sc, NULL,
+				  ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
+	}
 }
 
 static struct ath_chanctx *
@@ -449,6 +260,9 @@
 	cur = sc->cur_chan;
 	prev = ath_chanctx_get_next(sc, cur);
 
+	if (!prev->switch_after_beacon)
+		return;
+
 	getrawmonotonic(&ts);
 	cur_tsf = (u32) cur->tsf_val +
 		  ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts);
@@ -469,25 +283,22 @@
 	prev->tsf_val += offset;
 }
 
-void ath_chanctx_timer(unsigned long data)
-{
-	struct ath_softc *sc = (struct ath_softc *) data;
-
-	ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
-}
-
 /* Configure the TSF based hardware timer for a channel switch.
  * Also set up backup software timer, in case the gen timer fails.
  * This could be caused by a hardware reset.
  */
 static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
 {
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_hw *ah = sc->sc_ah;
 
 	ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000);
 	tsf_time -= ath9k_hw_gettsf32(ah);
 	tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1;
-	mod_timer(&sc->sched.timer, tsf_time);
+	mod_timer(&sc->sched.timer, jiffies + tsf_time);
+
+	ath_dbg(common, CHAN_CTX,
+		"Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time));
 }
 
 void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
@@ -500,40 +311,56 @@
 	struct ath_chanctx *ctx;
 	u32 tsf_time;
 	u32 beacon_int;
-	bool noa_changed = false;
 
 	if (vif)
 		avp = (struct ath_vif *) vif->drv_priv;
 
 	spin_lock_bh(&sc->chan_lock);
 
+	ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s\n",
+		sc->cur_chan->chandef.center_freq1,
+		chanctx_event_string(ev),
+		chanctx_state_string(sc->sched.state));
+
 	switch (ev) {
 	case ATH_CHANCTX_EVENT_BEACON_PREPARE:
 		if (avp->offchannel_duration)
 			avp->offchannel_duration = 0;
 
-		if (avp->chanctx != sc->cur_chan)
+		if (avp->chanctx != sc->cur_chan) {
+			ath_dbg(common, CHAN_CTX,
+				"Contexts differ, not preparing beacon\n");
 			break;
+		}
 
-		if (sc->sched.offchannel_pending) {
+		if (sc->sched.offchannel_pending && !sc->sched.wait_switch) {
 			sc->sched.offchannel_pending = false;
 			sc->next_chan = &sc->offchannel.chan;
 			sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+			ath_dbg(common, CHAN_CTX,
+				"Setting offchannel_pending to false\n");
 		}
 
 		ctx = ath_chanctx_get_next(sc, sc->cur_chan);
 		if (ctx->active && sc->sched.state == ATH_CHANCTX_STATE_IDLE) {
 			sc->next_chan = ctx;
 			sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+			ath_dbg(common, CHAN_CTX,
+				"Set next context, move chanctx state to WAIT_FOR_BEACON\n");
 		}
 
 		/* if the timer missed its window, use the next interval */
-		if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER)
+		if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER) {
 			sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+			ath_dbg(common, CHAN_CTX,
+				"Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n");
+		}
 
 		if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
 			break;
 
+		ath_dbg(common, CHAN_CTX, "Preparing beacon for vif: %pM\n", vif->addr);
+
 		sc->sched.beacon_pending = true;
 		sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER);
 
@@ -545,47 +372,107 @@
 		sc->sched.switch_start_time = tsf_time;
 		sc->cur_chan->last_beacon = sc->sched.next_tbtt;
 
-		/* Prevent wrap-around issues */
-		if (avp->periodic_noa_duration &&
-		    tsf_time - avp->periodic_noa_start > BIT(30))
-			avp->periodic_noa_duration = 0;
+		/*
+		 * If an offchannel switch is scheduled to happen after
+		 * a beacon transmission, update the NoA with one-shot
+		 * values and increment the index.
+		 */
+		if (sc->next_chan == &sc->offchannel.chan) {
+			avp->noa_index++;
+			avp->offchannel_start = tsf_time;
+			avp->offchannel_duration = sc->sched.offchannel_duration;
 
-		if (ctx->active && !avp->periodic_noa_duration) {
-			avp->periodic_noa_start = tsf_time;
-			avp->periodic_noa_duration =
-				TU_TO_USEC(cur_conf->beacon_interval) / 2 -
-				sc->sched.channel_switch_time;
-			noa_changed = true;
-		} else if (!ctx->active && avp->periodic_noa_duration) {
-			avp->periodic_noa_duration = 0;
-			noa_changed = true;
+			ath_dbg(common, CHAN_CTX,
+				"offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
+				avp->offchannel_duration,
+				avp->offchannel_start,
+				avp->noa_index);
+
+			/*
+			 * When multiple contexts are active, the NoA
+			 * has to be recalculated and advertised after
+			 * an offchannel operation.
+			 */
+			if (ctx->active && avp->noa_duration)
+				avp->noa_duration = 0;
+
+			break;
+		}
+
+		/*
+		 * Clear the extend_absence flag if it had been
+		 * set during the previous beacon transmission,
+		 * since we need to revert to the normal NoA
+		 * schedule.
+		 */
+		if (ctx->active && sc->sched.extend_absence) {
+			avp->noa_duration = 0;
+			sc->sched.extend_absence = false;
 		}
 
 		/* If at least two consecutive beacons were missed on the STA
 		 * chanctx, stay on the STA channel for one extra beacon period,
 		 * to resync the timer properly.
 		 */
-		if (ctx->active && sc->sched.beacon_miss >= 2)
-			sc->sched.offchannel_duration = 3 * beacon_int / 2;
-
-		if (sc->sched.offchannel_duration) {
-			noa_changed = true;
-			avp->offchannel_start = tsf_time;
-			avp->offchannel_duration =
-				sc->sched.offchannel_duration;
+		if (ctx->active && sc->sched.beacon_miss >= 2) {
+			avp->noa_duration = 0;
+			sc->sched.extend_absence = true;
 		}
 
-		if (noa_changed)
+		/* Prevent wrap-around issues */
+		if (avp->noa_duration && tsf_time - avp->noa_start > BIT(30))
+			avp->noa_duration = 0;
+
+		/*
+		 * If multiple contexts are active, start periodic
+		 * NoA and increment the index for the first
+		 * announcement.
+		 */
+		if (ctx->active &&
+		    (!avp->noa_duration || sc->sched.force_noa_update)) {
 			avp->noa_index++;
+			avp->noa_start = tsf_time;
+
+			if (sc->sched.extend_absence)
+				avp->noa_duration = (3 * beacon_int / 2) +
+					sc->sched.channel_switch_time;
+			else
+				avp->noa_duration =
+					TU_TO_USEC(cur_conf->beacon_interval) / 2 +
+					sc->sched.channel_switch_time;
+
+			if (test_bit(ATH_OP_SCANNING, &common->op_flags) ||
+			    sc->sched.extend_absence)
+				avp->periodic_noa = false;
+			else
+				avp->periodic_noa = true;
+
+			ath_dbg(common, CHAN_CTX,
+				"noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
+				avp->noa_duration,
+				avp->noa_start,
+				avp->noa_index,
+				avp->periodic_noa);
+		}
+
+		if (ctx->active && sc->sched.force_noa_update)
+			sc->sched.force_noa_update = false;
+
 		break;
 	case ATH_CHANCTX_EVENT_BEACON_SENT:
-		if (!sc->sched.beacon_pending)
+		if (!sc->sched.beacon_pending) {
+			ath_dbg(common, CHAN_CTX,
+				"No pending beacon\n");
 			break;
+		}
 
 		sc->sched.beacon_pending = false;
 		if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
 			break;
 
+		ath_dbg(common, CHAN_CTX,
+			"Move chanctx state to WAIT_FOR_TIMER\n");
+
 		sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
 		ath_chanctx_setup_timer(sc, sc->sched.switch_start_time);
 		break;
@@ -597,6 +484,9 @@
 		    sc->sched.beacon_pending)
 			sc->sched.beacon_miss++;
 
+		ath_dbg(common, CHAN_CTX,
+			"Move chanctx state to SWITCH\n");
+
 		sc->sched.state = ATH_CHANCTX_STATE_SWITCH;
 		ieee80211_queue_work(sc->hw, &sc->chanctx_work);
 		break;
@@ -625,6 +515,9 @@
 		    avp->chanctx != sc->cur_chan)
 			break;
 
+		ath_dbg(common, CHAN_CTX,
+			"Move chanctx state from FORCE_ACTIVE to IDLE\n");
+
 		sc->sched.state = ATH_CHANCTX_STATE_IDLE;
 		/* fall through */
 	case ATH_CHANCTX_EVENT_SWITCH:
@@ -640,10 +533,15 @@
 		sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan);
 		cur_conf = &sc->cur_chan->beacon;
 
+		ath_dbg(common, CHAN_CTX,
+			"Move chanctx state to WAIT_FOR_TIMER (event SWITCH)\n");
+
 		sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
+		sc->sched.wait_switch = false;
 
 		tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2;
-		if (sc->sched.beacon_miss >= 2) {
+
+		if (sc->sched.extend_absence) {
 			sc->sched.beacon_miss = 0;
 			tsf_time *= 3;
 		}
@@ -679,7 +577,874 @@
 		sc->next_chan = ctx;
 		ieee80211_queue_work(sc->hw, &sc->chanctx_work);
 		break;
+	case ATH_CHANCTX_EVENT_ASSIGN:
+		/*
+		 * When adding a new channel context, check if a scan
+		 * is in progress and abort it since the addition of
+		 * a new channel context is usually followed by VIF
+		 * assignment, in which case we have to start multi-channel
+		 * operation.
+		 */
+		if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
+			ath_dbg(common, CHAN_CTX,
+				"Aborting HW scan to add new context\n");
+
+			spin_unlock_bh(&sc->chan_lock);
+			del_timer_sync(&sc->offchannel.timer);
+			ath_scan_complete(sc, true);
+			spin_lock_bh(&sc->chan_lock);
+		}
+		break;
+	case ATH_CHANCTX_EVENT_CHANGE:
+		break;
 	}
 
 	spin_unlock_bh(&sc->chan_lock);
 }
+
+void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+				enum ath_chanctx_event ev)
+{
+	if (sc->sched.beacon_pending)
+		ath_chanctx_event(sc, NULL, ev);
+}
+
+void ath_chanctx_beacon_recv_ev(struct ath_softc *sc,
+				enum ath_chanctx_event ev)
+{
+	ath_chanctx_event(sc, NULL, ev);
+}
+
+static int ath_scan_channel_duration(struct ath_softc *sc,
+				     struct ieee80211_channel *chan)
+{
+	struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+
+	if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR))
+		return (HZ / 9); /* ~110 ms */
+
+	return (HZ / 16); /* ~60 ms */
+}
+
+static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
+			       struct cfg80211_chan_def *chandef)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	spin_lock_bh(&sc->chan_lock);
+
+	if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) &&
+	    (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) {
+		if (chandef)
+			ctx->chandef = *chandef;
+
+		sc->sched.offchannel_pending = true;
+		sc->sched.wait_switch = true;
+		sc->sched.offchannel_duration =
+			jiffies_to_usecs(sc->offchannel.duration) +
+			sc->sched.channel_switch_time;
+
+		spin_unlock_bh(&sc->chan_lock);
+		ath_dbg(common, CHAN_CTX,
+			"Set offchannel_pending to true\n");
+		return;
+	}
+
+	sc->next_chan = ctx;
+	if (chandef) {
+		ctx->chandef = *chandef;
+		ath_dbg(common, CHAN_CTX,
+			"Assigned next_chan to %d MHz\n", chandef->center_freq1);
+	}
+
+	if (sc->next_chan == &sc->offchannel.chan) {
+		sc->sched.offchannel_duration =
+			jiffies_to_usecs(sc->offchannel.duration) +
+			sc->sched.channel_switch_time;
+
+		if (chandef) {
+			ath_dbg(common, CHAN_CTX,
+				"Offchannel duration for chan %d MHz : %u\n",
+				chandef->center_freq1,
+				sc->sched.offchannel_duration);
+		}
+	}
+	spin_unlock_bh(&sc->chan_lock);
+	ieee80211_queue_work(sc->hw, &sc->chanctx_work);
+}
+
+static void ath_chanctx_offchan_switch(struct ath_softc *sc,
+				       struct ieee80211_channel *chan)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct cfg80211_chan_def chandef;
+
+	cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+	ath_dbg(common, CHAN_CTX,
+		"Channel definition created: %d MHz\n", chandef.center_freq1);
+
+	ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef);
+}
+
+static struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc,
+						     bool active)
+{
+	struct ath_chanctx *ctx;
+
+	ath_for_each_chanctx(sc, ctx) {
+		if (!ctx->assigned || list_empty(&ctx->vifs))
+			continue;
+		if (active && !ctx->active)
+			continue;
+
+		if (ctx->switch_after_beacon)
+			return ctx;
+	}
+
+	return &sc->chanctx[0];
+}
+
+static void
+ath_scan_next_channel(struct ath_softc *sc)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+	struct ieee80211_channel *chan;
+
+	if (sc->offchannel.scan_idx >= req->n_channels) {
+		ath_dbg(common, CHAN_CTX,
+			"Moving offchannel state to ATH_OFFCHANNEL_IDLE, "
+			"scan_idx: %d, n_channels: %d\n",
+			sc->offchannel.scan_idx,
+			req->n_channels);
+
+		sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
+		ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
+				   NULL);
+		return;
+	}
+
+	ath_dbg(common, CHAN_CTX,
+		"Moving offchannel state to ATH_OFFCHANNEL_PROBE_SEND, scan_idx: %d\n",
+		sc->offchannel.scan_idx);
+
+	chan = req->channels[sc->offchannel.scan_idx++];
+	sc->offchannel.duration = ath_scan_channel_duration(sc, chan);
+	sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND;
+
+	ath_chanctx_offchan_switch(sc, chan);
+}
+
+void ath_offchannel_next(struct ath_softc *sc)
+{
+	struct ieee80211_vif *vif;
+
+	if (sc->offchannel.scan_req) {
+		vif = sc->offchannel.scan_vif;
+		sc->offchannel.chan.txpower = vif->bss_conf.txpower;
+		ath_scan_next_channel(sc);
+	} else if (sc->offchannel.roc_vif) {
+		vif = sc->offchannel.roc_vif;
+		sc->offchannel.chan.txpower = vif->bss_conf.txpower;
+		sc->offchannel.duration =
+			msecs_to_jiffies(sc->offchannel.roc_duration);
+		sc->offchannel.state = ATH_OFFCHANNEL_ROC_START;
+		ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan);
+	} else {
+		ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
+				   NULL);
+		sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
+		if (sc->ps_idle)
+			ath_cancel_work(sc);
+	}
+}
+
+void ath_roc_complete(struct ath_softc *sc, bool abort)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	if (abort)
+		ath_dbg(common, CHAN_CTX, "RoC aborted\n");
+	else
+		ath_dbg(common, CHAN_CTX, "RoC expired\n");
+
+	sc->offchannel.roc_vif = NULL;
+	sc->offchannel.roc_chan = NULL;
+	if (!abort)
+		ieee80211_remain_on_channel_expired(sc->hw);
+	ath_offchannel_next(sc);
+	ath9k_ps_restore(sc);
+}
+
+void ath_scan_complete(struct ath_softc *sc, bool abort)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	if (abort)
+		ath_dbg(common, CHAN_CTX, "HW scan aborted\n");
+	else
+		ath_dbg(common, CHAN_CTX, "HW scan complete\n");
+
+	sc->offchannel.scan_req = NULL;
+	sc->offchannel.scan_vif = NULL;
+	sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
+	ieee80211_scan_completed(sc->hw, abort);
+	clear_bit(ATH_OP_SCANNING, &common->op_flags);
+	spin_lock_bh(&sc->chan_lock);
+	if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+		sc->sched.force_noa_update = true;
+	spin_unlock_bh(&sc->chan_lock);
+	ath_offchannel_next(sc);
+	ath9k_ps_restore(sc);
+}
+
+static void ath_scan_send_probe(struct ath_softc *sc,
+				struct cfg80211_ssid *ssid)
+{
+	struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+	struct ieee80211_vif *vif = sc->offchannel.scan_vif;
+	struct ath_tx_control txctl = {};
+	struct sk_buff *skb;
+	struct ieee80211_tx_info *info;
+	int band = sc->offchannel.chan.chandef.chan->band;
+
+	skb = ieee80211_probereq_get(sc->hw, vif,
+			ssid->ssid, ssid->ssid_len, req->ie_len);
+	if (!skb)
+		return;
+
+	info = IEEE80211_SKB_CB(skb);
+	if (req->no_cck)
+		info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
+
+	if (req->ie_len)
+		memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
+
+	skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+
+	if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
+		goto error;
+
+	txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
+	txctl.force_channel = true;
+	if (ath_tx_start(sc->hw, skb, &txctl))
+		goto error;
+
+	return;
+
+error:
+	ieee80211_free_txskb(sc->hw, skb);
+}
+
+static void ath_scan_channel_start(struct ath_softc *sc)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+	int i;
+
+	if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) &&
+	    req->n_ssids) {
+		for (i = 0; i < req->n_ssids; i++)
+			ath_scan_send_probe(sc, &req->ssids[i]);
+
+	}
+
+	ath_dbg(common, CHAN_CTX,
+		"Moving offchannel state to ATH_OFFCHANNEL_PROBE_WAIT\n");
+
+	sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT;
+	mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration);
+}
+
+static void ath_chanctx_timer(unsigned long data)
+{
+	struct ath_softc *sc = (struct ath_softc *) data;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	ath_dbg(common, CHAN_CTX,
+		"Channel context timer invoked\n");
+
+	ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
+}
+
+static void ath_offchannel_timer(unsigned long data)
+{
+	struct ath_softc *sc = (struct ath_softc *)data;
+	struct ath_chanctx *ctx;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n",
+		__func__, offchannel_state_string(sc->offchannel.state));
+
+	switch (sc->offchannel.state) {
+	case ATH_OFFCHANNEL_PROBE_WAIT:
+		if (!sc->offchannel.scan_req)
+			return;
+
+		/* get first active channel context */
+		ctx = ath_chanctx_get_oper_chan(sc, true);
+		if (ctx->active) {
+			ath_dbg(common, CHAN_CTX,
+				"Switch to oper/active context, "
+				"move offchannel state to ATH_OFFCHANNEL_SUSPEND\n");
+
+			sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND;
+			ath_chanctx_switch(sc, ctx, NULL);
+			mod_timer(&sc->offchannel.timer, jiffies + HZ / 10);
+			break;
+		}
+		/* fall through */
+	case ATH_OFFCHANNEL_SUSPEND:
+		if (!sc->offchannel.scan_req)
+			return;
+
+		ath_scan_next_channel(sc);
+		break;
+	case ATH_OFFCHANNEL_ROC_START:
+	case ATH_OFFCHANNEL_ROC_WAIT:
+		ctx = ath_chanctx_get_oper_chan(sc, false);
+		sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
+		ath_chanctx_switch(sc, ctx, NULL);
+		break;
+	default:
+		break;
+	}
+}
+
+static bool
+ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
+			      bool powersave)
+{
+	struct ieee80211_vif *vif = avp->vif;
+	struct ieee80211_sta *sta = NULL;
+	struct ieee80211_hdr_3addr *nullfunc;
+	struct ath_tx_control txctl;
+	struct sk_buff *skb;
+	int band = sc->cur_chan->chandef.chan->band;
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_STATION:
+		if (!avp->assoc)
+			return false;
+
+		skb = ieee80211_nullfunc_get(sc->hw, vif);
+		if (!skb)
+			return false;
+
+		nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
+		if (powersave)
+			nullfunc->frame_control |=
+				cpu_to_le16(IEEE80211_FCTL_PM);
+
+		skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+		if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
+			dev_kfree_skb_any(skb);
+			return false;
+		}
+		break;
+	default:
+		return false;
+	}
+
+	memset(&txctl, 0, sizeof(txctl));
+	txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
+	txctl.sta = sta;
+	txctl.force_channel = true;
+	if (ath_tx_start(sc->hw, skb, &txctl)) {
+		ieee80211_free_txskb(sc->hw, skb);
+		return false;
+	}
+
+	return true;
+}
+
+static bool
+ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave)
+{
+	struct ath_vif *avp;
+	bool sent = false;
+
+	rcu_read_lock();
+	list_for_each_entry(avp, &sc->cur_chan->vifs, list) {
+		if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave))
+			sent = true;
+	}
+	rcu_read_unlock();
+
+	return sent;
+}
+
+static bool ath_chanctx_defer_switch(struct ath_softc *sc)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	if (sc->cur_chan == &sc->offchannel.chan)
+		return false;
+
+	switch (sc->sched.state) {
+	case ATH_CHANCTX_STATE_SWITCH:
+		return false;
+	case ATH_CHANCTX_STATE_IDLE:
+		if (!sc->cur_chan->switch_after_beacon)
+			return false;
+
+		ath_dbg(common, CHAN_CTX,
+			"Defer switch, set chanctx state to WAIT_FOR_BEACON\n");
+
+		sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+		break;
+	default:
+		break;
+	}
+
+	return true;
+}
+
+static void ath_offchannel_channel_change(struct ath_softc *sc)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n",
+		__func__, offchannel_state_string(sc->offchannel.state));
+
+	switch (sc->offchannel.state) {
+	case ATH_OFFCHANNEL_PROBE_SEND:
+		if (!sc->offchannel.scan_req)
+			return;
+
+		if (sc->cur_chan->chandef.chan !=
+		    sc->offchannel.chan.chandef.chan)
+			return;
+
+		ath_scan_channel_start(sc);
+		break;
+	case ATH_OFFCHANNEL_IDLE:
+		if (!sc->offchannel.scan_req)
+			return;
+
+		ath_scan_complete(sc, false);
+		break;
+	case ATH_OFFCHANNEL_ROC_START:
+		if (sc->cur_chan != &sc->offchannel.chan)
+			break;
+
+		sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT;
+		mod_timer(&sc->offchannel.timer,
+			  jiffies + sc->offchannel.duration);
+		ieee80211_ready_on_channel(sc->hw);
+		break;
+	case ATH_OFFCHANNEL_ROC_DONE:
+		ath_roc_complete(sc, false);
+		break;
+	default:
+		break;
+	}
+}
+
+void ath_chanctx_set_next(struct ath_softc *sc, bool force)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath_chanctx *old_ctx;
+	struct timespec ts;
+	bool measure_time = false;
+	bool send_ps = false;
+	bool queues_stopped = false;
+
+	spin_lock_bh(&sc->chan_lock);
+	if (!sc->next_chan) {
+		spin_unlock_bh(&sc->chan_lock);
+		return;
+	}
+
+	if (!force && ath_chanctx_defer_switch(sc)) {
+		spin_unlock_bh(&sc->chan_lock);
+		return;
+	}
+
+	ath_dbg(common, CHAN_CTX,
+		"%s: current: %d MHz, next: %d MHz\n",
+		__func__,
+		sc->cur_chan->chandef.center_freq1,
+		sc->next_chan->chandef.center_freq1);
+
+	if (sc->cur_chan != sc->next_chan) {
+		ath_dbg(common, CHAN_CTX,
+			"Stopping current chanctx: %d\n",
+			sc->cur_chan->chandef.center_freq1);
+		sc->cur_chan->stopped = true;
+		spin_unlock_bh(&sc->chan_lock);
+
+		if (sc->next_chan == &sc->offchannel.chan) {
+			getrawmonotonic(&ts);
+			measure_time = true;
+		}
+
+		ath9k_chanctx_stop_queues(sc, sc->cur_chan);
+		queues_stopped = true;
+
+		__ath9k_flush(sc->hw, ~0, true);
+
+		if (ath_chanctx_send_ps_frame(sc, true))
+			__ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
+
+		send_ps = true;
+		spin_lock_bh(&sc->chan_lock);
+
+		if (sc->cur_chan != &sc->offchannel.chan) {
+			getrawmonotonic(&sc->cur_chan->tsf_ts);
+			sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
+		}
+	}
+	old_ctx = sc->cur_chan;
+	sc->cur_chan = sc->next_chan;
+	sc->cur_chan->stopped = false;
+	sc->next_chan = NULL;
+
+	if (!sc->sched.offchannel_pending)
+		sc->sched.offchannel_duration = 0;
+
+	if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE)
+		sc->sched.state = ATH_CHANCTX_STATE_IDLE;
+
+	spin_unlock_bh(&sc->chan_lock);
+
+	if (sc->sc_ah->chip_fullsleep ||
+	    memcmp(&sc->cur_chandef, &sc->cur_chan->chandef,
+		   sizeof(sc->cur_chandef))) {
+		ath_dbg(common, CHAN_CTX,
+			"%s: Set channel %d MHz\n",
+			__func__, sc->cur_chan->chandef.center_freq1);
+		ath_set_channel(sc);
+		if (measure_time)
+			sc->sched.channel_switch_time =
+				ath9k_hw_get_tsf_offset(&ts, NULL);
+		/*
+		 * A reset will ensure that all queues are woken up,
+		 * so there is no need to awaken them again.
+		 */
+		goto out;
+	}
+
+	if (queues_stopped)
+		ath9k_chanctx_wake_queues(sc, old_ctx);
+out:
+	if (send_ps)
+		ath_chanctx_send_ps_frame(sc, false);
+
+	ath_offchannel_channel_change(sc);
+	ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH);
+}
+
+static void ath_chanctx_work(struct work_struct *work)
+{
+	struct ath_softc *sc = container_of(work, struct ath_softc,
+					    chanctx_work);
+	mutex_lock(&sc->mutex);
+	ath_chanctx_set_next(sc, false);
+	mutex_unlock(&sc->mutex);
+}
+
+void ath9k_offchannel_init(struct ath_softc *sc)
+{
+	struct ath_chanctx *ctx;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *chan;
+	int i;
+
+	sband = &common->sbands[IEEE80211_BAND_2GHZ];
+	if (!sband->n_channels)
+		sband = &common->sbands[IEEE80211_BAND_5GHZ];
+
+	chan = &sband->channels[0];
+
+	ctx = &sc->offchannel.chan;
+	INIT_LIST_HEAD(&ctx->vifs);
+	ctx->txpower = ATH_TXPOWER_MAX;
+	cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
+
+	for (i = 0; i < ARRAY_SIZE(ctx->acq); i++)
+		INIT_LIST_HEAD(&ctx->acq[i]);
+
+	sc->offchannel.chan.offchannel = true;
+}
+
+void ath9k_init_channel_context(struct ath_softc *sc)
+{
+	INIT_WORK(&sc->chanctx_work, ath_chanctx_work);
+
+	setup_timer(&sc->offchannel.timer, ath_offchannel_timer,
+		    (unsigned long)sc);
+	setup_timer(&sc->sched.timer, ath_chanctx_timer,
+		    (unsigned long)sc);
+}
+
+void ath9k_deinit_channel_context(struct ath_softc *sc)
+{
+	cancel_work_sync(&sc->chanctx_work);
+}
+
+bool ath9k_is_chanctx_enabled(void)
+{
+	return (ath9k_use_chanctx == 1);
+}
+
+/********************/
+/* Queue management */
+/********************/
+
+void ath9k_chanctx_stop_queues(struct ath_softc *sc, struct ath_chanctx *ctx)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	int i;
+
+	if (ctx == &sc->offchannel.chan) {
+		ieee80211_stop_queue(sc->hw,
+				     sc->hw->offchannel_tx_hw_queue);
+	} else {
+		for (i = 0; i < IEEE80211_NUM_ACS; i++)
+			ieee80211_stop_queue(sc->hw,
+					     ctx->hw_queue_base + i);
+	}
+
+	if (ah->opmode == NL80211_IFTYPE_AP)
+		ieee80211_stop_queue(sc->hw, sc->hw->queues - 2);
+}
+
+
+void ath9k_chanctx_wake_queues(struct ath_softc *sc, struct ath_chanctx *ctx)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	int i;
+
+	if (ctx == &sc->offchannel.chan) {
+		ieee80211_wake_queue(sc->hw,
+				     sc->hw->offchannel_tx_hw_queue);
+	} else {
+		for (i = 0; i < IEEE80211_NUM_ACS; i++)
+			ieee80211_wake_queue(sc->hw,
+					     ctx->hw_queue_base + i);
+	}
+
+	if (ah->opmode == NL80211_IFTYPE_AP)
+		ieee80211_wake_queue(sc->hw, sc->hw->queues - 2);
+}
+
+/*****************/
+/* P2P Powersave */
+/*****************/
+
+static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	s32 tsf, target_tsf;
+
+	if (!avp || !avp->noa.has_next_tsf)
+		return;
+
+	ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
+
+	tsf = ath9k_hw_gettsf32(sc->sc_ah);
+
+	target_tsf = avp->noa.next_tsf;
+	if (!avp->noa.absent)
+		target_tsf -= ATH_P2P_PS_STOP_TIME;
+
+	if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
+		target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
+
+	ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
+}
+
+static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+	struct ath_vif *avp = (void *)vif->drv_priv;
+	u32 tsf;
+
+	if (!sc->p2p_ps_timer)
+		return;
+
+	if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
+		return;
+
+	sc->p2p_ps_vif = avp;
+	tsf = ath9k_hw_gettsf32(sc->sc_ah);
+	ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
+	ath9k_update_p2p_ps_timer(sc, avp);
+}
+
+static u8 ath9k_get_ctwin(struct ath_softc *sc, struct ath_vif *avp)
+{
+	struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
+	u8 switch_time, ctwin;
+
+	/*
+	 * Channel switch in multi-channel mode is deferred
+	 * by a quarter beacon interval when handling
+	 * ATH_CHANCTX_EVENT_BEACON_PREPARE, so the P2P-GO
+	 * interface is guaranteed to be discoverable
+	 * for that duration after a TBTT.
+	 */
+	switch_time = cur_conf->beacon_interval / 4;
+
+	ctwin = avp->vif->bss_conf.p2p_noa_attr.oppps_ctwindow;
+	if (ctwin && (ctwin < switch_time))
+		return ctwin;
+
+	if (switch_time < P2P_DEFAULT_CTWIN)
+		return 0;
+
+	return P2P_DEFAULT_CTWIN;
+}
+
+void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+			  struct sk_buff *skb)
+{
+	static const u8 noa_ie_hdr[] = {
+		WLAN_EID_VENDOR_SPECIFIC,	/* type */
+		0,				/* length */
+		0x50, 0x6f, 0x9a,		/* WFA OUI */
+		0x09,				/* P2P subtype */
+		0x0c,				/* Notice of Absence */
+		0x00,				/* LSB of little-endian len */
+		0x00,				/* MSB of little-endian len */
+	};
+
+	struct ieee80211_p2p_noa_attr *noa;
+	int noa_len, noa_desc, i = 0;
+	u8 *hdr;
+
+	if (!avp->offchannel_duration && !avp->noa_duration)
+		return;
+
+	noa_desc = !!avp->offchannel_duration + !!avp->noa_duration;
+	noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
+
+	hdr = skb_put(skb, sizeof(noa_ie_hdr));
+	memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr));
+	hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2;
+	hdr[7] = noa_len;
+
+	noa = (void *) skb_put(skb, noa_len);
+	memset(noa, 0, noa_len);
+
+	noa->index = avp->noa_index;
+	noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp);
+
+	if (avp->noa_duration) {
+		if (avp->periodic_noa) {
+			u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
+			noa->desc[i].count = 255;
+			noa->desc[i].interval = cpu_to_le32(interval);
+		} else {
+			noa->desc[i].count = 1;
+		}
+
+		noa->desc[i].start_time = cpu_to_le32(avp->noa_start);
+		noa->desc[i].duration = cpu_to_le32(avp->noa_duration);
+		i++;
+	}
+
+	if (avp->offchannel_duration) {
+		noa->desc[i].count = 1;
+		noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start);
+		noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration);
+	}
+}
+
+void ath9k_p2p_ps_timer(void *priv)
+{
+	struct ath_softc *sc = priv;
+	struct ath_vif *avp = sc->p2p_ps_vif;
+	struct ieee80211_vif *vif;
+	struct ieee80211_sta *sta;
+	struct ath_node *an;
+	u32 tsf;
+
+	del_timer_sync(&sc->sched.timer);
+	ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer);
+	ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
+
+	if (!avp || avp->chanctx != sc->cur_chan)
+		return;
+
+	tsf = ath9k_hw_gettsf32(sc->sc_ah);
+	if (!avp->noa.absent)
+		tsf += ATH_P2P_PS_STOP_TIME;
+
+	if (!avp->noa.has_next_tsf ||
+	    avp->noa.next_tsf - tsf > BIT(31))
+		ieee80211_update_p2p_noa(&avp->noa, tsf);
+
+	ath9k_update_p2p_ps_timer(sc, avp);
+
+	rcu_read_lock();
+
+	vif = avp->vif;
+	sta = ieee80211_find_sta(vif, avp->bssid);
+	if (!sta)
+		goto out;
+
+	an = (void *) sta->drv_priv;
+	if (an->sleeping == !!avp->noa.absent)
+		goto out;
+
+	an->sleeping = avp->noa.absent;
+	if (an->sleeping)
+		ath_tx_aggr_sleep(sta, sc, an);
+	else
+		ath_tx_aggr_wakeup(sc, an);
+
+out:
+	rcu_read_unlock();
+}
+
+void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
+				struct ieee80211_vif *vif)
+{
+	unsigned long flags;
+
+	spin_lock_bh(&sc->sc_pcu_lock);
+	spin_lock_irqsave(&sc->sc_pm_lock, flags);
+	if (!(sc->ps_flags & PS_BEACON_SYNC))
+		ath9k_update_p2p_ps(sc, vif);
+	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+	spin_unlock_bh(&sc->sc_pcu_lock);
+}
+
+void ath9k_p2p_beacon_sync(struct ath_softc *sc)
+{
+	if (sc->p2p_ps_vif)
+		ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
+}
+
+void ath9k_p2p_remove_vif(struct ath_softc *sc,
+			  struct ieee80211_vif *vif)
+{
+	struct ath_vif *avp = (void *)vif->drv_priv;
+
+	spin_lock_bh(&sc->sc_pcu_lock);
+	if (avp == sc->p2p_ps_vif) {
+		sc->p2p_ps_vif = NULL;
+		ath9k_update_p2p_ps_timer(sc, NULL);
+	}
+	spin_unlock_bh(&sc->sc_pcu_lock);
+}
+
+int ath9k_init_p2p(struct ath_softc *sc)
+{
+	sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
+					       NULL, sc, AR_FIRST_NDP_TIMER);
+	if (!sc->p2p_ps_timer)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void ath9k_deinit_p2p(struct ath_softc *sc)
+{
+	if (sc->p2p_ps_timer)
+		ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
+}
+
+#endif /* CPTCFG_ATH9K_CHANNEL_CONTEXT */
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index e438a76..947be9a 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -838,7 +838,7 @@
 			iter_data.nmeshes, iter_data.nwds);
 		len += scnprintf(buf + len, sizeof(buf) - len,
 			" ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
-			iter_data.nadhocs, sc->nvifs, sc->nbcnvifs);
+			iter_data.nadhocs, sc->cur_chan->nvifs, sc->nbcnvifs);
 	}
 
 	if (len > sizeof(buf))
@@ -1169,6 +1169,29 @@
 };
 #endif
 
+#ifdef CPTCFG_ATH9K_DYNACK
+static ssize_t read_file_ackto(struct file *file, char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	struct ath_hw *ah = sc->sc_ah;
+	char buf[32];
+	unsigned int len;
+
+	len = sprintf(buf, "%u %c\n", ah->dynack.ackto,
+		      (ah->dynack.enabled) ? 'A' : 'S');
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_ackto = {
+	.read = read_file_ackto,
+	.open = simple_open,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+#endif
+
 /* Ethtool support for get-stats */
 
 #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
@@ -1374,5 +1397,10 @@
 			    &fops_btcoex);
 #endif
 
+#ifdef CPTCFG_ATH9K_DYNACK
+	debugfs_create_file("ack_to", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+			    sc, &fops_ackto);
+#endif
+
 	return 0;
 }
diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c
new file mode 100644
index 0000000..22b3cc4
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/dynack.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2014, Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+#include "hw.h"
+#include "dynack.h"
+
+#define COMPUTE_TO		(5 * HZ)
+#define LATEACK_DELAY		(10 * HZ)
+#define LATEACK_TO		256
+#define MAX_DELAY		300
+#define EWMA_LEVEL		96
+#define EWMA_DIV		128
+
+/**
+ * ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation
+ *
+ */
+static inline u32 ath_dynack_ewma(u32 old, u32 new)
+{
+	return (new * (EWMA_DIV - EWMA_LEVEL) + old * EWMA_LEVEL) / EWMA_DIV;
+}
+
+/**
+ * ath_dynack_get_sifs - get sifs time based on phy used
+ * @ah: ath hw
+ * @phy: phy used
+ *
+ */
+static inline u32 ath_dynack_get_sifs(struct ath_hw *ah, int phy)
+{
+	u32 sifs = CCK_SIFS_TIME;
+
+	if (phy == WLAN_RC_PHY_OFDM) {
+		if (IS_CHAN_QUARTER_RATE(ah->curchan))
+			sifs = OFDM_SIFS_TIME_QUARTER;
+		else if (IS_CHAN_HALF_RATE(ah->curchan))
+			sifs = OFDM_SIFS_TIME_HALF;
+		else
+			sifs = OFDM_SIFS_TIME;
+	}
+	return sifs;
+}
+
+/**
+ * ath_dynack_bssidmask - filter out ACK frames based on BSSID mask
+ * @ah: ath hw
+ * @mac: receiver address
+ */
+static inline bool ath_dynack_bssidmask(struct ath_hw *ah, const u8 *mac)
+{
+	int i;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		if ((common->macaddr[i] & common->bssidmask[i]) !=
+		    (mac[i] & common->bssidmask[i]))
+			return false;
+	}
+
+	return true;
+}
+
+/**
+ * ath_dynack_compute_ackto - compute ACK timeout as the maximum STA timeout
+ * @ah: ath hw
+ *
+ * should be called while holding qlock
+ */
+static void ath_dynack_compute_ackto(struct ath_hw *ah)
+{
+	struct ath_node *an;
+	u32 to = 0;
+	struct ath_dynack *da = &ah->dynack;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	list_for_each_entry(an, &da->nodes, list)
+		if (an->ackto > to)
+			to = an->ackto;
+
+	if (to && da->ackto != to) {
+		u32 slottime;
+
+		slottime = (to - 3) / 2;
+		da->ackto = to;
+		ath_dbg(common, DYNACK, "ACK timeout %u slottime %u\n",
+			da->ackto, slottime);
+		ath9k_hw_setslottime(ah, slottime);
+		ath9k_hw_set_ack_timeout(ah, da->ackto);
+		ath9k_hw_set_cts_timeout(ah, da->ackto);
+	}
+}
+
+/**
+ * ath_dynack_compute_to - compute STA ACK timeout
+ * @ah: ath hw
+ *
+ * should be called while holding qlock
+ */
+static void ath_dynack_compute_to(struct ath_hw *ah)
+{
+	u32 ackto, ack_ts;
+	u8 *dst, *src;
+	struct ieee80211_sta *sta;
+	struct ath_node *an;
+	struct ts_info *st_ts;
+	struct ath_dynack *da = &ah->dynack;
+
+	rcu_read_lock();
+
+	while (da->st_rbf.h_rb != da->st_rbf.t_rb &&
+	       da->ack_rbf.h_rb != da->ack_rbf.t_rb) {
+		ack_ts = da->ack_rbf.tstamp[da->ack_rbf.h_rb];
+		st_ts = &da->st_rbf.ts[da->st_rbf.h_rb];
+		dst = da->st_rbf.addr[da->st_rbf.h_rb].h_dest;
+		src = da->st_rbf.addr[da->st_rbf.h_rb].h_src;
+
+		ath_dbg(ath9k_hw_common(ah), DYNACK,
+			"ack_ts %u st_ts %u st_dur %u [%u-%u]\n",
+			ack_ts, st_ts->tstamp, st_ts->dur,
+			da->ack_rbf.h_rb, da->st_rbf.h_rb);
+
+		if (ack_ts > st_ts->tstamp + st_ts->dur) {
+			ackto = ack_ts - st_ts->tstamp - st_ts->dur;
+
+			if (ackto < MAX_DELAY) {
+				sta = ieee80211_find_sta_by_ifaddr(ah->hw, dst,
+								   src);
+				if (sta) {
+					an = (struct ath_node *)sta->drv_priv;
+					an->ackto = ath_dynack_ewma(an->ackto,
+								    ackto);
+					ath_dbg(ath9k_hw_common(ah), DYNACK,
+						"%pM to %u\n", dst, an->ackto);
+					if (time_is_before_jiffies(da->lto)) {
+						ath_dynack_compute_ackto(ah);
+						da->lto = jiffies + COMPUTE_TO;
+					}
+				}
+				INCR(da->ack_rbf.h_rb, ATH_DYN_BUF);
+			}
+			INCR(da->st_rbf.h_rb, ATH_DYN_BUF);
+		} else {
+			INCR(da->ack_rbf.h_rb, ATH_DYN_BUF);
+		}
+	}
+
+	rcu_read_unlock();
+}
+
+/**
+ * ath_dynack_sample_tx_ts - status timestamp sampling method
+ * @ah: ath hw
+ * @skb: socket buffer
+ * @ts: tx status info
+ *
+ */
+void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
+			     struct ath_tx_status *ts)
+{
+	u8 ridx;
+	struct ieee80211_hdr *hdr;
+	struct ath_dynack *da = &ah->dynack;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+	if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !da->enabled)
+		return;
+
+	spin_lock_bh(&da->qlock);
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+
+	/* late ACK */
+	if (ts->ts_status & ATH9K_TXERR_XRETRY) {
+		if (ieee80211_is_assoc_req(hdr->frame_control) ||
+		    ieee80211_is_assoc_resp(hdr->frame_control)) {
+			ath_dbg(common, DYNACK, "late ack\n");
+			ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2);
+			ath9k_hw_set_ack_timeout(ah, LATEACK_TO);
+			ath9k_hw_set_cts_timeout(ah, LATEACK_TO);
+			da->lto = jiffies + LATEACK_DELAY;
+		}
+
+		spin_unlock_bh(&da->qlock);
+		return;
+	}
+
+	ridx = ts->ts_rateindex;
+
+	da->st_rbf.ts[da->st_rbf.t_rb].tstamp = ts->ts_tstamp;
+	da->st_rbf.ts[da->st_rbf.t_rb].dur = ts->duration;
+	ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1);
+	ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2);
+
+	if (!(info->status.rates[ridx].flags & IEEE80211_TX_RC_MCS)) {
+		u32 phy, sifs;
+		const struct ieee80211_rate *rate;
+		struct ieee80211_tx_rate *rates = info->status.rates;
+
+		rate = &common->sbands[info->band].bitrates[rates[ridx].idx];
+		if (info->band == IEEE80211_BAND_2GHZ &&
+		    !(rate->flags & IEEE80211_RATE_ERP_G))
+			phy = WLAN_RC_PHY_CCK;
+		else
+			phy = WLAN_RC_PHY_OFDM;
+
+		sifs = ath_dynack_get_sifs(ah, phy);
+		da->st_rbf.ts[da->st_rbf.t_rb].dur -= sifs;
+	}
+
+	ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n",
+		hdr->addr1, da->st_rbf.ts[da->st_rbf.t_rb].tstamp,
+		da->st_rbf.ts[da->st_rbf.t_rb].dur, da->st_rbf.h_rb,
+		(da->st_rbf.t_rb + 1) % ATH_DYN_BUF);
+
+	INCR(da->st_rbf.t_rb, ATH_DYN_BUF);
+	if (da->st_rbf.t_rb == da->st_rbf.h_rb)
+		INCR(da->st_rbf.h_rb, ATH_DYN_BUF);
+
+	ath_dynack_compute_to(ah);
+
+	spin_unlock_bh(&da->qlock);
+}
+EXPORT_SYMBOL(ath_dynack_sample_tx_ts);
+
+/**
+ * ath_dynack_sample_ack_ts - ACK timestamp sampling method
+ * @ah: ath hw
+ * @skb: socket buffer
+ * @ts: rx timestamp
+ *
+ */
+void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb,
+			      u32 ts)
+{
+	struct ath_dynack *da = &ah->dynack;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+	if (!ath_dynack_bssidmask(ah, hdr->addr1) || !da->enabled)
+		return;
+
+	spin_lock_bh(&da->qlock);
+	da->ack_rbf.tstamp[da->ack_rbf.t_rb] = ts;
+
+	ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n",
+		da->ack_rbf.tstamp[da->ack_rbf.t_rb],
+		da->ack_rbf.h_rb, (da->ack_rbf.t_rb + 1) % ATH_DYN_BUF);
+
+	INCR(da->ack_rbf.t_rb, ATH_DYN_BUF);
+	if (da->ack_rbf.t_rb == da->ack_rbf.h_rb)
+		INCR(da->ack_rbf.h_rb, ATH_DYN_BUF);
+
+	ath_dynack_compute_to(ah);
+
+	spin_unlock_bh(&da->qlock);
+}
+EXPORT_SYMBOL(ath_dynack_sample_ack_ts);
+
+/**
+ * ath_dynack_node_init - init ath_node related info
+ * @ah: ath hw
+ * @an: ath node
+ *
+ */
+void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an)
+{
+	/* ackto = slottime + sifs + air delay */
+	u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
+	struct ath_dynack *da = &ah->dynack;
+
+	an->ackto = ackto;
+
+	spin_lock(&da->qlock);
+	list_add_tail(&an->list, &da->nodes);
+	spin_unlock(&da->qlock);
+}
+EXPORT_SYMBOL(ath_dynack_node_init);
+
+/**
+ * ath_dynack_node_deinit - deinit ath_node related info
+ * @ah: ath hw
+ * @an: ath node
+ *
+ */
+void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an)
+{
+	struct ath_dynack *da = &ah->dynack;
+
+	spin_lock(&da->qlock);
+	list_del(&an->list);
+	spin_unlock(&da->qlock);
+}
+EXPORT_SYMBOL(ath_dynack_node_deinit);
+
+/**
+ * ath_dynack_reset - reset dynack processing
+ * @ah: ath hw
+ *
+ */
+void ath_dynack_reset(struct ath_hw *ah)
+{
+	/* ackto = slottime + sifs + air delay */
+	u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
+	struct ath_dynack *da = &ah->dynack;
+
+	da->lto = jiffies;
+	da->ackto = ackto;
+
+	da->st_rbf.t_rb = 0;
+	da->st_rbf.h_rb = 0;
+	da->ack_rbf.t_rb = 0;
+	da->ack_rbf.h_rb = 0;
+
+	/* init acktimeout */
+	ath9k_hw_setslottime(ah, (ackto - 3) / 2);
+	ath9k_hw_set_ack_timeout(ah, ackto);
+	ath9k_hw_set_cts_timeout(ah, ackto);
+}
+EXPORT_SYMBOL(ath_dynack_reset);
+
+/**
+ * ath_dynack_init - init dynack data structure
+ * @ah: ath hw
+ *
+ */
+void ath_dynack_init(struct ath_hw *ah)
+{
+	struct ath_dynack *da = &ah->dynack;
+
+	memset(da, 0, sizeof(struct ath_dynack));
+
+	spin_lock_init(&da->qlock);
+	INIT_LIST_HEAD(&da->nodes);
+
+	ah->hw->wiphy->features |= NL80211_FEATURE_ACKTO_ESTIMATION;
+}
diff --git a/drivers/net/wireless/ath/ath9k/dynack.h b/drivers/net/wireless/ath/ath9k/dynack.h
new file mode 100644
index 0000000..81d9a08
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/dynack.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014, Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef DYNACK_H
+#define DYNACK_H
+
+#define ATH_DYN_BUF	64
+
+struct ath_hw;
+struct ath_node;
+
+/**
+ * struct ath_dyn_rxbuf - ACK frame ring buffer
+ * @h_rb: ring buffer head
+ * @t_rb: ring buffer tail
+ * @tstamp: ACK RX timestamp buffer
+ */
+struct ath_dyn_rxbuf {
+	u16 h_rb, t_rb;
+	u32 tstamp[ATH_DYN_BUF];
+};
+
+struct ts_info {
+	u32 tstamp;
+	u32 dur;
+};
+
+struct haddr_pair {
+	u8 h_dest[ETH_ALEN];
+	u8 h_src[ETH_ALEN];
+};
+
+/**
+ * struct ath_dyn_txbuf - tx frame ring buffer
+ * @h_rb: ring buffer head
+ * @t_rb: ring buffer tail
+ * @addr: dest/src address pair for a given TX frame
+ * @ts: TX frame timestamp buffer
+ */
+struct ath_dyn_txbuf {
+	u16 h_rb, t_rb;
+	struct haddr_pair addr[ATH_DYN_BUF];
+	struct ts_info ts[ATH_DYN_BUF];
+};
+
+/**
+ * struct ath_dynack - dynack processing info
+ * @enabled: enable dyn ack processing
+ * @ackto: current ACK timeout
+ * @lto: last ACK timeout computation
+ * @nodes: ath_node linked list
+ * @qlock: ts queue spinlock
+ * @ack_rbf: ACK ts ring buffer
+ * @st_rbf: status ts ring buffer
+ */
+struct ath_dynack {
+	bool enabled;
+	int ackto;
+	unsigned long lto;
+
+	struct list_head nodes;
+
+	/* protect timestamp queue access */
+	spinlock_t qlock;
+	struct ath_dyn_rxbuf ack_rbf;
+	struct ath_dyn_txbuf st_rbf;
+};
+
+#if defined(CPTCFG_ATH9K_DYNACK)
+void ath_dynack_reset(struct ath_hw *ah);
+void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an);
+void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an);
+void ath_dynack_init(struct ath_hw *ah);
+void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, u32 ts);
+void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
+			     struct ath_tx_status *ts);
+#else
+static inline void ath_dynack_init(struct ath_hw *ah) {}
+static inline void ath_dynack_node_init(struct ath_hw *ah,
+					struct ath_node *an) {}
+static inline void ath_dynack_node_deinit(struct ath_hw *ah,
+					  struct ath_node *an) {}
+static inline void ath_dynack_sample_ack_ts(struct ath_hw *ah,
+					    struct sk_buff *skb, u32 ts) {}
+static inline void ath_dynack_sample_tx_ts(struct ath_hw *ah,
+					   struct sk_buff *skb,
+					   struct ath_tx_status *ts) {}
+#endif
+
+#endif /* DYNACK_H */
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 458289a..b153389 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -464,6 +464,7 @@
 		return -ENOMEM;
 
 	ah->dev = priv->dev;
+	ah->hw = priv->hw;
 	ah->hw_version.devid = devid;
 	ah->hw_version.usbdev = drv_info;
 	ah->ah_flags |= AH_USE_EEPROM;
@@ -592,6 +593,8 @@
 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN |
 			    WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 
+	hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+
 	hw->queues = 4;
 	hw->max_listen_interval = 1;
 
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index a55213c..c03b3fa 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1722,7 +1722,7 @@
 }
 
 static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
-					 u8 coverage_class)
+					 s16 coverage_class)
 {
 	struct ath9k_htc_priv *priv = hw->priv;
 
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index ade7cca..134862c 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -67,6 +67,12 @@
 	return ath9k_hw_ops(ah)->proc_txdesc(ah, ds, ts);
 }
 
+static inline int ath9k_hw_get_duration(struct ath_hw *ah, const void *ds,
+					int index)
+{
+	return ath9k_hw_ops(ah)->get_duration(ah, ds, index);
+}
+
 static inline void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
 		struct ath_hw_antcomb_conf *antconf)
 {
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 0368ba1..3e83eec 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -222,31 +222,28 @@
 {
 	u32 val;
 
+	if (ah->get_mac_revision)
+		ah->hw_version.macRev = ah->get_mac_revision();
+
 	switch (ah->hw_version.devid) {
 	case AR5416_AR9100_DEVID:
 		ah->hw_version.macVersion = AR_SREV_VERSION_9100;
 		break;
 	case AR9300_DEVID_AR9330:
 		ah->hw_version.macVersion = AR_SREV_VERSION_9330;
-		if (ah->get_mac_revision) {
-			ah->hw_version.macRev = ah->get_mac_revision();
-		} else {
+		if (!ah->get_mac_revision) {
 			val = REG_READ(ah, AR_SREV);
 			ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
 		}
 		return;
 	case AR9300_DEVID_AR9340:
 		ah->hw_version.macVersion = AR_SREV_VERSION_9340;
-		val = REG_READ(ah, AR_SREV);
-		ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
 		return;
 	case AR9300_DEVID_QCA955X:
 		ah->hw_version.macVersion = AR_SREV_VERSION_9550;
 		return;
 	case AR9300_DEVID_AR953X:
 		ah->hw_version.macVersion = AR_SREV_VERSION_9531;
-		if (ah->get_mac_revision)
-			ah->hw_version.macRev = ah->get_mac_revision();
 		return;
 	}
 
@@ -647,6 +644,8 @@
 		return ret;
 	}
 
+	ath_dynack_init(ah);
+
 	return 0;
 }
 EXPORT_SYMBOL(ath9k_hw_init);
@@ -702,6 +701,8 @@
 {
 	u32 pll;
 
+	pll = ath9k_hw_compute_pll_control(ah, chan);
+
 	if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) {
 		/* program BB PLL ki and kd value, ki=0x4, kd=0x40 */
 		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
@@ -752,7 +753,8 @@
 		REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3,
 			      AR_CH0_DPLL3_PHASE_SHIFT, 0x1);
 
-		REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
+		REG_WRITE(ah, AR_RTC_PLL_CONTROL,
+			  pll | AR_RTC_9300_PLL_BYPASS);
 		udelay(1000);
 
 		/* program refdiv, nint, frac to RTC register */
@@ -768,7 +770,8 @@
 	} else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
 		u32 regval, pll2_divint, pll2_divfrac, refdiv;
 
-		REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
+		REG_WRITE(ah, AR_RTC_PLL_CONTROL,
+			  pll | AR_RTC_9300_SOC_PLL_BYPASS);
 		udelay(1000);
 
 		REG_SET_BIT(ah, AR_PHY_PLL_MODE, 0x1 << 16);
@@ -841,7 +844,6 @@
 		udelay(1000);
 	}
 
-	pll = ath9k_hw_compute_pll_control(ah, chan);
 	if (AR_SREV_9565(ah))
 		pll |= 0x40000;
 	REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
@@ -935,21 +937,21 @@
 	REG_WRITE(ah, AR_D_GBL_IFS_SIFS, val);
 }
 
-static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
+void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
 {
 	u32 val = ath9k_hw_mac_to_clks(ah, us);
 	val = min(val, (u32) 0xFFFF);
 	REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val);
 }
 
-static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
+void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
 {
 	u32 val = ath9k_hw_mac_to_clks(ah, us);
 	val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK));
 	REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val);
 }
 
-static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
+void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
 {
 	u32 val = ath9k_hw_mac_to_clks(ah, us);
 	val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS));
@@ -1053,6 +1055,14 @@
 		ctstimeout += 48 - sifstime - ah->slottime;
 	}
 
+	if (ah->dynack.enabled) {
+		acktimeout = ah->dynack.ackto;
+		ctstimeout = acktimeout;
+		slottime = (acktimeout - 3) / 2;
+	} else {
+		ah->dynack.ackto = acktimeout;
+	}
+
 	ath9k_hw_set_sifs_time(ah, sifstime);
 	ath9k_hw_setslottime(ah, slottime);
 	ath9k_hw_set_ack_timeout(ah, acktimeout);
@@ -1182,9 +1192,12 @@
 
 	switch (opmode) {
 	case NL80211_IFTYPE_ADHOC:
-		set |= AR_STA_ID1_ADHOC;
-		REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
-		break;
+		if (!AR_SREV_9340_13(ah)) {
+			set |= AR_STA_ID1_ADHOC;
+			REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
+			break;
+		}
+		/* fall through */
 	case NL80211_IFTYPE_MESH_POINT:
 	case NL80211_IFTYPE_AP:
 		set |= AR_STA_ID1_STA_AP;
@@ -1954,6 +1967,12 @@
 	if (AR_SREV_9565(ah) && common->bt_ant_diversity)
 		REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
 
+	if (ah->hw->conf.radar_enabled) {
+		/* set HW specific DFS configuration */
+		ah->radar_conf.ext_channel = IS_CHAN_HT40(chan);
+		ath9k_hw_set_radar_params(ah);
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL(ath9k_hw_reset);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index cee504e..a578e51 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -29,6 +29,7 @@
 #include "reg.h"
 #include "phy.h"
 #include "btcoex.h"
+#include "dynack.h"
 
 #include "../regd.h"
 
@@ -690,6 +691,7 @@
 			   struct ath_tx_info *i);
 	int (*proc_txdesc)(struct ath_hw *ah, void *ds,
 			   struct ath_tx_status *ts);
+	int (*get_duration)(struct ath_hw *ah, const void *ds, int index);
 	void (*antdiv_comb_conf_get)(struct ath_hw *ah,
 			struct ath_hw_antcomb_conf *antconf);
 	void (*antdiv_comb_conf_set)(struct ath_hw *ah,
@@ -924,6 +926,8 @@
 	int (*external_reset)(void);
 
 	const struct firmware *eeprom_blob;
+
+	struct ath_dynack dynack;
 };
 
 struct ath_bus_ops {
@@ -1080,6 +1084,10 @@
 void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning);
 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
 
+void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us);
+void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us);
+void ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
+
 #ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
 static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah)
 {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 4b77e84..4f59abf 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -61,10 +61,14 @@
 module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
 MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
 
+#ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
+
 int ath9k_use_chanctx;
 module_param_named(use_chanctx, ath9k_use_chanctx, int, 0444);
 MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency");
 
+#endif /* CPTCFG_ATH9K_CHANNEL_CONTEXT */
+
 bool is_ath9k_unloaded;
 
 #ifdef CPTCFG_MAC80211_LEDS
@@ -511,7 +515,7 @@
 	sc->tx99_power = MAX_RATE_POWER + 1;
 	init_waitqueue_head(&sc->tx_wait);
 	sc->cur_chan = &sc->chanctx[0];
-	if (!ath9k_use_chanctx)
+	if (!ath9k_is_chanctx_enabled())
 		sc->cur_chan->hw_queue_base = 0;
 
 	if (!pdata || pdata->use_eeprom) {
@@ -567,11 +571,9 @@
 	setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc);
 	INIT_WORK(&sc->hw_reset_work, ath_reset_work);
 	INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
-	INIT_WORK(&sc->chanctx_work, ath_chanctx_work);
 	INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
-	setup_timer(&sc->offchannel.timer, ath_offchannel_timer,
-		    (unsigned long)sc);
-	setup_timer(&sc->sched.timer, ath_chanctx_timer, (unsigned long)sc);
+
+	ath9k_init_channel_context(sc);
 
 	/*
 	 * Cache line size is used to size and align various
@@ -600,13 +602,15 @@
 	if (ret)
 		goto err_btcoex;
 
-	sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
-		NULL, sc, AR_FIRST_NDP_TIMER);
+	ret = ath9k_init_p2p(sc);
+	if (ret)
+		goto err_btcoex;
 
 	ath9k_cmn_init_crypto(sc->sc_ah);
 	ath9k_init_misc(sc);
 	ath_fill_led_pin(sc);
 	ath_chanctx_init(sc);
+	ath9k_offchannel_init(sc);
 
 	if (common->bus_ops->aspm_init)
 		common->bus_ops->aspm_init(common);
@@ -672,18 +676,14 @@
 	{ .max = 2048,	.types = BIT(NL80211_IFTYPE_WDS) },
 };
 
-static const struct ieee80211_iface_limit if_limits_multi[] = {
-	{ .max = 1,	.types = BIT(NL80211_IFTYPE_STATION) },
-	{ .max = 1,	.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
-				 BIT(NL80211_IFTYPE_P2P_GO) },
-};
+#ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
 
-static const struct ieee80211_iface_limit if_dfs_limits[] = {
-	{ .max = 1,	.types = BIT(NL80211_IFTYPE_AP) |
-#ifdef CPTCFG_MAC80211_MESH
-				 BIT(NL80211_IFTYPE_MESH_POINT) |
-#endif
-				 BIT(NL80211_IFTYPE_ADHOC) },
+static const struct ieee80211_iface_limit if_limits_multi[] = {
+	{ .max = 2,	.types = BIT(NL80211_IFTYPE_STATION) |
+				 BIT(NL80211_IFTYPE_AP) |
+				 BIT(NL80211_IFTYPE_P2P_CLIENT) |
+				 BIT(NL80211_IFTYPE_P2P_GO) },
+	{ .max = 1,	.types = BIT(NL80211_IFTYPE_ADHOC) },
 };
 
 static const struct ieee80211_iface_combination if_comb_multi[] = {
@@ -696,6 +696,16 @@
 	},
 };
 
+#endif /* CPTCFG_ATH9K_CHANNEL_CONTEXT */
+
+static const struct ieee80211_iface_limit if_dfs_limits[] = {
+	{ .max = 1,	.types = BIT(NL80211_IFTYPE_AP) |
+#ifdef CPTCFG_MAC80211_MESH
+				 BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
+				 BIT(NL80211_IFTYPE_ADHOC) },
+};
+
 static const struct ieee80211_iface_combination if_comb[] = {
 	{
 		.limits = if_limits,
@@ -753,8 +763,9 @@
 	if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)
 		hw->flags |= IEEE80211_HW_MFP_CAPABLE;
 
-	hw->wiphy->features |= (NL80211_FEATURE_ACTIVE_MONITOR |
-				NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE);
+	hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
+			       NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
+			       NL80211_FEATURE_P2P_GO_CTWIN;
 
 	if (!config_enabled(CPTCFG_ATH9K_TX99)) {
 		hw->wiphy->interface_modes =
@@ -763,24 +774,31 @@
 			BIT(NL80211_IFTYPE_AP) |
 			BIT(NL80211_IFTYPE_STATION) |
 			BIT(NL80211_IFTYPE_ADHOC) |
-			BIT(NL80211_IFTYPE_MESH_POINT);
-		if (!ath9k_use_chanctx) {
+			BIT(NL80211_IFTYPE_MESH_POINT) |
+			BIT(NL80211_IFTYPE_WDS);
+
 			hw->wiphy->iface_combinations = if_comb;
 			hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
-			hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS);
-		} else {
-			hw->wiphy->iface_combinations = if_comb_multi;
-			hw->wiphy->n_iface_combinations =
-				ARRAY_SIZE(if_comb_multi);
-			hw->wiphy->max_scan_ssids = 255;
-			hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
-			hw->wiphy->max_remain_on_channel_duration = 10000;
-			hw->chanctx_data_size = sizeof(void *);
-			hw->extra_beacon_tailroom =
-				sizeof(struct ieee80211_p2p_noa_attr) + 9;
-		}
 	}
 
+#ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
+
+	if (ath9k_is_chanctx_enabled()) {
+		hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS);
+		hw->wiphy->iface_combinations = if_comb_multi;
+		hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi);
+		hw->wiphy->max_scan_ssids = 255;
+		hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+		hw->wiphy->max_remain_on_channel_duration = 10000;
+		hw->chanctx_data_size = sizeof(void *);
+		hw->extra_beacon_tailroom =
+			sizeof(struct ieee80211_p2p_noa_attr) + 9;
+
+		ath_dbg(common, CHAN_CTX, "Use channel contexts\n");
+	}
+
+#endif /* CPTCFG_ATH9K_CHANNEL_CONTEXT */
+
 	hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
@@ -793,7 +811,7 @@
 	/* allow 4 queues per channel context +
 	 * 1 cab queue + 1 offchannel tx queue
 	 */
-	hw->queues = 10;
+	hw->queues = ATH9K_NUM_TX_QUEUES;
 	/* last queue for offchannel */
 	hw->offchannel_tx_hw_queue = hw->queues - 1;
 	hw->max_rates = 4;
@@ -915,9 +933,7 @@
 {
 	int i = 0;
 
-	if (sc->p2p_ps_timer)
-		ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
-
+	ath9k_deinit_p2p(sc);
 	ath9k_deinit_btcoex(sc);
 
 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 6c56caf..aa69cea 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -121,6 +121,7 @@
 	u32 evm0;
 	u32 evm1;
 	u32 evm2;
+	u32 duration;
 };
 
 struct ath_rx_status {
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 105d9ea..c3fde99 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -60,8 +60,10 @@
 
 	spin_lock_bh(&txq->axq_lock);
 
-	if (txq->axq_depth)
+	if (txq->axq_depth) {
 		pending = true;
+		goto out;
+	}
 
 	if (txq->mac80211_qnum >= 0) {
 		struct list_head *list;
@@ -70,6 +72,7 @@
 		if (!list_empty(list))
 			pending = true;
 	}
+out:
 	spin_unlock_bh(&txq->axq_lock);
 	return pending;
 }
@@ -223,18 +226,12 @@
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
 	unsigned long flags;
-	int i;
 
-	if (ath_startrecv(sc) != 0) {
-		ath_err(common, "Unable to restart recv logic\n");
-		return false;
-	}
-
+	ath9k_calculate_summary_state(sc, sc->cur_chan);
+	ath_startrecv(sc);
 	ath9k_cmn_update_txpow(ah, sc->curtxpow,
 			       sc->cur_chan->txpower, &sc->curtxpow);
-
 	clear_bit(ATH_OP_HW_RESET, &common->op_flags);
-	ath9k_calculate_summary_state(sc, sc->cur_chan);
 
 	if (!sc->cur_chan->offchannel && start) {
 		/* restore per chanctx TSF timer */
@@ -267,22 +264,7 @@
 
 	ath9k_hw_set_interrupts(ah);
 	ath9k_hw_enable_interrupts(ah);
-
-	if (!ath9k_use_chanctx)
-		ieee80211_wake_queues(sc->hw);
-	else {
-		if (sc->cur_chan == &sc->offchannel.chan)
-			ieee80211_wake_queue(sc->hw,
-					sc->hw->offchannel_tx_hw_queue);
-		else {
-			for (i = 0; i < IEEE80211_NUM_ACS; i++)
-				ieee80211_wake_queue(sc->hw,
-					sc->cur_chan->hw_queue_base + i);
-		}
-		if (ah->opmode == NL80211_IFTYPE_AP)
-			ieee80211_wake_queue(sc->hw, sc->hw->queues - 2);
-	}
-
+	ieee80211_wake_queues(sc->hw);
 	ath9k_p2p_ps_timer(sc);
 
 	return true;
@@ -314,6 +296,9 @@
 	if (!ath_prepare_reset(sc))
 		fastcc = false;
 
+	if (ath9k_is_chanctx_enabled())
+		fastcc = false;
+
 	spin_lock_bh(&sc->chan_lock);
 	sc->cur_chandef = sc->cur_chan->chandef;
 	spin_unlock_bh(&sc->chan_lock);
@@ -358,12 +343,16 @@
 	memset(&an->key_idx, 0, sizeof(an->key_idx));
 
 	ath_tx_node_init(sc, an);
+
+	ath_dynack_node_init(sc->sc_ah, an);
 }
 
 static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
 {
 	struct ath_node *an = (struct ath_node *)sta->drv_priv;
 	ath_tx_node_cleanup(sc, an);
+
+	ath_dynack_node_deinit(sc->sc_ah, an);
 }
 
 void ath9k_tasklet(unsigned long data)
@@ -822,7 +811,8 @@
 	struct ath_common *common = ath9k_hw_common(ah);
 	bool prev_idle;
 
-	cancel_work_sync(&sc->chanctx_work);
+	ath9k_deinit_channel_context(sc);
+
 	mutex_lock(&sc->mutex);
 
 	ath_cancel_work(sc);
@@ -903,9 +893,10 @@
 	}
 }
 
-static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
+			   u8 *mac, struct ieee80211_vif *vif)
 {
-	struct ath9k_vif_iter_data *iter_data = data;
+	struct ath_vif *avp = (struct ath_vif *)vif->drv_priv;
 	int i;
 
 	if (iter_data->has_hw_macaddr) {
@@ -923,12 +914,10 @@
 	switch (vif->type) {
 	case NL80211_IFTYPE_AP:
 		iter_data->naps++;
-		if (vif->bss_conf.enable_beacon)
-			iter_data->beacons = true;
 		break;
 	case NL80211_IFTYPE_STATION:
 		iter_data->nstations++;
-		if (vif->bss_conf.assoc && !iter_data->primary_sta)
+		if (avp->assoc && !iter_data->primary_sta)
 			iter_data->primary_sta = vif;
 		break;
 	case NL80211_IFTYPE_ADHOC:
@@ -949,6 +938,34 @@
 	}
 }
 
+static void ath9k_update_bssid_mask(struct ath_softc *sc,
+				    struct ath_chanctx *ctx,
+				    struct ath9k_vif_iter_data *iter_data)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath_vif *avp;
+	int i;
+
+	if (!ath9k_is_chanctx_enabled())
+		return;
+
+	list_for_each_entry(avp, &ctx->vifs, list) {
+		if (ctx->nvifs_assigned != 1)
+			continue;
+
+		if (!avp->vif->p2p || !iter_data->has_hw_macaddr)
+			continue;
+
+		ether_addr_copy(common->curbssid, avp->bssid);
+
+		/* perm_addr will be used as the p2p device address. */
+		for (i = 0; i < ETH_ALEN; i++)
+			iter_data->mask[i] &=
+				~(iter_data->hw_macaddr[i] ^
+				  sc->hw->wiphy->perm_addr[i]);
+	}
+}
+
 /* Called with sc->mutex held. */
 void ath9k_calculate_iter_data(struct ath_softc *sc,
 			       struct ath_chanctx *ctx,
@@ -968,38 +985,20 @@
 	list_for_each_entry(avp, &ctx->vifs, list)
 		ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif);
 
-	if (ctx == &sc->offchannel.chan) {
-		struct ieee80211_vif *vif;
-
-		if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START)
-			vif = sc->offchannel.scan_vif;
-		else
-			vif = sc->offchannel.roc_vif;
-
-		if (vif)
-			ath9k_vif_iter(iter_data, vif->addr, vif);
-		iter_data->beacons = false;
-	}
+	ath9k_update_bssid_mask(sc, ctx, iter_data);
 }
 
 static void ath9k_set_assoc_state(struct ath_softc *sc,
 				  struct ieee80211_vif *vif, bool changed)
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+	struct ath_vif *avp = (struct ath_vif *)vif->drv_priv;
 	unsigned long flags;
 
 	set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
-	/* Set the AID, BSSID and do beacon-sync only when
-	 * the HW opmode is STATION.
-	 *
-	 * But the primary bit is set above in any case.
-	 */
-	if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
-		return;
 
-	ether_addr_copy(common->curbssid, bss_conf->bssid);
-	common->curaid = bss_conf->aid;
+	ether_addr_copy(common->curbssid, avp->bssid);
+	common->curaid = avp->aid;
 	ath9k_hw_write_associd(sc->sc_ah);
 
 	if (changed) {
@@ -1019,6 +1018,43 @@
 		vif->addr, common->curbssid);
 }
 
+#ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
+static void ath9k_set_offchannel_state(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ieee80211_vif *vif = NULL;
+
+	ath9k_ps_wakeup(sc);
+
+	if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START)
+		vif = sc->offchannel.scan_vif;
+	else
+		vif = sc->offchannel.roc_vif;
+
+	if (WARN_ON(!vif))
+		goto exit;
+
+	eth_zero_addr(common->curbssid);
+	eth_broadcast_addr(common->bssidmask);
+	ether_addr_copy(common->macaddr, vif->addr);
+	common->curaid = 0;
+	ah->opmode = vif->type;
+	ah->imask &= ~ATH9K_INT_SWBA;
+	ah->imask &= ~ATH9K_INT_TSFOOR;
+	ah->slottime = ATH9K_SLOT_TIME_9;
+
+	ath_hw_setbssidmask(common);
+	ath9k_hw_setopmode(ah);
+	ath9k_hw_write_associd(sc->sc_ah);
+	ath9k_hw_set_interrupts(ah);
+	ath9k_hw_init_global_settings(ah);
+
+exit:
+	ath9k_ps_restore(sc);
+}
+#endif
+
 /* Called with sc->mutex held. */
 void ath9k_calculate_summary_state(struct ath_softc *sc,
 				   struct ath_chanctx *ctx)
@@ -1026,12 +1062,18 @@
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath9k_vif_iter_data iter_data;
+	struct ath_beacon_config *cur_conf;
 
 	ath_chanctx_check_active(sc, ctx);
 
 	if (ctx != sc->cur_chan)
 		return;
 
+#ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
+	if (ctx == &sc->offchannel.chan)
+		return ath9k_set_offchannel_state(sc);
+#endif
+
 	ath9k_ps_wakeup(sc);
 	ath9k_calculate_iter_data(sc, ctx, &iter_data);
 
@@ -1042,8 +1084,11 @@
 	ath_hw_setbssidmask(common);
 
 	if (iter_data.naps > 0) {
+		cur_conf = &ctx->beacon;
 		ath9k_hw_set_tsfadjust(ah, true);
 		ah->opmode = NL80211_IFTYPE_AP;
+		if (cur_conf->enable_beacon)
+			iter_data.beacons = true;
 	} else {
 		ath9k_hw_set_tsfadjust(ah, false);
 
@@ -1072,13 +1117,11 @@
 	if (ah->opmode == NL80211_IFTYPE_STATION) {
 		bool changed = (iter_data.primary_sta != ctx->primary_sta);
 
-		iter_data.beacons = true;
 		if (iter_data.primary_sta) {
+			iter_data.beacons = true;
 			ath9k_set_assoc_state(sc, iter_data.primary_sta,
 					      changed);
-			if (!ctx->primary_sta ||
-			    !ctx->primary_sta->bss_conf.assoc)
-				ctx->primary_sta = iter_data.primary_sta;
+			ctx->primary_sta = iter_data.primary_sta;
 		} else {
 			ctx->primary_sta = NULL;
 			memset(common->curbssid, 0, ETH_ALEN);
@@ -1107,11 +1150,27 @@
 	else
 		clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
 
-	ctx->primary_sta = iter_data.primary_sta;
+	ath_dbg(common, CONFIG,
+		"macaddr: %pM, bssid: %pM, bssidmask: %pM\n",
+		common->macaddr, common->curbssid, common->bssidmask);
 
 	ath9k_ps_restore(sc);
 }
 
+static void ath9k_assign_hw_queues(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif)
+{
+	int i;
+
+	for (i = 0; i < IEEE80211_NUM_ACS; i++)
+		vif->hw_queue[i] = i;
+
+	if (vif->type == NL80211_IFTYPE_AP)
+		vif->cab_queue = hw->queues - 2;
+	else
+		vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+}
+
 static int ath9k_add_interface(struct ieee80211_hw *hw,
 			       struct ieee80211_vif *vif)
 {
@@ -1120,12 +1179,11 @@
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath_vif *avp = (void *)vif->drv_priv;
 	struct ath_node *an = &avp->mcast_node;
-	int i;
 
 	mutex_lock(&sc->mutex);
 
 	if (config_enabled(CPTCFG_ATH9K_TX99)) {
-		if (sc->nvifs >= 1) {
+		if (sc->cur_chan->nvifs >= 1) {
 			mutex_unlock(&sc->mutex);
 			return -EOPNOTSUPP;
 		}
@@ -1133,22 +1191,18 @@
 	}
 
 	ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
-	sc->nvifs++;
+	sc->cur_chan->nvifs++;
 
 	if (ath9k_uses_beacons(vif->type))
 		ath9k_beacon_assign_slot(sc, vif);
 
 	avp->vif = vif;
-	if (!ath9k_use_chanctx) {
+	if (!ath9k_is_chanctx_enabled()) {
 		avp->chanctx = sc->cur_chan;
 		list_add_tail(&avp->list, &avp->chanctx->vifs);
 	}
-	for (i = 0; i < IEEE80211_NUM_ACS; i++)
-		vif->hw_queue[i] = i;
-	if (vif->type == NL80211_IFTYPE_AP)
-		vif->cab_queue = hw->queues - 2;
-	else
-		vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+
+	ath9k_assign_hw_queues(hw, vif);
 
 	an->sc = sc;
 	an->sta = NULL;
@@ -1168,7 +1222,6 @@
 	struct ath_softc *sc = hw->priv;
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_vif *avp = (void *)vif->drv_priv;
-	int i;
 
 	mutex_lock(&sc->mutex);
 
@@ -1188,43 +1241,13 @@
 	if (ath9k_uses_beacons(vif->type))
 		ath9k_beacon_assign_slot(sc, vif);
 
-	for (i = 0; i < IEEE80211_NUM_ACS; i++)
-		vif->hw_queue[i] = i;
-
-	if (vif->type == NL80211_IFTYPE_AP)
-		vif->cab_queue = hw->queues - 2;
-	else
-		vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
-
+	ath9k_assign_hw_queues(hw, vif);
 	ath9k_calculate_summary_state(sc, avp->chanctx);
 
 	mutex_unlock(&sc->mutex);
 	return 0;
 }
 
-static void
-ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
-{
-	struct ath_hw *ah = sc->sc_ah;
-	s32 tsf, target_tsf;
-
-	if (!avp || !avp->noa.has_next_tsf)
-		return;
-
-	ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
-
-	tsf = ath9k_hw_gettsf32(sc->sc_ah);
-
-	target_tsf = avp->noa.next_tsf;
-	if (!avp->noa.absent)
-		target_tsf -= ATH_P2P_PS_STOP_TIME;
-
-	if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
-		target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
-
-	ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
-}
-
 static void ath9k_remove_interface(struct ieee80211_hw *hw,
 				   struct ieee80211_vif *vif)
 {
@@ -1236,16 +1259,11 @@
 
 	mutex_lock(&sc->mutex);
 
-	spin_lock_bh(&sc->sc_pcu_lock);
-	if (avp == sc->p2p_ps_vif) {
-		sc->p2p_ps_vif = NULL;
-		ath9k_update_p2p_ps_timer(sc, NULL);
-	}
-	spin_unlock_bh(&sc->sc_pcu_lock);
+	ath9k_p2p_remove_vif(sc, vif);
 
-	sc->nvifs--;
+	sc->cur_chan->nvifs--;
 	sc->tx99_vif = NULL;
-	if (!ath9k_use_chanctx)
+	if (!ath9k_is_chanctx_enabled())
 		list_del(&avp->list);
 
 	if (ath9k_uses_beacons(vif->type))
@@ -1423,7 +1441,7 @@
 		}
 	}
 
-	if (!ath9k_use_chanctx && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
+	if (!ath9k_is_chanctx_enabled() && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
 		ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL);
 		ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef);
 	}
@@ -1463,7 +1481,10 @@
 	changed_flags &= SUPPORTED_FILTERS;
 	*total_flags &= SUPPORTED_FILTERS;
 
-	sc->rx.rxfilter = *total_flags;
+	spin_lock_bh(&sc->chan_lock);
+	sc->cur_chan->rxfilter = *total_flags;
+	spin_unlock_bh(&sc->chan_lock);
+
 	ath9k_ps_wakeup(sc);
 	rfilt = ath_calcrxfilter(sc);
 	ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
@@ -1687,70 +1708,6 @@
 	return ret;
 }
 
-void ath9k_p2p_ps_timer(void *priv)
-{
-	struct ath_softc *sc = priv;
-	struct ath_vif *avp = sc->p2p_ps_vif;
-	struct ieee80211_vif *vif;
-	struct ieee80211_sta *sta;
-	struct ath_node *an;
-	u32 tsf;
-
-	del_timer_sync(&sc->sched.timer);
-	ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer);
-	ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
-
-	if (!avp || avp->chanctx != sc->cur_chan)
-		return;
-
-	tsf = ath9k_hw_gettsf32(sc->sc_ah);
-	if (!avp->noa.absent)
-		tsf += ATH_P2P_PS_STOP_TIME;
-
-	if (!avp->noa.has_next_tsf ||
-	    avp->noa.next_tsf - tsf > BIT(31))
-		ieee80211_update_p2p_noa(&avp->noa, tsf);
-
-	ath9k_update_p2p_ps_timer(sc, avp);
-
-	rcu_read_lock();
-
-	vif = avp->vif;
-	sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
-	if (!sta)
-		goto out;
-
-	an = (void *) sta->drv_priv;
-	if (an->sleeping == !!avp->noa.absent)
-		goto out;
-
-	an->sleeping = avp->noa.absent;
-	if (an->sleeping)
-		ath_tx_aggr_sleep(sta, sc, an);
-	else
-		ath_tx_aggr_wakeup(sc, an);
-
-out:
-	rcu_read_unlock();
-}
-
-void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
-{
-	struct ath_vif *avp = (void *)vif->drv_priv;
-	u32 tsf;
-
-	if (!sc->p2p_ps_timer)
-		return;
-
-	if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
-		return;
-
-	sc->p2p_ps_vif = avp;
-	tsf = ath9k_hw_gettsf32(sc->sc_ah);
-	ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
-	ath9k_update_p2p_ps_timer(sc, avp);
-}
-
 static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
 				   struct ieee80211_vif *vif,
 				   struct ieee80211_bss_conf *bss_conf,
@@ -1765,7 +1722,6 @@
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath_vif *avp = (void *)vif->drv_priv;
-	unsigned long flags;
 	int slottime;
 
 	ath9k_ps_wakeup(sc);
@@ -1775,9 +1731,17 @@
 		ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n",
 			bss_conf->bssid, bss_conf->assoc);
 
+		ether_addr_copy(avp->bssid, bss_conf->bssid);
+		avp->aid = bss_conf->aid;
+		avp->assoc = bss_conf->assoc;
+
 		ath9k_calculate_summary_state(sc, avp->chanctx);
-		if (bss_conf->assoc)
-			ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_ASSOC);
+
+		if (ath9k_is_chanctx_enabled()) {
+			if (bss_conf->assoc)
+				ath_chanctx_event(sc, vif,
+						  ATH_CHANCTX_EVENT_ASSOC);
+		}
 	}
 
 	if (changed & BSS_CHANGED_IBSS) {
@@ -1789,9 +1753,9 @@
 	if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
 	    (changed & BSS_CHANGED_BEACON_INT) ||
 	    (changed & BSS_CHANGED_BEACON_INFO)) {
+		ath9k_beacon_config(sc, vif, changed);
 		if (changed & BSS_CHANGED_BEACON_ENABLED)
 			ath9k_calculate_summary_state(sc, avp->chanctx);
-		ath9k_beacon_config(sc, vif, changed);
 	}
 
 	if ((avp->chanctx == sc->cur_chan) &&
@@ -1814,14 +1778,8 @@
 		}
 	}
 
-	if (changed & BSS_CHANGED_P2P_PS) {
-		spin_lock_bh(&sc->sc_pcu_lock);
-		spin_lock_irqsave(&sc->sc_pm_lock, flags);
-		if (!(sc->ps_flags & PS_BEACON_SYNC))
-			ath9k_update_p2p_ps(sc, vif);
-		spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
-		spin_unlock_bh(&sc->sc_pcu_lock);
-	}
+	if (changed & BSS_CHANGED_P2P_PS)
+		ath9k_p2p_bss_info_changed(sc, vif);
 
 	if (changed & CHECK_ANI)
 		ath_check_ani(sc);
@@ -1959,7 +1917,22 @@
 	return 0;
 }
 
-static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
+static void ath9k_enable_dynack(struct ath_softc *sc)
+{
+#ifdef CPTCFG_ATH9K_DYNACK
+	u32 rfilt;
+	struct ath_hw *ah = sc->sc_ah;
+
+	ath_dynack_reset(ah);
+
+	ah->dynack.enabled = true;
+	rfilt = ath_calcrxfilter(sc);
+	ath9k_hw_setrxfilter(ah, rfilt);
+#endif
+}
+
+static void ath9k_set_coverage_class(struct ieee80211_hw *hw,
+				     s16 coverage_class)
 {
 	struct ath_softc *sc = hw->priv;
 	struct ath_hw *ah = sc->sc_ah;
@@ -1968,11 +1941,22 @@
 		return;
 
 	mutex_lock(&sc->mutex);
-	ah->coverage_class = coverage_class;
 
-	ath9k_ps_wakeup(sc);
-	ath9k_hw_init_global_settings(ah);
-	ath9k_ps_restore(sc);
+	if (coverage_class >= 0) {
+		ah->coverage_class = coverage_class;
+		if (ah->dynack.enabled) {
+			u32 rfilt;
+
+			ah->dynack.enabled = false;
+			rfilt = ath_calcrxfilter(sc);
+			ath9k_hw_setrxfilter(ah, rfilt);
+		}
+		ath9k_ps_wakeup(sc);
+		ath9k_hw_init_global_settings(ah);
+		ath9k_ps_restore(sc);
+	} else if (!ah->dynack.enabled) {
+		ath9k_enable_dynack(sc);
+	}
 
 	mutex_unlock(&sc->mutex);
 }
@@ -1985,9 +1969,6 @@
 		if (!ATH_TXQ_SETUP(sc, i))
 			continue;
 
-		if (!sc->tx.txq[i].axq_depth)
-			continue;
-
 		npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
 		if (npend)
 			break;
@@ -2013,7 +1994,6 @@
 	struct ath_common *common = ath9k_hw_common(ah);
 	int timeout = HZ / 5; /* 200 ms */
 	bool drain_txq;
-	int i;
 
 	cancel_delayed_work_sync(&sc->tx_complete_work);
 
@@ -2041,10 +2021,6 @@
 			ath_reset(sc);
 
 		ath9k_ps_restore(sc);
-		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
-			ieee80211_wake_queue(sc->hw,
-					     sc->cur_chan->hw_queue_base + i);
-		}
 	}
 
 	ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
@@ -2053,16 +2029,8 @@
 static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
 {
 	struct ath_softc *sc = hw->priv;
-	int i;
 
-	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-		if (!ATH_TXQ_SETUP(sc, i))
-			continue;
-
-		if (ath9k_has_pending_frames(sc, &sc->tx.txq[i]))
-			return true;
-	}
-	return false;
+	return ath9k_has_tx_pending(sc);
 }
 
 static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
@@ -2207,207 +2175,7 @@
 	clear_bit(ATH_OP_SCANNING, &common->op_flags);
 }
 
-static int ath_scan_channel_duration(struct ath_softc *sc,
-				     struct ieee80211_channel *chan)
-{
-	struct cfg80211_scan_request *req = sc->offchannel.scan_req;
-
-	if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR))
-		return (HZ / 9); /* ~110 ms */
-
-	return (HZ / 16); /* ~60 ms */
-}
-
-static void
-ath_scan_next_channel(struct ath_softc *sc)
-{
-	struct cfg80211_scan_request *req = sc->offchannel.scan_req;
-	struct ieee80211_channel *chan;
-
-	if (sc->offchannel.scan_idx >= req->n_channels) {
-		sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
-		ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
-				   NULL);
-		return;
-	}
-
-	chan = req->channels[sc->offchannel.scan_idx++];
-	sc->offchannel.duration = ath_scan_channel_duration(sc, chan);
-	sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND;
-	ath_chanctx_offchan_switch(sc, chan);
-}
-
-static void ath_offchannel_next(struct ath_softc *sc)
-{
-	struct ieee80211_vif *vif;
-
-	if (sc->offchannel.scan_req) {
-		vif = sc->offchannel.scan_vif;
-		sc->offchannel.chan.txpower = vif->bss_conf.txpower;
-		ath_scan_next_channel(sc);
-	} else if (sc->offchannel.roc_vif) {
-		vif = sc->offchannel.roc_vif;
-		sc->offchannel.chan.txpower = vif->bss_conf.txpower;
-		sc->offchannel.duration = sc->offchannel.roc_duration;
-		sc->offchannel.state = ATH_OFFCHANNEL_ROC_START;
-		ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan);
-	} else {
-		ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
-				   NULL);
-		sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
-		if (sc->ps_idle)
-			ath_cancel_work(sc);
-	}
-}
-
-static void ath_roc_complete(struct ath_softc *sc, bool abort)
-{
-	sc->offchannel.roc_vif = NULL;
-	sc->offchannel.roc_chan = NULL;
-	if (!abort)
-		ieee80211_remain_on_channel_expired(sc->hw);
-	ath_offchannel_next(sc);
-	ath9k_ps_restore(sc);
-}
-
-static void ath_scan_complete(struct ath_softc *sc, bool abort)
-{
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
-	sc->offchannel.scan_req = NULL;
-	sc->offchannel.scan_vif = NULL;
-	sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
-	ieee80211_scan_completed(sc->hw, abort);
-	clear_bit(ATH_OP_SCANNING, &common->op_flags);
-	ath_offchannel_next(sc);
-	ath9k_ps_restore(sc);
-}
-
-static void ath_scan_send_probe(struct ath_softc *sc,
-				struct cfg80211_ssid *ssid)
-{
-	struct cfg80211_scan_request *req = sc->offchannel.scan_req;
-	struct ieee80211_vif *vif = sc->offchannel.scan_vif;
-	struct ath_tx_control txctl = {};
-	struct sk_buff *skb;
-	struct ieee80211_tx_info *info;
-	int band = sc->offchannel.chan.chandef.chan->band;
-
-	skb = ieee80211_probereq_get(sc->hw, vif,
-			ssid->ssid, ssid->ssid_len, req->ie_len);
-	if (!skb)
-		return;
-
-	info = IEEE80211_SKB_CB(skb);
-	if (req->no_cck)
-		info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
-
-	if (req->ie_len)
-		memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
-
-	skb_set_queue_mapping(skb, IEEE80211_AC_VO);
-
-	if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
-		goto error;
-
-	txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
-	txctl.force_channel = true;
-	if (ath_tx_start(sc->hw, skb, &txctl))
-		goto error;
-
-	return;
-
-error:
-	ieee80211_free_txskb(sc->hw, skb);
-}
-
-static void ath_scan_channel_start(struct ath_softc *sc)
-{
-	struct cfg80211_scan_request *req = sc->offchannel.scan_req;
-	int i;
-
-	if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) &&
-	    req->n_ssids) {
-		for (i = 0; i < req->n_ssids; i++)
-			ath_scan_send_probe(sc, &req->ssids[i]);
-
-	}
-
-	sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT;
-	mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration);
-}
-
-void ath_offchannel_channel_change(struct ath_softc *sc)
-{
-	switch (sc->offchannel.state) {
-	case ATH_OFFCHANNEL_PROBE_SEND:
-		if (!sc->offchannel.scan_req)
-			return;
-
-		if (sc->cur_chan->chandef.chan !=
-		    sc->offchannel.chan.chandef.chan)
-			return;
-
-		ath_scan_channel_start(sc);
-		break;
-	case ATH_OFFCHANNEL_IDLE:
-		if (!sc->offchannel.scan_req)
-			return;
-
-		ath_scan_complete(sc, false);
-		break;
-	case ATH_OFFCHANNEL_ROC_START:
-		if (sc->cur_chan != &sc->offchannel.chan)
-			break;
-
-		sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT;
-		mod_timer(&sc->offchannel.timer, jiffies +
-			  msecs_to_jiffies(sc->offchannel.duration));
-		ieee80211_ready_on_channel(sc->hw);
-		break;
-	case ATH_OFFCHANNEL_ROC_DONE:
-		ath_roc_complete(sc, false);
-		break;
-	default:
-		break;
-	}
-}
-
-void ath_offchannel_timer(unsigned long data)
-{
-	struct ath_softc *sc = (struct ath_softc *)data;
-	struct ath_chanctx *ctx;
-
-	switch (sc->offchannel.state) {
-	case ATH_OFFCHANNEL_PROBE_WAIT:
-		if (!sc->offchannel.scan_req)
-			return;
-
-		/* get first active channel context */
-		ctx = ath_chanctx_get_oper_chan(sc, true);
-		if (ctx->active) {
-			sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND;
-			ath_chanctx_switch(sc, ctx, NULL);
-			mod_timer(&sc->offchannel.timer, jiffies + HZ / 10);
-			break;
-		}
-		/* fall through */
-	case ATH_OFFCHANNEL_SUSPEND:
-		if (!sc->offchannel.scan_req)
-			return;
-
-		ath_scan_next_channel(sc);
-		break;
-	case ATH_OFFCHANNEL_ROC_START:
-	case ATH_OFFCHANNEL_ROC_WAIT:
-		ctx = ath_chanctx_get_oper_chan(sc, false);
-		sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
-		ath_chanctx_switch(sc, ctx, NULL);
-		break;
-	default:
-		break;
-	}
-}
+#ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
 
 static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			 struct ieee80211_scan_request *hw_req)
@@ -2430,8 +2198,13 @@
 	sc->offchannel.scan_req = req;
 	sc->offchannel.scan_idx = 0;
 
-	if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE)
+	ath_dbg(common, CHAN_CTX, "HW scan request received on vif: %pM\n",
+		vif->addr);
+
+	if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) {
+		ath_dbg(common, CHAN_CTX, "Starting HW scan\n");
 		ath_offchannel_next(sc);
+	}
 
 out:
 	mutex_unlock(&sc->mutex);
@@ -2443,6 +2216,9 @@
 				 struct ieee80211_vif *vif)
 {
 	struct ath_softc *sc = hw->priv;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	ath_dbg(common, CHAN_CTX, "Cancel HW scan on vif: %pM\n", vif->addr);
 
 	mutex_lock(&sc->mutex);
 	del_timer_sync(&sc->offchannel.timer);
@@ -2456,6 +2232,7 @@
 				   enum ieee80211_roc_type type)
 {
 	struct ath_softc *sc = hw->priv;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	int ret = 0;
 
 	mutex_lock(&sc->mutex);
@@ -2470,8 +2247,14 @@
 	sc->offchannel.roc_chan = chan;
 	sc->offchannel.roc_duration = duration;
 
-	if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE)
+	ath_dbg(common, CHAN_CTX,
+		"RoC request on vif: %pM, type: %d duration: %d\n",
+		vif->addr, type, duration);
+
+	if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) {
+		ath_dbg(common, CHAN_CTX, "Starting RoC period\n");
 		ath_offchannel_next(sc);
+	}
 
 out:
 	mutex_unlock(&sc->mutex);
@@ -2482,9 +2265,11 @@
 static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw)
 {
 	struct ath_softc *sc = hw->priv;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
 	mutex_lock(&sc->mutex);
 
+	ath_dbg(common, CHAN_CTX, "Cancel RoC\n");
 	del_timer_sync(&sc->offchannel.timer);
 
 	if (sc->offchannel.roc_vif) {
@@ -2501,6 +2286,7 @@
 			     struct ieee80211_chanctx_conf *conf)
 {
 	struct ath_softc *sc = hw->priv;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_chanctx *ctx, **ptr;
 	int pos;
 
@@ -2515,10 +2301,18 @@
 		ctx->assigned = true;
 		pos = ctx - &sc->chanctx[0];
 		ctx->hw_queue_base = pos * IEEE80211_NUM_ACS;
+
+		ath_dbg(common, CHAN_CTX,
+			"Add channel context: %d MHz\n",
+			conf->def.chan->center_freq);
+
 		ath_chanctx_set_channel(sc, ctx, &conf->def);
+		ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ASSIGN);
+
 		mutex_unlock(&sc->mutex);
 		return 0;
 	}
+
 	mutex_unlock(&sc->mutex);
 	return -ENOSPC;
 }
@@ -2528,12 +2322,19 @@
 				 struct ieee80211_chanctx_conf *conf)
 {
 	struct ath_softc *sc = hw->priv;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_chanctx *ctx = ath_chanctx_get(conf);
 
 	mutex_lock(&sc->mutex);
+
+	ath_dbg(common, CHAN_CTX,
+		"Remove channel context: %d MHz\n",
+		conf->def.chan->center_freq);
+
 	ctx->assigned = false;
-	ctx->hw_queue_base = -1;
+	ctx->hw_queue_base = 0;
 	ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN);
+
 	mutex_unlock(&sc->mutex);
 }
 
@@ -2542,9 +2343,13 @@
 				 u32 changed)
 {
 	struct ath_softc *sc = hw->priv;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_chanctx *ctx = ath_chanctx_get(conf);
 
 	mutex_lock(&sc->mutex);
+	ath_dbg(common, CHAN_CTX,
+		"Change channel context: %d MHz\n",
+		conf->def.chan->center_freq);
 	ath_chanctx_set_channel(sc, ctx, &conf->def);
 	mutex_unlock(&sc->mutex);
 }
@@ -2554,16 +2359,25 @@
 				    struct ieee80211_chanctx_conf *conf)
 {
 	struct ath_softc *sc = hw->priv;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_vif *avp = (void *)vif->drv_priv;
 	struct ath_chanctx *ctx = ath_chanctx_get(conf);
 	int i;
 
 	mutex_lock(&sc->mutex);
+
+	ath_dbg(common, CHAN_CTX,
+		"Assign VIF (addr: %pM, type: %d, p2p: %d) to channel context: %d MHz\n",
+		vif->addr, vif->type, vif->p2p,
+		conf->def.chan->center_freq);
+
 	avp->chanctx = ctx;
+	ctx->nvifs_assigned++;
 	list_add_tail(&avp->list, &ctx->vifs);
 	ath9k_calculate_summary_state(sc, ctx);
 	for (i = 0; i < IEEE80211_NUM_ACS; i++)
 		vif->hw_queue[i] = ctx->hw_queue_base + i;
+
 	mutex_unlock(&sc->mutex);
 
 	return 0;
@@ -2574,36 +2388,80 @@
 				       struct ieee80211_chanctx_conf *conf)
 {
 	struct ath_softc *sc = hw->priv;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_vif *avp = (void *)vif->drv_priv;
 	struct ath_chanctx *ctx = ath_chanctx_get(conf);
 	int ac;
 
 	mutex_lock(&sc->mutex);
+
+	ath_dbg(common, CHAN_CTX,
+		"Remove VIF (addr: %pM, type: %d, p2p: %d) from channel context: %d MHz\n",
+		vif->addr, vif->type, vif->p2p,
+		conf->def.chan->center_freq);
+
 	avp->chanctx = NULL;
+	ctx->nvifs_assigned--;
 	list_del(&avp->list);
 	ath9k_calculate_summary_state(sc, ctx);
 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
 		vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE;
+
+	mutex_unlock(&sc->mutex);
+}
+
+static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
+				 struct ieee80211_vif *vif)
+{
+	struct ath_softc *sc = hw->priv;
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
+	bool changed = false;
+
+	if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+		return;
+
+	if (!avp->chanctx)
+		return;
+
+	mutex_lock(&sc->mutex);
+
+	spin_lock_bh(&sc->chan_lock);
+	if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
+		sc->next_chan = avp->chanctx;
+		changed = true;
+	}
+	ath_dbg(common, CHAN_CTX,
+		"%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n",
+		__func__, changed);
+	sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
+	spin_unlock_bh(&sc->chan_lock);
+
+	if (changed)
+		ath_chanctx_set_next(sc, true);
+
 	mutex_unlock(&sc->mutex);
 }
 
 void ath9k_fill_chanctx_ops(void)
 {
-	if (!ath9k_use_chanctx)
+	if (!ath9k_is_chanctx_enabled())
 		return;
 
-	ath9k_ops.hw_scan = ath9k_hw_scan;
-	ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan;
-	ath9k_ops.remain_on_channel  = ath9k_remain_on_channel;
+	ath9k_ops.hw_scan                  = ath9k_hw_scan;
+	ath9k_ops.cancel_hw_scan           = ath9k_cancel_hw_scan;
+	ath9k_ops.remain_on_channel        = ath9k_remain_on_channel;
 	ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel;
-	ath9k_ops.add_chanctx        = ath9k_add_chanctx;
-	ath9k_ops.remove_chanctx     = ath9k_remove_chanctx;
-	ath9k_ops.change_chanctx     = ath9k_change_chanctx;
-	ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx;
-	ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx;
-	ath9k_ops.mgd_prepare_tx = ath9k_chanctx_force_active;
+	ath9k_ops.add_chanctx              = ath9k_add_chanctx;
+	ath9k_ops.remove_chanctx           = ath9k_remove_chanctx;
+	ath9k_ops.change_chanctx           = ath9k_change_chanctx;
+	ath9k_ops.assign_vif_chanctx       = ath9k_assign_vif_chanctx;
+	ath9k_ops.unassign_vif_chanctx     = ath9k_unassign_vif_chanctx;
+	ath9k_ops.mgd_prepare_tx           = ath9k_mgd_prepare_tx;
 }
 
+#endif
+
 struct ieee80211_ops ath9k_ops = {
 	.tx 		    = ath9k_tx,
 	.start 		    = ath9k_start,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index cae6018..b231f21 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -387,7 +387,9 @@
 	if (sc->hw->conf.radar_enabled)
 		rfilt |= ATH9K_RX_FILTER_PHYRADAR | ATH9K_RX_FILTER_PHYERR;
 
-	if (sc->rx.rxfilter & FIF_PROBE_REQ)
+	spin_lock_bh(&sc->chan_lock);
+
+	if (sc->cur_chan->rxfilter & FIF_PROBE_REQ)
 		rfilt |= ATH9K_RX_FILTER_PROBEREQ;
 
 	/*
@@ -398,24 +400,25 @@
 	if (sc->sc_ah->is_monitoring)
 		rfilt |= ATH9K_RX_FILTER_PROM;
 
-	if (sc->rx.rxfilter & FIF_CONTROL)
+	if ((sc->cur_chan->rxfilter & FIF_CONTROL) ||
+	    sc->sc_ah->dynack.enabled)
 		rfilt |= ATH9K_RX_FILTER_CONTROL;
 
 	if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
-	    (sc->nvifs <= 1) &&
-	    !(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC))
+	    (sc->cur_chan->nvifs <= 1) &&
+	    !(sc->cur_chan->rxfilter & FIF_BCN_PRBRESP_PROMISC))
 		rfilt |= ATH9K_RX_FILTER_MYBEACON;
 	else
 		rfilt |= ATH9K_RX_FILTER_BEACON;
 
 	if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
-	    (sc->rx.rxfilter & FIF_PSPOLL))
+	    (sc->cur_chan->rxfilter & FIF_PSPOLL))
 		rfilt |= ATH9K_RX_FILTER_PSPOLL;
 
-	if (conf_is_ht(&sc->hw->conf))
+	if (sc->cur_chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
 		rfilt |= ATH9K_RX_FILTER_COMP_BAR;
 
-	if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
+	if (sc->cur_chan->nvifs > 1 || (sc->cur_chan->rxfilter & FIF_OTHER_BSS)) {
 		/* This is needed for older chips */
 		if (sc->sc_ah->hw_version.macVersion <= AR_SREV_VERSION_9160)
 			rfilt |= ATH9K_RX_FILTER_PROM;
@@ -425,22 +428,24 @@
 	if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah))
 		rfilt |= ATH9K_RX_FILTER_4ADDRESS;
 
-	if (ath9k_use_chanctx &&
+	if (ath9k_is_chanctx_enabled() &&
 	    test_bit(ATH_OP_SCANNING, &common->op_flags))
 		rfilt |= ATH9K_RX_FILTER_BEACON;
 
+	spin_unlock_bh(&sc->chan_lock);
+
 	return rfilt;
 
 }
 
-int ath_startrecv(struct ath_softc *sc)
+void ath_startrecv(struct ath_softc *sc)
 {
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_rxbuf *bf, *tbf;
 
 	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
 		ath_edma_start_recv(sc);
-		return 0;
+		return;
 	}
 
 	if (list_empty(&sc->rx.rxbuf))
@@ -463,8 +468,6 @@
 start_recv:
 	ath_opmode_init(sc);
 	ath9k_hw_startpcureceive(ah, sc->cur_chan->offchannel);
-
-	return 0;
 }
 
 static void ath_flushrecv(struct ath_softc *sc)
@@ -535,6 +538,7 @@
 static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	bool skip_beacon = false;
 
 	if (skb->len < 24 + 8 + 2 + 2)
 		return;
@@ -545,10 +549,19 @@
 		sc->ps_flags &= ~PS_BEACON_SYNC;
 		ath_dbg(common, PS,
 			"Reconfigure beacon timers based on synchronized timestamp\n");
-		if (!(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0)))
+
+#ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
+		if (ath9k_is_chanctx_enabled()) {
+			if (sc->cur_chan == &sc->offchannel.chan)
+				skip_beacon = true;
+		}
+#endif
+
+		if (!skip_beacon &&
+		    !(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0)))
 			ath9k_set_beacon(sc);
-		if (sc->p2p_ps_vif)
-			ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
+
+		ath9k_p2p_beacon_sync(sc);
 	}
 
 	if (ath_beacon_dtim_pending_cab(skb)) {
@@ -867,8 +880,13 @@
 	 * everything but the rate is checked here, the rate check is done
 	 * separately to avoid doing two lookups for a rate for each frame.
 	 */
-	if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, sc->rx.rxfilter))
+	spin_lock_bh(&sc->chan_lock);
+	if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error,
+				 sc->cur_chan->rxfilter)) {
+		spin_unlock_bh(&sc->chan_lock);
 		return -EINVAL;
+	}
+	spin_unlock_bh(&sc->chan_lock);
 
 	if (ath_is_mybeacon(common, hdr)) {
 		RX_STAT_INC(rx_beacons);
@@ -892,9 +910,10 @@
 		return -EINVAL;
 	}
 
-	if (rx_stats->is_mybeacon) {
-		sc->sched.next_tbtt = rx_stats->rs_tstamp;
-		ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_BEACON_RECEIVED);
+	if (ath9k_is_chanctx_enabled()) {
+		if (rx_stats->is_mybeacon)
+			ath_chanctx_beacon_recv_ev(sc,
+					   ATH_CHANCTX_EVENT_BEACON_RECEIVED);
 	}
 
 	ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status);
@@ -991,6 +1010,7 @@
 	unsigned long flags;
 	dma_addr_t new_buf_addr;
 	unsigned int budget = 512;
+	struct ieee80211_hdr *hdr;
 
 	if (edma)
 		dma_type = DMA_BIDIRECTIONAL;
@@ -1120,6 +1140,10 @@
 		ath9k_apply_ampdu_details(sc, &rs, rxs);
 		ath_debug_rate_stats(sc, &rs, skb);
 
+		hdr = (struct ieee80211_hdr *)skb->data;
+		if (ieee80211_is_ack(hdr->frame_control))
+			ath_dynack_sample_ack_ts(sc->sc_ah, skb, rs.rs_tstamp);
+
 		ieee80211_rx(hw, skb);
 
 requeue_drop_frag:
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index a149970..2a938f4 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -903,6 +903,10 @@
 #define AR_SREV_9340(_ah) \
 	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340))
 
+#define AR_SREV_9340_13(_ah) \
+	(AR_SREV_9340((_ah)) && \
+	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9340_13))
+
 #define AR_SREV_9340_13_OR_LATER(_ah) \
 	(AR_SREV_9340((_ah)) && \
 	 ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9340_13))
@@ -1240,12 +1244,23 @@
 #define AR_CH0_DPLL3_PHASE_SHIFT_S   23
 #define AR_PHY_CCA_NOM_VAL_2GHZ      -118
 
+#define AR_RTC_9300_SOC_PLL_DIV_INT          0x0000003f
+#define AR_RTC_9300_SOC_PLL_DIV_INT_S        0
+#define AR_RTC_9300_SOC_PLL_DIV_FRAC         0x000fffc0
+#define AR_RTC_9300_SOC_PLL_DIV_FRAC_S       6
+#define AR_RTC_9300_SOC_PLL_REFDIV           0x01f00000
+#define AR_RTC_9300_SOC_PLL_REFDIV_S         20
+#define AR_RTC_9300_SOC_PLL_CLKSEL           0x06000000
+#define AR_RTC_9300_SOC_PLL_CLKSEL_S         25
+#define AR_RTC_9300_SOC_PLL_BYPASS           0x08000000
+
 #define AR_RTC_9300_PLL_DIV          0x000003ff
 #define AR_RTC_9300_PLL_DIV_S        0
 #define AR_RTC_9300_PLL_REFDIV       0x00003C00
 #define AR_RTC_9300_PLL_REFDIV_S     10
 #define AR_RTC_9300_PLL_CLKSEL       0x0000C000
 #define AR_RTC_9300_PLL_CLKSEL_S     14
+#define AR_RTC_9300_PLL_BYPASS       0x00010000
 
 #define AR_RTC_9160_PLL_DIV	0x000003ff
 #define AR_RTC_9160_PLL_DIV_S   0
diff --git a/drivers/net/wireless/ath/ath9k/spectral.h b/drivers/net/wireless/ath/ath9k/spectral.h
index 137e2e6..0b9465e 100644
--- a/drivers/net/wireless/ath/ath9k/spectral.h
+++ b/drivers/net/wireless/ath/ath9k/spectral.h
@@ -17,6 +17,8 @@
 #ifndef SPECTRAL_H
 #define SPECTRAL_H
 
+#include "../spectral_common.h"
+
 /* enum spectral_mode:
  *
  * @SPECTRAL_DISABLED: spectral mode is disabled
@@ -54,8 +56,6 @@
 	u8 max_exp;
 } __packed;
 
-#define SPECTRAL_HT20_NUM_BINS		56
-
 /* WARNING: don't actually use this struct! MAC may vary the amount of
  * data by -1/+2. This struct is for reference only.
  */
@@ -83,8 +83,6 @@
 	u8 max_exp;
 } __packed;
 
-#define SPECTRAL_HT20_40_NUM_BINS		128
-
 /* WARNING: don't actually use this struct! MAC may vary the amount of
  * data. This struct is for reference only.
  */
@@ -125,71 +123,6 @@
 	return bins[0] & 0x3f;
 }
 
-/* FFT sample format given to userspace via debugfs.
- *
- * Please keep the type/length at the front position and change
- * other fields after adding another sample type
- *
- * TODO: this might need rework when switching to nl80211-based
- * interface.
- */
-enum ath_fft_sample_type {
-	ATH_FFT_SAMPLE_HT20 = 1,
-	ATH_FFT_SAMPLE_HT20_40,
-};
-
-struct fft_sample_tlv {
-	u8 type;	/* see ath_fft_sample */
-	__be16 length;
-	/* type dependent data follows */
-} __packed;
-
-struct fft_sample_ht20 {
-	struct fft_sample_tlv tlv;
-
-	u8 max_exp;
-
-	__be16 freq;
-	s8 rssi;
-	s8 noise;
-
-	__be16 max_magnitude;
-	u8 max_index;
-	u8 bitmap_weight;
-
-	__be64 tsf;
-
-	u8 data[SPECTRAL_HT20_NUM_BINS];
-} __packed;
-
-struct fft_sample_ht20_40 {
-	struct fft_sample_tlv tlv;
-
-	u8 channel_type;
-	__be16 freq;
-
-	s8 lower_rssi;
-	s8 upper_rssi;
-
-	__be64 tsf;
-
-	s8 lower_noise;
-	s8 upper_noise;
-
-	__be16 lower_max_magnitude;
-	__be16 upper_max_magnitude;
-
-	u8 lower_max_index;
-	u8 upper_max_index;
-
-	u8 lower_bitmap_weight;
-	u8 upper_bitmap_weight;
-
-	u8 max_exp;
-
-	u8 data[SPECTRAL_HT20_40_NUM_BINS];
-} __packed;
-
 void ath9k_spectral_init_debug(struct ath_softc *sc);
 void ath9k_spectral_deinit_debug(struct ath_softc *sc);
 
diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c
index 2397292..40ab65e 100644
--- a/drivers/net/wireless/ath/ath9k/tx99.c
+++ b/drivers/net/wireless/ath/ath9k/tx99.c
@@ -54,6 +54,12 @@
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_tx_info *tx_info;
 	struct sk_buff *skb;
+	struct ath_vif *avp;
+
+	if (!sc->tx99_vif)
+		return NULL;
+
+	avp = (struct ath_vif *)sc->tx99_vif->drv_priv;
 
 	skb = alloc_skb(len, GFP_KERNEL);
 	if (!skb)
@@ -71,7 +77,7 @@
 	memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
 	memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
 
-	hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
+	hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
 
 	tx_info = IEEE80211_SKB_CB(skb);
 	memset(tx_info, 0, sizeof(*tx_info));
@@ -174,7 +180,7 @@
 	ssize_t len;
 	int r;
 
-	if (sc->nvifs > 1)
+	if (sc->cur_chan->nvifs > 1)
 		return -EOPNOTSUPP;
 
 	len = min(count, sizeof(buf) - 1);
diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c
index a4f4f0d..5f30e58 100644
--- a/drivers/net/wireless/ath/ath9k/wow.c
+++ b/drivers/net/wireless/ath/ath9k/wow.c
@@ -193,7 +193,8 @@
 	u32 wow_triggers_enabled = 0;
 	int ret = 0;
 
-	cancel_work_sync(&sc->chanctx_work);
+	ath9k_deinit_channel_context(sc);
+
 	mutex_lock(&sc->mutex);
 
 	ath_cancel_work(sc);
@@ -231,7 +232,7 @@
 		goto fail_wow;
 	}
 
-	if (sc->nvifs > 1) {
+	if (sc->cur_chan->nvifs > 1) {
 		ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
 		ret = 1;
 		goto fail_wow;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 0135a6e..993fbda 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -158,7 +158,6 @@
 {
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ath_frame_info *fi = get_frame_info(skb);
-	int hw_queue;
 	int q = fi->txq;
 
 	if (q < 0)
@@ -168,10 +167,9 @@
 	if (WARN_ON(--txq->pending_frames < 0))
 		txq->pending_frames = 0;
 
-	hw_queue = (info->hw_queue >= sc->hw->queues - 2) ? q : info->hw_queue;
 	if (txq->stopped &&
 	    txq->pending_frames < sc->tx.txq_max_pending[q]) {
-		ieee80211_wake_queue(sc->hw, hw_queue);
+		ieee80211_wake_queue(sc->hw, info->hw_queue);
 		txq->stopped = false;
 	}
 }
@@ -587,6 +585,10 @@
 				memcpy(tx_info->control.rates, rates, sizeof(rates));
 				ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok);
 				rc_update = false;
+				if (bf == bf->bf_lastbf)
+					ath_dynack_sample_tx_ts(sc->sc_ah,
+								bf->bf_mpdu,
+								ts);
 			}
 
 			ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
@@ -681,12 +683,15 @@
 	if (bf_is_ampdu_not_probing(bf))
 		txq->axq_ampdu_depth--;
 
+	ts->duration = ath9k_hw_get_duration(sc->sc_ah, bf->bf_desc,
+					     ts->ts_rateindex);
 	if (!bf_isampdu(bf)) {
 		if (!flush) {
 			info = IEEE80211_SKB_CB(bf->bf_mpdu);
 			memcpy(info->control.rates, bf->rates,
 			       sizeof(info->control.rates));
 			ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
+			ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts);
 		}
 		ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
 	} else
@@ -1836,15 +1841,17 @@
 	if (txq->mac80211_qnum < 0)
 		return;
 
-	spin_lock_bh(&sc->chan_lock);
-	ac_list = &sc->cur_chan->acq[txq->mac80211_qnum];
-	spin_unlock_bh(&sc->chan_lock);
-
-	if (test_bit(ATH_OP_HW_RESET, &common->op_flags) ||
-	    list_empty(ac_list))
+	if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
 		return;
 
 	spin_lock_bh(&sc->chan_lock);
+	ac_list = &sc->cur_chan->acq[txq->mac80211_qnum];
+
+	if (list_empty(ac_list)) {
+		spin_unlock_bh(&sc->chan_lock);
+		return;
+	}
+
 	rcu_read_lock();
 
 	last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list);
@@ -2132,6 +2139,28 @@
 	return bf;
 }
 
+void ath_assign_seq(struct ath_common *common, struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_vif *vif = info->control.vif;
+	struct ath_vif *avp;
+
+	if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
+		return;
+
+	if (!vif)
+		return;
+
+	avp = (struct ath_vif *)vif->drv_priv;
+
+	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+		avp->seq_no += 0x10;
+
+	hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+	hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
+}
+
 static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
 			  struct ath_tx_control *txctl)
 {
@@ -2155,17 +2184,7 @@
 	if (info->control.hw_key)
 		frmlen += info->control.hw_key->icv_len;
 
-	/*
-	 * As a temporary workaround, assign seq# here; this will likely need
-	 * to be cleaned up to work better with Beacon transmission and virtual
-	 * BSSes.
-	 */
-	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-		if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
-			sc->tx.seq_no += 0x10;
-		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-		hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
-	}
+	ath_assign_seq(ath9k_hw_common(sc->sc_ah), skb);
 
 	if ((vif && vif->type != NL80211_IFTYPE_AP &&
 	            vif->type != NL80211_IFTYPE_AP_VLAN) ||
@@ -2202,9 +2221,8 @@
 	struct ath_txq *txq = txctl->txq;
 	struct ath_atx_tid *tid = NULL;
 	struct ath_buf *bf;
-	bool queue;
-	int q, hw_queue;
-	int ret;
+	bool queue, skip_uapsd = false;
+	int q, ret;
 
 	if (vif)
 		avp = (void *)vif->drv_priv;
@@ -2223,14 +2241,13 @@
 	 */
 
 	q = skb_get_queue_mapping(skb);
-	hw_queue = (info->hw_queue >= sc->hw->queues - 2) ? q : info->hw_queue;
 
 	ath_txq_lock(sc, txq);
 	if (txq == sc->tx.txq_map[q]) {
 		fi->txq = q;
 		if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
 		    !txq->stopped) {
-			ieee80211_stop_queue(sc->hw, hw_queue);
+			ieee80211_stop_queue(sc->hw, info->hw_queue);
 			txq->stopped = true;
 		}
 	}
@@ -2245,15 +2262,14 @@
 	     sc->cur_chan->stopped) && !txctl->force_channel) {
 		if (!txctl->an)
 			txctl->an = &avp->mcast_node;
-		info->flags &= ~IEEE80211_TX_CTL_PS_RESPONSE;
 		queue = true;
+		skip_uapsd = true;
 	}
 
 	if (txctl->an && queue)
 		tid = ath_get_skb_tid(sc, txctl->an, skb);
 
-	if (info->flags & (IEEE80211_TX_CTL_PS_RESPONSE |
-			   IEEE80211_TX_CTL_TX_OFFCHAN)) {
+	if (!skip_uapsd && (info->flags & IEEE80211_TX_CTL_PS_RESPONSE)) {
 		ath_txq_unlock(sc, txq);
 		txq = sc->tx.uapsdq;
 		ath_txq_lock(sc, txq);
@@ -2632,8 +2648,11 @@
 			sc->beacon.tx_processed = true;
 			sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
 
-			ath_chanctx_event(sc, NULL,
-					  ATH_CHANCTX_EVENT_BEACON_SENT);
+			if (ath9k_is_chanctx_enabled()) {
+				ath_chanctx_event(sc, NULL,
+						  ATH_CHANCTX_EVENT_BEACON_SENT);
+			}
+
 			ath9k_csa_update(sc);
 			continue;
 		}
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 5852802..d561990 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1430,18 +1430,10 @@
 		if (!sta_info->ht_sta)
 			return -EOPNOTSUPP;
 
-		rcu_read_lock();
-		if (rcu_dereference(sta_info->agg[tid])) {
-			rcu_read_unlock();
-			return -EBUSY;
-		}
-
 		tid_info = kzalloc(sizeof(struct carl9170_sta_tid),
 				   GFP_ATOMIC);
-		if (!tid_info) {
-			rcu_read_unlock();
+		if (!tid_info)
 			return -ENOMEM;
-		}
 
 		tid_info->hsn = tid_info->bsn = tid_info->snx = (*ssn);
 		tid_info->state = CARL9170_TID_STATE_PROGRESS;
@@ -1460,7 +1452,6 @@
 		list_add_tail_rcu(&tid_info->list, &ar->tx_ampdu_list);
 		rcu_assign_pointer(sta_info->agg[tid], tid_info);
 		spin_unlock_bh(&ar->tx_ampdu_list_lock);
-		rcu_read_unlock();
 
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index 4cadfd4..ae86a60 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -1557,7 +1557,7 @@
 	}
 
 out:
-	rcu_assign_pointer(ar->beacon_iter, cvif);
+	RCU_INIT_POINTER(ar->beacon_iter, cvif);
 	return cvif;
 }
 
diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c
index 8b0ac14..338d723 100644
--- a/drivers/net/wireless/ath/main.c
+++ b/drivers/net/wireless/ath/main.c
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 
 #include "ath.h"
+#include "trace.h"
 
 MODULE_AUTHOR("Atheros Communications");
 MODULE_DESCRIPTION("Shared library for Atheros wireless LAN cards.");
@@ -78,11 +79,13 @@
 	vaf.fmt = fmt;
 	vaf.va = &args;
 
-	if (common && common->hw && common->hw->wiphy)
+	if (common && common->hw && common->hw->wiphy) {
 		printk("%sath: %s: %pV",
 		       level, wiphy_name(common->hw->wiphy), &vaf);
-	else
+		trace_ath_log(common->hw->wiphy, &vaf);
+	} else {
 		printk("%sath: %pV", level, &vaf);
+	}
 
 	va_end(args);
 }
diff --git a/drivers/net/wireless/ath/spectral_common.h b/drivers/net/wireless/ath/spectral_common.h
new file mode 100644
index 0000000..0d742ac
--- /dev/null
+++ b/drivers/net/wireless/ath/spectral_common.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SPECTRAL_COMMON_H
+#define SPECTRAL_COMMON_H
+
+#define SPECTRAL_HT20_NUM_BINS		56
+#define SPECTRAL_HT20_40_NUM_BINS		128
+
+/* TODO: could possibly be 512, but no samples this large
+ * could be acquired so far.
+ */
+#define SPECTRAL_ATH10K_MAX_NUM_BINS		256
+
+/* FFT sample format given to userspace via debugfs.
+ *
+ * Please keep the type/length at the front position and change
+ * other fields after adding another sample type
+ *
+ * TODO: this might need rework when switching to nl80211-based
+ * interface.
+ */
+enum ath_fft_sample_type {
+	ATH_FFT_SAMPLE_HT20 = 1,
+	ATH_FFT_SAMPLE_HT20_40,
+	ATH_FFT_SAMPLE_ATH10K,
+};
+
+struct fft_sample_tlv {
+	u8 type;	/* see ath_fft_sample */
+	__be16 length;
+	/* type dependent data follows */
+} __packed;
+
+struct fft_sample_ht20 {
+	struct fft_sample_tlv tlv;
+
+	u8 max_exp;
+
+	__be16 freq;
+	s8 rssi;
+	s8 noise;
+
+	__be16 max_magnitude;
+	u8 max_index;
+	u8 bitmap_weight;
+
+	__be64 tsf;
+
+	u8 data[SPECTRAL_HT20_NUM_BINS];
+} __packed;
+
+struct fft_sample_ht20_40 {
+	struct fft_sample_tlv tlv;
+
+	u8 channel_type;
+	__be16 freq;
+
+	s8 lower_rssi;
+	s8 upper_rssi;
+
+	__be64 tsf;
+
+	s8 lower_noise;
+	s8 upper_noise;
+
+	__be16 lower_max_magnitude;
+	__be16 upper_max_magnitude;
+
+	u8 lower_max_index;
+	u8 upper_max_index;
+
+	u8 lower_bitmap_weight;
+	u8 upper_bitmap_weight;
+
+	u8 max_exp;
+
+	u8 data[SPECTRAL_HT20_40_NUM_BINS];
+} __packed;
+
+struct fft_sample_ath10k {
+	struct fft_sample_tlv tlv;
+	u8 chan_width_mhz;
+	__be16 freq1;
+	__be16 freq2;
+	__be16 noise;
+	__be16 max_magnitude;
+	__be16 total_gain_db;
+	__be16 base_pwr_db;
+	__be64 tsf;
+	s8 max_index;
+	u8 rssi;
+	u8 relpwr_db;
+	u8 avgpwr_db;
+	u8 max_exp;
+
+	u8 data[0];
+} __packed;
+
+#endif /* SPECTRAL_COMMON_H */
diff --git a/drivers/net/wireless/ath/trace.c b/drivers/net/wireless/ath/trace.c
new file mode 100644
index 0000000..18fb3a0
--- /dev/null
+++ b/drivers/net/wireless/ath/trace.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h>
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
diff --git a/drivers/net/wireless/ath/trace.h b/drivers/net/wireless/ath/trace.h
new file mode 100644
index 0000000..fef4c02
--- /dev/null
+++ b/drivers/net/wireless/ath/trace.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_H
+
+#include <linux/tracepoint.h>
+#include "ath.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ath
+
+#if !defined(CPTCFG_ATH_TRACEPOINTS)
+
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) static inline void trace_ ## name(proto) {}
+
+#endif /* CPTCFG_ATH_TRACEPOINTS */
+
+TRACE_EVENT(ath_log,
+
+	    TP_PROTO(struct wiphy *wiphy,
+		     struct va_format *vaf),
+
+	    TP_ARGS(wiphy, vaf),
+
+	    TP_STRUCT__entry(
+		    __string(device, wiphy_name(wiphy))
+		    __string(driver, KBUILD_MODNAME)
+		    __dynamic_array(char, msg, ATH_DBG_MAX_LEN)
+	    ),
+
+	    TP_fast_assign(
+		    __assign_str(device, wiphy_name(wiphy));
+		    __assign_str(driver, KBUILD_MODNAME);
+		    WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+					   ATH_DBG_MAX_LEN,
+					   vaf->fmt,
+					   *vaf->va) >= ATH_DBG_MAX_LEN);
+	    ),
+
+	    TP_printk(
+		    "%s %s %s",
+		    __get_str(driver),
+		    __get_str(device),
+		    __get_str(msg)
+	    )
+);
+
+#endif /* _TRACE_H || TRACE_HEADER_MULTI_READ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig
index b5cc906..821897d 100644
--- a/drivers/net/wireless/ath/wil6210/Kconfig
+++ b/drivers/net/wireless/ath/wil6210/Kconfig
@@ -40,3 +40,12 @@
 	  option if you are interested in debugging the driver.
 
 	  If unsure, say Y to make it easier to debug problems.
+
+config WIL6210_PLATFORM_MSM
+	bool "wil6210 MSM platform specific support"
+	depends on WIL6210
+	depends on ARCH_MSM
+	default y
+	---help---
+	  Say Y here to enable wil6210 driver support for MSM
+	  platform specific features
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index 9388e9c..54394ea 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -10,7 +10,12 @@
 wil6210-y += txrx.o
 wil6210-y += debug.o
 wil6210-y += rx_reorder.o
+wil6210-y += ioctl.o
+wil6210-y += fw.o
 wil6210-$(CPTCFG_WIL6210_TRACING) += trace.o
+wil6210-y += wil_platform.o
+wil6210-$(CPTCFG_WIL6210_PLATFORM_MSM) += wil_platform_msm.o
+wil6210-y += ethtool.o
 
 # for tracing framework to find trace.h
 CFLAGS_trace.o := -I$(src)
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 4ac2c20..d9f4b30 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -296,6 +296,7 @@
 	n = min(request->n_channels, 4U);
 	for (i = 0; i < n; i++) {
 		int ch = request->channels[i]->hw_value;
+
 		if (ch == 0) {
 			wil_err(wil,
 				"Scan requested for unknown frequency %dMhz\n",
@@ -308,15 +309,47 @@
 			     request->channels[i]->center_freq);
 	}
 
+	if (request->ie_len)
+		print_hex_dump_bytes("Scan IE ", DUMP_PREFIX_OFFSET,
+				     request->ie, request->ie_len);
+	else
+		wil_dbg_misc(wil, "Scan has no IE's\n");
+
+	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len,
+			request->ie);
+	if (rc) {
+		wil_err(wil, "Aborting scan, set_ie failed: %d\n", rc);
+		goto out;
+	}
+
 	rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
 			cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
 
-	if (rc)
+out:
+	if (rc) {
+		del_timer_sync(&wil->scan_timer);
 		wil->scan_request = NULL;
+	}
 
 	return rc;
 }
 
+static void wil_print_connect_params(struct wil6210_priv *wil,
+				     struct cfg80211_connect_params *sme)
+{
+	wil_info(wil, "Connecting to:\n");
+	if (sme->channel) {
+		wil_info(wil, "  Channel: %d freq %d\n",
+			 sme->channel->hw_value, sme->channel->center_freq);
+	}
+	if (sme->bssid)
+		wil_info(wil, "  BSSID: %pM\n", sme->bssid);
+	if (sme->ssid)
+		print_hex_dump(KERN_INFO, "  SSID: ", DUMP_PREFIX_OFFSET,
+			       16, 1, sme->ssid, sme->ssid_len, true);
+	wil_info(wil, "  Privacy: %s\n", sme->privacy ? "secure" : "open");
+}
+
 static int wil_cfg80211_connect(struct wiphy *wiphy,
 				struct net_device *ndev,
 				struct cfg80211_connect_params *sme)
@@ -333,6 +366,8 @@
 	    test_bit(wil_status_fwconnected, &wil->status))
 		return -EALREADY;
 
+	wil_print_connect_params(wil, sme);
+
 	bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
 			       sme->ssid, sme->ssid_len,
 			       WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
@@ -358,22 +393,22 @@
 				sme->ie_len);
 			goto out;
 		}
-		/*
-		 * For secure assoc, send:
-		 * (1) WMI_DELETE_CIPHER_KEY_CMD
-		 * (2) WMI_SET_APPIE_CMD
-		 */
+		/* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */
 		rc = wmi_del_cipher_key(wil, 0, bss->bssid);
 		if (rc) {
 			wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
 			goto out;
 		}
-		/* WMI_SET_APPIE_CMD */
-		rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
-		if (rc) {
-			wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
-			goto out;
-		}
+	}
+
+	/* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info
+	 * elements. Send it also in case it's empty, to erase previously set
+	 * ies in FW.
+	 */
+	rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
+	if (rc) {
+		wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
+		goto out;
 	}
 
 	/* WMI_CONNECT_CMD */
@@ -619,6 +654,45 @@
 	return rc;
 }
 
+static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
+				      struct net_device *ndev,
+				      struct cfg80211_beacon_data *bcon)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+	int rc;
+
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
+	if (wil_fix_bcon(wil, bcon)) {
+		wil_dbg_misc(wil, "Fixed bcon\n");
+		wil_print_bcon_data(bcon);
+	}
+
+	/* FW do not form regular beacon, so bcon IE's are not set
+	 * For the DMG bcon, when it will be supported, bcon IE's will
+	 * be reused; add something like:
+	 * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
+	 * bcon->beacon_ies);
+	 */
+	rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
+			bcon->proberesp_ies_len,
+			bcon->proberesp_ies);
+	if (rc) {
+		wil_err(wil, "set_ie(PROBE_RESP) failed\n");
+		return rc;
+	}
+
+	rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP,
+			bcon->assocresp_ies_len,
+			bcon->assocresp_ies);
+	if (rc) {
+		wil_err(wil, "set_ie(ASSOC_RESP) failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
 static int wil_cfg80211_start_ap(struct wiphy *wiphy,
 				 struct net_device *ndev,
 				 struct cfg80211_ap_settings *info)
@@ -654,14 +728,12 @@
 		wil_print_bcon_data(bcon);
 	}
 
+	wil_set_recovery_state(wil, fw_recovery_idle);
+
 	mutex_lock(&wil->mutex);
 
-	rc = wil_reset(wil);
-	if (rc)
-		goto out;
-
-	/* Rx VRING. */
-	rc = wil_rx_init(wil);
+	__wil_down(wil);
+	rc = __wil_up(wil);
 	if (rc)
 		goto out;
 
@@ -669,9 +741,6 @@
 	if (rc)
 		goto out;
 
-	/* MAC address - pre-requisite for other commands */
-	wmi_set_mac_address(wil, ndev->dev_addr);
-
 	/* IE's */
 	/* bcon 'head IE's are not relevant for 60g band */
 	/*
@@ -693,7 +762,6 @@
 	if (rc)
 		goto out;
 
-
 	netif_carrier_on(ndev);
 
 out:
@@ -704,17 +772,23 @@
 static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
 				struct net_device *ndev)
 {
-	int rc = 0;
+	int rc, rc1;
 	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
 	wil_dbg_misc(wil, "%s()\n", __func__);
 
+	wil_set_recovery_state(wil, fw_recovery_idle);
+
 	mutex_lock(&wil->mutex);
 
 	rc = wmi_pcp_stop(wil);
 
+	__wil_down(wil);
+	rc1 = __wil_up(wil);
+
 	mutex_unlock(&wil->mutex);
-	return rc;
+
+	return min(rc, rc1);
 }
 
 static int wil_cfg80211_del_station(struct wiphy *wiphy,
@@ -744,6 +818,7 @@
 	.del_key = wil_cfg80211_del_key,
 	.set_default_key = wil_cfg80211_set_default_key,
 	/* AP mode */
+	.change_beacon = wil_cfg80211_change_beacon,
 	.start_ap = wil_cfg80211_start_ap,
 	.stop_ap = wil_cfg80211_stop_ap,
 	.del_station = wil_cfg80211_del_station,
@@ -753,6 +828,7 @@
 {
 	/* TODO: set real value */
 	wiphy->max_scan_ssids = 10;
+	wiphy->max_scan_ie_len = WMI_MAX_IE_LEN;
 	wiphy->max_num_pmkids = 0 /* TODO: */;
 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
 				 BIT(NL80211_IFTYPE_AP) |
@@ -762,8 +838,8 @@
 	 */
 	wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
 			WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
-	dev_warn(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
-		 __func__, wiphy->flags);
+	dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
+		__func__, wiphy->flags);
 	wiphy->probe_resp_offload =
 		NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
 		NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
@@ -784,7 +860,9 @@
 	int rc = 0;
 	struct wireless_dev *wdev;
 
-	wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+	dev_dbg(dev, "%s()\n", __func__);
+
+	wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
 	if (!wdev)
 		return ERR_PTR(-ENOMEM);
 
@@ -816,6 +894,8 @@
 {
 	struct wireless_dev *wdev = wil_to_wdev(wil);
 
+	dev_dbg(wil_to_dev(wil), "%s()\n", __func__);
+
 	if (!wdev)
 		return;
 
diff --git a/drivers/net/wireless/ath/wil6210/debug.c b/drivers/net/wireless/ath/wil6210/debug.c
index 9eeabf4..8d99021 100644
--- a/drivers/net/wireless/ath/wil6210/debug.c
+++ b/drivers/net/wireless/ath/wil6210/debug.c
@@ -17,43 +17,37 @@
 #include "wil6210.h"
 #include "trace.h"
 
-int wil_err(struct wil6210_priv *wil, const char *fmt, ...)
+void wil_err(struct wil6210_priv *wil, const char *fmt, ...)
 {
 	struct net_device *ndev = wil_to_ndev(wil);
 	struct va_format vaf = {
 		.fmt = fmt,
 	};
 	va_list args;
-	int ret;
 
 	va_start(args, fmt);
 	vaf.va = &args;
-	ret = netdev_err(ndev, "%pV", &vaf);
+	netdev_err(ndev, "%pV", &vaf);
 	trace_wil6210_log_err(&vaf);
 	va_end(args);
-
-	return ret;
 }
 
-int wil_info(struct wil6210_priv *wil, const char *fmt, ...)
+void wil_info(struct wil6210_priv *wil, const char *fmt, ...)
 {
 	struct net_device *ndev = wil_to_ndev(wil);
 	struct va_format vaf = {
 		.fmt = fmt,
 	};
 	va_list args;
-	int ret;
 
 	va_start(args, fmt);
 	vaf.va = &args;
-	ret = netdev_info(ndev, "%pV", &vaf);
+	netdev_info(ndev, "%pV", &vaf);
 	trace_wil6210_log_info(&vaf);
 	va_end(args);
-
-	return ret;
 }
 
-int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...)
+void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...)
 {
 	struct va_format vaf = {
 		.fmt = fmt,
@@ -64,6 +58,4 @@
 	vaf.va = &args;
 	trace_wil6210_log_dbg(&vaf);
 	va_end(args);
-
-	return 0;
 }
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 8f66186..54a6ddc 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -22,6 +22,7 @@
 #include <linux/power_supply.h>
 
 #include "wil6210.h"
+#include "wmi.h"
 #include "txrx.h"
 
 /* Nasty hack. Better have per device instances */
@@ -29,6 +30,21 @@
 static u32 dbg_txdesc_index;
 static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
 
+enum dbg_off_type {
+	doff_u32 = 0,
+	doff_x32 = 1,
+	doff_ulong = 2,
+	doff_io32 = 3,
+};
+
+/* offset to "wil" */
+struct dbg_off {
+	const char *name;
+	umode_t mode;
+	ulong off;
+	enum dbg_off_type type;
+};
+
 static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
 			    const char *name, struct vring *vring,
 			    char _s, char _h)
@@ -45,20 +61,22 @@
 	if (x)
 		seq_printf(s, "0x%08x\n", ioread32(x));
 	else
-		seq_printf(s, "???\n");
+		seq_puts(s, "???\n");
 
 	if (vring->va && (vring->size < 1025)) {
 		uint i;
+
 		for (i = 0; i < vring->size; i++) {
 			volatile struct vring_tx_desc *d = &vring->va[i].tx;
+
 			if ((i % 64) == 0 && (i != 0))
-				seq_printf(s, "\n");
+				seq_puts(s, "\n");
 			seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
 					_s : (vring->ctx[i].skb ? _h : 'h'));
 		}
-		seq_printf(s, "\n");
+		seq_puts(s, "\n");
 	}
-	seq_printf(s, "}\n");
+	seq_puts(s, "}\n");
 }
 
 static int wil_vring_debugfs_show(struct seq_file *s, void *data)
@@ -69,7 +87,7 @@
 	wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_');
 
 	for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
-		struct vring *vring = &(wil->vring_tx[i]);
+		struct vring *vring = &wil->vring_tx[i];
 		struct vring_tx_data *txdata = &wil->vring_tx_data[i];
 
 		if (vring->va) {
@@ -147,7 +165,7 @@
 	if (!wmi_addr(wil, r.base) ||
 	    !wmi_addr(wil, r.tail) ||
 	    !wmi_addr(wil, r.head)) {
-		seq_printf(s, "  ??? pointers are garbage?\n");
+		seq_puts(s, "  ??? pointers are garbage?\n");
 		goto out;
 	}
 
@@ -166,6 +184,7 @@
 			   le32_to_cpu(d.addr));
 		if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
 			u16 len = le16_to_cpu(hdr.len);
+
 			seq_printf(s, " -> %04x %04x %04x %02x\n",
 				   le16_to_cpu(hdr.seq), len,
 				   le16_to_cpu(hdr.type), hdr.flags);
@@ -183,6 +202,7 @@
 				wil_memcpy_fromio_32(databuf, src, len);
 				while (n < len) {
 					int l = min(len - n, 16);
+
 					hex_dump_to_buffer(databuf + n, l,
 							   16, 1, printbuf,
 							   sizeof(printbuf),
@@ -192,11 +212,11 @@
 				}
 			}
 		} else {
-			seq_printf(s, "\n");
+			seq_puts(s, "\n");
 		}
 	}
  out:
-	seq_printf(s, "}\n");
+	seq_puts(s, "}\n");
 }
 
 static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
@@ -244,9 +264,9 @@
 static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
 						   umode_t mode,
 						   struct dentry *parent,
-						   void __iomem *value)
+						   void *value)
 {
-	return debugfs_create_file(name, mode, parent, (void * __force)value,
+	return debugfs_create_file(name, mode, parent, value,
 				   &fops_iomem_x32);
 }
 
@@ -255,11 +275,13 @@
 	*(ulong *)data = val;
 	return 0;
 }
+
 static int wil_debugfs_ulong_get(void *data, u64 *val)
 {
 	*val = *(ulong *)data;
 	return 0;
 }
+
 DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get,
 			wil_debugfs_ulong_set, "%llu\n");
 
@@ -270,6 +292,62 @@
 	return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
 }
 
+/**
+ * wil6210_debugfs_init_offset - create set of debugfs files
+ * @wil - driver's context, used for printing
+ * @dbg - directory on the debugfs, where files will be created
+ * @base - base address used in address calculation
+ * @tbl - table with file descriptions. Should be terminated with empty element.
+ *
+ * Creates files accordingly to the @tbl.
+ */
+static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
+					struct dentry *dbg, void *base,
+					const struct dbg_off * const tbl)
+{
+	int i;
+
+	for (i = 0; tbl[i].name; i++) {
+		struct dentry *f;
+
+		switch (tbl[i].type) {
+		case doff_u32:
+			f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
+					       base + tbl[i].off);
+			break;
+		case doff_x32:
+			f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
+					       base + tbl[i].off);
+			break;
+		case doff_ulong:
+			f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode,
+						     dbg, base + tbl[i].off);
+			break;
+		case doff_io32:
+			f = wil_debugfs_create_iomem_x32(tbl[i].name,
+							 tbl[i].mode, dbg,
+							 base + tbl[i].off);
+			break;
+		default:
+			f = ERR_PTR(-EINVAL);
+		}
+		if (IS_ERR_OR_NULL(f))
+			wil_err(wil, "Create file \"%s\": err %ld\n",
+				tbl[i].name, PTR_ERR(f));
+	}
+}
+
+static const struct dbg_off isr_off[] = {
+	{"ICC", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICC), doff_io32},
+	{"ICR", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICR), doff_io32},
+	{"ICM", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICM), doff_io32},
+	{"ICS",		  S_IWUSR, offsetof(struct RGF_ICR, ICS), doff_io32},
+	{"IMV", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, IMV), doff_io32},
+	{"IMS",		  S_IWUSR, offsetof(struct RGF_ICR, IMS), doff_io32},
+	{"IMC",		  S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32},
+	{},
+};
+
 static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
 				      const char *name,
 				      struct dentry *parent, u32 off)
@@ -279,24 +357,19 @@
 	if (IS_ERR_OR_NULL(d))
 		return -ENODEV;
 
-	wil_debugfs_create_iomem_x32("ICC", S_IRUGO | S_IWUSR, d,
-				     wil->csr + off);
-	wil_debugfs_create_iomem_x32("ICR", S_IRUGO | S_IWUSR, d,
-				     wil->csr + off + 4);
-	wil_debugfs_create_iomem_x32("ICM", S_IRUGO | S_IWUSR, d,
-				     wil->csr + off + 8);
-	wil_debugfs_create_iomem_x32("ICS", S_IWUSR, d,
-				     wil->csr + off + 12);
-	wil_debugfs_create_iomem_x32("IMV", S_IRUGO | S_IWUSR, d,
-				     wil->csr + off + 16);
-	wil_debugfs_create_iomem_x32("IMS", S_IWUSR, d,
-				     wil->csr + off + 20);
-	wil_debugfs_create_iomem_x32("IMC", S_IWUSR, d,
-				     wil->csr + off + 24);
+	wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
+				    isr_off);
 
 	return 0;
 }
 
+static const struct dbg_off pseudo_isr_off[] = {
+	{"CAUSE",   S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
+	{"MASK_SW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
+	{"MASK_FW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
+	{},
+};
+
 static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
 					     struct dentry *parent)
 {
@@ -305,16 +378,19 @@
 	if (IS_ERR_OR_NULL(d))
 		return -ENODEV;
 
-	wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO, d, wil->csr +
-				     HOSTADDR(RGF_DMA_PSEUDO_CAUSE));
-	wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO, d, wil->csr +
-				     HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
-	wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO, d, wil->csr +
-				     HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW));
+	wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
+				    pseudo_isr_off);
 
 	return 0;
 }
 
+static const struct dbg_off itr_cnt_off[] = {
+	{"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
+	{"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
+	{"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
+	{},
+};
+
 static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
 					  struct dentry *parent)
 {
@@ -323,12 +399,8 @@
 	if (IS_ERR_OR_NULL(d))
 		return -ENODEV;
 
-	wil_debugfs_create_iomem_x32("TRSH", S_IRUGO | S_IWUSR, d, wil->csr +
-				     HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
-	wil_debugfs_create_iomem_x32("DATA", S_IRUGO | S_IWUSR, d, wil->csr +
-				     HOSTADDR(RGF_DMA_ITR_CNT_DATA));
-	wil_debugfs_create_iomem_x32("CTL", S_IRUGO | S_IWUSR, d, wil->csr +
-				     HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+	wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
+				    itr_cnt_off);
 
 	return 0;
 }
@@ -359,7 +431,7 @@
 };
 
 static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
-				size_t count, loff_t *ppos)
+				    size_t count, loff_t *ppos)
 {
 	enum { max_count = 4096 };
 	struct debugfs_blob_wrapper *blob = file->private_data;
@@ -411,6 +483,7 @@
 {
 	return debugfs_create_file(name, mode, parent, blob, &fops_ioblob);
 }
+
 /*---reset---*/
 static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
 				    size_t len, loff_t *ppos)
@@ -436,6 +509,7 @@
 	.write = wil_write_file_reset,
 	.open  = simple_open,
 };
+
 /*---write channel 1..4 to rxon for it, 0 to rxoff---*/
 static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
 				   size_t len, loff_t *ppos)
@@ -446,6 +520,7 @@
 	bool on;
 
 	char *kbuf = kmalloc(len + 1, GFP_KERNEL);
+
 	if (!kbuf)
 		return -ENOMEM;
 	if (copy_from_user(kbuf, buf, len)) {
@@ -482,6 +557,7 @@
 	.write = wil_write_file_rxon,
 	.open  = simple_open,
 };
+
 /*---tx_mgmt---*/
 /* Write mgmt frame to this file to send it */
 static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
@@ -492,8 +568,8 @@
 	struct wireless_dev *wdev = wil_to_wdev(wil);
 	struct cfg80211_mgmt_tx_params params;
 	int rc;
-
 	void *frame = kmalloc(len, GFP_KERNEL);
+
 	if (!frame)
 		return -ENOMEM;
 
@@ -562,8 +638,10 @@
 {
 	char printbuf[16 * 3 + 2];
 	int i = 0;
+
 	while (i < len) {
 		int l = min(len - i, 16);
+
 		hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
 				   sizeof(printbuf), false);
 		seq_printf(s, "%s%s\n", prefix, printbuf);
@@ -601,10 +679,8 @@
 	struct wil6210_priv *wil = s->private;
 	struct vring *vring;
 	bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS);
-	if (tx)
-		vring = &(wil->vring_tx[dbg_vring_index]);
-	else
-		vring = &wil->vring_rx;
+
+	vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx;
 
 	if (!vring->va) {
 		if (tx)
@@ -619,7 +695,7 @@
 		 * only field used, .dma.length, is the same
 		 */
 		volatile struct vring_tx_desc *d =
-				&(vring->va[dbg_txdesc_index].tx);
+				&vring->va[dbg_txdesc_index].tx;
 		volatile u32 *u = (volatile u32 *)d;
 		struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb;
 
@@ -639,7 +715,7 @@
 			wil_seq_print_skb(s, skb);
 			kfree_skb(skb);
 		}
-		seq_printf(s, "}\n");
+		seq_puts(s, "}\n");
 	} else {
 		if (tx)
 			seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n",
@@ -666,16 +742,79 @@
 };
 
 /*---------beamforming------------*/
+static char *wil_bfstatus_str(u32 status)
+{
+	switch (status) {
+	case 0:
+		return "Failed";
+	case 1:
+		return "OK";
+	case 2:
+		return "Retrying";
+	default:
+		return "??";
+	}
+}
+
+static bool is_all_zeros(void * const x_, size_t sz)
+{
+	/* if reply is all-0, ignore this CID */
+	u32 *x = x_;
+	int n;
+
+	for (n = 0; n < sz / sizeof(*x); n++)
+		if (x[n])
+			return false;
+
+	return true;
+}
+
 static int wil_bf_debugfs_show(struct seq_file *s, void *data)
 {
+	int rc;
+	int i;
 	struct wil6210_priv *wil = s->private;
-	seq_printf(s,
-		   "TSF : 0x%016llx\n"
-		   "TxMCS : %d\n"
-		   "Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n",
-		   wil->stats.tsf, wil->stats.bf_mcs,
-		   wil->stats.my_rx_sector, wil->stats.my_tx_sector,
-		   wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
+	struct wmi_notify_req_cmd cmd = {
+		.interval_usec = 0,
+	};
+	struct {
+		struct wil6210_mbox_hdr_wmi wmi;
+		struct wmi_notify_req_done_event evt;
+	} __packed reply;
+
+	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+		u32 status;
+
+		cmd.cid = i;
+		rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
+			      WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
+			      sizeof(reply), 20);
+		/* if reply is all-0, ignore this CID */
+		if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
+			continue;
+
+		status = le32_to_cpu(reply.evt.status);
+		seq_printf(s, "CID %d {\n"
+			   "  TSF = 0x%016llx\n"
+			   "  TxMCS = %2d TxTpt = %4d\n"
+			   "  SQI = %4d\n"
+			   "  Status = 0x%08x %s\n"
+			   "  Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
+			   "  Goodput(rx:tx) %4d:%4d\n"
+			   "}\n",
+			   i,
+			   le64_to_cpu(reply.evt.tsf),
+			   le16_to_cpu(reply.evt.bf_mcs),
+			   le32_to_cpu(reply.evt.tx_tpt),
+			   reply.evt.sqi,
+			   status, wil_bfstatus_str(status),
+			   le16_to_cpu(reply.evt.my_rx_sector),
+			   le16_to_cpu(reply.evt.my_tx_sector),
+			   le16_to_cpu(reply.evt.other_rx_sector),
+			   le16_to_cpu(reply.evt.other_tx_sector),
+			   le32_to_cpu(reply.evt.rx_goodput),
+			   le32_to_cpu(reply.evt.tx_goodput));
+	}
 	return 0;
 }
 
@@ -690,6 +829,7 @@
 	.read		= seq_read,
 	.llseek		= seq_lseek,
 };
+
 /*---------SSID------------*/
 static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf,
 				  size_t count, loff_t *ppos)
@@ -752,10 +892,10 @@
 {
 	struct wil6210_priv *wil = s->private;
 	u32 t_m, t_r;
-
 	int rc = wmi_get_temperature(wil, &t_m, &t_r);
+
 	if (rc) {
-		seq_printf(s, "Failed\n");
+		seq_puts(s, "Failed\n");
 		return 0;
 	}
 
@@ -811,6 +951,7 @@
 	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
 		struct wil_sta_info *p = &wil->sta[i];
 		char *status = "unknown";
+
 		switch (p->status) {
 		case wil_sta_unused:
 			status = "unused   ";
@@ -871,7 +1012,6 @@
 	rxf_old = rxf;
 	txf_old = txf;
 
-
 #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \
 	" " __stringify(x) : ""
 
@@ -901,11 +1041,77 @@
 	.llseek		= seq_lseek,
 };
 
+/*---------recovery------------*/
+/* mode = [manual|auto]
+ * state = [idle|pending|running]
+ */
+static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	struct wil6210_priv *wil = file->private_data;
+	char buf[80];
+	int n;
+	static const char * const sstate[] = {"idle", "pending", "running"};
+
+	n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n",
+		     no_fw_recovery ? "manual" : "auto",
+		     sstate[wil->recovery_state]);
+
+	n = min_t(int, n, sizeof(buf));
+
+	return simple_read_from_buffer(user_buf, count, ppos,
+				       buf, n);
+}
+
+static ssize_t wil_write_file_recovery(struct file *file,
+				       const char __user *buf_,
+				       size_t count, loff_t *ppos)
+{
+	struct wil6210_priv *wil = file->private_data;
+	static const char run_command[] = "run";
+	char buf[sizeof(run_command) + 1]; /* to detect "runx" */
+	ssize_t rc;
+
+	if (wil->recovery_state != fw_recovery_pending) {
+		wil_err(wil, "No recovery pending\n");
+		return -EINVAL;
+	}
+
+	if (*ppos != 0) {
+		wil_err(wil, "Offset [%d]\n", (int)*ppos);
+		return -EINVAL;
+	}
+
+	if (count > sizeof(buf)) {
+		wil_err(wil, "Input too long, len = %d\n", (int)count);
+		return -EINVAL;
+	}
+
+	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count);
+	if (rc < 0)
+		return rc;
+
+	buf[rc] = '\0';
+	if (0 == strcmp(buf, run_command))
+		wil_set_recovery_state(wil, fw_recovery_running);
+	else
+		wil_err(wil, "Bad recovery command \"%s\"\n", buf);
+
+	return rc;
+}
+
+static const struct file_operations fops_recovery = {
+	.read = wil_read_file_recovery,
+	.write = wil_write_file_recovery,
+	.open  = simple_open,
+};
+
 /*---------Station matrix------------*/
 static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
 {
 	int i;
 	u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
+
 	seq_printf(s, "0x%03x [", r->head_seq_num);
 	for (i = 0; i < r->buf_size; i++) {
 		if (i == index)
@@ -920,10 +1126,12 @@
 {
 	struct wil6210_priv *wil = s->private;
 	int i, tid;
+	unsigned long flags;
 
 	for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
 		struct wil_sta_info *p = &wil->sta[i];
 		char *status = "unknown";
+
 		switch (p->status) {
 		case wil_sta_unused:
 			status = "unused   ";
@@ -939,13 +1147,16 @@
 			   (p->data_port_open ? " data_port_open" : ""));
 
 		if (p->status == wil_sta_connected) {
+			spin_lock_irqsave(&p->tid_rx_lock, flags);
 			for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
 				struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
+
 				if (r) {
 					seq_printf(s, "[%2d] ", tid);
 					wil_print_rxtid(s, r);
 				}
 			}
+			spin_unlock_irqrestore(&p->tid_rx_lock, flags);
 		}
 	}
 
@@ -985,6 +1196,89 @@
 	}
 }
 
+/* misc files */
+static const struct {
+	const char *name;
+	umode_t mode;
+	const struct file_operations *fops;
+} dbg_files[] = {
+	{"mbox",	S_IRUGO,		&fops_mbox},
+	{"vrings",	S_IRUGO,		&fops_vring},
+	{"stations",	S_IRUGO,		&fops_sta},
+	{"desc",	S_IRUGO,		&fops_txdesc},
+	{"bf",		S_IRUGO,		&fops_bf},
+	{"ssid",	S_IRUGO | S_IWUSR,	&fops_ssid},
+	{"mem_val",	S_IRUGO,		&fops_memread},
+	{"reset",		  S_IWUSR,	&fops_reset},
+	{"rxon",		  S_IWUSR,	&fops_rxon},
+	{"tx_mgmt",		  S_IWUSR,	&fops_txmgmt},
+	{"wmi_send",		  S_IWUSR,	&fops_wmi},
+	{"temp",	S_IRUGO,		&fops_temp},
+	{"freq",	S_IRUGO,		&fops_freq},
+	{"link",	S_IRUGO,		&fops_link},
+	{"info",	S_IRUGO,		&fops_info},
+	{"recovery",	S_IRUGO | S_IWUSR,	&fops_recovery},
+};
+
+static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
+				       struct dentry *dbg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
+		debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
+				    wil, dbg_files[i].fops);
+}
+
+/* interrupt control blocks */
+static const struct {
+	const char *name;
+	u32 icr_off;
+} dbg_icr[] = {
+	{"USER_ICR",		HOSTADDR(RGF_USER_USER_ICR)},
+	{"DMA_EP_TX_ICR",	HOSTADDR(RGF_DMA_EP_TX_ICR)},
+	{"DMA_EP_RX_ICR",	HOSTADDR(RGF_DMA_EP_RX_ICR)},
+	{"DMA_EP_MISC_ICR",	HOSTADDR(RGF_DMA_EP_MISC_ICR)},
+};
+
+static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
+				     struct dentry *dbg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
+		wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
+					   dbg_icr[i].icr_off);
+}
+
+#define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
+	offsetof(struct wil6210_priv, name), type}
+
+/* fields in struct wil6210_priv */
+static const struct dbg_off dbg_wil_off[] = {
+	WIL_FIELD(secure_pcp,	S_IRUGO | S_IWUSR,	doff_u32),
+	WIL_FIELD(status,	S_IRUGO | S_IWUSR,	doff_ulong),
+	WIL_FIELD(fw_version,	S_IRUGO,		doff_u32),
+	WIL_FIELD(hw_version,	S_IRUGO,		doff_x32),
+	WIL_FIELD(recovery_count, S_IRUGO,		doff_u32),
+	{},
+};
+
+static const struct dbg_off dbg_wil_regs[] = {
+	{"RGF_MAC_MTRL_COUNTER_0", S_IRUGO, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
+		doff_io32},
+	{"RGF_USER_USAGE_1", S_IRUGO, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
+	{},
+};
+
+/* static parameters */
+static const struct dbg_off dbg_statics[] = {
+	{"desc_index",	S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32},
+	{"vring_index",	S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32},
+	{"mem_addr",	S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32},
+	{},
+};
+
 int wil6210_debugfs_init(struct wil6210_priv *wil)
 {
 	struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
@@ -993,51 +1287,17 @@
 	if (IS_ERR_OR_NULL(dbg))
 		return -ENODEV;
 
-	debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
-	debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
-	debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta);
-	debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc);
-	debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg,
-			   &dbg_txdesc_index);
-	debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg,
-			   &dbg_vring_index);
-
-	debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf);
-	debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
-	debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
-			   &wil->secure_pcp);
-	wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg,
-				 &wil->status);
-	debugfs_create_u32("fw_version", S_IRUGO, dbg, &wil->fw_version);
-	debugfs_create_x32("hw_version", S_IRUGO, dbg, &wil->hw_version);
-
-	wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg,
-				   HOSTADDR(RGF_USER_USER_ICR));
-	wil6210_debugfs_create_ISR(wil, "DMA_EP_TX_ICR", dbg,
-				   HOSTADDR(RGF_DMA_EP_TX_ICR));
-	wil6210_debugfs_create_ISR(wil, "DMA_EP_RX_ICR", dbg,
-				   HOSTADDR(RGF_DMA_EP_RX_ICR));
-	wil6210_debugfs_create_ISR(wil, "DMA_EP_MISC_ICR", dbg,
-				   HOSTADDR(RGF_DMA_EP_MISC_ICR));
-	wil6210_debugfs_create_pseudo_ISR(wil, dbg);
-	wil6210_debugfs_create_ITR_CNT(wil, dbg);
-
-	wil_debugfs_create_iomem_x32("RGF_USER_USAGE_1", S_IRUGO, dbg,
-				     wil->csr +
-				     HOSTADDR(RGF_USER_USAGE_1));
-	debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr);
-	debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread);
-
-	debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset);
-	debugfs_create_file("rxon", S_IWUSR, dbg, wil, &fops_rxon);
-	debugfs_create_file("tx_mgmt", S_IWUSR, dbg, wil, &fops_txmgmt);
-	debugfs_create_file("wmi_send", S_IWUSR, dbg, wil, &fops_wmi);
-	debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp);
-	debugfs_create_file("freq", S_IRUGO, dbg, wil, &fops_freq);
-	debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link);
-	debugfs_create_file("info", S_IRUGO, dbg, wil, &fops_info);
-
+	wil6210_debugfs_init_files(wil, dbg);
+	wil6210_debugfs_init_isr(wil, dbg);
 	wil6210_debugfs_init_blobs(wil, dbg);
+	wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
+	wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
+				    dbg_wil_regs);
+	wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
+
+	wil6210_debugfs_create_pseudo_ISR(wil, dbg);
+
+	wil6210_debugfs_create_ITR_CNT(wil, dbg);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c
new file mode 100644
index 0000000..d686638
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/ethtool.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/rtnetlink.h>
+#include <net/cfg80211.h>
+
+#include "wil6210.h"
+
+static int wil_ethtoolops_begin(struct net_device *ndev)
+{
+	struct wil6210_priv *wil = ndev_to_wil(ndev);
+
+	mutex_lock(&wil->mutex);
+
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
+	return 0;
+}
+
+static void wil_ethtoolops_complete(struct net_device *ndev)
+{
+	struct wil6210_priv *wil = ndev_to_wil(ndev);
+
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
+	mutex_unlock(&wil->mutex);
+}
+
+static int wil_ethtoolops_get_coalesce(struct net_device *ndev,
+				       struct ethtool_coalesce *cp)
+{
+	struct wil6210_priv *wil = ndev_to_wil(ndev);
+	u32 itr_en, itr_val = 0;
+
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
+	itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+	if (itr_en & BIT_DMA_ITR_CNT_CRL_EN)
+		itr_val = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
+
+	cp->rx_coalesce_usecs = itr_val;
+
+	return 0;
+}
+
+static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
+				       struct ethtool_coalesce *cp)
+{
+	struct wil6210_priv *wil = ndev_to_wil(ndev);
+
+	wil_dbg_misc(wil, "%s(%d usec)\n", __func__, cp->rx_coalesce_usecs);
+
+	if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+		wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n");
+		return -EINVAL;
+	}
+
+	/* only @rx_coalesce_usecs supported, ignore
+	 * other parameters
+	 */
+
+	if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX)
+		goto out_bad;
+
+	wil->itr_trsh = cp->rx_coalesce_usecs;
+	wil_set_itr_trsh(wil);
+
+	return 0;
+
+out_bad:
+	wil_dbg_misc(wil, "Unsupported coalescing params. Raw command:\n");
+	print_hex_dump_debug("DBG[MISC] coal ", DUMP_PREFIX_OFFSET, 16, 4,
+			     cp, sizeof(*cp), false);
+	return -EINVAL;
+}
+
+static const struct ethtool_ops wil_ethtool_ops = {
+	.begin		= wil_ethtoolops_begin,
+	.complete	= wil_ethtoolops_complete,
+	.get_drvinfo	= cfg80211_get_drvinfo,
+	.get_coalesce	= wil_ethtoolops_get_coalesce,
+	.set_coalesce	= wil_ethtoolops_set_coalesce,
+};
+
+void wil_set_ethtoolops(struct net_device *ndev)
+{
+	ndev->ethtool_ops = &wil_ethtool_ops;
+}
diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c
new file mode 100644
index 0000000..8c6f3b0
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/fw.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/crc32.h>
+#include "wil6210.h"
+#include "fw.h"
+
+MODULE_FIRMWARE(WIL_FW_NAME);
+
+/* target operations */
+/* register read */
+#define R(a) ioread32(wil->csr + HOSTADDR(a))
+/* register write. wmb() to make sure it is completed */
+#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
+/* register set = read, OR, write */
+#define S(a, v) W(a, R(a) | v)
+/* register clear = read, AND with inverted, write */
+#define C(a, v) W(a, R(a) & ~v)
+
+static
+void wil_memset_toio_32(volatile void __iomem *dst, u32 val,
+			size_t count)
+{
+	volatile u32 __iomem *d = dst;
+
+	for (count += 4; count > 4; count -= 4)
+		__raw_writel(val, d++);
+}
+
+#include "fw_inc.c"
diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h
new file mode 100644
index 0000000..7a2c6c1
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/fw.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define WIL_FW_SIGNATURE (0x36323130) /* '0126' */
+#define WIL_FW_FMT_VERSION (1) /* format version driver supports */
+
+enum wil_fw_record_type {
+	wil_fw_type_comment = 1,
+	wil_fw_type_data = 2,
+	wil_fw_type_fill = 3,
+	wil_fw_type_action = 4,
+	wil_fw_type_verify = 5,
+	wil_fw_type_file_header = 6,
+	wil_fw_type_direct_write = 7,
+	wil_fw_type_gateway_data = 8,
+	wil_fw_type_gateway_data4 = 9,
+};
+
+struct wil_fw_record_head {
+	__le16 type; /* enum wil_fw_record_type */
+	__le16 flags; /* to be defined */
+	__le32 size; /* whole record, bytes after head */
+} __packed;
+
+/* data block. write starting from @addr
+ * data_size inferred from the @head.size. For this case,
+ * data_size = @head.size - offsetof(struct wil_fw_record_data, data)
+ */
+struct wil_fw_record_data { /* type == wil_fw_type_data */
+	__le32 addr;
+	__le32 data[0]; /* [data_size], see above */
+} __packed;
+
+/* fill with constant @value, @size bytes starting from @addr */
+struct wil_fw_record_fill { /* type == wil_fw_type_fill */
+	__le32 addr;
+	__le32 value;
+	__le32 size;
+} __packed;
+
+/* free-form comment
+ * for informational purpose, data_size is @head.size from record header
+ */
+struct wil_fw_record_comment { /* type == wil_fw_type_comment */
+	u8 data[0]; /* free-form data [data_size], see above */
+} __packed;
+
+/* perform action
+ * data_size = @head.size - offsetof(struct wil_fw_record_action, data)
+ */
+struct wil_fw_record_action { /* type == wil_fw_type_action */
+	__le32 action; /* action to perform: reset, wait for fw ready etc. */
+	__le32 data[0]; /* action specific, [data_size], see above */
+} __packed;
+
+/* data block for struct wil_fw_record_direct_write */
+struct wil_fw_data_dwrite {
+	__le32 addr;
+	__le32 value;
+	__le32 mask;
+} __packed;
+
+/* write @value to the @addr,
+ * preserve original bits accordingly to the @mask
+ * data_size is @head.size where @head is record header
+ */
+struct wil_fw_record_direct_write { /* type == wil_fw_type_direct_write */
+	struct wil_fw_data_dwrite data[0];
+} __packed;
+
+/* verify condition: [@addr] & @mask == @value
+ * if condition not met, firmware download fails
+ */
+struct wil_fw_record_verify { /* type == wil_fw_verify */
+	__le32 addr; /* read from this address */
+	__le32 value; /* reference value */
+	__le32 mask; /* mask for verification */
+} __packed;
+
+/* file header
+ * First record of every file
+ */
+struct wil_fw_record_file_header {
+	__le32 signature ; /* Wilocity signature */
+	__le32 reserved;
+	__le32 crc; /* crc32 of the following data  */
+	__le32 version; /* format version */
+	__le32 data_len; /* total data in file, including this record */
+	u8 comment[32]; /* short description */
+} __packed;
+
+/* 1-dword gateway */
+/* data block for the struct wil_fw_record_gateway_data */
+struct wil_fw_data_gw {
+	__le32 addr;
+	__le32 value;
+} __packed;
+
+/* gateway write block.
+ * write starting address and values from the data buffer
+ * through the gateway
+ * data_size inferred from the @head.size. For this case,
+ * data_size = @head.size - offsetof(struct wil_fw_record_gateway_data, data)
+ */
+struct wil_fw_record_gateway_data { /* type == wil_fw_type_gateway_data */
+	__le32 gateway_addr_addr;
+	__le32 gateway_value_addr;
+	__le32 gateway_cmd_addr;
+	__le32 gateway_ctrl_address;
+#define WIL_FW_GW_CTL_BUSY	BIT(29) /* gateway busy performing operation */
+#define WIL_FW_GW_CTL_RUN	BIT(30) /* start gateway operation */
+	__le32 command;
+	struct wil_fw_data_gw data[0]; /* total size [data_size], see above */
+} __packed;
+
+/* 4-dword gateway */
+/* data block for the struct wil_fw_record_gateway_data4 */
+struct wil_fw_data_gw4 {
+	__le32 addr;
+	__le32 value[4];
+} __packed;
+
+/* gateway write block.
+ * write starting address and values from the data buffer
+ * through the gateway
+ * data_size inferred from the @head.size. For this case,
+ * data_size = @head.size - offsetof(struct wil_fw_record_gateway_data4, data)
+ */
+struct wil_fw_record_gateway_data4 { /* type == wil_fw_type_gateway_data4 */
+	__le32 gateway_addr_addr;
+	__le32 gateway_value_addr[4];
+	__le32 gateway_cmd_addr;
+	__le32 gateway_ctrl_address; /* same logic as for 1-dword gw */
+	__le32 command;
+	struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */
+} __packed;
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
new file mode 100644
index 0000000..44cb71f
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Algorithmic part of the firmware download.
+ * To be included in the container file providing framework
+ */
+
+#define wil_err_fw(wil, fmt, arg...) wil_err(wil, "ERR[ FW ]" fmt, ##arg)
+#define wil_dbg_fw(wil, fmt, arg...) wil_dbg(wil, "DBG[ FW ]" fmt, ##arg)
+#define wil_hex_dump_fw(prefix_str, prefix_type, rowsize,		\
+			groupsize, buf, len, ascii)			\
+			print_hex_dump_debug("DBG[ FW ]" prefix_str,	\
+					     prefix_type, rowsize,	\
+					     groupsize, buf, len, ascii)
+
+#define FW_ADDR_CHECK(ioaddr, val, msg) do { \
+		ioaddr = wmi_buffer(wil, val); \
+		if (!ioaddr) { \
+			wil_err_fw(wil, "bad " msg ": 0x%08x\n", \
+				   le32_to_cpu(val)); \
+			return -EINVAL; \
+		} \
+	} while (0)
+
+/**
+ * wil_fw_verify - verify firmware file validity
+ *
+ * perform various checks for the firmware file header.
+ * records are not validated.
+ *
+ * Return file size or negative error
+ */
+static int wil_fw_verify(struct wil6210_priv *wil, const u8 *data, size_t size)
+{
+	const struct wil_fw_record_head *hdr = (const void *)data;
+	struct wil_fw_record_file_header fh;
+	const struct wil_fw_record_file_header *fh_;
+	u32 crc;
+	u32 dlen;
+
+	if (size % 4) {
+		wil_err_fw(wil, "image size not aligned: %zu\n", size);
+		return -EINVAL;
+	}
+	/* have enough data for the file header? */
+	if (size < sizeof(*hdr) + sizeof(fh)) {
+		wil_err_fw(wil, "file too short: %zu bytes\n", size);
+		return -EINVAL;
+	}
+
+	/* start with the file header? */
+	if (le16_to_cpu(hdr->type) != wil_fw_type_file_header) {
+		wil_err_fw(wil, "no file header\n");
+		return -EINVAL;
+	}
+
+	/* data_len */
+	fh_ = (struct wil_fw_record_file_header *)&hdr[1];
+	dlen = le32_to_cpu(fh_->data_len);
+	if (dlen % 4) {
+		wil_err_fw(wil, "data length not aligned: %lu\n", (ulong)dlen);
+		return -EINVAL;
+	}
+	if (size < dlen) {
+		wil_err_fw(wil, "file truncated at %zu/%lu\n",
+			   size, (ulong)dlen);
+		return -EINVAL;
+	}
+	if (dlen < sizeof(*hdr) + sizeof(fh)) {
+		wil_err_fw(wil, "data length too short: %lu\n", (ulong)dlen);
+		return -EINVAL;
+	}
+
+	/* signature */
+	if (le32_to_cpu(fh_->signature) != WIL_FW_SIGNATURE) {
+		wil_err_fw(wil, "bad header signature: 0x%08x\n",
+			   le32_to_cpu(fh_->signature));
+		return -EINVAL;
+	}
+
+	/* version */
+	if (le32_to_cpu(fh_->version) > WIL_FW_FMT_VERSION) {
+		wil_err_fw(wil, "unsupported header version: %d\n",
+			   le32_to_cpu(fh_->version));
+		return -EINVAL;
+	}
+
+	/* checksum. ~crc32(~0, data, size) when fh.crc set to 0*/
+	fh = *fh_;
+	fh.crc = 0;
+
+	crc = crc32_le(~0, (unsigned char const *)hdr, sizeof(*hdr));
+	crc = crc32_le(crc, (unsigned char const *)&fh, sizeof(fh));
+	crc = crc32_le(crc, (unsigned char const *)&fh_[1],
+		       dlen - sizeof(*hdr) - sizeof(fh));
+	crc = ~crc;
+
+	if (crc != le32_to_cpu(fh_->crc)) {
+		wil_err_fw(wil, "checksum mismatch:"
+			   " calculated for %lu bytes 0x%08x != 0x%08x\n",
+			   (ulong)dlen, crc, le32_to_cpu(fh_->crc));
+		return -EINVAL;
+	}
+
+	return (int)dlen;
+}
+
+static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
+			     size_t size)
+{
+	wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true);
+
+	return 0;
+}
+
+static int fw_handle_data(struct wil6210_priv *wil, const void *data,
+			  size_t size)
+{
+	const struct wil_fw_record_data *d = data;
+	void __iomem *dst;
+	size_t s = size - sizeof(*d);
+
+	if (size < sizeof(*d) + sizeof(u32)) {
+		wil_err_fw(wil, "data record too short: %zu\n", size);
+		return -EINVAL;
+	}
+
+	FW_ADDR_CHECK(dst, d->addr, "address");
+	wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
+		   s);
+	wil_memcpy_toio_32(dst, d->data, s);
+	wmb(); /* finish before processing next record */
+
+	return 0;
+}
+
+static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
+			  size_t size)
+{
+	const struct wil_fw_record_fill *d = data;
+	void __iomem *dst;
+	u32 v;
+	size_t s = (size_t)le32_to_cpu(d->size);
+
+	if (size != sizeof(*d)) {
+		wil_err_fw(wil, "bad size for fill record: %zu\n", size);
+		return -EINVAL;
+	}
+
+	if (s < sizeof(u32)) {
+		wil_err_fw(wil, "fill size too short: %zu\n", s);
+		return -EINVAL;
+	}
+
+	if (s % sizeof(u32)) {
+		wil_err_fw(wil, "fill size not aligned: %zu\n", s);
+		return -EINVAL;
+	}
+
+	FW_ADDR_CHECK(dst, d->addr, "address");
+
+	v = le32_to_cpu(d->value);
+	wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
+		   le32_to_cpu(d->addr), v, s);
+	wil_memset_toio_32(dst, v, s);
+	wmb(); /* finish before processing next record */
+
+	return 0;
+}
+
+static int fw_handle_file_header(struct wil6210_priv *wil, const void *data,
+				 size_t size)
+{
+	const struct wil_fw_record_file_header *d = data;
+
+	if (size != sizeof(*d)) {
+		wil_err_fw(wil, "file header length incorrect: %zu\n", size);
+		return -EINVAL;
+	}
+
+	wil_dbg_fw(wil, "new file, ver. %d, %i bytes\n",
+		   d->version, d->data_len);
+	wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, d->comment,
+			sizeof(d->comment), true);
+
+	return 0;
+}
+
+static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data,
+				  size_t size)
+{
+	const struct wil_fw_record_direct_write *d = data;
+	const struct wil_fw_data_dwrite *block = d->data;
+	int n, i;
+
+	if (size % sizeof(*block)) {
+		wil_err_fw(wil, "record size not aligned on %zu: %zu\n",
+			   sizeof(*block), size);
+		return -EINVAL;
+	}
+	n = size / sizeof(*block);
+
+	for (i = 0; i < n; i++) {
+		void __iomem *dst;
+		u32 m = le32_to_cpu(block[i].mask);
+		u32 v = le32_to_cpu(block[i].value);
+		u32 x, y;
+
+		FW_ADDR_CHECK(dst, block[i].addr, "address");
+
+		x = ioread32(dst);
+		y = (x & m) | (v & ~m);
+		wil_dbg_fw(wil, "write [0x%08x] <== 0x%08x "
+			   "(old 0x%08x val 0x%08x mask 0x%08x)\n",
+			   le32_to_cpu(block[i].addr), y, x, v, m);
+		iowrite32(y, dst);
+		wmb(); /* finish before processing next record */
+	}
+
+	return 0;
+}
+
+static int gw_write(struct wil6210_priv *wil, void __iomem *gwa_addr,
+		    void __iomem *gwa_cmd, void __iomem *gwa_ctl, u32 gw_cmd,
+		    u32 a)
+{
+	unsigned delay = 0;
+
+	iowrite32(a, gwa_addr);
+	iowrite32(gw_cmd, gwa_cmd);
+	wmb(); /* finish before activate gw */
+
+	iowrite32(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */
+	do {
+		udelay(1); /* typical time is few usec */
+		if (delay++ > 100) {
+			wil_err_fw(wil, "gw timeout\n");
+			return -EINVAL;
+		}
+	} while (ioread32(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */
+
+	return 0;
+}
+
+static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data,
+				  size_t size)
+{
+	const struct wil_fw_record_gateway_data *d = data;
+	const struct wil_fw_data_gw *block = d->data;
+	void __iomem *gwa_addr;
+	void __iomem *gwa_val;
+	void __iomem *gwa_cmd;
+	void __iomem *gwa_ctl;
+	u32 gw_cmd;
+	int n, i;
+
+	if (size < sizeof(*d) + sizeof(*block)) {
+		wil_err_fw(wil, "gateway record too short: %zu\n", size);
+		return -EINVAL;
+	}
+
+	if ((size - sizeof(*d)) % sizeof(*block)) {
+		wil_err_fw(wil, "gateway record data size"
+			   " not aligned on %zu: %zu\n",
+			   sizeof(*block), size - sizeof(*d));
+		return -EINVAL;
+	}
+	n = (size - sizeof(*d)) / sizeof(*block);
+
+	gw_cmd = le32_to_cpu(d->command);
+
+	wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n",
+		   n, gw_cmd);
+
+	FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
+	FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr");
+	FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
+	FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
+
+	wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x"
+		   " cmd 0x%08x ctl 0x%08x\n",
+		   le32_to_cpu(d->gateway_addr_addr),
+		   le32_to_cpu(d->gateway_value_addr),
+		   le32_to_cpu(d->gateway_cmd_addr),
+		   le32_to_cpu(d->gateway_ctrl_address));
+
+	for (i = 0; i < n; i++) {
+		int rc;
+		u32 a = le32_to_cpu(block[i].addr);
+		u32 v = le32_to_cpu(block[i].value);
+
+		wil_dbg_fw(wil, "  gw write[%3d] [0x%08x] <== 0x%08x\n",
+			   i, a, v);
+
+		iowrite32(v, gwa_val);
+		rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data,
+				   size_t size)
+{
+	const struct wil_fw_record_gateway_data4 *d = data;
+	const struct wil_fw_data_gw4 *block = d->data;
+	void __iomem *gwa_addr;
+	void __iomem *gwa_val[ARRAY_SIZE(block->value)];
+	void __iomem *gwa_cmd;
+	void __iomem *gwa_ctl;
+	u32 gw_cmd;
+	int n, i, k;
+
+	if (size < sizeof(*d) + sizeof(*block)) {
+		wil_err_fw(wil, "gateway4 record too short: %zu\n", size);
+		return -EINVAL;
+	}
+
+	if ((size - sizeof(*d)) % sizeof(*block)) {
+		wil_err_fw(wil, "gateway4 record data size"
+			   " not aligned on %zu: %zu\n",
+			   sizeof(*block), size - sizeof(*d));
+		return -EINVAL;
+	}
+	n = (size - sizeof(*d)) / sizeof(*block);
+
+	gw_cmd = le32_to_cpu(d->command);
+
+	wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n",
+		   n, gw_cmd);
+
+	FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
+	for (k = 0; k < ARRAY_SIZE(block->value); k++)
+		FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k],
+			      "gateway_value_addr");
+	FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
+	FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
+
+	wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n",
+		   le32_to_cpu(d->gateway_addr_addr),
+		   le32_to_cpu(d->gateway_cmd_addr),
+		   le32_to_cpu(d->gateway_ctrl_address));
+	wil_hex_dump_fw("val addresses: ", DUMP_PREFIX_NONE, 16, 4,
+			d->gateway_value_addr, sizeof(d->gateway_value_addr),
+			false);
+
+	for (i = 0; i < n; i++) {
+		int rc;
+		u32 a = le32_to_cpu(block[i].addr);
+		u32 v[ARRAY_SIZE(block->value)];
+
+		for (k = 0; k < ARRAY_SIZE(block->value); k++)
+			v[k] = le32_to_cpu(block[i].value[k]);
+
+		wil_dbg_fw(wil, "  gw4 write[%3d] [0x%08x] <==\n", i, a);
+		wil_hex_dump_fw("    val ", DUMP_PREFIX_NONE, 16, 4, v,
+				sizeof(v), false);
+
+		for (k = 0; k < ARRAY_SIZE(block->value); k++)
+			iowrite32(v[k], gwa_val[k]);
+		rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+static const struct {
+	int type;
+	int (*handler)(struct wil6210_priv *wil, const void *data, size_t size);
+} wil_fw_handlers[] = {
+	{wil_fw_type_comment, fw_handle_comment},
+	{wil_fw_type_data, fw_handle_data},
+	{wil_fw_type_fill, fw_handle_fill},
+	/* wil_fw_type_action */
+	/* wil_fw_type_verify */
+	{wil_fw_type_file_header, fw_handle_file_header},
+	{wil_fw_type_direct_write, fw_handle_direct_write},
+	{wil_fw_type_gateway_data, fw_handle_gateway_data},
+	{wil_fw_type_gateway_data4, fw_handle_gateway_data4},
+};
+
+static int wil_fw_handle_record(struct wil6210_priv *wil, int type,
+				const void *data, size_t size)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wil_fw_handlers); i++) {
+		if (wil_fw_handlers[i].type == type)
+			return wil_fw_handlers[i].handler(wil, data, size);
+	}
+
+	wil_err_fw(wil, "unknown record type: %d\n", type);
+	return -EINVAL;
+}
+
+/**
+ * wil_fw_load - load FW into device
+ *
+ * Load the FW and uCode code and data to the corresponding device
+ * memory regions
+ *
+ * Return error code
+ */
+static int wil_fw_load(struct wil6210_priv *wil, const void *data, size_t size)
+{
+	int rc = 0;
+	const struct wil_fw_record_head *hdr;
+	size_t s, hdr_sz;
+
+	for (hdr = data;; hdr = (const void *)hdr + s, size -= s) {
+		if (size < sizeof(*hdr))
+			break;
+		hdr_sz = le32_to_cpu(hdr->size);
+		s = sizeof(*hdr) + hdr_sz;
+		if (s > size)
+			break;
+		if (hdr_sz % 4) {
+			wil_err_fw(wil, "unaligned record size: %zu\n",
+				   hdr_sz);
+			return -EINVAL;
+		}
+		rc = wil_fw_handle_record(wil, le16_to_cpu(hdr->type),
+					  &hdr[1], hdr_sz);
+		if (rc)
+			return rc;
+	}
+	if (size) {
+		wil_err_fw(wil, "unprocessed bytes: %zu\n", size);
+		if (size >= sizeof(*hdr)) {
+			wil_err_fw(wil, "Stop at offset %ld"
+				   " record type %d [%zd bytes]\n",
+				   (const void *)hdr - data,
+				   le16_to_cpu(hdr->type), hdr_sz);
+		}
+		return -EINVAL;
+	}
+	/* Mark FW as loaded from host */
+	S(RGF_USER_USAGE_6, 1);
+
+	return rc;
+}
+
+/**
+ * wil_request_firmware - Request firmware and load to device
+ *
+ * Request firmware image from the file and load it to device
+ *
+ * Return error code
+ */
+int wil_request_firmware(struct wil6210_priv *wil, const char *name)
+{
+	int rc, rc1;
+	const struct firmware *fw;
+	size_t sz;
+	const void *d;
+
+	rc = request_firmware(&fw, name, wil_to_pcie_dev(wil));
+	if (rc) {
+		wil_err_fw(wil, "Failed to load firmware %s\n", name);
+		return rc;
+	}
+	wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size);
+
+	for (sz = fw->size, d = fw->data; sz; sz -= rc1, d += rc1) {
+		rc1 = wil_fw_verify(wil, d, sz);
+		if (rc1 < 0) {
+			rc = rc1;
+			goto out;
+		}
+		rc = wil_fw_load(wil, d, rc1);
+		if (rc < 0)
+			goto out;
+	}
+
+out:
+	release_firmware(fw);
+	return rc;
+}
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index e2067a3..b7a0f6f 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -135,7 +135,7 @@
 		  HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
 }
 
-void wil6210_disable_irq(struct wil6210_priv *wil)
+void wil_mask_irq(struct wil6210_priv *wil)
 {
 	wil_dbg_irq(wil, "%s()\n", __func__);
 
@@ -145,7 +145,7 @@
 	wil6210_mask_irq_pseudo(wil);
 }
 
-void wil6210_enable_irq(struct wil6210_priv *wil)
+void wil_unmask_irq(struct wil6210_priv *wil)
 {
 	wil_dbg_irq(wil, "%s()\n", __func__);
 
@@ -157,17 +157,7 @@
 		  offsetof(struct RGF_ICR, ICC));
 
 	/* interrupt moderation parameters */
-	if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
-		/* disable interrupt moderation for monitor
-		 * to get better timestamp precision
-		 */
-		iowrite32(0, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
-	} else {
-		iowrite32(WIL6210_ITR_TRSH,
-			  wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
-		iowrite32(BIT_DMA_ITR_CNT_CRL_EN,
-			  wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
-	}
+	wil_set_itr_trsh(wil);
 
 	wil6210_unmask_irq_pseudo(wil);
 	wil6210_unmask_irq_tx(wil);
@@ -196,8 +186,13 @@
 		wil_dbg_irq(wil, "RX done\n");
 		isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
 		if (test_bit(wil_status_reset_done, &wil->status)) {
-			wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
-			napi_schedule(&wil->napi_rx);
+			if (test_bit(wil_status_napi_en, &wil->status)) {
+				wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
+				napi_schedule(&wil->napi_rx);
+			} else {
+				wil_err(wil, "Got Rx interrupt while "
+					"stopping interface\n");
+			}
 		} else {
 			wil_err(wil, "Got Rx interrupt while in reset\n");
 		}
@@ -506,7 +501,8 @@
 
 	return rc;
 }
-/* can't use wil_ioread32_and_clear because ICC value is not ser yet */
+
+/* can't use wil_ioread32_and_clear because ICC value is not set yet */
 static inline void wil_clear32(void __iomem *addr)
 {
 	u32 x = ioread32(addr);
@@ -522,11 +518,15 @@
 		    offsetof(struct RGF_ICR, ICR));
 	wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
 		    offsetof(struct RGF_ICR, ICR));
+	wmb(); /* make sure write completed */
 }
 
 int wil6210_init_irq(struct wil6210_priv *wil, int irq)
 {
 	int rc;
+
+	wil_dbg_misc(wil, "%s() n_msi=%d\n", __func__, wil->n_msi);
+
 	if (wil->n_msi == 3)
 		rc = wil6210_request_3msi(wil, irq);
 	else
@@ -534,17 +534,14 @@
 					  wil6210_thread_irq,
 					  wil->n_msi ? 0 : IRQF_SHARED,
 					  WIL_NAME, wil);
-	if (rc)
-		return rc;
-
-	wil6210_enable_irq(wil);
-
-	return 0;
+	return rc;
 }
 
 void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
 {
-	wil6210_disable_irq(wil);
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
+	wil_mask_irq(wil);
 	free_irq(irq, wil);
 	if (wil->n_msi == 3) {
 		free_irq(irq + 1, wil);
diff --git a/drivers/net/wireless/ath/wil6210/ioctl.c b/drivers/net/wireless/ath/wil6210/ioctl.c
new file mode 100644
index 0000000..e9c0673
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/ioctl.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/uaccess.h>
+
+#include "wil6210.h"
+#include <uapi/linux/wil6210_uapi.h>
+
+#define wil_hex_dump_ioctl(prefix_str, buf, len) \
+	print_hex_dump_debug("DBG[IOC ]" prefix_str, \
+			     DUMP_PREFIX_OFFSET, 16, 1, buf, len, true)
+#define wil_dbg_ioctl(wil, fmt, arg...) wil_dbg(wil, "DBG[IOC ]" fmt, ##arg)
+
+static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr,
+				  uint32_t size, enum wil_memio_op op)
+{
+	void __iomem *a;
+	u32 off;
+
+	switch (op & wil_mmio_addr_mask) {
+	case wil_mmio_addr_linker:
+		a = wmi_buffer(wil, cpu_to_le32(addr));
+		break;
+	case wil_mmio_addr_ahb:
+		a = wmi_addr(wil, addr);
+		break;
+	case wil_mmio_addr_bar:
+		a = wmi_addr(wil, addr + WIL6210_FW_HOST_OFF);
+		break;
+	default:
+		wil_err(wil, "Unsupported address mode, op = 0x%08x\n", op);
+		return NULL;
+	}
+
+	off = a - wil->csr;
+	if (size >= WIL6210_MEM_SIZE - off) {
+		wil_err(wil, "Requested block does not fit into memory: "
+			"off = 0x%08x size = 0x%08x\n", off, size);
+		return NULL;
+	}
+
+	return a;
+}
+
+static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data)
+{
+	struct wil_memio io;
+	void __iomem *a;
+	bool need_copy = false;
+
+	if (copy_from_user(&io, data, sizeof(io)))
+		return -EFAULT;
+
+	wil_dbg_ioctl(wil, "IO: addr = 0x%08x val = 0x%08x op = 0x%08x\n",
+		      io.addr, io.val, io.op);
+
+	a = wil_ioc_addr(wil, io.addr, sizeof(u32), io.op);
+	if (!a) {
+		wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr,
+			io.op);
+		return -EINVAL;
+	}
+	/* operation */
+	switch (io.op & wil_mmio_op_mask) {
+	case wil_mmio_read:
+		io.val = ioread32(a);
+		need_copy = true;
+		break;
+	case wil_mmio_write:
+		iowrite32(io.val, a);
+		wmb(); /* make sure write propagated to HW */
+		break;
+	default:
+		wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op);
+		return -EINVAL;
+	}
+
+	if (need_copy) {
+		wil_dbg_ioctl(wil, "IO done: addr = 0x%08x"
+			      " val = 0x%08x op = 0x%08x\n",
+			      io.addr, io.val, io.op);
+		if (copy_to_user(data, &io, sizeof(io)))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int wil_ioc_memio_block(struct wil6210_priv *wil, void __user *data)
+{
+	struct wil_memio_block io;
+	void *block;
+	void __iomem *a;
+	int rc = 0;
+
+	if (copy_from_user(&io, data, sizeof(io)))
+		return -EFAULT;
+
+	wil_dbg_ioctl(wil, "IO: addr = 0x%08x size = 0x%08x op = 0x%08x\n",
+		      io.addr, io.size, io.op);
+
+	/* size */
+	if (io.size % 4) {
+		wil_err(wil, "size is not multiple of 4:  0x%08x\n", io.size);
+		return -EINVAL;
+	}
+
+	a = wil_ioc_addr(wil, io.addr, io.size, io.op);
+	if (!a) {
+		wil_err(wil, "invalid address 0x%08x, op = 0x%08x\n", io.addr,
+			io.op);
+		return -EINVAL;
+	}
+
+	block = kmalloc(io.size, GFP_USER);
+	if (!block)
+		return -ENOMEM;
+
+	/* operation */
+	switch (io.op & wil_mmio_op_mask) {
+	case wil_mmio_read:
+		wil_memcpy_fromio_32(block, a, io.size);
+		wil_hex_dump_ioctl("Read  ", block, io.size);
+		if (copy_to_user(io.block, block, io.size)) {
+			rc = -EFAULT;
+			goto out_free;
+		}
+		break;
+	case wil_mmio_write:
+		if (copy_from_user(block, io.block, io.size)) {
+			rc = -EFAULT;
+			goto out_free;
+		}
+		wil_memcpy_toio_32(a, block, io.size);
+		wmb(); /* make sure write propagated to HW */
+		wil_hex_dump_ioctl("Write ", block, io.size);
+		break;
+	default:
+		wil_err(wil, "Unsupported operation, op = 0x%08x\n", io.op);
+		rc = -EINVAL;
+		break;
+	}
+
+out_free:
+	kfree(block);
+	return rc;
+}
+
+int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd)
+{
+	switch (cmd) {
+	case WIL_IOCTL_MEMIO:
+		return wil_ioc_memio_dword(wil, data);
+	case WIL_IOCTL_MEMIO_BLOCK:
+		return wil_ioc_memio_block(wil, data);
+	default:
+		wil_dbg_ioctl(wil, "Unsupported IOCTL 0x%04x\n", cmd);
+		return -ENOIOCTLCMD;
+	}
+}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 3704d2a..6500caf 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -20,10 +20,26 @@
 
 #include "wil6210.h"
 #include "txrx.h"
+#include "wmi.h"
 
-static bool no_fw_recovery;
+#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
+#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
+
+bool no_fw_recovery;
 module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");
+MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");
+
+static bool no_fw_load = true;
+module_param(no_fw_load, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash.");
+
+static unsigned int itr_trsh = WIL6210_ITR_TRSH_DEFAULT;
+
+module_param(itr_trsh, uint, S_IRUGO);
+MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs.");
+
+#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
+#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
 
 /*
  * Due to a hardware issue,
@@ -64,6 +80,7 @@
 	struct net_device *ndev = wil_to_ndev(wil);
 	struct wireless_dev *wdev = wil->wdev;
 	struct wil_sta_info *sta = &wil->sta[cid];
+
 	wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
 		     sta->status);
 
@@ -83,9 +100,16 @@
 	}
 
 	for (i = 0; i < WIL_STA_TID_NUM; i++) {
-		struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
+		struct wil_tid_ampdu_rx *r;
+		unsigned long flags;
+
+		spin_lock_irqsave(&sta->tid_rx_lock, flags);
+
+		r = sta->tid_rx[i];
 		sta->tid_rx[i] = NULL;
 		wil_tid_ampdu_rx_free(wil, r);
+
+		spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
 	}
 	for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
 		if (wil->vring2cid_tid[i][0] == cid)
@@ -167,17 +191,38 @@
 	schedule_work(&wil->fw_error_worker);
 }
 
+static int wil_wait_for_recovery(struct wil6210_priv *wil)
+{
+	if (wait_event_interruptible(wil->wq, wil->recovery_state !=
+				     fw_recovery_pending)) {
+		wil_err(wil, "Interrupt, canceling recovery\n");
+		return -ERESTARTSYS;
+	}
+	if (wil->recovery_state != fw_recovery_running) {
+		wil_info(wil, "Recovery cancelled\n");
+		return -EINTR;
+	}
+	wil_info(wil, "Proceed with recovery\n");
+	return 0;
+}
+
+void wil_set_recovery_state(struct wil6210_priv *wil, int state)
+{
+	wil_dbg_misc(wil, "%s(%d -> %d)\n", __func__,
+		     wil->recovery_state, state);
+
+	wil->recovery_state = state;
+	wake_up_interruptible(&wil->wq);
+}
+
 static void wil_fw_error_worker(struct work_struct *work)
 {
-	struct wil6210_priv *wil = container_of(work,
-			struct wil6210_priv, fw_error_worker);
+	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+						fw_error_worker);
 	struct wireless_dev *wdev = wil->wdev;
 
 	wil_dbg_misc(wil, "fw error worker\n");
 
-	if (no_fw_recovery)
-		return;
-
 	/* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
 	 * passed since last recovery attempt
 	 */
@@ -200,12 +245,15 @@
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_P2P_CLIENT:
 	case NL80211_IFTYPE_MONITOR:
-		wil_info(wil, "fw error recovery started (try %d)...\n",
+		wil_info(wil, "fw error recovery requested (try %d)...\n",
 			 wil->recovery_count);
-		wil_reset(wil);
+		if (!no_fw_recovery)
+			wil->recovery_state = fw_recovery_running;
+		if (0 != wil_wait_for_recovery(wil))
+			break;
 
-		/* need to re-allocate Rx ring after reset */
-		wil_rx_init(wil);
+		__wil_down(wil);
+		__wil_up(wil);
 		break;
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_P2P_GO:
@@ -220,6 +268,7 @@
 static int wil_find_free_vring(struct wil6210_priv *wil)
 {
 	int i;
+
 	for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
 		if (!wil->vring_tx[i].va)
 			return i;
@@ -254,14 +303,19 @@
 
 int wil_priv_init(struct wil6210_priv *wil)
 {
+	uint i;
+
 	wil_dbg_misc(wil, "%s()\n", __func__);
 
 	memset(wil->sta, 0, sizeof(wil->sta));
+	for (i = 0; i < WIL6210_MAX_CID; i++)
+		spin_lock_init(&wil->sta[i].tid_rx_lock);
 
 	mutex_init(&wil->mutex);
 	mutex_init(&wil->wmi_mutex);
 
 	init_completion(&wil->wmi_ready);
+	init_completion(&wil->wmi_call);
 
 	wil->pending_connect_cid = -1;
 	setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
@@ -274,6 +328,7 @@
 
 	INIT_LIST_HEAD(&wil->pending_wmi_ev);
 	spin_lock_init(&wil->wmi_ev_lock);
+	init_waitqueue_head(&wil->wq);
 
 	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi");
 	if (!wil->wmi_wq)
@@ -286,18 +341,24 @@
 	}
 
 	wil->last_fw_recovery = jiffies;
+	wil->itr_trsh = itr_trsh;
 
 	return 0;
 }
 
 void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
 {
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	del_timer_sync(&wil->connect_timer);
 	_wil6210_disconnect(wil, bssid);
 }
 
 void wil_priv_deinit(struct wil6210_priv *wil)
 {
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
+	wil_set_recovery_state(wil, fw_recovery_idle);
 	del_timer_sync(&wil->scan_timer);
 	cancel_work_sync(&wil->disconnect_worker);
 	cancel_work_sync(&wil->fw_error_worker);
@@ -309,7 +370,29 @@
 	destroy_workqueue(wil->wmi_wq);
 }
 
-static void wil_target_reset(struct wil6210_priv *wil)
+/* target operations */
+/* register read */
+#define R(a) ioread32(wil->csr + HOSTADDR(a))
+/* register write. wmb() to make sure it is completed */
+#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
+/* register set = read, OR, write */
+#define S(a, v) W(a, R(a) | v)
+/* register clear = read, AND with inverted, write */
+#define C(a, v) W(a, R(a) & ~v)
+
+static inline void wil_halt_cpu(struct wil6210_priv *wil)
+{
+	W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
+	W(RGF_USER_MAC_CPU_0,  BIT_USER_MAC_CPU_MAN_RST);
+}
+
+static inline void wil_release_cpu(struct wil6210_priv *wil)
+{
+	/* Start CPU */
+	W(RGF_USER_USER_CPU_0, 1);
+}
+
+static int wil_target_reset(struct wil6210_priv *wil)
 {
 	int delay = 0;
 	u32 hw_state;
@@ -318,57 +401,41 @@
 
 	wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name);
 
-	/* register read */
-#define R(a) ioread32(wil->csr + HOSTADDR(a))
-	/* register write */
-#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))
-	/* register set = read, OR, write */
-#define S(a, v) W(a, R(a) | v)
-	/* register clear = read, AND with inverted, write */
-#define C(a, v) W(a, R(a) & ~v)
-
 	wil->hw_version = R(RGF_USER_FW_REV_ID);
 	rev_id = wil->hw_version & 0xff;
 
 	/* Clear MAC link up */
 	S(RGF_HP_CTRL, BIT(15));
-	/* hpal_perst_from_pad_src_n_mask */
-	S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6));
-	/* car_perst_rst_src_n_mask */
-	S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7));
-	wmb(); /* order is important here */
+	S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
+	S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
+
+	wil_halt_cpu(wil);
+	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */
 
 	if (is_sparrow) {
 		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
-		wmb(); /* order is important here */
+		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
 	}
 
-	W(RGF_USER_MAC_CPU_0,  BIT(1)); /* mac_cpu_man_rst */
-	W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
-	wmb(); /* order is important here */
-
 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
-	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000B0 : 0x00000170);
-	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
-	wmb(); /* order is important here */
+	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170);
+	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
 
 	if (is_sparrow) {
 		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
-		wmb(); /* order is important here */
+		W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
 	}
 
 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
-	wmb(); /* order is important here */
 
 	if (is_sparrow) {
 		W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
 		/* reset A2 PCIE AHB */
 		W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
-
 	} else {
 		W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
 		if (rev_id == 1) {
@@ -378,21 +445,19 @@
 			W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
 			W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
 		}
-
 	}
 
 	/* TODO: check order here!!! Erez code is different */
 	W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
-	wmb(); /* order is important here */
 
-	/* wait until device ready */
+	/* wait until device ready. typical time is 200..250 msec */
 	do {
-		msleep(1);
+		msleep(RST_DELAY);
 		hw_state = R(RGF_USER_HW_MACHINE_STATE);
-		if (delay++ > 100) {
+		if (delay++ > RST_COUNT) {
 			wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
 				hw_state);
-			return;
+			return -ETIME;
 		}
 	} while (hw_state != HW_MACHINE_BOOT_DONE);
 
@@ -401,15 +466,35 @@
 		W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
 
 	C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
-	wmb(); /* order is important here */
 
-	wil_dbg_misc(wil, "Reset completed in %d ms\n", delay);
+	wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
+	return 0;
+}
+
+/**
+ * wil_set_itr_trsh: - apply interrupt coalescing params
+ */
+void wil_set_itr_trsh(struct wil6210_priv *wil)
+{
+	/* disable, use usec resolution */
+	W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EXT_TICK);
+
+	/* disable interrupt moderation for monitor
+	 * to get better timestamp precision
+	 */
+	if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR)
+		return;
+
+	wil_info(wil, "set ITR_TRSH = %d usec\n", wil->itr_trsh);
+	W(RGF_DMA_ITR_CNT_TRSH, wil->itr_trsh);
+	W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EN |
+	  BIT_DMA_ITR_CNT_CRL_EXT_TICK); /* start it */
+}
 
 #undef R
 #undef W
 #undef S
 #undef C
-}
 
 void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
 {
@@ -424,6 +509,7 @@
 {
 	ulong to = msecs_to_jiffies(1000);
 	ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
+
 	if (0 == left) {
 		wil_err(wil, "Firmware not ready\n");
 		return -ETIME;
@@ -443,15 +529,15 @@
 {
 	int rc;
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	WARN_ON(!mutex_is_locked(&wil->mutex));
+	WARN_ON(test_bit(wil_status_napi_en, &wil->status));
 
 	cancel_work_sync(&wil->disconnect_worker);
 	wil6210_disconnect(wil, NULL);
 
 	wil->status = 0; /* prevent NAPI from being scheduled */
-	if (test_bit(wil_status_napi_en, &wil->status)) {
-		napi_synchronize(&wil->napi_rx);
-	}
 
 	if (wil->scan_request) {
 		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
@@ -461,24 +547,50 @@
 		wil->scan_request = NULL;
 	}
 
-	wil6210_disable_irq(wil);
+	wil_mask_irq(wil);
 
 	wmi_event_flush(wil);
 
 	flush_workqueue(wil->wmi_wq_conn);
 	flush_workqueue(wil->wmi_wq);
 
-	/* TODO: put MAC in reset */
-	wil_target_reset(wil);
-
+	rc = wil_target_reset(wil);
 	wil_rx_fini(wil);
+	if (rc)
+		return rc;
+
+	if (!no_fw_load) {
+		wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME);
+		wil_halt_cpu(wil);
+		/* Loading f/w from the file */
+		rc = wil_request_firmware(wil, WIL_FW_NAME);
+		if (rc)
+			return rc;
+
+		/* clear any interrupts which on-card-firmware may have set */
+		wil6210_clear_irq(wil);
+		{ /* CAF_ICR - clear and mask */
+			u32 a = HOSTADDR(RGF_CAF_ICR) +
+				offsetof(struct RGF_ICR, ICR);
+			u32 m = HOSTADDR(RGF_CAF_ICR) +
+				offsetof(struct RGF_ICR, IMV);
+			u32 icr = ioread32(wil->csr + a);
+
+			iowrite32(icr, wil->csr + a); /* W1C */
+			iowrite32(~0, wil->csr + m);
+			wmb(); /* wait for completion */
+		}
+		wil_release_cpu(wil);
+	} else {
+		wil_info(wil, "Use firmware from on-card flash\n");
+	}
 
 	/* init after reset */
 	wil->pending_connect_cid = -1;
 	reinit_completion(&wil->wmi_ready);
+	reinit_completion(&wil->wmi_call);
 
-	/* TODO: release MAC reset */
-	wil6210_enable_irq(wil);
+	wil_unmask_irq(wil);
 
 	/* we just started MAC, wait for FW ready */
 	rc = wil_wait_for_fw_ready(wil);
@@ -489,6 +601,7 @@
 void wil_fw_error_recovery(struct wil6210_priv *wil)
 {
 	wil_dbg_misc(wil, "starting fw error recovery\n");
+	wil->recovery_state = fw_recovery_pending;
 	schedule_work(&wil->fw_error_worker);
 }
 
@@ -514,7 +627,7 @@
 	netif_carrier_off(ndev);
 }
 
-static int __wil_up(struct wil6210_priv *wil)
+int __wil_up(struct wil6210_priv *wil)
 {
 	struct net_device *ndev = wil_to_ndev(wil);
 	struct wireless_dev *wdev = wil->wdev;
@@ -560,11 +673,15 @@
 	/* MAC address - pre-requisite for other commands */
 	wmi_set_mac_address(wil, ndev->dev_addr);
 
-
+	wil_dbg_misc(wil, "NAPI enable\n");
 	napi_enable(&wil->napi_rx);
 	napi_enable(&wil->napi_tx);
 	set_bit(wil_status_napi_en, &wil->status);
 
+	if (wil->platform_ops.bus_request)
+		wil->platform_ops.bus_request(wil->platform_handle,
+					      WIL_MAX_BUS_REQUEST_KBPS);
+
 	return 0;
 }
 
@@ -572,6 +689,8 @@
 {
 	int rc;
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	mutex_lock(&wil->mutex);
 	rc = __wil_up(wil);
 	mutex_unlock(&wil->mutex);
@@ -579,13 +698,23 @@
 	return rc;
 }
 
-static int __wil_down(struct wil6210_priv *wil)
+int __wil_down(struct wil6210_priv *wil)
 {
+	int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
+			WAIT_FOR_DISCONNECT_INTERVAL_MS;
+
 	WARN_ON(!mutex_is_locked(&wil->mutex));
 
-	clear_bit(wil_status_napi_en, &wil->status);
-	napi_disable(&wil->napi_rx);
-	napi_disable(&wil->napi_tx);
+	if (wil->platform_ops.bus_request)
+		wil->platform_ops.bus_request(wil->platform_handle, 0);
+
+	wil_disable_irq(wil);
+	if (test_and_clear_bit(wil_status_napi_en, &wil->status)) {
+		napi_disable(&wil->napi_rx);
+		napi_disable(&wil->napi_tx);
+		wil_dbg_misc(wil, "NAPI disable\n");
+	}
+	wil_enable_irq(wil);
 
 	if (wil->scan_request) {
 		wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
@@ -595,7 +724,24 @@
 		wil->scan_request = NULL;
 	}
 
-	wil6210_disconnect(wil, NULL);
+	if (test_bit(wil_status_fwconnected, &wil->status) ||
+	    test_bit(wil_status_fwconnecting, &wil->status))
+		wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
+
+	/* make sure wil is idle (not connected) */
+	mutex_unlock(&wil->mutex);
+	while (iter--) {
+		int idle = !test_bit(wil_status_fwconnected, &wil->status) &&
+			   !test_bit(wil_status_fwconnecting, &wil->status);
+		if (idle)
+			break;
+		msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
+	}
+	mutex_lock(&wil->mutex);
+
+	if (!iter)
+		wil_err(wil, "timeout waiting for idle FW/HW\n");
+
 	wil_rx_fini(wil);
 
 	return 0;
@@ -605,6 +751,9 @@
 {
 	int rc;
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
+	wil_set_recovery_state(wil, fw_recovery_idle);
 	mutex_lock(&wil->mutex);
 	rc = __wil_down(wil);
 	mutex_unlock(&wil->mutex);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 7afce6e..2399651 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,11 +17,14 @@
 #include <linux/etherdevice.h>
 
 #include "wil6210.h"
+#include "txrx.h"
 
 static int wil_open(struct net_device *ndev)
 {
 	struct wil6210_priv *wil = ndev_to_wil(ndev);
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	return wil_up(wil);
 }
 
@@ -29,6 +32,8 @@
 {
 	struct wil6210_priv *wil = ndev_to_wil(ndev);
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	return wil_down(wil);
 }
 
@@ -36,8 +41,10 @@
 {
 	struct wil6210_priv *wil = ndev_to_wil(ndev);
 
-	if (new_mtu < 68 || new_mtu > IEEE80211_MAX_DATA_LEN_DMG)
+	if (new_mtu < 68 || new_mtu > (TX_BUF_LEN - ETH_HLEN)) {
+		wil_err(wil, "invalid MTU %d\n", new_mtu);
 		return -EINVAL;
+	}
 
 	wil_dbg_misc(wil, "change MTU %d -> %d\n", ndev->mtu, new_mtu);
 	ndev->mtu = new_mtu;
@@ -45,6 +52,17 @@
 	return 0;
 }
 
+static int wil_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+	struct wil6210_priv *wil = ndev_to_wil(ndev);
+
+	int ret = wil_ioctl(wil, ifr->ifr_data, cmd);
+
+	wil_dbg_misc(wil, "ioctl(0x%04x) -> %d\n", cmd, ret);
+
+	return ret;
+}
+
 static const struct net_device_ops wil_netdev_ops = {
 	.ndo_open		= wil_open,
 	.ndo_stop		= wil_stop,
@@ -52,6 +70,7 @@
 	.ndo_set_mac_address	= eth_mac_addr,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_change_mtu		= wil_change_mtu,
+	.ndo_do_ioctl		= wil_do_ioctl,
 };
 
 static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget)
@@ -121,6 +140,8 @@
 	wil->csr = csr;
 	wil->wdev = wdev;
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	rc = wil_priv_init(wil);
 	if (rc) {
 		dev_err(dev, "wil_priv_init failed\n");
@@ -140,6 +161,7 @@
 	}
 
 	ndev->netdev_ops = &wil_netdev_ops;
+	wil_set_ethtoolops(ndev);
 	ndev->ieee80211_ptr = wdev;
 	ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
 			    NETIF_F_SG | NETIF_F_GRO;
@@ -168,11 +190,17 @@
 void wil_if_free(struct wil6210_priv *wil)
 {
 	struct net_device *ndev = wil_to_ndev(wil);
+
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	if (!ndev)
 		return;
 
-	free_netdev(ndev);
 	wil_priv_deinit(wil);
+
+	wil_to_ndev(wil) = NULL;
+	free_netdev(ndev);
+
 	wil_wdev_free(wil);
 }
 
@@ -181,6 +209,8 @@
 	struct net_device *ndev = wil_to_ndev(wil);
 	int rc;
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	rc = register_netdev(ndev);
 	if (rc < 0) {
 		dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
@@ -196,5 +226,7 @@
 {
 	struct net_device *ndev = wil_to_ndev(wil);
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	unregister_netdev(ndev);
 }
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index d3fbfa2..66626a8 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/moduleparam.h>
+#include <linux/interrupt.h>
 
 #include "wil6210.h"
 
@@ -30,6 +31,28 @@
 module_param(debug_fw, bool, S_IRUGO);
 MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug");
 
+void wil_disable_irq(struct wil6210_priv *wil)
+{
+	int irq = wil->pdev->irq;
+
+	disable_irq(irq);
+	if (wil->n_msi == 3) {
+		disable_irq(irq + 1);
+		disable_irq(irq + 2);
+	}
+}
+
+void wil_enable_irq(struct wil6210_priv *wil)
+{
+	int irq = wil->pdev->irq;
+
+	enable_irq(irq);
+	if (wil->n_msi == 3) {
+		enable_irq(irq + 1);
+		enable_irq(irq + 2);
+	}
+}
+
 /* Bus ops */
 static int wil_if_pcie_enable(struct wil6210_priv *wil)
 {
@@ -41,6 +64,8 @@
 	 */
 	int msi_only = pdev->msi_enabled;
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	pdev->msi_enabled = 0;
 
 	pci_set_master(pdev);
@@ -107,6 +132,8 @@
 {
 	struct pci_dev *pdev = wil->pdev;
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	pci_clear_master(pdev);
 	/* disable and release IRQ */
 	wil6210_fini_irq(wil, pdev->irq);
@@ -180,6 +207,10 @@
 	wil->board = board;
 
 	wil6210_clear_irq(wil);
+
+	wil->platform_handle =
+			wil_platform_init(&pdev->dev, &wil->platform_ops);
+
 	/* FW should raise IRQ when ready */
 	rc = wil_if_pcie_enable(wil);
 	if (rc) {
@@ -204,6 +235,8 @@
  bus_disable:
 	wil_if_pcie_disable(wil);
  if_free:
+	if (wil->platform_ops.uninit)
+		wil->platform_ops.uninit(wil->platform_handle);
 	wil_if_free(wil);
  err_iounmap:
 	pci_iounmap(pdev, csr);
@@ -218,12 +251,17 @@
 static void wil_pcie_remove(struct pci_dev *pdev)
 {
 	struct wil6210_priv *wil = pci_get_drvdata(pdev);
+	void __iomem *csr = wil->csr;
+
+	wil_dbg_misc(wil, "%s()\n", __func__);
 
 	wil6210_debugfs_remove(wil);
-	wil_if_pcie_disable(wil);
 	wil_if_remove(wil);
+	wil_if_pcie_disable(wil);
+	if (wil->platform_ops.uninit)
+		wil->platform_ops.uninit(wil->platform_handle);
 	wil_if_free(wil);
-	pci_iounmap(pdev, wil->csr);
+	pci_iounmap(pdev, csr);
 	pci_release_region(pdev, 0);
 	pci_disable_device(pdev);
 }
@@ -243,6 +281,8 @@
 	  .driver_data = (kernel_ulong_t)&wil_board_marlon },
 	{ PCI_DEVICE(0x1ae9, 0x0310),
 	  .driver_data = (kernel_ulong_t)&wil_board_sparrow },
+	{ PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */
+	  .driver_data = (kernel_ulong_t)&wil_board_sparrow },
 	{ /* end: all zeroes */	},
 };
 MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 180ca47..489cb73 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -1,3 +1,19 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
 #include "wil6210.h"
 #include "txrx.h"
 
@@ -82,22 +98,25 @@
 	int mid = wil_rxdesc_mid(d);
 	u16 seq = wil_rxdesc_seq(d);
 	struct wil_sta_info *sta = &wil->sta[cid];
-	struct wil_tid_ampdu_rx *r = sta->tid_rx[tid];
+	struct wil_tid_ampdu_rx *r;
 	u16 hseq;
 	int index;
+	unsigned long flags;
 
 	wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
 		     mid, cid, tid, seq);
 
+	spin_lock_irqsave(&sta->tid_rx_lock, flags);
+
+	r = sta->tid_rx[tid];
 	if (!r) {
+		spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
 		wil_netif_rx_any(skb, ndev);
 		return;
 	}
 
 	hseq = r->head_seq_num;
 
-	spin_lock(&r->reorder_lock);
-
 	/** Due to the race between WMI events, where BACK establishment
 	 * reported, and data Rx, few packets may be pass up before reorder
 	 * buffer get allocated. Catch up by pretending SSN is what we
@@ -160,13 +179,14 @@
 	wil_reorder_release(wil, r);
 
 out:
-	spin_unlock(&r->reorder_lock);
+	spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
 }
 
 struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
 						int size, u16 ssn)
 {
 	struct wil_tid_ampdu_rx *r = kzalloc(sizeof(*r), GFP_KERNEL);
+
 	if (!r)
 		return NULL;
 
@@ -181,7 +201,6 @@
 		return NULL;
 	}
 
-	spin_lock_init(&r->reorder_lock);
 	r->ssn = ssn;
 	r->head_seq_num = ssn;
 	r->buf_size = size;
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index d346794..2936ef0 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -52,6 +52,7 @@
 {
 	return wil_vring_next_tail(vring) == vring->swhead;
 }
+
 /*
  * Available space in Tx Vring
  */
@@ -86,6 +87,8 @@
 	size_t sz = vring->size * sizeof(vring->va[0]);
 	uint i;
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	BUILD_BUG_ON(sizeof(vring->va[0]) != 32);
 
 	vring->swhead = 0;
@@ -110,7 +113,8 @@
 	 * we can use any
 	 */
 	for (i = 0; i < vring->size; i++) {
-		volatile struct vring_tx_desc *_d = &(vring->va[i].tx);
+		volatile struct vring_tx_desc *_d = &vring->va[i].tx;
+
 		_d->dma.status = TX_DMA_STATUS_DU;
 	}
 
@@ -125,6 +129,7 @@
 {
 	dma_addr_t pa = wil_desc_addr(&d->dma.addr);
 	u16 dmalen = le16_to_cpu(d->dma.length);
+
 	switch (ctx->mapped_as) {
 	case wil_mapped_as_single:
 		dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE);
@@ -143,6 +148,18 @@
 	struct device *dev = wil_to_dev(wil);
 	size_t sz = vring->size * sizeof(vring->va[0]);
 
+	if (tx) {
+		int vring_index = vring - wil->vring_tx;
+
+		wil_dbg_misc(wil, "free Tx vring %d [%d] 0x%p:%pad 0x%p\n",
+			     vring_index, vring->size, vring->va,
+			     &vring->pa, vring->ctx);
+	} else {
+		wil_dbg_misc(wil, "free Rx vring [%d] 0x%p:%pad 0x%p\n",
+			     vring->size, vring->va,
+			     &vring->pa, vring->ctx);
+	}
+
 	while (!wil_vring_is_empty(vring)) {
 		dma_addr_t pa;
 		u16 dmalen;
@@ -191,11 +208,12 @@
 	struct device *dev = wil_to_dev(wil);
 	unsigned int sz = RX_BUF_LEN;
 	struct vring_rx_desc dd, *d = &dd;
-	volatile struct vring_rx_desc *_d = &(vring->va[i].rx);
+	volatile struct vring_rx_desc *_d = &vring->va[i].rx;
 	dma_addr_t pa;
 
 	/* TODO align */
 	struct sk_buff *skb = dev_alloc_skb(sz + headroom);
+
 	if (unlikely(!skb))
 		return -ENOMEM;
 
@@ -274,9 +292,11 @@
 			 */
 			int len = min_t(int, 8 + sizeof(phy_data),
 					wil_rxdesc_phy_length(d));
+
 			if (len > 8) {
 				void *p = skb_tail_pointer(skb);
 				void *pa = PTR_ALIGN(p, 8);
+
 				if (skb_tailroom(skb) >= len + (pa - p)) {
 					phy_length = len - 8;
 					memcpy(phy_data, pa, phy_length);
@@ -372,13 +392,12 @@
 	int cid;
 	struct wil_net_stats *stats;
 
-
 	BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb));
 
 	if (wil_vring_is_empty(vring))
 		return NULL;
 
-	_d = &(vring->va[vring->swhead].rx);
+	_d = &vring->va[vring->swhead].rx;
 	if (!(_d->dma.status & RX_DMA_STATUS_DU)) {
 		/* it is not error, we just reached end of Rx done area */
 		return NULL;
@@ -414,7 +433,6 @@
 	cid = wil_rxdesc_cid(d);
 	stats = &wil->sta[cid].stats;
 	stats->last_mcs_rx = wil_rxdesc_mcs(d);
-	wil->stats.last_mcs_rx = stats->last_mcs_rx;
 
 	/* use radiotap header only if required */
 	if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
@@ -533,7 +551,7 @@
 			[GRO_NORMAL]		= "GRO_NORMAL",
 			[GRO_DROP]		= "GRO_DROP",
 		};
-		wil_dbg_txrx(wil, "Rx complete %d bytes => %s,\n",
+		wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n",
 			     len, gro_res_str[rc]);
 	}
 }
@@ -574,7 +592,6 @@
 			else
 				wil_netif_rx_any(skb, ndev);
 		}
-
 	}
 	wil_rx_refill(wil, v->size);
 }
@@ -584,6 +601,8 @@
 	struct vring *vring = &wil->vring_rx;
 	int rc;
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	if (vring->va) {
 		wil_err(wil, "Rx ring already allocated\n");
 		return -EINVAL;
@@ -613,6 +632,8 @@
 {
 	struct vring *vring = &wil->vring_rx;
 
+	wil_dbg_misc(wil, "%s()\n", __func__);
+
 	if (vring->va)
 		wil_vring_free(wil, vring, 0);
 }
@@ -647,6 +668,9 @@
 	struct vring *vring = &wil->vring_tx[id];
 	struct vring_tx_data *txdata = &wil->vring_tx_data[id];
 
+	wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__,
+		     cmd.vring_cfg.tx_sw_ring.max_mpdu_size);
+
 	if (vring->va) {
 		wil_err(wil, "Tx ring [%d] already allocated\n", id);
 		rc = -EINVAL;
@@ -696,6 +720,8 @@
 	if (!vring->va)
 		return;
 
+	wil_dbg_misc(wil, "%s() id=%d\n", __func__, id);
+
 	/* make sure NAPI won't touch this vring */
 	wil->vring_tx_data[id].enabled = 0;
 	if (test_bit(wil_status_napi_en, &wil->status))
@@ -722,6 +748,7 @@
 	for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
 		if (wil->vring2cid_tid[i][0] == cid) {
 			struct vring *v = &wil->vring_tx[i];
+
 			wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
 				     __func__, eth->h_dest, i);
 			if (v->va) {
@@ -741,6 +768,7 @@
 {
 	struct ethhdr *eth = (void *)skb->data;
 	int cid = wil->vring2cid_tid[vring_index][0];
+
 	memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN);
 }
 
@@ -751,7 +779,7 @@
  * duplicate skb and send it to other active vrings
  */
 static struct vring *wil_tx_bcast(struct wil6210_priv *wil,
-				       struct sk_buff *skb)
+				  struct sk_buff *skb)
 {
 	struct vring *v, *v2;
 	struct sk_buff *skb2;
@@ -834,8 +862,8 @@
 }
 
 static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,
-				struct vring_tx_desc *d,
-				struct sk_buff *skb)
+					 struct vring_tx_desc *d,
+					 struct sk_buff *skb)
 {
 	int protocol;
 
@@ -903,10 +931,9 @@
 			1 + nr_frags);
 		return -ENOMEM;
 	}
-	_d = &(vring->va[i].tx);
+	_d = &vring->va[i].tx;
 
-	pa = dma_map_single(dev, skb->data,
-			skb_headlen(skb), DMA_TO_DEVICE);
+	pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
 
 	wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb),
 		     skb->data, &pa);
@@ -935,10 +962,11 @@
 		const struct skb_frag_struct *frag =
 				&skb_shinfo(skb)->frags[f];
 		int len = skb_frag_size(frag);
+
 		i = (swhead + f + 1) % vring->size;
-		_d = &(vring->va[i].tx);
+		_d = &vring->va[i].tx;
 		pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
-				DMA_TO_DEVICE);
+				      DMA_TO_DEVICE);
 		if (unlikely(dma_mapping_error(dev, pa)))
 			goto dma_error;
 		vring->ctx[i].mapped_as = wil_mapped_as_page;
@@ -983,7 +1011,7 @@
 
 		i = (swhead + f) % vring->size;
 		ctx = &vring->ctx[i];
-		_d = &(vring->va[i].tx);
+		_d = &vring->va[i].tx;
 		*d = *_d;
 		_d->dma.status = TX_DMA_STATUS_DU;
 		wil_txdesc_unmap(dev, d, ctx);
@@ -997,7 +1025,6 @@
 	return -EINVAL;
 }
 
-
 netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct wil6210_priv *wil = ndev_to_wil(ndev);
@@ -1025,15 +1052,15 @@
 	pr_once_fw = false;
 
 	/* find vring */
-	if (is_unicast_ether_addr(eth->h_dest)) {
+	if (is_unicast_ether_addr(eth->h_dest))
 		vring = wil_find_tx_vring(wil, skb);
-	} else {
+	else
 		vring = wil_tx_bcast(wil, skb);
-	}
 	if (!vring) {
 		wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
 		goto drop;
 	}
+
 	/* set up vring entry */
 	rc = wil_tx_vring(wil, vring, skb);
 
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index bc5706a..de04671 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -20,9 +20,9 @@
 #define BUF_SW_OWNED    (1)
 #define BUF_HW_OWNED    (0)
 
-/* size of max. Rx packet */
-#define RX_BUF_LEN      (2048)
-#define TX_BUF_LEN      (2048)
+/* size of max. Tx/Rx buffers, as supported by FW */
+#define RX_BUF_LEN      (2242)
+#define TX_BUF_LEN      (2242)
 /* how many bytes to reserve for rtap header? */
 #define WIL6210_RTAP_SIZE (128)
 
@@ -237,7 +237,6 @@
 #define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2
 #define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000 /* L4 type: 0-UDP, 2-TCP */
 
-
 #define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_POS 0
 #define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_LEN 7
 #define DMA_CFG_DESC_TX_OFFLOAD_CFG_MAC_LEN_MSK 0x7F /* MAC hdr len */
@@ -246,7 +245,6 @@
 #define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_LEN 1
 #define DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_MSK 0x80 /* 1-IPv4, 0-IPv6 */
 
-
 #define TX_DMA_STATUS_DU         BIT(0)
 
 struct vring_tx_dma {
@@ -347,7 +345,6 @@
 #define RX_DMA_ERROR_L3_ERR   BIT(4)
 #define RX_DMA_ERROR_L4_ERR   BIT(5)
 
-
 /* Status field */
 #define RX_DMA_STATUS_DU         BIT(0)
 #define RX_DMA_STATUS_ERROR      BIT(2)
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 67e9624..ce6488e 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -21,8 +21,14 @@
 #include <linux/wireless.h>
 #include <net/cfg80211.h>
 #include <linux/timex.h>
+#include "wil_platform.h"
+
+extern bool no_fw_recovery;
 
 #define WIL_NAME "wil6210"
+#define WIL_FW_NAME "wil6210.fw"
+
+#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
 
 struct wil_board {
 	int board;
@@ -47,7 +53,9 @@
 #define WIL6210_MAX_TX_RINGS	(24) /* HW limit */
 #define WIL6210_MAX_CID		(8) /* HW limit */
 #define WIL6210_NAPI_BUDGET	(16) /* arbitrary */
-#define WIL6210_ITR_TRSH	(10000) /* arbitrary - about 15 IRQs/msec */
+/* Max supported by wil6210 value for interrupt threshold is 5sec. */
+#define WIL6210_ITR_TRSH_MAX (5000000)
+#define WIL6210_ITR_TRSH_DEFAULT	(300) /* usec */
 #define WIL6210_FW_RECOVERY_RETRIES	(5) /* try to recover this many times */
 #define WIL6210_FW_RECOVERY_TO	msecs_to_jiffies(5000)
 #define WIL6210_SCAN_TO		msecs_to_jiffies(10000)
@@ -86,22 +94,29 @@
 
 /* registers - FW addresses */
 #define RGF_USER_USAGE_1		(0x880004)
+#define RGF_USER_USAGE_6		(0x880018)
 #define RGF_USER_HW_MACHINE_STATE	(0x8801dc)
 	#define HW_MACHINE_BOOT_DONE	(0x3fffffd)
 #define RGF_USER_USER_CPU_0		(0x8801e0)
+	#define BIT_USER_USER_CPU_MAN_RST	BIT(1) /* user_cpu_man_rst */
 #define RGF_USER_MAC_CPU_0		(0x8801fc)
+	#define BIT_USER_MAC_CPU_MAN_RST	BIT(1) /* mac_cpu_man_rst */
 #define RGF_USER_USER_SCRATCH_PAD	(0x8802bc)
 #define RGF_USER_FW_REV_ID		(0x880a8c) /* chip revision */
 #define RGF_USER_CLKS_CTL_0		(0x880abc)
+	#define BIT_USER_CLKS_CAR_AHB_SW_SEL	BIT(1) /* ref clk/PLL */
 	#define BIT_USER_CLKS_RST_PWGD	BIT(11) /* reset on "power good" */
 #define RGF_USER_CLKS_CTL_SW_RST_VEC_0	(0x880b04)
 #define RGF_USER_CLKS_CTL_SW_RST_VEC_1	(0x880b08)
 #define RGF_USER_CLKS_CTL_SW_RST_VEC_2	(0x880b0c)
 #define RGF_USER_CLKS_CTL_SW_RST_VEC_3	(0x880b10)
 #define RGF_USER_CLKS_CTL_SW_RST_MASK_0	(0x880b14)
+	#define BIT_HPAL_PERST_FROM_PAD	BIT(6)
+	#define BIT_CAR_PERST_RST	BIT(7)
 #define RGF_USER_USER_ICR		(0x880b4c) /* struct RGF_ICR */
 	#define BIT_USER_USER_ICR_SW_INT_2	BIT(18)
 #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0	(0x880c18)
+#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1	(0x880c2c)
 
 #define RGF_DMA_EP_TX_ICR		(0x881bb4) /* struct RGF_ICR */
 	#define BIT_DMA_EP_TX_ICR_TX_DONE	BIT(0)
@@ -133,6 +148,11 @@
 #define RGF_HP_CTRL			(0x88265c)
 #define RGF_PCIE_LOS_COUNTER_CTL	(0x882dc4)
 
+/* MAC timer, usec, for packet lifetime */
+#define RGF_MAC_MTRL_COUNTER_0		(0x886aa8)
+
+#define RGF_CAF_ICR			(0x88946c) /* struct RGF_ICR */
+
 /* popular locations */
 #define HOST_MBOX   HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
 #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
@@ -151,6 +171,7 @@
 	u32 host; /* PCI/Host address - BAR0 + 0x880000 */
 	const char *name; /* for debugfs */
 };
+
 /* array size should be in sync with actual definition in the wmi.c */
 extern const struct fw_map fw_mapping[7];
 
@@ -300,18 +321,12 @@
  * @timeout: reset timer value (in TUs).
  * @dialog_token: dialog token for aggregation session
  * @rcu_head: RCU head used for freeing this struct
- * @reorder_lock: serializes access to reorder buffer, see below.
  *
  * This structure's lifetime is managed by RCU, assignments to
  * the array holding it must hold the aggregation mutex.
  *
- * The @reorder_lock is used to protect the members of this
- * struct, except for @timeout, @buf_size and @dialog_token,
- * which are constant across the lifetime of the struct (the
- * dialog token being used only for debugging).
  */
 struct wil_tid_ampdu_rx {
-	spinlock_t reorder_lock; /* see above */
 	struct sk_buff **reorder_buf;
 	unsigned long *reorder_time;
 	struct timer_list session_timer;
@@ -327,17 +342,6 @@
 	bool first_time; /* is it 1-st time this buffer used? */
 };
 
-struct wil6210_stats {
-	u64 tsf;
-	u32 snr;
-	u16 last_mcs_rx;
-	u16 bf_mcs; /* last BF, used for Tx */
-	u16 my_rx_sector;
-	u16 my_tx_sector;
-	u16 peer_rx_sector;
-	u16 peer_tx_sector;
-};
-
 enum wil_sta_status {
 	wil_sta_unused = 0,
 	wil_sta_conn_pending = 1,
@@ -371,10 +375,17 @@
 	bool data_port_open; /* can send any data, not only EAPOL */
 	/* Rx BACK */
 	struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
+	spinlock_t tid_rx_lock; /* guarding tid_rx array */
 	unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)];
 	unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)];
 };
 
+enum {
+	fw_recovery_idle = 0,
+	fw_recovery_pending = 1,
+	fw_recovery_running = 2,
+};
+
 struct wil6210_priv {
 	struct pci_dev *pdev;
 	int n_msi;
@@ -385,18 +396,22 @@
 	u32 hw_version;
 	struct wil_board *board;
 	u8 n_mids; /* number of additional MIDs as reported by FW */
-	int recovery_count; /* num of FW recovery attempts in a short time */
+	u32 recovery_count; /* num of FW recovery attempts in a short time */
+	u32 recovery_state; /* FW recovery state machine */
 	unsigned long last_fw_recovery; /* jiffies of last fw recovery */
+	wait_queue_head_t wq; /* for all wait_event() use */
 	/* profile */
 	u32 monitor_flags;
 	u32 secure_pcp; /* create secure PCP? */
 	int sinfo_gen;
+	u32 itr_trsh;
 	/* cached ISR registers */
 	u32 isr_misc;
 	/* mailbox related */
 	struct mutex wmi_mutex;
 	struct wil6210_mbox_ctl mbox_ctl;
 	struct completion wmi_ready;
+	struct completion wmi_call;
 	u16 wmi_seq;
 	u16 reply_id; /**< wait for this WMI event */
 	void *reply_buf;
@@ -430,11 +445,13 @@
 
 	struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
 	/* statistics */
-	struct wil6210_stats stats;
 	atomic_t isr_count_rx, isr_count_tx;
 	/* debugfs */
 	struct dentry *debug;
 	struct debugfs_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
+
+	void *platform_handle;
+	struct wil_platform_ops platform_ops;
 };
 
 #define wil_to_wiphy(i) (i->wdev->wiphy)
@@ -444,10 +461,11 @@
 #define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w))
 #define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
 #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
+#define wil_to_pcie_dev(i) (&i->pdev->dev)
 
-int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
-int wil_err(struct wil6210_priv *wil, const char *fmt, ...);
-int wil_info(struct wil6210_priv *wil, const char *fmt, ...);
+void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
+void wil_err(struct wil6210_priv *wil, const char *fmt, ...);
+void wil_info(struct wil6210_priv *wil, const char *fmt, ...);
 #define wil_dbg(wil, fmt, arg...) do { \
 	netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
 	wil_dbg_trace(wil, fmt, ##arg); \
@@ -458,6 +476,7 @@
 #define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
 #define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg)
 
+#if defined(CONFIG_DYNAMIC_DEBUG)
 #define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize,	\
 			  groupsize, buf, len, ascii)		\
 			  print_hex_dump_debug("DBG[TXRX]" prefix_str,\
@@ -469,6 +488,19 @@
 			 print_hex_dump_debug("DBG[ WMI]" prefix_str,\
 					prefix_type, rowsize,	\
 					groupsize, buf, len, ascii)
+#else /* defined(CONFIG_DYNAMIC_DEBUG) */
+static inline
+void wil_hex_dump_txrx(const char *prefix_str, int prefix_type, int rowsize,
+		       int groupsize, const void *buf, size_t len, bool ascii)
+{
+}
+
+static inline
+void wil_hex_dump_wmi(const char *prefix_str, int prefix_type, int rowsize,
+		      int groupsize, const void *buf, size_t len, bool ascii)
+{
+}
+#endif /* defined(CONFIG_DYNAMIC_DEBUG) */
 
 void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
 			  size_t count);
@@ -482,13 +514,18 @@
 int wil_priv_init(struct wil6210_priv *wil);
 void wil_priv_deinit(struct wil6210_priv *wil);
 int wil_reset(struct wil6210_priv *wil);
+void wil_set_itr_trsh(struct wil6210_priv *wil);
 void wil_fw_error_recovery(struct wil6210_priv *wil);
+void wil_set_recovery_state(struct wil6210_priv *wil, int state);
 void wil_link_on(struct wil6210_priv *wil);
 void wil_link_off(struct wil6210_priv *wil);
 int wil_up(struct wil6210_priv *wil);
+int __wil_up(struct wil6210_priv *wil);
 int wil_down(struct wil6210_priv *wil);
+int __wil_down(struct wil6210_priv *wil);
 void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
 int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
+void wil_set_ethtoolops(struct net_device *ndev);
 
 void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
 void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
@@ -519,8 +556,10 @@
 void wil6210_clear_irq(struct wil6210_priv *wil);
 int wil6210_init_irq(struct wil6210_priv *wil, int irq);
 void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
-void wil6210_disable_irq(struct wil6210_priv *wil);
-void wil6210_enable_irq(struct wil6210_priv *wil);
+void wil_mask_irq(struct wil6210_priv *wil);
+void wil_unmask_irq(struct wil6210_priv *wil);
+void wil_disable_irq(struct wil6210_priv *wil);
+void wil_enable_irq(struct wil6210_priv *wil);
 int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 			 struct cfg80211_mgmt_tx_params *params,
 			 u64 *cookie);
@@ -556,4 +595,7 @@
 
 int wil_iftype_nl2wmi(enum nl80211_iftype type);
 
+int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd);
+int wil_request_firmware(struct wil6210_priv *wil, const char *name);
+
 #endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c
new file mode 100644
index 0000000..10d96e9
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "linux/device.h"
+#include "wil_platform.h"
+
+#ifdef CPTCFG_WIL6210_PLATFORM_MSM
+#include "wil_platform_msm.h"
+#endif
+
+/**
+ * wil_platform_init() - wil6210 platform module init
+ *
+ * The function must be called before all other functions in this module.
+ * It returns a handle which is used with the rest of the API
+ *
+ */
+void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops)
+{
+	void *handle = NULL;
+
+	if (!ops) {
+		dev_err(dev, "Invalid parameter. Cannot init platform module\n");
+		return NULL;
+	}
+
+#ifdef CPTCFG_WIL6210_PLATFORM_MSM
+	handle = wil_platform_msm_init(dev, ops);
+	if (handle)
+		return handle;
+#endif
+
+	/* other platform specific init functions should be called here */
+
+	return handle;
+}
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h
new file mode 100644
index 0000000..158c73b
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WIL_PLATFORM_H__
+#define __WIL_PLATFORM_H__
+
+struct device;
+
+/**
+ * struct wil_platform_ops - wil platform module callbacks
+ */
+struct wil_platform_ops {
+	int (*bus_request)(void *handle, uint32_t kbps /* KBytes/Sec */);
+	int (*suspend)(void *handle);
+	int (*resume)(void *handle);
+	void (*uninit)(void *handle);
+};
+
+void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops);
+
+#endif /* __WIL_PLATFORM_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.c b/drivers/net/wireless/ath/wil6210/wil_platform_msm.c
new file mode 100644
index 0000000..b354a74
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil_platform_msm.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/msm-bus.h>
+
+#include "wil_platform.h"
+#include "wil_platform_msm.h"
+
+/**
+ * struct wil_platform_msm - wil6210 msm platform module info
+ *
+ * @dev: device object
+ * @msm_bus_handle: handle for using msm_bus API
+ * @pdata: bus scale info retrieved from DT
+ */
+struct wil_platform_msm {
+	struct device *dev;
+	uint32_t msm_bus_handle;
+	struct msm_bus_scale_pdata *pdata;
+};
+
+#define KBTOB(a) (a * 1000ULL)
+
+/**
+ * wil_platform_get_pdata() - Generate bus client data from device tree
+ * provided by clients.
+ *
+ * dev: device object
+ * of_node: Device tree node to extract information from
+ *
+ * The function returns a valid pointer to the allocated bus-scale-pdata
+ * if the vectors were correctly read from the client's device node.
+ * Any error in reading or parsing the device node will return NULL
+ * to the caller.
+ */
+static struct msm_bus_scale_pdata *wil_platform_get_pdata(
+		struct device *dev,
+		struct device_node *of_node)
+{
+	struct msm_bus_scale_pdata *pdata;
+	struct msm_bus_paths *usecase;
+	int i, j, ret, len;
+	unsigned int num_usecases, num_paths, mem_size;
+	const uint32_t *vec_arr;
+	struct msm_bus_vectors *vectors;
+
+	/* first read num_usecases and num_paths so we can calculate
+	 * amount of memory to allocate
+	 */
+	ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases",
+				   &num_usecases);
+	if (ret) {
+		dev_err(dev, "Error: num-usecases not found\n");
+		return NULL;
+	}
+
+	ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths",
+				   &num_paths);
+	if (ret) {
+		dev_err(dev, "Error: num_paths not found\n");
+		return NULL;
+	}
+
+	/* pdata memory layout:
+	 *   msm_bus_scale_pdata
+	 *   msm_bus_paths[num_usecases]
+	 *   msm_bus_vectors[num_usecases][num_paths]
+	 */
+	mem_size = sizeof(struct msm_bus_scale_pdata) +
+		   sizeof(struct msm_bus_paths) * num_usecases +
+		   sizeof(struct msm_bus_vectors) * num_usecases * num_paths;
+
+	pdata = kzalloc(mem_size, GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	ret = of_property_read_string(of_node, "qcom,msm-bus,name",
+				      &pdata->name);
+	if (ret) {
+		dev_err(dev, "Error: Client name not found\n");
+		goto err;
+	}
+
+	if (of_property_read_bool(of_node, "qcom,msm-bus,active-only")) {
+		pdata->active_only = 1;
+	} else {
+		dev_info(dev, "active_only flag absent.\n");
+		dev_info(dev, "Using dual context by default\n");
+	}
+
+	pdata->num_usecases = num_usecases;
+	pdata->usecase = (struct msm_bus_paths *)(pdata + 1);
+
+	vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len);
+	if (vec_arr == NULL) {
+		dev_err(dev, "Error: Vector array not found\n");
+		goto err;
+	}
+
+	if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) {
+		dev_err(dev, "Error: Length-error on getting vectors\n");
+		goto err;
+	}
+
+	vectors = (struct msm_bus_vectors *)(pdata->usecase + num_usecases);
+	for (i = 0; i < num_usecases; i++) {
+		usecase = &pdata->usecase[i];
+		usecase->num_paths = num_paths;
+		usecase->vectors = &vectors[i];
+
+		for (j = 0; j < num_paths; j++) {
+			int index = ((i * num_paths) + j) * 4;
+
+			usecase->vectors[j].src = be32_to_cpu(vec_arr[index]);
+			usecase->vectors[j].dst =
+				be32_to_cpu(vec_arr[index + 1]);
+			usecase->vectors[j].ab = (uint64_t)
+				KBTOB(be32_to_cpu(vec_arr[index + 2]));
+			usecase->vectors[j].ib = (uint64_t)
+				KBTOB(be32_to_cpu(vec_arr[index + 3]));
+		}
+	}
+
+	return pdata;
+
+err:
+	kfree(pdata);
+
+	return NULL;
+}
+
+/* wil_platform API (callbacks) */
+
+static int wil_platform_bus_request(void *handle,
+				    uint32_t kbps /* KBytes/Sec */)
+{
+	int rc, i;
+	struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
+	int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */
+	struct msm_bus_paths *usecase;
+	uint32_t usecase_kbps;
+	uint32_t min_kbps = ~0;
+
+	/* find the lowest usecase that is bigger than requested kbps */
+	for (i = 0; i < msm->pdata->num_usecases; i++) {
+		usecase = &msm->pdata->usecase[i];
+		/* assume we have single path (vectors[0]). If we ever
+		 * have multiple paths, need to define the behavior */
+		usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000);
+		if (usecase_kbps >= kbps && usecase_kbps < min_kbps) {
+			min_kbps = usecase_kbps;
+			vote = i;
+		}
+	}
+
+	rc = msm_bus_scale_client_update_request(msm->msm_bus_handle, vote);
+	if (rc)
+		dev_err(msm->dev, "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n",
+			kbps, vote, rc);
+	else
+		/* TOOD: remove */
+		dev_info(msm->dev, "msm_bus_scale_client_update_request succeeded. kbps=%d vote=%d\n",
+			 kbps, vote);
+
+	return rc;
+}
+
+static void wil_platform_uninit(void *handle)
+{
+	struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
+
+	dev_info(msm->dev, "wil_platform_uninit\n");
+
+	if (msm->msm_bus_handle)
+		msm_bus_scale_unregister_client(msm->msm_bus_handle);
+
+	kfree(msm->pdata);
+	kfree(msm);
+}
+
+static int wil_platform_msm_bus_register(struct wil_platform_msm *msm,
+					 struct device_node *node)
+{
+	msm->pdata = wil_platform_get_pdata(msm->dev, node);
+	if (!msm->pdata) {
+		dev_err(msm->dev, "Failed getting DT info\n");
+		return -EINVAL;
+	}
+
+	msm->msm_bus_handle = msm_bus_scale_register_client(msm->pdata);
+	if (!msm->msm_bus_handle) {
+		dev_err(msm->dev, "Failed msm_bus registration\n");
+		return -EINVAL;
+	}
+
+	dev_info(msm->dev, "msm_bus registration succeeded! handle 0x%x\n",
+		 msm->msm_bus_handle);
+
+	return 0;
+}
+
+/**
+ * wil_platform_msm_init() - wil6210 msm platform module init
+ *
+ * The function must be called before all other functions in this module.
+ * It returns a handle which is used with the rest of the API
+ *
+ */
+void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops)
+{
+	struct device_node *of_node;
+	struct wil_platform_msm *msm;
+	int rc;
+
+	of_node = of_find_compatible_node(NULL, NULL, "qcom,wil6210");
+	if (!of_node) {
+		/* this could mean non-msm platform */
+		dev_err(dev, "DT node not found\n");
+		return NULL;
+	}
+
+	msm = kzalloc(sizeof(*msm), GFP_KERNEL);
+	if (!msm)
+		return NULL;
+
+	msm->dev = dev;
+
+	/* register with msm_bus module for scaling requests */
+	rc = wil_platform_msm_bus_register(msm, of_node);
+	if (rc)
+		goto cleanup;
+
+	memset(ops, 0, sizeof(*ops));
+	ops->bus_request = wil_platform_bus_request;
+	ops->uninit = wil_platform_uninit;
+
+	return (void *)msm;
+
+cleanup:
+	kfree(msm);
+	return NULL;
+}
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.h b/drivers/net/wireless/ath/wil6210/wil_platform_msm.h
new file mode 100644
index 0000000..2f2229e
--- /dev/null
+++ b/drivers/net/wireless/ath/wil6210/wil_platform_msm.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WIL_PLATFORM__MSM_H__
+#define __WIL_PLATFORM_MSM_H__
+
+#include "wil_platform.h"
+
+void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops);
+
+#endif /* __WIL_PLATFORM__MSM_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 1d1d0af..4311df9 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <linux/moduleparam.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 
@@ -22,6 +23,10 @@
 #include "wmi.h"
 #include "trace.h"
 
+static uint max_assoc_sta = 1;
+module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
+
 /**
  * WMI event receiving - theory of operations
  *
@@ -152,6 +157,7 @@
 		 struct wil6210_mbox_hdr *hdr)
 {
 	void __iomem *src = wmi_buffer(wil, ptr);
+
 	if (!src)
 		return -EINVAL;
 
@@ -273,6 +279,7 @@
 	struct net_device *ndev = wil_to_ndev(wil);
 	struct wireless_dev *wdev = wil->wdev;
 	struct wmi_ready_event *evt = d;
+
 	wil->fw_version = le32_to_cpu(evt->sw_version);
 	wil->n_mids = evt->numof_additional_mids;
 
@@ -292,8 +299,9 @@
 {
 	wil_dbg_wmi(wil, "WMI: got FW ready event\n");
 
+	wil_set_recovery_state(wil, fw_recovery_idle);
 	set_bit(wil_status_fwready, &wil->status);
-	/* reuse wmi_ready for the firmware ready indication */
+	/* let the reset sequence continue */
 	complete(&wil->wmi_ready);
 }
 
@@ -346,11 +354,11 @@
 				    rx_mgmt_frame->bssid);
 			cfg80211_put_bss(wiphy, bss);
 		} else {
-			wil_err(wil, "cfg80211_inform_bss() failed\n");
+			wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
 		}
 	} else {
 		cfg80211_rx_mgmt(wil->wdev, freq, signal,
-				 (void *)rx_mgmt_frame, d_len, 0, GFP_KERNEL);
+				 (void *)rx_mgmt_frame, d_len, 0);
 	}
 }
 
@@ -482,33 +490,6 @@
 	mutex_unlock(&wil->mutex);
 }
 
-static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
-{
-	struct wmi_notify_req_done_event *evt = d;
-
-	if (len < sizeof(*evt)) {
-		wil_err(wil, "Short NOTIFY event\n");
-		return;
-	}
-
-	wil->stats.tsf = le64_to_cpu(evt->tsf);
-	wil->stats.snr = le32_to_cpu(evt->snr_val);
-	wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs);
-	wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector);
-	wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector);
-	wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
-	wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
-	wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n"
-		    "BF status 0x%08x SNR 0x%08x SQI %d%%\n"
-		    "Tx Tpt %d goodput %d Rx goodput %d\n"
-		    "Sectors(rx:tx) my %d:%d peer %d:%d\n",
-		    wil->stats.bf_mcs, wil->stats.tsf, evt->status,
-		    wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt),
-		    le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
-		    wil->stats.my_rx_sector, wil->stats.my_tx_sector,
-		    wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
-}
-
 /*
  * Firmware reports EAPOL frame using WME event.
  * Reconstruct Ethernet frame and deliver it via normal Rx
@@ -617,27 +598,40 @@
 		return;
 	}
 
+	mutex_lock(&wil->mutex);
+
 	cid = wil->vring2cid_tid[evt->ringid][0];
 	if (cid >= WIL6210_MAX_CID) {
 		wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid);
-		return;
+		goto out;
 	}
 
 	sta = &wil->sta[cid];
 	if (sta->status == wil_sta_unused) {
 		wil_err(wil, "CID %d unused\n", cid);
-		return;
+		goto out;
 	}
 
 	wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr);
 	for (i = 0; i < WIL_STA_TID_NUM; i++) {
-		struct wil_tid_ampdu_rx *r = sta->tid_rx[i];
+		struct wil_tid_ampdu_rx *r;
+		unsigned long flags;
+
+		spin_lock_irqsave(&sta->tid_rx_lock, flags);
+
+		r = sta->tid_rx[i];
 		sta->tid_rx[i] = NULL;
 		wil_tid_ampdu_rx_free(wil, r);
+
+		spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+
 		if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize)
 			sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil,
 						evt->agg_wsize, 0);
 	}
+
+out:
+	mutex_unlock(&wil->mutex);
 }
 
 static const struct {
@@ -651,7 +645,6 @@
 	{WMI_SCAN_COMPLETE_EVENTID,	wmi_evt_scan_complete},
 	{WMI_CONNECT_EVENTID,		wmi_evt_connect},
 	{WMI_DISCONNECT_EVENTID,	wmi_evt_disconnect},
-	{WMI_NOTIFY_REQ_DONE_EVENTID,	wmi_evt_notify},
 	{WMI_EAPOL_RX_EVENTID,		wmi_evt_eapol_rx},
 	{WMI_DATA_PORT_OPEN_EVENTID,	wmi_evt_linkup},
 	{WMI_WBE_LINKDOWN_EVENTID,	wmi_evt_linkdown},
@@ -676,7 +669,7 @@
 	unsigned n;
 
 	if (!test_bit(wil_status_reset_done, &wil->status)) {
-		wil_err(wil, "Reset not completed\n");
+		wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
 		return;
 	}
 
@@ -731,6 +724,7 @@
 			struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi;
 			u16 id = le16_to_cpu(wmi->id);
 			u32 tstamp = le32_to_cpu(wmi->timestamp);
+
 			wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
 				    id, wmi->mid, tstamp);
 			trace_wil6210_wmi_event(wmi, &wmi[1],
@@ -771,8 +765,8 @@
 	wil->reply_id = reply_id;
 	wil->reply_buf = reply;
 	wil->reply_size = reply_size;
-	remain = wait_for_completion_timeout(&wil->wmi_ready,
-			msecs_to_jiffies(to_msec));
+	remain = wait_for_completion_timeout(&wil->wmi_call,
+					     msecs_to_jiffies(to_msec));
 	if (0 == remain) {
 		wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
 			cmdid, reply_id, to_msec);
@@ -822,7 +816,7 @@
 		.network_type = wmi_nettype,
 		.disable_sec_offload = 1,
 		.channel = chan - 1,
-		.pcp_max_assoc_sta = WIL6210_MAX_CID,
+		.pcp_max_assoc_sta = max_assoc_sta,
 	};
 	struct {
 		struct wil6210_mbox_hdr_wmi wmi;
@@ -832,6 +826,14 @@
 	if (!wil->secure_pcp)
 		cmd.disable_sec = 1;
 
+	if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) ||
+	    (cmd.pcp_max_assoc_sta <= 0)) {
+		wil_info(wil,
+			 "Requested connection limit %u, valid values are 1 - %d. Setting to %d\n",
+			 max_assoc_sta, WIL6210_MAX_CID, WIL6210_MAX_CID);
+		cmd.pcp_max_assoc_sta = WIL6210_MAX_CID;
+	}
+
 	/*
 	 * Processing time may be huge, in case of secure AP it takes about
 	 * 3500ms for FW to start AP
@@ -968,8 +970,11 @@
 	int rc;
 	u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
 	struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
+
 	if (!cmd)
 		return -ENOMEM;
+	if (!ie)
+		ie_len = 0;
 
 	cmd->mgmt_frm_type = type;
 	/* BUG: FW API define ieLen as u8. Will fix FW */
@@ -1143,6 +1148,9 @@
 		struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]);
 		void *evt_data = (void *)(&wmi[1]);
 		u16 id = le16_to_cpu(wmi->id);
+
+		wil_dbg_wmi(wil, "Handle WMI 0x%04x (reply_id 0x%04x)\n",
+			    id, wil->reply_id);
 		/* check if someone waits for this event */
 		if (wil->reply_id && wil->reply_id == id) {
 			if (wil->reply_buf) {
@@ -1153,7 +1161,7 @@
 						     len - sizeof(*wmi));
 			}
 			wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id);
-			complete(&wil->wmi_ready);
+			complete(&wil->wmi_call);
 			return;
 		}
 		/* unsolicited event */
@@ -1199,9 +1207,11 @@
 	struct pending_wmi_event *evt;
 	struct list_head *lh;
 
+	wil_dbg_wmi(wil, "Start %s\n", __func__);
 	while ((lh = next_wmi_ev(wil)) != NULL) {
 		evt = list_entry(lh, struct pending_wmi_event, list);
 		wmi_event_handle(wil, &evt->event.hdr);
 		kfree(evt);
 	}
+	wil_dbg_wmi(wil, "Finished %s\n", __func__);
 }
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 17334c8..27b9743 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  * Copyright (c) 2006-2012 Wilocity .
  *
  * Permission to use, copy, modify, and/or distribute this software for any
@@ -179,7 +179,6 @@
 	WMI_CRYPT_AES_GCMP		= 0x20,
 };
 
-
 enum wmi_connect_ctrl_flag_bits {
 	WMI_CONNECT_ASSOC_POLICY_USER		= 0x0001,
 	WMI_CONNECT_SEND_REASSOC		= 0x0002,
@@ -219,7 +218,6 @@
 	__le16 disconnect_reason;
 } __packed;
 
-
 /*
  * WMI_SET_PMK_CMDID
  */
@@ -234,7 +232,6 @@
 	u8 pmk[WMI_PMK_LEN];
 } __packed;
 
-
 /*
  * WMI_SET_PASSPHRASE_CMDID
  */
@@ -273,7 +270,6 @@
 	u8 mac[WMI_MAC_LEN];
 } __packed;
 
-
 /*
  * WMI_START_SCAN_CMDID
  *
@@ -325,7 +321,6 @@
 	u8 ssid[WMI_MAX_SSID_LEN];
 } __packed;
 
-
 /*
  * WMI_SET_APPIE_CMDID
  * Add Application specified IE to a management frame
@@ -351,7 +346,6 @@
 	u8 ie_info[0];
 } __packed;
 
-
 /*
  * WMI_PXMT_RANGE_CFG_CMDID
  */
@@ -380,7 +374,6 @@
 	__le32 rf_mgmt_type;
 } __packed;
 
-
 /*
  * WMI_RF_RX_TEST_CMDID
  */
@@ -426,7 +419,6 @@
 	u8 disable_sec;
 } __packed;
 
-
 /******* P2P ***********/
 
 /*
@@ -797,7 +789,6 @@
 	__le32 measure_marlon_r_en;
 } __packed;
 
-
 /*
  * WMI Events
  */
@@ -887,7 +878,6 @@
  * Events data structures
  */
 
-
 enum wmi_fw_status {
 	WMI_FW_STATUS_SUCCESS,
 	WMI_FW_STATUS_FAILURE,
@@ -980,7 +970,7 @@
  * WMI_NOTIFY_REQ_DONE_EVENTID
  */
 struct wmi_notify_req_done_event {
-	__le32 status;
+	__le32 status; /* beamforming status, 0: fail; 1: OK; 2: retrying */
 	__le64 tsf;
 	__le32 snr_val;
 	__le32 tx_tpt;
@@ -1038,8 +1028,8 @@
 	__le16 protocol_reason_status;	/* reason code, see 802.11 spec. */
 	u8 bssid[WMI_MAC_LEN];		/* set if known */
 	u8 disconnect_reason;		/* see wmi_disconnect_reason */
-	u8 assoc_resp_len;		/* not in use */
-	u8 assoc_info[0];		/* not in use */
+	u8 assoc_resp_len;	/* not used */
+	u8 assoc_info[0];	/* not used */
 } __packed;
 
 /*
@@ -1081,7 +1071,6 @@
 	__le16 reason;
 } __packed;
 
-
 /*
  * WMI_VRING_CFG_DONE_EVENTID
  */
@@ -1147,7 +1136,6 @@
 	u8 reserved[3];
 } __packed;
 
-
 /*
  * WMI_GET_PCP_CHANNEL_EVENTID
  */
@@ -1156,7 +1144,6 @@
 	u8 reserved[3];
 } __packed;
 
-
 /*
 * WMI_PORT_ALLOCATED_EVENTID
 */
@@ -1260,7 +1247,6 @@
 	u8 channel;	/* From Radio MNGR */
 } __packed;
 
-
 /*
  * WMI_TX_MGMT_PACKET_EVENTID
  */
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index 9cfc59b..186c62f 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -18,6 +18,7 @@
 b43-y				+= dma.o
 b43-y				+= pio.o
 b43-y				+= rfkill.o
+b43-y				+= ppr.o
 b43-$(CPTCFG_B43_LEDS)		+= leds.o
 b43-$(CPTCFG_B43_PCMCIA)	+= pcmcia.o
 b43-$(CPTCFG_B43_SDIO)		+= sdio.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index a1f4475..c58c307 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -45,6 +45,7 @@
 #define B43_MMIO_RAM_DATA		0x134
 #define B43_MMIO_PS_STATUS		0x140
 #define B43_MMIO_RADIO_HWENABLED_HI	0x158
+#define B43_MMIO_MAC_HW_CAP		0x15C	/* MAC capabilities (corerev >= 13) */
 #define B43_MMIO_SHM_CONTROL		0x160
 #define B43_MMIO_SHM_DATA		0x164
 #define B43_MMIO_SHM_DATA_UNALIGNED	0x166
@@ -253,6 +254,8 @@
 #define B43_SHM_SH_CHAN			0x00A0	/* Current channel (low 8bit only) */
 #define  B43_SHM_SH_CHAN_5GHZ		0x0100	/* Bit set, if 5 Ghz channel */
 #define  B43_SHM_SH_CHAN_40MHZ		0x0200	/* Bit set, if 40 Mhz channel width */
+#define B43_SHM_SH_MACHW_L		0x00C0	/* Location where the ucode expects the MAC capabilities */
+#define B43_SHM_SH_MACHW_H		0x00C2	/* Location where the ucode expects the MAC capabilities */
 #define B43_SHM_SH_HOSTF5		0x00D4	/* Hostflags 5 for ucode options */
 #define B43_SHM_SH_BCMCFIFOID		0x0108	/* Last posted cookie to the bcast/mcast FIFO */
 /* TSSI information */
@@ -297,6 +300,7 @@
 #define B43_SHM_SH_LFFBLIM		0x0046	/* Long frame fallback retry limit */
 #define B43_SHM_SH_BEACPHYCTL		0x0054	/* Beacon PHY TX control word (see PHY TX control) */
 #define B43_SHM_SH_EXTNPHYCTL		0x00B0	/* Extended bytes for beacon PHY control (N) */
+#define B43_SHM_SH_BCN_LI		0x00B6	/* beacon listen interval */
 /* SHM_SHARED ACK/CTS control */
 #define B43_SHM_SH_ACKCTSPHYCTL		0x0022	/* ACK/CTS PHY control word (see PHY TX control) */
 /* SHM_SHARED probe response variables */
@@ -457,6 +461,7 @@
 #define B43_MACCTL_RADIOLOCK		0x00080000	/* Radio lock */
 #define B43_MACCTL_BEACPROMISC		0x00100000	/* Beacon Promiscuous */
 #define B43_MACCTL_KEEP_BADPLCP		0x00200000	/* Keep frames with bad PLCP */
+#define B43_MACCTL_PHY_LOCK		0x00200000
 #define B43_MACCTL_KEEP_CTL		0x00400000	/* Keep control frames */
 #define B43_MACCTL_KEEP_BAD		0x00800000	/* Keep bad frames (FCS) */
 #define B43_MACCTL_PROMISC		0x01000000	/* Promiscuous mode */
@@ -475,6 +480,11 @@
 #define B43_MACCMD_CCA			0x00000008	/* Clear channel assessment */
 #define B43_MACCMD_BGNOISE		0x00000010	/* Background noise */
 
+/* B43_MMIO_PSM_PHY_HDR bits */
+#define B43_PSM_HDR_MAC_PHY_RESET	0x00000001
+#define B43_PSM_HDR_MAC_PHY_CLOCK_EN	0x00000002
+#define B43_PSM_HDR_MAC_PHY_FORCE_CLK	0x00000004
+
 /* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */
 #define B43_BCMA_CLKCTLST_80211_PLL_REQ	0x00000100
 #define B43_BCMA_CLKCTLST_PHY_PLL_REQ	0x00000200
@@ -791,6 +801,13 @@
 	bool pcm_request_failed;
 };
 
+enum b43_band {
+	B43_BAND_2G = 0,
+	B43_BAND_5G_LO = 1,
+	B43_BAND_5G_MI = 2,
+	B43_BAND_5G_HI = 3,
+};
+
 /* Device (802.11 core) initialization status. */
 enum {
 	B43_STAT_UNINIT = 0,	/* Uninitialized. */
@@ -1012,6 +1029,16 @@
 	dev->dev->write16(dev->dev, offset, value);
 }
 
+/* To optimize this check for flush_writes on BCM47XX_BCMA only. */
+static inline void b43_write16f(struct b43_wldev *dev, u16 offset, u16 value)
+{
+	b43_write16(dev, offset, value);
+#if defined(CONFIG_BCM47XX_BCMA)
+	if (dev->dev->flush_writes)
+		b43_read16(dev, offset);
+#endif
+}
+
 static inline void b43_maskset16(struct b43_wldev *dev, u16 offset, u16 mask,
 				 u16 set)
 {
diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c
index 30d7313..7f59714 100644
--- a/drivers/net/wireless/b43/bus.c
+++ b/drivers/net/wireless/b43/bus.c
@@ -22,6 +22,10 @@
 
 */
 
+#ifdef CONFIG_BCM47XX_BCMA
+#include <asm/mach-bcm47xx/bcm47xx.h>
+#endif
+
 #include "b43.h"
 #include "bus.h"
 
@@ -102,6 +106,12 @@
 	dev->write32 = b43_bus_bcma_write32;
 	dev->block_read = b43_bus_bcma_block_read;
 	dev->block_write = b43_bus_bcma_block_write;
+#ifdef CONFIG_BCM47XX_BCMA
+	if (b43_bus_host_is_pci(dev) &&
+	    bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA &&
+	    bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4716)
+		dev->flush_writes = true;
+#endif
 
 	dev->dev = &core->dev;
 	dev->dma_dev = core->dma_dev;
diff --git a/drivers/net/wireless/b43/bus.h b/drivers/net/wireless/b43/bus.h
index f1b492f..617a70b 100644
--- a/drivers/net/wireless/b43/bus.h
+++ b/drivers/net/wireless/b43/bus.h
@@ -33,6 +33,7 @@
 			   size_t count, u16 offset, u8 reg_width);
 	void (*block_write)(struct b43_bus_dev *dev, const void *buffer,
 			    size_t count, u16 offset, u8 reg_width);
+	bool flush_writes;
 
 	struct device *dev;
 	struct device *dma_dev;
@@ -60,7 +61,21 @@
 #else
 	return false;
 #endif
+};
+
+static inline bool b43_bus_host_is_pci(struct b43_bus_dev *dev)
+{
+#ifdef CPTCFG_B43_BCMA
+	if (dev->bus_type == B43_BUS_BCMA)
+		return (dev->bdev->bus->hosttype == BCMA_HOSTTYPE_PCI);
+#endif
+#ifdef CPTCFG_B43_SSB
+	if (dev->bus_type == B43_BUS_SSB)
+		return (dev->sdev->bus->bustype == SSB_BUSTYPE_PCI);
+#endif
+	return false;
 }
+
 static inline bool b43_bus_host_is_sdio(struct b43_bus_dev *dev)
 {
 #ifdef CPTCFG_B43_SSB
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index c745aaa..d726f6c 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1204,6 +1204,36 @@
 	}
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */
+void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev)
+{
+	struct bcma_drv_cc *bcma_cc __maybe_unused;
+	struct ssb_chipcommon *ssb_cc __maybe_unused;
+
+	switch (dev->dev->bus_type) {
+#ifdef CPTCFG_B43_BCMA
+	case B43_BUS_BCMA:
+		bcma_cc = &dev->dev->bdev->bus->drv_cc;
+
+		bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
+		bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
+		bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
+		bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
+		break;
+#endif
+#ifdef CPTCFG_B43_SSB
+	case B43_BUS_SSB:
+		ssb_cc = &dev->dev->sdev->bus->chipco;
+
+		chipco_write32(ssb_cc, SSB_CHIPCO_CHIPCTL_ADDR, 0);
+		chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4);
+		chipco_set32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, 0x4);
+		chipco_mask32(ssb_cc, SSB_CHIPCO_CHIPCTL_DATA, ~0x4);
+		break;
+#endif
+	}
+}
+
 #ifdef CPTCFG_B43_BCMA
 static void b43_bcma_phy_reset(struct b43_wldev *dev)
 {
@@ -2985,7 +3015,22 @@
 {
 	u16 chip_id = dev->dev->chip_id;
 
-	if (chip_id == BCMA_CHIP_ID_BCM43131 ||
+	if (chip_id == BCMA_CHIP_ID_BCM4331) {
+		switch (spurmode) {
+		case 2: /* 168 Mhz: 2^26/168 = 0x61862 */
+			b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x1862);
+			b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
+			break;
+		case 1: /* 164 Mhz: 2^26/164 = 0x63e70 */
+			b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x3e70);
+			b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
+			break;
+		default: /* 160 Mhz: 2^26/160 = 0x66666 */
+			b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x6666);
+			b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x6);
+			break;
+		}
+	} else if (chip_id == BCMA_CHIP_ID_BCM43131 ||
 	    chip_id == BCMA_CHIP_ID_BCM43217 ||
 	    chip_id == BCMA_CHIP_ID_BCM43222 ||
 	    chip_id == BCMA_CHIP_ID_BCM43224 ||
@@ -3106,6 +3151,7 @@
 	case B43_PHYTYPE_HT:
 	case B43_PHYTYPE_LCN:
 		b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
+		b43_rate_memory_write(dev, B43_OFDM_RATE_9MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1);
@@ -3884,6 +3930,12 @@
 	return 0;
 }
 
+static void b43_set_beacon_listen_interval(struct b43_wldev *dev, u16 interval)
+{
+	interval = min_t(u16, interval, (u16)0xFF);
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BCN_LI, interval);
+}
+
 /* Write the short and long frame retry limit values. */
 static void b43_set_retry_limits(struct b43_wldev *dev,
 				 unsigned int short_retry,
@@ -3912,6 +3964,9 @@
 	mutex_lock(&wl->mutex);
 	b43_mac_suspend(dev);
 
+	if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL)
+		b43_set_beacon_listen_interval(dev, conf->listen_interval);
+
 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
 		phy->chandef = &conf->chandef;
 		phy->channel = conf->chandef.chan->hw_value;
@@ -4466,10 +4521,10 @@
 	if (core_rev == 40 || core_rev == 42) {
 		radio_manuf = 0x17F;
 
-		b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 0);
+		b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 0);
 		radio_rev = b43_read16(dev, B43_MMIO_RADIO24_DATA);
 
-		b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 1);
+		b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 1);
 		radio_id = b43_read16(dev, B43_MMIO_RADIO24_DATA);
 
 		radio_ver = 0; /* Is there version somewhere? */
@@ -4477,7 +4532,7 @@
 		u16 radio24[3];
 
 		for (tmp = 0; tmp < 3; tmp++) {
-			b43_write16(dev, B43_MMIO_RADIO24_CONTROL, tmp);
+			b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, tmp);
 			radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA);
 		}
 
@@ -4494,13 +4549,12 @@
 			else
 				tmp = 0x5205017F;
 		} else {
-			b43_write16(dev, B43_MMIO_RADIO_CONTROL,
-				    B43_RADIOCTL_ID);
+			b43_write16f(dev, B43_MMIO_RADIO_CONTROL,
+				     B43_RADIOCTL_ID);
 			tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
-			b43_write16(dev, B43_MMIO_RADIO_CONTROL,
-				    B43_RADIOCTL_ID);
-			tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH)
-				<< 16;
+			b43_write16f(dev, B43_MMIO_RADIO_CONTROL,
+				     B43_RADIOCTL_ID);
+			tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
 		}
 		radio_manuf = (tmp & 0x00000FFF);
 		radio_id = (tmp & 0x0FFFF000) >> 12;
@@ -4813,6 +4867,16 @@
 	hf &= ~B43_HF_SKCFPUP;
 	b43_hf_write(dev, hf);
 
+	/* tell the ucode MAC capabilities */
+	if (dev->dev->core_rev >= 13) {
+		u32 mac_hw_cap = b43_read32(dev, B43_MMIO_MAC_HW_CAP);
+
+		b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_L,
+				mac_hw_cap & 0xffff);
+		b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_MACHW_H,
+				(mac_hw_cap >> 16) & 0xffff);
+	}
+
 	b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
 			     B43_DEFAULT_LONG_RETRY_LIMIT);
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
@@ -4835,6 +4899,10 @@
 	/* Maximum Contention Window */
 	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
+	/* write phytype and phyvers */
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYTYPE, phy->type);
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PHYVER, phy->rev);
+
 	if (b43_bus_host_is_pcmcia(dev->dev) ||
 	    b43_bus_host_is_sdio(dev->dev)) {
 		dev->__using_pio_transfers = true;
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
index 9f22e4b..c46430c 100644
--- a/drivers/net/wireless/b43/main.h
+++ b/drivers/net/wireless/b43/main.h
@@ -96,6 +96,8 @@
 #define B43_PS_ASLEEP	(1 << 3)	/* Force device asleep */
 void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags);
 
+void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev);
+
 void b43_mac_suspend(struct b43_wldev *dev);
 void b43_mac_enable(struct b43_wldev *dev);
 void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on);
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c
index 25e4043..99c036f 100644
--- a/drivers/net/wireless/b43/phy_a.c
+++ b/drivers/net/wireless/b43/phy_a.c
@@ -444,14 +444,14 @@
 static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg)
 {
 	reg = adjust_phyreg(dev, reg);
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
 	return b43_read16(dev, B43_MMIO_PHY_DATA);
 }
 
 static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
 	reg = adjust_phyreg(dev, reg);
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
 	b43_write16(dev, B43_MMIO_PHY_DATA, value);
 }
 
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 0ff26d8..94da49c 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -222,12 +222,18 @@
 u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
 {
 	assert_mac_suspended(dev);
+	dev->phy.writes_counter = 0;
 	return dev->phy.ops->radio_read(dev, reg);
 }
 
 void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
 	assert_mac_suspended(dev);
+	if (b43_bus_host_is_pci(dev->dev) &&
+	    ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) {
+		b43_read32(dev, B43_MMIO_MACCTL);
+		dev->phy.writes_counter = 1;
+	}
 	dev->phy.ops->radio_write(dev, reg, value);
 }
 
@@ -268,17 +274,28 @@
 {
 	assert_mac_suspended(dev);
 	dev->phy.writes_counter = 0;
-	return dev->phy.ops->phy_read(dev, reg);
+
+	if (dev->phy.ops->phy_read)
+		return dev->phy.ops->phy_read(dev, reg);
+
+	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
+	return b43_read16(dev, B43_MMIO_PHY_DATA);
 }
 
 void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
 	assert_mac_suspended(dev);
-	dev->phy.ops->phy_write(dev, reg, value);
-	if (++dev->phy.writes_counter == B43_MAX_WRITES_IN_ROW) {
+	if (b43_bus_host_is_pci(dev->dev) &&
+	    ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) {
 		b43_read16(dev, B43_MMIO_PHY_VER);
-		dev->phy.writes_counter = 0;
+		dev->phy.writes_counter = 1;
 	}
+
+	if (dev->phy.ops->phy_write)
+		return dev->phy.ops->phy_write(dev, reg, value);
+
+	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16(dev, B43_MMIO_PHY_DATA, value);
 }
 
 void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c
index 8f5c14b..727ce6e 100644
--- a/drivers/net/wireless/b43/phy_g.c
+++ b/drivers/net/wireless/b43/phy_g.c
@@ -2555,13 +2555,13 @@
 
 static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg)
 {
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
 	return b43_read16(dev, B43_MMIO_PHY_DATA);
 }
 
 static void b43_gphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
 	b43_write16(dev, B43_MMIO_PHY_DATA, value);
 }
 
@@ -2572,7 +2572,7 @@
 	/* G-PHY needs 0x80 for read access. */
 	reg |= 0x80;
 
-	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
 	return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
 }
 
@@ -2581,7 +2581,7 @@
 	/* Register 1 is a 32-bit register. */
 	B43_WARN_ON(reg == 1);
 
-	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
 	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
 }
 
diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c
index f2974c6..bd68945 100644
--- a/drivers/net/wireless/b43/phy_ht.c
+++ b/drivers/net/wireless/b43/phy_ht.c
@@ -81,80 +81,104 @@
 	udelay(50);
 
 	/* Calibration */
-	b43_radio_mask(dev, 0x2b, ~0x1);
-	b43_radio_mask(dev, 0x2e, ~0x4);
-	b43_radio_set(dev, 0x2e, 0x4);
-	b43_radio_set(dev, 0x2b, 0x1);
+	b43_radio_mask(dev, R2059_RFPLL_MISC_EN, ~0x1);
+	b43_radio_mask(dev, R2059_RFPLL_MISC_CAL_RESETN, ~0x4);
+	b43_radio_set(dev, R2059_RFPLL_MISC_CAL_RESETN, 0x4);
+	b43_radio_set(dev, R2059_RFPLL_MISC_EN, 0x1);
 
 	udelay(300);
 }
 
+/* Calibrate resistors in LPF of PLL? */
+static void b43_radio_2059_rcal(struct b43_wldev *dev)
+{
+	/* Enable */
+	b43_radio_set(dev, R2059_C3 | R2059_RCAL_CONFIG, 0x1);
+	usleep_range(10, 20);
+
+	b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1);
+	b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2);
+
+	/* Start */
+	b43_radio_set(dev, R2059_C3 | R2059_RCAL_CONFIG, 0x2);
+	usleep_range(100, 200);
+
+	/* Stop */
+	b43_radio_mask(dev, R2059_C3 | R2059_RCAL_CONFIG, ~0x2);
+
+	if (!b43_radio_wait_value(dev, R2059_C3 | R2059_RCAL_STATUS, 1, 1, 100,
+				  1000000))
+		b43err(dev->wl, "Radio 0x2059 rcal timeout\n");
+
+	/* Disable */
+	b43_radio_mask(dev, R2059_C3 | R2059_RCAL_CONFIG, ~0x1);
+
+	b43_radio_set(dev, 0xa, 0x60);
+}
+
+/* Calibrate the internal RC oscillator? */
+static void b43_radio_2057_rccal(struct b43_wldev *dev)
+{
+	const u16 radio_values[3][2] = {
+		{ 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 },
+	};
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		b43_radio_write(dev, R2059_RCCAL_MASTER, radio_values[i][0]);
+		b43_radio_write(dev, R2059_RCCAL_X1, 0x6E);
+		b43_radio_write(dev, R2059_RCCAL_TRC0, radio_values[i][1]);
+
+		/* Start */
+		b43_radio_write(dev, R2059_RCCAL_START_R1_Q1_P1, 0x55);
+
+		/* Wait */
+		if (!b43_radio_wait_value(dev, R2059_RCCAL_DONE_OSCCAP, 2, 2,
+					  500, 5000000))
+			b43err(dev->wl, "Radio 0x2059 rccal timeout\n");
+
+		/* Stop */
+		b43_radio_write(dev, R2059_RCCAL_START_R1_Q1_P1, 0x15);
+	}
+
+	b43_radio_mask(dev, R2059_RCCAL_MASTER, ~0x1);
+}
+
+static void b43_radio_2059_init_pre(struct b43_wldev *dev)
+{
+	b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD, ~B43_PHY_HT_RF_CTL_CMD_CHIP0_PU);
+	b43_phy_set(dev, B43_PHY_HT_RF_CTL_CMD, B43_PHY_HT_RF_CTL_CMD_FORCE);
+	b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD, ~B43_PHY_HT_RF_CTL_CMD_FORCE);
+	b43_phy_set(dev, B43_PHY_HT_RF_CTL_CMD, B43_PHY_HT_RF_CTL_CMD_CHIP0_PU);
+}
+
 static void b43_radio_2059_init(struct b43_wldev *dev)
 {
 	const u16 routing[] = { R2059_C1, R2059_C2, R2059_C3 };
-	const u16 radio_values[3][2] = {
-		{ 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 },
-	};
-	u16 i, j;
+	int i;
 
-	b43_radio_write(dev, R2059_ALL | 0x51, 0x0070);
-	b43_radio_write(dev, R2059_ALL | 0x5a, 0x0003);
+	/* Prepare (reset?) radio */
+	b43_radio_2059_init_pre(dev);
+
+	r2059_upload_inittabs(dev);
 
 	for (i = 0; i < ARRAY_SIZE(routing); i++)
 		b43_radio_set(dev, routing[i] | 0x146, 0x3);
 
-	b43_radio_set(dev, 0x2e, 0x0078);
-	b43_radio_set(dev, 0xc0, 0x0080);
+	/* Post init starts below */
+
+	b43_radio_set(dev, R2059_RFPLL_MISC_CAL_RESETN, 0x0078);
+	b43_radio_set(dev, R2059_XTAL_CONFIG2, 0x0080);
 	msleep(2);
-	b43_radio_mask(dev, 0x2e, ~0x0078);
-	b43_radio_mask(dev, 0xc0, ~0x0080);
+	b43_radio_mask(dev, R2059_RFPLL_MISC_CAL_RESETN, ~0x0078);
+	b43_radio_mask(dev, R2059_XTAL_CONFIG2, ~0x0080);
 
 	if (1) { /* FIXME */
-		b43_radio_set(dev, R2059_C3 | 0x4, 0x1);
-		udelay(10);
-		b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1);
-		b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2);
-
-		b43_radio_set(dev, R2059_C3 | 0x4, 0x2);
-		udelay(100);
-		b43_radio_mask(dev, R2059_C3 | 0x4, ~0x2);
-
-		for (i = 0; i < 10000; i++) {
-			if (b43_radio_read(dev, R2059_C3 | 0x145) & 1) {
-				i = 0;
-				break;
-			}
-			udelay(100);
-		}
-		if (i)
-			b43err(dev->wl, "radio 0x945 timeout\n");
-
-		b43_radio_mask(dev, R2059_C3 | 0x4, ~0x1);
-		b43_radio_set(dev, 0xa, 0x60);
-
-		for (i = 0; i < 3; i++) {
-			b43_radio_write(dev, 0x17F, radio_values[i][0]);
-			b43_radio_write(dev, 0x13D, 0x6E);
-			b43_radio_write(dev, 0x13E, radio_values[i][1]);
-			b43_radio_write(dev, 0x13C, 0x55);
-
-			for (j = 0; j < 10000; j++) {
-				if (b43_radio_read(dev, 0x140) & 2) {
-					j = 0;
-					break;
-				}
-				udelay(500);
-			}
-			if (j)
-				b43err(dev->wl, "radio 0x140 timeout\n");
-
-			b43_radio_write(dev, 0x13C, 0x15);
-		}
-
-		b43_radio_mask(dev, 0x17F, ~0x1);
+		b43_radio_2059_rcal(dev);
+		b43_radio_2057_rccal(dev);
 	}
 
-	b43_radio_mask(dev, 0x11, ~0x0008);
+	b43_radio_mask(dev, R2059_RFPLL_MASTER, ~0x0008);
 }
 
 /**************************************************
@@ -297,6 +321,26 @@
 	b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
 }
 
+static void b43_phy_ht_bphy_reset(struct b43_wldev *dev, bool reset)
+{
+	u16 tmp;
+
+	tmp = b43_read16(dev, B43_MMIO_PSM_PHY_HDR);
+	b43_write16(dev, B43_MMIO_PSM_PHY_HDR,
+		    tmp | B43_PSM_HDR_MAC_PHY_FORCE_CLK);
+
+	/* Put BPHY in or take it out of the reset */
+	if (reset)
+		b43_phy_set(dev, B43_PHY_B_BBCFG,
+			    B43_PHY_B_BBCFG_RSTCCA | B43_PHY_B_BBCFG_RSTRX);
+	else
+		b43_phy_mask(dev, B43_PHY_B_BBCFG,
+			     (u16)~(B43_PHY_B_BBCFG_RSTCCA |
+				    B43_PHY_B_BBCFG_RSTRX));
+
+	b43_write16(dev, B43_MMIO_PSM_PHY_HDR, tmp);
+}
+
 /**************************************************
  * Samples
  **************************************************/
@@ -704,7 +748,6 @@
 {
 	struct bcma_device *core = dev->dev->bdev;
 	int spuravoid = 0;
-	u16 tmp;
 
 	/* Check for 13 and 14 is just a guess, we don't have enough logs. */
 	if (new_channel->hw_value == 13 || new_channel->hw_value == 14)
@@ -717,22 +760,9 @@
 			  B43_BCMA_CLKCTLST_80211_PLL_ST |
 			  B43_BCMA_CLKCTLST_PHY_PLL_ST, false);
 
-	/* Values has been taken from wlc_bmac_switch_macfreq comments */
-	switch (spuravoid) {
-	case 2: /* 126MHz */
-		tmp = 0x2082;
-		break;
-	case 1: /* 123MHz */
-		tmp = 0x5341;
-		break;
-	default: /* 120MHz */
-		tmp = 0x8889;
-	}
+	b43_mac_switch_freq(dev, spuravoid);
 
-	b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, tmp);
-	b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
-
-	/* TODO: reset PLL */
+	b43_wireless_core_phy_pll_reset(dev);
 
 	if (spuravoid)
 		b43_phy_set(dev, B43_PHY_HT_BBCFG, B43_PHY_HT_BBCFG_RSTRX);
@@ -747,13 +777,19 @@
 				const struct b43_phy_ht_channeltab_e_phy *e,
 				struct ieee80211_channel *new_channel)
 {
-	bool old_band_5ghz;
+	if (new_channel->band == IEEE80211_BAND_5GHZ) {
+		/* Switch to 2 GHz for a moment to access B-PHY regs */
+		b43_phy_mask(dev, B43_PHY_HT_BANDCTL, ~B43_PHY_HT_BANDCTL_5GHZ);
 
-	old_band_5ghz = b43_phy_read(dev, B43_PHY_HT_BANDCTL) & 0; /* FIXME */
-	if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) {
-		/* TODO */
-	} else if (new_channel->band == IEEE80211_BAND_2GHZ && old_band_5ghz) {
-		/* TODO */
+		b43_phy_ht_bphy_reset(dev, true);
+
+		/* Switch to 5 GHz */
+		b43_phy_set(dev, B43_PHY_HT_BANDCTL, B43_PHY_HT_BANDCTL_5GHZ);
+	} else {
+		/* Switch to 2 GHz */
+		b43_phy_mask(dev, B43_PHY_HT_BANDCTL, ~B43_PHY_HT_BANDCTL_5GHZ);
+
+		b43_phy_ht_bphy_reset(dev, false);
 	}
 
 	b43_phy_write(dev, B43_PHY_HT_BW1, e->bw1);
@@ -1002,19 +1038,10 @@
 	if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
 		b43err(dev->wl, "MAC not suspended\n");
 
-	/* In the following PHY ops we copy wl's dummy behaviour.
-	 * TODO: Find out if reads (currently hidden in masks/masksets) are
-	 * needed and replace following ops with just writes or w&r.
-	 * Note: B43_PHY_HT_RF_CTL1 register is tricky, wrong operation can
-	 * cause delayed (!) machine lock up. */
 	if (blocked) {
-		b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
+		b43_phy_mask(dev, B43_PHY_HT_RF_CTL_CMD,
+			     ~B43_PHY_HT_RF_CTL_CMD_CHIP0_PU);
 	} else {
-		b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
-		b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x1);
-		b43_phy_mask(dev, B43_PHY_HT_RF_CTL1, 0);
-		b43_phy_maskset(dev, B43_PHY_HT_RF_CTL1, 0, 0x2);
-
 		if (dev->phy.radio_ver == 0x2059)
 			b43_radio_2059_init(dev);
 		else
@@ -1071,22 +1098,10 @@
  * R/W ops.
  **************************************************/
 
-static u16 b43_phy_ht_op_read(struct b43_wldev *dev, u16 reg)
-{
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-	return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_phy_ht_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-	b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
 static void b43_phy_ht_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
 				 u16 set)
 {
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
 	b43_write16(dev, B43_MMIO_PHY_DATA,
 		    (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
 }
@@ -1096,14 +1111,14 @@
 	/* HT-PHY needs 0x200 for read access */
 	reg |= 0x200;
 
-	b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
 	return b43_read16(dev, B43_MMIO_RADIO24_DATA);
 }
 
 static void b43_phy_ht_op_radio_write(struct b43_wldev *dev, u16 reg,
 				      u16 value)
 {
-	b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
 	b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
 }
 
@@ -1126,8 +1141,6 @@
 	.free			= b43_phy_ht_op_free,
 	.prepare_structs	= b43_phy_ht_op_prepare_structs,
 	.init			= b43_phy_ht_op_init,
-	.phy_read		= b43_phy_ht_op_read,
-	.phy_write		= b43_phy_ht_op_write,
 	.phy_maskset		= b43_phy_ht_op_maskset,
 	.radio_read		= b43_phy_ht_op_radio_read,
 	.radio_write		= b43_phy_ht_op_radio_write,
diff --git a/drivers/net/wireless/b43/phy_ht.h b/drivers/net/wireless/b43/phy_ht.h
index 6cae370..c086f56 100644
--- a/drivers/net/wireless/b43/phy_ht.h
+++ b/drivers/net/wireless/b43/phy_ht.h
@@ -81,7 +81,9 @@
 #define B43_PHY_HT_RF_SEQ_STATUS		B43_PHY_EXTG(0x004)
 /* Values for the status are the same as for the trigger */
 
-#define B43_PHY_HT_RF_CTL1			B43_PHY_EXTG(0x010)
+#define B43_PHY_HT_RF_CTL_CMD			0x810
+#define  B43_PHY_HT_RF_CTL_CMD_FORCE		0x0001
+#define  B43_PHY_HT_RF_CTL_CMD_CHIP0_PU		0x0002
 
 #define B43_PHY_HT_RF_CTL_INT_C1		B43_PHY_EXTG(0x04c)
 #define B43_PHY_HT_RF_CTL_INT_C2		B43_PHY_EXTG(0x06c)
@@ -104,6 +106,9 @@
 #define  B43_PHY_HT_TXPCTL_TARG_PWR2_C3_SHIFT	0
 #define B43_PHY_HT_TX_PCTL_STATUS_C3		B43_PHY_EXTG(0x169)
 
+#define B43_PHY_B_BBCFG				B43_PHY_N_BMODE(0x001)
+#define  B43_PHY_B_BBCFG_RSTCCA			0x4000 /* Reset CCA */
+#define  B43_PHY_B_BBCFG_RSTRX			0x8000 /* Reset RX */
 #define B43_PHY_HT_TEST				B43_PHY_N_BMODE(0x00A)
 
 
diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c
index e76bbdf..97461cc 100644
--- a/drivers/net/wireless/b43/phy_lcn.c
+++ b/drivers/net/wireless/b43/phy_lcn.c
@@ -810,22 +810,10 @@
  * R/W ops.
  **************************************************/
 
-static u16 b43_phy_lcn_op_read(struct b43_wldev *dev, u16 reg)
-{
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-	return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_phy_lcn_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-	b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
 static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
 				   u16 set)
 {
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
 	b43_write16(dev, B43_MMIO_PHY_DATA,
 		    (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
 }
@@ -835,14 +823,14 @@
 	/* LCN-PHY needs 0x200 for read access */
 	reg |= 0x200;
 
-	b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
 	return b43_read16(dev, B43_MMIO_RADIO24_DATA);
 }
 
 static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg,
 				       u16 value)
 {
-	b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
 	b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
 }
 
@@ -855,8 +843,6 @@
 	.free			= b43_phy_lcn_op_free,
 	.prepare_structs	= b43_phy_lcn_op_prepare_structs,
 	.init			= b43_phy_lcn_op_init,
-	.phy_read		= b43_phy_lcn_op_read,
-	.phy_write		= b43_phy_lcn_op_write,
 	.phy_maskset		= b43_phy_lcn_op_maskset,
 	.radio_read		= b43_phy_lcn_op_radio_read,
 	.radio_write		= b43_phy_lcn_op_radio_write,
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 92190da..058a9f2 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -1985,22 +1985,10 @@
 	b43_mac_enable(dev);
 }
 
-static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg)
-{
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-	return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-	b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
 static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
 				 u16 set)
 {
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
 	b43_write16(dev, B43_MMIO_PHY_DATA,
 		    (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
 }
@@ -2016,7 +2004,7 @@
 	} else
 		reg |= 0x200;
 
-	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
 	return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
 }
 
@@ -2025,7 +2013,7 @@
 	/* Register 1 is a 32-bit register. */
 	B43_WARN_ON(reg == 1);
 
-	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
 	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
 }
 
@@ -2713,8 +2701,6 @@
 	.free			= b43_lpphy_op_free,
 	.prepare_structs	= b43_lpphy_op_prepare_structs,
 	.init			= b43_lpphy_op_init,
-	.phy_read		= b43_lpphy_op_read,
-	.phy_write		= b43_lpphy_op_write,
 	.phy_maskset		= b43_lpphy_op_maskset,
 	.radio_read		= b43_lpphy_op_radio_read,
 	.radio_write		= b43_lpphy_op_radio_write,
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 6a12c55..2ea4408 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -34,6 +34,7 @@
 #include "radio_2056.h"
 #include "radio_2057.h"
 #include "main.h"
+#include "ppr.h"
 
 struct nphy_txgains {
 	u16 tx_lpf[2];
@@ -3606,16 +3607,6 @@
  * Tx and Rx
  **************************************************/
 
-static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev)
-{//TODO
-}
-
-static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
-							bool ignore_tssi)
-{//TODO
-	return B43_TXPWR_RES_DONE;
-}
-
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */
 static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
 {
@@ -4069,6 +4060,7 @@
 
 	s16 a1[2], b0[2], b1[2];
 	u8 idle[2];
+	u8 ppr_max;
 	s8 target[2];
 	s32 num, den, pwr;
 	u32 regval[64];
@@ -4147,7 +4139,12 @@
 			b1[0] = b1[1] = -1393;
 		}
 	}
-	/* target[0] = target[1] = nphy->tx_power_max; */
+
+	ppr_max = b43_ppr_get_max(dev, &nphy->tx_pwr_max_ppr);
+	if (ppr_max) {
+		target[0] = ppr_max;
+		target[1] = ppr_max;
+	}
 
 	if (dev->phy.rev >= 3) {
 		if (sprom->fem.ghz2.tssipos)
@@ -4235,8 +4232,9 @@
 
 	const u32 *table = NULL;
 	u32 rfpwr_offset;
-	u8 pga_gain;
+	u8 pga_gain, pad_gain;
 	int i;
+	const s16 *uninitialized_var(rf_pwr_offset_table);
 
 	table = b43_nphy_get_tx_gain_table(dev);
 	if (!table)
@@ -4252,13 +4250,27 @@
 	nphy->gmval = (table[0] >> 16) & 0x7000;
 #endif
 
+	if (phy->rev >= 19) {
+		return;
+	} else if (phy->rev >= 7) {
+		rf_pwr_offset_table = b43_ntab_get_rf_pwr_offset_table(dev);
+		if (!rf_pwr_offset_table)
+			return;
+		/* TODO: Enable this once we have gains configured */
+		return;
+	}
+
 	for (i = 0; i < 128; i++) {
 		if (phy->rev >= 19) {
 			/* TODO */
 			return;
 		} else if (phy->rev >= 7) {
-			/* TODO */
-			return;
+			pga_gain = (table[i] >> 24) & 0xf;
+			pad_gain = (table[i] >> 19) & 0x1f;
+			if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+				rfpwr_offset = rf_pwr_offset_table[pad_gain];
+			else
+				rfpwr_offset = rf_pwr_offset_table[pga_gain];
 		} else {
 			pga_gain = (table[i] >> 24) & 0xF;
 			if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
@@ -5874,6 +5886,69 @@
 	b43_mac_enable(dev);
 }
 
+static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
+							bool ignore_tssi)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_phy_n *nphy = dev->phy.n;
+	struct ieee80211_channel *channel = dev->wl->hw->conf.chandef.chan;
+	struct b43_ppr *ppr = &nphy->tx_pwr_max_ppr;
+	u8 max; /* qdBm */
+	bool tx_pwr_state;
+
+	if (nphy->tx_pwr_last_recalc_freq == channel->center_freq &&
+	    nphy->tx_pwr_last_recalc_limit == phy->desired_txpower)
+		return B43_TXPWR_RES_DONE;
+
+	/* Make sure we have a clean PPR */
+	b43_ppr_clear(dev, ppr);
+
+	/* HW limitations */
+	b43_ppr_load_max_from_sprom(dev, ppr, B43_BAND_2G);
+
+	/* Regulatory & user settings */
+	max = INT_TO_Q52(phy->chandef->chan->max_power);
+	if (phy->desired_txpower)
+		max = min_t(u8, max, INT_TO_Q52(phy->desired_txpower));
+	b43_ppr_apply_max(dev, ppr, max);
+	if (b43_debug(dev, B43_DBG_XMITPOWER))
+		b43dbg(dev->wl, "Calculated TX power: " Q52_FMT "\n",
+		       Q52_ARG(b43_ppr_get_max(dev, ppr)));
+
+	/* TODO: Enable this once we get gains working */
+#if 0
+	/* Some extra gains */
+	hw_gain = 6; /* N-PHY specific */
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+		hw_gain += sprom->antenna_gain.a0;
+	else
+		hw_gain += sprom->antenna_gain.a1;
+	b43_ppr_add(dev, ppr, -hw_gain);
+#endif
+
+	/* Make sure we didn't go too low */
+	b43_ppr_apply_min(dev, ppr, INT_TO_Q52(8));
+
+	/* Apply */
+	tx_pwr_state = nphy->txpwrctrl;
+	b43_mac_suspend(dev);
+	b43_nphy_tx_power_ctl_setup(dev);
+	if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12) {
+		b43_maskset32(dev, B43_MMIO_MACCTL, ~0, B43_MACCTL_PHY_LOCK);
+		b43_read32(dev, B43_MMIO_MACCTL);
+		udelay(1);
+	}
+	b43_nphy_tx_power_ctrl(dev, nphy->txpwrctrl);
+	if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12)
+		b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_PHY_LOCK, 0);
+	b43_mac_enable(dev);
+
+	nphy->tx_pwr_last_recalc_freq = channel->center_freq;
+	nphy->tx_pwr_last_recalc_limit = phy->desired_txpower;
+
+	return B43_TXPWR_RES_DONE;
+}
+
 /**************************************************
  * N-PHY init
  **************************************************/
@@ -6294,7 +6369,7 @@
 		b43_mac_switch_freq(dev, spuravoid);
 
 		if (dev->phy.rev == 3 || dev->phy.rev == 4)
-			; /* TODO: reset PLL */
+			b43_wireless_core_phy_pll_reset(dev);
 
 		if (spuravoid)
 			b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTRX);
@@ -6407,6 +6482,7 @@
 	nphy = kzalloc(sizeof(*nphy), GFP_KERNEL);
 	if (!nphy)
 		return -ENOMEM;
+
 	dev->phy.n = nphy;
 
 	return 0;
@@ -6497,26 +6573,13 @@
 #endif /* B43_DEBUG */
 }
 
-static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg)
-{
-	check_phyreg(dev, reg);
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-	return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
-	check_phyreg(dev, reg);
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-	b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
 static void b43_nphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
 				 u16 set)
 {
 	check_phyreg(dev, reg);
-	b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
 	b43_maskset16(dev, B43_MMIO_PHY_DATA, mask, set);
+	dev->phy.writes_counter = 1;
 }
 
 static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
@@ -6529,7 +6592,7 @@
 	else
 		reg |= 0x100;
 
-	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
 	return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
 }
 
@@ -6538,7 +6601,7 @@
 	/* Register 1 is a 32-bit register. */
 	B43_WARN_ON(dev->phy.rev < 7 && reg == 1);
 
-	b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+	b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
 	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
 }
 
@@ -6652,8 +6715,6 @@
 	.free			= b43_nphy_op_free,
 	.prepare_structs	= b43_nphy_op_prepare_structs,
 	.init			= b43_nphy_op_init,
-	.phy_read		= b43_nphy_op_read,
-	.phy_write		= b43_nphy_op_write,
 	.phy_maskset		= b43_nphy_op_maskset,
 	.radio_read		= b43_nphy_op_radio_read,
 	.radio_write		= b43_nphy_op_radio_write,
@@ -6662,5 +6723,4 @@
 	.switch_channel		= b43_nphy_op_switch_channel,
 	.get_default_chan	= b43_nphy_op_get_default_chan,
 	.recalc_txpower		= b43_nphy_op_recalc_txpower,
-	.adjust_txpower		= b43_nphy_op_adjust_txpower,
 };
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h
index 30bec81..a6da2c3 100644
--- a/drivers/net/wireless/b43/phy_n.h
+++ b/drivers/net/wireless/b43/phy_n.h
@@ -2,6 +2,7 @@
 #define B43_NPHY_H_
 
 #include "phy_common.h"
+#include "ppr.h"
 
 
 /* N-PHY registers. */
@@ -967,6 +968,9 @@
 	struct b43_phy_n_txpwrindex txpwrindex[2];
 	struct b43_phy_n_pwr_ctl_info pwr_ctl_info[2];
 	struct b43_chanspec txiqlocal_chanspec;
+	struct b43_ppr tx_pwr_max_ppr;
+	u16 tx_pwr_last_recalc_freq;
+	int tx_pwr_last_recalc_limit;
 
 	u8 txrx_chain;
 	u16 tx_rx_cal_phy_saveregs[11];
diff --git a/drivers/net/wireless/b43/ppr.c b/drivers/net/wireless/b43/ppr.c
new file mode 100644
index 0000000..9a77027
--- /dev/null
+++ b/drivers/net/wireless/b43/ppr.c
@@ -0,0 +1,199 @@
+/*
+ * Broadcom B43 wireless driver
+ * PPR (Power Per Rate) management
+ *
+ * Copyright (c) 2014 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 "ppr.h"
+#include "b43.h"
+
+#define ppr_for_each_entry(ppr, i, entry)				\
+	for (i = 0, entry = &(ppr)->__all_rates[i];			\
+	     i < B43_PPR_RATES_NUM;					\
+	     i++, entry++)
+
+void b43_ppr_clear(struct b43_wldev *dev, struct b43_ppr *ppr)
+{
+	memset(ppr, 0, sizeof(*ppr));
+
+	/* Compile-time PPR check */
+	BUILD_BUG_ON(sizeof(struct b43_ppr) != B43_PPR_RATES_NUM * sizeof(u8));
+}
+
+void b43_ppr_add(struct b43_wldev *dev, struct b43_ppr *ppr, int diff)
+{
+	int i;
+	u8 *rate;
+
+	ppr_for_each_entry(ppr, i, rate) {
+		*rate = clamp_val(*rate + diff, 0, 127);
+	}
+}
+
+void b43_ppr_apply_max(struct b43_wldev *dev, struct b43_ppr *ppr, u8 max)
+{
+	int i;
+	u8 *rate;
+
+	ppr_for_each_entry(ppr, i, rate) {
+		*rate = min(*rate, max);
+	}
+}
+
+void b43_ppr_apply_min(struct b43_wldev *dev, struct b43_ppr *ppr, u8 min)
+{
+	int i;
+	u8 *rate;
+
+	ppr_for_each_entry(ppr, i, rate) {
+		*rate = max(*rate, min);
+	}
+}
+
+u8 b43_ppr_get_max(struct b43_wldev *dev, struct b43_ppr *ppr)
+{
+	u8 res = 0;
+	int i;
+	u8 *rate;
+
+	ppr_for_each_entry(ppr, i, rate) {
+		res = max(*rate, res);
+	}
+
+	return res;
+}
+
+bool b43_ppr_load_max_from_sprom(struct b43_wldev *dev, struct b43_ppr *ppr,
+				 enum b43_band band)
+{
+	struct b43_ppr_rates *rates = &ppr->rates;
+	struct ssb_sprom *sprom = dev->dev->bus_sprom;
+	struct b43_phy *phy = &dev->phy;
+	u8 maxpwr, off;
+	u32 sprom_ofdm_po;
+	u16 *sprom_mcs_po;
+	u8 extra_cdd_po, extra_stbc_po;
+	int i;
+
+	switch (band) {
+	case B43_BAND_2G:
+		maxpwr = min(sprom->core_pwr_info[0].maxpwr_2g,
+			     sprom->core_pwr_info[1].maxpwr_2g);
+		sprom_ofdm_po = sprom->ofdm2gpo;
+		sprom_mcs_po = sprom->mcs2gpo;
+		extra_cdd_po = (sprom->cddpo >> 0) & 0xf;
+		extra_stbc_po = (sprom->stbcpo >> 0) & 0xf;
+		break;
+	case B43_BAND_5G_LO:
+		maxpwr = min(sprom->core_pwr_info[0].maxpwr_5gl,
+			     sprom->core_pwr_info[1].maxpwr_5gl);
+		sprom_ofdm_po = sprom->ofdm5glpo;
+		sprom_mcs_po = sprom->mcs5glpo;
+		extra_cdd_po = (sprom->cddpo >> 8) & 0xf;
+		extra_stbc_po = (sprom->stbcpo >> 8) & 0xf;
+		break;
+	case B43_BAND_5G_MI:
+		maxpwr = min(sprom->core_pwr_info[0].maxpwr_5g,
+			     sprom->core_pwr_info[1].maxpwr_5g);
+		sprom_ofdm_po = sprom->ofdm5gpo;
+		sprom_mcs_po = sprom->mcs5gpo;
+		extra_cdd_po = (sprom->cddpo >> 4) & 0xf;
+		extra_stbc_po = (sprom->stbcpo >> 4) & 0xf;
+		break;
+	case B43_BAND_5G_HI:
+		maxpwr = min(sprom->core_pwr_info[0].maxpwr_5gh,
+			     sprom->core_pwr_info[1].maxpwr_5gh);
+		sprom_ofdm_po = sprom->ofdm5ghpo;
+		sprom_mcs_po = sprom->mcs5ghpo;
+		extra_cdd_po = (sprom->cddpo >> 12) & 0xf;
+		extra_stbc_po = (sprom->stbcpo >> 12) & 0xf;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return false;
+	}
+
+	if (band == B43_BAND_2G) {
+		for (i = 0; i < 4; i++) {
+			off = ((sprom->cck2gpo >> (i * 4)) & 0xf) * 2;
+			rates->cck[i] = maxpwr - off;
+		}
+	}
+
+	/* OFDM */
+	for (i = 0; i < 8; i++) {
+		off = ((sprom_ofdm_po >> (i * 4)) & 0xf) * 2;
+		rates->ofdm[i] = maxpwr - off;
+	}
+
+	/* MCS 20 SISO */
+	rates->mcs_20[0] = rates->ofdm[0];
+	rates->mcs_20[1] = rates->ofdm[2];
+	rates->mcs_20[2] = rates->ofdm[3];
+	rates->mcs_20[3] = rates->ofdm[4];
+	rates->mcs_20[4] = rates->ofdm[5];
+	rates->mcs_20[5] = rates->ofdm[6];
+	rates->mcs_20[6] = rates->ofdm[7];
+	rates->mcs_20[7] = rates->ofdm[7];
+
+	/* MCS 20 CDD */
+	for (i = 0; i < 4; i++) {
+		off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2;
+		rates->mcs_20_cdd[i] = maxpwr - off;
+		if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+			rates->mcs_20_cdd[i] -= extra_cdd_po;
+	}
+	for (i = 0; i < 4; i++) {
+		off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2;
+		rates->mcs_20_cdd[4 + i] = maxpwr - off;
+		if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+			rates->mcs_20_cdd[4 + i] -= extra_cdd_po;
+	}
+
+	/* OFDM 20 CDD */
+	rates->ofdm_20_cdd[0] = rates->mcs_20_cdd[0];
+	rates->ofdm_20_cdd[1] = rates->mcs_20_cdd[0];
+	rates->ofdm_20_cdd[2] = rates->mcs_20_cdd[1];
+	rates->ofdm_20_cdd[3] = rates->mcs_20_cdd[2];
+	rates->ofdm_20_cdd[4] = rates->mcs_20_cdd[3];
+	rates->ofdm_20_cdd[5] = rates->mcs_20_cdd[4];
+	rates->ofdm_20_cdd[6] = rates->mcs_20_cdd[5];
+	rates->ofdm_20_cdd[7] = rates->mcs_20_cdd[6];
+
+	/* MCS 20 STBC */
+	for (i = 0; i < 4; i++) {
+		off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2;
+		rates->mcs_20_stbc[i] = maxpwr - off;
+		if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+			rates->mcs_20_stbc[i] -= extra_stbc_po;
+	}
+	for (i = 0; i < 4; i++) {
+		off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2;
+		rates->mcs_20_stbc[4 + i] = maxpwr - off;
+		if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+			rates->mcs_20_stbc[4 + i] -= extra_stbc_po;
+	}
+
+	/* MCS 20 SDM */
+	for (i = 0; i < 4; i++) {
+		off = ((sprom_mcs_po[2] >> (i * 4)) & 0xf) * 2;
+		rates->mcs_20_sdm[i] = maxpwr - off;
+	}
+	for (i = 0; i < 4; i++) {
+		off = ((sprom_mcs_po[3] >> (i * 4)) & 0xf) * 2;
+		rates->mcs_20_sdm[4 + i] = maxpwr - off;
+	}
+
+	return true;
+}
diff --git a/drivers/net/wireless/b43/ppr.h b/drivers/net/wireless/b43/ppr.h
new file mode 100644
index 0000000..24d7447
--- /dev/null
+++ b/drivers/net/wireless/b43/ppr.h
@@ -0,0 +1,45 @@
+#ifndef LINUX_B43_PPR_H_
+#define LINUX_B43_PPR_H_
+
+#include <linux/types.h>
+
+#define B43_PPR_CCK_RATES_NUM		4
+#define B43_PPR_OFDM_RATES_NUM		8
+#define B43_PPR_MCS_RATES_NUM		8
+
+#define B43_PPR_RATES_NUM	(B43_PPR_CCK_RATES_NUM +	\
+				 B43_PPR_OFDM_RATES_NUM * 2 +	\
+				 B43_PPR_MCS_RATES_NUM * 4)
+
+struct b43_ppr_rates {
+	u8 cck[B43_PPR_CCK_RATES_NUM];
+	u8 ofdm[B43_PPR_OFDM_RATES_NUM];
+	u8 ofdm_20_cdd[B43_PPR_OFDM_RATES_NUM];
+	u8 mcs_20[B43_PPR_MCS_RATES_NUM]; /* SISO */
+	u8 mcs_20_cdd[B43_PPR_MCS_RATES_NUM];
+	u8 mcs_20_stbc[B43_PPR_MCS_RATES_NUM];
+	u8 mcs_20_sdm[B43_PPR_MCS_RATES_NUM];
+};
+
+struct b43_ppr {
+	/* All powers are in qdbm (Q5.2) */
+	union {
+		u8 __all_rates[B43_PPR_RATES_NUM];
+		struct b43_ppr_rates rates;
+	};
+};
+
+struct b43_wldev;
+enum b43_band;
+
+void b43_ppr_clear(struct b43_wldev *dev, struct b43_ppr *ppr);
+
+void b43_ppr_add(struct b43_wldev *dev, struct b43_ppr *ppr, int diff);
+void b43_ppr_apply_max(struct b43_wldev *dev, struct b43_ppr *ppr, u8 max);
+void b43_ppr_apply_min(struct b43_wldev *dev, struct b43_ppr *ppr, u8 min);
+u8 b43_ppr_get_max(struct b43_wldev *dev, struct b43_ppr *ppr);
+
+bool b43_ppr_load_max_from_sprom(struct b43_wldev *dev, struct b43_ppr *ppr,
+				 enum b43_band band);
+
+#endif /* LINUX_B43_PPR_H_ */
diff --git a/drivers/net/wireless/b43/radio_2059.c b/drivers/net/wireless/b43/radio_2059.c
index 38e31d8..a3cf9ef 100644
--- a/drivers/net/wireless/b43/radio_2059.c
+++ b/drivers/net/wireless/b43/radio_2059.c
@@ -25,6 +25,13 @@
 #include "b43.h"
 #include "radio_2059.h"
 
+/* Extracted from MMIO dump of 6.30.223.141 */
+static u16 r2059_phy_rev1_init[][2] = {
+	{ 0x051, 0x70 }, { 0x05a, 0x03 }, { 0x079, 0x01 }, { 0x082, 0x70 },
+	{ 0x083, 0x00 }, { 0x084, 0x70 }, { 0x09a, 0x7f }, { 0x0b6, 0x10 },
+	{ 0x188, 0x05 },
+};
+
 #define RADIOREGS(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \
 		  r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \
 		  r20) \
@@ -58,73 +65,87 @@
 	.phy_regs.bw5	= r4,	\
 	.phy_regs.bw6	= r5
 
+/* Extracted from MMIO dump of 6.30.223.141
+ * TODO: Values for channels 12 & 13 are outdated (from some old 5.x driver)!
+ */
 static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radio2059[] = {
-  {	.freq			= 2412,
-	RADIOREGS(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c,
-		  0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03,
-		  0x00, 0x00, 0x00, 0xf0, 0x00),
-	PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
-  },
-  {	.freq			= 2417,
-	RADIOREGS(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71,
-		  0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03,
-		  0x00, 0x00, 0x00, 0xf0, 0x00),
-	PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
-  },
-  {	.freq			= 2422,
-	RADIOREGS(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76,
-		  0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03,
-		  0x00, 0x00, 0x00, 0xf0, 0x00),
-	PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
-  },
-  {	.freq			= 2427,
-	RADIOREGS(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b,
-		  0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03,
-		  0x00, 0x00, 0x00, 0xf0, 0x00),
-	PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
-  },
-  {	.freq			= 2432,
-	RADIOREGS(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80,
-		  0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03,
-		  0x00, 0x00, 0x00, 0xf0, 0x00),
-	PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
-  },
-  {	.freq			= 2437,
-	RADIOREGS(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85,
-		  0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03,
-		  0x00, 0x00, 0x00, 0xf0, 0x00),
-	PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
-  },
-  {	.freq			= 2442,
-	RADIOREGS(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a,
-		  0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03,
-		  0x00, 0x00, 0x00, 0xf0, 0x00),
-	PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
-  },
-  {	.freq			= 2447,
-	RADIOREGS(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f,
-		  0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03,
-		  0x00, 0x00, 0x00, 0xf0, 0x00),
-	PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
-  },
-  {	.freq			= 2452,
-	RADIOREGS(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94,
-		  0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03,
-		  0x00, 0x00, 0x00, 0xf0, 0x00),
-	PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
-  },
-  {	.freq			= 2457,
-	RADIOREGS(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99,
-		  0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03,
-		  0x00, 0x00, 0x00, 0xf0, 0x00),
-	PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
-  },
-  {	.freq			= 2462,
-	RADIOREGS(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e,
-		  0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03,
-		  0x00, 0x00, 0x00, 0xf0, 0x00),
-	PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
-  },
+	{
+		.freq			= 2412,
+		RADIOREGS(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c,
+			  0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73,
+			  0x00, 0x00, 0x00, 0xd0, 0x00),
+		PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
+	},
+	{
+		.freq			= 2417,
+		RADIOREGS(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71,
+			  0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73,
+			  0x00, 0x00, 0x00, 0xd0, 0x00),
+		PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
+	},
+	{
+		.freq			= 2422,
+		RADIOREGS(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76,
+			  0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x73,
+			  0x00, 0x00, 0x00, 0xd0, 0x00),
+		PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
+	},
+	{
+		.freq			= 2427,
+		RADIOREGS(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b,
+			  0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x73,
+			  0x00, 0x00, 0x00, 0xa0, 0x00),
+		PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
+	},
+	{
+		.freq			= 2432,
+		RADIOREGS(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80,
+			  0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x73,
+			  0x00, 0x00, 0x00, 0xa0, 0x00),
+		PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
+	},
+	{
+		.freq			= 2437,
+		RADIOREGS(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85,
+			  0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x73,
+			  0x00, 0x00, 0x00, 0xa0, 0x00),
+		PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
+	},
+	{
+		.freq			= 2442,
+		RADIOREGS(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a,
+			  0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73,
+			  0x00, 0x00, 0x00, 0x80, 0x00),
+		PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
+	},
+	{
+		.freq			= 2447,
+		RADIOREGS(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f,
+			  0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73,
+			  0x00, 0x00, 0x00, 0x80, 0x00),
+		PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
+	},
+	{
+		.freq			= 2452,
+		RADIOREGS(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94,
+			  0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x73,
+			  0x00, 0x00, 0x00, 0x80, 0x00),
+		PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
+	},
+	{
+		.freq			= 2457,
+		RADIOREGS(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99,
+			  0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x73,
+			  0x00, 0x00, 0x00, 0x60, 0x00),
+		PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
+	},
+	{
+		.freq			= 2462,
+		RADIOREGS(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e,
+			  0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x73,
+			  0x00, 0x00, 0x00, 0x60, 0x00),
+		PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
+	},
   {	.freq			= 2467,
 	RADIOREGS(0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3,
 		  0x09, 0x0f, 0x05, 0x00, 0x05, 0x00, 0x61, 0x03,
@@ -137,8 +158,196 @@
 		  0x00, 0x00, 0x00, 0xf0, 0x00),
 	PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429),
   },
+	{
+		.freq			= 5180,
+		RADIOREGS(0xbe, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x06,
+			  0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00,
+			  0x0f, 0x4f, 0xa3, 0x00, 0xfc),
+		PHYREGS(0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb),
+	},
+	{
+		.freq			= 5200,
+		RADIOREGS(0xc5, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x08,
+			  0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00,
+			  0x0f, 0x4f, 0x93, 0x00, 0xfb),
+		PHYREGS(0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9),
+	},
+	{
+		.freq			= 5220,
+		RADIOREGS(0xcc, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0a,
+			  0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00,
+			  0x0f, 0x4f, 0x93, 0x00, 0xea),
+		PHYREGS(0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7),
+	},
+	{
+		.freq			= 5240,
+		RADIOREGS(0xd2, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0c,
+			  0x02, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00,
+			  0x0f, 0x4f, 0x93, 0x00, 0xda),
+		PHYREGS(0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5),
+	},
+	{
+		.freq			= 5260,
+		RADIOREGS(0xd9, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x0e,
+			  0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00,
+			  0x0f, 0x4f, 0x93, 0x00, 0xca),
+		PHYREGS(0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3),
+	},
+	{
+		.freq			= 5280,
+		RADIOREGS(0xe0, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x10,
+			  0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00,
+			  0x0f, 0x4f, 0x93, 0x00, 0xb9),
+		PHYREGS(0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1),
+	},
+	{
+		.freq			= 5300,
+		RADIOREGS(0xe6, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x12,
+			  0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00,
+			  0x0f, 0x4c, 0x83, 0x00, 0xb8),
+		PHYREGS(0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0),
+	},
+	{
+		.freq			= 5320,
+		RADIOREGS(0xed, 0x16, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x14,
+			  0x02, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x00,
+			  0x0f, 0x4c, 0x83, 0x00, 0xa8),
+		PHYREGS(0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee),
+	},
+	{
+		.freq			= 5500,
+		RADIOREGS(0x29, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x26,
+			  0x02, 0x09, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00,
+			  0x0a, 0x46, 0x43, 0x00, 0x75),
+		PHYREGS(0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd),
+	},
+	{
+		.freq			= 5520,
+		RADIOREGS(0x30, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x28,
+			  0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
+			  0x0a, 0x46, 0x43, 0x00, 0x75),
+		PHYREGS(0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc),
+	},
+	{
+		.freq			= 5540,
+		RADIOREGS(0x36, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2a,
+			  0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
+			  0x0a, 0x46, 0x43, 0x00, 0x75),
+		PHYREGS(0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da),
+	},
+	{
+		.freq			= 5560,
+		RADIOREGS(0x3d, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2c,
+			  0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
+			  0x0a, 0x46, 0x43, 0x00, 0x75),
+		PHYREGS(0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8),
+	},
+	{
+		.freq			= 5580,
+		RADIOREGS(0x44, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x2e,
+			  0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
+			  0x0a, 0x46, 0x43, 0x00, 0x74),
+		PHYREGS(0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7),
+	},
+	{
+		.freq			= 5600,
+		RADIOREGS(0x4a, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x30,
+			  0x02, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
+			  0x09, 0x44, 0x23, 0x00, 0x54),
+		PHYREGS(0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5),
+	},
+	{
+		.freq			= 5620,
+		RADIOREGS(0x51, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x32,
+			  0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
+			  0x09, 0x44, 0x23, 0x00, 0x54),
+		PHYREGS(0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3),
+	},
+	{
+		.freq			= 5640,
+		RADIOREGS(0x58, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x34,
+			  0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
+			  0x09, 0x44, 0x23, 0x00, 0x43),
+		PHYREGS(0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2),
+	},
+	{
+		.freq			= 5660,
+		RADIOREGS(0x5e, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x36,
+			  0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
+			  0x09, 0x43, 0x23, 0x00, 0x43),
+		PHYREGS(0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0),
+	},
+	{
+		.freq			= 5680,
+		RADIOREGS(0x65, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x38,
+			  0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
+			  0x09, 0x42, 0x23, 0x00, 0x43),
+		PHYREGS(0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce),
+	},
+	{
+		.freq			= 5700,
+		RADIOREGS(0x6c, 0x17, 0x10, 0x1f, 0x08, 0x08, 0x3f, 0x3a,
+			  0x02, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
+			  0x08, 0x42, 0x13, 0x00, 0x32),
+		PHYREGS(0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd),
+	},
+	{
+		.freq			= 5745,
+		RADIOREGS(0x7b, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x7d,
+			  0x04, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00,
+			  0x08, 0x42, 0x13, 0x00, 0x21),
+		PHYREGS(0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9),
+	},
+	{
+		.freq			= 5765,
+		RADIOREGS(0x81, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x81,
+			  0x04, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00,
+			  0x08, 0x42, 0x13, 0x00, 0x11),
+		PHYREGS(0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8),
+	},
+	{
+		.freq			= 5785,
+		RADIOREGS(0x88, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x85,
+			  0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00,
+			  0x08, 0x42, 0x13, 0x00, 0x00),
+		PHYREGS(0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6),
+	},
+	{
+		.freq			= 5805,
+		RADIOREGS(0x8f, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x89,
+			  0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00,
+			  0x06, 0x41, 0x03, 0x00, 0x00),
+		PHYREGS(0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4),
+	},
+	{
+		.freq			= 5825,
+		RADIOREGS(0x95, 0x17, 0x20, 0x1f, 0x08, 0x08, 0x3f, 0x8d,
+			  0x04, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x00,
+			  0x06, 0x41, 0x03, 0x00, 0x00),
+		PHYREGS(0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3),
+	},
 };
 
+void r2059_upload_inittabs(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 *table = NULL;
+	u16 size, i;
+
+	switch (phy->rev) {
+	case 1:
+		table = r2059_phy_rev1_init[0];
+		size = ARRAY_SIZE(r2059_phy_rev1_init);
+		break;
+	default:
+		B43_WARN_ON(1);
+		return;
+	}
+
+	for (i = 0; i < size; i++, table += 2)
+		b43_radio_write(dev, R2059_ALL | table[0], table[1]);
+}
+
 const struct b43_phy_ht_channeltab_e_radio2059
 *b43_phy_ht_get_channeltab_e_r2059(struct b43_wldev *dev, u16 freq)
 {
diff --git a/drivers/net/wireless/b43/radio_2059.h b/drivers/net/wireless/b43/radio_2059.h
index 40a82d7..9e22fb6 100644
--- a/drivers/net/wireless/b43/radio_2059.h
+++ b/drivers/net/wireless/b43/radio_2059.h
@@ -10,6 +10,18 @@
 #define R2059_C3			0x800
 #define R2059_ALL			0xC00
 
+#define R2059_RCAL_CONFIG			0x004
+#define R2059_RFPLL_MASTER			0x011
+#define R2059_RFPLL_MISC_EN			0x02b
+#define R2059_RFPLL_MISC_CAL_RESETN		0x02e
+#define R2059_XTAL_CONFIG2			0x0c0
+#define R2059_RCCAL_START_R1_Q1_P1		0x13c
+#define R2059_RCCAL_X1				0x13d
+#define R2059_RCCAL_TRC0			0x13e
+#define R2059_RCCAL_DONE_OSCCAP			0x140
+#define R2059_RCAL_STATUS			0x145
+#define R2059_RCCAL_MASTER			0x17f
+
 /* Values for various registers uploaded on channel switching */
 struct b43_phy_ht_channeltab_e_radio2059 {
 	/* The channel frequency in MHz */
@@ -40,6 +52,8 @@
 	struct b43_phy_ht_channeltab_e_phy phy_regs;
 };
 
+void r2059_upload_inittabs(struct b43_wldev *dev);
+
 const struct b43_phy_ht_channeltab_e_radio2059
 *b43_phy_ht_get_channeltab_e_r2059(struct b43_wldev *dev, u16 freq);
 
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index 4b58850..25d1cbd 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -2878,6 +2878,40 @@
 	-54, -46, -39, -31, -23, -15, -8, 0
 };
 
+/* Extracted from MMIO dump of 6.30.223.248
+ * Entries: 0, 15, 17, 21, 24, 26, 27, 29, 30 were guessed
+ */
+static const s16 b43_ntab_rf_pwr_offset_2057_rev9_2g[] = {
+	-133, -133, -107, -92, -81,
+	-73, -66, -61, -56, -52,
+	-48, -44, -41, -37, -34,
+	-31, -28, -25, -22, -19,
+	-17, -14, -12, -10, -9,
+	-7, -5, -4, -3, -2,
+	-1, 0,
+};
+
+/* Extracted from MMIO dump of 6.30.223.248 */
+static const s16 b43_ntab_rf_pwr_offset_2057_rev9_5g[] = {
+	-101, -94, -86, -79, -72,
+	-65, -57, -50, -42, -35,
+	-28, -21, -16, -9, -4,
+	0,
+};
+
+/* Extracted from MMIO dump of 6.30.223.248
+ * Entries: 0, 26, 28, 29, 30, 31 were guessed
+ */
+static const s16 b43_ntab_rf_pwr_offset_2057_rev14_2g[] = {
+	-111, -111, -111, -84, -70,
+	-59, -52, -45, -40, -36,
+	-32, -29, -26, -23, -21,
+	-18, -16, -15, -13, -11,
+	-10, -8, -7, -6, -5,
+	-4, -4, -3, -3, -2,
+	-2, -1,
+};
+
 const u16 tbl_iqcal_gainparams[2][9][8] = {
 	{
 		{ 0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69 },
@@ -3197,7 +3231,7 @@
 			{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
 			0x527E, /* invalid for external LNA! */
 			{ 0x513F, 0x513F, 0x513F, 0x513F }, /* invalid for external LNA! */
-			0x1076, 0x0066, 0x0000, /* low is invalid (the last one) */
+			0x007E, 0x0066, 0x0000, /* low is invalid (the last one) */
 			0x18, 0x18, 0x18,
 			0x01D0, 0x5,
 		},
@@ -3708,9 +3742,43 @@
 	}
 }
 
+const s16 *b43_ntab_get_rf_pwr_offset_table(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+		switch (phy->rev) {
+		case 17:
+			if (phy->radio_rev == 14)
+				return b43_ntab_rf_pwr_offset_2057_rev14_2g;
+			break;
+		case 16:
+			if (phy->radio_rev == 9)
+				return b43_ntab_rf_pwr_offset_2057_rev9_2g;
+			break;
+		}
+
+		b43err(dev->wl,
+		       "No 2GHz RF power table available for this device\n");
+		return NULL;
+	} else {
+		switch (phy->rev) {
+		case 16:
+			if (phy->radio_rev == 9)
+				return b43_ntab_rf_pwr_offset_2057_rev9_5g;
+			break;
+		}
+
+		b43err(dev->wl,
+		       "No 5GHz RF power table available for this device\n");
+		return NULL;
+	}
+}
+
 struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
 	struct b43_wldev *dev, bool ghz5, bool ext_lna)
 {
+	struct b43_phy *phy = &dev->phy;
 	struct nphy_gain_ctl_workaround_entry *e;
 	u8 phy_idx;
 
@@ -3729,37 +3797,49 @@
 	e = &nphy_gain_ctl_workaround[ghz5][phy_idx];
 
 	/* Some workarounds to the workarounds... */
-	if (ghz5 && dev->phy.rev >= 6) {
-		if (dev->phy.radio_rev == 11 &&
-		    !b43_is_40mhz(dev))
-			e->cliplo_gain = 0x2d;
-	} else if (!ghz5 && dev->phy.rev >= 5) {
-		static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a,
-						0x106c, 0x1074, 0x107c, 0x207c};
+	if (!ghz5) {
 		u8 tr_iso = dev->dev->bus_sprom->fem.ghz2.tr_iso;
 
-		if (ext_lna) {
+		if (tr_iso > 7)
+			tr_iso = 3;
+
+		if (phy->rev >= 6) {
+			static const int gain_data[] = { 0x106a, 0x106c, 0x1074,
+							 0x107c, 0x007e, 0x107e,
+							 0x207e, 0x307e, };
+
+			e->cliplo_gain = gain_data[tr_iso];
+		} else if (phy->rev == 5) {
+			static const int gain_data[] = { 0x0062, 0x0064, 0x006a,
+							 0x106a, 0x106c, 0x1074,
+							 0x107c, 0x207c, };
+
+			e->cliplo_gain = gain_data[tr_iso];
+		}
+
+		if (phy->rev >= 5 && ext_lna) {
 			e->rfseq_init[0] &= ~0x4000;
 			e->rfseq_init[1] &= ~0x4000;
 			e->rfseq_init[2] &= ~0x4000;
 			e->rfseq_init[3] &= ~0x4000;
 			e->init_gain &= ~0x4000;
 		}
-		if (tr_iso > 7)
-			tr_iso = 3;
-		e->cliplo_gain = gain_data[tr_iso];
-
-	} else if (ghz5 && dev->phy.rev == 4 && ext_lna) {
-		e->rfseq_init[0] &= ~0x4000;
-		e->rfseq_init[1] &= ~0x4000;
-		e->rfseq_init[2] &= ~0x4000;
-		e->rfseq_init[3] &= ~0x4000;
-		e->init_gain &= ~0x4000;
-		e->rfseq_init[0] |= 0x1000;
-		e->rfseq_init[1] |= 0x1000;
-		e->rfseq_init[2] |= 0x1000;
-		e->rfseq_init[3] |= 0x1000;
-		e->init_gain |= 0x1000;
+	} else {
+		if (phy->rev >= 6) {
+			if (phy->radio_rev == 11 && !b43_is_40mhz(dev))
+				e->crsminu = 0x2d;
+		} else if (phy->rev == 4 && ext_lna) {
+			e->rfseq_init[0] &= ~0x4000;
+			e->rfseq_init[1] &= ~0x4000;
+			e->rfseq_init[2] &= ~0x4000;
+			e->rfseq_init[3] &= ~0x4000;
+			e->init_gain &= ~0x4000;
+			e->rfseq_init[0] |= 0x1000;
+			e->rfseq_init[1] |= 0x1000;
+			e->rfseq_init[2] |= 0x1000;
+			e->rfseq_init[3] |= 0x1000;
+			e->init_gain |= 0x1000;
+		}
 	}
 
 	return e;
diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h
index 3ce2e6f..b51f386 100644
--- a/drivers/net/wireless/b43/tables_nphy.h
+++ b/drivers/net/wireless/b43/tables_nphy.h
@@ -191,6 +191,8 @@
 
 const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev);
 
+const s16 *b43_ntab_get_rf_pwr_offset_table(struct b43_wldev *dev);
+
 extern const s8 b43_ntab_papd_pga_gain_delta_ipa_2g[];
 
 extern const u16 tbl_iqcal_gainparams[2][9][8];
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index 98d9074..ba61153 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -97,9 +97,13 @@
 };
 
 /* MAC TX control */
+#define B43_TXH_MAC_RTS_FB_SHORTPRMBL	0x80000000 /* RTS fallback preamble */
+#define B43_TXH_MAC_RTS_SHORTPRMBL	0x40000000 /* RTS main rate preamble */
+#define B43_TXH_MAC_FB_SHORTPRMBL	0x20000000 /* Main fallback preamble */
 #define B43_TXH_MAC_USEFBR		0x10000000 /* Use fallback rate for this AMPDU */
 #define B43_TXH_MAC_KEYIDX		0x0FF00000 /* Security key index */
 #define B43_TXH_MAC_KEYIDX_SHIFT	20
+#define B43_TXH_MAC_ALT_TXPWR		0x00080000 /* Use alternate txpwr defined at loc. M_ALT_TXPWR_IDX */
 #define B43_TXH_MAC_KEYALG		0x00070000 /* Security key algorithm */
 #define B43_TXH_MAC_KEYALG_SHIFT	16
 #define B43_TXH_MAC_AMIC		0x00008000 /* AMIC */
@@ -126,25 +130,25 @@
 #define B43_TXH_EFT_FB			0x03 /* Data frame fallback encoding */
 #define  B43_TXH_EFT_FB_CCK		0x00 /* CCK */
 #define  B43_TXH_EFT_FB_OFDM		0x01 /* OFDM */
-#define  B43_TXH_EFT_FB_EWC		0x02 /* EWC */
-#define  B43_TXH_EFT_FB_N		0x03 /* N */
+#define  B43_TXH_EFT_FB_HT		0x02 /* HT */
+#define  B43_TXH_EFT_FB_VHT		0x03 /* VHT */
 #define B43_TXH_EFT_RTS			0x0C /* RTS/CTS encoding */
 #define  B43_TXH_EFT_RTS_CCK		0x00 /* CCK */
 #define  B43_TXH_EFT_RTS_OFDM		0x04 /* OFDM */
-#define  B43_TXH_EFT_RTS_EWC		0x08 /* EWC */
-#define  B43_TXH_EFT_RTS_N		0x0C /* N */
+#define  B43_TXH_EFT_RTS_HT		0x08 /* HT */
+#define  B43_TXH_EFT_RTS_VHT		0x0C /* VHT */
 #define B43_TXH_EFT_RTSFB		0x30 /* RTS/CTS fallback encoding */
 #define  B43_TXH_EFT_RTSFB_CCK		0x00 /* CCK */
 #define  B43_TXH_EFT_RTSFB_OFDM		0x10 /* OFDM */
-#define  B43_TXH_EFT_RTSFB_EWC		0x20 /* EWC */
-#define  B43_TXH_EFT_RTSFB_N		0x30 /* N */
+#define  B43_TXH_EFT_RTSFB_HT		0x20 /* HT */
+#define  B43_TXH_EFT_RTSFB_VHT		0x30 /* VHT */
 
 /* PHY TX control word */
 #define B43_TXH_PHY_ENC			0x0003 /* Data frame encoding */
 #define  B43_TXH_PHY_ENC_CCK		0x0000 /* CCK */
 #define  B43_TXH_PHY_ENC_OFDM		0x0001 /* OFDM */
-#define  B43_TXH_PHY_ENC_EWC		0x0002 /* EWC */
-#define  B43_TXH_PHY_ENC_N		0x0003 /* N */
+#define  B43_TXH_PHY_ENC_HT		0x0002 /* HT */
+#define  B43_TXH_PHY_ENC_VHT		0x0003 /* VHT */
 #define B43_TXH_PHY_SHORTPRMBL		0x0010 /* Use short preamble */
 #define B43_TXH_PHY_ANT			0x03C0 /* Antenna selection */
 #define  B43_TXH_PHY_ANT0		0x0000 /* Use antenna 0 */
@@ -162,7 +166,7 @@
 #define  B43_TXH_PHY1_BW_20		0x0002 /* 20 MHz */
 #define  B43_TXH_PHY1_BW_20U		0x0003 /* 20 MHz upper */
 #define  B43_TXH_PHY1_BW_40		0x0004 /* 40 MHz */
-#define  B43_TXH_PHY1_BW_40DUP		0x0005 /* 50 MHz duplicate */
+#define  B43_TXH_PHY1_BW_40DUP		0x0005 /* 40 MHz duplicate */
 #define B43_TXH_PHY1_MODE		0x0038 /* Mode */
 #define  B43_TXH_PHY1_MODE_SISO		0x0000 /* SISO */
 #define  B43_TXH_PHY1_MODE_CDD		0x0008 /* CDD */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
index 3158756..027ff83 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -67,6 +67,7 @@
  * @txctl: transmit a control request message to dongle.
  * @rxctl: receive a control response message from dongle.
  * @gettxq: obtain a reference of bus transmit queue (optional).
+ * @wowl_config: specify if dongle is configured for wowl when going to suspend
  *
  * This structure provides an abstract interface towards the
  * bus specific driver. For control messages to common driver
@@ -80,6 +81,7 @@
 	int (*txctl)(struct device *dev, unsigned char *msg, uint len);
 	int (*rxctl)(struct device *dev, unsigned char *msg, uint len);
 	struct pktq * (*gettxq)(struct device *dev);
+	void (*wowl_config)(struct device *dev, bool enabled);
 };
 
 
@@ -114,6 +116,7 @@
  * @dstats: dongle-based statistical data.
  * @dcmd_list: bus/device specific dongle initialization commands.
  * @chip: device identifier of the dongle chip.
+ * @wowl_supported: is wowl supported by bus driver.
  * @chiprev: revision of the dongle chip.
  */
 struct brcmf_bus {
@@ -131,6 +134,7 @@
 	u32 chip;
 	u32 chiprev;
 	bool always_use_fws_queue;
+	bool wowl_supported;
 
 	struct brcmf_bus_ops *ops;
 	struct brcmf_bus_msgbuf *msgbuf;
@@ -177,6 +181,13 @@
 	return bus->ops->gettxq(bus->dev);
 }
 
+static inline
+void brcmf_bus_wowl_config(struct brcmf_bus *bus, bool enabled)
+{
+	if (bus->ops->wowl_config)
+		bus->ops->wowl_config(bus->dev, enabled);
+}
+
 static inline bool brcmf_bus_ready(struct brcmf_bus *bus)
 {
 	return bus->state == BRCMF_BUS_LOAD || bus->state == BRCMF_BUS_DATA;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
index 50877e3..aed53ac 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c
@@ -107,6 +107,8 @@
 	struct brcmf_if *ifp = drvr->iflist[0];
 
 	brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan");
+	if (drvr->bus_if->wowl_supported)
+		brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
 
 	/* set chip related quirks */
 	switch (drvr->bus_if->chip) {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
index 961d175..b9a796d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.h
@@ -22,7 +22,8 @@
  * MCHAN: multi-channel for concurrent P2P.
  */
 #define BRCMF_FEAT_LIST \
-	BRCMF_FEAT_DEF(MCHAN)
+	BRCMF_FEAT_DEF(MCHAN) \
+	BRCMF_FEAT_DEF(WOWL)
 /*
  * Quirks:
  *
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
index a1016b8..1faa929 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
@@ -354,7 +354,7 @@
 	struct brcmf_flowring *flow;
 	u32 i;
 
-	flow = kzalloc(sizeof(*flow), GFP_ATOMIC);
+	flow = kzalloc(sizeof(*flow), GFP_KERNEL);
 	if (flow) {
 		flow->dev = dev;
 		flow->nrofrings = nrofrings;
@@ -364,7 +364,7 @@
 		for (i = 0; i < ARRAY_SIZE(flow->hash); i++)
 			flow->hash[i].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
 		flow->rings = kcalloc(nrofrings, sizeof(*flow->rings),
-				      GFP_ATOMIC);
+				      GFP_KERNEL);
 		if (!flow->rings) {
 			kfree(flow);
 			flow = NULL;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
index 2bc68a2..5ff5cd0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
@@ -53,6 +53,62 @@
 #define BRCMF_OBSS_COEX_OFF		0
 #define BRCMF_OBSS_COEX_ON		1
 
+/* WOWL bits */
+/* Wakeup on Magic packet: */
+#define WL_WOWL_MAGIC			(1 << 0)
+/* Wakeup on Netpattern */
+#define WL_WOWL_NET			(1 << 1)
+/* Wakeup on loss-of-link due to Disassoc/Deauth: */
+#define WL_WOWL_DIS			(1 << 2)
+/* Wakeup on retrograde TSF: */
+#define WL_WOWL_RETR			(1 << 3)
+/* Wakeup on loss of beacon: */
+#define WL_WOWL_BCN			(1 << 4)
+/* Wakeup after test: */
+#define WL_WOWL_TST			(1 << 5)
+/* Wakeup after PTK refresh: */
+#define WL_WOWL_M1			(1 << 6)
+/* Wakeup after receipt of EAP-Identity Req: */
+#define WL_WOWL_EAPID			(1 << 7)
+/* Wakeind via PME(0) or GPIO(1): */
+#define WL_WOWL_PME_GPIO		(1 << 8)
+/* need tkip phase 1 key to be updated by the driver: */
+#define WL_WOWL_NEEDTKIP1		(1 << 9)
+/* enable wakeup if GTK fails: */
+#define WL_WOWL_GTK_FAILURE		(1 << 10)
+/* support extended magic packets: */
+#define WL_WOWL_EXTMAGPAT		(1 << 11)
+/* support ARP/NS/keepalive offloading: */
+#define WL_WOWL_ARPOFFLOAD		(1 << 12)
+/* read protocol version for EAPOL frames: */
+#define WL_WOWL_WPA2			(1 << 13)
+/* If the bit is set, use key rotaton: */
+#define WL_WOWL_KEYROT			(1 << 14)
+/* If the bit is set, frm received was bcast frame: */
+#define WL_WOWL_BCAST			(1 << 15)
+/* If the bit is set, scan offload is enabled: */
+#define WL_WOWL_SCANOL			(1 << 16)
+/* Wakeup on tcpkeep alive timeout: */
+#define WL_WOWL_TCPKEEP_TIME		(1 << 17)
+/* Wakeup on mDNS Conflict Resolution: */
+#define WL_WOWL_MDNS_CONFLICT		(1 << 18)
+/* Wakeup on mDNS Service Connect: */
+#define WL_WOWL_MDNS_SERVICE		(1 << 19)
+/* tcp keepalive got data: */
+#define WL_WOWL_TCPKEEP_DATA		(1 << 20)
+/* Firmware died in wowl mode: */
+#define WL_WOWL_FW_HALT			(1 << 21)
+/* Enable detection of radio button changes: */
+#define WL_WOWL_ENAB_HWRADIO		(1 << 22)
+/* Offloads detected MIC failure(s): */
+#define WL_WOWL_MIC_FAIL		(1 << 23)
+/* Wakeup in Unassociated state (Net/Magic Pattern): */
+#define WL_WOWL_UNASSOC			(1 << 24)
+/* Wakeup if received matched secured pattern: */
+#define WL_WOWL_SECURE			(1 << 25)
+/* Link Down indication in WoWL mode: */
+#define WL_WOWL_LINKDOWN		(1 << 31)
+
 /* join preference types for join_pref iovar */
 enum brcmf_join_pref_types {
 	BRCMF_JOIN_PREF_RSSI = 1,
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index d42f7d0..183f08d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -1636,7 +1636,7 @@
 	if (!signal_len)
 		return 0;
 	/* if flow control disabled, skip to packet data and leave */
-	if (!fws->fw_signals) {
+	if ((!fws) || (!fws->fw_signals)) {
 		skb_pull(skb, signal_len);
 		return 0;
 	}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
index 8f8b937..11cc051 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
@@ -208,6 +208,14 @@
 	__le32				rsvd0[3];
 };
 
+struct brcmf_msgbuf_work_item {
+	struct list_head queue;
+	u32 flowid;
+	int ifidx;
+	u8 sa[ETH_ALEN];
+	u8 da[ETH_ALEN];
+};
+
 struct brcmf_msgbuf {
 	struct brcmf_pub *drvr;
 
@@ -230,7 +238,7 @@
 	dma_addr_t ioctbuf_handle;
 	u32 ioctbuf_phys_hi;
 	u32 ioctbuf_phys_lo;
-	u32 ioctl_resp_status;
+	int ioctl_resp_status;
 	u32 ioctl_resp_ret_len;
 	u32 ioctl_resp_pktid;
 
@@ -248,6 +256,10 @@
 	struct work_struct txflow_work;
 	unsigned long *flow_map;
 	unsigned long *txstatus_done_map;
+
+	struct work_struct flowring_work;
+	spinlock_t flowring_work_lock;
+	struct list_head work_queue;
 };
 
 struct brcmf_msgbuf_pktid {
@@ -284,11 +296,11 @@
 	struct brcmf_msgbuf_pktid *array;
 	struct brcmf_msgbuf_pktids *pktids;
 
-	array = kcalloc(nr_array_entries, sizeof(*array), GFP_ATOMIC);
+	array = kcalloc(nr_array_entries, sizeof(*array), GFP_KERNEL);
 	if (!array)
 		return NULL;
 
-	pktids = kzalloc(sizeof(*pktids), GFP_ATOMIC);
+	pktids = kzalloc(sizeof(*pktids), GFP_KERNEL);
 	if (!pktids) {
 		kfree(array);
 		return NULL;
@@ -544,11 +556,29 @@
 }
 
 
-static u32 brcmf_msgbuf_flowring_create(struct brcmf_msgbuf *msgbuf, int ifidx,
-					struct sk_buff *skb)
+static struct brcmf_msgbuf_work_item *
+brcmf_msgbuf_dequeue_work(struct brcmf_msgbuf *msgbuf)
+{
+	struct brcmf_msgbuf_work_item *work = NULL;
+	ulong flags;
+
+	spin_lock_irqsave(&msgbuf->flowring_work_lock, flags);
+	if (!list_empty(&msgbuf->work_queue)) {
+		work = list_first_entry(&msgbuf->work_queue,
+					struct brcmf_msgbuf_work_item, queue);
+		list_del(&work->queue);
+	}
+	spin_unlock_irqrestore(&msgbuf->flowring_work_lock, flags);
+
+	return work;
+}
+
+
+static u32
+brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf,
+				    struct brcmf_msgbuf_work_item *work)
 {
 	struct msgbuf_tx_flowring_create_req *create;
-	struct ethhdr *eh = (struct ethhdr *)(skb->data);
 	struct brcmf_commonring *commonring;
 	void *ret_ptr;
 	u32 flowid;
@@ -557,16 +587,11 @@
 	long long address;
 	int err;
 
-	flowid = brcmf_flowring_create(msgbuf->flow, eh->h_dest,
-				       skb->priority, ifidx);
-	if (flowid == BRCMF_FLOWRING_INVALID_ID)
-		return flowid;
-
+	flowid = work->flowid;
 	dma_sz = BRCMF_H2D_TXFLOWRING_MAX_ITEM * BRCMF_H2D_TXFLOWRING_ITEMSIZE;
-
 	dma_buf = dma_alloc_coherent(msgbuf->drvr->bus_if->dev, dma_sz,
 				     &msgbuf->flowring_dma_handle[flowid],
-				     GFP_ATOMIC);
+				     GFP_KERNEL);
 	if (!dma_buf) {
 		brcmf_err("dma_alloc_coherent failed\n");
 		brcmf_flowring_delete(msgbuf->flow, flowid);
@@ -589,13 +614,13 @@
 
 	create = (struct msgbuf_tx_flowring_create_req *)ret_ptr;
 	create->msg.msgtype = MSGBUF_TYPE_FLOW_RING_CREATE;
-	create->msg.ifidx = ifidx;
+	create->msg.ifidx = work->ifidx;
 	create->msg.request_id = 0;
 	create->tid = brcmf_flowring_tid(msgbuf->flow, flowid);
 	create->flow_ring_id = cpu_to_le16(flowid +
 					   BRCMF_NROF_H2D_COMMON_MSGRINGS);
-	memcpy(create->sa, eh->h_source, ETH_ALEN);
-	memcpy(create->da, eh->h_dest, ETH_ALEN);
+	memcpy(create->sa, work->sa, ETH_ALEN);
+	memcpy(create->da, work->da, ETH_ALEN);
 	address = (long long)(long)msgbuf->flowring_dma_handle[flowid];
 	create->flow_ring_addr.high_addr = cpu_to_le32(address >> 32);
 	create->flow_ring_addr.low_addr = cpu_to_le32(address & 0xffffffff);
@@ -603,7 +628,7 @@
 	create->len_item = cpu_to_le16(BRCMF_H2D_TXFLOWRING_ITEMSIZE);
 
 	brcmf_dbg(MSGBUF, "Send Flow Create Req flow ID %d for peer %pM prio %d ifindex %d\n",
-		  flowid, eh->h_dest, create->tid, ifidx);
+		  flowid, work->da, create->tid, work->ifidx);
 
 	err = brcmf_commonring_write_complete(commonring);
 	brcmf_commonring_unlock(commonring);
@@ -617,6 +642,53 @@
 }
 
 
+static void brcmf_msgbuf_flowring_worker(struct work_struct *work)
+{
+	struct brcmf_msgbuf *msgbuf;
+	struct brcmf_msgbuf_work_item *create;
+
+	msgbuf = container_of(work, struct brcmf_msgbuf, flowring_work);
+
+	while ((create = brcmf_msgbuf_dequeue_work(msgbuf))) {
+		brcmf_msgbuf_flowring_create_worker(msgbuf, create);
+		kfree(create);
+	}
+}
+
+
+static u32 brcmf_msgbuf_flowring_create(struct brcmf_msgbuf *msgbuf, int ifidx,
+					struct sk_buff *skb)
+{
+	struct brcmf_msgbuf_work_item *create;
+	struct ethhdr *eh = (struct ethhdr *)(skb->data);
+	u32 flowid;
+	ulong flags;
+
+	create = kzalloc(sizeof(*create), GFP_ATOMIC);
+	if (create == NULL)
+		return BRCMF_FLOWRING_INVALID_ID;
+
+	flowid = brcmf_flowring_create(msgbuf->flow, eh->h_dest,
+				       skb->priority, ifidx);
+	if (flowid == BRCMF_FLOWRING_INVALID_ID) {
+		kfree(create);
+		return flowid;
+	}
+
+	create->flowid = flowid;
+	create->ifidx = ifidx;
+	memcpy(create->sa, eh->h_source, ETH_ALEN);
+	memcpy(create->da, eh->h_dest, ETH_ALEN);
+
+	spin_lock_irqsave(&msgbuf->flowring_work_lock, flags);
+	list_add_tail(&create->queue, &msgbuf->work_queue);
+	spin_unlock_irqrestore(&msgbuf->flowring_work_lock, flags);
+	schedule_work(&msgbuf->flowring_work);
+
+	return flowid;
+}
+
+
 static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid)
 {
 	struct brcmf_flowring *flow = msgbuf->flow;
@@ -767,7 +839,8 @@
 
 	ioctl_resp = (struct msgbuf_ioctl_resp_hdr *)buf;
 
-	msgbuf->ioctl_resp_status = le16_to_cpu(ioctl_resp->compl_hdr.status);
+	msgbuf->ioctl_resp_status =
+			(s16)le16_to_cpu(ioctl_resp->compl_hdr.status);
 	msgbuf->ioctl_resp_ret_len = le16_to_cpu(ioctl_resp->resp_len);
 	msgbuf->ioctl_resp_pktid = le32_to_cpu(ioctl_resp->msg.request_id);
 
@@ -1271,7 +1344,7 @@
 	u32 count;
 
 	if_msgbuf = drvr->bus_if->msgbuf;
-	msgbuf = kzalloc(sizeof(*msgbuf), GFP_ATOMIC);
+	msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL);
 	if (!msgbuf)
 		goto fail;
 
@@ -1282,11 +1355,11 @@
 	}
 	INIT_WORK(&msgbuf->txflow_work, brcmf_msgbuf_txflow_worker);
 	count = BITS_TO_LONGS(if_msgbuf->nrof_flowrings);
-	msgbuf->flow_map = kzalloc(count, GFP_ATOMIC);
+	msgbuf->flow_map = kzalloc(count, GFP_KERNEL);
 	if (!msgbuf->flow_map)
 		goto fail;
 
-	msgbuf->txstatus_done_map = kzalloc(count, GFP_ATOMIC);
+	msgbuf->txstatus_done_map = kzalloc(count, GFP_KERNEL);
 	if (!msgbuf->txstatus_done_map)
 		goto fail;
 
@@ -1294,7 +1367,7 @@
 	msgbuf->ioctbuf = dma_alloc_coherent(drvr->bus_if->dev,
 					     BRCMF_TX_IOCTL_MAX_MSG_SIZE,
 					     &msgbuf->ioctbuf_handle,
-					     GFP_ATOMIC);
+					     GFP_KERNEL);
 	if (!msgbuf->ioctbuf)
 		goto fail;
 	address = (long long)(long)msgbuf->ioctbuf_handle;
@@ -1317,7 +1390,7 @@
 	msgbuf->flowrings = (struct brcmf_commonring **)if_msgbuf->flowrings;
 	msgbuf->nrof_flowrings = if_msgbuf->nrof_flowrings;
 	msgbuf->flowring_dma_handle = kzalloc(msgbuf->nrof_flowrings *
-		sizeof(*msgbuf->flowring_dma_handle), GFP_ATOMIC);
+		sizeof(*msgbuf->flowring_dma_handle), GFP_KERNEL);
 	if (!msgbuf->flowring_dma_handle)
 		goto fail;
 
@@ -1357,6 +1430,10 @@
 	brcmf_msgbuf_rxbuf_event_post(msgbuf);
 	brcmf_msgbuf_rxbuf_ioctlresp_post(msgbuf);
 
+	INIT_WORK(&msgbuf->flowring_work, brcmf_msgbuf_flowring_worker);
+	spin_lock_init(&msgbuf->flowring_work_lock);
+	INIT_LIST_HEAD(&msgbuf->work_queue);
+
 	return 0;
 
 fail:
@@ -1379,11 +1456,19 @@
 void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr)
 {
 	struct brcmf_msgbuf *msgbuf;
+	struct brcmf_msgbuf_work_item *work;
 
 	brcmf_dbg(TRACE, "Enter\n");
 	if (drvr->proto->pd) {
 		msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
-
+		cancel_work_sync(&msgbuf->flowring_work);
+		while (!list_empty(&msgbuf->work_queue)) {
+			work = list_first_entry(&msgbuf->work_queue,
+						struct brcmf_msgbuf_work_item,
+						queue);
+			list_del(&work->queue);
+			kfree(work);
+		}
 		kfree(msgbuf->flow_map);
 		kfree(msgbuf->txstatus_done_map);
 		if (msgbuf->txflow_wq)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
index 057b982..d54c58a 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -440,8 +440,11 @@
 
 	/* In case of COB type, firmware has default mac address
 	 * After Initializing firmware, we have to set current mac address to
-	 * firmware for P2P device address
+	 * firmware for P2P device address. This must be done with discovery
+	 * disabled.
 	 */
+	brcmf_fil_iovar_int_set(ifp, "p2p_disc", 0);
+
 	ret = brcmf_fil_iovar_data_set(ifp, "p2p_da_override", p2p_mac,
 				       ETH_ALEN);
 	if (ret)
@@ -1431,8 +1434,7 @@
 					      IEEE80211_BAND_5GHZ);
 
 	wdev = &ifp->vif->wdev;
-	cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0,
-			 GFP_ATOMIC);
+	cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0);
 
 	kfree(mgmt_frame);
 	return 0;
@@ -1896,8 +1898,7 @@
 					      IEEE80211_BAND_2GHZ :
 					      IEEE80211_BAND_5GHZ);
 
-	cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0,
-			 GFP_ATOMIC);
+	cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
 
 	brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
 		  mgmt_frame_len, e->datalen, chanspec, freq);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
index e5101b2..8c0632e 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
@@ -165,6 +165,8 @@
 
 #define BRCMF_H2D_HOST_D3_INFORM		0x00000001
 #define BRCMF_H2D_HOST_DS_ACK			0x00000002
+#define BRCMF_H2D_HOST_D0_INFORM_IN_USE		0x00000008
+#define BRCMF_H2D_HOST_D0_INFORM		0x00000010
 
 #define BRCMF_PCIE_MBDATA_TIMEOUT		2000
 
@@ -243,6 +245,7 @@
 	wait_queue_head_t mbdata_resp_wait;
 	bool mbdata_completed;
 	bool irq_allocated;
+	bool wowl_enabled;
 };
 
 struct brcmf_pcie_ringbuf {
@@ -537,7 +540,7 @@
 }
 
 
-static void
+static int
 brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)
 {
 	struct brcmf_pcie_shared_info *shared;
@@ -558,13 +561,15 @@
 		msleep(10);
 		i++;
 		if (i > 100)
-			break;
+			return -EIO;
 		cur_htod_mb_data = brcmf_pcie_read_tcm32(devinfo, addr);
 	}
 
 	brcmf_pcie_write_tcm32(devinfo, addr, htod_mb_data);
 	pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_SBMBX, 1);
 	pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_SBMBX, 1);
+
+	return 0;
 }
 
 
@@ -1229,11 +1234,27 @@
 }
 
 
+static void brcmf_pcie_wowl_config(struct device *dev, bool enabled)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
+	struct brcmf_pciedev_info *devinfo = buspub->devinfo;
+
+	brcmf_dbg(PCIE, "Configuring WOWL, enabled=%d\n", enabled);
+	devinfo->wowl_enabled = enabled;
+	if (enabled)
+		device_set_wakeup_enable(&devinfo->pdev->dev, true);
+	else
+		device_set_wakeup_enable(&devinfo->pdev->dev, false);
+}
+
+
 static struct brcmf_bus_ops brcmf_pcie_bus_ops = {
 	.txdata = brcmf_pcie_tx,
 	.stop = brcmf_pcie_down,
 	.txctl = brcmf_pcie_tx_ctlpkt,
 	.rxctl = brcmf_pcie_rx_ctlpkt,
+	.wowl_config = brcmf_pcie_wowl_config,
 };
 
 
@@ -1668,6 +1689,7 @@
 	bus->ops = &brcmf_pcie_bus_ops;
 	bus->proto_type = BRCMF_PROTO_MSGBUF;
 	bus->chip = devinfo->coreid;
+	bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot);
 	dev_set_drvdata(&pdev->dev, bus);
 
 	ret = brcmf_pcie_get_fwnames(devinfo);
@@ -1759,36 +1781,62 @@
 		brcmf_err("Timeout on response for entering D3 substate\n");
 		return -EIO;
 	}
-	brcmf_pcie_release_irq(devinfo);
+	brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D0_INFORM_IN_USE);
 
 	err = pci_save_state(pdev);
-	if (err) {
+	if (err)
 		brcmf_err("pci_save_state failed, err=%d\n", err);
-		return err;
+	if ((err) || (!devinfo->wowl_enabled)) {
+		brcmf_chip_detach(devinfo->ci);
+		devinfo->ci = NULL;
+		brcmf_pcie_remove(pdev);
+		return 0;
 	}
 
-	brcmf_chip_detach(devinfo->ci);
-	devinfo->ci = NULL;
-
-	brcmf_pcie_remove(pdev);
-
 	return pci_prepare_to_sleep(pdev);
 }
 
-
 static int brcmf_pcie_resume(struct pci_dev *pdev)
 {
+	struct brcmf_pciedev_info *devinfo;
+	struct brcmf_bus *bus;
 	int err;
 
-	brcmf_dbg(PCIE, "Enter, pdev=%p\n", pdev);
+	bus = dev_get_drvdata(&pdev->dev);
+	brcmf_dbg(PCIE, "Enter, pdev=%p, bus=%p\n", pdev, bus);
 
 	err = pci_set_power_state(pdev, PCI_D0);
 	if (err) {
 		brcmf_err("pci_set_power_state failed, err=%d\n", err);
-		return err;
+		goto cleanup;
 	}
 	pci_restore_state(pdev);
+	pci_enable_wake(pdev, PCI_D3hot, false);
+	pci_enable_wake(pdev, PCI_D3cold, false);
 
+	/* Check if device is still up and running, if so we are ready */
+	if (bus) {
+		devinfo = bus->bus_priv.pcie->devinfo;
+		if (brcmf_pcie_read_reg32(devinfo,
+					  BRCMF_PCIE_PCIE2REG_INTMASK) != 0) {
+			if (brcmf_pcie_send_mb_data(devinfo,
+						    BRCMF_H2D_HOST_D0_INFORM))
+				goto cleanup;
+			brcmf_dbg(PCIE, "Hot resume, continue....\n");
+			brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
+			brcmf_bus_change_state(bus, BRCMF_BUS_DATA);
+			brcmf_pcie_intr_enable(devinfo);
+			return 0;
+		}
+	}
+
+cleanup:
+	if (bus) {
+		devinfo = bus->bus_priv.pcie->devinfo;
+		brcmf_chip_detach(devinfo->ci);
+		devinfo->ci = NULL;
+		brcmf_pcie_remove(pdev);
+	}
 	err = brcmf_pcie_probe(pdev, NULL);
 	if (err)
 		brcmf_err("probe after resume failed, err=%d\n", err);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 16a246b..28fa25b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -37,6 +37,7 @@
 #include "fwil.h"
 #include "proto.h"
 #include "vendor.h"
+#include "dhd_bus.h"
 
 #define BRCMF_SCAN_IE_LEN_MAX		2048
 #define BRCMF_PNO_VERSION		2
@@ -2397,9 +2398,13 @@
 	brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
 	brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
 
-	bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
-		0, notify_capability, notify_interval, notify_ie,
-		notify_ielen, notify_signal, GFP_KERNEL);
+	bss = cfg80211_inform_bss(wiphy, notify_channel,
+				  CFG80211_BSS_FTYPE_UNKNOWN,
+				  (const u8 *)bi->BSSID,
+				  0, notify_capability,
+				  notify_interval, notify_ie,
+				  notify_ielen, notify_signal,
+				  GFP_KERNEL);
 
 	if (!bss)
 		return -ENOMEM;
@@ -2425,7 +2430,7 @@
 	s32 err = 0;
 	int i;
 
-	bss_list = cfg->bss_list;
+	bss_list = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
 	if (bss_list->count != 0 &&
 	    bss_list->version != BRCMF_BSS_INFO_VERSION) {
 		brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
@@ -2501,9 +2506,11 @@
 	brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
 	brcmf_dbg(CONN, "signal: %d\n", notify_signal);
 
-	bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
-		0, notify_capability, notify_interval,
-		notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
+	bss = cfg80211_inform_bss(wiphy, notify_channel,
+				  CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
+				  notify_capability, notify_interval,
+				  notify_ie, notify_ielen, notify_signal,
+				  GFP_KERNEL);
 
 	if (!bss) {
 		err = -ENOMEM;
@@ -2599,6 +2606,7 @@
 			container_of(work, struct brcmf_cfg80211_info,
 				     escan_timeout_work);
 
+	brcmf_inform_bss(cfg);
 	brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
 }
 
@@ -2737,12 +2745,9 @@
 		if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
 			goto exit;
 		if (cfg->scan_request) {
-			cfg->bss_list = (struct brcmf_scan_results *)
-				cfg->escan_info.escan_buf;
 			brcmf_inform_bss(cfg);
 			aborted = status != BRCMF_E_STATUS_SUCCESS;
-			brcmf_notify_escan_complete(cfg, ifp, aborted,
-						    false);
+			brcmf_notify_escan_complete(cfg, ifp, aborted, false);
 		} else
 			brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
 				  status);
@@ -2776,50 +2781,91 @@
 
 static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
 {
+	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+	struct net_device *ndev = cfg_to_ndev(cfg);
+	struct brcmf_if *ifp = netdev_priv(ndev);
+
 	brcmf_dbg(TRACE, "Enter\n");
 
+	if (cfg->wowl_enabled) {
+		brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
+				      cfg->pre_wowl_pmmode);
+		brcmf_fil_iovar_data_set(ifp, "wowl_pattern", "clr", 4);
+		brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
+		cfg->wowl_enabled = false;
+	}
 	return 0;
 }
 
+static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
+				 struct brcmf_if *ifp,
+				 struct cfg80211_wowlan *wowl)
+{
+	u32 wowl_config;
+
+	brcmf_dbg(TRACE, "Suspend, wowl config.\n");
+
+	brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->pre_wowl_pmmode);
+	brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
+
+	wowl_config = 0;
+	if (wowl->disconnect)
+		wowl_config |= WL_WOWL_DIS | WL_WOWL_BCN | WL_WOWL_RETR;
+		/* Note: if "wowl" target and not "wowlpf" then wowl_bcn_loss
+		 * should be configured. This paramater is not supported by
+		 * wowlpf.
+		 */
+	if (wowl->magic_pkt)
+		wowl_config |= WL_WOWL_MAGIC;
+	brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
+	brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
+	brcmf_bus_wowl_config(cfg->pub->bus_if, true);
+	cfg->wowl_enabled = true;
+}
+
 static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
-				  struct cfg80211_wowlan *wow)
+				  struct cfg80211_wowlan *wowl)
 {
 	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
 	struct net_device *ndev = cfg_to_ndev(cfg);
+	struct brcmf_if *ifp = netdev_priv(ndev);
 	struct brcmf_cfg80211_vif *vif;
 
 	brcmf_dbg(TRACE, "Enter\n");
 
-	/*
-	 * if the primary net_device is not READY there is nothing
+	/* if the primary net_device is not READY there is nothing
 	 * we can do but pray resume goes smoothly.
 	 */
-	vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
-	if (!check_vif_up(vif))
+	if (!check_vif_up(ifp->vif))
 		goto exit;
 
-	list_for_each_entry(vif, &cfg->vif_list, list) {
-		if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
-			continue;
-		/*
-		 * While going to suspend if associated with AP disassociate
-		 * from AP to save power while system is in suspended state
-		 */
-		brcmf_link_down(vif);
-
-		/* Make sure WPA_Supplicant receives all the event
-		 * generated due to DISASSOC call to the fw to keep
-		 * the state fw and WPA_Supplicant state consistent
-		 */
-		brcmf_delay(500);
-	}
-
 	/* end any scanning */
 	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
 		brcmf_abort_scanning(cfg);
 
-	/* Turn off watchdog timer */
-	brcmf_set_mpc(netdev_priv(ndev), 1);
+	if (wowl == NULL) {
+		brcmf_bus_wowl_config(cfg->pub->bus_if, false);
+		list_for_each_entry(vif, &cfg->vif_list, list) {
+			if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
+				continue;
+			/* While going to suspend if associated with AP
+			 * disassociate from AP to save power while system is
+			 * in suspended state
+			 */
+			brcmf_link_down(vif);
+			/* Make sure WPA_Supplicant receives all the event
+			 * generated due to DISASSOC call to the fw to keep
+			 * the state fw and WPA_Supplicant state consistent
+			 */
+			brcmf_delay(500);
+		}
+		/* Configure MPC */
+		brcmf_set_mpc(ifp, 1);
+
+	} else {
+		/* Configure WOWL paramaters */
+		brcmf_configure_wowl(cfg, ifp, wowl);
+	}
 
 exit:
 	brcmf_dbg(TRACE, "Exit\n");
@@ -5394,6 +5440,21 @@
 	wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
 }
 
+
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support brcmf_wowlan_support = {
+	.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
+};
+#endif
+
+static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
+{
+#ifdef CONFIG_PM
+	/* wowl settings */
+	wiphy->wowlan = &brcmf_wowlan_support;
+#endif
+}
+
 static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
 {
 	struct ieee80211_iface_combination ifc_combo;
@@ -5431,6 +5492,9 @@
 	wiphy->vendor_commands = brcmf_vendor_cmds;
 	wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;
 
+	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL))
+		brcmf_wiphy_wowl_params(wiphy);
+
 	return brcmf_setup_wiphybands(wiphy);
 }
 
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
index f9fb109..6abf94e 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
@@ -35,7 +35,7 @@
 #define WL_SCAN_PASSIVE_TIME		120
 
 #define WL_ESCAN_BUF_SIZE		(1024 * 64)
-#define WL_ESCAN_TIMER_INTERVAL_MS	8000 /* E-Scan timeout */
+#define WL_ESCAN_TIMER_INTERVAL_MS	10000 /* E-Scan timeout */
 
 #define WL_ESCAN_ACTION_START		1
 #define WL_ESCAN_ACTION_CONTINUE	2
@@ -363,6 +363,8 @@
  * @vif_list: linked list of vif instances.
  * @vif_cnt: number of vif instances.
  * @vif_event: vif event signalling.
+ * @wowl_enabled; set during suspend, is wowl used.
+ * @pre_wowl_pmmode: intermediate storage of pm mode during wowl.
  */
 struct brcmf_cfg80211_info {
 	struct wiphy *wiphy;
@@ -371,7 +373,6 @@
 	struct brcmf_btcoex_info *btcoex;
 	struct cfg80211_scan_request *scan_request;
 	struct mutex usr_sync;
-	struct brcmf_scan_results *bss_list;
 	struct brcmf_cfg80211_scan_req scan_req_int;
 	struct wl_cfg80211_bss_info *bss_info;
 	struct brcmf_cfg80211_ie ie;
@@ -397,6 +398,8 @@
 	struct brcmf_cfg80211_vif_event vif_event;
 	struct completion vif_disabled;
 	struct brcmu_d11inf d11inf;
+	bool wowl_enabled;
+	u32 pre_wowl_pmmode;
 };
 
 /**
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c
index 4fb9635..796f5f9 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c
@@ -746,7 +746,7 @@
 /* !! may be called with core in reset */
 void dma_detach(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 
 	brcms_dbg_dma(di->core, "%s:\n", di->name);
 
@@ -842,7 +842,7 @@
 
 void dma_rxinit(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 
 	brcms_dbg_dma(di->core, "%s:\n", di->name);
 
@@ -924,7 +924,7 @@
  */
 int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 	struct sk_buff_head dma_frames;
 	struct sk_buff *p, *next;
 	uint len;
@@ -1022,7 +1022,7 @@
  */
 bool dma_rxfill(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 	struct sk_buff *p;
 	u16 rxin, rxout;
 	u32 flags = 0;
@@ -1106,7 +1106,7 @@
 
 void dma_rxreclaim(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 	struct sk_buff *p;
 
 	brcms_dbg_dma(di->core, "%s:\n", di->name);
@@ -1126,7 +1126,7 @@
 /* get the address of the var in order to change later */
 unsigned long dma_getvar(struct dma_pub *pub, const char *name)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 
 	if (!strcmp(name, "&txavail"))
 		return (unsigned long)&(di->dma.txavail);
@@ -1137,7 +1137,7 @@
 
 void dma_txinit(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 	u32 control = D64_XC_XE;
 
 	brcms_dbg_dma(di->core, "%s:\n", di->name);
@@ -1170,7 +1170,7 @@
 
 void dma_txsuspend(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 
 	brcms_dbg_dma(di->core, "%s:\n", di->name);
 
@@ -1182,7 +1182,7 @@
 
 void dma_txresume(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 
 	brcms_dbg_dma(di->core, "%s:\n", di->name);
 
@@ -1194,7 +1194,7 @@
 
 bool dma_txsuspended(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 
 	return (di->ntxd == 0) ||
 	       ((bcma_read32(di->core,
@@ -1204,7 +1204,7 @@
 
 void dma_txreclaim(struct dma_pub *pub, enum txd_range range)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 	struct sk_buff *p;
 
 	brcms_dbg_dma(di->core, "%s: %s\n",
@@ -1225,7 +1225,7 @@
 
 bool dma_txreset(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 	u32 status;
 
 	if (di->ntxd == 0)
@@ -1252,7 +1252,7 @@
 
 bool dma_rxreset(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 	u32 status;
 
 	if (di->nrxd == 0)
@@ -1377,7 +1377,7 @@
 int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub,
 	       struct sk_buff *p)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 	struct brcms_ampdu_session *session = &di->ampdu_session;
 	struct ieee80211_tx_info *tx_info;
 	bool is_ampdu;
@@ -1427,7 +1427,7 @@
 
 void dma_txflush(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 	struct brcms_ampdu_session *session = &di->ampdu_session;
 
 	if (!skb_queue_empty(&session->skb_list))
@@ -1436,7 +1436,7 @@
 
 int dma_txpending(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 	return ntxdactive(di, di->txin, di->txout);
 }
 
@@ -1446,7 +1446,7 @@
  */
 void dma_kick_tx(struct dma_pub *pub)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 	struct brcms_ampdu_session *session = &di->ampdu_session;
 
 	if (!skb_queue_empty(&session->skb_list) && dma64_txidle(di))
@@ -1465,7 +1465,7 @@
  */
 struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
 {
-	struct dma_info *di = (struct dma_info *)pub;
+	struct dma_info *di = container_of(pub, struct dma_info, dma);
 	u16 start, end, i;
 	u16 active_desc;
 	struct sk_buff *txp;
@@ -1547,7 +1547,7 @@
 void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc)
 		      (void *pkt, void *arg_a), void *arg_a)
 {
-	struct dma_info *di = (struct dma_info *) dmah;
+	struct dma_info *di = container_of(dmah, struct dma_info, dma);
 	uint i =   di->txin;
 	uint end = di->txout;
 	struct sk_buff *skb;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
index 57ecc05..941b1e4 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
@@ -128,19 +128,19 @@
 
 void wlc_phyreg_enter(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim);
 }
 
 void wlc_phyreg_exit(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim);
 }
 
 void wlc_radioreg_enter(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO);
 
 	udelay(10);
@@ -148,7 +148,7 @@
 
 void wlc_radioreg_exit(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	(void)bcma_read16(pi->d11core, D11REGOFFS(phyversion));
 	pi->phy_wreg = 0;
@@ -586,7 +586,7 @@
 
 void wlc_phy_detach(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	if (pih) {
 		if (--pi->refcnt)
@@ -613,7 +613,7 @@
 wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev,
 		       u16 *radioid, u16 *radiover)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	*phytype = (u16) pi->pubpi.phy_type;
 	*phyrev = (u16) pi->pubpi.phy_rev;
 	*radioid = pi->pubpi.radioid;
@@ -624,19 +624,19 @@
 
 bool wlc_phy_get_encore(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	return pi->pubpi.abgphy_encore;
 }
 
 u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	return pi->pubpi.coreflags;
 }
 
 void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	if (ISNPHY(pi)) {
 		if (on) {
@@ -673,7 +673,7 @@
 
 u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	u32 phy_bw_clkbits = 0;
 
@@ -698,14 +698,14 @@
 
 void wlc_phy_por_inform(struct brcms_phy_pub *ppi)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	pi->phy_init_por = true;
 }
 
 void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	pi->edcrs_threshold_lock = lock;
 
@@ -717,14 +717,14 @@
 
 void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	pi->do_initcal = initcal;
 }
 
 void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	if (!pi || !pi->sh)
 		return;
@@ -734,7 +734,7 @@
 
 void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	if (!pi || !pi->sh)
 		return;
@@ -746,7 +746,7 @@
 {
 	u32 mc;
 	void (*phy_init)(struct brcms_phy *) = NULL;
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	if (pi->init_in_progress)
 		return;
@@ -798,7 +798,7 @@
 
 void wlc_phy_cal_init(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	void (*cal_init)(struct brcms_phy *) = NULL;
 
 	if (WARN((bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
@@ -816,7 +816,7 @@
 
 int wlc_phy_down(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	int callbacks = 0;
 
 	if (pi->phycal_timer
@@ -1070,7 +1070,7 @@
 
 void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	if (set)
 		mboolset(pi->measure_hold, id);
@@ -1082,7 +1082,7 @@
 
 void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	if (mute)
 		mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
@@ -1096,7 +1096,7 @@
 
 void wlc_phy_clear_tssi(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	if (ISNPHY(pi)) {
 		return;
@@ -1115,7 +1115,7 @@
 
 void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	(void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
 
 	if (ISNPHY(pi)) {
@@ -1149,35 +1149,35 @@
 
 u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	return pi->bw;
 }
 
 void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	pi->bw = bw;
 }
 
 void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	pi->radio_chanspec = newch;
 
 }
 
 u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	return pi->radio_chanspec;
 }
 
 void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	u16 m_cur_channel;
 	void (*chanspec_set)(struct brcms_phy *, u16) = NULL;
 	m_cur_channel = CHSPEC_CHANNEL(chanspec);
@@ -1226,7 +1226,7 @@
 void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi,
 					  bool wide_filter)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	pi->channel_14_wide_filter = wide_filter;
 
@@ -1246,7 +1246,7 @@
 wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
 			      struct brcms_chanvec *channels)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	uint i;
 	uint channel;
 
@@ -1267,7 +1267,7 @@
 
 u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	uint i;
 	uint channel;
 	u16 chspec;
@@ -1311,7 +1311,7 @@
 
 int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	*qdbm = pi->tx_user_target[0];
 	if (override != NULL)
@@ -1323,7 +1323,7 @@
 				struct txpwr_limits *txpwr)
 {
 	bool mac_enabled = false;
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	memcpy(&pi->tx_user_target[TXP_FIRST_CCK],
 	       &txpwr->cck[0], BRCMS_NUM_RATES_CCK);
@@ -1371,7 +1371,7 @@
 
 int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	int i;
 
 	if (qdbm > 127)
@@ -1407,7 +1407,7 @@
 wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr,
 			  u8 *max_pwr, int txp_rate_idx)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	uint i;
 
 	*min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR;
@@ -1456,7 +1456,7 @@
 wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan,
 				  u8 *max_txpwr, u8 *min_txpwr)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	u8 tx_pwr_max = 0;
 	u8 tx_pwr_min = 255;
 	u8 max_num_rate;
@@ -1493,14 +1493,14 @@
 
 u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	return pi->tx_power_min;
 }
 
 u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	return pi->tx_power_max;
 }
@@ -1812,21 +1812,21 @@
 
 void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	pi->txpwr_percent = txpwr_percent;
 }
 
 void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	pi->sh->machwcap = machwcap;
 }
 
 void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	u16 rxc;
 	rxc = 0;
 
@@ -1857,7 +1857,7 @@
 wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr,
 			  u16 chanspec)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec);
 
@@ -1881,14 +1881,14 @@
 
 void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	pi->ofdm_rateset_war = war;
 }
 
 void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	pi->bf_preempt_4306 = bf_preempt;
 }
@@ -1945,7 +1945,7 @@
 
 bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	if (ISNPHY(pi))
 		return pi->nphy_txpwrctrl;
@@ -1955,7 +1955,7 @@
 
 void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	bool suspend;
 
 	if (!pi->hwpwrctrl_capable)
@@ -2038,7 +2038,7 @@
 wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,
 			    uint channel)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	uint rate, num_rates;
 	u8 min_pwr, max_pwr;
 
@@ -2136,21 +2136,21 @@
 
 void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	pi->antsel_type = antsel_type;
 }
 
 bool wlc_phy_test_ison(struct brcms_phy_pub *ppi)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	return pi->phytest_on;
 }
 
 void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	bool suspend;
 
 	pi->sh->rx_antdiv = val;
@@ -2283,7 +2283,7 @@
 
 void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	u16 jssi_aux;
 	u8 channel = 0;
 	s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
@@ -2339,7 +2339,7 @@
 static void
 wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
 	bool sampling_in_progress = (pi->phynoise_state != 0);
 	bool wait_for_intr = true;
@@ -2531,7 +2531,7 @@
 {
 	int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK;
 	uint radioid = pih->radioid;
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	if ((pi->sh->corerev >= 11)
 	    && !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) {
@@ -2591,7 +2591,7 @@
 
 void wlc_phy_watchdog(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	bool delay_phy_cal = false;
 	pi->sh->now++;
 
@@ -2651,7 +2651,7 @@
 
 void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	uint i;
 	uint k;
 
@@ -2711,7 +2711,7 @@
 	s16 nphy_currtemp = 0;
 	s16 delta_temp = 0;
 	bool do_periodic_cal = true;
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	if (!ISNPHY(pi))
 		return;
@@ -2804,7 +2804,7 @@
 
 void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	pi->sh->hw_phytxchain = txchain;
 	pi->sh->hw_phyrxchain = rxchain;
@@ -2815,7 +2815,7 @@
 
 void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	pi->sh->phytxchain = txchain;
 
@@ -2827,7 +2827,7 @@
 
 void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	*txchain = pi->sh->phytxchain;
 	*rxchain = pi->sh->phyrxchain;
@@ -2837,7 +2837,7 @@
 {
 	s16 nphy_currtemp;
 	u8 active_bitmap;
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33;
 
@@ -2867,7 +2867,7 @@
 
 s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	u8 siso_mcs_id, cdd_mcs_id;
 
 	siso_mcs_id =
@@ -2944,7 +2944,7 @@
 
 bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	if (ISNPHY(pi))
 		return wlc_phy_n_txpower_ipa_ison(pi);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
index b2d6d6d..5f13662 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
@@ -2865,7 +2865,7 @@
 {
 	bool suspend, tx_gain_override_old;
 	struct lcnphy_txgains old_gains;
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
 	    idleTssi0_regvalue_2C;
 	u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
@@ -3084,7 +3084,7 @@
 	s32 a1, b0, b1;
 	s32 tssi, pwr, maxtargetpwr, mintargetpwr;
 	bool suspend;
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 
 	suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
 			 MCTL_EN_MAC));
@@ -4348,7 +4348,7 @@
 {
 	s8 index;
 	u16 index2;
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
 	u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
 	if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
index 93869e8..084f18f 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
@@ -14121,7 +14121,7 @@
 
 bool wlc_phy_bist_check_phy(struct brcms_phy_pub *pih)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	u32 phybist0, phybist1, phybist2, phybist3, phybist4;
 
 	if (NREV_GE(pi->pubpi.phy_rev, 16))
@@ -19734,7 +19734,7 @@
 	u16 regval;
 	u16 tbl_buf[16];
 	uint i;
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 	u16 tbl_opcode;
 	bool suspend;
 
@@ -19812,7 +19812,7 @@
 u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih)
 {
 	u16 regval, rxen_bits;
-	struct brcms_phy *pi = (struct brcms_phy *) pih;
+	struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro);
 
 	regval = read_phy_reg(pi, 0xa2);
 	rxen_bits = (regval >> 4) & 0xf;
@@ -21342,7 +21342,7 @@
 
 void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init)
 {
-	struct brcms_phy *pi = (struct brcms_phy *) ppi;
+	struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
 	u16 mask = 0xfc00;
 	u32 mc = 0;
 
diff --git a/drivers/net/wireless/brcm80211/include/defs.h b/drivers/net/wireless/brcm80211/include/defs.h
index fb7cbcf..8d1e85e 100644
--- a/drivers/net/wireless/brcm80211/include/defs.h
+++ b/drivers/net/wireless/brcm80211/include/defs.h
@@ -74,10 +74,6 @@
 #define	BRCM_BAND_2G		2	/* 2.4 Ghz */
 #define	BRCM_BAND_ALL		3	/* all bands */
 
-/* Values for PM */
-#define PM_OFF	0
-#define PM_MAX	1
-
 /* Debug levels */
 #define BRCM_DL_INFO		0x00000001
 #define BRCM_DL_MAC80211	0x00000002
@@ -87,6 +83,7 @@
 #define BRCM_DL_DMA		0x00000020
 #define BRCM_DL_HT		0x00000040
 
+/* Values for PM */
 #define PM_OFF	0
 #define PM_MAX	1
 #define PM_FAST 2
diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c
index 40078f5..964b64a 100644
--- a/drivers/net/wireless/cw1200/cw1200_spi.c
+++ b/drivers/net/wireless/cw1200/cw1200_spi.c
@@ -398,7 +398,7 @@
 		return -1;
 	}
 
-	self = kzalloc(sizeof(*self), GFP_KERNEL);
+	self = devm_kzalloc(&func->dev, sizeof(*self), GFP_KERNEL);
 	if (!self) {
 		pr_err("Can't allocate SPI hwbus_priv.");
 		return -ENOMEM;
@@ -424,7 +424,6 @@
 	if (status) {
 		cw1200_spi_irq_unsubscribe(self);
 		cw1200_spi_off(plat_data);
-		kfree(self);
 	}
 
 	return status;
@@ -441,7 +440,6 @@
 			cw1200_core_release(self->core);
 			self->core = NULL;
 		}
-		kfree(self);
 	}
 	cw1200_spi_off(dev_get_platdata(&func->dev));
 
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 0d9748c..5e111ea 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -2009,7 +2009,6 @@
 	u32 chan;
 	char *txratename;
 	u8 bssid[ETH_ALEN];
-	DECLARE_SSID_BUF(ssid);
 
 	/*
 	 * TBD: BSSID is usually 00:00:00:00:00:00 here and not
@@ -2071,8 +2070,8 @@
 		break;
 	}
 
-	IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n",
-		       priv->net_dev->name, print_ssid(ssid, essid, essid_len),
+	IPW_DEBUG_INFO("%s: Associated with '%*pE' at %s, channel %d (BSSID=%pM)\n",
+		       priv->net_dev->name, essid_len, essid,
 		       txratename, chan, bssid);
 
 	/* now we copy read ssid into dev */
@@ -2099,9 +2098,8 @@
 		.host_command_length = ssid_len
 	};
 	int err;
-	DECLARE_SSID_BUF(ssid);
 
-	IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len));
+	IPW_DEBUG_HC("SSID: '%*pE'\n", ssid_len, essid);
 
 	if (ssid_len)
 		memcpy(cmd.host_command_parameters, essid, ssid_len);
@@ -2142,11 +2140,8 @@
 
 static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
 {
-	DECLARE_SSID_BUF(ssid);
-
 	IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
-		  "disassociated: '%s' %pM\n",
-		  print_ssid(ssid, priv->essid, priv->essid_len),
+		  "disassociated: '%*pE' %pM\n", priv->essid_len, priv->essid,
 		  priv->bssid);
 
 	priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
@@ -6979,7 +6974,6 @@
 	char *essid = "";	/* ANY */
 	int length = 0;
 	int err = 0;
-	DECLARE_SSID_BUF(ssid);
 
 	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
@@ -7009,8 +7003,7 @@
 		goto done;
 	}
 
-	IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
-		     print_ssid(ssid, essid, length), length);
+	IPW_DEBUG_WX("Setting ESSID: '%*pE' (%d)\n", length, essid, length);
 
 	priv->essid_len = length;
 	memcpy(priv->essid, essid, priv->essid_len);
@@ -7031,13 +7024,12 @@
 	 */
 
 	struct ipw2100_priv *priv = libipw_priv(dev);
-	DECLARE_SSID_BUF(ssid);
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured ESSID then return that; otherwise return ANY */
 	if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
-		IPW_DEBUG_WX("Getting essid: '%s'\n",
-			     print_ssid(ssid, priv->essid, priv->essid_len));
+		IPW_DEBUG_WX("Getting essid: '%*pE'\n",
+			     priv->essid_len, priv->essid);
 		memcpy(extra, priv->essid, priv->essid_len);
 		wrqu->essid.length = priv->essid_len;
 		wrqu->essid.flags = 1;	/* active */
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index bf2f767..c2b7368 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -4496,7 +4496,6 @@
 static void ipw_rx_notification(struct ipw_priv *priv,
 				       struct ipw_rx_notification *notif)
 {
-	DECLARE_SSID_BUF(ssid);
 	u16 size = le16_to_cpu(notif->size);
 
 	IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size);
@@ -4509,9 +4508,8 @@
 			case CMAS_ASSOCIATED:{
 					IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 						  IPW_DL_ASSOC,
-						  "associated: '%s' %pM\n",
-						  print_ssid(ssid, priv->essid,
-							     priv->essid_len),
+						  "associated: '%*pE' %pM\n",
+						  priv->essid_len, priv->essid,
 						  priv->bssid);
 
 					switch (priv->ieee->iw_mode) {
@@ -4585,14 +4583,9 @@
 						IPW_DEBUG(IPW_DL_NOTIF |
 							  IPW_DL_STATE |
 							  IPW_DL_ASSOC,
-							  "deauthenticated: '%s' "
-							  "%pM"
-							  ": (0x%04X) - %s\n",
-							  print_ssid(ssid,
-								     priv->
-								     essid,
-								     priv->
-								     essid_len),
+							  "deauthenticated: '%*pE' %pM: (0x%04X) - %s\n",
+							  priv->essid_len,
+							  priv->essid,
 							  priv->bssid,
 							  le16_to_cpu(auth->status),
 							  ipw_get_status_code
@@ -4610,9 +4603,8 @@
 
 					IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 						  IPW_DL_ASSOC,
-						  "authenticated: '%s' %pM\n",
-						  print_ssid(ssid, priv->essid,
-							     priv->essid_len),
+						  "authenticated: '%*pE' %pM\n",
+						  priv->essid_len, priv->essid,
 						  priv->bssid);
 					break;
 				}
@@ -4638,9 +4630,8 @@
 
 					IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 						  IPW_DL_ASSOC,
-						  "disassociated: '%s' %pM\n",
-						  print_ssid(ssid, priv->essid,
-							     priv->essid_len),
+						  "disassociated: '%*pE' %pM\n",
+						  priv->essid_len, priv->essid,
 						  priv->bssid);
 
 					priv->status &=
@@ -4676,9 +4667,8 @@
 			switch (auth->state) {
 			case CMAS_AUTHENTICATED:
 				IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
-					  "authenticated: '%s' %pM\n",
-					  print_ssid(ssid, priv->essid,
-						     priv->essid_len),
+					  "authenticated: '%*pE' %pM\n",
+					  priv->essid_len, priv->essid,
 					  priv->bssid);
 				priv->status |= STATUS_AUTH;
 				break;
@@ -4695,9 +4685,8 @@
 				}
 				IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 					  IPW_DL_ASSOC,
-					  "deauthenticated: '%s' %pM\n",
-					  print_ssid(ssid, priv->essid,
-						     priv->essid_len),
+					  "deauthenticated: '%*pE' %pM\n",
+					  priv->essid_len, priv->essid,
 					  priv->bssid);
 
 				priv->status &= ~(STATUS_ASSOCIATING |
@@ -5516,16 +5505,13 @@
 				  int roaming)
 {
 	struct ipw_supported_rates rates;
-	DECLARE_SSID_BUF(ssid);
 
 	/* Verify that this network's capability is compatible with the
 	 * current mode (AdHoc or Infrastructure) */
 	if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
 	     !(network->capability & WLAN_CAPABILITY_IBSS))) {
-		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded due to "
-				"capability mismatch.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded due to capability mismatch.\n",
+				network->ssid_len, network->ssid,
 				network->bssid);
 		return 0;
 	}
@@ -5536,10 +5522,8 @@
 		if ((network->ssid_len != match->network->ssid_len) ||
 		    memcmp(network->ssid, match->network->ssid,
 			   network->ssid_len)) {
-			IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-					"because of non-network ESSID.\n",
-					print_ssid(ssid, network->ssid,
-						   network->ssid_len),
+			IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of non-network ESSID.\n",
+					network->ssid_len, network->ssid,
 					network->bssid);
 			return 0;
 		}
@@ -5550,17 +5534,10 @@
 		    ((network->ssid_len != priv->essid_len) ||
 		     memcmp(network->ssid, priv->essid,
 			    min(network->ssid_len, priv->essid_len)))) {
-			char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-
-			strncpy(escaped,
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
-				sizeof(escaped));
-			IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-					"because of ESSID mismatch: '%s'.\n",
-					escaped, network->bssid,
-					print_ssid(ssid, priv->essid,
-						   priv->essid_len));
+			IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of ESSID mismatch: '%*pE'.\n",
+					network->ssid_len, network->ssid,
+					network->bssid, priv->essid_len,
+					priv->essid);
 			return 0;
 		}
 	}
@@ -5569,26 +5546,20 @@
 	 * testing everything else. */
 
 	if (network->time_stamp[0] < match->network->time_stamp[0]) {
-		IPW_DEBUG_MERGE("Network '%s excluded because newer than "
-				"current network.\n",
-				print_ssid(ssid, match->network->ssid,
-					   match->network->ssid_len));
+		IPW_DEBUG_MERGE("Network '%*pE excluded because newer than current network.\n",
+				match->network->ssid_len, match->network->ssid);
 		return 0;
 	} else if (network->time_stamp[1] < match->network->time_stamp[1]) {
-		IPW_DEBUG_MERGE("Network '%s excluded because newer than "
-				"current network.\n",
-				print_ssid(ssid, match->network->ssid,
-					   match->network->ssid_len));
+		IPW_DEBUG_MERGE("Network '%*pE excluded because newer than current network.\n",
+				match->network->ssid_len, match->network->ssid);
 		return 0;
 	}
 
 	/* Now go through and see if the requested network is valid... */
 	if (priv->ieee->scan_age != 0 &&
 	    time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
-		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-				"because of age: %ums.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of age: %ums.\n",
+				network->ssid_len, network->ssid,
 				network->bssid,
 				jiffies_to_msecs(jiffies -
 						 network->last_scanned));
@@ -5597,10 +5568,8 @@
 
 	if ((priv->config & CFG_STATIC_CHANNEL) &&
 	    (network->channel != priv->channel)) {
-		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-				"because of channel mismatch: %d != %d.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of channel mismatch: %d != %d.\n",
+				network->ssid_len, network->ssid,
 				network->bssid,
 				network->channel, priv->channel);
 		return 0;
@@ -5609,10 +5578,8 @@
 	/* Verify privacy compatibility */
 	if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
 	    ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
-		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-				"because of privacy mismatch: %s != %s.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of privacy mismatch: %s != %s.\n",
+				network->ssid_len, network->ssid,
 				network->bssid,
 				priv->
 				capability & CAP_PRIVACY_ON ? "on" : "off",
@@ -5623,22 +5590,16 @@
 	}
 
 	if (ether_addr_equal(network->bssid, priv->bssid)) {
-		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-				"because of the same BSSID match: %pM"
-				".\n", print_ssid(ssid, network->ssid,
-						  network->ssid_len),
-				network->bssid,
-				priv->bssid);
+		IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of the same BSSID match: %pM.\n",
+				network->ssid_len, network->ssid,
+				network->bssid, priv->bssid);
 		return 0;
 	}
 
 	/* Filter out any incompatible freq / mode combinations */
 	if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
-		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-				"because of invalid frequency/mode "
-				"combination.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of invalid frequency/mode combination.\n",
+				network->ssid_len, network->ssid,
 				network->bssid);
 		return 0;
 	}
@@ -5646,20 +5607,15 @@
 	/* Ensure that the rates supported by the driver are compatible with
 	 * this AP, including verification of basic rates (mandatory) */
 	if (!ipw_compatible_rates(priv, network, &rates)) {
-		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-				"because configured rate mask excludes "
-				"AP mandatory rate.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because configured rate mask excludes AP mandatory rate.\n",
+				network->ssid_len, network->ssid,
 				network->bssid);
 		return 0;
 	}
 
 	if (rates.num_rates == 0) {
-		IPW_DEBUG_MERGE("Network '%s (%pM)' excluded "
-				"because of no compatible rates.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of no compatible rates.\n",
+				network->ssid_len, network->ssid,
 				network->bssid);
 		return 0;
 	}
@@ -5671,16 +5627,14 @@
 	/* Set up 'new' AP to this network */
 	ipw_copy_rates(&match->rates, &rates);
 	match->network = network;
-	IPW_DEBUG_MERGE("Network '%s (%pM)' is a viable match.\n",
-			print_ssid(ssid, network->ssid, network->ssid_len),
-			network->bssid);
+	IPW_DEBUG_MERGE("Network '%*pE (%pM)' is a viable match.\n",
+			network->ssid_len, network->ssid, network->bssid);
 
 	return 1;
 }
 
 static void ipw_merge_adhoc_network(struct work_struct *work)
 {
-	DECLARE_SSID_BUF(ssid);
 	struct ipw_priv *priv =
 		container_of(work, struct ipw_priv, merge_networks);
 	struct libipw_network *network = NULL;
@@ -5710,9 +5664,8 @@
 
 		mutex_lock(&priv->mutex);
 		if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) {
-			IPW_DEBUG_MERGE("remove network %s\n",
-					print_ssid(ssid, priv->essid,
-						   priv->essid_len));
+			IPW_DEBUG_MERGE("remove network %*pE\n",
+					priv->essid_len, priv->essid);
 			ipw_remove_current_network(priv);
 		}
 
@@ -5728,7 +5681,6 @@
 			    struct libipw_network *network, int roaming)
 {
 	struct ipw_supported_rates rates;
-	DECLARE_SSID_BUF(ssid);
 
 	/* Verify that this network's capability is compatible with the
 	 * current mode (AdHoc or Infrastructure) */
@@ -5736,10 +5688,8 @@
 	     !(network->capability & WLAN_CAPABILITY_ESS)) ||
 	    (priv->ieee->iw_mode == IW_MODE_ADHOC &&
 	     !(network->capability & WLAN_CAPABILITY_IBSS))) {
-		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded due to "
-				"capability mismatch.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded due to capability mismatch.\n",
+				network->ssid_len, network->ssid,
 				network->bssid);
 		return 0;
 	}
@@ -5750,10 +5700,8 @@
 		if ((network->ssid_len != match->network->ssid_len) ||
 		    memcmp(network->ssid, match->network->ssid,
 			   network->ssid_len)) {
-			IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-					"because of non-network ESSID.\n",
-					print_ssid(ssid, network->ssid,
-						   network->ssid_len),
+			IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of non-network ESSID.\n",
+					network->ssid_len, network->ssid,
 					network->bssid);
 			return 0;
 		}
@@ -5764,16 +5712,10 @@
 		    ((network->ssid_len != priv->essid_len) ||
 		     memcmp(network->ssid, priv->essid,
 			    min(network->ssid_len, priv->essid_len)))) {
-			char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-			strncpy(escaped,
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
-				sizeof(escaped));
-			IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-					"because of ESSID mismatch: '%s'.\n",
-					escaped, network->bssid,
-					print_ssid(ssid, priv->essid,
-						   priv->essid_len));
+			IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of ESSID mismatch: '%*pE'.\n",
+					network->ssid_len, network->ssid,
+					network->bssid, priv->essid_len,
+					priv->essid);
 			return 0;
 		}
 	}
@@ -5781,16 +5723,10 @@
 	/* If the old network rate is better than this one, don't bother
 	 * testing everything else. */
 	if (match->network && match->network->stats.rssi > network->stats.rssi) {
-		char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-		strncpy(escaped,
-			print_ssid(ssid, network->ssid, network->ssid_len),
-			sizeof(escaped));
-		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because "
-				"'%s (%pM)' has a stronger signal.\n",
-				escaped, network->bssid,
-				print_ssid(ssid, match->network->ssid,
-					   match->network->ssid_len),
-				match->network->bssid);
+		IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because '%*pE (%pM)' has a stronger signal.\n",
+				network->ssid_len, network->ssid,
+				network->bssid, match->network->ssid_len,
+				match->network->ssid, match->network->bssid);
 		return 0;
 	}
 
@@ -5798,11 +5734,8 @@
 	 * last 3 seconds, do not try and associate again... */
 	if (network->last_associate &&
 	    time_after(network->last_associate + (HZ * 3UL), jiffies)) {
-		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-				"because of storming (%ums since last "
-				"assoc attempt).\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of storming (%ums since last assoc attempt).\n",
+				network->ssid_len, network->ssid,
 				network->bssid,
 				jiffies_to_msecs(jiffies -
 						 network->last_associate));
@@ -5812,10 +5745,8 @@
 	/* Now go through and see if the requested network is valid... */
 	if (priv->ieee->scan_age != 0 &&
 	    time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
-		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-				"because of age: %ums.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of age: %ums.\n",
+				network->ssid_len, network->ssid,
 				network->bssid,
 				jiffies_to_msecs(jiffies -
 						 network->last_scanned));
@@ -5824,10 +5755,8 @@
 
 	if ((priv->config & CFG_STATIC_CHANNEL) &&
 	    (network->channel != priv->channel)) {
-		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-				"because of channel mismatch: %d != %d.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of channel mismatch: %d != %d.\n",
+				network->ssid_len, network->ssid,
 				network->bssid,
 				network->channel, priv->channel);
 		return 0;
@@ -5836,10 +5765,8 @@
 	/* Verify privacy compatibility */
 	if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
 	    ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
-		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-				"because of privacy mismatch: %s != %s.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of privacy mismatch: %s != %s.\n",
+				network->ssid_len, network->ssid,
 				network->bssid,
 				priv->capability & CAP_PRIVACY_ON ? "on" :
 				"off",
@@ -5850,31 +5777,24 @@
 
 	if ((priv->config & CFG_STATIC_BSSID) &&
 	    !ether_addr_equal(network->bssid, priv->bssid)) {
-		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-				"because of BSSID mismatch: %pM.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of BSSID mismatch: %pM.\n",
+				network->ssid_len, network->ssid,
 				network->bssid, priv->bssid);
 		return 0;
 	}
 
 	/* Filter out any incompatible freq / mode combinations */
 	if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
-		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-				"because of invalid frequency/mode "
-				"combination.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of invalid frequency/mode combination.\n",
+				network->ssid_len, network->ssid,
 				network->bssid);
 		return 0;
 	}
 
 	/* Filter out invalid channel in current GEO */
 	if (!libipw_is_valid_channel(priv->ieee, network->channel)) {
-		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-				"because of invalid channel in current GEO\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of invalid channel in current GEO\n",
+				network->ssid_len, network->ssid,
 				network->bssid);
 		return 0;
 	}
@@ -5882,20 +5802,15 @@
 	/* Ensure that the rates supported by the driver are compatible with
 	 * this AP, including verification of basic rates (mandatory) */
 	if (!ipw_compatible_rates(priv, network, &rates)) {
-		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-				"because configured rate mask excludes "
-				"AP mandatory rate.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because configured rate mask excludes AP mandatory rate.\n",
+				network->ssid_len, network->ssid,
 				network->bssid);
 		return 0;
 	}
 
 	if (rates.num_rates == 0) {
-		IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded "
-				"because of no compatible rates.\n",
-				print_ssid(ssid, network->ssid,
-					   network->ssid_len),
+		IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of no compatible rates.\n",
+				network->ssid_len, network->ssid,
 				network->bssid);
 		return 0;
 	}
@@ -5908,9 +5823,8 @@
 	ipw_copy_rates(&match->rates, &rates);
 	match->network = network;
 
-	IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n",
-			print_ssid(ssid, network->ssid, network->ssid_len),
-			network->bssid);
+	IPW_DEBUG_ASSOC("Network '%*pE (%pM)' is a viable match.\n",
+			network->ssid_len, network->ssid, network->bssid);
 
 	return 1;
 }
@@ -6152,7 +6066,6 @@
 
 static void ipw_debug_config(struct ipw_priv *priv)
 {
-	DECLARE_SSID_BUF(ssid);
 	IPW_DEBUG_INFO("Scan completed, no valid APs matched "
 		       "[CFG 0x%08X]\n", priv->config);
 	if (priv->config & CFG_STATIC_CHANNEL)
@@ -6160,8 +6073,8 @@
 	else
 		IPW_DEBUG_INFO("Channel unlocked.\n");
 	if (priv->config & CFG_STATIC_ESSID)
-		IPW_DEBUG_INFO("ESSID locked to '%s'\n",
-			       print_ssid(ssid, priv->essid, priv->essid_len));
+		IPW_DEBUG_INFO("ESSID locked to '%*pE'\n",
+			       priv->essid_len, priv->essid);
 	else
 		IPW_DEBUG_INFO("ESSID unlocked.\n");
 	if (priv->config & CFG_STATIC_BSSID)
@@ -7385,7 +7298,6 @@
 				 struct ipw_supported_rates *rates, int roaming)
 {
 	int err;
-	DECLARE_SSID_BUF(ssid);
 
 	if (priv->config & CFG_FIXED_RATE)
 		ipw_set_fixed_rate(priv, network->mode);
@@ -7451,10 +7363,9 @@
 		priv->assoc_request.capability &=
 		    ~cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME);
 
-	IPW_DEBUG_ASSOC("%ssociation attempt: '%s', channel %d, "
-			"802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
+	IPW_DEBUG_ASSOC("%ssociation attempt: '%*pE', channel %d, 802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
 			roaming ? "Rea" : "A",
-			print_ssid(ssid, priv->essid, priv->essid_len),
+			priv->essid_len, priv->essid,
 			network->channel,
 			ipw_modes[priv->assoc_request.ieee_mode],
 			rates->num_rates,
@@ -7553,9 +7464,8 @@
 		return err;
 	}
 
-	IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM\n",
-		  print_ssid(ssid, priv->essid, priv->essid_len),
-		  priv->bssid);
+	IPW_DEBUG(IPW_DL_STATE, "associating: '%*pE' %pM\n",
+		  priv->essid_len, priv->essid, priv->bssid);
 
 	return 0;
 }
@@ -7645,7 +7555,6 @@
 	struct ipw_supported_rates *rates;
 	struct list_head *element;
 	unsigned long flags;
-	DECLARE_SSID_BUF(ssid);
 
 	if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
 		IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n");
@@ -7704,10 +7613,8 @@
 			/* If there are no more slots, expire the oldest */
 			list_del(&oldest->list);
 			target = oldest;
-			IPW_DEBUG_ASSOC("Expired '%s' (%pM) from "
-					"network list.\n",
-					print_ssid(ssid, target->ssid,
-						   target->ssid_len),
+			IPW_DEBUG_ASSOC("Expired '%*pE' (%pM) from network list.\n",
+					target->ssid_len, target->ssid,
 					target->bssid);
 			list_add_tail(&target->list,
 				      &priv->ieee->network_free_list);
@@ -9093,7 +9000,6 @@
 {
 	struct ipw_priv *priv = libipw_priv(dev);
         int length;
-	DECLARE_SSID_BUF(ssid);
 
         mutex_lock(&priv->mutex);
 
@@ -9118,8 +9024,7 @@
 		return 0;
 	}
 
-	IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n",
-		     print_ssid(ssid, extra, length), length);
+	IPW_DEBUG_WX("Setting ESSID: '%*pE' (%d)\n", length, extra, length);
 
 	priv->essid_len = length;
 	memcpy(priv->essid, extra, priv->essid_len);
@@ -9138,15 +9043,14 @@
 			    union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = libipw_priv(dev);
-	DECLARE_SSID_BUF(ssid);
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured ESSID then return that; otherwise return ANY */
 	mutex_lock(&priv->mutex);
 	if (priv->config & CFG_STATIC_ESSID ||
 	    priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
-		IPW_DEBUG_WX("Getting essid: '%s'\n",
-			     print_ssid(ssid, priv->essid, priv->essid_len));
+		IPW_DEBUG_WX("Getting essid: '%*pE'\n",
+			     priv->essid_len, priv->essid);
 		memcpy(extra, priv->essid, priv->essid_len);
 		wrqu->essid.length = priv->essid_len;
 		wrqu->essid.flags = 1;	/* active */
diff --git a/drivers/net/wireless/ipw2x00/libipw_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c
index dcac13a..651a1ee 100644
--- a/drivers/net/wireless/ipw2x00/libipw_rx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_rx.c
@@ -1120,7 +1120,6 @@
 				      *info_element, u16 length,
 				      struct libipw_network *network)
 {
-	DECLARE_SSID_BUF(ssid);
 	u8 i;
 #ifdef CPTCFG_LIBIPW_DEBUG
 	char rates_str[64];
@@ -1151,10 +1150,9 @@
 				memset(network->ssid + network->ssid_len, 0,
 				       IW_ESSID_MAX_SIZE - network->ssid_len);
 
-			LIBIPW_DEBUG_MGMT("WLAN_EID_SSID: '%s' len=%d.\n",
-					     print_ssid(ssid, network->ssid,
-							network->ssid_len),
-					     network->ssid_len);
+			LIBIPW_DEBUG_MGMT("WLAN_EID_SSID: '%*pE' len=%d.\n",
+					  network->ssid_len, network->ssid,
+					  network->ssid_len);
 			break;
 
 		case WLAN_EID_SUPP_RATES:
@@ -1399,8 +1397,6 @@
 					 struct libipw_network *network,
 					 struct libipw_rx_stats *stats)
 {
-	DECLARE_SSID_BUF(ssid);
-
 	network->qos_data.active = 0;
 	network->qos_data.supported = 0;
 	network->qos_data.param_count = 0;
@@ -1447,11 +1443,9 @@
 	}
 
 	if (network->mode == 0) {
-		LIBIPW_DEBUG_SCAN("Filtered out '%s (%pM)' "
-				     "network.\n",
-				     print_ssid(ssid, network->ssid,
-						 network->ssid_len),
-				     network->bssid);
+		LIBIPW_DEBUG_SCAN("Filtered out '%*pE (%pM)' network.\n",
+				  network->ssid_len, network->ssid,
+				  network->bssid);
 		return 1;
 	}
 
@@ -1563,11 +1557,9 @@
 	struct libipw_info_element *info_element = beacon->info_element;
 #endif
 	unsigned long flags;
-	DECLARE_SSID_BUF(ssid);
 
-	LIBIPW_DEBUG_SCAN("'%s' (%pM"
-		     "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
-		     print_ssid(ssid, info_element->data, info_element->len),
+	LIBIPW_DEBUG_SCAN("'%*pE' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
+		     info_element->len, info_element->data,
 		     beacon->header.addr3,
 		     (beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0',
 		     (beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0',
@@ -1587,12 +1579,11 @@
 		     (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0');
 
 	if (libipw_network_init(ieee, beacon, &network, stats)) {
-		LIBIPW_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n",
-				     print_ssid(ssid, info_element->data,
-						 info_element->len),
-				     beacon->header.addr3,
-				     is_beacon(beacon->header.frame_ctl) ?
-				     "BEACON" : "PROBE RESPONSE");
+		LIBIPW_DEBUG_SCAN("Dropped '%*pE' (%pM) via %s.\n",
+				  info_element->len, info_element->data,
+				  beacon->header.addr3,
+				  is_beacon(beacon->header.frame_ctl) ?
+				  "BEACON" : "PROBE RESPONSE");
 		return;
 	}
 
@@ -1624,11 +1615,9 @@
 			/* If there are no more slots, expire the oldest */
 			list_del(&oldest->list);
 			target = oldest;
-			LIBIPW_DEBUG_SCAN("Expired '%s' (%pM) from "
-					     "network list.\n",
-					     print_ssid(ssid, target->ssid,
-							 target->ssid_len),
-					     target->bssid);
+			LIBIPW_DEBUG_SCAN("Expired '%*pE' (%pM) from network list.\n",
+					  target->ssid_len, target->ssid,
+					  target->bssid);
 			libipw_network_reset(target);
 		} else {
 			/* Otherwise just pull from the free list */
@@ -1638,23 +1627,21 @@
 		}
 
 #ifdef CPTCFG_LIBIPW_DEBUG
-		LIBIPW_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
-				     print_ssid(ssid, network.ssid,
-						 network.ssid_len),
-				     network.bssid,
-				     is_beacon(beacon->header.frame_ctl) ?
-				     "BEACON" : "PROBE RESPONSE");
+		LIBIPW_DEBUG_SCAN("Adding '%*pE' (%pM) via %s.\n",
+				  network.ssid_len, network.ssid,
+				  network.bssid,
+				  is_beacon(beacon->header.frame_ctl) ?
+				  "BEACON" : "PROBE RESPONSE");
 #endif
 		memcpy(target, &network, sizeof(*target));
 		network.ibss_dfs = NULL;
 		list_add_tail(&target->list, &ieee->network_list);
 	} else {
-		LIBIPW_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n",
-				     print_ssid(ssid, target->ssid,
-						 target->ssid_len),
-				     target->bssid,
-				     is_beacon(beacon->header.frame_ctl) ?
-				     "BEACON" : "PROBE RESPONSE");
+		LIBIPW_DEBUG_SCAN("Updating '%*pE' (%pM) via %s.\n",
+				  target->ssid_len, target->ssid,
+				  target->bssid,
+				  is_beacon(beacon->header.frame_ctl) ?
+				  "BEACON" : "PROBE RESPONSE");
 		update_network(target, &network);
 		network.ibss_dfs = NULL;
 	}
diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c
index 54aba47..dd29f46 100644
--- a/drivers/net/wireless/ipw2x00/libipw_wx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_wx.c
@@ -272,7 +272,6 @@
 	char *ev = extra;
 	char *stop = ev + wrqu->data.length;
 	int i = 0;
-	DECLARE_SSID_BUF(ssid);
 
 	LIBIPW_DEBUG_WX("Getting scan\n");
 
@@ -290,12 +289,10 @@
 			ev = libipw_translate_scan(ieee, ev, stop, network,
 						      info);
 		else {
-			LIBIPW_DEBUG_SCAN("Not showing network '%s ("
-					     "%pM)' due to age (%ums).\n",
-					     print_ssid(ssid, network->ssid,
-							 network->ssid_len),
-					     network->bssid,
-					     elapsed_jiffies_msecs(
+			LIBIPW_DEBUG_SCAN("Not showing network '%*pE (%pM)' due to age (%ums).\n",
+					  network->ssid_len, network->ssid,
+					  network->bssid,
+					  elapsed_jiffies_msecs(
 					               network->last_scanned));
 		}
 	}
@@ -322,7 +319,6 @@
 	int i, key, key_provided, len;
 	struct lib80211_crypt_data **crypt;
 	int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
-	DECLARE_SSID_BUF(ssid);
 
 	LIBIPW_DEBUG_WX("SET_ENCODE\n");
 
@@ -417,8 +413,8 @@
 		if (len > erq->length)
 			memset(sec.keys[key] + erq->length, 0,
 			       len - erq->length);
-		LIBIPW_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
-				   key, print_ssid(ssid, sec.keys[key], len),
+		LIBIPW_DEBUG_WX("Setting key %d to '%*pE' (%d:%d bytes)\n",
+				   key, len, sec.keys[key],
 				   erq->length, len);
 		sec.key_sizes[key] = len;
 		if (*crypt)
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 01a8afa..6c9cbb8 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -4633,7 +4633,7 @@
 	else {
 		ret = il_set_tx_power(il, val, false);
 		if (ret)
-			IL_ERR("failed setting tx power (0x%d).\n", ret);
+			IL_ERR("failed setting tx power (0x%08x).\n", ret);
 		else
 			ret = count;
 	}
@@ -5757,9 +5757,8 @@
 	    IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
 	    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 	if (il->cfg->sku & IL_SKU_N)
-		hw->flags |=
-		    IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
-		    IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+		hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS |
+				       NL80211_FEATURE_STATIC_SMPS;
 
 	hw->sta_data_size = sizeof(struct il_station_priv);
 	hw->vif_data_size = sizeof(struct il_vif_priv);
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 8a0ce45..3721c07 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -88,6 +88,16 @@
 	  If unsure, don't enable this option, as some programs might
 	  expect incoming broadcasts for their normal operations.
 
+config IWLWIFI_UAPSD
+	bool "enable U-APSD by default"
+	depends on IWLMVM
+	help
+	  Say Y here to enable U-APSD by default. This may cause
+	  interoperability problems with some APs, manifesting in lower than
+	  expected throughput due to those APs not enabling aggregation
+
+	  If unsure, say N.
+
 menu "Debugging Options"
 
 config IWLWIFI_DEBUG
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index d2ebd09..d8ebc7e 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -125,8 +125,8 @@
 	 */
 
 	if (priv->nvm_data->sku_cap_11n_enable)
-		hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
-			     IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+		hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS |
+				       NL80211_FEATURE_STATIC_SMPS;
 
 	/*
 	 * Enable 11w if advertised by firmware and software crypto
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
index c1f6805..29f423b 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -580,7 +580,7 @@
 		 * time, or we hadn't time to drain the AC queues.
 		 */
 		if (agg_state == IWL_AGG_ON)
-			iwl_trans_txq_disable(priv->trans, txq_id);
+			iwl_trans_txq_disable(priv->trans, txq_id, true);
 		else
 			IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
 					    agg_state);
@@ -686,7 +686,7 @@
 		 * time, or we hadn't time to drain the AC queues.
 		 */
 		if (agg_state == IWL_AGG_ON)
-			iwl_trans_txq_disable(priv->trans, txq_id);
+			iwl_trans_txq_disable(priv->trans, txq_id, true);
 		else
 			IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
 					    agg_state);
@@ -781,7 +781,7 @@
 				"Can continue DELBA flow ssn = next_recl = %d\n",
 				tid_data->next_reclaimed);
 			iwl_trans_txq_disable(priv->trans,
-					      tid_data->agg.txq_id);
+					      tid_data->agg.txq_id, true);
 			iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id);
 			tid_data->agg.state = IWL_AGG_OFF;
 			ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index d53adc2..b04b885 100644
--- a/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -129,7 +131,8 @@
 	.max_data_size = IWL60_RTC_DATA_SIZE,			\
 	.base_params = &iwl7000_base_params,			\
 	.led_mode = IWL_LED_RF_STATE,				\
-	.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000
+	.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000,	\
+	.non_shared_ant = ANT_A
 
 
 const struct iwl_cfg iwl7260_2ac_cfg = {
@@ -218,6 +221,12 @@
 	{0},
 };
 
+static const struct iwl_ht_params iwl7265_ht_params = {
+	.stbc = true,
+	.ldpc = true,
+	.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
+};
+
 const struct iwl_cfg iwl3165_2ac_cfg = {
 	.name = "Intel(R) Dual Band Wireless AC 3165",
 	.fw_name_pre = IWL3165_FW_PRE,
@@ -232,7 +241,7 @@
 	.name = "Intel(R) Dual Band Wireless AC 7265",
 	.fw_name_pre = IWL7265_FW_PRE,
 	IWL_DEVICE_7000,
-	.ht_params = &iwl7000_ht_params,
+	.ht_params = &iwl7265_ht_params,
 	.nvm_ver = IWL7265_NVM_VERSION,
 	.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
 	.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
@@ -242,7 +251,7 @@
 	.name = "Intel(R) Dual Band Wireless N 7265",
 	.fw_name_pre = IWL7265_FW_PRE,
 	IWL_DEVICE_7000,
-	.ht_params = &iwl7000_ht_params,
+	.ht_params = &iwl7265_ht_params,
 	.nvm_ver = IWL7265_NVM_VERSION,
 	.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
 	.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
@@ -252,7 +261,7 @@
 	.name = "Intel(R) Wireless N 7265",
 	.fw_name_pre = IWL7265_FW_PRE,
 	IWL_DEVICE_7000,
-	.ht_params = &iwl7000_ht_params,
+	.ht_params = &iwl7265_ht_params,
 	.nvm_ver = IWL7265_NVM_VERSION,
 	.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
 	.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c
index e93c697..e435148 100644
--- a/drivers/net/wireless/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-8000.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -79,7 +81,7 @@
 #define IWL8000_NVM_VERSION		0x0a1d
 #define IWL8000_TX_POWER_VERSION	0xffff /* meaningless */
 
-#define IWL8000_FW_PRE "iwlwifi-8000-"
+#define IWL8000_FW_PRE "iwlwifi-8000"
 #define IWL8000_MODULE_FIRMWARE(api) IWL8000_FW_PRE __stringify(api) ".ucode"
 
 #define NVM_HW_SECTION_NUM_FAMILY_8000		10
@@ -101,6 +103,7 @@
 };
 
 static const struct iwl_ht_params iwl8000_ht_params = {
+	.ldpc = true,
 	.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
 };
 
@@ -113,7 +116,17 @@
 	.max_data_size = IWL60_RTC_DATA_SIZE,			\
 	.base_params = &iwl8000_base_params,			\
 	.led_mode = IWL_LED_RF_STATE,				\
-	.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000
+	.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000,	\
+	.non_shared_ant = ANT_A
+
+const struct iwl_cfg iwl8260_2n_cfg = {
+	.name = "Intel(R) Dual Band Wireless N 8260",
+	.fw_name_pre = IWL8000_FW_PRE,
+	IWL_DEVICE_8000,
+	.ht_params = &iwl8000_ht_params,
+	.nvm_ver = IWL8000_NVM_VERSION,
+	.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
+};
 
 const struct iwl_cfg iwl8260_2ac_cfg = {
 	.name = "Intel(R) Dual Band Wireless AC 8260",
@@ -133,6 +146,7 @@
 	.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
 	.default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000,
 	.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
+	.disable_dummy_notification = true,
 };
 
 MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 8d62500..6926711 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -171,6 +171,7 @@
 
 /*
  * @stbc: support Tx STBC and 1*SS Rx STBC
+ * @ldpc: support Tx/Rx with LDPC
  * @use_rts_for_aggregation: use rts/cts protection for HT traffic
  * @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40
  */
@@ -178,6 +179,7 @@
 	enum ieee80211_smps_mode smps_mode;
 	const bool ht_greenfield_support; /* if used set to true */
 	const bool stbc;
+	const bool ldpc;
 	bool use_rts_for_aggregation;
 	u8 ht40_bands;
 };
@@ -228,6 +230,7 @@
  * @max_data_size: The maximal length of the fw data section
  * @valid_tx_ant: valid transmit antenna
  * @valid_rx_ant: valid receive antenna
+ * @non_shared_ant: the antenna that is for WiFi only
  * @nvm_ver: NVM version
  * @nvm_calib_ver: NVM calibration version
  * @lib: pointer to the lib ops
@@ -260,6 +263,7 @@
 	const u32 max_inst_size;
 	u8   valid_tx_ant;
 	u8   valid_rx_ant;
+	u8   non_shared_ant;
 	bool bt_shared_single_ant;
 	u16  nvm_ver;
 	u16  nvm_calib_ver;
@@ -280,6 +284,7 @@
 	bool no_power_up_nic_in_init;
 	const char *default_nvm_file;
 	unsigned int max_rx_agg_size;
+	bool disable_dummy_notification;
 };
 
 /*
@@ -341,6 +346,7 @@
 extern const struct iwl_cfg iwl7265_2ac_cfg;
 extern const struct iwl_cfg iwl7265_2n_cfg;
 extern const struct iwl_cfg iwl7265_n_cfg;
+extern const struct iwl_cfg iwl8260_2n_cfg;
 extern const struct iwl_cfg iwl8260_2ac_cfg;
 extern const struct iwl_cfg iwl8260_2ac_sdio_cfg;
 #endif /* CPTCFG_IWLMVM */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index fe129c9..3f6f015 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -293,6 +295,16 @@
 #define CSR_HW_REV_DASH(_val)          (((_val) & 0x0000003) >> 0)
 #define CSR_HW_REV_STEP(_val)          (((_val) & 0x000000C) >> 2)
 
+
+/**
+ *  hw_rev values
+ */
+enum {
+	SILICON_A_STEP = 0,
+	SILICON_B_STEP,
+};
+
+
 #define CSR_HW_REV_TYPE_MSK            (0x000FFF0)
 #define CSR_HW_REV_TYPE_5300           (0x0000020)
 #define CSR_HW_REV_TYPE_5350           (0x0000030)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 23441fb..2eb2346 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -145,6 +145,7 @@
 #define IWL_DL_HCMD		0x00000004
 #define IWL_DL_STATE		0x00000008
 /* 0x000000F0 - 0x00000010 */
+#define IWL_DL_QUOTA		0x00000010
 #define IWL_DL_TE		0x00000020
 #define IWL_DL_EEPROM		0x00000040
 #define IWL_DL_RADIO		0x00000080
@@ -189,6 +190,7 @@
 #define IWL_DEBUG_LED(p, f, a...)	IWL_DEBUG(p, IWL_DL_LED, f, ## a)
 #define IWL_DEBUG_WEP(p, f, a...)	IWL_DEBUG(p, IWL_DL_WEP, f, ## a)
 #define IWL_DEBUG_HC(p, f, a...)	IWL_DEBUG(p, IWL_DL_HCMD, f, ## a)
+#define IWL_DEBUG_QUOTA(p, f, a...)	IWL_DEBUG(p, IWL_DL_QUOTA, f, ## a)
 #define IWL_DEBUG_TE(p, f, a...)	IWL_DEBUG(p, IWL_DL_TE, f, ## a)
 #define IWL_DEBUG_EEPROM(d, f, a...)	IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a)
 #define IWL_DEBUG_CALIB(p, f, a...)	IWL_DEBUG(p, IWL_DL_CALIB, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
index 23e7351..90987d6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
@@ -36,15 +36,8 @@
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_tx);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_info);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_warn);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_crit);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_err);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dbg);
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index 4c45baf..5e8d279 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -67,6 +69,7 @@
 #include <linux/vmalloc.h>
 
 #include "iwl-drv.h"
+#include "iwl-csr.h"
 #include "iwl-debug.h"
 #include "iwl-trans.h"
 #include "iwl-op-mode.h"
@@ -242,6 +245,23 @@
 	snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s.ucode",
 		 name_pre, tag);
 
+	/*
+	 * Starting 8000B - FW name format has changed. This overwrites the
+	 * previous name and uses the new format.
+	 */
+	if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
+		char rev_step[2] = {
+			'A' + CSR_HW_REV_STEP(drv->trans->hw_rev), 0
+		};
+
+		/* A-step doesn't have an indication */
+		if (CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP)
+			rev_step[0] = 0;
+
+		snprintf(drv->firmware_name, sizeof(drv->firmware_name),
+			 "%s%s-%s.ucode", name_pre, rev_step, tag);
+	}
+
 	IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n",
 		       (drv->fw_index == UCODE_EXPERIMENTAL_INDEX)
 				? "EXPERIMENTAL " : "",
@@ -1254,7 +1274,9 @@
 	.bt_coex_active = true,
 	.power_level = IWL_POWER_INDEX_1,
 	.wd_disable = true,
-	.uapsd_disable = false,
+#ifndef CPTCFG_IWLWIFI_UAPSD
+	.uapsd_disable = true,
+#endif /* CPTCFG_IWLWIFI_UAPSD */
 	/* the rest are 0 by default */
 };
 IWL_EXPORT_SYMBOL(iwlwifi_mod_params);
@@ -1359,7 +1381,7 @@
 module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling,
 		   int, S_IRUGO);
 MODULE_PARM_DESC(antenna_coupling,
-		 "specify antenna coupling in dB (defualt: 0 dB)");
+		 "specify antenna coupling in dB (default: 0 dB)");
 
 module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO);
 MODULE_PARM_DESC(wd_disable,
@@ -1370,7 +1392,11 @@
 
 module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable,
 		   bool, S_IRUGO);
+#ifdef CPTCFG_IWLWIFI_UAPSD
 MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: N)");
+#else
+MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: Y)");
+#endif
 
 /*
  * set bt_coex_active to true, uCode will do kill/defer
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h
index b2451b2..b987412 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.h
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
index 07ff7e0..74b796d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
@@ -758,6 +758,9 @@
 			ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
 	}
 
+	if (cfg->ht_params->ldpc)
+		ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+
 	if (iwlwifi_mod_params.amsdu_size_8K)
 		ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index de5994a..e30a41d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 929a806..401f7be 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 1bb5193..4f6e668 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -125,6 +127,9 @@
  * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA.
  * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit.
  * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API.
+ * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif.
+ * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
+ *	longer than the passive one, which is essential for fragmented scan.
  */
 enum iwl_ucode_tlv_api {
 	IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID	= BIT(0),
@@ -133,14 +138,31 @@
 	IWL_UCODE_TLV_API_CSA_FLOW		= BIT(4),
 	IWL_UCODE_TLV_API_DISABLE_STA_TX	= BIT(5),
 	IWL_UCODE_TLV_API_LMAC_SCAN		= BIT(6),
+	IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF	= BIT(7),
+	IWL_UCODE_TLV_API_FRAGMENTED_SCAN	= BIT(8),
 };
 
 /**
  * enum iwl_ucode_tlv_capa - ucode capabilities
  * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3
+ * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current
+ *	tx power value into TPC Report action frame and Link Measurement Report
+ *	action frame
+ * @IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT: supports adding DS params
+ *	element in probe requests.
+ * @IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in
+ *	probe requests.
+ * @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests
+ * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA),
+ *	which also implies support for the scheduler configuration command
  */
 enum iwl_ucode_tlv_capa {
-	IWL_UCODE_TLV_CAPA_D0I3_SUPPORT		= BIT(0),
+	IWL_UCODE_TLV_CAPA_D0I3_SUPPORT			= BIT(0),
+	IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT	= BIT(8),
+	IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT	= BIT(9),
+	IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT	= BIT(10),
+	IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT		= BIT(11),
+	IWL_UCODE_TLV_CAPA_DQA_SUPPORT			= BIT(12),
 };
 
 /* The default calibrate table size if not specified by firmware file */
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index 3cb440b..17bd1b5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -193,7 +193,7 @@
 	 * DEVICE_SET_NMI_8000B_REG - is used.
 	 */
 	if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) ||
-	    ((trans->hw_rev & 0xc) == 0x0))
+	    (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP))
 		iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL);
 	else
 		iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG,
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index 354255f..c302e74 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -332,6 +334,9 @@
 		       3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
 		       7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
 
+	if (cfg->ht_params->ldpc)
+		vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
+
 	if (num_tx_ants > 1)
 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
 	else
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
index 99785c8..b6d666e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 47033a3..1560f45 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -281,6 +283,7 @@
 #define SCD_CHAINEXT_EN		(SCD_BASE + 0x244)
 #define SCD_AGGR_SEL		(SCD_BASE + 0x248)
 #define SCD_INTERRUPT_MASK	(SCD_BASE + 0x108)
+#define SCD_EN_CTRL		(SCD_BASE + 0x254)
 
 static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl)
 {
diff --git a/drivers/net/wireless/iwlwifi/iwl-scd.h b/drivers/net/wireless/iwlwifi/iwl-scd.h
new file mode 100644
index 0000000..6c622b2
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-scd.h
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_scd_h__
+#define __iwl_scd_h__
+
+#include "iwl-trans.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
+
+
+static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans,
+					    u16 txq_id)
+{
+	iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
+		       (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+		       (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
+static inline void iwl_scd_txq_set_chain(struct iwl_trans *trans,
+					 u16 txq_id)
+{
+	iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
+}
+
+static inline void iwl_scd_txq_enable_agg(struct iwl_trans *trans,
+					  u16 txq_id)
+{
+	iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+}
+
+static inline void iwl_scd_txq_disable_agg(struct iwl_trans *trans,
+					   u16 txq_id)
+{
+	iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+}
+
+static inline void iwl_scd_disable_agg(struct iwl_trans *trans)
+{
+	iwl_set_bits_prph(trans, SCD_AGGR_SEL, 0);
+}
+
+static inline void iwl_scd_activate_fifos(struct iwl_trans *trans)
+{
+	iwl_write_prph(trans, SCD_TXFACT, IWL_MASK(0, 7));
+}
+
+static inline void iwl_scd_deactivate_fifos(struct iwl_trans *trans)
+{
+	iwl_write_prph(trans, SCD_TXFACT, 0);
+}
+
+static inline void iwl_scd_enable_set_active(struct iwl_trans *trans,
+					     u32 value)
+{
+	iwl_write_prph(trans, SCD_EN_CTRL, value);
+}
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 8fe8c5f..98b4c95 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -375,6 +377,7 @@
  *	if unset 4k will be the RX buffer size
  * @bc_table_dword: set to true if the BC table expects the byte count to be
  *	in DWORD (as opposed to bytes)
+ * @scd_set_active: should the transport configure the SCD for HCMD queue
  * @queue_watchdog_timeout: time (in ms) after which queues
  *	are considered stuck and will trigger device restart
  * @command_names: array of command names, must be 256 entries
@@ -390,6 +393,7 @@
 
 	bool rx_buf_size_8k;
 	bool bc_table_dword;
+	bool scd_set_active;
 	unsigned int queue_watchdog_timeout;
 	const char *const *command_names;
 };
@@ -401,6 +405,14 @@
 
 struct iwl_trans;
 
+struct iwl_trans_txq_scd_cfg {
+	u8 fifo;
+	s8 sta_id;
+	u8 tid;
+	bool aggregate;
+	int frame_limit;
+};
+
 /**
  * struct iwl_trans_ops - transport specific operations
  *
@@ -437,7 +449,9 @@
  *	Must be atomic
  * @txq_enable: setup a queue. To setup an AC queue, use the
  *	iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before
- *	this one. The op_mode must not configure the HCMD queue. May sleep.
+ *	this one. The op_mode must not configure the HCMD queue. The scheduler
+ *	configuration may be %NULL, in which case the hardware will not be
+ *	configured. May sleep.
  * @txq_disable: de-configure a Tx queue to send AMPDUs
  *	Must be atomic
  * @wait_tx_queue_empty: wait until tx queues are empty. May sleep.
@@ -492,9 +506,10 @@
 	void (*reclaim)(struct iwl_trans *trans, int queue, int ssn,
 			struct sk_buff_head *skbs);
 
-	void (*txq_enable)(struct iwl_trans *trans, int queue, int fifo,
-			   int sta_id, int tid, int frame_limit, u16 ssn);
-	void (*txq_disable)(struct iwl_trans *trans, int queue);
+	void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn,
+			   const struct iwl_trans_txq_scd_cfg *cfg);
+	void (*txq_disable)(struct iwl_trans *trans, int queue,
+			    bool configure_scd);
 
 	int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
 	int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm);
@@ -766,29 +781,51 @@
 	trans->ops->reclaim(trans, queue, ssn, skbs);
 }
 
-static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue)
+static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue,
+					 bool configure_scd)
 {
-	trans->ops->txq_disable(trans, queue);
+	trans->ops->txq_disable(trans, queue, configure_scd);
 }
 
-static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
-					int fifo, int sta_id, int tid,
-					int frame_limit, u16 ssn)
+static inline void
+iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn,
+			 const struct iwl_trans_txq_scd_cfg *cfg)
 {
 	might_sleep();
 
 	if (unlikely((trans->state != IWL_TRANS_FW_ALIVE)))
 		IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
 
-	trans->ops->txq_enable(trans, queue, fifo, sta_id, tid,
-				 frame_limit, ssn);
+	trans->ops->txq_enable(trans, queue, ssn, cfg);
+}
+
+static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
+					int fifo, int sta_id, int tid,
+					int frame_limit, u16 ssn)
+{
+	struct iwl_trans_txq_scd_cfg cfg = {
+		.fifo = fifo,
+		.sta_id = sta_id,
+		.tid = tid,
+		.frame_limit = frame_limit,
+		.aggregate = sta_id >= 0,
+	};
+
+	iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg);
 }
 
 static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue,
 					   int fifo)
 {
-	iwl_trans_txq_enable(trans, queue, fifo, -1,
-			     IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0);
+	struct iwl_trans_txq_scd_cfg cfg = {
+		.fifo = fifo,
+		.sta_id = -1,
+		.tid = IWL_MAX_TID_COUNT,
+		.frame_limit = IWL_FRAME_LIMIT,
+		.aggregate = false,
+	};
+
+	iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg);
 }
 
 static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile
index e0d6853..ffb7f07 100644
--- a/drivers/net/wireless/iwlwifi/mvm/Makefile
+++ b/drivers/net/wireless/iwlwifi/mvm/Makefile
@@ -3,7 +3,7 @@
 iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o
 iwlmvm-y += scan.o time-event.o rs.o
 iwlmvm-y += power.o coex.o coex_legacy.o
-iwlmvm-y += tt.o offloading.o
+iwlmvm-y += tt.o offloading.o tdls.o
 iwlmvm-$(CPTCFG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
 iwlmvm-$(CPTCFG_IWLWIFI_LEDS) += led.o
 iwlmvm-$(CONFIG_PM_SLEEP) += d3.o
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c
index ce71625..8df2021 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -1144,6 +1146,10 @@
 
 bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
 {
+	/* there is no other antenna, shared antenna is always available */
+	if (mvm->cfg->bt_shared_single_ant)
+		return true;
+
 	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
 		return iwl_mvm_bt_coex_is_shared_ant_avail_old(mvm);
 
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
index a3be333..585c0ab 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h
index ca79f71..d4dfbe4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/iwlwifi/mvm/constants.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -63,12 +65,18 @@
 #ifndef __MVM_CONSTANTS_H
 #define __MVM_CONSTANTS_H
 
+#include <linux/ieee80211.h>
+
 #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT	(100 * USEC_PER_MSEC)
 #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT	(100 * USEC_PER_MSEC)
 #define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT	(10 * USEC_PER_MSEC)
 #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT	(10 * USEC_PER_MSEC)
 #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT		(50 * USEC_PER_MSEC)
 #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT		(50 * USEC_PER_MSEC)
+#define IWL_MVM_UAPSD_QUEUES		(IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
+					 IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\
+					 IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\
+					 IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
 #define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS	20
 #define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS	8
 #define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS	30
@@ -82,7 +90,10 @@
 #define IWL_MVM_BT_COEX_EN_RED_TXP_THRESH	62
 #define IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH	65
 #define IWL_MVM_BT_COEX_SYNC2SCO		1
-#define IWL_MVM_BT_COEX_CORUNNING		1
+#define IWL_MVM_BT_COEX_CORUNNING		0
 #define IWL_MVM_BT_COEX_MPLUT			1
+#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL	0
+#define IWL_MVM_QUOTA_THRESHOLD			8
+#define IWL_MVM_RS_RSSI_BASED_INIT_RATE         0
 
 #endif /* __MVM_CONSTANTS_H */
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index c2cbc9e..d45d6df 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -700,7 +702,7 @@
 		return ret;
 	rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta);
 
-	ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false);
+	ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
 	if (ret)
 		return ret;
 
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
index 87e517b..9aa2311 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -118,6 +120,10 @@
 		IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
 		dbgfs_pm->uapsd_misbehaving = val;
 		break;
+	case MVM_DEBUGFS_PM_USE_PS_POLL:
+		IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val);
+		dbgfs_pm->use_ps_poll = val;
+		break;
 	}
 }
 
@@ -168,6 +174,10 @@
 		if (sscanf(buf + 18, "%d", &val) != 1)
 			return -EINVAL;
 		param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
+	} else if (!strncmp("use_ps_poll=", buf, 12)) {
+		if (sscanf(buf + 12, "%d", &val) != 1)
+			return -EINVAL;
+		param = MVM_DEBUGFS_PM_USE_PS_POLL;
 	} else {
 		return -EINVAL;
 	}
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index 1875206..7765c2b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -257,6 +259,96 @@
 	return count;
 }
 
+static ssize_t iwl_dbgfs_set_nic_temperature_read(struct file *file,
+						  char __user *user_buf,
+						  size_t count, loff_t *ppos)
+{
+	struct iwl_mvm *mvm = file->private_data;
+	char buf[16];
+	int pos;
+
+	if (!mvm->temperature_test)
+		pos = scnprintf(buf , sizeof(buf), "disabled\n");
+	else
+		pos = scnprintf(buf , sizeof(buf), "%d\n", mvm->temperature);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+/*
+ * Set NIC Temperature
+ * Cause the driver to ignore the actual NIC temperature reported by the FW
+ * Enable: any value between IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -
+ * IWL_MVM_DEBUG_SET_TEMPERATURE_MAX
+ * Disable: IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE
+ */
+static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm,
+						   char *buf, size_t count,
+						   loff_t *ppos)
+{
+	int temperature;
+
+	if (!mvm->ucode_loaded && !mvm->temperature_test)
+		return -EIO;
+
+	if (kstrtoint(buf, 10, &temperature))
+		return -EINVAL;
+	/* not a legal temperature */
+	if ((temperature > IWL_MVM_DEBUG_SET_TEMPERATURE_MAX &&
+	     temperature != IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) ||
+	    temperature < IWL_MVM_DEBUG_SET_TEMPERATURE_MIN)
+		return -EINVAL;
+
+	mutex_lock(&mvm->mutex);
+	if (temperature == IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) {
+		if (!mvm->temperature_test)
+			goto out;
+
+		mvm->temperature_test = false;
+		/* Since we can't read the temp while awake, just set
+		 * it to zero until we get the next RX stats from the
+		 * firmware.
+		 */
+		mvm->temperature = 0;
+	} else {
+		mvm->temperature_test = true;
+		mvm->temperature = temperature;
+	}
+	IWL_DEBUG_TEMP(mvm, "%sabling debug set temperature (temp = %d)\n",
+		       mvm->temperature_test ? "En" : "Dis" ,
+		       mvm->temperature);
+	/* handle the temperature change */
+	iwl_mvm_tt_handler(mvm);
+
+out:
+	mutex_unlock(&mvm->mutex);
+
+	return count;
+}
+
+static ssize_t iwl_dbgfs_nic_temp_read(struct file *file,
+				       char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	struct iwl_mvm *mvm = file->private_data;
+	char buf[16];
+	int pos, temp;
+
+	if (!mvm->ucode_loaded)
+		return -EIO;
+
+	mutex_lock(&mvm->mutex);
+	temp = iwl_mvm_get_temp(mvm);
+	mutex_unlock(&mvm->mutex);
+
+	if (temp < 0)
+		return temp;
+
+	pos = scnprintf(buf , sizeof(buf), "%d\n", temp);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
 static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
 				       size_t count, loff_t *ppos)
 {
@@ -1190,6 +1282,18 @@
 	PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
 	PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
 	PRINT_MVM_REF(IWL_MVM_REF_USER);
+	PRINT_MVM_REF(IWL_MVM_REF_TX);
+	PRINT_MVM_REF(IWL_MVM_REF_TX_AGG);
+	PRINT_MVM_REF(IWL_MVM_REF_ADD_IF);
+	PRINT_MVM_REF(IWL_MVM_REF_START_AP);
+	PRINT_MVM_REF(IWL_MVM_REF_BSS_CHANGED);
+	PRINT_MVM_REF(IWL_MVM_REF_PREPARE_TX);
+	PRINT_MVM_REF(IWL_MVM_REF_PROTECT_TDLS);
+	PRINT_MVM_REF(IWL_MVM_REF_CHECK_CTKILL);
+	PRINT_MVM_REF(IWL_MVM_REF_PRPH_READ);
+	PRINT_MVM_REF(IWL_MVM_REF_PRPH_WRITE);
+	PRINT_MVM_REF(IWL_MVM_REF_NMI);
+	PRINT_MVM_REF(IWL_MVM_REF_TM_CMD);
 	PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK);
 
 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
@@ -1296,6 +1400,8 @@
 MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
 MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64);
+MVM_DEBUGFS_READ_FILE_OPS(nic_temp);
 MVM_DEBUGFS_READ_FILE_OPS(stations);
 MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
 MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
@@ -1336,6 +1442,9 @@
 	MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
 	MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
 	MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
+	MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir,
+			     S_IWUSR | S_IRUSR);
+	MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR);
 	MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
 	MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR);
 	MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
@@ -1380,6 +1489,13 @@
 		goto err;
 #endif
 
+	if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR,
+			       mvm->debugfs_dir,
+			       &mvm->low_latency_agg_frame_limit))
+		goto err;
+	if (!debugfs_create_u8("ps_disabled", S_IRUSR,
+			       mvm->debugfs_dir, &mvm->ps_disabled))
+		goto err;
 	if (!debugfs_create_blob("nvm_hw", S_IRUSR,
 				  mvm->debugfs_dir, &mvm->nvm_hw_blob))
 		goto err;
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.h b/drivers/net/wireless/iwlwifi/mvm/debugfs.h
index e3a9774..8c4190e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
index 6987571..816883f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
index 13696fe..e74cdf2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
index c3a8c86..27dd863 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
index c02a9e4..1354c68 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -668,6 +670,8 @@
  * @IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE: send iteration complete notification
  * @IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS multiple SSID matching
  * @IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented
+ * @IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED: insert WFA vendor-specific TPC report
+ *	and DS parameter set IEs into probe requests.
  */
 enum iwl_mvm_lmac_scan_flags {
 	IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL		= BIT(0),
@@ -676,6 +680,7 @@
 	IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE	= BIT(3),
 	IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS	= BIT(4),
 	IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED	= BIT(5),
+	IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED	= BIT(6),
 };
 
 enum iwl_scan_priority {
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
index 47bd040..21dd5b7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
index d6073f6..5bca1f8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
@@ -66,6 +66,7 @@
 /**
  * enum iwl_tx_flags - bitmasks for tx_flags in TX command
  * @TX_CMD_FLG_PROT_REQUIRE: use RTS or CTS-to-self to protect the frame
+ * @TX_CMD_FLG_WRITE_TX_POWER: update current tx power value in the mgmt frame
  * @TX_CMD_FLG_ACK: expect ACK from receiving station
  * @TX_CMD_FLG_STA_RATE: use RS table with initial index from the TX command.
  *	Otherwise, use rate_n_flags from the TX command
@@ -97,6 +98,7 @@
  */
 enum iwl_tx_flags {
 	TX_CMD_FLG_PROT_REQUIRE		= BIT(0),
+	TX_CMD_FLG_WRITE_TX_POWER	= BIT(1),
 	TX_CMD_FLG_ACK			= BIT(3),
 	TX_CMD_FLG_STA_RATE		= BIT(4),
 	TX_CMD_FLG_BAR			= BIT(6),
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 9a922f3..667a922 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -73,16 +75,20 @@
 #include "fw-api-coex.h"
 #include "fw-api-scan.h"
 
-/* maximal number of Tx queues in any platform */
-#define IWL_MVM_MAX_QUEUES	20
-
 /* Tx queue numbers */
 enum {
 	IWL_MVM_OFFCHANNEL_QUEUE = 8,
 	IWL_MVM_CMD_QUEUE = 9,
 };
 
-#define IWL_MVM_CMD_FIFO	7
+enum iwl_mvm_tx_fifo {
+	IWL_MVM_TX_FIFO_BK = 0,
+	IWL_MVM_TX_FIFO_BE,
+	IWL_MVM_TX_FIFO_VI,
+	IWL_MVM_TX_FIFO_VO,
+	IWL_MVM_TX_FIFO_MCAST = 5,
+	IWL_MVM_TX_FIFO_CMD = 7,
+};
 
 #define IWL_MVM_STATION_COUNT	16
 
@@ -110,6 +116,9 @@
 	TXPATH_FLUSH = 0x1e,
 	MGMT_MCAST_KEY = 0x1f,
 
+	/* scheduler config */
+	SCD_QUEUE_CFG = 0x1d,
+
 	/* global key */
 	WEP_KEY = 0x20,
 
@@ -184,6 +193,8 @@
 	REPLY_RX_MPDU_CMD = 0xc1,
 	BA_NOTIF = 0xc5,
 
+	MARKER_CMD = 0xcb,
+
 	/* BT Coex */
 	BT_COEX_PRIO_TABLE = 0xcc,
 	BT_COEX_PROT_ENV = 0xcd,
@@ -197,6 +208,10 @@
 	REPLY_SF_CFG_CMD = 0xd1,
 	REPLY_BEACON_FILTERING_CMD = 0xd2,
 
+	/* DTS measurements */
+	CMD_DTS_MEASUREMENT_TRIGGER = 0xdc,
+	DTS_MEASUREMENT_NOTIFICATION = 0xdd,
+
 	REPLY_DEBUG_CMD = 0xf0,
 	DEBUG_LOG_MSG = 0xf7,
 
@@ -542,7 +557,7 @@
 	TE_WIDI_TX_SYNC,
 
 	/* Channel Switch NoA */
-	TE_P2P_GO_CSA_NOA,
+	TE_CHANNEL_SWITCH_PERIOD,
 
 	TE_MAX
 }; /* MAC_EVENT_TYPE_API_E_VER_1 */
@@ -1307,6 +1322,38 @@
 	struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER];
 } __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */
 
+/*
+ * enum iwl_mvm_marker_id - maker ids
+ *
+ * The ids for different type of markers to insert into the usniffer logs
+ */
+enum iwl_mvm_marker_id {
+	MARKER_ID_TX_FRAME_LATENCY = 1,
+}; /* MARKER_ID_API_E_VER_1 */
+
+/**
+ * struct iwl_mvm_marker - mark info into the usniffer logs
+ *
+ * (MARKER_CMD = 0xcb)
+ *
+ * Mark the UTC time stamp into the usniffer logs together with additional
+ * metadata, so the usniffer output can be parsed.
+ * In the command response the ucode will return the GP2 time.
+ *
+ * @dw_len: The amount of dwords following this byte including this byte.
+ * @marker_id: A unique marker id (iwl_mvm_marker_id).
+ * @reserved: reserved.
+ * @timestamp: in milliseconds since 1970-01-01 00:00:00 UTC
+ * @metadata: additional meta data that will be written to the unsiffer log
+ */
+struct iwl_mvm_marker {
+	u8 dwLen;
+	u8 markerId;
+	__le16 reserved;
+	__le64 timestamp;
+	__le32 metadata[0];
+} __packed; /* MARKER_API_S_VER_1 */
+
 struct mvm_statistics_dbg {
 	__le32 burst_check;
 	__le32 burst_count;
@@ -1561,6 +1608,8 @@
 
 #define SF_LONG_DELAY_AGING_TIMER 1000000	/* 1 Sec */
 
+#define SF_CFG_DUMMY_NOTIF_OFF	BIT(16)
+
 /**
  * Smart Fifo configuration command.
  * @state: smart fifo state, types listed in enum %iwl_sf_sate.
@@ -1576,4 +1625,89 @@
 	__le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
 } __packed; /* SF_CFG_API_S_VER_2 */
 
+/* DTS measurements */
+
+enum iwl_dts_measurement_flags {
+	DTS_TRIGGER_CMD_FLAGS_TEMP	= BIT(0),
+	DTS_TRIGGER_CMD_FLAGS_VOLT	= BIT(1),
+};
+
+/**
+ * iwl_dts_measurement_cmd - request DTS temperature and/or voltage measurements
+ *
+ * @flags: indicates which measurements we want as specified in &enum
+ *	   iwl_dts_measurement_flags
+ */
+struct iwl_dts_measurement_cmd {
+	__le32 flags;
+} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_CMD_S */
+
+/**
+ * iwl_dts_measurement_notif - notification received with the measurements
+ *
+ * @temp: the measured temperature
+ * @voltage: the measured voltage
+ */
+struct iwl_dts_measurement_notif {
+	__le32 temp;
+	__le32 voltage;
+} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */
+
+/**
+ * enum iwl_scd_control - scheduler config command control flags
+ * @IWL_SCD_CONTROL_RM_TID: remove TID from this queue
+ * @IWL_SCD_CONTROL_SET_SSN: use the SSN and program it into HW
+ */
+enum iwl_scd_control {
+	IWL_SCD_CONTROL_RM_TID	= BIT(4),
+	IWL_SCD_CONTROL_SET_SSN	= BIT(5),
+};
+
+/**
+ * enum iwl_scd_flags - scheduler config command flags
+ * @IWL_SCD_FLAGS_SHARE_TID: multiple TIDs map to this queue
+ * @IWL_SCD_FLAGS_SHARE_RA: multiple RAs map to this queue
+ * @IWL_SCD_FLAGS_DQA_ENABLED: DQA is enabled
+ */
+enum iwl_scd_flags {
+	IWL_SCD_FLAGS_SHARE_TID		= BIT(0),
+	IWL_SCD_FLAGS_SHARE_RA		= BIT(1),
+	IWL_SCD_FLAGS_DQA_ENABLED	= BIT(2),
+};
+
+#define IWL_SCDQ_INVALID_STA	0xff
+
+/**
+ * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command
+ * @token:	dialog token addba - unused legacy
+ * @sta_id:	station id 4-bit
+ * @tid:	TID 0..7
+ * @scd_queue:	TFD queue num 0 .. 31
+ * @enable:	1 queue enable, 0 queue disable
+ * @aggregate:	1 aggregated queue, 0 otherwise
+ * @tx_fifo:	tx fifo num 0..7
+ * @window:	up to 64
+ * @ssn:	starting seq num 12-bit
+ * @control:	command control flags
+ * @flags:	flags - see &enum iwl_scd_flags
+ *
+ * Note that every time the command is sent, all parameters must
+ * be filled with the exception of
+ *  - the SSN, which is only used with @IWL_SCD_CONTROL_SET_SSN
+ *  - the window, which is only relevant when starting aggregation
+ */
+struct iwl_scd_txq_cfg_cmd {
+	u8 token;
+	u8 sta_id;
+	u8 tid;
+	u8 scd_queue;
+	u8 enable;
+	u8 aggregate;
+	u8 tx_fifo;
+	u8 window;
+	__le16 ssn;
+	u8 control;
+	u8 flags;
+} __packed;
+
 #endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index 883e702..23fd711 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -242,10 +244,10 @@
 			mvm->queue_to_mac80211[i] = i;
 		else
 			mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
-		atomic_set(&mvm->queue_stop_count[i], 0);
 	}
 
-	mvm->transport_queue_stop = 0;
+	for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
+		atomic_set(&mvm->mac80211_queue_stop_count[i], 0);
 
 	mvm->ucode_loaded = true;
 
@@ -452,6 +454,9 @@
 	for (i = 0; i < IWL_MVM_STATION_COUNT; i++)
 		RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
 
+	/* reset quota debouncing buffer - 0xff will yield invalid data */
+	memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd));
+
 	/* Add auxiliary station for scanning */
 	ret = iwl_mvm_add_aux_sta(mvm);
 	if (ret)
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 8242e68..0c5c0b0 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -81,7 +83,7 @@
 	struct ieee80211_vif *vif;
 	unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)];
 	unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)];
-	unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_MAX_QUEUES)];
+	u32 used_hw_queues;
 	enum iwl_tsf_id preferred_tsf;
 	bool found_vif;
 };
@@ -192,12 +194,31 @@
 		data->preferred_tsf = NUM_TSF_IDS;
 }
 
+/*
+ * Get the mask of the queues used by the vif
+ */
+u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
+				struct ieee80211_vif *vif)
+{
+	u32 qmask = 0, ac;
+
+	if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
+		return BIT(IWL_MVM_OFFCHANNEL_QUEUE);
+
+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+		qmask |= BIT(vif->hw_queue[ac]);
+
+	if (vif->type == NL80211_IFTYPE_AP)
+		qmask |= BIT(vif->cab_queue);
+
+	return qmask;
+}
+
 static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
 				       struct ieee80211_vif *vif)
 {
 	struct iwl_mvm_mac_iface_iterator_data *data = _data;
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-	u32 ac;
 
 	/* Iterator may already find the interface being added -- skip it */
 	if (vif == data->vif) {
@@ -206,12 +227,7 @@
 	}
 
 	/* Mark the queues used by the vif */
-	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-		if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
-			__set_bit(vif->hw_queue[ac], data->used_hw_queues);
-
-	if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
-		__set_bit(vif->cab_queue, data->used_hw_queues);
+	data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(data->mvm, vif);
 
 	/* Mark MAC IDs as used by clearing the available bit, and
 	 * (below) mark TSFs as used if their existing use is not
@@ -225,24 +241,6 @@
 	iwl_mvm_mac_tsf_id_iter(_data, mac, vif);
 }
 
-/*
- * Get the mask of the queus used by the vif
- */
-u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
-				struct ieee80211_vif *vif)
-{
-	u32 qmask = 0, ac;
-
-	if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
-		return BIT(IWL_MVM_OFFCHANNEL_QUEUE);
-
-	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-		if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
-			qmask |= BIT(vif->hw_queue[ac]);
-
-	return qmask;
-}
-
 void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
 				    struct ieee80211_vif *vif)
 {
@@ -277,15 +275,15 @@
 		.available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 },
 		/* no preference yet */
 		.preferred_tsf = NUM_TSF_IDS,
-		.used_hw_queues = {
+		.used_hw_queues =
 			BIT(IWL_MVM_OFFCHANNEL_QUEUE) |
 			BIT(mvm->aux_queue) |
-			BIT(IWL_MVM_CMD_QUEUE)
-		},
+			BIT(IWL_MVM_CMD_QUEUE),
 		.found_vif = false,
 	};
 	u32 ac;
 	int ret, i;
+	unsigned long used_hw_queues;
 
 	/*
 	 * Allocate a MAC ID and a TSF for this MAC, along with the queues
@@ -368,9 +366,11 @@
 		return 0;
 	}
 
+	used_hw_queues = data.used_hw_queues;
+
 	/* Find available queues, and allocate them to the ACs */
 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-		u8 queue = find_first_zero_bit(data.used_hw_queues,
+		u8 queue = find_first_zero_bit(&used_hw_queues,
 					       mvm->first_agg_queue);
 
 		if (queue >= mvm->first_agg_queue) {
@@ -379,13 +379,13 @@
 			goto exit_fail;
 		}
 
-		__set_bit(queue, data.used_hw_queues);
+		__set_bit(queue, &used_hw_queues);
 		vif->hw_queue[ac] = queue;
 	}
 
 	/* Allocate the CAB queue for softAP and GO interfaces */
 	if (vif->type == NL80211_IFTYPE_AP) {
-		u8 queue = find_first_zero_bit(data.used_hw_queues,
+		u8 queue = find_first_zero_bit(&used_hw_queues,
 					       mvm->first_agg_queue);
 
 		if (queue >= mvm->first_agg_queue) {
@@ -427,17 +427,17 @@
 
 	switch (vif->type) {
 	case NL80211_IFTYPE_P2P_DEVICE:
-		iwl_trans_ac_txq_enable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE,
-					IWL_MVM_TX_FIFO_VO);
+		iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
+				      IWL_MVM_TX_FIFO_VO);
 		break;
 	case NL80211_IFTYPE_AP:
-		iwl_trans_ac_txq_enable(mvm->trans, vif->cab_queue,
-					IWL_MVM_TX_FIFO_MCAST);
+		iwl_mvm_enable_ac_txq(mvm, vif->cab_queue,
+				      IWL_MVM_TX_FIFO_MCAST);
 		/* fall through */
 	default:
 		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-			iwl_trans_ac_txq_enable(mvm->trans, vif->hw_queue[ac],
-						iwl_mvm_ac_to_tx_fifo[ac]);
+			iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac],
+					      iwl_mvm_ac_to_tx_fifo[ac]);
 		break;
 	}
 
@@ -452,14 +452,14 @@
 
 	switch (vif->type) {
 	case NL80211_IFTYPE_P2P_DEVICE:
-		iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE);
+		iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE);
 		break;
 	case NL80211_IFTYPE_AP:
-		iwl_trans_txq_disable(mvm->trans, vif->cab_queue);
+		iwl_mvm_disable_txq(mvm, vif->cab_queue);
 		/* fall through */
 	default:
 		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-			iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac]);
+			iwl_mvm_disable_txq(mvm, vif->hw_queue[ac]);
 	}
 }
 
@@ -586,6 +586,7 @@
 static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
 					struct ieee80211_vif *vif,
 					struct iwl_mac_ctx_cmd *cmd,
+					const u8 *bssid_override,
 					u32 action)
 {
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -593,6 +594,7 @@
 	bool ht_enabled = !!(vif->bss_conf.ht_operation_mode &
 			     IEEE80211_HT_OP_MODE_PROTECTION);
 	u8 cck_ack_rates, ofdm_ack_rates;
+	const u8 *bssid = bssid_override ?: vif->bss_conf.bssid;
 	int i;
 
 	cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
@@ -625,8 +627,9 @@
 	cmd->tsf_id = cpu_to_le32(mvmvif->tsf_id);
 
 	memcpy(cmd->node_addr, vif->addr, ETH_ALEN);
-	if (vif->bss_conf.bssid)
-		memcpy(cmd->bssid_addr, vif->bss_conf.bssid, ETH_ALEN);
+
+	if (bssid)
+		memcpy(cmd->bssid_addr, bssid, ETH_ALEN);
 	else
 		eth_broadcast_addr(cmd->bssid_addr);
 
@@ -695,7 +698,8 @@
 
 static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
 				    struct ieee80211_vif *vif,
-				    u32 action, bool force_assoc_off)
+				    u32 action, bool force_assoc_off,
+				    const u8 *bssid_override)
 {
 	struct iwl_mac_ctx_cmd cmd = {};
 	struct iwl_mac_data_sta *ctxt_sta;
@@ -703,7 +707,7 @@
 	WARN_ON(vif->type != NL80211_IFTYPE_STATION);
 
 	/* Fill the common data for all mac context types */
-	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, bssid_override, action);
 
 	if (vif->p2p) {
 		struct ieee80211_p2p_noa_attr *noa =
@@ -784,7 +788,7 @@
 
 	WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
 
-	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
 
 	cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC |
 				       MAC_FILTER_IN_CONTROL_AND_MGMT |
@@ -805,7 +809,7 @@
 
 	WARN_ON(vif->type != NL80211_IFTYPE_ADHOC);
 
-	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
 
 	cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_BEACON |
 				       MAC_FILTER_IN_PROBE_REQUEST);
@@ -844,7 +848,7 @@
 
 	WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);
 
-	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
 
 	cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
 
@@ -1072,7 +1076,7 @@
 	WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p);
 
 	/* Fill the common data for all mac context types */
-	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
 
 	/*
 	 * pass probe requests and beacons from other APs (needed
@@ -1098,7 +1102,7 @@
 	WARN_ON(vif->type != NL80211_IFTYPE_AP || !vif->p2p);
 
 	/* Fill the common data for all mac context types */
-	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+	iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
 
 	/*
 	 * pass probe requests and beacons from other APs (needed
@@ -1121,12 +1125,14 @@
 }
 
 static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-				u32 action, bool force_assoc_off)
+				u32 action, bool force_assoc_off,
+				const u8 *bssid_override)
 {
 	switch (vif->type) {
 	case NL80211_IFTYPE_STATION:
 		return iwl_mvm_mac_ctxt_cmd_sta(mvm, vif, action,
-						force_assoc_off);
+						force_assoc_off,
+						bssid_override);
 		break;
 	case NL80211_IFTYPE_AP:
 		if (!vif->p2p)
@@ -1157,7 +1163,7 @@
 		return -EIO;
 
 	ret = iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD,
-				   true);
+				   true, NULL);
 	if (ret)
 		return ret;
 
@@ -1169,7 +1175,7 @@
 }
 
 int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-			     bool force_assoc_off)
+			     bool force_assoc_off, const u8 *bssid_override)
 {
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 
@@ -1178,7 +1184,7 @@
 		return -EIO;
 
 	return iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY,
-				    force_assoc_off);
+				    force_assoc_off, bssid_override);
 }
 
 int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
@@ -1226,13 +1232,13 @@
 		    !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) {
 			u32 rel_time = (c + 1) *
 				       csa_vif->bss_conf.beacon_int -
-				       IWL_MVM_CHANNEL_SWITCH_TIME;
+				       IWL_MVM_CHANNEL_SWITCH_TIME_GO;
 			u32 apply_time = gp2 + rel_time * 1024;
 
-			iwl_mvm_schedule_csa_noa(mvm, csa_vif,
-						 IWL_MVM_CHANNEL_SWITCH_TIME -
-						 IWL_MVM_CHANNEL_SWITCH_MARGIN,
-						 apply_time);
+			iwl_mvm_schedule_csa_period(mvm, csa_vif,
+					 IWL_MVM_CHANNEL_SWITCH_TIME_GO -
+					 IWL_MVM_CHANNEL_SWITCH_MARGIN,
+					 apply_time);
 		}
 	} else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) {
 		/* we don't have CSA NoA scheduled yet, switch now */
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 6edbcf2..fec128f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -277,14 +279,6 @@
 	}
 }
 
-static int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm)
-{
-	/* we create the 802.11 header and SSID element */
-	if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID)
-		return mvm->fw->ucode_capa.max_probe_length - 24 - 2;
-	return mvm->fw->ucode_capa.max_probe_length - 24 - 34;
-}
-
 int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
 {
 	struct ieee80211_hw *hw = mvm->hw;
@@ -302,8 +296,7 @@
 		    IEEE80211_HW_TIMING_BEACON_ONLY |
 		    IEEE80211_HW_CONNECTION_MONITOR |
 		    IEEE80211_HW_CHANCTX_STA_CSA |
-		    IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
-		    IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+		    IEEE80211_HW_SUPPORTS_CLONED_SKBS;
 
 	hw->queues = mvm->first_agg_queue;
 	hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
@@ -325,7 +318,7 @@
 	    IWL_UCODE_API(mvm->fw->ucode_ver) >= 9 &&
 	    !iwlwifi_mod_params.uapsd_disable) {
 		hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
-		hw->uapsd_queues = IWL_UAPSD_AC_INFO;
+		hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
 		hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
 	}
 
@@ -378,7 +371,7 @@
 
 	iwl_mvm_reset_phy_ctxts(mvm);
 
-	hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm);
+	hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm, false);
 
 	hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
 
@@ -407,7 +400,25 @@
 
 	hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
 			       NL80211_FEATURE_LOW_PRIORITY_SCAN |
-			       NL80211_FEATURE_P2P_GO_OPPPS;
+			       NL80211_FEATURE_P2P_GO_OPPPS |
+			       NL80211_FEATURE_DYNAMIC_SMPS |
+			       NL80211_FEATURE_STATIC_SMPS;
+
+	if (mvm->fw->ucode_capa.capa[0] &
+	    IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT)
+		hw->wiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION;
+	if (mvm->fw->ucode_capa.capa[0] &
+	    IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT)
+		hw->wiphy->features |= NL80211_FEATURE_QUIET;
+
+	if (mvm->fw->ucode_capa.capa[0] &
+	    IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT)
+		hw->wiphy->features |=
+			NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES;
+
+	if (mvm->fw->ucode_capa.capa[0] &
+	    IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT)
+		hw->wiphy->features |= NL80211_FEATURE_WFA_TPC_IE_IN_PROBES;
 
 	mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
 
@@ -668,8 +679,9 @@
 }
 
 #ifdef CPTCFG_IWLWIFI_DEBUGFS
-static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
+void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 {
+	static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
 	struct iwl_fw_error_dump_file *dump_file;
 	struct iwl_fw_error_dump_data *dump_data;
 	struct iwl_fw_error_dump_info *dump_info;
@@ -761,23 +773,20 @@
 		file_len += fw_error_dump->trans_ptr->len;
 	dump_file->file_len = cpu_to_le32(file_len);
 	mvm->fw_error_dump = fw_error_dump;
+
+	/* notify the userspace about the error we had */
+	kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
 }
 #endif
 
 static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
 {
-#ifdef CPTCFG_IWLWIFI_DEBUGFS
-	static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
-
 	iwl_mvm_fw_error_dump(mvm);
 
-	/* notify the userspace about the error we had */
-	kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
-#endif
-
 	iwl_trans_stop_device(mvm->trans);
 
 	mvm->scan_status = IWL_MVM_SCAN_NONE;
+	mvm->ps_disabled = false;
 
 	/* just in case one was running */
 	ieee80211_remain_on_channel_expired(mvm->hw);
@@ -805,16 +814,18 @@
 	 * ucode_down ref until reconfig is complete */
 	iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
 
+	/* clear any stale d0i3 state */
+	clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
+
 	mvm->vif_count = 0;
 	mvm->rx_ba_sessions = 0;
 }
 
-static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
+int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
 {
-	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 	int ret;
 
-	mutex_lock(&mvm->mutex);
+	lockdep_assert_held(&mvm->mutex);
 
 	/* Clean up some internal and mac80211 state on restart */
 	if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
@@ -831,6 +842,16 @@
 		iwl_mvm_d0i3_enable_tx(mvm, NULL);
 	}
 
+	return ret;
+}
+
+static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	int ret;
+
+	mutex_lock(&mvm->mutex);
+	ret = __iwl_mvm_mac_start(mvm);
 	mutex_unlock(&mvm->mutex);
 
 	return ret;
@@ -856,14 +877,9 @@
 	mutex_unlock(&mvm->mutex);
 }
 
-static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
+void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
 {
-	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-
-	flush_work(&mvm->d0i3_exit_work);
-	flush_work(&mvm->async_handlers_wk);
-
-	mutex_lock(&mvm->mutex);
+	lockdep_assert_held(&mvm->mutex);
 
 	/* disallow low power states when the FW is down */
 	iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
@@ -882,8 +898,21 @@
 	/* async_handlers_list is empty and will stay empty: HW is stopped */
 
 	/* the fw is stopped, the aux sta is dead: clean up driver state */
-	iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
+	iwl_mvm_del_aux_sta(mvm);
 
+	mvm->ucode_loaded = false;
+}
+
+static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+	flush_work(&mvm->d0i3_exit_work);
+	flush_work(&mvm->async_handlers_wk);
+	flush_work(&mvm->fw_error_dump_wk);
+
+	mutex_lock(&mvm->mutex);
+	__iwl_mvm_mac_stop(mvm);
 	mutex_unlock(&mvm->mutex);
 
 	/*
@@ -967,10 +996,7 @@
 	 */
 	if (vif->type == NL80211_IFTYPE_AP ||
 	    vif->type == NL80211_IFTYPE_ADHOC) {
-		u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
-		ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta,
-					       qmask,
-					       ieee80211_vif_type_p2p(vif));
+		ret = iwl_mvm_alloc_bcast_sta(mvm, vif);
 		if (ret) {
 			IWL_ERR(mvm, "Failed to allocate bcast sta\n");
 			goto out_release;
@@ -1018,7 +1044,7 @@
 		if (ret)
 			goto out_unref_phy;
 
-		ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
+		ret = iwl_mvm_add_bcast_sta(mvm, vif);
 		if (ret)
 			goto out_unbind;
 
@@ -1059,14 +1085,7 @@
 static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
 					struct ieee80211_vif *vif)
 {
-	u32 tfd_msk = 0, ac;
-
-	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-		if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
-			tfd_msk |= BIT(vif->hw_queue[ac]);
-
-	if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
-		tfd_msk |= BIT(vif->cab_queue);
+	u32 tfd_msk = iwl_mvm_mac_get_queues_mask(mvm, vif);
 
 	if (tfd_msk) {
 		mutex_lock(&mvm->mutex);
@@ -1122,13 +1141,13 @@
 			mvm->noa_duration = 0;
 		}
 #endif
-		iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
+		iwl_mvm_dealloc_bcast_sta(mvm, vif);
 		goto out_release;
 	}
 
 	if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
 		mvm->p2p_device_vif = NULL;
-		iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+		iwl_mvm_rm_bcast_sta(mvm, vif);
 		iwl_mvm_binding_remove_vif(mvm, vif);
 		iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
 		mvmvif->phy_ctxt = NULL;
@@ -1202,14 +1221,15 @@
 	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 	struct iwl_mcast_filter_cmd *cmd;
 	struct netdev_hw_addr *addr;
-	int addr_count = netdev_hw_addr_list_count(mc_list);
-	bool pass_all = false;
+	int addr_count;
+	bool pass_all;
 	int len;
 
-	if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) {
-		pass_all = true;
+	addr_count = netdev_hw_addr_list_count(mc_list);
+	pass_all = addr_count > MAX_MCAST_FILTERING_ADDRESSES ||
+		   IWL_MVM_FW_MCAST_FILTER_PASS_ALL;
+	if (pass_all)
 		addr_count = 0;
-	}
 
 	len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4);
 	cmd = kzalloc(len, GFP_ATOMIC);
@@ -1409,28 +1429,6 @@
 }
 #endif
 
-static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)
-{
-	struct ieee80211_sta *sta;
-	struct iwl_mvm_sta *mvmsta;
-	int i;
-
-	lockdep_assert_held(&mvm->mutex);
-
-	for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
-		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
-						lockdep_is_held(&mvm->mutex));
-		if (!sta || IS_ERR(sta) || !sta->tdls)
-			continue;
-
-		mvmsta = iwl_mvm_sta_from_mac80211(sta);
-		ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,
-				NL80211_TDLS_TEARDOWN,
-				WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,
-				GFP_KERNEL);
-	}
-}
-
 static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
 					     struct ieee80211_vif *vif,
 					     struct ieee80211_bss_conf *bss_conf,
@@ -1447,10 +1445,23 @@
 	if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc)
 		iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
 
-	ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false);
+	/*
+	 * If we're not associated yet, take the (new) BSSID before associating
+	 * so the firmware knows. If we're already associated, then use the old
+	 * BSSID here, and we'll send a cleared one later in the CHANGED_ASSOC
+	 * branch for disassociation below.
+	 */
+	if (changes & BSS_CHANGED_BSSID && !mvmvif->associated)
+		memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN);
+
+	ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, mvmvif->bssid);
 	if (ret)
 		IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
 
+	/* after sending it once, adopt mac80211 data */
+	memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN);
+	mvmvif->associated = bss_conf->assoc;
+
 	if (changes & BSS_CHANGED_ASSOC) {
 		if (bss_conf->assoc) {
 			/* add quota for this interface */
@@ -1478,13 +1489,17 @@
 				 */
 				u32 dur = (11 * vif->bss_conf.beacon_int) / 10;
 				iwl_mvm_protect_session(mvm, vif, dur, dur,
-							5 * dur);
+							5 * dur, false);
 			}
 
 			iwl_mvm_sf_update(mvm, vif, false);
 			iwl_mvm_power_vif_assoc(mvm, vif);
-			if (vif->p2p)
+			if (vif->p2p) {
 				iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT);
+				iwl_mvm_update_smps(mvm, vif,
+						    IWL_MVM_SMPS_REQ_PROT,
+						    IEEE80211_SMPS_DYNAMIC);
+			}
 		} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
 			/*
 			 * If update fails - SF might be running in associated
@@ -1508,6 +1523,13 @@
 
 			if (vif->p2p)
 				iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT);
+
+			/* this will take the cleared BSSID from bss_conf */
+			ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+			if (ret)
+				IWL_ERR(mvm,
+					"failed to update MAC %pM (clear after unassoc)\n",
+					vif->addr);
 		}
 
 		iwl_mvm_recalc_multicast(mvm);
@@ -1604,7 +1626,7 @@
 
 	/* Send the bcast station. At this stage the TBTT and DTIM time events
 	 * are added and applied to the scheduler */
-	ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
+	ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
 	if (ret)
 		goto out_unbind;
 
@@ -1620,7 +1642,7 @@
 
 	/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
 	if (vif->p2p && mvm->p2p_device_vif)
-		iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);
+		iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);
 
 	iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS);
 
@@ -1636,7 +1658,7 @@
 out_quota_failed:
 	iwl_mvm_power_update_mac(mvm);
 	mvmvif->ap_ibss_active = false;
-	iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+	iwl_mvm_send_rm_bcast_sta(mvm, vif);
 out_unbind:
 	iwl_mvm_binding_remove_vif(mvm, vif);
 out_remove:
@@ -1678,10 +1700,10 @@
 
 	/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
 	if (vif->p2p && mvm->p2p_device_vif)
-		iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);
+		iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);
 
 	iwl_mvm_update_quotas(mvm, NULL);
-	iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+	iwl_mvm_send_rm_bcast_sta(mvm, vif);
 	iwl_mvm_binding_remove_vif(mvm, vif);
 
 	iwl_mvm_power_update_mac(mvm);
@@ -1704,8 +1726,8 @@
 		return;
 
 	if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT |
-		       BSS_CHANGED_BANDWIDTH) &&
-	    iwl_mvm_mac_ctxt_changed(mvm, vif, false))
+		       BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS) &&
+	    iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL))
 		IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
 
 	/* Need to send a new beacon template to the FW */
@@ -1935,48 +1957,6 @@
 	mutex_unlock(&mvm->mutex);
 }
 
-int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
-{
-	struct ieee80211_sta *sta;
-	struct iwl_mvm_sta *mvmsta;
-	int count = 0;
-	int i;
-
-	lockdep_assert_held(&mvm->mutex);
-
-	for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
-		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
-						lockdep_is_held(&mvm->mutex));
-		if (!sta || IS_ERR(sta) || !sta->tdls)
-			continue;
-
-		if (vif) {
-			mvmsta = iwl_mvm_sta_from_mac80211(sta);
-			if (mvmsta->vif != vif)
-				continue;
-		}
-
-		count++;
-	}
-
-	return count;
-}
-
-static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm,
-				      struct ieee80211_vif *vif,
-				      bool sta_added)
-{
-	int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif);
-
-	/*
-	 * Disable ps when the first TDLS sta is added and re-enable it
-	 * when the last TDLS sta is removed
-	 */
-	if ((tdls_sta_cnt == 1 && sta_added) ||
-	    (tdls_sta_cnt == 0 && !sta_added))
-		iwl_mvm_power_update_mac(mvm);
-}
-
 static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
 				 struct ieee80211_vif *vif,
 				 struct ieee80211_sta *sta,
@@ -2116,7 +2096,7 @@
 		int ret;
 
 		mutex_lock(&mvm->mutex);
-		ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false);
+		ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
 		mutex_unlock(&mvm->mutex);
 		return ret;
 	}
@@ -2144,33 +2124,12 @@
 
 	mutex_lock(&mvm->mutex);
 	/* Try really hard to protect the session and hear a beacon */
-	iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500);
+	iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false);
 	mutex_unlock(&mvm->mutex);
 
 	iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX);
 }
 
-static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
-						  struct ieee80211_vif *vif)
-{
-	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-	u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int;
-
-	/*
-	 * iwl_mvm_protect_session() reads directly from the device
-	 * (the system time), so make sure it is available.
-	 */
-	if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS))
-		return;
-
-	mutex_lock(&mvm->mutex);
-	/* Protect the session to hear the TDLS setup response on the channel */
-	iwl_mvm_protect_session(mvm, vif, duration, duration, 100);
-	mutex_unlock(&mvm->mutex);
-
-	iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS);
-}
-
 static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
 					struct ieee80211_vif *vif,
 					struct cfg80211_sched_scan_request *req,
@@ -2185,7 +2144,13 @@
 
 	mutex_lock(&mvm->mutex);
 
-	if (!iwl_mvm_is_idle(mvm)) {
+	/* Newest FW fixes sched scan while connected on another interface */
+	if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) {
+		if (!vif->bss_conf.idle) {
+			ret = -EBUSY;
+			goto out;
+		}
+	} else if (!iwl_mvm_is_idle(mvm)) {
 		ret = -EBUSY;
 		goto out;
 	}
@@ -2703,7 +2668,10 @@
 		ret = 0;
 		goto out;
 	case NL80211_IFTYPE_STATION:
+		break;
 	case NL80211_IFTYPE_MONITOR:
+		/* always disable PS when a monitor interface is active */
+		mvmvif->ps_disabled = true;
 		break;
 	default:
 		ret = -EINVAL;
@@ -2735,7 +2703,20 @@
 	if ((vif->type == NL80211_IFTYPE_AP) ||
 	    (switching_chanctx && (vif->type == NL80211_IFTYPE_STATION))) {
 		iwl_mvm_update_quotas(mvm, NULL);
-		iwl_mvm_mac_ctxt_changed(mvm, vif, false);
+		iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+	}
+
+	if (vif->csa_active && vif->type == NL80211_IFTYPE_STATION) {
+		struct iwl_mvm_sta *mvmsta;
+
+		mvmsta = iwl_mvm_sta_from_staid_protected(mvm,
+							  mvmvif->ap_sta_id);
+
+		if (WARN_ON(!mvmsta))
+			goto out;
+
+		/* TODO: only re-enable after the first beacon */
+		iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false);
 	}
 
 	goto out;
@@ -2769,6 +2750,7 @@
 {
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 	struct ieee80211_vif *disabled_vif = NULL;
+	struct iwl_mvm_sta *mvmsta;
 
 	lockdep_assert_held(&mvm->mutex);
 
@@ -2779,6 +2761,7 @@
 		goto out;
 	case NL80211_IFTYPE_MONITOR:
 		mvmvif->monitor_active = false;
+		mvmvif->ps_disabled = false;
 		break;
 	case NL80211_IFTYPE_AP:
 		/* This part is triggered only during CSA */
@@ -2799,7 +2782,13 @@
 
 		disabled_vif = vif;
 
-		iwl_mvm_mac_ctxt_changed(mvm, vif, true);
+		mvmsta = iwl_mvm_sta_from_staid_protected(mvm,
+							  mvmvif->ap_sta_id);
+
+		if (!WARN_ON(!mvmsta))
+			iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true);
+
+		iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);
 		break;
 	default:
 		break;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index ccb7dd0..a1d1fc2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -85,11 +87,11 @@
 /* A TimeUnit is 1024 microsecond */
 #define MSEC_TO_TU(_msec)	(_msec*1000/1024)
 
-/*
- * The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0"
- * TBTT. This value should be big enough to ensure that we switch in time.
+/* This value represents the number of TUs before CSA "beacon 0" TBTT
+ * when the CSA time-event needs to be scheduled to start.  It must be
+ * big enough to ensure that we switch in time.
  */
-#define IWL_MVM_CHANNEL_SWITCH_TIME 40
+#define IWL_MVM_CHANNEL_SWITCH_TIME_GO		40
 
 /*
  * This value (in TUs) is used to fine tune the CSA NoA end time which should
@@ -103,14 +105,6 @@
  */
 #define IWL_MVM_CS_UNBLOCK_TX_TIMEOUT 3
 
-enum iwl_mvm_tx_fifo {
-	IWL_MVM_TX_FIFO_BK = 0,
-	IWL_MVM_TX_FIFO_BE,
-	IWL_MVM_TX_FIFO_VI,
-	IWL_MVM_TX_FIFO_VO,
-	IWL_MVM_TX_FIFO_MCAST = 5,
-};
-
 extern const struct ieee80211_ops iwl_mvm_hw_ops;
 
 /**
@@ -186,10 +180,6 @@
 };
 
 #define IWL_CONN_MAX_LISTEN_INTERVAL	10
-#define IWL_UAPSD_AC_INFO		(IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\
-					 IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\
-					 IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\
-					 IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
 #define IWL_UAPSD_MAX_SP		IEEE80211_WMM_IE_STA_QOSINFO_SP_2
 
 #ifdef CPTCFG_IWLWIFI_DEBUGFS
@@ -203,6 +193,7 @@
 	MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7),
 	MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8),
 	MVM_DEBUGFS_PM_UAPSD_MISBEHAVING = BIT(9),
+	MVM_DEBUGFS_PM_USE_PS_POLL = BIT(10),
 };
 
 struct iwl_dbgfs_pm {
@@ -215,6 +206,7 @@
 	u32 lprx_rssi_threshold;
 	bool snooze_ena;
 	bool uapsd_misbehaving;
+	bool use_ps_poll;
 	int mask;
 };
 
@@ -253,6 +245,7 @@
 enum iwl_mvm_smps_type_request {
 	IWL_MVM_SMPS_REQ_BT_COEX,
 	IWL_MVM_SMPS_REQ_TT,
+	IWL_MVM_SMPS_REQ_PROT,
 	NUM_IWL_MVM_SMPS_REQ,
 };
 
@@ -277,6 +270,8 @@
 	IWL_MVM_REF_TM_CMD,
 	IWL_MVM_REF_EXIT_WORK,
 
+	/* update debugfs.c when changing this */
+
 	IWL_MVM_REF_COUNT,
 };
 
@@ -315,6 +310,9 @@
  * @id: between 0 and 3
  * @color: to solve races upon MAC addition and removal
  * @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA
+ * @bssid: BSSID for this (client) interface
+ * @associated: indicates that we're currently associated, used only for
+ *	managing the firmware state in iwl_mvm_bss_info_changed_station()
  * @uploaded: indicates the MAC context has been added to the device
  * @ap_ibss_active: indicates that AP/IBSS is configured and that the interface
  *	should get quota etc.
@@ -323,6 +321,7 @@
  *	interface should get quota etc.
  * @low_latency: indicates that this interface is in low-latency mode
  *	(VMACLowLatencyMode)
+ * @ps_disabled: indicates that this interface requires PS to be disabled
  * @queue_params: QoS params for this MAC
  * @bcast_sta: station used for broadcast packets. Used by the following
  *  vifs: P2P_DEVICE, GO and AP.
@@ -335,11 +334,15 @@
 	u16 color;
 	u8 ap_sta_id;
 
+	u8 bssid[ETH_ALEN];
+	bool associated;
+
 	bool uploaded;
 	bool ap_ibss_active;
 	bool pm_enabled;
 	bool monitor_active;
 	bool low_latency;
+	bool ps_disabled;
 	struct iwl_mvm_vif_bf_data bf_data;
 
 	u32 ap_beacon_time;
@@ -512,6 +515,10 @@
 	D0I3_PENDING_WAKEUP,
 };
 
+#define IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE 0xff
+#define IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -100
+#define IWL_MVM_DEBUG_SET_TEMPERATURE_MAX 200
+
 struct iwl_mvm {
 	/* for logger access */
 	struct device *dev;
@@ -553,9 +560,8 @@
 
 	struct mvm_statistics_rx rx_stats;
 
-	unsigned long transport_queue_stop;
 	u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
-	atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
+	atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES];
 
 	const char *nvm_file_name;
 	struct iwl_nvm_data *nvm_data;
@@ -641,6 +647,7 @@
 
 	/* -1 for always, 0 for never, >0 for that many times */
 	s8 restart_fw;
+	struct work_struct fw_error_dump_wk;
 	struct iwl_mvm_dump_ptrs *fw_error_dump;
 
 #ifdef CPTCFG_IWLWIFI_LEDS
@@ -694,6 +701,14 @@
 	/* Thermal Throttling and CTkill */
 	struct iwl_mvm_tt_mgmt thermal_throttle;
 	s32 temperature;	/* Celsius */
+	/*
+	 * Debug option to set the NIC temperature. This option makes the
+	 * driver think this is the actual NIC temperature, and ignore the
+	 * real temperature that is received from the fw
+	 */
+	bool temperature_test;  /* Debug test temperature is enabled */
+
+	struct iwl_time_quota_cmd last_quota_cmd;
 
 #ifdef CPTCFG_NL80211_TESTMODE
 	u32 noa_duration;
@@ -706,7 +721,7 @@
 	u8 last_agg_queue;
 
 	/* Indicate if device power save is allowed */
-	bool ps_disabled;
+	u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */
 
 	struct ieee80211_vif __rcu *csa_vif;
 	struct ieee80211_vif __rcu *csa_tx_blocked_vif;
@@ -714,6 +729,8 @@
 
 	/* system time of last beacon (for AP/GO interface) */
 	u32 ap_last_beacon_gp2;
+
+	u8 low_latency_agg_frame_limit;
 };
 
 /* Extract MVM priv from op_mode and _hw */
@@ -762,6 +779,11 @@
 	       (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
 }
 
+static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm)
+{
+	return mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_DQA_SUPPORT;
+}
+
 extern const u8 iwl_mvm_ac_to_tx_fifo[];
 
 struct iwl_rate_info {
@@ -772,6 +794,9 @@
 	u8 ieee;	/* MAC header:  IWL_RATE_6M_IEEE, etc. */
 };
 
+void __iwl_mvm_mac_stop(struct iwl_mvm *mvm);
+int __iwl_mvm_mac_start(struct iwl_mvm *mvm);
+
 /******************
  * MVM Methods
  ******************/
@@ -878,7 +903,7 @@
 void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-			     bool force_assoc_off);
+			     bool force_assoc_off, const u8 *bssid_override);
 int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
 				struct ieee80211_vif *vif);
@@ -910,6 +935,7 @@
 int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
 			     struct iwl_device_cmd *cmd);
 int iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
+int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan);
 
 /* Scheduled scan */
 int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
@@ -964,10 +990,14 @@
 				struct iwl_mvm_frame_stats *stats,
 				u32 rate, bool agg);
 int rs_pretty_print_rate(char *buf, const u32 rate);
+void rs_update_last_rssi(struct iwl_mvm *mvm,
+			 struct iwl_lq_sta *lq_sta,
+			 struct ieee80211_rx_status *rx_status);
 
 /* power management */
 int iwl_mvm_power_update_device(struct iwl_mvm *mvm);
 int iwl_mvm_power_update_mac(struct iwl_mvm *mvm);
+int iwl_mvm_power_update_ps(struct iwl_mvm *mvm);
 int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 				 char *buf, int bufsz);
 
@@ -1120,6 +1150,39 @@
 	return mvmvif->low_latency;
 }
 
+/* hw scheduler queue config */
+void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn,
+			const struct iwl_trans_txq_scd_cfg *cfg);
+void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue);
+
+static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue,
+					 u8 fifo)
+{
+	struct iwl_trans_txq_scd_cfg cfg = {
+		.fifo = fifo,
+		.tid = IWL_MAX_TID_COUNT,
+		.aggregate = false,
+		.frame_limit = IWL_FRAME_LIMIT,
+	};
+
+	iwl_mvm_enable_txq(mvm, queue, 0, &cfg);
+}
+
+static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue,
+					  int fifo, int sta_id, int tid,
+					  int frame_limit, u16 ssn)
+{
+	struct iwl_trans_txq_scd_cfg cfg = {
+		.fifo = fifo,
+		.sta_id = sta_id,
+		.tid = tid,
+		.frame_limit = frame_limit,
+		.aggregate = true,
+	};
+
+	iwl_mvm_enable_txq(mvm, queue, ssn, &cfg);
+}
+
 /* Assoc status */
 bool iwl_mvm_is_idle(struct iwl_mvm *mvm);
 
@@ -1129,6 +1192,7 @@
 void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff);
 void iwl_mvm_tt_exit(struct iwl_mvm *mvm);
 void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);
+int iwl_mvm_get_temp(struct iwl_mvm *mvm);
 
 /* smart fifo */
 int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@@ -1136,7 +1200,17 @@
 
 /* TDLS */
 int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm);
+void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			       bool sta_added);
+void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
+					   struct ieee80211_vif *vif);
 
 void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
+#ifdef CPTCFG_IWLWIFI_DEBUGFS
+void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
+#else
+static inline void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) {}
+#endif
 
 #endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index 1e6a619..f23b8fd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -62,6 +64,7 @@
  *****************************************************************************/
 #include <linux/firmware.h>
 #include "iwl-trans.h"
+#include "iwl-csr.h"
 #include "mvm.h"
 #include "iwl-eeprom-parse.h"
 #include "iwl-eeprom-read.h"
@@ -347,7 +350,7 @@
 	/* Maximal size depends on HW family and step */
 	if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
 		max_section_size = IWL_MAX_NVM_SECTION_SIZE;
-	else if ((mvm->trans->hw_rev & 0xc) == 0) /* Family 8000 A-step */
+	else if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP)
 		max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE;
 	else /* Family 8000 B-step */
 		max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE;
diff --git a/drivers/net/wireless/iwlwifi/mvm/offloading.c b/drivers/net/wireless/iwlwifi/mvm/offloading.c
index 9bfb95e..adcbf4c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/offloading.c
+++ b/drivers/net/wireless/iwlwifi/mvm/offloading.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 07def38..4de8ec8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -330,6 +332,8 @@
 	CMD(BCAST_FILTER_CMD),
 	CMD(REPLY_SF_CFG_CMD),
 	CMD(REPLY_BEACON_FILTERING_CMD),
+	CMD(CMD_DTS_MEASUREMENT_TRIGGER),
+	CMD(DTS_MEASUREMENT_NOTIFICATION),
 	CMD(REPLY_THERMAL_MNG_BACKOFF),
 	CMD(MAC_PM_POWER_TABLE),
 	CMD(BT_COEX_CI),
@@ -338,6 +342,7 @@
 	CMD(BT_COEX_UPDATE_REDUCED_TXP),
 	CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),
 	CMD(ANTENNA_COUPLING_NOTIFICATION),
+	CMD(SCD_QUEUE_CFG),
 };
 #undef CMD
 
@@ -362,6 +367,8 @@
 	return 0;
 }
 
+static void iwl_mvm_fw_error_dump_wk(struct work_struct *work);
+
 static struct iwl_op_mode *
 iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 		      const struct iwl_fw *fw, struct dentry *dbgfs_dir)
@@ -415,6 +422,7 @@
 		mvm->first_agg_queue = 12;
 	}
 	mvm->sf_state = SF_UNINIT;
+	mvm->low_latency_agg_frame_limit = 6;
 
 	mutex_init(&mvm->mutex);
 	mutex_init(&mvm->d0i3_suspend_mutex);
@@ -428,6 +436,7 @@
 	INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
 	INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk);
 	INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
+	INIT_WORK(&mvm->fw_error_dump_wk, iwl_mvm_fw_error_dump_wk);
 
 	spin_lock_init(&mvm->d0i3_tx_lock);
 	spin_lock_init(&mvm->refs_lock);
@@ -456,7 +465,8 @@
 	trans_cfg.command_names = iwl_mvm_cmd_strings;
 
 	trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE;
-	trans_cfg.cmd_fifo = IWL_MVM_CMD_FIFO;
+	trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD;
+	trans_cfg.scd_set_active = true;
 
 	snprintf(mvm->hw->wiphy->fw_version,
 		 sizeof(mvm->hw->wiphy->fw_version),
@@ -494,7 +504,7 @@
 		goto out_free;
 
 	/*
-	 * Even if nvm exists in the nvm_file driver should read agin the nvm
+	 * Even if nvm exists in the nvm_file driver should read again the nvm
 	 * from the nic because there might be entries that exist in the OTP
 	 * and not in the file.
 	 * for nics with no_power_up_nic_in_init: rely completley on nvm_file
@@ -700,14 +710,13 @@
 	if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
 		return;
 
-	if (atomic_inc_return(&mvm->queue_stop_count[mq]) > 1) {
+	if (atomic_inc_return(&mvm->mac80211_queue_stop_count[mq]) > 1) {
 		IWL_DEBUG_TX_QUEUES(mvm,
 				    "queue %d (mac80211 %d) already stopped\n",
 				    queue, mq);
 		return;
 	}
 
-	set_bit(mq, &mvm->transport_queue_stop);
 	ieee80211_stop_queue(mvm->hw, mq);
 }
 
@@ -719,15 +728,13 @@
 	if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
 		return;
 
-	if (atomic_dec_return(&mvm->queue_stop_count[mq]) > 0) {
+	if (atomic_dec_return(&mvm->mac80211_queue_stop_count[mq]) > 0) {
 		IWL_DEBUG_TX_QUEUES(mvm,
-				    "queue %d (mac80211 %d) already awake\n",
+				    "queue %d (mac80211 %d) still stopped\n",
 				    queue, mq);
 		return;
 	}
 
-	clear_bit(mq, &mvm->transport_queue_stop);
-
 	ieee80211_wake_queue(mvm->hw, mq);
 }
 
@@ -781,6 +788,16 @@
 	module_put(THIS_MODULE);
 }
 
+static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)
+{
+	struct iwl_mvm *mvm =
+		container_of(work, struct iwl_mvm, fw_error_dump_wk);
+
+	mutex_lock(&mvm->mutex);
+	iwl_mvm_fw_error_dump(mvm);
+	mutex_unlock(&mvm->mutex);
+}
+
 void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
 {
 	iwl_abort_notification_waits(&mvm->notif_wait);
@@ -846,6 +863,8 @@
 		if (fw_error && mvm->restart_fw > 0)
 			mvm->restart_fw--;
 		ieee80211_restart_hw(mvm->hw);
+	} else if (fw_error) {
+		schedule_work(&mvm->fw_error_dump_wk);
 	}
 }
 
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
index 6cc243f..12283b5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index 8f01295..27db05b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -198,8 +200,15 @@
 		}
 	}
 
-	if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
+	if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
+#ifdef CPTCFG_IWLWIFI_DEBUGFS
+		/* set advanced pm flag with no uapsd ACs to enable ps-poll */
+		if (mvmvif->dbgfs_pm.use_ps_poll)
+			cmd->flags |=
+				cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
+#endif
 		return;
+	}
 
 	cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK);
 
@@ -277,12 +286,28 @@
 	return true;
 }
 
+static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif)
+{
+	struct ieee80211_chanctx_conf *chanctx_conf;
+	struct ieee80211_channel *chan;
+	bool radar_detect = false;
+
+	rcu_read_lock();
+	chanctx_conf = rcu_dereference(vif->chanctx_conf);
+	WARN_ON(!chanctx_conf);
+	if (chanctx_conf) {
+		chan = chanctx_conf->def.chan;
+		radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
+	}
+	rcu_read_unlock();
+
+	return radar_detect;
+}
+
 static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
 				    struct ieee80211_vif *vif,
 				    struct iwl_mac_power_cmd *cmd)
 {
-	struct ieee80211_chanctx_conf *chanctx_conf;
-	struct ieee80211_channel *chan;
 	int dtimper, dtimper_msec;
 	int keep_alive;
 	bool radar_detect = false;
@@ -311,7 +336,7 @@
 	cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
 
 	if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) ||
-	    !mvmvif->pm_enabled)
+	    !mvmvif->pm_enabled || iwl_mvm_tdls_sta_count(mvm, vif))
 		return;
 
 	cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@@ -324,14 +349,7 @@
 	}
 
 	/* Check if radar detection is required on current channel */
-	rcu_read_lock();
-	chanctx_conf = rcu_dereference(vif->chanctx_conf);
-	WARN_ON(!chanctx_conf);
-	if (chanctx_conf) {
-		chan = chanctx_conf->def.chan;
-		radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
-	}
-	rcu_read_unlock();
+	radar_detect = iwl_mvm_power_is_radar(vif);
 
 	/* Check skip over DTIM conditions */
 	if (!radar_detect && (dtimper <= 10) &&
@@ -492,17 +510,33 @@
 	bool bss_active;
 	bool ap_active;
 	bool monitor_active;
-	bool bss_tdls;
-	bool p2p_tdls;
 };
 
-static void iwl_mvm_power_iterator(void *_data, u8 *mac,
-				   struct ieee80211_vif *vif)
+static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac,
+					      struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	mvmvif->pm_enabled = false;
+}
+
+static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8* mac,
+					       struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	bool *disable_ps = _data;
+
+	if (mvmvif->phy_ctxt)
+		if (mvmvif->phy_ctxt->id < MAX_PHYS)
+			*disable_ps |= mvmvif->ps_disabled;
+}
+
+static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
+					    struct ieee80211_vif *vif)
 {
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 	struct iwl_power_vifs *power_iterator = _data;
 
-	mvmvif->pm_enabled = false;
 	switch (ieee80211_vif_type_p2p(vif)) {
 	case NL80211_IFTYPE_P2P_DEVICE:
 		break;
@@ -530,8 +564,6 @@
 		/* only a single MAC of the same type */
 		WARN_ON(power_iterator->p2p_vif);
 		power_iterator->p2p_vif = vif;
-		power_iterator->p2p_tdls =
-			!!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif);
 		if (mvmvif->phy_ctxt)
 			if (mvmvif->phy_ctxt->id < MAX_PHYS)
 				power_iterator->p2p_active = true;
@@ -541,8 +573,6 @@
 		/* only a single MAC of the same type */
 		WARN_ON(power_iterator->bss_vif);
 		power_iterator->bss_vif = vif;
-		power_iterator->bss_tdls =
-			!!iwl_mvm_tdls_sta_count(power_iterator->mvm, vif);
 		if (mvmvif->phy_ctxt)
 			if (mvmvif->phy_ctxt->id < MAX_PHYS)
 				power_iterator->bss_active = true;
@@ -558,9 +588,8 @@
 	}
 }
 
-static void
-iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
-				    struct iwl_power_vifs *vifs)
+static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
+				 struct iwl_power_vifs *vifs)
 {
 	struct iwl_mvm_vif *bss_mvmvif = NULL;
 	struct iwl_mvm_vif *p2p_mvmvif = NULL;
@@ -570,10 +599,11 @@
 
 	lockdep_assert_held(&mvm->mutex);
 
-	/* get vifs info + set pm_enable to false */
+	/* set pm_enable to false */
 	ieee80211_iterate_active_interfaces_atomic(mvm->hw,
-					    IEEE80211_IFACE_ITER_NORMAL,
-					    iwl_mvm_power_iterator, vifs);
+					IEEE80211_IFACE_ITER_NORMAL,
+					iwl_mvm_power_disable_pm_iterator,
+					NULL);
 
 	if (vifs->bss_vif)
 		bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif);
@@ -585,15 +615,13 @@
 		ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif);
 
 	/* enable PM on bss if bss stand alone */
-	if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active &&
-	    !vifs->bss_tdls) {
+	if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) {
 		bss_mvmvif->pm_enabled = true;
 		return;
 	}
 
 	/* enable PM on p2p if p2p stand alone */
-	if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active &&
-	    !vifs->p2p_tdls) {
+	if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) {
 		if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM)
 			p2p_mvmvif->pm_enabled = true;
 		return;
@@ -816,32 +844,92 @@
 	return ret;
 }
 
-int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
+static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm)
+{
+	bool disable_ps;
+	int ret;
+
+	/* disable PS if CAM */
+	disable_ps = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM);
+	/* ...or if any of the vifs require PS to be off */
+	ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+					IEEE80211_IFACE_ITER_NORMAL,
+					iwl_mvm_power_ps_disabled_iterator,
+					&disable_ps);
+
+	/* update device power state if it has changed */
+	if (mvm->ps_disabled != disable_ps) {
+		bool old_ps_disabled = mvm->ps_disabled;
+
+		mvm->ps_disabled = disable_ps;
+		ret = iwl_mvm_power_update_device(mvm);
+		if (ret) {
+			mvm->ps_disabled = old_ps_disabled;
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm,
+				struct iwl_power_vifs *vifs)
 {
 	struct iwl_mvm_vif *mvmvif;
+	bool ba_enable;
+
+	if (!vifs->bf_vif)
+		return 0;
+
+	mvmvif = iwl_mvm_vif_from_mac80211(vifs->bf_vif);
+
+	ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled ||
+		      !vifs->bf_vif->bss_conf.ps ||
+		      iwl_mvm_vif_low_latency(mvmvif));
+
+	return iwl_mvm_update_beacon_abort(mvm, vifs->bf_vif, ba_enable);
+}
+
+int iwl_mvm_power_update_ps(struct iwl_mvm *mvm)
+{
 	struct iwl_power_vifs vifs = {
 		.mvm = mvm,
 	};
-	bool ba_enable;
 	int ret;
 
 	lockdep_assert_held(&mvm->mutex);
 
+	/* get vifs info */
+	ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+					IEEE80211_IFACE_ITER_NORMAL,
+					iwl_mvm_power_get_vifs_iterator, &vifs);
+
+	ret = iwl_mvm_power_set_ps(mvm);
+	if (ret)
+		return ret;
+
+	return iwl_mvm_power_set_ba(mvm, &vifs);
+}
+
+int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
+{
+	struct iwl_power_vifs vifs = {
+		.mvm = mvm,
+	};
+	int ret;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	/* get vifs info */
+	ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+					IEEE80211_IFACE_ITER_NORMAL,
+					iwl_mvm_power_get_vifs_iterator, &vifs);
+
 	iwl_mvm_power_set_pm(mvm, &vifs);
 
-	/* disable PS if CAM */
-	if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) {
-		mvm->ps_disabled = true;
-	} else {
-	/* don't update device power state unless we add / remove monitor */
-		if (vifs.monitor_vif) {
-			if (vifs.monitor_active)
-				mvm->ps_disabled = true;
-			ret = iwl_mvm_power_update_device(mvm);
-			if (ret)
-				return ret;
-		}
-	}
+	ret = iwl_mvm_power_set_ps(mvm);
+	if (ret)
+		return ret;
 
 	if (vifs.bss_vif) {
 		ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif);
@@ -855,16 +943,7 @@
 			return ret;
 	}
 
-	if (!vifs.bf_vif)
-		return 0;
-
-	mvmvif = iwl_mvm_vif_from_mac80211(vifs.bf_vif);
-
-	ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled ||
-		      !vifs.bf_vif->bss_conf.ps ||
-		      iwl_mvm_vif_low_latency(mvmvif));
-
-	return iwl_mvm_update_beacon_abort(mvm, vifs.bf_vif, ba_enable);
+	return iwl_mvm_power_set_ba(mvm, &vifs);
 }
 
 int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
@@ -883,17 +962,22 @@
 
 	iwl_mvm_power_build_cmd(mvm, vif, &cmd);
 	if (enable) {
-		/* configure skip over dtim up to 300 msec */
+		/* configure skip over dtim up to 306TU - 314 msec */
 		int dtimper = vif->bss_conf.dtim_period ?: 1;
-		int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
+		int dtimper_tu = dtimper * vif->bss_conf.beacon_int;
+		bool radar_detect = iwl_mvm_power_is_radar(vif);
 
-		if (WARN_ON(!dtimper_msec))
+		if (WARN_ON(!dtimper_tu))
 			return 0;
 
-		cmd.skip_dtim_periods = 300 / dtimper_msec;
-		if (cmd.skip_dtim_periods)
-			cmd.flags |=
-				cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
+		/* Check skip over DTIM conditions */
+		/* TODO: check that multicast wake lock is off */
+		if (!radar_detect && (dtimper < 10)) {
+			cmd.skip_dtim_periods = 306 / dtimper_tu;
+			if (cmd.skip_dtim_periods)
+				cmd.flags |= cpu_to_le16(
+					POWER_FLAGS_SKIP_OVER_DTIM_MSK);
+		}
 	}
 	iwl_mvm_power_log(mvm, &cmd);
 #ifdef CPTCFG_IWLWIFI_DEBUGFS
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c
index 173a568..f392b35 100644
--- a/drivers/net/wireless/iwlwifi/mvm/quota.c
+++ b/drivers/net/wireless/iwlwifi/mvm/quota.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -161,6 +163,9 @@
 		quota *= (beacon_int - mvm->noa_duration);
 		quota /= beacon_int;
 
+		IWL_DEBUG_QUOTA(mvm, "quota: adjust for NoA from %d to %d\n",
+				le32_to_cpu(cmd->quotas[i].quota), quota);
+
 		cmd->quotas[i].quota = cpu_to_le32(quota);
 	}
 #endif
@@ -170,12 +175,14 @@
 			  struct ieee80211_vif *disabled_vif)
 {
 	struct iwl_time_quota_cmd cmd = {};
-	int i, idx, ret, num_active_macs, quota, quota_rem, n_non_lowlat;
+	int i, idx, err, num_active_macs, quota, quota_rem, n_non_lowlat;
 	struct iwl_mvm_quota_iterator_data data = {
 		.n_interfaces = {},
 		.colors = { -1, -1, -1, -1 },
 		.disabled_vif = disabled_vif,
 	};
+	struct iwl_time_quota_cmd *last = &mvm->last_quota_cmd;
+	bool send = false;
 
 	lockdep_assert_held(&mvm->mutex);
 
@@ -222,6 +229,9 @@
 		quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat;
 		quota_rem = QUOTA_100 - n_non_lowlat * quota -
 			    QUOTA_LOWLAT_MIN;
+		IWL_DEBUG_QUOTA(mvm,
+				"quota: low-latency binding active, remaining quota per other binding: %d\n",
+				quota);
 	} else if (num_active_macs) {
 		/*
 		 * There are 0 or more than 1 low latency bindings, or all the
@@ -230,6 +240,9 @@
 		 */
 		quota = QUOTA_100 / num_active_macs;
 		quota_rem = QUOTA_100 % num_active_macs;
+		IWL_DEBUG_QUOTA(mvm,
+				"quota: splitting evenly per binding: %d\n",
+				quota);
 	} else {
 		/* values don't really matter - won't be used */
 		quota = 0;
@@ -271,6 +284,9 @@
 	for (i = 0; i < MAX_BINDINGS; i++) {
 		if (le32_to_cpu(cmd.quotas[i].quota) != 0) {
 			le32_add_cpu(&cmd.quotas[i].quota, quota_rem);
+			IWL_DEBUG_QUOTA(mvm,
+					"quota: giving remainder of %d to binding %d\n",
+					quota_rem, i);
 			break;
 		}
 	}
@@ -279,15 +295,33 @@
 
 	/* check that we have non-zero quota for all valid bindings */
 	for (i = 0; i < MAX_BINDINGS; i++) {
+		if (cmd.quotas[i].id_and_color != last->quotas[i].id_and_color)
+			send = true;
+		if (cmd.quotas[i].max_duration != last->quotas[i].max_duration)
+			send = true;
+		if (abs((int)le32_to_cpu(cmd.quotas[i].quota) -
+			(int)le32_to_cpu(last->quotas[i].quota))
+						> IWL_MVM_QUOTA_THRESHOLD)
+			send = true;
 		if (cmd.quotas[i].id_and_color == cpu_to_le32(FW_CTXT_INVALID))
 			continue;
 		WARN_ONCE(cmd.quotas[i].quota == 0,
 			  "zero quota on binding %d\n", i);
 	}
 
-	ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0,
-				   sizeof(cmd), &cmd);
-	if (ret)
-		IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
-	return ret;
+	if (!send) {
+		/* don't send a practically unchanged command, the firmware has
+		 * to re-initialize a lot of state and that can have an adverse
+		 * impact on it
+		 */
+		return 0;
+	}
+
+	err = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd);
+
+	if (err)
+		IWL_ERR(mvm, "Failed to send quota: %d\n", err);
+	else
+		mvm->last_quota_cmd = cmd;
+	return err;
 }
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index c230eb2..287e744 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -1,6 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -376,9 +377,9 @@
 }
 
 static void rs_rate_scale_perform(struct iwl_mvm *mvm,
-				   struct sk_buff *skb,
-				   struct ieee80211_sta *sta,
-				   struct iwl_lq_sta *lq_sta);
+				  struct ieee80211_sta *sta,
+				  struct iwl_lq_sta *lq_sta,
+				  int tid);
 static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
 			   struct ieee80211_sta *sta,
 			   struct iwl_lq_sta *lq_sta,
@@ -504,10 +505,10 @@
 static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate,
 				const char *prefix)
 {
-	IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d\n",
+	IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d\n",
 		       prefix, rs_pretty_lq_type(rate->type),
 		       rate->index, rs_pretty_ant(rate->ant),
-		       rate->bw, rate->sgi);
+		       rate->bw, rate->sgi, rate->ldpc);
 }
 
 static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
@@ -671,8 +672,10 @@
 		return -EINVAL;
 
 	if (tbl->column != RS_COLUMN_INVALID) {
-		lq_sta->tx_stats[tbl->column][scale_index].total += attempts;
-		lq_sta->tx_stats[tbl->column][scale_index].success += successes;
+		struct lq_sta_pers *pers = &lq_sta->pers;
+
+		pers->tx_stats[tbl->column][scale_index].total += attempts;
+		pers->tx_stats[tbl->column][scale_index].success += successes;
 	}
 
 	/* Select window for current tx bit rate */
@@ -741,6 +744,8 @@
 	ucode_rate |= rate->bw;
 	if (rate->sgi)
 		ucode_rate |= RATE_MCS_SGI_MSK;
+	if (rate->ldpc)
+		ucode_rate |= RATE_MCS_LDPC_MSK;
 
 	return ucode_rate;
 }
@@ -778,6 +783,8 @@
 	/* HT or VHT */
 	if (ucode_rate & RATE_MCS_SGI_MSK)
 		rate->sgi = true;
+	if (ucode_rate & RATE_MCS_LDPC_MSK)
+		rate->ldpc = true;
 
 	rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK;
 
@@ -964,13 +971,13 @@
 			     rate->index > IWL_RATE_MCS_9_INDEX);
 
 		rate->index = rs_ht_to_legacy[rate->index];
+		rate->ldpc = false;
 	} else {
 		/* Downgrade to SISO with same MCS if in MIMO  */
 		rate->type = is_vht_mimo2(rate) ?
 			LQ_VHT_SISO : LQ_HT_SISO;
 	}
 
-
 	if (num_of_ant(rate->ant) > 1)
 		rate->ant = first_antenna(mvm->fw->valid_tx_ant);
 
@@ -1000,27 +1007,35 @@
 	return RATE_MCS_CHAN_WIDTH_20;
 }
 
-/*
- * mac80211 sends us Tx status
- */
-static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
-			 struct ieee80211_sta *sta, void *priv_sta,
-			 struct sk_buff *skb)
+static u8 rs_get_tid(struct ieee80211_hdr *hdr)
+{
+	u8 tid = IWL_MAX_TID_COUNT;
+
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
+		u8 *qc = ieee80211_get_qos_ctl(hdr);
+		tid = qc[0] & 0xf;
+	}
+
+	if (unlikely(tid > IWL_MAX_TID_COUNT))
+		tid = IWL_MAX_TID_COUNT;
+
+	return tid;
+}
+
+void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+			  int tid, struct ieee80211_tx_info *info)
 {
 	int legacy_success;
 	int retries;
 	int mac_index, i;
-	struct iwl_lq_sta *lq_sta = priv_sta;
 	struct iwl_lq_cmd *table;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_r;
-	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	enum mac80211_rate_control_flags mac_flags;
 	u32 ucode_rate;
 	struct rs_rate rate;
 	struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
 	u8 reduced_txp = (uintptr_t)info->status.status_driver_data[0];
+	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+	struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta;
 
 	/* Treat uninitialized rate scaling data same as non-existing. */
 	if (!lq_sta) {
@@ -1038,10 +1053,6 @@
 		return;
 	}
 #endif
-	if (!ieee80211_is_data(hdr->frame_control) ||
-	    info->flags & IEEE80211_TX_CTL_NO_ACK)
-		return;
-
 	/* This packet was aggregated but doesn't carry status info */
 	if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
 	    !(info->flags & IEEE80211_TX_STAT_AMPDU))
@@ -1087,7 +1098,7 @@
 		for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
 			ieee80211_stop_tx_ba_session(sta, tid);
 
-		iwl_mvm_rs_rate_init(mvm, sta, sband->band, false);
+		iwl_mvm_rs_rate_init(mvm, sta, info->band, false);
 		return;
 	}
 	lq_sta->last_tx = jiffies;
@@ -1214,8 +1225,28 @@
 	IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
 done:
 	/* See if there's a better rate or modulation mode to try. */
-	if (sta && sta->supp_rates[sband->band])
-		rs_rate_scale_perform(mvm, skb, sta, lq_sta);
+	if (sta && sta->supp_rates[info->band])
+		rs_rate_scale_perform(mvm, sta, lq_sta, tid);
+}
+
+/*
+ * mac80211 sends us Tx status
+ */
+static void rs_mac80211_tx_status(void *mvm_r,
+				  struct ieee80211_supported_band *sband,
+				  struct ieee80211_sta *sta, void *priv_sta,
+				  struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_r;
+	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+	if (!ieee80211_is_data(hdr->frame_control) ||
+	    info->flags & IEEE80211_TX_CTL_NO_ACK)
+		return;
+
+	iwl_mvm_rs_tx_status(mvm, sta, rs_get_tid(hdr), info);
 }
 
 /*
@@ -1486,22 +1517,6 @@
 	iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
 }
 
-static u8 rs_get_tid(struct iwl_lq_sta *lq_data,
-		     struct ieee80211_hdr *hdr)
-{
-	u8 tid = IWL_MAX_TID_COUNT;
-
-	if (ieee80211_is_data_qos(hdr->frame_control)) {
-		u8 *qc = ieee80211_get_qos_ctl(hdr);
-		tid = qc[0] & 0xf;
-	}
-
-	if (unlikely(tid > IWL_MAX_TID_COUNT))
-		tid = IWL_MAX_TID_COUNT;
-
-	return tid;
-}
-
 static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
 					 struct iwl_lq_sta *lq_sta,
 					 struct ieee80211_sta *sta,
@@ -1620,6 +1635,7 @@
 	}
 
 	rate->bw = rs_bw_from_sta_bw(sta);
+	rate->ldpc = lq_sta->ldpc;
 	search_tbl->column = col_id;
 	rs_set_expected_tpt_table(lq_sta, search_tbl);
 
@@ -1939,12 +1955,10 @@
  * Do rate scaling and search for new modulation mode.
  */
 static void rs_rate_scale_perform(struct iwl_mvm *mvm,
-				  struct sk_buff *skb,
 				  struct ieee80211_sta *sta,
-				  struct iwl_lq_sta *lq_sta)
+				  struct iwl_lq_sta *lq_sta,
+				  int tid)
 {
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	int low = IWL_RATE_INVALID;
 	int high = IWL_RATE_INVALID;
 	int index;
@@ -1961,29 +1975,12 @@
 	u8 done_search = 0;
 	u16 high_low;
 	s32 sr;
-	u8 tid = IWL_MAX_TID_COUNT;
 	u8 prev_agg = lq_sta->is_agg;
 	struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
 	struct iwl_mvm_tid_data *tid_data;
 	struct rs_rate *rate;
 
-	/* Send management frames and NO_ACK data using lowest rate. */
-	/* TODO: this could probably be improved.. */
-	if (!ieee80211_is_data(hdr->frame_control) ||
-	    info->flags & IEEE80211_TX_CTL_NO_ACK)
-		return;
-
-	tid = rs_get_tid(lq_sta, hdr);
-	if ((tid != IWL_MAX_TID_COUNT) &&
-	    (lq_sta->tx_agg_tid_en & (1 << tid))) {
-		tid_data = &sta_priv->tid_data[tid];
-		if (tid_data->state == IWL_AGG_OFF)
-			lq_sta->is_agg = 0;
-		else
-			lq_sta->is_agg = 1;
-	} else {
-		lq_sta->is_agg = 0;
-	}
+	lq_sta->is_agg = !!sta_priv->agg_tids;
 
 	/*
 	 * Select rate-scale / modulation-mode table to work with in
@@ -2030,18 +2027,7 @@
 		return;
 	}
 
-	/* force user max rate if set by user */
-	if ((lq_sta->max_rate_idx != -1) &&
-	    (lq_sta->max_rate_idx < index)) {
-		index = lq_sta->max_rate_idx;
-		update_lq = 1;
-		window = &(tbl->win[index]);
-		IWL_DEBUG_RATE(mvm,
-			       "Forcing user max rate %d\n",
-			       index);
-		goto lq_update;
-	}
-
+	/* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
 	window = &(tbl->win[index]);
 
 	/*
@@ -2129,10 +2115,7 @@
 	low = high_low & 0xff;
 	high = (high_low >> 8) & 0xff;
 
-	/* If user set max rate, dont allow higher than user constrain */
-	if ((lq_sta->max_rate_idx != -1) &&
-	    (lq_sta->max_rate_idx < high))
-		high = IWL_RATE_INVALID;
+	/* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
 
 	sr = window->success_ratio;
 
@@ -2294,6 +2277,110 @@
 	lq_sta->last_txrate_idx = index;
 }
 
+struct rs_init_rate_info {
+	s8 rssi;
+	u8 rate_idx;
+};
+
+static const struct rs_init_rate_info rs_init_rates_24ghz[] = {
+	{ -60, IWL_RATE_54M_INDEX },
+	{ -64, IWL_RATE_48M_INDEX },
+	{ -68, IWL_RATE_36M_INDEX },
+	{ -80, IWL_RATE_24M_INDEX },
+	{ -84, IWL_RATE_18M_INDEX },
+	{ -85, IWL_RATE_12M_INDEX },
+	{ -86, IWL_RATE_11M_INDEX },
+	{ -88, IWL_RATE_5M_INDEX  },
+	{ -90, IWL_RATE_2M_INDEX  },
+	{ S8_MIN, IWL_RATE_1M_INDEX },
+};
+
+static const struct rs_init_rate_info rs_init_rates_5ghz[] = {
+	{ -60, IWL_RATE_54M_INDEX },
+	{ -64, IWL_RATE_48M_INDEX },
+	{ -72, IWL_RATE_36M_INDEX },
+	{ -80, IWL_RATE_24M_INDEX },
+	{ -84, IWL_RATE_18M_INDEX },
+	{ -85, IWL_RATE_12M_INDEX },
+	{ -87, IWL_RATE_9M_INDEX  },
+	{ S8_MIN, IWL_RATE_6M_INDEX },
+};
+
+/* Choose an initial legacy rate and antenna to use based on the RSSI
+ * of last Rx
+ */
+static void rs_get_initial_rate(struct iwl_mvm *mvm,
+				struct iwl_lq_sta *lq_sta,
+				enum ieee80211_band band,
+				struct rs_rate *rate)
+{
+	int i, nentries;
+	s8 best_rssi = S8_MIN;
+	u8 best_ant = ANT_NONE;
+	u8 valid_tx_ant = mvm->fw->valid_tx_ant;
+	const struct rs_init_rate_info *initial_rates;
+
+	for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) {
+		if (!(lq_sta->pers.chains & BIT(i)))
+			continue;
+
+		if (lq_sta->pers.chain_signal[i] > best_rssi) {
+			best_rssi = lq_sta->pers.chain_signal[i];
+			best_ant = BIT(i);
+		}
+	}
+
+	IWL_DEBUG_RATE(mvm, "Best ANT: %s Best RSSI: %d\n",
+		       rs_pretty_ant(best_ant), best_rssi);
+
+	if (best_ant != ANT_A && best_ant != ANT_B)
+		rate->ant = first_antenna(valid_tx_ant);
+	else
+		rate->ant = best_ant;
+
+	rate->sgi = false;
+	rate->ldpc = false;
+	rate->bw = RATE_MCS_CHAN_WIDTH_20;
+
+	rate->index = find_first_bit(&lq_sta->active_legacy_rate,
+				     BITS_PER_LONG);
+
+	if (band == IEEE80211_BAND_5GHZ) {
+		rate->type = LQ_LEGACY_A;
+		initial_rates = rs_init_rates_5ghz;
+		nentries = ARRAY_SIZE(rs_init_rates_5ghz);
+	} else {
+		rate->type = LQ_LEGACY_G;
+		initial_rates = rs_init_rates_24ghz;
+		nentries = ARRAY_SIZE(rs_init_rates_24ghz);
+	}
+
+	if (IWL_MVM_RS_RSSI_BASED_INIT_RATE) {
+		for (i = 0; i < nentries; i++) {
+			int rate_idx = initial_rates[i].rate_idx;
+			if ((best_rssi >= initial_rates[i].rssi) &&
+			    (BIT(rate_idx) & lq_sta->active_legacy_rate)) {
+				rate->index = rate_idx;
+				break;
+			}
+		}
+	}
+
+	IWL_DEBUG_RATE(mvm, "rate_idx %d ANT %s\n", rate->index,
+		       rs_pretty_ant(rate->ant));
+}
+
+/* Save info about RSSI of last Rx */
+void rs_update_last_rssi(struct iwl_mvm *mvm,
+			 struct iwl_lq_sta *lq_sta,
+			 struct ieee80211_rx_status *rx_status)
+{
+	lq_sta->pers.chains = rx_status->chains;
+	lq_sta->pers.chain_signal[0] = rx_status->chain_signal[0];
+	lq_sta->pers.chain_signal[1] = rx_status->chain_signal[1];
+	lq_sta->pers.chain_signal[2] = rx_status->chain_signal[2];
+}
+
 /**
  * rs_initialize_lq - Initialize a station's hardware rate table
  *
@@ -2316,17 +2403,11 @@
 {
 	struct iwl_scale_tbl_info *tbl;
 	struct rs_rate *rate;
-	int i;
 	u8 active_tbl = 0;
-	u8 valid_tx_ant;
 
 	if (!sta || !lq_sta)
 		return;
 
-	i = lq_sta->last_txrate_idx;
-
-	valid_tx_ant = mvm->fw->valid_tx_ant;
-
 	if (!lq_sta->search_better_tbl)
 		active_tbl = lq_sta->active_tbl;
 	else
@@ -2335,17 +2416,8 @@
 	tbl = &(lq_sta->lq_info[active_tbl]);
 	rate = &tbl->rate;
 
-	if ((i < 0) || (i >= IWL_RATE_COUNT))
-		i = 0;
-
-	rate->index = i;
-	rate->ant = first_antenna(valid_tx_ant);
-	rate->sgi = false;
-	rate->bw = RATE_MCS_CHAN_WIDTH_20;
-	if (band == IEEE80211_BAND_5GHZ)
-		rate->type = LQ_LEGACY_A;
-	else
-		rate->type = LQ_LEGACY_G;
+	rs_get_initial_rate(mvm, lq_sta, band, rate);
+	lq_sta->last_txrate_idx = rate->index;
 
 	WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B);
 	if (rate->ant == ANT_A)
@@ -2363,23 +2435,13 @@
 			struct ieee80211_tx_rate_control *txrc)
 {
 	struct sk_buff *skb = txrc->skb;
-	struct ieee80211_supported_band *sband = txrc->sband;
 	struct iwl_op_mode *op_mode __maybe_unused =
 			(struct iwl_op_mode *)mvm_r;
 	struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct iwl_lq_sta *lq_sta = mvm_sta;
 
-	/* Get max rate if user set max rate */
-	if (lq_sta) {
-		lq_sta->max_rate_idx = txrc->max_rate_idx;
-		if ((sband->band == IEEE80211_BAND_5GHZ) &&
-		    (lq_sta->max_rate_idx != -1))
-			lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE;
-		if ((lq_sta->max_rate_idx < 0) ||
-		    (lq_sta->max_rate_idx >= IWL_RATE_COUNT))
-			lq_sta->max_rate_idx = -1;
-	}
+	/* TODO: handle rate_idx_mask and rate_idx_mcs_mask */
 
 	/* Treat uninitialized rate scaling data same as non-existing. */
 	if (lq_sta && !lq_sta->pers.drv) {
@@ -2412,6 +2474,8 @@
 	lq_sta->pers.dbg_fixed_rate = 0;
 	lq_sta->pers.dbg_fixed_txp_reduction = TPC_INVALID;
 #endif
+	lq_sta->pers.chains = 0;
+	memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal));
 
 	return &sta_priv->lq_sta;
 }
@@ -2580,7 +2644,6 @@
 	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
 	 * after assoc.. */
 
-	lq_sta->max_rate_idx = -1;
 	lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
 	lq_sta->band = sband->band;
 	/*
@@ -2609,9 +2672,16 @@
 		lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
 
 		lq_sta->is_vht = false;
+		if (mvm->cfg->ht_params->ldpc &&
+		    (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
+			lq_sta->ldpc = true;
 	} else {
 		rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
 		lq_sta->is_vht = true;
+
+		if (mvm->cfg->ht_params->ldpc &&
+		    (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
+			lq_sta->ldpc = true;
 	}
 
 	lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate,
@@ -2621,11 +2691,12 @@
 	lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate,
 						   BITS_PER_LONG);
 
-	IWL_DEBUG_RATE(mvm, "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d\n",
+	IWL_DEBUG_RATE(mvm,
+		       "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d\n",
 		       lq_sta->active_legacy_rate,
 		       lq_sta->active_siso_rate,
 		       lq_sta->active_mimo2_rate,
-		       lq_sta->is_vht);
+		       lq_sta->is_vht, lq_sta->ldpc);
 	IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
 		       lq_sta->max_legacy_rate_idx,
 		       lq_sta->max_siso_rate_idx,
@@ -2638,11 +2709,6 @@
 
 	/* as default allow aggregation for all tids */
 	lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
-
-	/* Set last_txrate_idx to lowest rate */
-	lq_sta->last_txrate_idx = rate_lowest_index(sband, sta);
-	if (sband->band == IEEE80211_BAND_5GHZ)
-		lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
 	lq_sta->is_agg = 0;
 #ifdef CPTCFG_IWLWIFI_DEBUGFS
 	iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats);
@@ -2678,6 +2744,7 @@
 	int i;
 	int num_rates = ARRAY_SIZE(lq_cmd->rs_table);
 	__le32 ucode_rate_le32 = cpu_to_le32(ucode_rate);
+	u8 ant = (ucode_rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS;
 
 	for (i = 0; i < num_rates; i++)
 		lq_cmd->rs_table[i] = ucode_rate_le32;
@@ -2688,6 +2755,13 @@
 		lq_cmd->mimo_delim = num_rates - 1;
 	else
 		lq_cmd->mimo_delim = 0;
+
+	lq_cmd->reduced_tpc = 0;
+
+	if (num_of_ant(ant) == 1)
+		lq_cmd->single_stream_ant_msk = ant;
+
+	lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
 }
 #endif /* CPTCFG_MAC80211_DEBUGFS */
 
@@ -2811,31 +2885,55 @@
 			   const struct rs_rate *initial_rate)
 {
 	struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
-	u8 ant = initial_rate->ant;
+	struct iwl_mvm_sta *mvmsta;
+	struct iwl_mvm_vif *mvmvif;
+
+	lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+	lq_cmd->agg_time_limit =
+		cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
 
 #ifdef CPTCFG_MAC80211_DEBUGFS
 	if (lq_sta->pers.dbg_fixed_rate) {
 		rs_build_rates_table_from_fixed(mvm, lq_cmd,
 						lq_sta->band,
 						lq_sta->pers.dbg_fixed_rate);
-		lq_cmd->reduced_tpc = 0;
-		ant = (lq_sta->pers.dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) >>
-			RATE_MCS_ANT_POS;
-	} else
+		return;
+	}
 #endif
-		rs_build_rates_table(mvm, lq_sta, initial_rate);
+	if (WARN_ON_ONCE(!sta || !initial_rate))
+		return;
 
-	if (num_of_ant(ant) == 1)
-		lq_cmd->single_stream_ant_msk = ant;
+	rs_build_rates_table(mvm, lq_sta, initial_rate);
 
-	lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-	lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+	if (num_of_ant(initial_rate->ant) == 1)
+		lq_cmd->single_stream_ant_msk = initial_rate->ant;
+
+	mvmsta = iwl_mvm_sta_from_mac80211(sta);
+	mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
+
+	if (num_of_ant(initial_rate->ant) == 1)
+		lq_cmd->single_stream_ant_msk = initial_rate->ant;
+
+	lq_cmd->agg_frame_cnt_limit = mvmsta->max_agg_bufsize;
+
+	/*
+	 * In case of low latency, tell the firwmare to leave a frame in the
+	 * Tx Fifo so that it can start a transaction in the same TxOP. This
+	 * basically allows the firmware to send bursts.
+	 */
+	if (iwl_mvm_vif_low_latency(mvmvif)) {
+		lq_cmd->agg_frame_cnt_limit--;
+
+		if (mvm->low_latency_agg_frame_limit)
+			lq_cmd->agg_frame_cnt_limit =
+				min(lq_cmd->agg_frame_cnt_limit,
+				    mvm->low_latency_agg_frame_limit);
+	}
+
+	if (mvmsta->vif->p2p)
+		lq_cmd->flags |= LQ_FLAG_USE_RTS_MSK;
 
 	lq_cmd->agg_time_limit =
-		cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
-
-	if (sta)
-		lq_cmd->agg_time_limit =
 			cpu_to_le16(iwl_mvm_coex_agg_time_limit(mvm, sta));
 }
 
@@ -2932,10 +3030,7 @@
 		       lq_sta->lq.sta_id, lq_sta->pers.dbg_fixed_rate);
 
 	if (lq_sta->pers.dbg_fixed_rate) {
-		struct rs_rate rate;
-		rs_rate_from_ucode_rate(lq_sta->pers.dbg_fixed_rate,
-					lq_sta->band, &rate);
-		rs_fill_lq_cmd(mvm, NULL, lq_sta, &rate);
+		rs_fill_lq_cmd(mvm, NULL, lq_sta, NULL);
 		iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq, false);
 	}
 }
@@ -3002,8 +3097,9 @@
 				   (is_ht20(rate)) ? "20MHz" :
 				   (is_ht40(rate)) ? "40MHz" :
 				   (is_ht80(rate)) ? "80Mhz" : "BAD BW");
-		   desc += sprintf(buff+desc, " %s %s\n",
+		   desc += sprintf(buff+desc, " %s %s %s\n",
 				   (rate->sgi) ? "SGI" : "NGI",
+				   (rate->ldpc) ? "LDPC" : "BCC",
 				   (lq_sta->is_agg) ? "AGG on" : "");
 	}
 	desc += sprintf(buff+desc, "last tx rate=0x%X\n",
@@ -3151,7 +3247,7 @@
 				 "%s,", column_name[col]);
 
 		for (rate = 0; rate < IWL_RATE_COUNT; rate++) {
-			stats = &(lq_sta->tx_stats[col][rate]);
+			stats = &(lq_sta->pers.tx_stats[col][rate]);
 			pos += scnprintf(pos, endpos - pos,
 					 "%llu/%llu,",
 					 stats->success,
@@ -3170,7 +3266,7 @@
 					       size_t count, loff_t *ppos)
 {
 	struct iwl_lq_sta *lq_sta = file->private_data;
-	memset(lq_sta->tx_stats, 0, sizeof(lq_sta->tx_stats));
+	memset(lq_sta->pers.tx_stats, 0, sizeof(lq_sta->pers.tx_stats));
 
 	return count;
 }
@@ -3216,7 +3312,7 @@
 
 static const struct rate_control_ops rs_mvm_ops = {
 	.name = RS_NAME,
-	.tx_status = rs_tx_status,
+	.tx_status = rs_mac80211_tx_status,
 	.get_rate = rs_get_rate,
 	.rate_init = rs_rate_init_stub,
 	.alloc = rs_alloc,
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index 366872e..bcb4b1d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -207,6 +207,7 @@
 	u8 ant;
 	u32 bw;
 	bool sgi;
+	bool ldpc;
 };
 
 
@@ -329,10 +330,9 @@
 				 */
 	u64 last_tx;
 	bool is_vht;
+	bool ldpc;              /* LDPC Rx is supported by the STA */
 	enum ieee80211_band band;
 
-	struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT];
-
 	/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
 	unsigned long active_legacy_rate;
 	unsigned long active_siso_rate;
@@ -343,7 +343,6 @@
 	u8 max_siso_rate_idx;
 	u8 max_mimo2_rate_idx;
 
-	s8 max_rate_idx;     /* Max rate set by user */
 	u8 missed_rate_counter;
 
 	struct iwl_lq_cmd lq;
@@ -361,11 +360,14 @@
 	int tpc_reduce;
 
 	/* persistent fields - initialized only once - keep last! */
-	struct {
+	struct lq_sta_pers {
 #ifdef CPTCFG_MAC80211_DEBUGFS
 		u32 dbg_fixed_rate;
 		u8 dbg_fixed_txp_reduction;
 #endif
+		u8 chains;
+		s8 chain_signal[IEEE80211_MAX_CHAINS];
+		struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT];
 		struct iwl_mvm *drv;
 	} pers;
 };
@@ -374,6 +376,10 @@
 void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 			  enum ieee80211_band band, bool init);
 
+/* Notify RS about Tx status */
+void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+			  int tid, struct ieee80211_tx_info *info);
+
 /**
  * iwl_rate_control_register - Register the rate control algorithm callbacks
  *
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index adaed34..e61514b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -244,6 +246,7 @@
 	struct iwl_rx_packet *pkt = rxb_addr(rxb);
 	struct iwl_rx_phy_info *phy_info;
 	struct iwl_rx_mpdu_res_start *rx_res;
+	struct ieee80211_sta *sta;
 	u32 len;
 	u32 ampdu_status;
 	u32 rate_n_flags;
@@ -259,23 +262,6 @@
 	memset(&rx_status, 0, sizeof(rx_status));
 
 	/*
-	 * We have tx blocked stations (with CS bit). If we heard frames from
-	 * a blocked station on a new channel we can TX to it again.
-	 */
-	if (unlikely(mvm->csa_tx_block_bcn_timeout)) {
-		struct ieee80211_sta *sta;
-
-		rcu_read_lock();
-
-		sta = ieee80211_find_sta(
-			rcu_dereference(mvm->csa_tx_blocked_vif), hdr->addr2);
-		if (sta)
-			iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
-
-		rcu_read_unlock();
-	}
-
-	/*
 	 * drop the packet if it has failed being decrypted by HW
 	 */
 	if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, &rx_status, rx_pkt_status)) {
@@ -323,6 +309,29 @@
 	IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal,
 			      (unsigned long long)rx_status.mactime);
 
+	rcu_read_lock();
+	/*
+	 * We have tx blocked stations (with CS bit). If we heard frames from
+	 * a blocked station on a new channel we can TX to it again.
+	 */
+	if (unlikely(mvm->csa_tx_block_bcn_timeout)) {
+		sta = ieee80211_find_sta(
+			rcu_dereference(mvm->csa_tx_blocked_vif), hdr->addr2);
+		if (sta)
+			iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
+	}
+
+	/* This is fine since we don't support multiple AP interfaces */
+	sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL);
+	if (sta) {
+		struct iwl_mvm_sta *mvmsta;
+		mvmsta = iwl_mvm_sta_from_mac80211(sta);
+		rs_update_last_rssi(mvm, &mvmsta->lq_sta,
+				    &rx_status);
+	}
+
+	rcu_read_unlock();
+
 	/* set the preamble flag if appropriate */
 	if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE))
 		rx_status.flag |= RX_FLAG_SHORTPRE;
@@ -491,10 +500,29 @@
 		.mvm = mvm,
 	};
 
+	/*
+	 * set temperature debug enabled - ignore FW temperature updates
+	 * and use the user set temperature.
+	 */
+	if (mvm->temperature_test) {
+		if (mvm->temperature < le32_to_cpu(common->temperature))
+			IWL_DEBUG_TEMP(mvm,
+				       "Ignoring FW temperature update that is greater than the debug set temperature (debug temp = %d, fw temp = %d)\n",
+				       mvm->temperature,
+				       le32_to_cpu(common->temperature));
+		/*
+		 * skip iwl_mvm_tt_handler since we are in
+		 * temperature debug mode and we are ignoring
+		 * the new temperature value
+		 */
+		goto update;
+	}
+
 	if (mvm->temperature != le32_to_cpu(common->temperature)) {
 		mvm->temperature = le32_to_cpu(common->temperature);
 		iwl_mvm_tt_handler(mvm);
 	}
+update:
 	iwl_mvm_update_rx_statistics(mvm, stats);
 
 	ieee80211_iterate_active_interfaces(mvm->hw,
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 004b1f5..cb85e63 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -158,8 +160,8 @@
 static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
 {
 	if (band == IEEE80211_BAND_2GHZ)
-		return 30  + 3 * (n_ssids + 1);
-	return 20  + 2 * (n_ssids + 1);
+		return 20  + 3 * (n_ssids + 1);
+	return 10  + 2 * (n_ssids + 1);
 }
 
 static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band)
@@ -279,6 +281,7 @@
 {
 	bool global_bound = false;
 	enum ieee80211_band band;
+	u8 frag_passive_dwell = 0;
 
 	ieee80211_iterate_active_interfaces_atomic(mvm->hw,
 					    IEEE80211_IFACE_ITER_NORMAL,
@@ -288,12 +291,36 @@
 	if (!global_bound)
 		goto not_bound;
 
-	params->suspend_time = 100;
-	params->max_out_time = 600;
+	params->suspend_time = 30;
+	params->max_out_time = 170;
 
 	if (iwl_mvm_low_latency(mvm)) {
-		params->suspend_time = 250;
-		params->max_out_time = 250;
+		if (mvm->fw->ucode_capa.api[0] &
+		    IWL_UCODE_TLV_API_FRAGMENTED_SCAN) {
+			params->suspend_time = 105;
+			params->max_out_time = 70;
+			frag_passive_dwell = 20;
+		} else {
+			params->suspend_time = 120;
+			params->max_out_time = 120;
+		}
+	}
+
+	if (frag_passive_dwell && (mvm->fw->ucode_capa.api[0] &
+				   IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) {
+		/*
+		 * P2P device scan should not be fragmented to avoid negative
+		 * impact on P2P device discovery. Configure max_out_time to be
+		 * equal to dwell time on passive channel. Take a longest
+		 * possible value, one that corresponds to 2GHz band
+		 */
+		if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+			u32 passive_dwell =
+				iwl_mvm_get_passive_dwell(IEEE80211_BAND_2GHZ);
+			params->max_out_time = passive_dwell;
+		} else {
+			params->passive_fragmented = true;
+		}
 	}
 
 	if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
@@ -302,12 +329,65 @@
 not_bound:
 
 	for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
-		params->dwell[band].passive = iwl_mvm_get_passive_dwell(band);
+		if (params->passive_fragmented)
+			params->dwell[band].passive = frag_passive_dwell;
+		else
+			params->dwell[band].passive =
+				iwl_mvm_get_passive_dwell(band);
 		params->dwell[band].active = iwl_mvm_get_active_dwell(band,
 								      n_ssids);
 	}
 }
 
+static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm)
+{
+	/* require rrm scan whenever the fw supports it */
+	return mvm->fw->ucode_capa.capa[0] &
+	       IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT;
+}
+
+static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm,
+					   bool is_sched_scan)
+{
+	int max_probe_len;
+
+	if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
+		max_probe_len = SCAN_OFFLOAD_PROBE_REQ_SIZE;
+	else
+		max_probe_len = mvm->fw->ucode_capa.max_probe_length;
+
+	/* we create the 802.11 header and SSID element */
+	max_probe_len -= 24 + 2;
+
+	/* basic ssid is added only for hw_scan with and old api */
+	if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID) &&
+	    !(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) &&
+	    !is_sched_scan)
+		max_probe_len -= 32;
+
+	return max_probe_len;
+}
+
+int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan)
+{
+	int max_ie_len = iwl_mvm_max_scan_ie_fw_cmd_room(mvm, is_sched_scan);
+
+	if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN))
+		return max_ie_len;
+
+	/* TODO: [BUG] This function should return the maximum allowed size of
+	 * scan IEs, however the LMAC scan api contains both 2GHZ and 5GHZ IEs
+	 * in the same command. So the correct implementation of this function
+	 * is just iwl_mvm_max_scan_ie_fw_cmd_room() / 2. Currently the scan
+	 * command has only 512 bytes and it would leave us with about 240
+	 * bytes for scan IEs, which is clearly not enough. So meanwhile
+	 * we will report an incorrect value. This may result in a failure to
+	 * issue a scan in unified_scan_lmac and unified_sched_scan_lmac
+	 * functions with -ENOBUFS, if a large enough probe will be provided.
+	 */
+	return max_ie_len;
+}
+
 int iwl_mvm_scan_request(struct iwl_mvm *mvm,
 			 struct ieee80211_vif *vif,
 			 struct cfg80211_scan_request *req)
@@ -1100,10 +1180,11 @@
 				       struct iwl_mvm_scan_params *params)
 {
 	memset(cmd, 0, ksize(cmd));
-	cmd->active_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].active;
-	cmd->passive_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].passive;
-	/* TODO: Use params; now fragmented isn't used. */
-	cmd->fragmented_dwell = 0;
+	cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active;
+	cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
+	if (params->passive_fragmented)
+		cmd->fragmented_dwell =
+				params->dwell[IEEE80211_BAND_2GHZ].passive;
 	cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
 	cmd->max_out_time = cpu_to_le32(params->max_out_time);
 	cmd->suspend_time = cpu_to_le32(params->suspend_time);
@@ -1121,6 +1202,10 @@
 				    IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
 				    IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
 	}
+
+	if (iwl_mvm_rrm_scan_needed(mvm))
+		cmd->scan_flags |=
+			cpu_to_le32(IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED);
 }
 
 int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
@@ -1148,13 +1233,12 @@
 	if (WARN_ON(mvm->scan_cmd == NULL))
 		return -ENOMEM;
 
-	if (WARN_ON_ONCE(req->req.n_ssids > PROBE_OPTION_MAX ||
-			 req->ies.common_ie_len + req->ies.len[0] +
-				req->ies.len[1] + 24 + 2 >
-					SCAN_OFFLOAD_PROBE_REQ_SIZE ||
-			 req->req.n_channels >
-				mvm->fw->ucode_capa.n_scan_channels))
-		return -1;
+	if (req->req.n_ssids > PROBE_OPTION_MAX ||
+	    req->ies.common_ie_len + req->ies.len[NL80211_BAND_2GHZ] +
+	    req->ies.len[NL80211_BAND_5GHZ] >
+		iwl_mvm_max_scan_ie_fw_cmd_room(mvm, false) ||
+	    req->req.n_channels > mvm->fw->ucode_capa.n_scan_channels)
+		return -ENOBUFS;
 
 	mvm->scan_status = IWL_MVM_SCAN_OS;
 
@@ -1176,7 +1260,7 @@
 	if (req->req.n_ssids == 0)
 		flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
 
-	cmd->scan_flags = cpu_to_le32(flags);
+	cmd->scan_flags |= cpu_to_le32(flags);
 
 	cmd->flags = iwl_mvm_scan_rxon_flags(req->req.channels[0]->band);
 	cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
@@ -1242,10 +1326,11 @@
 	if (WARN_ON(mvm->scan_cmd == NULL))
 		return -ENOMEM;
 
-	if (WARN_ON_ONCE(req->n_ssids > PROBE_OPTION_MAX ||
-			 ies->common_ie_len + ies->len[0] + ies->len[1] + 24 + 2
-				> SCAN_OFFLOAD_PROBE_REQ_SIZE ||
-			 req->n_channels > mvm->fw->ucode_capa.n_scan_channels))
+	if (req->n_ssids > PROBE_OPTION_MAX ||
+	    ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] +
+	    ies->len[NL80211_BAND_5GHZ] >
+		iwl_mvm_max_scan_ie_fw_cmd_room(mvm, true) ||
+	    req->n_channels > mvm->fw->ucode_capa.n_scan_channels)
 		return -ENOBUFS;
 
 	iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, &params);
@@ -1273,7 +1358,7 @@
 	if (req->n_ssids == 0)
 		flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
 
-	cmd->scan_flags = cpu_to_le32(flags);
+	cmd->scan_flags |= cpu_to_le32(flags);
 
 	cmd->flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band);
 	cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c
index e843b67..7eb78e2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sf.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sf.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -177,6 +179,10 @@
 	struct ieee80211_sta *sta;
 	int ret = 0;
 
+	if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF &&
+	    mvm->cfg->disable_dummy_notification)
+		sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF);
+
 	/*
 	 * If an associated AP sta changed its antenna configuration, the state
 	 * will remain FULL_ON but SF parameters need to be reconsidered.
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 7635488..1731c20 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -245,15 +247,20 @@
 		memset(&mvm_sta->tid_data[i], 0, sizeof(mvm_sta->tid_data[i]));
 		mvm_sta->tid_data[i].seq_number = seq;
 	}
+	mvm_sta->agg_tids = 0;
 
 	ret = iwl_mvm_sta_send_to_fw(mvm, sta, false);
 	if (ret)
 		return ret;
 
-	/* The first station added is the AP, the others are TDLS STAs */
-	if (vif->type == NL80211_IFTYPE_STATION &&
-	    mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
-		mvmvif->ap_sta_id = sta_id;
+	if (vif->type == NL80211_IFTYPE_STATION) {
+		if (!sta->tdls) {
+			WARN_ON(mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT);
+			mvmvif->ap_sta_id = sta_id;
+		} else {
+			WARN_ON(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT);
+		}
+	}
 
 	rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
 
@@ -458,8 +465,9 @@
 	return ret;
 }
 
-int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
-			     u32 qmask, enum nl80211_iftype iftype)
+static int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,
+				    struct iwl_mvm_int_sta *sta,
+				    u32 qmask, enum nl80211_iftype iftype)
 {
 	if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
 		sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype);
@@ -474,7 +482,8 @@
 	return 0;
 }
 
-void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta)
+static void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm,
+				    struct iwl_mvm_int_sta *sta)
 {
 	RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL);
 	memset(sta, 0, sizeof(struct iwl_mvm_int_sta));
@@ -527,8 +536,8 @@
 	lockdep_assert_held(&mvm->mutex);
 
 	/* Map Aux queue to fifo - needs to happen before adding Aux station */
-	iwl_trans_ac_txq_enable(mvm->trans, mvm->aux_queue,
-				IWL_MVM_TX_FIFO_MCAST);
+	iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue,
+			      IWL_MVM_TX_FIFO_MCAST);
 
 	/* Allocate aux station and assign to it the aux queue */
 	ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue),
@@ -544,6 +553,13 @@
 	return ret;
 }
 
+void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm)
+{
+	lockdep_assert_held(&mvm->mutex);
+
+	iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
+}
+
 /*
  * Send the add station command for the vif's broadcast station.
  * Assumes that the station was already allocated.
@@ -552,10 +568,10 @@
  * @vif: the interface to which the broadcast station is added
  * @bsta: the broadcast station to add.
  */
-int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-			   struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta;
 	static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 	const u8 *baddr = _baddr;
 
@@ -573,19 +589,40 @@
 
 /* Send the FW a request to remove the station from it's internal data
  * structures, but DO NOT remove the entry from the local data structures. */
-int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
-			      struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 	int ret;
 
 	lockdep_assert_held(&mvm->mutex);
 
-	ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id);
+	ret = iwl_mvm_rm_sta_common(mvm, mvmvif->bcast_sta.sta_id);
 	if (ret)
 		IWL_WARN(mvm, "Failed sending remove station\n");
 	return ret;
 }
 
+int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+	u32 qmask;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
+
+	/*
+	 * The firmware defines the TFD queue mask to only be relevant
+	 * for *unicast* queues, so the multicast (CAB) queue shouldn't
+	 * be included.
+	 */
+	if (vif->type == NL80211_IFTYPE_AP)
+		qmask &= ~BIT(vif->cab_queue);
+
+	return iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, qmask,
+					ieee80211_vif_type_p2p(vif));
+}
+
 /* Allocate a new station entry for the broadcast station to the given vif,
  * and send it to the FW.
  * Note that each P2P mac should have its own broadcast station.
@@ -593,45 +630,47 @@
  * @mvm: the mvm component
  * @vif: the interface to which the broadcast station is added
  * @bsta: the broadcast station to add. */
-int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-			  struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-	static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-	u32 qmask;
+	struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta;
 	int ret;
 
 	lockdep_assert_held(&mvm->mutex);
 
-	qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
-	ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask,
-				       ieee80211_vif_type_p2p(vif));
+	ret = iwl_mvm_alloc_bcast_sta(mvm, vif);
 	if (ret)
 		return ret;
 
-	ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr,
-					 mvmvif->id, mvmvif->color);
+	ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
 
 	if (ret)
 		iwl_mvm_dealloc_int_sta(mvm, bsta);
+
 	return ret;
 }
 
+void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+	iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
+}
+
 /*
  * Send the FW a request to remove the station from it's internal data
  * structures, and in addition remove it from the local data structure.
  */
-int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
 	int ret;
 
 	lockdep_assert_held(&mvm->mutex);
 
-	ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id);
-	if (ret)
-		return ret;
+	ret = iwl_mvm_send_rm_bcast_sta(mvm, vif);
 
-	iwl_mvm_dealloc_int_sta(mvm, bsta);
+	iwl_mvm_dealloc_bcast_sta(mvm, vif);
+
 	return ret;
 }
 
@@ -834,12 +873,16 @@
 	int queue, fifo, ret;
 	u16 ssn;
 
+	BUILD_BUG_ON((sizeof(mvmsta->agg_tids) * BITS_PER_BYTE)
+		     != IWL_MAX_TID_COUNT);
+
 	buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
 
 	spin_lock_bh(&mvmsta->lock);
 	ssn = tid_data->ssn;
 	queue = tid_data->txq_id;
 	tid_data->state = IWL_AGG_ON;
+	mvmsta->agg_tids |= BIT(tid);
 	tid_data->ssn = 0xffff;
 	spin_unlock_bh(&mvmsta->lock);
 
@@ -849,8 +892,8 @@
 	if (ret)
 		return -EIO;
 
-	iwl_trans_txq_enable(mvm->trans, queue, fifo, mvmsta->sta_id, tid,
-			     buf_size, ssn);
+	iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid,
+			       buf_size, ssn);
 
 	/*
 	 * Even though in theory the peer could have different
@@ -894,6 +937,8 @@
 	IWL_DEBUG_TX_QUEUES(mvm, "Stop AGG: sta %d tid %d q %d state %d\n",
 			    mvmsta->sta_id, tid, txq_id, tid_data->state);
 
+	mvmsta->agg_tids &= ~BIT(tid);
+
 	switch (tid_data->state) {
 	case IWL_AGG_ON:
 		tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
@@ -910,8 +955,16 @@
 		}
 
 		tid_data->ssn = 0xffff;
-		iwl_trans_txq_disable(mvm->trans, txq_id);
-		/* fall through */
+		tid_data->state = IWL_AGG_OFF;
+		mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE;
+		spin_unlock_bh(&mvmsta->lock);
+
+		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+
+		iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
+
+		iwl_mvm_disable_txq(mvm, txq_id);
+		return 0;
 	case IWL_AGG_STARTING:
 	case IWL_EMPTYING_HW_QUEUE_ADDBA:
 		/*
@@ -959,13 +1012,16 @@
 			    mvmsta->sta_id, tid, txq_id, tid_data->state);
 	old_state = tid_data->state;
 	tid_data->state = IWL_AGG_OFF;
+	mvmsta->agg_tids &= ~BIT(tid);
 	spin_unlock_bh(&mvmsta->lock);
 
 	if (old_state >= IWL_AGG_ON) {
 		if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
 			IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
 
-		iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+		iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
+
+		iwl_mvm_disable_txq(mvm, tid_data->txq_id);
 	}
 
 	mvm->queue_to_mac80211[tid_data->txq_id] =
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h
index 3b1c8bd..d9c0d7b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -297,6 +299,7 @@
  * @tx_protection: reference counter for controlling the Tx protection.
  * @tt_tx_protection: is thermal throttling enable Tx protection?
  * @disable_tx: is tx to this STA disabled?
+ * @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON)
  *
  * When mac80211 creates a station it reserves some space (hw->sta_data_size)
  * in the structure for use by driver. This structure is placed in that
@@ -321,6 +324,7 @@
 	bool tt_tx_protection;
 
 	bool disable_tx;
+	u8 agg_tids;
 };
 
 static inline struct iwl_mvm_sta *
@@ -387,17 +391,15 @@
 			    struct ieee80211_sta *sta, u16 tid);
 
 int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm);
-int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
-			     u32 qmask, enum nl80211_iftype iftype);
-void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm,
-			     struct iwl_mvm_int_sta *sta);
-int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-			   struct iwl_mvm_int_sta *bsta);
-int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
-			      struct iwl_mvm_int_sta *bsta);
-int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-			  struct iwl_mvm_int_sta *bsta);
-int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta);
+void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm);
+
+int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+
 void iwl_mvm_sta_drained_wk(struct work_struct *wk);
 void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
 				struct ieee80211_sta *sta);
diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c
new file mode 100644
index 0000000..66c82df
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c
@@ -0,0 +1,149 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include "mvm.h"
+#include "time-event.h"
+
+void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)
+{
+	struct ieee80211_sta *sta;
+	struct iwl_mvm_sta *mvmsta;
+	int i;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
+		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
+						lockdep_is_held(&mvm->mutex));
+		if (!sta || IS_ERR(sta) || !sta->tdls)
+			continue;
+
+		mvmsta = iwl_mvm_sta_from_mac80211(sta);
+		ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,
+				NL80211_TDLS_TEARDOWN,
+				WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,
+				GFP_KERNEL);
+	}
+}
+
+int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+	struct ieee80211_sta *sta;
+	struct iwl_mvm_sta *mvmsta;
+	int count = 0;
+	int i;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
+		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
+						lockdep_is_held(&mvm->mutex));
+		if (!sta || IS_ERR(sta) || !sta->tdls)
+			continue;
+
+		if (vif) {
+			mvmsta = iwl_mvm_sta_from_mac80211(sta);
+			if (mvmsta->vif != vif)
+				continue;
+		}
+
+		count++;
+	}
+
+	return count;
+}
+
+void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+			       bool sta_added)
+{
+	int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif);
+
+	/*
+	 * Disable ps when the first TDLS sta is added and re-enable it
+	 * when the last TDLS sta is removed
+	 */
+	if ((tdls_sta_cnt == 1 && sta_added) ||
+	    (tdls_sta_cnt == 0 && !sta_added))
+		iwl_mvm_power_update_mac(mvm);
+}
+
+void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
+					   struct ieee80211_vif *vif)
+{
+	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+	u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int;
+
+	/*
+	 * iwl_mvm_protect_session() reads directly from the device
+	 * (the system time), so make sure it is available.
+	 */
+	if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS))
+		return;
+
+	mutex_lock(&mvm->mutex);
+	/* Protect the session to hear the TDLS setup response on the channel */
+	iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true);
+	mutex_unlock(&mvm->mutex);
+
+	iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/testmode.h b/drivers/net/wireless/iwlwifi/mvm/testmode.h
index 0241665..79ab6be 100644
--- a/drivers/net/wireless/iwlwifi/mvm/testmode.h
+++ b/drivers/net/wireless/iwlwifi/mvm/testmode.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index 33e5041..b7f9e61 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -348,6 +350,38 @@
 	return 0;
 }
 
+static bool iwl_mvm_te_notif(struct iwl_notif_wait_data *notif_wait,
+			     struct iwl_rx_packet *pkt, void *data)
+{
+	struct iwl_mvm *mvm =
+		container_of(notif_wait, struct iwl_mvm, notif_wait);
+	struct iwl_mvm_time_event_data *te_data = data;
+	struct iwl_time_event_notif *resp;
+	int resp_len = iwl_rx_packet_payload_len(pkt);
+
+	if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_NOTIFICATION))
+		return true;
+
+	if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
+		IWL_ERR(mvm, "Invalid TIME_EVENT_NOTIFICATION response\n");
+		return true;
+	}
+
+	resp = (void *)pkt->data;
+
+	/* te_data->uid is already set in the TIME_EVENT_CMD response */
+	if (le32_to_cpu(resp->unique_id) != te_data->uid)
+		return false;
+
+	IWL_DEBUG_TE(mvm, "TIME_EVENT_NOTIFICATION response - UID = 0x%x\n",
+		     te_data->uid);
+	if (!resp->status)
+		IWL_ERR(mvm,
+			"TIME_EVENT_NOTIFICATION received but not executed\n");
+
+	return true;
+}
+
 static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait,
 					struct iwl_rx_packet *pkt, void *data)
 {
@@ -441,10 +475,12 @@
 void iwl_mvm_protect_session(struct iwl_mvm *mvm,
 			     struct ieee80211_vif *vif,
 			     u32 duration, u32 min_duration,
-			     u32 max_delay)
+			     u32 max_delay, bool wait_for_notif)
 {
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 	struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
+	const u8 te_notif_response[] = { TIME_EVENT_NOTIFICATION };
+	struct iwl_notification_wait wait_te_notif;
 	struct iwl_time_event_cmd time_cmd = {};
 
 	lockdep_assert_held(&mvm->mutex);
@@ -489,7 +525,28 @@
 				      TE_V2_NOTIF_HOST_EVENT_END |
 				      T2_V2_START_IMMEDIATELY);
 
-	iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
+	if (!wait_for_notif) {
+		iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
+		return;
+	}
+
+	/*
+	 * Create notification_wait for the TIME_EVENT_NOTIFICATION to use
+	 * right after we send the time event
+	 */
+	iwl_init_notification_wait(&mvm->notif_wait, &wait_te_notif,
+				   te_notif_response,
+				   ARRAY_SIZE(te_notif_response),
+				   iwl_mvm_te_notif, te_data);
+
+	/* If TE was sent OK - wait for the notification that started */
+	if (iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd)) {
+		IWL_ERR(mvm, "Failed to add TE to protect session\n");
+		iwl_remove_notification(&mvm->notif_wait, &wait_te_notif);
+	} else if (iwl_wait_notification(&mvm->notif_wait, &wait_te_notif,
+					 TU_TO_JIFFIES(max_delay))) {
+		IWL_ERR(mvm, "Failed to protect session until TE\n");
+	}
 }
 
 /*
@@ -643,9 +700,9 @@
 	iwl_mvm_roc_finished(mvm);
 }
 
-int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm,
-			      struct ieee80211_vif *vif,
-			      u32 duration, u32 apply_time)
+int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
+				struct ieee80211_vif *vif,
+				u32 duration, u32 apply_time)
 {
 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 	struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
@@ -654,14 +711,14 @@
 	lockdep_assert_held(&mvm->mutex);
 
 	if (te_data->running) {
-		IWL_DEBUG_TE(mvm, "CS NOA is already scheduled\n");
+		IWL_DEBUG_TE(mvm, "CS period is already scheduled\n");
 		return -EBUSY;
 	}
 
 	time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
 	time_cmd.id_and_color =
 		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
-	time_cmd.id = cpu_to_le32(TE_P2P_GO_CSA_NOA);
+	time_cmd.id = cpu_to_le32(TE_CHANNEL_SWITCH_PERIOD);
 	time_cmd.apply_time = cpu_to_le32(apply_time);
 	time_cmd.max_frags = TE_V2_FRAG_NONE;
 	time_cmd.duration = cpu_to_le32(duration);
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h
index 2f48a90..b350e47 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.h
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -124,10 +126,12 @@
  * @min_duration: will start a new session if the current session will end
  *	in less than min_duration.
  * @max_delay: maximum delay before starting the time event (in TU)
+ * @wait_for_notif: true if it is required that a time event notification be
+ *	waited for (that the time event has been scheduled before returning)
  *
  * This function can be used to start a session protection which means that the
  * fw will stay on the channel for %duration_ms milliseconds. This function
- * will block (sleep) until the session starts. This function can also be used
+ * can block (sleep) until the session starts. This function can also be used
  * to extend a currently running session.
  * This function is meant to be used for BSS association for example, where we
  * want to make sure that the fw stays on the channel during the association.
@@ -135,7 +139,7 @@
 void iwl_mvm_protect_session(struct iwl_mvm *mvm,
 			     struct ieee80211_vif *vif,
 			     u32 duration, u32 min_duration,
-			     u32 max_delay);
+			     u32 max_delay, bool wait_for_notif);
 
 /**
  * iwl_mvm_stop_session_protection - cancel the session protection.
@@ -215,7 +219,7 @@
 void iwl_mvm_roc_done_wk(struct work_struct *wk);
 
 /**
- * iwl_mvm_schedule_csa_noa - request NoA for channel switch
+ * iwl_mvm_schedule_csa_period - request channel switch absence period
  * @mvm: the mvm component
  * @vif: the virtual interface for which the channel switch is issued
  * @duration: the duration of the NoA in TU.
@@ -224,9 +228,9 @@
  * This function is used to schedule NoA time event and is used to perform
  * the channel switch flow.
  */
-int iwl_mvm_schedule_csa_noa(struct iwl_mvm *mvm,
-			     struct ieee80211_vif *vif,
-			     u32 duration, u32 apply_time);
+int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
+				struct ieee80211_vif *vif,
+				u32 duration, u32 apply_time);
 
 /**
  * iwl_mvm_te_scheduled - check if the fw received the TE cmd
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c
index 0464599..acca44a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tt.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -67,265 +69,101 @@
 #include "iwl-csr.h"
 #include "iwl-prph.h"
 
-#define OTP_DTS_DIODE_DEVIATION 96 /*in words*/
-/* VBG - Voltage Band Gap error data (temperature offset) */
-#define OTP_WP_DTS_VBG			(OTP_DTS_DIODE_DEVIATION + 2)
-#define MEAS_VBG_MIN_VAL		2300
-#define MEAS_VBG_MAX_VAL		3000
-#define MEAS_VBG_DEFAULT_VAL		2700
-#define DTS_DIODE_VALID(flags)		(flags & DTS_DIODE_REG_FLAGS_PASS_ONCE)
-#define MIN_TEMPERATURE			0
-#define MAX_TEMPERATURE			125
-#define TEMPERATURE_ERROR		(MAX_TEMPERATURE + 1)
-#define PTAT_DIGITAL_VALUE_MIN_VALUE	0
-#define PTAT_DIGITAL_VALUE_MAX_VALUE	0xFF
-#define DTS_VREFS_NUM			5
-static inline u32 DTS_DIODE_GET_VREFS_ID(u32 flags)
-{
-	return (flags & DTS_DIODE_REG_FLAGS_VREFS_ID) >>
-					DTS_DIODE_REG_FLAGS_VREFS_ID_POS;
-}
-
-#define CALC_VREFS_MIN_DIFF	43
-#define CALC_VREFS_MAX_DIFF	51
-#define CALC_LUT_SIZE		(1 + CALC_VREFS_MAX_DIFF - CALC_VREFS_MIN_DIFF)
-#define CALC_LUT_INDEX_OFFSET	CALC_VREFS_MIN_DIFF
-#define CALC_TEMPERATURE_RESULT_SHIFT_OFFSET	23
-
-/*
- * @digital_value: The diode's digital-value sampled (temperature/voltage)
- * @vref_low: The lower voltage-reference (the vref just below the diode's
- *	sampled digital-value)
- * @vref_high: The higher voltage-reference (the vref just above the diode's
- *	sampled digital-value)
- * @flags: bits[1:0]: The ID of the Vrefs pair (lowVref,highVref)
- *	bits[6:2]: Reserved.
- *	bits[7:7]: Indicates completion of at least 1 successful sample
- *	since last DTS reset.
- */
-struct iwl_mvm_dts_diode_bits {
-	u8 digital_value;
-	u8 vref_low;
-	u8 vref_high;
-	u8 flags;
-} __packed;
-
-union dts_diode_results {
-	u32 reg_value;
-	struct iwl_mvm_dts_diode_bits bits;
-} __packed;
-
-static s16 iwl_mvm_dts_get_volt_band_gap(struct iwl_mvm *mvm)
-{
-	struct iwl_nvm_section calib_sec;
-	const __le16 *calib;
-	u16 vbg;
-
-	/* TODO: move parsing to NVM code */
-	calib_sec = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION];
-	calib = (__le16 *)calib_sec.data;
-
-	vbg = le16_to_cpu(calib[OTP_WP_DTS_VBG]);
-
-	if (vbg < MEAS_VBG_MIN_VAL || vbg > MEAS_VBG_MAX_VAL)
-		vbg = MEAS_VBG_DEFAULT_VAL;
-
-	return vbg;
-}
-
-static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm)
-{
-	const u8 *calib;
-	u8 ptat, pa1, pa2, median;
-
-	/* TODO: move parsing to NVM code */
-	calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data;
-	ptat = calib[OTP_DTS_DIODE_DEVIATION * 2];
-	pa1 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 1];
-	pa2 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 2];
-
-	/* get the median: */
-	if (ptat > pa1) {
-		if (ptat > pa2)
-			median = (pa1 > pa2) ? pa1 : pa2;
-		else
-			median = ptat;
-	} else {
-		if (pa1 > pa2)
-			median = (ptat > pa2) ? ptat : pa2;
-		else
-			median = pa1;
-	}
-
-	return ptat - median;
-}
-
-static u8 iwl_mvm_dts_calibrate_ptat_deviation(struct iwl_mvm *mvm, u8 value)
-{
-	/* Calibrate the PTAT digital value, based on PTAT deviation data: */
-	s16 new_val = value - iwl_mvm_dts_get_ptat_deviation_offset(mvm);
-
-	if (new_val > PTAT_DIGITAL_VALUE_MAX_VALUE)
-		new_val = PTAT_DIGITAL_VALUE_MAX_VALUE;
-	else if (new_val < PTAT_DIGITAL_VALUE_MIN_VALUE)
-		new_val = PTAT_DIGITAL_VALUE_MIN_VALUE;
-
-	return new_val;
-}
-
-static bool dts_get_adjacent_vrefs(struct iwl_mvm *mvm,
-				   union dts_diode_results *avg_ptat)
-{
-	u8 vrefs_results[DTS_VREFS_NUM];
-	u8 low_vref_index = 0, flags;
-	u32 reg;
-
-	reg = iwl_read_prph(mvm->trans, DTSC_VREF_AVG);
-	memcpy(vrefs_results, &reg, sizeof(reg));
-	reg = iwl_read_prph(mvm->trans, DTSC_VREF5_AVG);
-	vrefs_results[4] = reg & 0xff;
-
-	if (avg_ptat->bits.digital_value < vrefs_results[0] ||
-	    avg_ptat->bits.digital_value > vrefs_results[4])
-		return false;
-
-	if (avg_ptat->bits.digital_value > vrefs_results[3])
-		low_vref_index = 3;
-	else if (avg_ptat->bits.digital_value > vrefs_results[2])
-		low_vref_index = 2;
-	else if (avg_ptat->bits.digital_value > vrefs_results[1])
-		low_vref_index = 1;
-
-	avg_ptat->bits.vref_low  = vrefs_results[low_vref_index];
-	avg_ptat->bits.vref_high = vrefs_results[low_vref_index + 1];
-	flags = avg_ptat->bits.flags;
-	avg_ptat->bits.flags =
-		(flags & ~DTS_DIODE_REG_FLAGS_VREFS_ID) |
-		(low_vref_index & DTS_DIODE_REG_FLAGS_VREFS_ID);
-	return true;
-}
-
-/*
- * return true it the results are valid, and false otherwise.
- */
-static bool dts_read_ptat_avg_results(struct iwl_mvm *mvm,
-				      union dts_diode_results *avg_ptat)
-{
-	u32 reg;
-	u8 tmp;
-
-	/* fill the diode value and pass_once with avg-reg results */
-	reg = iwl_read_prph(mvm->trans, DTSC_PTAT_AVG);
-	reg &= DTS_DIODE_REG_DIG_VAL | DTS_DIODE_REG_PASS_ONCE;
-	avg_ptat->reg_value = reg;
-
-	/* calibrate the PTAT digital value */
-	tmp = avg_ptat->bits.digital_value;
-	tmp = iwl_mvm_dts_calibrate_ptat_deviation(mvm, tmp);
-	avg_ptat->bits.digital_value = tmp;
-
-	/*
-	 * fill vrefs fields, based on the avgVrefs results
-	 * and the diode value
-	 */
-	return dts_get_adjacent_vrefs(mvm, avg_ptat) &&
-		DTS_DIODE_VALID(avg_ptat->bits.flags);
-}
-
-static s32 calculate_nic_temperature(union dts_diode_results avg_ptat,
-				     u16 volt_band_gap)
-{
-	u32 tmp_result;
-	u8 vrefs_diff;
-	/*
-	 * For temperature calculation (at the end, shift right by 23)
-	 * LUT[(D2-D1)] = ROUND{ 2^23 / ((D2-D1)*9*10) }
-	 * (D2-D1) ==   43    44    45    46    47    48    49    50    51
-	 */
-	static const u16 calc_lut[CALC_LUT_SIZE] = {
-		2168, 2118, 2071, 2026, 1983, 1942, 1902, 1864, 1828,
-	};
-
-	/*
-	 * The diff between the high and low voltage-references is assumed
-	 * to be strictly be in range of [60,68]
-	 */
-	vrefs_diff = avg_ptat.bits.vref_high - avg_ptat.bits.vref_low;
-
-	if (vrefs_diff < CALC_VREFS_MIN_DIFF ||
-	    vrefs_diff > CALC_VREFS_MAX_DIFF)
-		return TEMPERATURE_ERROR;
-
-	/* calculate the result: */
-	tmp_result =
-		vrefs_diff * (DTS_DIODE_GET_VREFS_ID(avg_ptat.bits.flags) + 9);
-	tmp_result += avg_ptat.bits.digital_value;
-	tmp_result -= avg_ptat.bits.vref_high;
-
-	/* multiply by the LUT value (based on the diff) */
-	tmp_result *= calc_lut[vrefs_diff - CALC_LUT_INDEX_OFFSET];
-
-	/*
-	 * Get the BandGap (the voltage refereces source) error data
-	 * (temperature offset)
-	 */
-	tmp_result *= volt_band_gap;
-
-	/*
-	 * here, tmp_result value can be up to 32-bits. We want to right-shift
-	 * it *without* sign-extend.
-	 */
-	tmp_result = tmp_result >> CALC_TEMPERATURE_RESULT_SHIFT_OFFSET;
-
-	/*
-	 * at this point, tmp_result should be in the range:
-	 * 200 <= tmp_result <= 365
-	 */
-	return (s16)tmp_result - 240;
-}
-
-static s32 check_nic_temperature(struct iwl_mvm *mvm)
-{
-	u16 volt_band_gap;
-	union dts_diode_results avg_ptat;
-
-	volt_band_gap = iwl_mvm_dts_get_volt_band_gap(mvm);
-
-	/* disable DTS */
-	iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0);
-
-	/* SV initialization */
-	iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 1);
-	iwl_write_prph(mvm->trans, DTSC_CFG_MODE,
-		       DTSC_CFG_MODE_PERIODIC);
-
-	/* wait for results */
-	msleep(100);
-	if (!dts_read_ptat_avg_results(mvm, &avg_ptat))
-		return TEMPERATURE_ERROR;
-
-	/* disable DTS */
-	iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0);
-
-	return calculate_nic_temperature(avg_ptat, volt_band_gap);
-}
+#define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT	HZ
 
 static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
 {
 	u32 duration = mvm->thermal_throttle.params->ct_kill_duration;
 
+	if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
+		return;
+
 	IWL_ERR(mvm, "Enter CT Kill\n");
 	iwl_mvm_set_hw_ctkill_state(mvm, true);
-	schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
-			      round_jiffies_relative(duration * HZ));
+
+	/* Don't schedule an exit work if we're in test mode, since
+	 * the temperature will not change unless we manually set it
+	 * again (or disable testing).
+	 */
+	if (!mvm->temperature_test)
+		schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
+				      round_jiffies_relative(duration * HZ));
 }
 
 static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm)
 {
+	if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
+		return;
+
 	IWL_ERR(mvm, "Exit CT Kill\n");
 	iwl_mvm_set_hw_ctkill_state(mvm, false);
 }
 
+static bool iwl_mvm_temp_notif(struct iwl_notif_wait_data *notif_wait,
+			       struct iwl_rx_packet *pkt, void *data)
+{
+	struct iwl_mvm *mvm =
+		container_of(notif_wait, struct iwl_mvm, notif_wait);
+	int *temp = data;
+	struct iwl_dts_measurement_notif *notif;
+	int len = iwl_rx_packet_payload_len(pkt);
+
+	if (WARN_ON_ONCE(len != sizeof(*notif))) {
+		IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n");
+		return true;
+	}
+
+	notif = (void *)pkt->data;
+
+	*temp = le32_to_cpu(notif->temp);
+
+	/* shouldn't be negative, but since it's s32, make sure it isn't */
+	if (WARN_ON_ONCE(*temp < 0))
+		*temp = 0;
+
+	IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", *temp);
+	return true;
+}
+
+static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
+{
+	struct iwl_dts_measurement_cmd cmd = {
+		.flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP),
+	};
+
+	return iwl_mvm_send_cmd_pdu(mvm, CMD_DTS_MEASUREMENT_TRIGGER, 0,
+				    sizeof(cmd), &cmd);
+}
+
+int iwl_mvm_get_temp(struct iwl_mvm *mvm)
+{
+	struct iwl_notification_wait wait_temp_notif;
+	static const u8 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION };
+	int ret, temp;
+
+	lockdep_assert_held(&mvm->mutex);
+
+	iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif,
+				   temp_notif, ARRAY_SIZE(temp_notif),
+				   iwl_mvm_temp_notif, &temp);
+
+	ret = iwl_mvm_get_temp_cmd(mvm);
+	if (ret) {
+		IWL_ERR(mvm, "Failed to get the temperature (err=%d)\n", ret);
+		iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif);
+		return ret;
+	}
+
+	ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif,
+				    IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT);
+	if (ret) {
+		IWL_ERR(mvm, "Getting the temperature timed out\n");
+		return ret;
+	}
+
+	return temp;
+}
+
 static void check_exit_ctkill(struct work_struct *work)
 {
 	struct iwl_mvm_tt_mgmt *tt;
@@ -338,28 +176,36 @@
 
 	duration = tt->params->ct_kill_duration;
 
-	/* make sure the device is available for direct read/writes */
-	if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL))
+	mutex_lock(&mvm->mutex);
+
+	if (__iwl_mvm_mac_start(mvm))
 		goto reschedule;
 
-	iwl_trans_start_hw(mvm->trans);
-	temp = check_nic_temperature(mvm);
-	iwl_trans_stop_device(mvm->trans);
+	/* make sure the device is available for direct read/writes */
+	if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) {
+		__iwl_mvm_mac_stop(mvm);
+		goto reschedule;
+	}
+
+	temp = iwl_mvm_get_temp(mvm);
 
 	iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL);
 
-	if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) {
-		IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n");
+	__iwl_mvm_mac_stop(mvm);
+
+	if (temp < 0)
 		goto reschedule;
-	}
+
 	IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
 
 	if (temp <= tt->params->ct_kill_exit) {
+		mutex_unlock(&mvm->mutex);
 		iwl_mvm_exit_ctkill(mvm);
 		return;
 	}
 
 reschedule:
+	mutex_unlock(&mvm->mutex);
 	schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
 			      round_jiffies(duration * HZ));
 }
@@ -444,6 +290,12 @@
 		return;
 	}
 
+	if (params->support_ct_kill &&
+	    temperature <= tt->params->ct_kill_exit) {
+		iwl_mvm_exit_ctkill(mvm);
+		return;
+	}
+
 	if (params->support_dynamic_smps) {
 		if (!tt->dynamic_smps &&
 		    temperature >= params->dynamic_smps_entry) {
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index 02a00d6..9877937 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -131,6 +133,11 @@
 	    !is_multicast_ether_addr(ieee80211_get_DA(hdr)))
 		tx_flags |= TX_CMD_FLG_PROT_REQUIRE;
 
+	if ((mvm->fw->ucode_capa.capa[0] &
+	     IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT) &&
+	    ieee80211_action_contains_tpc(skb))
+		tx_flags |= TX_CMD_FLG_WRITE_TX_POWER;
+
 	tx_cmd->tx_flags = cpu_to_le32(tx_flags);
 	/* Total # bytes to be transmitted */
 	tx_cmd->len = cpu_to_le16((u16)skb->len);
@@ -211,7 +218,7 @@
 
 	if (info->band == IEEE80211_BAND_2GHZ &&
 	    !iwl_mvm_bt_coex_is_shared_ant_avail(mvm))
-		rate_flags = BIT(ANT_A) << RATE_MCS_ANT_POS;
+		rate_flags = BIT(mvm->cfg->non_shared_ant) << RATE_MCS_ANT_POS;
 	else
 		rate_flags =
 			BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
@@ -486,11 +493,11 @@
 		IWL_DEBUG_TX_QUEUES(mvm,
 				    "Can continue DELBA flow ssn = next_recl = %d\n",
 				    tid_data->next_reclaimed);
-		iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+		iwl_mvm_disable_txq(mvm, tid_data->txq_id);
 		tid_data->state = IWL_AGG_OFF;
 		/*
 		 * we can't hold the mutex - but since we are after a sequence
-		 * point (call to iwl_trans_txq_disable), so we don't even need
+		 * point (call to iwl_mvm_disable_txq(), so we don't even need
 		 * a memory barrier.
 		 */
 		mvm->queue_to_mac80211[tid_data->txq_id] =
@@ -866,6 +873,19 @@
 	return 0;
 }
 
+static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info,
+					  struct iwl_mvm_ba_notif *ba_notif,
+					  struct iwl_mvm_tid_data *tid_data)
+{
+	info->flags |= IEEE80211_TX_STAT_AMPDU;
+	info->status.ampdu_ack_len = ba_notif->txed_2_done;
+	info->status.ampdu_len = ba_notif->txed;
+	iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags,
+				    info);
+	info->status.status_driver_data[0] =
+		(void *)(uintptr_t)tid_data->reduced_tpc;
+}
+
 int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
 			struct iwl_device_cmd *cmd)
 {
@@ -952,21 +972,37 @@
 		 */
 		info->flags |= IEEE80211_TX_STAT_ACK;
 
-		if (freed == 1) {
-			/* this is the first skb we deliver in this batch */
-			/* put the rate scaling data there */
-			info->flags |= IEEE80211_TX_STAT_AMPDU;
-			info->status.ampdu_ack_len = ba_notif->txed_2_done;
-			info->status.ampdu_len = ba_notif->txed;
-			iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags,
-						    info);
-			info->status.status_driver_data[0] =
-				(void *)(uintptr_t)tid_data->reduced_tpc;
-		}
+		/* this is the first skb we deliver in this batch */
+		/* put the rate scaling data there */
+		if (freed == 1)
+			iwl_mvm_tx_info_from_ba_notif(info, ba_notif, tid_data);
 	}
 
 	spin_unlock_bh(&mvmsta->lock);
 
+	/* We got a BA notif with 0 acked or scd_ssn didn't progress which is
+	 * possible (i.e. first MPDU in the aggregation wasn't acked)
+	 * Still it's important to update RS about sent vs. acked.
+	 */
+	if (skb_queue_empty(&reclaimed_skbs)) {
+		struct ieee80211_tx_info ba_info = {};
+		struct ieee80211_chanctx_conf *chanctx_conf = NULL;
+
+		if (mvmsta->vif)
+			chanctx_conf =
+				rcu_dereference(mvmsta->vif->chanctx_conf);
+
+		if (WARN_ON_ONCE(!chanctx_conf))
+			goto out;
+
+		ba_info.band = chanctx_conf->def.chan->band;
+		iwl_mvm_tx_info_from_ba_notif(&ba_info, ba_notif, tid_data);
+
+		IWL_DEBUG_TX_REPLY(mvm, "No reclaim. Update rs directly\n");
+		iwl_mvm_rs_tx_status(mvm, sta, tid, &ba_info);
+	}
+
+out:
 	rcu_read_unlock();
 
 	while (!skb_queue_empty(&reclaimed_skbs)) {
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index 763c709..ee6e5f9 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -387,15 +389,19 @@
 struct iwl_umac_error_event_table {
 	u32 valid;		/* (nonzero) valid, (0) log is empty */
 	u32 error_id;		/* type of error */
-	u32 pc;			/* program counter */
 	u32 blink1;		/* branch link */
 	u32 blink2;		/* branch link */
 	u32 ilink1;		/* interrupt link */
 	u32 ilink2;		/* interrupt link */
 	u32 data1;		/* error-specific data */
 	u32 data2;		/* error-specific data */
-	u32 line;		/* source code line of error */
-	u32 umac_ver;		/* umac version */
+	u32 data3;		/* error-specific data */
+	u32 umac_fw_ver;	/* UMAC version */
+	u32 umac_fw_api_ver;	/* UMAC FW API ver */
+	u32 frame_pointer;	/* core register 27*/
+	u32 stack_pointer;	/* core register 28 */
+	u32 cmd_header;	/* latest host cmd sent to UMAC */
+	u32 nic_isr_pref;	/* ISR status register */
 } __packed;
 
 #define ERROR_START_OFFSET  (1 * sizeof(u32))
@@ -409,7 +415,7 @@
 
 	base = mvm->umac_error_event_table;
 
-	if (base < 0x800000 || base >= 0x80C000) {
+	if (base < 0x800000) {
 		IWL_ERR(mvm,
 			"Not valid error log pointer 0x%08X for %s uCode\n",
 			base,
@@ -428,14 +434,19 @@
 
 	IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
 		desc_lookup(table.error_id));
-	IWL_ERR(mvm, "0x%08X | umac uPc\n", table.pc);
 	IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1);
 	IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2);
 	IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1);
 	IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2);
 	IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1);
 	IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2);
-	IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_ver);
+	IWL_ERR(mvm, "0x%08X | umac data3\n", table.data3);
+	IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_fw_ver);
+	IWL_ERR(mvm, "0x%08X | umac api version\n", table.umac_fw_api_ver);
+	IWL_ERR(mvm, "0x%08X | frame pointer\n", table.frame_pointer);
+	IWL_ERR(mvm, "0x%08X | stack pointer\n", table.stack_pointer);
+	IWL_ERR(mvm, "0x%08X | last host cmd\n", table.cmd_header);
+	IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref);
 }
 
 void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
@@ -519,6 +530,52 @@
 		iwl_mvm_dump_umac_error_log(mvm);
 }
 
+void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn,
+			const struct iwl_trans_txq_scd_cfg *cfg)
+{
+	if (iwl_mvm_is_dqa_supported(mvm)) {
+		struct iwl_scd_txq_cfg_cmd cmd = {
+			.scd_queue = queue,
+			.enable = 1,
+			.window = cfg->frame_limit,
+			.sta_id = cfg->sta_id,
+			.ssn = cpu_to_le16(ssn),
+			.tx_fifo = cfg->fifo,
+			.aggregate = cfg->aggregate,
+			.flags = IWL_SCD_FLAGS_DQA_ENABLED,
+			.tid = cfg->tid,
+			.control = IWL_SCD_CONTROL_SET_SSN,
+		};
+		int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0,
+					       sizeof(cmd), &cmd);
+		if (ret)
+			IWL_ERR(mvm,
+				"Failed to configure queue %d on FIFO %d\n",
+				queue, cfg->fifo);
+	}
+
+	iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn,
+				 iwl_mvm_is_dqa_supported(mvm) ? NULL : cfg);
+}
+
+void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue)
+{
+	iwl_trans_txq_disable(mvm->trans, queue,
+			      !iwl_mvm_is_dqa_supported(mvm));
+
+	if (iwl_mvm_is_dqa_supported(mvm)) {
+		struct iwl_scd_txq_cfg_cmd cmd = {
+			.scd_queue = queue,
+			.enable = 0,
+		};
+		int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, CMD_ASYNC,
+					       sizeof(cmd), &cmd);
+		if (ret)
+			IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n",
+				queue, ret);
+	}
+}
+
 /**
  * iwl_mvm_send_lq_cmd() - Send link quality command
  * @init: This command is sent as part of station initialization right
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index bfdd5cf..082d286 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -273,6 +275,8 @@
 	{IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x08B1, 0x4072, iwl7260_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x08B1, 0x4170, iwl7260_2ac_cfg)},
+	{IWL_PCI_DEVICE(0x08B1, 0x4C60, iwl7260_2ac_cfg)},
+	{IWL_PCI_DEVICE(0x08B1, 0x4C70, iwl7260_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x08B1, 0x4060, iwl7260_2n_cfg)},
 	{IWL_PCI_DEVICE(0x08B1, 0x406A, iwl7260_2n_cfg)},
 	{IWL_PCI_DEVICE(0x08B1, 0x4160, iwl7260_2n_cfg)},
@@ -316,6 +320,8 @@
 	{IWL_PCI_DEVICE(0x08B1, 0xC770, iwl7260_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x08B1, 0xC760, iwl7260_2n_cfg)},
 	{IWL_PCI_DEVICE(0x08B2, 0xC270, iwl7260_2ac_cfg)},
+	{IWL_PCI_DEVICE(0x08B1, 0xCC70, iwl7260_2ac_cfg)},
+	{IWL_PCI_DEVICE(0x08B1, 0xCC60, iwl7260_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x08B2, 0xC272, iwl7260_2ac_cfg)},
 	{IWL_PCI_DEVICE(0x08B2, 0xC260, iwl7260_2n_cfg)},
 	{IWL_PCI_DEVICE(0x08B2, 0xC26A, iwl7260_n_cfg)},
@@ -403,6 +409,7 @@
 
 /* 8000 Series */
 	{IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)},
+	{IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)},
 	{IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)},
 #endif /* CPTCFG_IWLMVM */
 
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index 97dd256..e6129af 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -1,6 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -256,6 +257,7 @@
  * @cmd_queue - command queue number
  * @rx_buf_size_8k: 8 kB RX buffer size
  * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
+ * @scd_set_active: should the transport configure the SCD for HCMD queue
  * @rx_page_order: page order for receive buffer size
  * @wd_timeout: queue watchdog timeout (jiffies)
  * @reg_lock: protect hw register access
@@ -305,6 +307,7 @@
 
 	bool rx_buf_size_8k;
 	bool bc_table_dword;
+	bool scd_set_active;
 	u32 rx_page_order;
 
 	const char *const *command_names;
@@ -364,9 +367,10 @@
 void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr);
 int iwl_pcie_tx_stop(struct iwl_trans *trans);
 void iwl_pcie_tx_free(struct iwl_trans *trans);
-void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
-			       int sta_id, int tid, int frame_limit, u16 ssn);
-void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue);
+void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn,
+			       const struct iwl_trans_txq_scd_cfg *cfg);
+void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue,
+				bool configure_scd);
 int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
 		      struct iwl_device_cmd *dev_cmd, int txq_id);
 void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans);
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index a2698e5..7b7e2f2 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -1,6 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -639,7 +640,7 @@
 		err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
 
 		if (reclaim) {
-			kfree(txq->entries[cmd_index].free_buf);
+			kzfree(txq->entries[cmd_index].free_buf);
 			txq->entries[cmd_index].free_buf = NULL;
 		}
 
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 9e618e9..9062249 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * 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
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -1169,6 +1171,7 @@
 
 	trans_pcie->command_names = trans_cfg->command_names;
 	trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
+	trans_pcie->scd_set_active = trans_cfg->scd_set_active;
 
 	/* Initialize NAPI here - it should be before registering to mac80211
 	 * in the opmode but after the HW struct is allocated.
@@ -2187,7 +2190,7 @@
 	 */
 	if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
 		trans->hw_rev = (trans->hw_rev & 0xfff0) |
-				((trans->hw_rev << 2) & 0xc);
+				(CSR_HW_REV_STEP(trans->hw_rev << 2) << 2);
 
 	trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
 	snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 6acccb1..eb8e298 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -1,6 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -34,6 +35,7 @@
 #include "iwl-csr.h"
 #include "iwl-prph.h"
 #include "iwl-io.h"
+#include "iwl-scd.h"
 #include "iwl-op-mode.h"
 #include "internal.h"
 /* FIXME: need to abstract out TX command (once we know what it looks like) */
@@ -618,8 +620,8 @@
 	/* De-alloc array of command/tx buffers */
 	if (txq_id == trans_pcie->cmd_queue)
 		for (i = 0; i < txq->q.n_window; i++) {
-			kfree(txq->entries[i].cmd);
-			kfree(txq->entries[i].free_buf);
+			kzfree(txq->entries[i].cmd);
+			kzfree(txq->entries[i].free_buf);
 		}
 
 	/* De-alloc circular buffer of TFDs */
@@ -644,17 +646,6 @@
 	memset(txq, 0, sizeof(*txq));
 }
 
-/*
- * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- */
-static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask)
-{
-	struct iwl_trans_pcie __maybe_unused *trans_pcie =
-		IWL_TRANS_GET_PCIE_TRANS(trans);
-
-	iwl_write_prph(trans, SCD_TXFACT, mask);
-}
-
 void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
 {
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -692,7 +683,7 @@
 				trans_pcie->cmd_fifo);
 
 	/* Activate all Tx DMA/FIFO channels */
-	iwl_pcie_txq_set_sched(trans, IWL_MASK(0, 7));
+	iwl_scd_activate_fifos(trans);
 
 	/* Enable DMA channel */
 	for (chan = 0; chan < FH_TCSR_CHNL_NUM; chan++)
@@ -745,7 +736,7 @@
 	/* Turn off all Tx DMA fifos */
 	spin_lock(&trans_pcie->irq_lock);
 
-	iwl_pcie_txq_set_sched(trans, 0);
+	iwl_scd_deactivate_fifos(trans);
 
 	/* Stop each Tx DMA channel, and wait for it to be idle */
 	for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
@@ -886,7 +877,7 @@
 	spin_lock(&trans_pcie->irq_lock);
 
 	/* Turn off all Tx DMA fifos */
-	iwl_write_prph(trans, SCD_TXFACT, 0);
+	iwl_scd_deactivate_fifos(trans);
 
 	/* Tell NIC where to find the "keep warm" buffer */
 	iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
@@ -1072,55 +1063,53 @@
 	return 0;
 }
 
-static inline void iwl_pcie_txq_set_inactive(struct iwl_trans *trans,
-					     u16 txq_id)
-{
-	/* Simply stop the queue, but don't change any configuration;
-	 * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
-	iwl_write_prph(trans,
-		SCD_QUEUE_STATUS_BITS(txq_id),
-		(0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
-		(1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
-}
-
 /* Receiver address (actually, Rx station's index into station table),
  * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
 #define BUILD_RAxTID(sta_id, tid)	(((sta_id) << 4) + (tid))
 
-void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
-			       int sta_id, int tid, int frame_limit, u16 ssn)
+void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
+			       const struct iwl_trans_txq_scd_cfg *cfg)
 {
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+	int fifo = -1;
 
 	if (test_and_set_bit(txq_id, trans_pcie->queue_used))
 		WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
 
-	/* Stop this Tx queue before configuring it */
-	iwl_pcie_txq_set_inactive(trans, txq_id);
+	if (cfg) {
+		fifo = cfg->fifo;
 
-	/* Set this queue as a chain-building queue unless it is CMD queue */
-	if (txq_id != trans_pcie->cmd_queue)
-		iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
+		/* Disable the scheduler prior configuring the cmd queue */
+		if (txq_id == trans_pcie->cmd_queue &&
+		    trans_pcie->scd_set_active)
+			iwl_scd_enable_set_active(trans, 0);
 
-	/* If this queue is mapped to a certain station: it is an AGG queue */
-	if (sta_id >= 0) {
-		u16 ra_tid = BUILD_RAxTID(sta_id, tid);
+		/* Stop this Tx queue before configuring it */
+		iwl_scd_txq_set_inactive(trans, txq_id);
 
-		/* Map receiver-address / traffic-ID to this queue */
-		iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id);
+		/* Set this queue as a chain-building queue unless it is CMD */
+		if (txq_id != trans_pcie->cmd_queue)
+			iwl_scd_txq_set_chain(trans, txq_id);
 
-		/* enable aggregations for the queue */
-		iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
-		trans_pcie->txq[txq_id].ampdu = true;
-	} else {
-		/*
-		 * disable aggregations for the queue, this will also make the
-		 * ra_tid mapping configuration irrelevant since it is now a
-		 * non-AGG queue.
-		 */
-		iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+		if (cfg->aggregate) {
+			u16 ra_tid = BUILD_RAxTID(cfg->sta_id, cfg->tid);
 
-		ssn = trans_pcie->txq[txq_id].q.read_ptr;
+			/* Map receiver-address / traffic-ID to this queue */
+			iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id);
+
+			/* enable aggregations for the queue */
+			iwl_scd_txq_enable_agg(trans, txq_id);
+			trans_pcie->txq[txq_id].ampdu = true;
+		} else {
+			/*
+			 * disable aggregations for the queue, this will also
+			 * make the ra_tid mapping configuration irrelevant
+			 * since it is now a non-AGG queue.
+			 */
+			iwl_scd_txq_disable_agg(trans, txq_id);
+
+			ssn = trans_pcie->txq[txq_id].q.read_ptr;
+		}
 	}
 
 	/* Place first TFD at index corresponding to start sequence number.
@@ -1128,32 +1117,44 @@
 	trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff);
 	trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff);
 
-	iwl_write_direct32(trans, HBUS_TARG_WRPTR,
-			   (ssn & 0xff) | (txq_id << 8));
-	iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
+	if (cfg) {
+		u8 frame_limit = cfg->frame_limit;
 
-	/* Set up Tx window size and frame limit for this queue */
-	iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
-			SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
-	iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
+		iwl_write_direct32(trans, HBUS_TARG_WRPTR,
+				   (ssn & 0xff) | (txq_id << 8));
+		iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
+
+		/* Set up Tx window size and frame limit for this queue */
+		iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
+				SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
+		iwl_trans_write_mem32(trans,
+			trans_pcie->scd_base_addr +
 			SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
 			((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-				SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+					SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
 			((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-				SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+					SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
 
-	/* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
-	iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
-		       (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
-		       (fifo << SCD_QUEUE_STTS_REG_POS_TXF) |
-		       (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
-		       SCD_QUEUE_STTS_REG_MSK);
+		/* Set up status area in SRAM, map to Tx DMA/FIFO, activate */
+		iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
+			       (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+			       (cfg->fifo << SCD_QUEUE_STTS_REG_POS_TXF) |
+			       (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
+			       SCD_QUEUE_STTS_REG_MSK);
+
+		/* enable the scheduler for this queue (only) */
+		if (txq_id == trans_pcie->cmd_queue &&
+		    trans_pcie->scd_set_active)
+			iwl_scd_enable_set_active(trans, BIT(txq_id));
+	}
+
 	trans_pcie->txq[txq_id].active = true;
 	IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n",
 			    txq_id, fifo, ssn & 0xff);
 }
 
-void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
+void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id,
+				bool configure_scd)
 {
 	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 	u32 stts_addr = trans_pcie->scd_base_addr +
@@ -1172,10 +1173,12 @@
 		return;
 	}
 
-	iwl_pcie_txq_set_inactive(trans, txq_id);
+	if (configure_scd) {
+		iwl_scd_txq_set_inactive(trans, txq_id);
 
-	iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
-			    ARRAY_SIZE(zero_val));
+		iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
+				    ARRAY_SIZE(zero_val));
+	}
 
 	iwl_pcie_txq_unmap(trans, txq_id);
 	trans_pcie->txq[txq_id].ampdu = false;
@@ -1406,7 +1409,7 @@
 
 	out_meta->flags = cmd->flags;
 	if (WARN_ON_ONCE(txq->entries[idx].free_buf))
-		kfree(txq->entries[idx].free_buf);
+		kzfree(txq->entries[idx].free_buf);
 	txq->entries[idx].free_buf = dup_buf;
 
 	trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr);
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 47a998d..34f09ef 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -590,7 +590,6 @@
 		int chan_no = -1;
 		const u8 *ssid = NULL;
 		u8 ssid_len = 0;
-		DECLARE_SSID_BUF(ssid_buf);
 
 		int len = get_unaligned_le16(pos);
 		pos += 2;
@@ -644,15 +643,14 @@
 			struct ieee80211_channel *channel =
 				ieee80211_get_channel(wiphy, freq);
 
-			lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %s, "
-				     "%d dBm\n",
-				     bssid, capa, chan_no,
-				     print_ssid(ssid_buf, ssid, ssid_len),
+			lbs_deb_scan("scan: %pM, capa %04x, chan %2d, %*pE, %d dBm\n",
+				     bssid, capa, chan_no, ssid_len, ssid,
 				     LBS_SCAN_RSSI_TO_MBM(rssi)/100);
 
 			if (channel &&
 			    !(channel->flags & IEEE80211_CHAN_DISABLED)) {
 				bss = cfg80211_inform_bss(wiphy, channel,
+					CFG80211_BSS_FTYPE_UNKNOWN,
 					bssid, get_unaligned_le64(tsfdesc),
 					capa, intvl, ie, ielen,
 					LBS_SCAN_RSSI_TO_MBM(rssi),
@@ -1353,7 +1351,7 @@
 		wait_event_interruptible_timeout(priv->scan_q,
 						 (priv->scan_req == NULL),
 						 (15 * HZ));
-		lbs_deb_assoc("assoc: scanning competed\n");
+		lbs_deb_assoc("assoc: scanning completed\n");
 	}
 
 	/* Find the BSS we want using available scan results */
@@ -1754,6 +1752,7 @@
 
 	bss = cfg80211_inform_bss(priv->wdev->wiphy,
 				  params->chandef.chan,
+				  CFG80211_BSS_FTYPE_UNKNOWN,
 				  bssid,
 				  0,
 				  capability,
@@ -1982,7 +1981,6 @@
 	struct lbs_private *priv = wiphy_priv(wiphy);
 	int ret = 0;
 	struct cfg80211_bss *bss;
-	DECLARE_SSID_BUF(ssid_buf);
 
 	if (dev == priv->mesh_dev)
 		return -EOPNOTSUPP;
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index 01a67f6..d0c881d 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -93,7 +93,6 @@
 {
 	struct cmd_ds_mesh_config cmd;
 	struct mrvl_meshie *ie;
-	DECLARE_SSID_BUF(ssid);
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.channel = cpu_to_le16(chan);
@@ -122,9 +121,9 @@
 	default:
 		return -1;
 	}
-	lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
-		    action, priv->mesh_tlv, chan,
-		    print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
+	lbs_deb_cmd("mesh config action %d type %x channel %d SSID %*pE\n",
+		    action, priv->mesh_tlv, chan, priv->mesh_ssid_len,
+		    priv->mesh_ssid);
 
 	return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
 }
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 088de9d..25c5acc 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -332,7 +332,7 @@
 
 err_prog_firmware:
 	priv->hw_reset_device(card);
-	lbtf_deb_leave_args(LBTF_DEB_MACOPS, "error programing fw; ret=%d", ret);
+	lbtf_deb_leave_args(LBTF_DEB_MACOPS, "error programming fw; ret=%d", ret);
 	return ret;
 }
 
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 67ad853..a3f2e06 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2045,8 +2045,6 @@
 
 	hw->flags = IEEE80211_HW_MFP_CAPABLE |
 		    IEEE80211_HW_SIGNAL_DBM |
-		    IEEE80211_HW_SUPPORTS_STATIC_SMPS |
-		    IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
 		    IEEE80211_HW_AMPDU_AGGREGATION |
 		    IEEE80211_HW_WANT_MONITOR_VIF |
 		    IEEE80211_HW_QUEUE_CONTROL |
@@ -2059,8 +2057,10 @@
 			    WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
 			    WIPHY_FLAG_AP_UAPSD |
 			    WIPHY_FLAG_HAS_CHANNEL_SWITCH;
-	hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
-	hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
+	hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
+			       NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
+			       NL80211_FEATURE_STATIC_SMPS |
+			       NL80211_FEATURE_DYNAMIC_SMPS;
 
 	/* ask mac80211 to reserve space for magic */
 	hw->vif_data_size = sizeof(struct hwsim_vif_priv);
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index 06a2c21..4005707 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -183,6 +183,15 @@
 	if (!tbl)
 		return;
 
+	spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
+	priv->adapter->rx_locked = true;
+	if (priv->adapter->rx_processing) {
+		spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
+		flush_workqueue(priv->adapter->rx_workqueue);
+	} else {
+		spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
+	}
+
 	start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1);
 	mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
 
@@ -194,6 +203,11 @@
 
 	kfree(tbl->rx_reorder_ptr);
 	kfree(tbl);
+
+	spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
+	priv->adapter->rx_locked = false;
+	spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
+
 }
 
 /*
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig
index 6e547a9..43e31bf 100644
--- a/drivers/net/wireless/mwifiex/Kconfig
+++ b/drivers/net/wireless/mwifiex/Kconfig
@@ -10,13 +10,13 @@
 	  mwifiex.
 
 config MWIFIEX_SDIO
-	tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8897"
+	tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8887/SD8897"
 	depends on m
 	depends on MWIFIEX && MMC
 	depends on FW_LOADER
 	---help---
 	  This adds support for wireless adapters based on Marvell
-	  8786/8787/8797 chipsets with SDIO interface.
+	  8786/8787/8797/8887/8897 chipsets with SDIO interface.
 
 	  If you choose to build it as a module, it will be called
 	  mwifiex_sdio.
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index e2e6bf1..0dd6729 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -246,7 +246,7 @@
 	}
 
 	if (priv->roc_cfg.cookie) {
-		wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llu\n",
+		wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llx\n",
 			  priv->roc_cfg.cookie);
 		return -EBUSY;
 	}
@@ -1557,6 +1557,7 @@
 						       band));
 
 	bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
+				  CFG80211_BSS_FTYPE_UNKNOWN,
 				  bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
 				  0, ie_buf, ie_len, 0, GFP_KERNEL);
 	cfg80211_put_bss(priv->wdev->wiphy, bss);
@@ -1935,13 +1936,6 @@
 
 	wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
 
-	if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
-	    atomic_read(&priv->wmm.tx_pkts_queued) >=
-	    MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN) {
-		dev_dbg(priv->adapter->dev, "scan rejected due to traffic\n");
-		return -EBUSY;
-	}
-
 	/* Block scan request if scan operation or scan cleanup when interface
 	 * is disabled is in process
 	 */
@@ -1980,7 +1974,7 @@
 		user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
 		user_scan_cfg->chan_list[i].radio_type = chan->band;
 
-		if (chan->flags & IEEE80211_CHAN_NO_IR)
+		if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids)
 			user_scan_cfg->chan_list[i].scan_type =
 						MWIFIEX_SCAN_TYPE_PASSIVE;
 		else
@@ -1990,6 +1984,11 @@
 		user_scan_cfg->chan_list[i].scan_time = 0;
 	}
 
+	if (priv->adapter->scan_chan_gap_enabled &&
+	    mwifiex_is_any_intf_active(priv))
+		user_scan_cfg->scan_chan_gap =
+					      priv->adapter->scan_chan_gap_time;
+
 	ret = mwifiex_scan_networks(priv, user_scan_cfg);
 	kfree(user_scan_cfg);
 	if (ret) {
@@ -2914,7 +2913,6 @@
 
 	wiphy->features |= NL80211_FEATURE_HT_IBSS |
 			   NL80211_FEATURE_INACTIVITY_TIMER |
-			   NL80211_FEATURE_LOW_PRIORITY_SCAN |
 			   NL80211_FEATURE_NEED_OBSS_SCAN;
 
 	/* Reserve space for mwifiex specific private data for BSS */
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index baf0aab..8559720 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -1470,7 +1470,7 @@
 	struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec;
 	struct mwifiex_adapter *adapter = priv->adapter;
 	struct mwifiex_ie_types_header *tlv;
-	struct hw_spec_fw_api_rev *api_rev;
+	struct hw_spec_api_rev *api_rev;
 	u16 resp_size, api_id;
 	int i, left_len, parsed_len = 0;
 
@@ -1538,23 +1538,30 @@
 		while (left_len > sizeof(struct mwifiex_ie_types_header)) {
 			tlv = (void *)&hw_spec->tlvs + parsed_len;
 			switch (le16_to_cpu(tlv->type)) {
-			case TLV_TYPE_FW_API_REV:
-				api_rev = (struct hw_spec_fw_api_rev *)tlv;
+			case TLV_TYPE_API_REV:
+				api_rev = (struct hw_spec_api_rev *)tlv;
 				api_id = le16_to_cpu(api_rev->api_id);
 				switch (api_id) {
 				case KEY_API_VER_ID:
-					adapter->fw_key_api_major_ver =
+					adapter->key_api_major_ver =
 							api_rev->major_ver;
-					adapter->fw_key_api_minor_ver =
+					adapter->key_api_minor_ver =
 							api_rev->minor_ver;
 					dev_dbg(adapter->dev,
-						"fw_key_api v%d.%d\n",
-						adapter->fw_key_api_major_ver,
-						adapter->fw_key_api_minor_ver);
+						"key_api v%d.%d\n",
+						adapter->key_api_major_ver,
+						adapter->key_api_minor_ver);
+					break;
+				case FW_API_VER_ID:
+					adapter->fw_api_ver =
+							api_rev->major_ver;
+					dev_dbg(adapter->dev,
+						"Firmware api version %d\n",
+						adapter->fw_api_ver);
 					break;
 				default:
 					dev_warn(adapter->dev,
-						 "Unknown FW api_id: %d\n",
+						 "Unknown api_id: %d\n",
 						 api_id);
 					break;
 				}
@@ -1567,7 +1574,8 @@
 			}
 			parsed_len += le16_to_cpu(tlv->len) +
 				      sizeof(struct mwifiex_ie_types_header);
-			left_len -= parsed_len;
+			left_len -= le16_to_cpu(tlv->len) +
+				      sizeof(struct mwifiex_ie_types_header);
 		}
 	}
 
@@ -1605,5 +1613,8 @@
 		adapter->if_ops.update_mp_end_port(adapter,
 					le16_to_cpu(hw_spec->mp_end_port));
 
+	if (adapter->fw_api_ver == MWIFIEX_FW_V15)
+		adapter->scan_chan_gap_enabled = true;
+
 	return 0;
 }
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index 097cb3f..9c054d2 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -48,8 +48,8 @@
 #define MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE        16
 #define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE   64
 #define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE   64
-#define MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE   48
-#define MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE   32
+#define MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE   64
+#define MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE   64
 
 #define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT  0xffff
 
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 49da2d5..1eb6173 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -83,7 +83,7 @@
 #define WPA_PN_SIZE		8
 #define KEY_PARAMS_FIXED_LEN	10
 #define KEY_INDEX_MASK		0xf
-#define FW_KEY_API_VER_MAJOR_V2	2
+#define KEY_API_VER_MAJOR_V2	2
 
 #define KEY_MCAST	BIT(0)
 #define KEY_UNICAST	BIT(1)
@@ -170,7 +170,8 @@
 #define TLV_TYPE_COALESCE_RULE      (PROPRIETARY_TLV_BASE_ID + 154)
 #define TLV_TYPE_KEY_PARAM_V2       (PROPRIETARY_TLV_BASE_ID + 156)
 #define TLV_TYPE_TDLS_IDLE_TIMEOUT  (PROPRIETARY_TLV_BASE_ID + 194)
-#define TLV_TYPE_FW_API_REV         (PROPRIETARY_TLV_BASE_ID + 199)
+#define TLV_TYPE_SCAN_CHANNEL_GAP   (PROPRIETARY_TLV_BASE_ID + 197)
+#define TLV_TYPE_API_REV            (PROPRIETARY_TLV_BASE_ID + 199)
 
 #define MWIFIEX_TX_DATA_BUF_SIZE_2K        2048
 
@@ -653,6 +654,12 @@
 	__le16 num_probes;
 } __packed;
 
+struct mwifiex_ie_types_scan_chan_gap {
+	struct mwifiex_ie_types_header header;
+	/* time gap in TUs to be used between two consecutive channels scan */
+	__le16 chan_gap;
+} __packed;
+
 struct mwifiex_ie_types_wildcard_ssid_params {
 	struct mwifiex_ie_types_header header;
 	u8 max_ssid_length;
@@ -844,11 +851,12 @@
 	} params;
 } __packed;
 
-enum FW_API_VER_ID {
+enum API_VER_ID {
 	KEY_API_VER_ID = 1,
+	FW_API_VER_ID = 2,
 };
 
-struct hw_spec_fw_api_rev {
+struct hw_spec_api_rev {
 	struct mwifiex_ie_types_header header;
 	__le16 api_id;
 	u8 major_ver;
@@ -1248,6 +1256,7 @@
 	u8 num_ssids;
 	/* Variable number (fixed maximum) of channels to scan up */
 	struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX];
+	u16 scan_chan_gap;
 } __packed;
 
 struct ie_body {
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 269a277..580aa45 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -212,6 +212,7 @@
 	adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME;
 	adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME;
 	adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME;
+	adapter->scan_chan_gap_time = MWIFIEX_DEF_SCAN_CHAN_GAP_TIME;
 
 	adapter->scan_probes = 1;
 
@@ -280,10 +281,9 @@
 	memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
 	adapter->arp_filter_size = 0;
 	adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
-	adapter->empty_tx_q_cnt = 0;
 	adapter->ext_scan = true;
-	adapter->fw_key_api_major_ver = 0;
-	adapter->fw_key_api_minor_ver = 0;
+	adapter->key_api_major_ver = 0;
+	adapter->key_api_minor_ver = 0;
 }
 
 /*
@@ -447,8 +447,10 @@
 	spin_lock_init(&adapter->cmd_free_q_lock);
 	spin_lock_init(&adapter->cmd_pending_q_lock);
 	spin_lock_init(&adapter->scan_pending_q_lock);
+	spin_lock_init(&adapter->rx_proc_lock);
 
 	skb_queue_head_init(&adapter->usb_rx_data_q);
+	skb_queue_head_init(&adapter->rx_data_q);
 
 	for (i = 0; i < adapter->priv_num; ++i) {
 		INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head);
@@ -614,6 +616,7 @@
 	int ret = -EINPROGRESS;
 	struct mwifiex_private *priv;
 	s32 i;
+	unsigned long flags;
 	struct sk_buff *skb;
 
 	/* mwifiex already shutdown */
@@ -648,6 +651,21 @@
 		}
 	}
 
+	spin_lock_irqsave(&adapter->rx_proc_lock, flags);
+
+	while ((skb = skb_dequeue(&adapter->rx_data_q))) {
+		struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+
+		atomic_dec(&adapter->rx_pending);
+		priv = adapter->priv[rx_info->bss_num];
+		if (priv)
+			priv->stats.rx_dropped++;
+
+		dev_kfree_skb_any(skb);
+	}
+
+	spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+
 	spin_lock(&adapter->mwifiex_lock);
 
 	if (adapter->if_ops.data_complete) {
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index c11e0ee..6044804 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -28,91 +28,6 @@
 static char *cal_data_cfg;
 module_param(cal_data_cfg, charp, 0);
 
-static void scan_delay_timer_fn(unsigned long data)
-{
-	struct mwifiex_private *priv = (struct mwifiex_private *)data;
-	struct mwifiex_adapter *adapter = priv->adapter;
-	struct cmd_ctrl_node *cmd_node, *tmp_node;
-	spinlock_t *scan_q_lock = &adapter->scan_pending_q_lock;
-	unsigned long flags;
-
-	if (adapter->surprise_removed)
-		return;
-
-	if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT ||
-	    !adapter->scan_processing) {
-		/*
-		 * Abort scan operation by cancelling all pending scan
-		 * commands
-		 */
-		spin_lock_irqsave(scan_q_lock, flags);
-		list_for_each_entry_safe(cmd_node, tmp_node,
-					 &adapter->scan_pending_q, list) {
-			list_del(&cmd_node->list);
-			mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
-		}
-		spin_unlock_irqrestore(scan_q_lock, flags);
-
-		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
-		adapter->scan_processing = false;
-		adapter->scan_delay_cnt = 0;
-		adapter->empty_tx_q_cnt = 0;
-		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
-
-		if (priv->scan_request) {
-			dev_dbg(adapter->dev, "info: aborting scan\n");
-			cfg80211_scan_done(priv->scan_request, 1);
-			priv->scan_request = NULL;
-		} else {
-			priv->scan_aborting = false;
-			dev_dbg(adapter->dev, "info: scan already aborted\n");
-		}
-		goto done;
-	}
-
-	if (!atomic_read(&priv->adapter->is_tx_received)) {
-		adapter->empty_tx_q_cnt++;
-		if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) {
-			/*
-			 * No Tx traffic for 200msec. Get scan command from
-			 * scan pending queue and put to cmd pending queue to
-			 * resume scan operation
-			 */
-			adapter->scan_delay_cnt = 0;
-			adapter->empty_tx_q_cnt = 0;
-			spin_lock_irqsave(scan_q_lock, flags);
-
-			if (list_empty(&adapter->scan_pending_q)) {
-				spin_unlock_irqrestore(scan_q_lock, flags);
-				goto done;
-			}
-
-			cmd_node = list_first_entry(&adapter->scan_pending_q,
-						    struct cmd_ctrl_node, list);
-			list_del(&cmd_node->list);
-			spin_unlock_irqrestore(scan_q_lock, flags);
-
-			mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
-							true);
-			queue_work(adapter->workqueue, &adapter->main_work);
-			goto done;
-		}
-	} else {
-		adapter->empty_tx_q_cnt = 0;
-	}
-
-	/* Delay scan operation further by 20msec */
-	mod_timer(&priv->scan_delay_timer, jiffies +
-		  msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
-	adapter->scan_delay_cnt++;
-
-done:
-	if (atomic_read(&priv->adapter->is_tx_received))
-		atomic_set(&priv->adapter->is_tx_received, false);
-
-	return;
-}
-
 /*
  * This function registers the device and performs all the necessary
  * initializations.
@@ -160,10 +75,6 @@
 
 		adapter->priv[i]->adapter = adapter;
 		adapter->priv_num++;
-
-		setup_timer(&adapter->priv[i]->scan_delay_timer,
-			    scan_delay_timer_fn,
-			    (unsigned long)adapter->priv[i]);
 	}
 	mwifiex_init_lock_list(adapter);
 
@@ -207,7 +118,6 @@
 	for (i = 0; i < adapter->priv_num; i++) {
 		if (adapter->priv[i]) {
 			mwifiex_free_curr_bcn(adapter->priv[i]);
-			del_timer_sync(&adapter->priv[i]->scan_delay_timer);
 			kfree(adapter->priv[i]);
 		}
 	}
@@ -216,6 +126,38 @@
 	return 0;
 }
 
+static int mwifiex_process_rx(struct mwifiex_adapter *adapter)
+{
+	unsigned long flags;
+	struct sk_buff *skb;
+
+	spin_lock_irqsave(&adapter->rx_proc_lock, flags);
+	if (adapter->rx_processing || adapter->rx_locked) {
+		spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+		goto exit_rx_proc;
+	} else {
+		adapter->rx_processing = true;
+		spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+	}
+
+	/* Check for Rx data */
+	while ((skb = skb_dequeue(&adapter->rx_data_q))) {
+		atomic_dec(&adapter->rx_pending);
+		if (adapter->delay_main_work &&
+		    (atomic_read(&adapter->rx_pending) < LOW_RX_PENDING)) {
+			adapter->delay_main_work = false;
+			queue_work(adapter->workqueue, &adapter->main_work);
+		}
+		mwifiex_handle_rx_packet(adapter, skb);
+	}
+	spin_lock_irqsave(&adapter->rx_proc_lock, flags);
+	adapter->rx_processing = false;
+	spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
+
+exit_rx_proc:
+	return 0;
+}
+
 /*
  * The main process.
  *
@@ -253,6 +195,19 @@
 		    (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY))
 			break;
 
+		/* If we process interrupts first, it would increase RX pending
+		 * even further. Avoid this by checking if rx_pending has
+		 * crossed high threshold and schedule rx work queue
+		 * and then process interrupts
+		 */
+		if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING) {
+			adapter->delay_main_work = true;
+			if (!adapter->rx_processing)
+				queue_work(adapter->rx_workqueue,
+					   &adapter->rx_work);
+			break;
+		}
+
 		/* Handle pending interrupt if any */
 		if (adapter->int_status) {
 			if (adapter->hs_activated)
@@ -261,6 +216,9 @@
 				adapter->if_ops.process_int_status(adapter);
 		}
 
+		if (adapter->rx_work_enabled && adapter->data_received)
+			queue_work(adapter->rx_workqueue, &adapter->rx_work);
+
 		/* Need to wake up the card ? */
 		if ((adapter->ps_state == PS_STATE_SLEEP) &&
 		    (adapter->pm_wakeup_card_req &&
@@ -273,6 +231,7 @@
 		}
 
 		if (IS_CARD_RX_RCVD(adapter)) {
+			adapter->data_received = false;
 			adapter->pm_wakeup_fw_try = false;
 			if (adapter->ps_state == PS_STATE_SLEEP)
 				adapter->ps_state = PS_STATE_AWAKE;
@@ -284,8 +243,8 @@
 			    adapter->tx_lock_flag)
 				break;
 
-			if ((adapter->scan_processing &&
-			     !adapter->scan_delay_cnt) || adapter->data_sent ||
+			if ((!adapter->scan_chan_gap_enabled &&
+			     adapter->scan_processing) || adapter->data_sent ||
 			    mwifiex_wmm_lists_empty(adapter)) {
 				if (adapter->cmd_sent || adapter->curr_cmd ||
 				    (!is_command_pending(adapter)))
@@ -339,7 +298,8 @@
 			}
 		}
 
-		if ((!adapter->scan_processing || adapter->scan_delay_cnt) &&
+		if ((adapter->scan_chan_gap_enabled ||
+		     !adapter->scan_processing) &&
 		    !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) {
 			mwifiex_wmm_process_tx(adapter);
 			if (adapter->hs_activated) {
@@ -366,7 +326,8 @@
 	} while (true);
 
 	spin_lock_irqsave(&adapter->main_proc_lock, flags);
-	if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter)) {
+	if (!adapter->delay_main_work &&
+	    (adapter->int_status || IS_CARD_RX_RCVD(adapter))) {
 		spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
 		goto process_start;
 	}
@@ -407,6 +368,12 @@
 	flush_workqueue(adapter->workqueue);
 	destroy_workqueue(adapter->workqueue);
 	adapter->workqueue = NULL;
+
+	if (adapter->rx_workqueue) {
+		flush_workqueue(adapter->rx_workqueue);
+		destroy_workqueue(adapter->rx_workqueue);
+		adapter->rx_workqueue = NULL;
+	}
 }
 
 /*
@@ -598,9 +565,6 @@
 	atomic_inc(&priv->adapter->tx_pending);
 	mwifiex_wmm_add_buf_txqueue(priv, skb);
 
-	if (priv->adapter->scan_delay_cnt)
-		atomic_set(&priv->adapter->is_tx_received, true);
-
 	queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
 
 	return 0;
@@ -834,6 +798,21 @@
 }
 
 /*
+ * This is the RX work queue function.
+ *
+ * It handles the RX operations.
+ */
+static void mwifiex_rx_work_queue(struct work_struct *work)
+{
+	struct mwifiex_adapter *adapter =
+		container_of(work, struct mwifiex_adapter, rx_work);
+
+	if (adapter->surprise_removed)
+		return;
+	mwifiex_process_rx(adapter);
+}
+
+/*
  * This is the main work queue function.
  *
  * It handles the main process, which in turn handles the complete
@@ -889,6 +868,11 @@
 	adapter->cmd_wait_q.status = 0;
 	adapter->scan_wait_q_woken = false;
 
+	if (num_possible_cpus() > 1) {
+		adapter->rx_work_enabled = true;
+		pr_notice("rx work enabled, cpus %d\n", num_possible_cpus());
+	}
+
 	adapter->workqueue =
 		alloc_workqueue("MWIFIEX_WORK_QUEUE",
 				WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
@@ -896,6 +880,18 @@
 		goto err_kmalloc;
 
 	INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
+
+	if (adapter->rx_work_enabled) {
+		adapter->rx_workqueue = alloc_workqueue("MWIFIEX_RX_WORK_QUEUE",
+							WQ_HIGHPRI |
+							WQ_MEM_RECLAIM |
+							WQ_UNBOUND, 1);
+		if (!adapter->rx_workqueue)
+			goto err_kmalloc;
+
+		INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue);
+	}
+
 	if (adapter->if_ops.iface_work)
 		INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work);
 
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index a2733b1..e263574 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -58,6 +58,9 @@
 #define MAX_TX_PENDING      100
 #define LOW_TX_PENDING      80
 
+#define HIGH_RX_PENDING     50
+#define LOW_RX_PENDING      20
+
 #define MWIFIEX_UPLD_SIZE               (2312)
 
 #define MAX_EVENT_SIZE                  2048
@@ -84,17 +87,12 @@
 #define MWIFIEX_PASSIVE_SCAN_CHAN_TIME	110
 #define MWIFIEX_ACTIVE_SCAN_CHAN_TIME	30
 #define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME	30
+#define MWIFIEX_DEF_SCAN_CHAN_GAP_TIME  50
 
 #define SCAN_RSSI(RSSI)					(0x100 - ((u8)(RSSI)))
 
 #define MWIFIEX_MAX_TOTAL_SCAN_TIME	(MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
 
-#define MWIFIEX_MAX_SCAN_DELAY_CNT			50
-#define MWIFIEX_MAX_EMPTY_TX_Q_CNT			10
-#define MWIFIEX_SCAN_DELAY_MSEC				20
-
-#define MWIFIEX_MIN_TX_PENDING_TO_CANCEL_SCAN		2
-
 #define RSN_GTK_OUI_OFFSET				2
 
 #define MWIFIEX_OUI_NOT_PRESENT			0
@@ -415,6 +413,7 @@
 #define FW_DUMP_MAX_NAME_LEN		8
 #define FW_DUMP_HOST_READY		0xEE
 #define FW_DUMP_DONE			0xFF
+#define FW_DUMP_READ_DONE		0xFE
 
 struct memory_type_mapping {
 	u8 mem_name[FW_DUMP_MAX_NAME_LEN];
@@ -547,7 +546,6 @@
 	u8 nick_name[16];
 	u16 current_key_index;
 	struct semaphore async_sem;
-	u8 report_scan_result;
 	struct cfg80211_scan_request *scan_request;
 	u8 cfg_bssid[6];
 	struct wps wps;
@@ -561,7 +559,6 @@
 	u16 proberesp_idx;
 	u16 assocresp_idx;
 	u16 rsn_idx;
-	struct timer_list scan_delay_timer;
 	u8 ap_11n_enabled;
 	u8 ap_11ac_enabled;
 	u32 mgmt_frame_mask;
@@ -721,6 +718,12 @@
 	atomic_t cmd_pending;
 	struct workqueue_struct *workqueue;
 	struct work_struct main_work;
+	struct workqueue_struct *rx_workqueue;
+	struct work_struct rx_work;
+	bool rx_work_enabled;
+	bool rx_processing;
+	bool delay_main_work;
+	bool rx_locked;
 	struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM];
 	/* spin lock for init/shutdown */
 	spinlock_t mwifiex_lock;
@@ -761,6 +764,8 @@
 	struct list_head scan_pending_q;
 	/* spin lock for scan_pending_q */
 	spinlock_t scan_pending_q_lock;
+	/* spin lock for RX processing routine */
+	spinlock_t rx_proc_lock;
 	struct sk_buff_head usb_rx_data_q;
 	u32 scan_processing;
 	u16 region_code;
@@ -770,6 +775,7 @@
 	u16 specific_scan_time;
 	u16 active_scan_time;
 	u16 passive_scan_time;
+	u16 scan_chan_gap_time;
 	u8 fw_bands;
 	u8 adhoc_start_band;
 	u8 config_bands;
@@ -815,8 +821,6 @@
 	spinlock_t queue_lock;		/* lock for tx queues */
 	u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
 	u16 max_mgmt_ie_index;
-	u8 scan_delay_cnt;
-	u8 empty_tx_q_cnt;
 	const struct firmware *cal_data;
 	struct device_node *dt_node;
 
@@ -828,17 +832,18 @@
 	u32 usr_dot_11ac_dev_cap_a;
 	u32 usr_dot_11ac_mcs_support;
 
-	atomic_t is_tx_received;
 	atomic_t pending_bridged_pkts;
 	struct semaphore *card_sem;
 	bool ext_scan;
 	u8 fw_api_ver;
-	u8 fw_key_api_major_ver, fw_key_api_minor_ver;
+	u8 key_api_major_ver, key_api_minor_ver;
 	struct work_struct iface_work;
 	unsigned long iface_work_flags;
 	struct memory_type_mapping *mem_type_mapping_tbl;
 	u8 num_mem_types;
 	u8 curr_mem_idx;
+	bool scan_chan_gap_enabled;
+	struct sk_buff_head rx_data_q;
 };
 
 int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -1139,6 +1144,25 @@
 	return priv->csa_chan;
 }
 
+static inline u8 mwifiex_is_any_intf_active(struct mwifiex_private *priv)
+{
+	struct mwifiex_private *priv_num;
+	int i;
+
+	for (i = 0; i < priv->adapter->priv_num; i++) {
+		priv_num = priv->adapter->priv[i];
+		if (priv_num) {
+			if ((GET_BSS_ROLE(priv_num) == MWIFIEX_BSS_ROLE_UAP &&
+			     priv_num->bss_started) ||
+			    (GET_BSS_ROLE(priv_num) == MWIFIEX_BSS_ROLE_STA &&
+			     priv_num->media_connected))
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
 int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
 			     u32 func_init_shutdown);
 int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8);
@@ -1274,6 +1298,7 @@
 bool mwifiex_is_bss_in_11ac_mode(struct mwifiex_private *priv);
 u8 mwifiex_get_center_freq_index(struct mwifiex_private *priv, u8 band,
 				 u32 pri_chan, u8 chan_bw);
+int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter);
 
 #ifdef CONFIG_DEBUG_FS
 void mwifiex_debugfs_init(void);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index ff05458..c3a20f9 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -42,6 +42,10 @@
 	{"DTCM", NULL, 0, 0xF1},
 	{"SQRAM", NULL, 0, 0xF2},
 	{"IRAM", NULL, 0, 0xF3},
+	{"APU", NULL, 0, 0xF4},
+	{"CIU", NULL, 0, 0xF5},
+	{"ICU", NULL, 0, 0xF6},
+	{"MAC", NULL, 0, 0xF7},
 };
 
 static int
@@ -1271,12 +1275,26 @@
 		 */
 		pkt_len = *((__le16 *)skb_data->data);
 		rx_len = le16_to_cpu(pkt_len);
-		skb_put(skb_data, rx_len);
-		dev_dbg(adapter->dev,
-			"info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
-			card->rxbd_rdptr, wrptr, rx_len);
-		skb_pull(skb_data, INTF_HEADER_LEN);
-		mwifiex_handle_rx_packet(adapter, skb_data);
+		if (WARN_ON(rx_len <= INTF_HEADER_LEN ||
+			    rx_len > MWIFIEX_RX_DATA_BUF_SIZE)) {
+			dev_err(adapter->dev,
+				"Invalid RX len %d, Rd=%#x, Wr=%#x\n",
+				rx_len, card->rxbd_rdptr, wrptr);
+			dev_kfree_skb_any(skb_data);
+		} else {
+			skb_put(skb_data, rx_len);
+			dev_dbg(adapter->dev,
+				"info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
+				card->rxbd_rdptr, wrptr, rx_len);
+			skb_pull(skb_data, INTF_HEADER_LEN);
+			if (adapter->rx_work_enabled) {
+				skb_queue_tail(&adapter->rx_data_q, skb_data);
+				adapter->data_received = true;
+				atomic_inc(&adapter->rx_pending);
+			} else {
+				mwifiex_handle_rx_packet(adapter, skb_data);
+			}
+		}
 
 		skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
 		if (!skb_tmp) {
@@ -1718,6 +1736,13 @@
 		   buffer is released. This is just to make things simpler,
 		   we need to find a better method of managing these buffers.
 		*/
+	} else {
+		if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+				      CPU_INTR_EVENT_DONE)) {
+			dev_warn(adapter->dev,
+				 "Write register failed\n");
+			return -1;
+		}
 	}
 
 	return 0;
@@ -2218,8 +2243,8 @@
 		if (ctrl_data != FW_DUMP_HOST_READY) {
 			dev_info(adapter->dev,
 				 "The ctrl reg was changed, re-try again!\n");
-			mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
-					  FW_DUMP_HOST_READY);
+			ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
+						FW_DUMP_HOST_READY);
 			if (ret) {
 				dev_err(adapter->dev, "PCIE write err\n");
 				return RDWR_STATUS_FAILURE;
@@ -2241,6 +2266,7 @@
 	u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0;
 	enum rdwr_status stat;
 	u32 memory_size;
+	int ret;
 	static char *env[] = { "DRIVER=mwifiex_pcie", "EVENT=fw_dump", NULL };
 
 	if (!card->pcie.supports_fw_dump)
@@ -2284,6 +2310,12 @@
 
 		if (memory_size == 0) {
 			dev_info(adapter->dev, "Firmware dump Finished!\n");
+			ret = mwifiex_write_reg(adapter, creg->fw_dump_ctrl,
+						FW_DUMP_READ_DONE);
+			if (ret) {
+				dev_err(adapter->dev, "PCIE write err\n");
+				goto done;
+			}
 			break;
 		}
 
@@ -2312,11 +2344,13 @@
 			reg_end = creg->fw_dump_end;
 			for (reg = reg_start; reg <= reg_end; reg++) {
 				mwifiex_read_reg_byte(adapter, reg, dbg_ptr);
-				if (dbg_ptr < end_ptr)
+				if (dbg_ptr < end_ptr) {
 					dbg_ptr++;
-				else
+				} else {
 					dev_err(adapter->dev,
 						"Allocated buf not enough\n");
+					goto done;
+				}
 			}
 
 			if (stat != RDWR_STATUS_DONE)
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h
index a1a8fd3..200e8b0 100644
--- a/drivers/net/wireless/mwifiex/pcie.h
+++ b/drivers/net/wireless/mwifiex/pcie.h
@@ -40,8 +40,8 @@
 #define MWIFIEX_TXBD_MASK			0x3F
 #define MWIFIEX_RXBD_MASK			0x3F
 
-#define MWIFIEX_MAX_EVT_BD			0x04
-#define MWIFIEX_EVTBD_MASK			0x07
+#define MWIFIEX_MAX_EVT_BD			0x08
+#define MWIFIEX_EVTBD_MASK			0x0f
 
 /* PCIE INTERNAL REGISTERS */
 #define PCIE_SCRATCH_0_REG				0xC10
@@ -69,6 +69,7 @@
 #define CPU_INTR_DOOR_BELL				BIT(1)
 #define CPU_INTR_SLEEP_CFM_DONE			BIT(2)
 #define CPU_INTR_RESET					BIT(3)
+#define CPU_INTR_EVENT_DONE				BIT(5)
 
 #define HOST_INTR_DNLD_DONE				BIT(0)
 #define HOST_INTR_UPLD_RDY				BIT(1)
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index dee717a..ca64d4c 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -799,6 +799,7 @@
 {
 	struct mwifiex_adapter *adapter = priv->adapter;
 	struct mwifiex_ie_types_num_probes *num_probes_tlv;
+	struct mwifiex_ie_types_scan_chan_gap *chan_gap_tlv;
 	struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
 	struct mwifiex_ie_types_bssid_list *bssid_tlv;
 	u8 *tlv_pos;
@@ -925,6 +926,23 @@
 		if ((i && ssid_filter) ||
 		    !is_zero_ether_addr(scan_cfg_out->specific_bssid))
 			*filtered_scan = true;
+
+		if (user_scan_in->scan_chan_gap) {
+			dev_dbg(adapter->dev, "info: scan: channel gap = %d\n",
+				user_scan_in->scan_chan_gap);
+			*max_chan_per_scan =
+					MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+
+			chan_gap_tlv = (void *)tlv_pos;
+			chan_gap_tlv->header.type =
+					 cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP);
+			chan_gap_tlv->header.len =
+				    cpu_to_le16(sizeof(chan_gap_tlv->chan_gap));
+			chan_gap_tlv->chan_gap =
+				     cpu_to_le16((user_scan_in->scan_chan_gap));
+			tlv_pos +=
+				  sizeof(struct mwifiex_ie_types_scan_chan_gap);
+		}
 	} else {
 		scan_cfg_out->bss_mode = (u8) adapter->scan_mode;
 		num_probes = adapter->scan_probes;
@@ -1050,12 +1068,6 @@
 							    *filtered_scan);
 	}
 
-	/*
-	 * In associated state we will reduce the number of channels scanned per
-	 * scan command to 1 to avoid any traffic delay/loss.
-	 */
-	if (priv->media_connected)
-			*max_chan_per_scan = 1;
 }
 
 /*
@@ -1719,7 +1731,8 @@
 
 		if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
 			bss = cfg80211_inform_bss(priv->wdev->wiphy,
-					    chan, bssid, timestamp,
+					    chan, CFG80211_BSS_FTYPE_UNKNOWN,
+					    bssid, timestamp,
 					    cap_info_bitmap, beacon_period,
 					    ie_buf, ie_len, rssi, GFP_KERNEL);
 			bss_priv = (struct mwifiex_bss_priv *)bss->priv;
@@ -1754,7 +1767,7 @@
 static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
 {
 	struct mwifiex_adapter *adapter = priv->adapter;
-	struct cmd_ctrl_node *cmd_node;
+	struct cmd_ctrl_node *cmd_node, *tmp_node;
 	unsigned long flags;
 
 	spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
@@ -1767,9 +1780,6 @@
 		if (!adapter->ext_scan)
 			mwifiex_complete_scan(priv);
 
-		if (priv->report_scan_result)
-			priv->report_scan_result = false;
-
 		if (priv->scan_request) {
 			dev_dbg(adapter->dev, "info: notifying scan done\n");
 			cfg80211_scan_done(priv->scan_request, 0);
@@ -1778,37 +1788,36 @@
 			priv->scan_aborting = false;
 			dev_dbg(adapter->dev, "info: scan already aborted\n");
 		}
-	} else {
-		if ((priv->scan_aborting && !priv->scan_request) ||
-		    priv->scan_block) {
-			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
-					       flags);
-			adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT;
-			mod_timer(&priv->scan_delay_timer, jiffies);
-			dev_dbg(priv->adapter->dev,
-				"info: %s: triggerring scan abort\n", __func__);
-		} else if (!mwifiex_wmm_lists_empty(adapter) &&
-			   (priv->scan_request && (priv->scan_request->flags &
-					    NL80211_SCAN_FLAG_LOW_PRIORITY))) {
-			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
-					       flags);
-			adapter->scan_delay_cnt = 1;
-			mod_timer(&priv->scan_delay_timer, jiffies +
-				  msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
-			dev_dbg(priv->adapter->dev,
-				"info: %s: deferring scan\n", __func__);
-		} else {
-			/* Get scan command from scan_pending_q and put to
-			 * cmd_pending_q
-			 */
-			cmd_node = list_first_entry(&adapter->scan_pending_q,
-						    struct cmd_ctrl_node, list);
+	} else if ((priv->scan_aborting && !priv->scan_request) ||
+		   priv->scan_block) {
+		list_for_each_entry_safe(cmd_node, tmp_node,
+					 &adapter->scan_pending_q, list) {
 			list_del(&cmd_node->list);
-			spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
-					       flags);
-			mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
-							true);
+			mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
 		}
+		spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+		adapter->scan_processing = false;
+		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+		if (priv->scan_request) {
+			dev_dbg(adapter->dev, "info: aborting scan\n");
+			cfg80211_scan_done(priv->scan_request, 1);
+			priv->scan_request = NULL;
+		} else {
+			priv->scan_aborting = false;
+			dev_dbg(adapter->dev, "info: scan already aborted\n");
+		}
+	} else {
+		/* Get scan command from scan_pending_q and put to
+		 * cmd_pending_q
+		 */
+		cmd_node = list_first_entry(&adapter->scan_pending_q,
+					    struct cmd_ctrl_node, list);
+		list_del(&cmd_node->list);
+		spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+		mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
 	}
 
 	return;
@@ -1970,9 +1979,34 @@
 /* This function handles the command response of extended scan */
 int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv)
 {
+	struct mwifiex_adapter *adapter = priv->adapter;
+	struct host_cmd_ds_command *cmd_ptr;
+	struct cmd_ctrl_node *cmd_node;
+	unsigned long cmd_flags, scan_flags;
+	bool complete_scan = false;
+
 	dev_dbg(priv->adapter->dev, "info: EXT scan returns successfully\n");
 
-	mwifiex_complete_scan(priv);
+	spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_flags);
+	spin_lock_irqsave(&adapter->scan_pending_q_lock, scan_flags);
+	if (list_empty(&adapter->scan_pending_q)) {
+		complete_scan = true;
+		list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) {
+			cmd_ptr = (void *)cmd_node->cmd_skb->data;
+			if (le16_to_cpu(cmd_ptr->command) ==
+			    HostCmd_CMD_802_11_SCAN_EXT) {
+				dev_dbg(priv->adapter->dev,
+					"Scan pending in command pending list");
+				complete_scan = false;
+				break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&adapter->scan_pending_q_lock, scan_flags);
+	spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, cmd_flags);
+
+	if (complete_scan)
+		mwifiex_complete_scan(priv);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index 3029873..78e36e5 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -279,6 +279,8 @@
 #define SDIO_DEVICE_ID_MARVELL_8797   (0x9129)
 /* Device ID for SD8897 */
 #define SDIO_DEVICE_ID_MARVELL_8897   (0x912d)
+/* Device ID for SD8887 */
+#define SDIO_DEVICE_ID_MARVELL_8887   (0x9135)
 
 /* WLAN IDs */
 static const struct sdio_device_id mwifiex_ids[] = {
@@ -290,6 +292,8 @@
 		.driver_data = (unsigned long) &mwifiex_sdio_sd8797},
 	{SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8897),
 		.driver_data = (unsigned long) &mwifiex_sdio_sd8897},
+	{SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887),
+		.driver_data = (unsigned long)&mwifiex_sdio_sd8887},
 	{},
 };
 
@@ -448,28 +452,31 @@
 static int mwifiex_init_sdio_new_mode(struct mwifiex_adapter *adapter)
 {
 	u8 reg;
+	struct sdio_mmc_card *card = adapter->card;
 
 	adapter->ioport = MEM_PORT;
 
 	/* enable sdio new mode */
-	if (mwifiex_read_reg(adapter, CARD_CONFIG_2_1_REG, &reg))
+	if (mwifiex_read_reg(adapter, card->reg->card_cfg_2_1_reg, &reg))
 		return -1;
-	if (mwifiex_write_reg(adapter, CARD_CONFIG_2_1_REG,
+	if (mwifiex_write_reg(adapter, card->reg->card_cfg_2_1_reg,
 			      reg | CMD53_NEW_MODE))
 		return -1;
 
 	/* Configure cmd port and enable reading rx length from the register */
-	if (mwifiex_read_reg(adapter, CMD_CONFIG_0, &reg))
+	if (mwifiex_read_reg(adapter, card->reg->cmd_cfg_0, &reg))
 		return -1;
-	if (mwifiex_write_reg(adapter, CMD_CONFIG_0, reg | CMD_PORT_RD_LEN_EN))
+	if (mwifiex_write_reg(adapter, card->reg->cmd_cfg_0,
+			      reg | CMD_PORT_RD_LEN_EN))
 		return -1;
 
 	/* Enable Dnld/Upld ready auto reset for cmd port after cmd53 is
 	 * completed
 	 */
-	if (mwifiex_read_reg(adapter, CMD_CONFIG_1, &reg))
+	if (mwifiex_read_reg(adapter, card->reg->cmd_cfg_1, &reg))
 		return -1;
-	if (mwifiex_write_reg(adapter, CMD_CONFIG_1, reg | CMD_PORT_AUTO_EN))
+	if (mwifiex_write_reg(adapter, card->reg->cmd_cfg_1,
+			      reg | CMD_PORT_AUTO_EN))
 		return -1;
 
 	return 0;
@@ -496,17 +503,17 @@
 	}
 
 	/* Read the IO port */
-	if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, &reg))
+	if (!mwifiex_read_reg(adapter, card->reg->io_port_0_reg, &reg))
 		adapter->ioport |= (reg & 0xff);
 	else
 		return -1;
 
-	if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, &reg))
+	if (!mwifiex_read_reg(adapter, card->reg->io_port_1_reg, &reg))
 		adapter->ioport |= ((reg & 0xff) << 8);
 	else
 		return -1;
 
-	if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, &reg))
+	if (!mwifiex_read_reg(adapter, card->reg->io_port_2_reg, &reg))
 		adapter->ioport |= ((reg & 0xff) << 16);
 	else
 		return -1;
@@ -514,8 +521,8 @@
 	pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport);
 
 	/* Set Host interrupt reset to read to clear */
-	if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, &reg))
-		mwifiex_write_reg(adapter, HOST_INT_RSR_REG,
+	if (!mwifiex_read_reg(adapter, card->reg->host_int_rsr_reg, &reg))
+		mwifiex_write_reg(adapter, card->reg->host_int_rsr_reg,
 				  reg | card->reg->sdio_int_mask);
 	else
 		return -1;
@@ -622,22 +629,15 @@
 
 	dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%08x\n", wr_bitmap);
 
-	if (card->supports_sdio_new_mode &&
-	    !(wr_bitmap & reg->data_port_mask)) {
+	if (!(wr_bitmap & card->mp_data_port_mask)) {
 		adapter->data_sent = true;
 		return -EBUSY;
-	} else if (!card->supports_sdio_new_mode &&
-		   !(wr_bitmap & card->mp_data_port_mask)) {
-		return -1;
 	}
 
 	if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) {
 		card->mp_wr_bitmap &= (u32) (~(1 << card->curr_wr_port));
 		*port = card->curr_wr_port;
-		if (((card->supports_sdio_new_mode) &&
-		     (++card->curr_wr_port == card->max_ports)) ||
-		    ((!card->supports_sdio_new_mode) &&
-		     (++card->curr_wr_port == card->mp_end_port)))
+		if (++card->curr_wr_port == card->mp_end_port)
 			card->curr_wr_port = reg->start_wr_port;
 	} else {
 		adapter->data_sent = true;
@@ -715,7 +715,7 @@
 	struct sdio_func *func = card->func;
 
 	sdio_claim_host(func);
-	mwifiex_write_reg_locked(func, HOST_INT_MASK_REG, 0);
+	mwifiex_write_reg_locked(func, card->reg->host_int_mask_reg, 0);
 	sdio_release_irq(func);
 	sdio_release_host(func);
 }
@@ -736,7 +736,7 @@
 		return;
 	}
 
-	sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG];
+	sdio_ireg = card->mp_regs[card->reg->host_int_status_reg];
 	if (sdio_ireg) {
 		/*
 		 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
@@ -801,7 +801,7 @@
 	}
 
 	/* Simply write the mask to the register */
-	ret = mwifiex_write_reg_locked(func, HOST_INT_MASK_REG,
+	ret = mwifiex_write_reg_locked(func, card->reg->host_int_mask_reg,
 				       card->reg->host_int_enable);
 	if (ret) {
 		dev_err(adapter->dev, "enable host interrupt failed\n");
@@ -1055,7 +1055,13 @@
 	switch (upld_typ) {
 	case MWIFIEX_TYPE_DATA:
 		dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n");
-		mwifiex_handle_rx_packet(adapter, skb);
+		if (adapter->rx_work_enabled) {
+			skb_queue_tail(&adapter->rx_data_q, skb);
+			adapter->data_received = true;
+			atomic_inc(&adapter->rx_pending);
+		} else {
+			mwifiex_handle_rx_packet(adapter, skb);
+		}
 		break;
 
 	case MWIFIEX_TYPE_CMD:
@@ -1335,8 +1341,8 @@
 		u32 pkt_type;
 
 		/* read the len of control packet */
-		rx_len = card->mp_regs[CMD_RD_LEN_1] << 8;
-		rx_len |= (u16) card->mp_regs[CMD_RD_LEN_0];
+		rx_len = card->mp_regs[reg->cmd_rd_len_1] << 8;
+		rx_len |= (u16)card->mp_regs[reg->cmd_rd_len_0];
 		rx_blocks = DIV_ROUND_UP(rx_len, MWIFIEX_SDIO_BLOCK_SIZE);
 		if (rx_len <= INTF_HEADER_LEN ||
 		    (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
@@ -1527,8 +1533,7 @@
 			__func__);
 
 		if (MP_TX_AGGR_IN_PROGRESS(card)) {
-			if (!mp_tx_aggr_port_limit_reached(card) &&
-			    MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) {
+			if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) {
 				f_precopy_cur_buf = 1;
 
 				if (!(card->mp_wr_bitmap &
@@ -1540,8 +1545,7 @@
 				/* No room in Aggr buf, send it */
 				f_send_aggr_buf = 1;
 
-				if (mp_tx_aggr_port_limit_reached(card) ||
-				    !(card->mp_wr_bitmap &
+				if (!(card->mp_wr_bitmap &
 				      (1 << card->curr_wr_port)))
 					f_send_cur_buf = 1;
 				else
@@ -1826,11 +1830,11 @@
 	sdio_set_drvdata(card->func, card);
 
 	/*
-	 * Read the HOST_INT_STATUS_REG for ACK the first interrupt got
+	 * Read the host_int_status_reg for ACK the first interrupt got
 	 * from the bootloader. If we don't do this we get a interrupt
 	 * as soon as we register the irq.
 	 */
-	mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg);
+	mwifiex_read_reg(adapter, card->reg->host_int_status_reg, &sdio_ireg);
 
 	/* Get SDIO ioport */
 	mwifiex_init_sdio_ioport(adapter);
@@ -2235,3 +2239,4 @@
 MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME);
 MODULE_FIRMWARE(SD8797_DEFAULT_FW_NAME);
 MODULE_FIRMWARE(SD8897_DEFAULT_FW_NAME);
+MODULE_FIRMWARE(SD8887_DEFAULT_FW_NAME);
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
index 6b8835e..20cd9ad 100644
--- a/drivers/net/wireless/mwifiex/sdio.h
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -33,6 +33,7 @@
 #define SD8787_DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin"
 #define SD8797_DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin"
 #define SD8897_DEFAULT_FW_NAME "mrvl/sd8897_uapsta.bin"
+#define SD8887_DEFAULT_FW_NAME "mrvl/sd8887_uapsta.bin"
 
 #define BLOCK_MODE	1
 #define BYTE_MODE	0
@@ -52,13 +53,9 @@
 #define HOST_TERM_CMD53			(0x1U << 2)
 #define REG_PORT			0
 #define MEM_PORT			0x10000
-#define CMD_RD_LEN_0			0xB4
-#define CMD_RD_LEN_1			0xB5
-#define CARD_CONFIG_2_1_REG             0xCD
+
 #define CMD53_NEW_MODE			(0x1U << 0)
-#define CMD_CONFIG_0			0xB8
 #define CMD_PORT_RD_LEN_EN		(0x1U << 2)
-#define CMD_CONFIG_1			0xB9
 #define CMD_PORT_AUTO_EN		(0x1U << 0)
 #define CMD_PORT_SLCT			0x8000
 #define UP_LD_CMD_PORT_HOST_INT_STATUS	(0x40U)
@@ -70,38 +67,23 @@
 /* Misc. Config Register : Auto Re-enable interrupts */
 #define AUTO_RE_ENABLE_INT              BIT(4)
 
-/* Host Control Registers */
-/* Host Control Registers : I/O port 0 */
-#define IO_PORT_0_REG			0x78
-/* Host Control Registers : I/O port 1 */
-#define IO_PORT_1_REG			0x79
-/* Host Control Registers : I/O port 2 */
-#define IO_PORT_2_REG			0x7A
-
 /* Host Control Registers : Configuration */
 #define CONFIGURATION_REG		0x00
 /* Host Control Registers : Host power up */
 #define HOST_POWER_UP			(0x1U << 1)
 
-/* Host Control Registers : Host interrupt mask */
-#define HOST_INT_MASK_REG		0x02
 /* Host Control Registers : Upload host interrupt mask */
 #define UP_LD_HOST_INT_MASK		(0x1U)
 /* Host Control Registers : Download host interrupt mask */
 #define DN_LD_HOST_INT_MASK		(0x2U)
 
-/* Host Control Registers : Host interrupt status */
-#define HOST_INTSTATUS_REG		0x03
 /* Host Control Registers : Upload host interrupt status */
 #define UP_LD_HOST_INT_STATUS		(0x1U)
 /* Host Control Registers : Download host interrupt status */
 #define DN_LD_HOST_INT_STATUS		(0x2U)
 
-/* Host Control Registers : Host interrupt RSR */
-#define HOST_INT_RSR_REG		0x01
-
 /* Host Control Registers : Host interrupt status */
-#define HOST_INT_STATUS_REG		0x28
+#define CARD_INT_STATUS_REG		0x28
 
 /* Card Control Registers : Card I/O ready */
 #define CARD_IO_READY                   (0x1U << 3)
@@ -203,10 +185,16 @@
 	u8 base_1_reg;
 	u8 poll_reg;
 	u8 host_int_enable;
+	u8 host_int_rsr_reg;
+	u8 host_int_status_reg;
+	u8 host_int_mask_reg;
 	u8 status_reg_0;
 	u8 status_reg_1;
 	u8 sdio_int_mask;
 	u32 data_port_mask;
+	u8 io_port_0_reg;
+	u8 io_port_1_reg;
+	u8 io_port_2_reg;
 	u8 max_mp_regs;
 	u8 rd_bitmap_l;
 	u8 rd_bitmap_u;
@@ -219,6 +207,15 @@
 	u8 rd_len_p0_l;
 	u8 rd_len_p0_u;
 	u8 card_misc_cfg_reg;
+	u8 card_cfg_2_1_reg;
+	u8 cmd_rd_len_0;
+	u8 cmd_rd_len_1;
+	u8 cmd_rd_len_2;
+	u8 cmd_rd_len_3;
+	u8 cmd_cfg_0;
+	u8 cmd_cfg_1;
+	u8 cmd_cfg_2;
+	u8 cmd_cfg_3;
 	u8 fw_dump_ctrl;
 	u8 fw_dump_start;
 	u8 fw_dump_end;
@@ -274,10 +271,16 @@
 	.base_1_reg = 0x0041,
 	.poll_reg = 0x30,
 	.host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK,
+	.host_int_rsr_reg = 0x1,
+	.host_int_mask_reg = 0x02,
+	.host_int_status_reg = 0x03,
 	.status_reg_0 = 0x60,
 	.status_reg_1 = 0x61,
 	.sdio_int_mask = 0x3f,
 	.data_port_mask = 0x0000fffe,
+	.io_port_0_reg = 0x78,
+	.io_port_1_reg = 0x79,
+	.io_port_2_reg = 0x7A,
 	.max_mp_regs = 64,
 	.rd_bitmap_l = 0x04,
 	.rd_bitmap_u = 0x05,
@@ -296,10 +299,16 @@
 	.poll_reg = 0x50,
 	.host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK |
 			CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK,
+	.host_int_rsr_reg = 0x1,
+	.host_int_status_reg = 0x03,
+	.host_int_mask_reg = 0x02,
 	.status_reg_0 = 0xc0,
 	.status_reg_1 = 0xc1,
 	.sdio_int_mask = 0xff,
 	.data_port_mask = 0xffffffff,
+	.io_port_0_reg = 0xD8,
+	.io_port_1_reg = 0xD9,
+	.io_port_2_reg = 0xDA,
 	.max_mp_regs = 184,
 	.rd_bitmap_l = 0x04,
 	.rd_bitmap_u = 0x05,
@@ -312,11 +321,61 @@
 	.rd_len_p0_l = 0x0c,
 	.rd_len_p0_u = 0x0d,
 	.card_misc_cfg_reg = 0xcc,
+	.card_cfg_2_1_reg = 0xcd,
+	.cmd_rd_len_0 = 0xb4,
+	.cmd_rd_len_1 = 0xb5,
+	.cmd_rd_len_2 = 0xb6,
+	.cmd_rd_len_3 = 0xb7,
+	.cmd_cfg_0 = 0xb8,
+	.cmd_cfg_1 = 0xb9,
+	.cmd_cfg_2 = 0xba,
+	.cmd_cfg_3 = 0xbb,
 	.fw_dump_ctrl = 0xe2,
 	.fw_dump_start = 0xe3,
 	.fw_dump_end = 0xea,
 };
 
+static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8887 = {
+	.start_rd_port = 0,
+	.start_wr_port = 0,
+	.base_0_reg = 0x6C,
+	.base_1_reg = 0x6D,
+	.poll_reg = 0x5C,
+	.host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK |
+			CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK,
+	.host_int_rsr_reg = 0x4,
+	.host_int_status_reg = 0x0C,
+	.host_int_mask_reg = 0x08,
+	.status_reg_0 = 0x90,
+	.status_reg_1 = 0x91,
+	.sdio_int_mask = 0xff,
+	.data_port_mask = 0xffffffff,
+	.io_port_0_reg = 0xE4,
+	.io_port_1_reg = 0xE5,
+	.io_port_2_reg = 0xE6,
+	.max_mp_regs = 196,
+	.rd_bitmap_l = 0x10,
+	.rd_bitmap_u = 0x11,
+	.rd_bitmap_1l = 0x12,
+	.rd_bitmap_1u = 0x13,
+	.wr_bitmap_l = 0x14,
+	.wr_bitmap_u = 0x15,
+	.wr_bitmap_1l = 0x16,
+	.wr_bitmap_1u = 0x17,
+	.rd_len_p0_l = 0x18,
+	.rd_len_p0_u = 0x19,
+	.card_misc_cfg_reg = 0xd8,
+	.card_cfg_2_1_reg = 0xd9,
+	.cmd_rd_len_0 = 0xc0,
+	.cmd_rd_len_1 = 0xc1,
+	.cmd_rd_len_2 = 0xc2,
+	.cmd_rd_len_3 = 0xc3,
+	.cmd_cfg_0 = 0xc4,
+	.cmd_cfg_1 = 0xc5,
+	.cmd_cfg_2 = 0xc6,
+	.cmd_cfg_3 = 0xc7,
+};
+
 static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = {
 	.firmware = SD8786_DEFAULT_FW_NAME,
 	.reg = &mwifiex_reg_sd87xx,
@@ -369,6 +428,19 @@
 	.supports_fw_dump = true,
 };
 
+static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = {
+	.firmware = SD8887_DEFAULT_FW_NAME,
+	.reg = &mwifiex_reg_sd8887,
+	.max_ports = 32,
+	.mp_agg_pkt_limit = 16,
+	.supports_sdio_new_mode = true,
+	.has_control_mask = false,
+	.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
+	.mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K,
+	.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K,
+	.supports_fw_dump = false,
+};
+
 /*
  * .cmdrsp_complete handler
  */
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 733de92..1c2ca29 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -938,7 +938,7 @@
 		cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN
 					+ key_param_len);
 
-		if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
+		if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
 			tlv_mac = (void *)((u8 *)&key_material->key_param_set +
 					   key_param_len);
 			tlv_mac->header.type =
@@ -965,7 +965,7 @@
 				u16 cmd_action, u32 cmd_oid,
 				struct mwifiex_ds_encrypt_key *enc_key)
 {
-	if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+	if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
 		return mwifiex_cmd_802_11_key_material_v2(priv, cmd,
 							  cmd_action, cmd_oid,
 							  enc_key);
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 08b78ba..4aad446 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -85,8 +85,6 @@
 		spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
 		adapter->scan_processing = false;
 		spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
-		if (priv->report_scan_result)
-			priv->report_scan_result = false;
 		break;
 
 	case HostCmd_CMD_MAC_CONTROL:
@@ -637,7 +635,7 @@
 static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
 					   struct host_cmd_ds_command *resp)
 {
-	if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+	if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
 		return mwifiex_ret_802_11_key_material_v2(priv, resp);
 	else
 		return mwifiex_ret_802_11_key_material_v1(priv, resp);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index caae973..92f3eb8 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -287,10 +287,13 @@
 			return -1;
 
 		if (mwifiex_band_to_radio_type(bss_desc->bss_band) ==
-						HostCmd_SCAN_RADIO_TYPE_BG)
+						HostCmd_SCAN_RADIO_TYPE_BG) {
 			config_bands = BAND_B | BAND_G | BAND_GN;
-		else
-			config_bands = BAND_A | BAND_AN | BAND_AAC;
+		} else {
+			config_bands = BAND_A | BAND_AN;
+			if (adapter->fw_bands & BAND_AAC)
+				config_bands |= BAND_AAC;
+		}
 
 		if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands))
 			adapter->config_bands = config_bands;
@@ -877,7 +880,7 @@
 			return -1;
 		}
 
-		if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2) {
+		if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) {
 			memcpy(encrypt_key->key_material,
 			       wep_key->key_material, wep_key->key_length);
 			encrypt_key->key_len = wep_key->key_length;
@@ -903,7 +906,7 @@
 			memset(&priv->wep_key[index], 0,
 			       sizeof(struct mwifiex_wep_key));
 
-		if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+		if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
 			enc_key = encrypt_key;
 		else
 			enc_key = NULL;
diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c
index 4c5fd95..e294907 100644
--- a/drivers/net/wireless/mwifiex/tdls.c
+++ b/drivers/net/wireless/mwifiex/tdls.c
@@ -871,7 +871,9 @@
 			break;
 		case WLAN_EID_RSN:
 			memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos,
-			       sizeof(struct ieee_types_header) + pos[1]);
+			       sizeof(struct ieee_types_header) +
+			       min_t(u8, pos[1], IEEE_MAX_IE_SIZE -
+				     sizeof(struct ieee_types_header)));
 			break;
 		case WLAN_EID_QOS_CAPA:
 			sta_ptr->tdls_cap.qos_info = pos[2];
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c
index 7118a18..4371e12 100644
--- a/drivers/net/wireless/mwifiex/usb.c
+++ b/drivers/net/wireless/mwifiex/usb.c
@@ -357,7 +357,7 @@
 		card->usb_boot_state = USB8XXX_FW_READY;
 		break;
 	default:
-		pr_warning("unknown id_product %#x\n", id_product);
+		pr_warn("unknown id_product %#x\n", id_product);
 		card->usb_boot_state = USB8XXX_FW_DNLD;
 		break;
 	}
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index cee0283..ec79c49 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -172,7 +172,7 @@
 
 	cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq,
 			 CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len,
-			 0, GFP_ATOMIC);
+			 0);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index 6298e2c..4178ddd 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -534,7 +534,7 @@
 
 	if (ctx->killed) {
 		spin_unlock_irqrestore(&upriv->req_lock, flags);
-		pr_warning("interrupt called with dead ctx");
+		pr_warn("interrupt called with dead ctx\n");
 		goto out;
 	}
 
@@ -671,8 +671,8 @@
 	default:
 		spin_unlock_irqrestore(&upriv->req_lock, flags);
 
-		pr_warning("Matched IN URB, unexpected context state(0x%x)",
-		     state);
+		pr_warn("Matched IN URB, unexpected context state(0x%x)\n",
+			state);
 		/* Throw this CTX away and try submitting another */
 		del_timer(&ctx->timer);
 		ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
@@ -1394,12 +1394,12 @@
 		/* When a device gets unplugged we get this every time
 		 * we resubmit, flooding the logs.  Since we don't use
 		 * USB timeouts, it shouldn't happen any other time*/
-		pr_warning("%s: urb timed out, not resubmiting", __func__);
+		pr_warn("%s: urb timed out, not resubmitting\n", __func__);
 		return;
 	}
 	if (urb->status == -ECONNABORTED) {
-		pr_warning("%s: connection abort, resubmiting urb",
-		     __func__);
+		pr_warn("%s: connection abort, resubmitting urb\n",
+			__func__);
 		goto resubmit;
 	}
 	if ((urb->status == -EILSEQ)
@@ -1605,13 +1605,10 @@
 	for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
 		ep = &interface->altsetting[0].endpoint[i].desc;
 
-		if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
-		     == USB_DIR_IN) &&
-		    ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-		     == USB_ENDPOINT_XFER_BULK)) {
+		if (usb_endpoint_is_bulk_in(ep)) {
 			/* we found a bulk in endpoint */
 			if (upriv->read_urb != NULL) {
-				pr_warning("Found a second bulk in ep, ignored");
+				pr_warn("Found a second bulk in ep, ignored\n");
 				continue;
 			}
 
@@ -1621,10 +1618,10 @@
 				goto error;
 			}
 			if (le16_to_cpu(ep->wMaxPacketSize) != 64)
-				pr_warning("bulk in: wMaxPacketSize!= 64");
+				pr_warn("bulk in: wMaxPacketSize!= 64\n");
 			if (ep->bEndpointAddress != (2 | USB_DIR_IN))
-				pr_warning("bulk in: bEndpointAddress: %d",
-				     ep->bEndpointAddress);
+				pr_warn("bulk in: bEndpointAddress: %d\n",
+					ep->bEndpointAddress);
 			upriv->read_pipe = usb_rcvbulkpipe(udev,
 							 ep->
 							 bEndpointAddress);
@@ -1636,21 +1633,18 @@
 			}
 		}
 
-		if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
-		     == USB_DIR_OUT) &&
-		    ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-		     == USB_ENDPOINT_XFER_BULK)) {
+		if (usb_endpoint_is_bulk_out(ep)) {
 			/* we found a bulk out endpoint */
 			if (upriv->bap_buf != NULL) {
-				pr_warning("Found a second bulk out ep, ignored");
+				pr_warn("Found a second bulk out ep, ignored\n");
 				continue;
 			}
 
 			if (le16_to_cpu(ep->wMaxPacketSize) != 64)
-				pr_warning("bulk out: wMaxPacketSize != 64");
+				pr_warn("bulk out: wMaxPacketSize != 64\n");
 			if (ep->bEndpointAddress != 2)
-				pr_warning("bulk out: bEndpointAddress: %d",
-				     ep->bEndpointAddress);
+				pr_warn("bulk out: bEndpointAddress: %d\n",
+					ep->bEndpointAddress);
 			upriv->write_pipe = usb_sndbulkpipe(udev,
 							  ep->
 							  bEndpointAddress);
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
index e175b9b..2c66166 100644
--- a/drivers/net/wireless/orinoco/scan.c
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -123,9 +123,10 @@
 	beacon_interval = le16_to_cpu(bss->a.beacon_interv);
 	signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
 
-	cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
-				   capability, beacon_interval, ie_buf, ie_len,
-				   signal, GFP_KERNEL);
+	cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
+				   bss->a.bssid, timestamp, capability,
+				   beacon_interval, ie_buf, ie_len, signal,
+				   GFP_KERNEL);
 	cfg80211_put_bss(wiphy, cbss);
 }
 
@@ -156,9 +157,10 @@
 	ie = bss->data;
 	signal = SIGNAL_TO_MBM(bss->level);
 
-	cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
-				   capability, beacon_interval, ie, ie_len,
-				   signal, GFP_KERNEL);
+	cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
+				   bss->bssid, timestamp, capability,
+				   beacon_interval, ie, ie_len, signal,
+				   GFP_KERNEL);
 	cfg80211_put_bss(wiphy, cbss);
 }
 
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index 16c7aef..58a1f09 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -696,7 +696,8 @@
 	WARN(total, "tx flush timeout, unresponsive firmware");
 }
 
-static void p54_set_coverage_class(struct ieee80211_hw *dev, u8 coverage_class)
+static void p54_set_coverage_class(struct ieee80211_hw *dev,
+				   s16 coverage_class)
 {
 	struct p54_common *priv = dev->priv;
 
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index fe48318..0f7b6d6 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2022,9 +2022,10 @@
 	capability = le16_to_cpu(fixed->capabilities);
 	beacon_interval = le16_to_cpu(fixed->beacon_interval);
 
-	bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
-		timestamp, capability, beacon_interval, ie, ie_len, signal,
-		GFP_KERNEL);
+	bss = cfg80211_inform_bss(priv->wdev.wiphy, channel,
+				  CFG80211_BSS_FTYPE_UNKNOWN, bssid->mac,
+				  timestamp, capability, beacon_interval,
+				  ie, ie_len, signal, GFP_KERNEL);
 	cfg80211_put_bss(priv->wdev.wiphy, bss);
 
 	return (bss != NULL);
@@ -2711,9 +2712,10 @@
 		bssid, (u32)timestamp, capability, beacon_period, ie_len,
 		ssid.essid, signal);
 
-	bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
-		timestamp, capability, beacon_period, ie_buf, ie_len,
-		signal, GFP_KERNEL);
+	bss = cfg80211_inform_bss(priv->wdev.wiphy, channel,
+				  CFG80211_BSS_FTYPE_UNKNOWN, bssid,
+				  timestamp, capability, beacon_period,
+				  ie_buf, ie_len, signal, GFP_KERNEL);
 	cfg80211_put_bss(priv->wdev.wiphy, bss);
 }
 
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index a394a9a..ebd5625 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -52,6 +52,7 @@
  * RF5592 2.4G/5G 2T2R
  * RF3070 2.4G 1T1R
  * RF5360 2.4G 1T1R
+ * RF5362 2.4G 1T1R
  * RF5370 2.4G 1T1R
  * RF5390 2.4G 1T1R
  */
@@ -72,6 +73,7 @@
 #define RF3070				0x3070
 #define RF3290				0x3290
 #define RF5360				0x5360
+#define RF5362				0x5362
 #define RF5370				0x5370
 #define RF5372				0x5372
 #define RF5390				0x5390
@@ -2039,7 +2041,7 @@
  * 2 - drop tx power by 12dBm,
  * 3 - increase tx power by 6dBm
  */
-#define BBP1_TX_POWER_CTRL		FIELD8(0x07)
+#define BBP1_TX_POWER_CTRL		FIELD8(0x03)
 #define BBP1_TX_ANTENNA			FIELD8(0x18)
 
 /*
@@ -2145,7 +2147,7 @@
 /* Bits [7-4] for RF3320 (RT3370/RT3390), on other chipsets reserved */
 #define RFCSR3_PA1_BIAS_CCK		FIELD8(0x70)
 #define RFCSR3_PA2_CASCODE_BIAS_CCKK	FIELD8(0x80)
-/* Bits for RF3290/RF5360/RF5370/RF5372/RF5390/RF5392 */
+/* Bits for RF3290/RF5360/RF5362/RF5370/RF5372/RF5390/RF5392 */
 #define RFCSR3_VCOCAL_EN		FIELD8(0x80)
 /* Bits for RF3050 */
 #define RFCSR3_BIT1			FIELD8(0x02)
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 2db7d78..5ad3899 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -3186,6 +3186,7 @@
 		break;
 	case RF3070:
 	case RF5360:
+	case RF5362:
 	case RF5370:
 	case RF5372:
 	case RF5390:
@@ -3203,6 +3204,7 @@
 	    rt2x00_rf(rt2x00dev, RF3290) ||
 	    rt2x00_rf(rt2x00dev, RF3322) ||
 	    rt2x00_rf(rt2x00dev, RF5360) ||
+	    rt2x00_rf(rt2x00dev, RF5362) ||
 	    rt2x00_rf(rt2x00dev, RF5370) ||
 	    rt2x00_rf(rt2x00dev, RF5372) ||
 	    rt2x00_rf(rt2x00dev, RF5390) ||
@@ -4317,6 +4319,7 @@
 	case RF3070:
 	case RF3290:
 	case RF5360:
+	case RF5362:
 	case RF5370:
 	case RF5372:
 	case RF5390:
@@ -7095,6 +7098,7 @@
 	case RF3320:
 	case RF3322:
 	case RF5360:
+	case RF5362:
 	case RF5370:
 	case RF5372:
 	case RF5390:
@@ -7551,6 +7555,7 @@
 	case RF3320:
 	case RF3322:
 	case RF5360:
+	case RF5362:
 	case RF5370:
 	case RF5372:
 	case RF5390:
@@ -7680,6 +7685,7 @@
 	case RF3070:
 	case RF3290:
 	case RF5360:
+	case RF5362:
 	case RF5370:
 	case RF5372:
 	case RF5390:
diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c
index 026d912..706b844 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c
@@ -189,6 +189,9 @@
 
 static const int rtl8180_queues_map[RTL8180_NR_TX_QUEUES] = {4, 7};
 
+/* LNA gain table for rtl8187se */
+static const u8 rtl8187se_lna_gain[4] = {02, 17, 29, 39};
+
 void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
 {
 	struct rtl8180_priv *priv = dev->priv;
@@ -210,13 +213,14 @@
 	struct rtl8180_priv *priv = dev->priv;
 	struct rtl818x_rx_cmd_desc *cmd_desc;
 	unsigned int count = 32;
-	u8 agc, sq, signal = 1;
+	u8 agc, sq;
+	s8 signal = 1;
 	dma_addr_t mapping;
 
 	while (count--) {
 		void *entry = priv->rx_ring + priv->rx_idx * priv->rx_ring_sz;
 		struct sk_buff *skb = priv->rx_buf[priv->rx_idx];
-		u32 flags, flags2;
+		u32 flags, flags2, flags3 = 0;
 		u64 tsft;
 
 		if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8187SE) {
@@ -229,6 +233,7 @@
 			 * the ownership flag
 			 */
 			rmb();
+			flags3 = le32_to_cpu(desc->flags3);
 			flags2 = le32_to_cpu(desc->flags2);
 			tsft = le64_to_cpu(desc->tsft);
 		} else {
@@ -287,8 +292,21 @@
 				signal = priv->rf->calc_rssi(agc, sq);
 				break;
 			case RTL818X_CHIP_FAMILY_RTL8187SE:
-				/* TODO: rtl8187se rssi */
-				signal = 10;
+				/* OFDM measure reported by HW is signed,
+				 * in 0.5dBm unit, with zero centered @ -41dBm
+				 * input signal.
+				 */
+				if (rx_status.rate_idx > 3) {
+					signal = (s8)((flags3 >> 16) & 0xff);
+					signal = signal / 2 - 41;
+				} else {
+					int idx, bb;
+
+					idx = (agc & 0x60) >> 5;
+					bb = (agc & 0x1F) * 2;
+					/* bias + BB gain + LNA gain */
+					signal = 4 - bb - rtl8187se_lna_gain[idx];
+				}
 				break;
 			}
 			rx_status.signal = signal;
@@ -724,35 +742,49 @@
 }
 
 static void rtl8180_conf_basic_rates(struct ieee80211_hw *dev,
-			    u32 rates_mask)
+			    u32 basic_mask)
 {
 	struct rtl8180_priv *priv = dev->priv;
-
-	u8 max, min;
 	u16 reg;
+	u32 resp_mask;
+	u8 basic_max;
+	u8 resp_max, resp_min;
 
-	max = fls(rates_mask) - 1;
-	min = ffs(rates_mask) - 1;
+	resp_mask = basic_mask;
+	/* IEEE80211 says the response rate should be equal to the highest basic
+	 * rate that is not faster than received frame. But it says also that if
+	 * the basic rate set does not contains any rate for the current
+	 * modulation class then mandatory rate set must be used for that
+	 * modulation class. Eventually add OFDM mandatory rates..
+	 */
+	if ((resp_mask & 0xf) == resp_mask)
+		resp_mask |= 0x150; /* 6, 12, 24Mbps */
 
 	switch (priv->chip_family) {
 
 	case RTL818X_CHIP_FAMILY_RTL8180:
 		/* in 8180 this is NOT a BITMAP */
+		basic_max = fls(basic_mask) - 1;
 		reg = rtl818x_ioread16(priv, &priv->map->BRSR);
 		reg &= ~3;
-		reg |= max;
+		reg |= basic_max;
 		rtl818x_iowrite16(priv, &priv->map->BRSR, reg);
 		break;
 
 	case RTL818X_CHIP_FAMILY_RTL8185:
+		resp_max = fls(resp_mask) - 1;
+		resp_min = ffs(resp_mask) - 1;
 		/* in 8185 this is a BITMAP */
-		rtl818x_iowrite16(priv, &priv->map->BRSR, rates_mask);
-		rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (max << 4) | min);
+		rtl818x_iowrite16(priv, &priv->map->BRSR, basic_mask);
+		rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (resp_max << 4) |
+				resp_min);
 		break;
 
 	case RTL818X_CHIP_FAMILY_RTL8187SE:
-		/* in 8187se this is a BITMAP */
-		rtl818x_iowrite16(priv, &priv->map->BRSR_8187SE, rates_mask);
+		/* in 8187se this is a BITMAP. BRSR reg actually sets
+		 * response rates.
+		 */
+		rtl818x_iowrite16(priv, &priv->map->BRSR_8187SE, resp_mask);
 		break;
 	}
 }
@@ -1835,7 +1867,7 @@
 		pci_try_set_mwi(pdev);
 	}
 
-	if (priv->chip_family == RTL818X_CHIP_FAMILY_RTL8185)
+	if (priv->chip_family != RTL818X_CHIP_FAMILY_RTL8180)
 		dev->flags |= IEEE80211_HW_SIGNAL_DBM;
 	else
 		dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
index 83c05a5..b0edfd8 100644
--- a/drivers/net/wireless/rtlwifi/Kconfig
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -6,7 +6,8 @@
 	---help---
 	  This option will enable support for the Realtek mac80211-based
 	  wireless drivers. Drivers rtl8192ce, rtl8192cu, rtl8192se, rtl8192de,
-	  rtl8723ae, rtl8723be, and rtl8188ae share some common code.
+	  rtl8723ae, rtl8723be, rtl8188ee, rtl8192ee, and rtl8821ae share
+	  some common code.
 
 if RTL_CARDS
 
@@ -87,6 +88,32 @@
 
 	If you choose to build it as a module, it will be called rtl8188ee
 
+config RTL8192EE
+	tristate "Realtek RTL8192EE Wireless Network Adapter"
+	depends on m
+	depends on PCI
+	select RTLWIFI
+	select RTLWIFI_PCI
+	select RTLBTCOEXIST
+	---help---
+	This is the driver for Realtek RTL8192EE 802.11n PCIe
+	wireless network adapters.
+
+	If you choose to build it as a module, it will be called rtl8192ee
+
+config RTL8821AE
+	tristate "Realtek RTL8821AE/RTL8812AE Wireless Network Adapter"
+	depends on m
+	depends on PCI
+	select RTLWIFI
+	select RTLWIFI_PCI
+	select RTLBTCOEXIST
+	---help---
+	This is the driver for Realtek RTL8i821AE/RTL8812AE 802.11av PCIe
+	wireless network adapters.
+
+	If you choose to build it as a module, it will be called rtl8821ae
+
 config RTL8192CU
 	tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"
 	depends on m
@@ -137,7 +164,7 @@
 config RTLBTCOEXIST
 	tristate
 	depends on m
-	depends on RTL8723AE || RTL8723BE
+	depends on RTL8723AE || RTL8723BE || RTL8821AE || RTL8192EE
 	default y
 
 endif
diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile
index 8bbc318..19fac8e 100644
--- a/drivers/net/wireless/rtlwifi/Makefile
+++ b/drivers/net/wireless/rtlwifi/Makefile
@@ -28,5 +28,7 @@
 obj-$(CPTCFG_RTL8188EE)		+= rtl8188ee/
 obj-$(CPTCFG_RTLBTCOEXIST)	+= btcoexist/
 obj-$(CPTCFG_RTL8723_COMMON)	+= rtl8723com/
+obj-$(CPTCFG_RTL8821AE)		+= rtl8821ae/
+obj-$(CPTCFG_RTL8192EE)		+= rtl8192ee/
 
 ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 93bb384..58ba718 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -34,7 +30,7 @@
 #include "cam.h"
 #include "ps.h"
 #include "regd.h"
-
+#include "pci.h"
 #include <linux/ip.h>
 #include <linux/module.h>
 #include <linux/udp.h>
@@ -211,7 +207,6 @@
 	 *highest supported RX rate
 	 */
 	if (rtlpriv->dm.supp_phymode_switch) {
-
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
 			 "Support phy mode switch\n");
 
@@ -244,6 +239,83 @@
 	}
 }
 
+static void _rtl_init_hw_vht_capab(struct ieee80211_hw *hw,
+				   struct ieee80211_sta_vht_cap *vht_cap)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+		u16 mcs_map;
+
+		vht_cap->vht_supported = true;
+		vht_cap->cap =
+			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 |
+			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
+			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+			IEEE80211_VHT_CAP_SHORT_GI_80 |
+			IEEE80211_VHT_CAP_TXSTBC |
+			IEEE80211_VHT_CAP_RXSTBC_1 |
+			IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+			IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+			IEEE80211_VHT_CAP_HTC_VHT |
+			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
+			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
+			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
+			0;
+
+		mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
+			IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 14;
+
+		vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
+		vht_cap->vht_mcs.rx_highest =
+			cpu_to_le16(MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9);
+		vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
+		vht_cap->vht_mcs.tx_highest =
+			cpu_to_le16(MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9);
+	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+		u16 mcs_map;
+
+		vht_cap->vht_supported = true;
+		vht_cap->cap =
+			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 |
+			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
+			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+			IEEE80211_VHT_CAP_SHORT_GI_80 |
+			IEEE80211_VHT_CAP_TXSTBC |
+			IEEE80211_VHT_CAP_RXSTBC_1 |
+			IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+			IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+			IEEE80211_VHT_CAP_HTC_VHT |
+			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
+			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
+			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
+			0;
+
+		mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
+			IEEE80211_VHT_MCS_NOT_SUPPORTED << 14;
+
+		vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
+		vht_cap->vht_mcs.rx_highest =
+			cpu_to_le16(MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9);
+		vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
+		vht_cap->vht_mcs.tx_highest =
+			cpu_to_le16(MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9);
+	}
+}
+
 static void _rtl_init_mac80211(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -252,9 +324,8 @@
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	struct ieee80211_supported_band *sband;
 
-
-	if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && rtlhal->bandset ==
-	    BAND_ON_BOTH) {
+	if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY &&
+	    rtlhal->bandset == BAND_ON_BOTH) {
 		/* 1: 2.4 G bands */
 		/* <1> use  mac->bands as mem for hw->wiphy->bands */
 		sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]);
@@ -282,6 +353,7 @@
 		/* <3> init ht cap base on ant_num */
 		_rtl_init_hw_ht_capab(hw, &sband->ht_cap);
 
+		_rtl_init_hw_vht_capab(hw, &sband->vht_cap);
 		/* <4> set mac->sband to wiphy->sband */
 		hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
 	} else {
@@ -292,8 +364,8 @@
 			/* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ]
 			 * to default value(1T1R) */
 			memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]),
-				 &rtl_band_2ghz,
-				 sizeof(struct ieee80211_supported_band));
+			       &rtl_band_2ghz,
+			       sizeof(struct ieee80211_supported_band));
 
 			/* <3> init ht cap base on ant_num */
 			_rtl_init_hw_ht_capab(hw, &sband->ht_cap);
@@ -307,12 +379,13 @@
 			/* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ]
 			 * to default value(1T1R) */
 			memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]),
-				 &rtl_band_5ghz,
-				 sizeof(struct ieee80211_supported_band));
+			       &rtl_band_5ghz,
+			       sizeof(struct ieee80211_supported_band));
 
 			/* <3> init ht cap base on ant_num */
 			_rtl_init_hw_ht_capab(hw, &sband->ht_cap);
 
+			_rtl_init_hw_vht_capab(hw, &sband->vht_cap);
 			/* <4> set mac->sband to wiphy->sband */
 			hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
 		} else {
@@ -326,7 +399,6 @@
 	    IEEE80211_HW_AMPDU_AGGREGATION |
 	    IEEE80211_HW_CONNECTION_MONITOR |
 	    /* IEEE80211_HW_SUPPORTS_CQM_RSSI | */
-	    IEEE80211_HW_CONNECTION_MONITOR |
 	    IEEE80211_HW_MFP_CAPABLE |
 	    IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0;
 
@@ -336,7 +408,6 @@
 			IEEE80211_HW_PS_NULLFUNC_STACK |
 			/* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
 			0;
-
 	hw->wiphy->interface_modes =
 	    BIT(NL80211_IFTYPE_AP) |
 	    BIT(NL80211_IFTYPE_STATION) |
@@ -344,8 +415,10 @@
 	    BIT(NL80211_IFTYPE_MESH_POINT) |
 	    BIT(NL80211_IFTYPE_P2P_CLIENT) |
 	    BIT(NL80211_IFTYPE_P2P_GO);
-
 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
+	hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+
 	hw->wiphy->rts_threshold = 2347;
 
 	hw->queues = AC_MAX;
@@ -358,6 +431,21 @@
 	/* hw->max_rates = 1; */
 	hw->sta_data_size = sizeof(struct rtl_sta_info);
 
+/* wowlan is not supported by kernel if CONFIG_PM is not defined */
+#ifdef CONFIG_PM
+	if (rtlpriv->psc.wo_wlan_mode) {
+		if (rtlpriv->psc.wo_wlan_mode & WAKE_ON_MAGIC_PACKET)
+			rtlpriv->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT;
+		if (rtlpriv->psc.wo_wlan_mode & WAKE_ON_PATTERN_MATCH) {
+			rtlpriv->wowlan.n_patterns =
+				MAX_SUPPORT_WOL_PATTERN_NUM;
+			rtlpriv->wowlan.pattern_min_len = MIN_WOL_PATTERN_SIZE;
+			rtlpriv->wowlan.pattern_max_len = MAX_WOL_PATTERN_SIZE;
+		}
+		hw->wiphy->wowlan = &rtlpriv->wowlan;
+	}
+#endif
+
 	/* <6> mac address */
 	if (is_valid_ether_addr(rtlefuse->dev_addr)) {
 		SET_IEEE80211_PERM_ADDR(hw, rtlefuse->dev_addr);
@@ -366,7 +454,6 @@
 		get_random_bytes((rtlmac1 + (ETH_ALEN - 1)), 1);
 		SET_IEEE80211_PERM_ADDR(hw, rtlmac1);
 	}
-
 }
 
 static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
@@ -378,10 +465,9 @@
 		    rtl_watch_dog_timer_callback, (unsigned long)hw);
 	setup_timer(&rtlpriv->works.dualmac_easyconcurrent_retrytimer,
 		    rtl_easy_concurrent_retrytimer_callback, (unsigned long)hw);
-
 	/* <2> work queue */
 	rtlpriv->works.hw = hw;
-	rtlpriv->works.rtl_wq = alloc_workqueue("%s", 0, 0, rtlpriv->cfg->name);
+	rtlpriv->works.rtl_wq = alloc_workqueue(rtlpriv->cfg->name, 0, 0);
 	INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq,
 			  (void *)rtl_watchdog_wq_callback);
 	INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq,
@@ -424,7 +510,7 @@
 	radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid);
 
 	if (valid) {
-		pr_info("wireless switch is %s\n",
+		pr_info("rtlwifi: wireless switch is %s\n",
 			rtlpriv->rfkill.rfkill_state ? "on" : "off");
 
 		rtlpriv->rfkill.rfkill_state = radio_state;
@@ -466,22 +552,18 @@
 
 	/* <4> locks */
 	mutex_init(&rtlpriv->locks.conf_mutex);
-	mutex_init(&rtlpriv->locks.ps_mutex);
 	spin_lock_init(&rtlpriv->locks.ips_lock);
 	spin_lock_init(&rtlpriv->locks.irq_th_lock);
-	spin_lock_init(&rtlpriv->locks.irq_pci_lock);
-	spin_lock_init(&rtlpriv->locks.tx_lock);
 	spin_lock_init(&rtlpriv->locks.h2c_lock);
 	spin_lock_init(&rtlpriv->locks.rf_ps_lock);
 	spin_lock_init(&rtlpriv->locks.rf_lock);
 	spin_lock_init(&rtlpriv->locks.waitq_lock);
 	spin_lock_init(&rtlpriv->locks.entry_list_lock);
-	spin_lock_init(&rtlpriv->locks.fw_ps_lock);
 	spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock);
 	spin_lock_init(&rtlpriv->locks.check_sendpkt_lock);
 	spin_lock_init(&rtlpriv->locks.fw_ps_lock);
 	spin_lock_init(&rtlpriv->locks.lps_lock);
-
+	spin_lock_init(&rtlpriv->locks.iqk_lock);
 	/* <5> init list */
 	INIT_LIST_HEAD(&rtlpriv->entry_list);
 
@@ -539,6 +621,7 @@
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	u8 rate_flag = info->control.rates[0].flags;
 	u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0;
+	u8 sgi_80 = 0, bw_80 = 0;
 	tcb_desc->use_shortgi = false;
 
 	if (sta == NULL)
@@ -546,24 +629,35 @@
 
 	sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
 	sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
+	sgi_80 = sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80;
 
-	if (!(sta->ht_cap.ht_supported))
+	if ((!sta->ht_cap.ht_supported) && (!sta->vht_cap.vht_supported))
 		return;
 
 	if (!sgi_40 && !sgi_20)
 		return;
 
-	if (mac->opmode == NL80211_IFTYPE_STATION)
+	if (mac->opmode == NL80211_IFTYPE_STATION) {
 		bw_40 = mac->bw_40;
-	else if (mac->opmode == NL80211_IFTYPE_AP ||
+		bw_80 = mac->bw_80;
+	} else if (mac->opmode == NL80211_IFTYPE_AP ||
 		 mac->opmode == NL80211_IFTYPE_ADHOC ||
-		 mac->opmode == NL80211_IFTYPE_MESH_POINT)
-		bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
+		 mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+		bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+		bw_80 = sta->vht_cap.vht_supported;
+	}
 
-	if (bw_40 && sgi_40)
-		tcb_desc->use_shortgi = true;
-	else if ((bw_40 == false) && sgi_20)
-		tcb_desc->use_shortgi = true;
+	if (bw_80) {
+		if (sgi_80)
+			tcb_desc->use_shortgi = true;
+		else
+			tcb_desc->use_shortgi = false;
+	} else {
+		if (bw_40 && sgi_40)
+			tcb_desc->use_shortgi = true;
+		else if (!bw_40 && sgi_20)
+			tcb_desc->use_shortgi = true;
+	}
 
 	if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI))
 		tcb_desc->use_shortgi = false;
@@ -613,7 +707,7 @@
 		if (mac->opmode == NL80211_IFTYPE_STATION) {
 			tcb_desc->ratr_index = 0;
 		} else if (mac->opmode == NL80211_IFTYPE_ADHOC ||
-			   mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+				mac->opmode == NL80211_IFTYPE_MESH_POINT) {
 			if (tcb_desc->multicast || tcb_desc->broadcast) {
 				tcb_desc->hw_rate =
 				    rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M];
@@ -634,7 +728,13 @@
 		    mac->opmode == NL80211_IFTYPE_MESH_POINT) {
 			tcb_desc->mac_id = 0;
 
-			if (mac->mode == WIRELESS_MODE_N_24G)
+			if (mac->mode == WIRELESS_MODE_AC_5G)
+				tcb_desc->ratr_index =
+					RATR_INX_WIRELESS_AC_5N;
+			else if (mac->mode == WIRELESS_MODE_AC_24G)
+				tcb_desc->ratr_index =
+					RATR_INX_WIRELESS_AC_24N;
+			else if (mac->mode == WIRELESS_MODE_N_24G)
 				tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB;
 			else if (mac->mode == WIRELESS_MODE_N_5G)
 				tcb_desc->ratr_index = RATR_INX_WIRELESS_NG;
@@ -644,8 +744,9 @@
 				tcb_desc->ratr_index = RATR_INX_WIRELESS_B;
 			else if (mac->mode & WIRELESS_MODE_A)
 				tcb_desc->ratr_index = RATR_INX_WIRELESS_G;
+
 		} else if (mac->opmode == NL80211_IFTYPE_AP ||
-			   mac->opmode == NL80211_IFTYPE_ADHOC) {
+			mac->opmode == NL80211_IFTYPE_ADHOC) {
 			if (NULL != sta) {
 				if (sta->aid > 0)
 					tcb_desc->mac_id = sta->aid + 1;
@@ -671,7 +772,8 @@
 	if (mac->opmode == NL80211_IFTYPE_AP ||
 	    mac->opmode == NL80211_IFTYPE_ADHOC ||
 	    mac->opmode == NL80211_IFTYPE_MESH_POINT) {
-		if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
+		if (!(sta->ht_cap.ht_supported) ||
+		    !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
 			return;
 	} else if (mac->opmode == NL80211_IFTYPE_STATION) {
 		if (!mac->bw_40 || !(sta->ht_cap.ht_supported))
@@ -684,16 +786,74 @@
 	if (tcb_desc->hw_rate <= rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M])
 		return;
 
-	tcb_desc->packet_bw = true;
+	tcb_desc->packet_bw = HT_CHANNEL_WIDTH_20_40;
+
+	if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE ||
+	    rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8821AE) {
+		if (mac->opmode == NL80211_IFTYPE_AP ||
+		    mac->opmode == NL80211_IFTYPE_ADHOC ||
+		    mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+			if (!(sta->vht_cap.vht_supported))
+				return;
+		} else if (mac->opmode == NL80211_IFTYPE_STATION) {
+			if (!mac->bw_80 ||
+			    !(sta->vht_cap.vht_supported))
+				return;
+		}
+		if (tcb_desc->hw_rate <=
+			rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15])
+			return;
+		tcb_desc->packet_bw = HT_CHANNEL_WIDTH_80;
+	}
 }
 
-static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw)
+static u8 _rtl_get_vht_highest_n_rate(struct ieee80211_hw *hw,
+				      struct ieee80211_sta *sta)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	u8 hw_rate;
+	u16 tx_mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.tx_mcs_map);
 
-	if (get_rf_type(rtlphy) == RF_2T2R)
+	if ((get_rf_type(rtlphy) == RF_2T2R) &&
+	    (tx_mcs_map & 0x000c) != 0x000c) {
+		if ((tx_mcs_map & 0x000c) >> 2 ==
+			IEEE80211_VHT_MCS_SUPPORT_0_7)
+			hw_rate =
+			rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS7];
+		else if ((tx_mcs_map  & 0x000c) >> 2 ==
+			IEEE80211_VHT_MCS_SUPPORT_0_8)
+			hw_rate =
+			rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9];
+		else
+			hw_rate =
+			rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9];
+	} else {
+		if ((tx_mcs_map  & 0x0003) ==
+			IEEE80211_VHT_MCS_SUPPORT_0_7)
+			hw_rate =
+			rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS7];
+		else if ((tx_mcs_map  & 0x0003) ==
+			IEEE80211_VHT_MCS_SUPPORT_0_8)
+			hw_rate =
+			rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9];
+		else
+			hw_rate =
+			rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9];
+	}
+
+	return hw_rate;
+}
+
+static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw,
+				  struct ieee80211_sta *sta)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 hw_rate;
+
+	if ((get_rf_type(rtlphy) == RF_2T2R) &&
+	    (sta->ht_cap.mcs.rx_mask[1] != 0))
 		hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15];
 	else
 		hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7];
@@ -801,9 +961,7 @@
 				break;
 			}
 		}
-
 	} else {
-
 		switch (desc_rate) {
 		case DESC92_RATEMCS0:
 			rate_idx = 0;
@@ -862,31 +1020,6 @@
 }
 EXPORT_SYMBOL(rtlwifi_rate_mapping);
 
-bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	__le16 fc = rtl_get_fc(skb);
-
-	if (rtlpriv->dm.supp_phymode_switch &&
-	    mac->link_state < MAC80211_LINKED &&
-	    (ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) {
-		if (rtlpriv->cfg->ops->chk_switch_dmdp)
-			rtlpriv->cfg->ops->chk_switch_dmdp(hw);
-	}
-	if (ieee80211_is_auth(fc)) {
-		RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n");
-		rtl_ips_nic_on(hw);
-
-		mac->link_state = MAC80211_LINKING;
-		/* Dual mac */
-		rtlpriv->phy.need_iqk = true;
-	}
-
-	return true;
-}
-EXPORT_SYMBOL_GPL(rtl_tx_mgmt_proc);
-
 void rtl_get_tcb_desc(struct ieee80211_hw *hw,
 		      struct ieee80211_tx_info *info,
 		      struct ieee80211_sta *sta,
@@ -896,13 +1029,11 @@
 	struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
 	struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
 	struct ieee80211_rate *txrate;
-	__le16 fc = hdr->frame_control;
+	__le16 fc = rtl_get_fc(skb);
 
 	txrate = ieee80211_get_tx_rate(hw, info);
 	if (txrate)
 		tcb_desc->hw_rate = txrate->hw_value;
-	else
-		tcb_desc->hw_rate = 0;
 
 	if (ieee80211_is_data(fc)) {
 		/*
@@ -929,15 +1060,21 @@
 			 *and N rate will all be controlled by FW
 			 *when tcb_desc->use_driver_rate = false
 			 */
-			if (sta && (sta->ht_cap.ht_supported)) {
-				tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw);
+			if (sta && sta->vht_cap.vht_supported) {
+				tcb_desc->hw_rate =
+				_rtl_get_vht_highest_n_rate(hw, sta);
 			} else {
-				if (rtlmac->mode == WIRELESS_MODE_B) {
+				if (sta && (sta->ht_cap.ht_supported)) {
 					tcb_desc->hw_rate =
-					   rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M];
+						_rtl_get_highest_n_rate(hw, sta);
 				} else {
-					tcb_desc->hw_rate =
-					   rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M];
+					if (rtlmac->mode == WIRELESS_MODE_B) {
+						tcb_desc->hw_rate =
+						    rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M];
+					} else {
+						tcb_desc->hw_rate =
+						    rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M];
+					}
 				}
 			}
 		}
@@ -962,54 +1099,58 @@
 }
 EXPORT_SYMBOL(rtl_get_tcb_desc);
 
-static bool addbareq_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
+bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	__le16 fc = rtl_get_fc(skb);
+
+	if (rtlpriv->dm.supp_phymode_switch &&
+	    mac->link_state < MAC80211_LINKED &&
+	    (ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) {
+		if (rtlpriv->cfg->ops->chk_switch_dmdp)
+			rtlpriv->cfg->ops->chk_switch_dmdp(hw);
+	}
+	if (ieee80211_is_auth(fc)) {
+		RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n");
+		rtl_ips_nic_on(hw);
+
+		mac->link_state = MAC80211_LINKING;
+		/* Dul mac */
+		rtlpriv->phy.need_iqk = true;
+
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(rtl_tx_mgmt_proc);
+
+struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw, u8 *sa,
+				u8 *bssid, u16 tid);
+
+static void process_agg_start(struct ieee80211_hw *hw,
+			      struct ieee80211_hdr *hdr, u16 tid)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct ieee80211_sta *sta = NULL;
-	struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
-	struct rtl_sta_info *sta_entry = NULL;
-	struct ieee80211_mgmt *mgmt = (void *)skb->data;
-	u16 capab = 0, tid = 0;
-	struct rtl_tid_data *tid_data;
-	struct sk_buff *skb_delba = NULL;
 	struct ieee80211_rx_status rx_status = { 0 };
+	struct sk_buff *skb_delba = NULL;
 
-	rcu_read_lock();
-	sta = rtl_find_sta(hw, hdr->addr3);
-	if (sta == NULL) {
-		RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_EMERG,
-			 "sta is NULL\n");
-		rcu_read_unlock();
-		return true;
+	skb_delba = rtl_make_del_ba(hw, hdr->addr2, hdr->addr3, tid);
+	if (skb_delba) {
+		rx_status.freq = hw->conf.chandef.chan->center_freq;
+		rx_status.band = hw->conf.chandef.chan->band;
+		rx_status.flag |= RX_FLAG_DECRYPTED;
+		rx_status.flag |= RX_FLAG_MACTIME_START;
+		rx_status.rate_idx = 0;
+		rx_status.signal = 50 + 10;
+		memcpy(IEEE80211_SKB_RXCB(skb_delba),
+		       &rx_status, sizeof(rx_status));
+		RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG,
+			      "fake del\n",
+			      skb_delba->data,
+			      skb_delba->len);
+		ieee80211_rx_irqsafe(hw, skb_delba);
 	}
-
-	sta_entry = (struct rtl_sta_info *)sta->drv_priv;
-	if (!sta_entry) {
-		rcu_read_unlock();
-		return true;
-	}
-	capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
-	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
-	tid_data = &sta_entry->tids[tid];
-	if (tid_data->agg.rx_agg_state == RTL_RX_AGG_START) {
-		skb_delba = rtl_make_del_ba(hw, hdr->addr2, hdr->addr3, tid);
-		if (skb_delba) {
-			rx_status.freq = hw->conf.chandef.chan->center_freq;
-			rx_status.band = hw->conf.chandef.chan->band;
-			rx_status.flag |= RX_FLAG_DECRYPTED;
-			rx_status.flag |= RX_FLAG_MACTIME_END;
-			rx_status.rate_idx = 0;
-			rx_status.signal = 50 + 10;
-			memcpy(IEEE80211_SKB_RXCB(skb_delba), &rx_status,
-			       sizeof(rx_status));
-			RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG,
-				      "fake del\n", skb_delba->data,
-				      skb_delba->len);
-			ieee80211_rx_irqsafe(hw, skb_delba);
-		}
-	}
-	rcu_read_unlock();
-	return false;
 }
 
 bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
@@ -1017,8 +1158,8 @@
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	__le16 fc = hdr->frame_control;
-	u8 *act = (u8 *)skb->data + MAC80211_3ADDR_LEN;
+	__le16 fc = rtl_get_fc(skb);
+	u8 *act = (u8 *)(((u8 *)skb->data + MAC80211_3ADDR_LEN));
 	u8 category;
 
 	if (!ieee80211_is_action(fc))
@@ -1034,18 +1175,47 @@
 				return false;
 
 			RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
-				 "%s ACT_ADDBAREQ From :%pM\n",
-				 is_tx ? "Tx" : "Rx", hdr->addr2);
+				"%s ACT_ADDBAREQ From :%pM\n",
+				is_tx ? "Tx" : "Rx", hdr->addr2);
 			RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "req\n",
-				      skb->data, skb->len);
-			if (!is_tx)
-				if (addbareq_rx(hw, skb))
+				skb->data, skb->len);
+			if (!is_tx) {
+				struct ieee80211_sta *sta = NULL;
+				struct rtl_sta_info *sta_entry = NULL;
+				struct rtl_tid_data *tid_data;
+				struct ieee80211_mgmt *mgmt = (void *)skb->data;
+				u16 capab = 0, tid = 0;
+
+				rcu_read_lock();
+				sta = rtl_find_sta(hw, hdr->addr3);
+				if (sta == NULL) {
+					RT_TRACE(rtlpriv, COMP_SEND | COMP_RECV,
+						 DBG_DMESG, "sta is NULL\n");
+					rcu_read_unlock();
 					return true;
+				}
+
+				sta_entry =
+					(struct rtl_sta_info *)sta->drv_priv;
+				if (!sta_entry) {
+					rcu_read_unlock();
+					return true;
+				}
+				capab =
+				  le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+				tid = (capab &
+				       IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+				tid_data = &sta_entry->tids[tid];
+				if (tid_data->agg.rx_agg_state ==
+				    RTL_RX_AGG_START)
+					process_agg_start(hw, hdr, tid);
+				rcu_read_unlock();
+			}
 			break;
 		case ACT_ADDBARSP:
 			RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
 				 "%s ACT_ADDBARSP From :%pM\n",
-				 is_tx ? "Tx" : "Rx", hdr->addr2);
+				  is_tx ? "Tx" : "Rx", hdr->addr2);
 			break;
 		case ACT_DELBA:
 			RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
@@ -1061,6 +1231,17 @@
 }
 EXPORT_SYMBOL_GPL(rtl_action_proc);
 
+static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc)
+{
+	rtlpriv->ra.is_special_data = true;
+	if (rtlpriv->cfg->ops->get_btc_status())
+		rtlpriv->btcoexist.btc_ops->btc_special_packet_notify(
+					rtlpriv, 1);
+	rtlpriv->enter_ps = false;
+	schedule_work(&rtlpriv->works.lps_change_work);
+	ppsc->last_delaylps_stamp_jiffies = jiffies;
+}
+
 /*should call before software enc*/
 u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
 {
@@ -1069,57 +1250,77 @@
 	__le16 fc = rtl_get_fc(skb);
 	u16 ether_type;
 	u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb);
+	u8 encrypt_header_len = 0;
+	u8 offset;
 	const struct iphdr *ip;
 
 	if (!ieee80211_is_data(fc))
-		return false;
+		goto end;
 
-	ip = (const struct iphdr *)(skb->data + mac_hdr_len +
-				    SNAP_SIZE + PROTOC_TYPE_SIZE);
-	ether_type = be16_to_cpup((__be16 *)
-				  (skb->data + mac_hdr_len + SNAP_SIZE));
-
-	switch (ether_type) {
-	case ETH_P_IP: {
-		struct udphdr *udp;
-		u16 src;
-		u16 dst;
-
-		if (ip->protocol != IPPROTO_UDP)
-			return false;
-		udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2));
-		src = be16_to_cpu(udp->source);
-		dst = be16_to_cpu(udp->dest);
-
-		/* If this case involves port 68 (UDP BOOTP client) connecting
-		 * with port 67 (UDP BOOTP server), then return true so that
-		 * the lowest speed is used.
-		 */
-		if (!((src == 68 && dst == 67) || (src == 67 && dst == 68)))
-			return false;
-
-		RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
-			 "dhcp %s !!\n", is_tx ? "Tx" : "Rx");
+	switch (rtlpriv->sec.pairwise_enc_algorithm) {
+	case WEP40_ENCRYPTION:
+	case WEP104_ENCRYPTION:
+		encrypt_header_len = 4;/*WEP_IV_LEN*/
 		break;
-	}
-	case ETH_P_ARP:
+	case TKIP_ENCRYPTION:
+		encrypt_header_len = 8;/*TKIP_IV_LEN*/
 		break;
-	case ETH_P_PAE:
-		RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
-			 "802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx");
+	case AESCCMP_ENCRYPTION:
+		encrypt_header_len = 8;/*CCMP_HDR_LEN;*/
 		break;
-	case ETH_P_IPV6:
-		/* TODO: Is this right? */
-		return false;
 	default:
-		return false;
+		break;
 	}
-	if (is_tx) {
-		rtlpriv->enter_ps = false;
-		schedule_work(&rtlpriv->works.lps_change_work);
-		ppsc->last_delaylps_stamp_jiffies = jiffies;
+
+	offset = mac_hdr_len + SNAP_SIZE + encrypt_header_len;
+	ether_type = be16_to_cpup((__be16 *)(skb->data + offset));
+
+	if (ETH_P_IP == ether_type) {
+		ip = (struct iphdr *)((u8 *)skb->data + offset +
+		     PROTOC_TYPE_SIZE);
+		if (IPPROTO_UDP == ip->protocol) {
+			struct udphdr *udp = (struct udphdr *)((u8 *)ip +
+							       (ip->ihl << 2));
+			if (((((u8 *)udp)[1] == 68) &&
+			     (((u8 *)udp)[3] == 67)) ||
+			    ((((u8 *)udp)[1] == 67) &&
+			     (((u8 *)udp)[3] == 68))) {
+				/* 68 : UDP BOOTP client
+				 * 67 : UDP BOOTP server
+				 */
+				RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV),
+					 DBG_DMESG, "dhcp %s !!\n",
+					 (is_tx) ? "Tx" : "Rx");
+
+				if (is_tx)
+					setup_arp_tx(rtlpriv, ppsc);
+				return true;
+			}
+		}
+	} else if (ETH_P_ARP == ether_type) {
+		if (is_tx)
+			setup_arp_tx(rtlpriv, ppsc);
+
+		return true;
+	} else if (ETH_P_PAE == ether_type) {
+		RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
+			 "802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx");
+
+		if (is_tx) {
+			rtlpriv->ra.is_special_data = true;
+			rtlpriv->enter_ps = false;
+			schedule_work(&rtlpriv->works.lps_change_work);
+			ppsc->last_delaylps_stamp_jiffies = jiffies;
+		}
+
+		return true;
+	} else if (0x86DD == ether_type) {
+		return true;
 	}
-	return true;
+
+end:
+	rtlpriv->ra.is_special_data = false;
+	return false;
 }
 EXPORT_SYMBOL_GPL(rtl_is_special_data);
 
@@ -1128,12 +1329,11 @@
  * functions called by core.c
  *
  *********************************************************/
-int rtl_tx_agg_start(struct ieee80211_hw *hw,
-		struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		     struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_tid_data *tid_data;
-	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_sta_info *sta_entry = NULL;
 
 	if (sta == NULL)
@@ -1147,43 +1347,38 @@
 		return -ENXIO;
 	tid_data = &sta_entry->tids[tid];
 
-	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "on ra = %pM tid = %d seq:%d\n",
-		 sta->addr, tid, tid_data->seq_number);
+	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
+		 "on ra = %pM tid = %d seq:%d\n", sta->addr, tid,
+		 tid_data->seq_number);
 
 	*ssn = tid_data->seq_number;
 	tid_data->agg.agg_state = RTL_AGG_START;
 
-	ieee80211_start_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid);
-
+	ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 	return 0;
 }
 
-int rtl_tx_agg_stop(struct ieee80211_hw *hw,
-		struct ieee80211_sta *sta, u16 tid)
+int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		    struct ieee80211_sta *sta, u16 tid)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_tid_data *tid_data;
 	struct rtl_sta_info *sta_entry = NULL;
 
 	if (sta == NULL)
 		return -EINVAL;
 
-	if (!sta->addr) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "ra = NULL\n");
-		return -EINVAL;
-	}
-
-	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "on ra = %pM tid = %d\n",
-		 sta->addr, tid);
+	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
+		 "on ra = %pM tid = %d\n", sta->addr, tid);
 
 	if (unlikely(tid >= MAX_TID_COUNT))
 		return -EINVAL;
 
 	sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+	tid_data = &sta_entry->tids[tid];
 	sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP;
 
-	ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid);
-
+	ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 	return 0;
 }
 
@@ -1222,11 +1417,6 @@
 	if (sta == NULL)
 		return -EINVAL;
 
-	if (!sta->addr) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "ra = NULL\n");
-		return -EINVAL;
-	}
-
 	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
 		 "on ra = %pM tid = %d\n", sta->addr, tid);
 
@@ -1238,7 +1428,6 @@
 
 	return 0;
 }
-
 int rtl_tx_agg_oper(struct ieee80211_hw *hw,
 		struct ieee80211_sta *sta, u16 tid)
 {
@@ -1248,13 +1437,8 @@
 	if (sta == NULL)
 		return -EINVAL;
 
-	if (!sta->addr) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "ra = NULL\n");
-		return -EINVAL;
-	}
-
-	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "on ra = %pM tid = %d\n",
-		 sta->addr, tid);
+	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
+		 "on ra = %pM tid = %d\n", sta->addr, tid);
 
 	if (unlikely(tid >= MAX_TID_COUNT))
 		return -EINVAL;
@@ -1292,7 +1476,7 @@
 		return;
 
 	/* and only beacons from the associated BSSID, please */
-	if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid))
+	if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
 		return;
 
 	rtlpriv->link_info.bcn_rx_inperiod++;
@@ -1332,8 +1516,7 @@
 		mac->cnt_after_linked = 0;
 	}
 
-	/*
-	 *<2> to check if traffic busy, if
+	/* <2> to check if traffic busy, if
 	 * busytraffic we don't change channel
 	 */
 	if (mac->link_state >= MAC80211_LINKED) {
@@ -1381,32 +1564,29 @@
 		for (tid = 0; tid <= 7; tid++) {
 			for (idx = 0; idx <= 2; idx++)
 				rtlpriv->link_info.tidtx_in4period[tid][idx] =
-				  rtlpriv->link_info.tidtx_in4period[tid]
-				  [idx + 1];
+					rtlpriv->link_info.tidtx_in4period[tid]
+					[idx + 1];
 			rtlpriv->link_info.tidtx_in4period[tid][3] =
 				rtlpriv->link_info.tidtx_inperiod[tid];
 
 			for (idx = 0; idx <= 3; idx++)
 				tidtx_inp4eriod[tid] +=
-				  rtlpriv->link_info.tidtx_in4period[tid][idx];
+				   rtlpriv->link_info.tidtx_in4period[tid][idx];
 			aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4;
 			if (aver_tidtx_inperiod[tid] > 5000)
 				rtlpriv->link_info.higher_busytxtraffic[tid] =
-						   true;
+									true;
 			else
 				rtlpriv->link_info.higher_busytxtraffic[tid] =
-						   false;
+									false;
 		}
 
 		if (((rtlpriv->link_info.num_rx_inperiod +
 		      rtlpriv->link_info.num_tx_inperiod) > 8) ||
 		    (rtlpriv->link_info.num_rx_inperiod > 2))
-			rtlpriv->enter_ps = true;
+			rtl_lps_enter(hw);
 		else
-			rtlpriv->enter_ps = false;
-
-		/* LeisurePS only work in infra mode. */
-		schedule_work(&rtlpriv->works.lps_change_work);
+			rtl_lps_leave(hw);
 	}
 
 	rtlpriv->link_info.num_rx_inperiod = 0;
@@ -1421,32 +1601,37 @@
 	rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic;
 
 	/* <3> DM */
-	rtlpriv->cfg->ops->dm_watchdog(hw);
+	if (!rtlpriv->cfg->mod_params->disable_watchdog)
+		rtlpriv->cfg->ops->dm_watchdog(hw);
 
 	/* <4> roaming */
 	if (mac->link_state == MAC80211_LINKED &&
 	    mac->opmode == NL80211_IFTYPE_STATION) {
 		if ((rtlpriv->link_info.bcn_rx_inperiod +
-		     rtlpriv->link_info.num_rx_inperiod) == 0) {
+		    rtlpriv->link_info.num_rx_inperiod) == 0) {
 			rtlpriv->link_info.roam_times++;
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
 				 "AP off for %d s\n",
-				 (rtlpriv->link_info.roam_times * 2));
+				(rtlpriv->link_info.roam_times * 2));
 
-			/* if we can't recv beacon for 6s, we should
-			 * reconnect this AP
+			/* if we can't recv beacon for 10s,
+			 * we should reconnect this AP
 			 */
-			if ((rtlpriv->link_info.roam_times >= 3) &&
-			    !is_zero_ether_addr(rtlpriv->mac80211.bssid)) {
+			if (rtlpriv->link_info.roam_times >= 5) {
 				RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 					 "AP off, try to reconnect now\n");
 				rtlpriv->link_info.roam_times = 0;
-				ieee80211_connection_loss(rtlpriv->mac80211.vif);
+				ieee80211_connection_loss(
+					rtlpriv->mac80211.vif);
 			}
 		} else {
 			rtlpriv->link_info.roam_times = 0;
 		}
 	}
+
+	if (rtlpriv->cfg->ops->get_btc_status())
+		rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv);
+
 	rtlpriv->link_info.bcn_rx_inperiod = 0;
 }
 
@@ -1461,7 +1646,6 @@
 	mod_timer(&rtlpriv->works.watchdog_timer,
 		  jiffies + MSECS(RTL_WATCH_DOG_TIME));
 }
-
 void rtl_fwevt_wq_callback(void *data)
 {
 	struct rtl_works *rtlworks =
@@ -1471,7 +1655,6 @@
 
 	rtlpriv->cfg->ops->c2h_command_handle(hw);
 }
-
 void rtl_easy_concurrent_retrytimer_callback(unsigned long data)
 {
 	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
@@ -1483,7 +1666,6 @@
 
 	rtlpriv->cfg->ops->dualmac_easy_concurrent(hw);
 }
-
 /*********************************************************
  *
  * frame process functions
@@ -1511,7 +1693,8 @@
 /* when we use 2 rx ants we send IEEE80211_SMPS_OFF */
 /* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */
 static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw,
-		enum ieee80211_smps_mode smps, u8 *da, u8 *bssid)
+				     enum ieee80211_smps_mode smps,
+				     u8 *da, u8 *bssid)
 {
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	struct sk_buff *skb;
@@ -1536,6 +1719,9 @@
 	case IEEE80211_SMPS_AUTOMATIC:/* 0 */
 	case IEEE80211_SMPS_NUM_MODES:/* 4 */
 		WARN_ON(1);
+	/* Here will get a 'MISSING_BREAK' in Coverity Test, just ignore it.
+	 * According to Kernel Code, here is right.
+	 */
 	case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/
 		action_frame->u.action.u.ht_smps.smps_control =
 				WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */
@@ -1554,8 +1740,8 @@
 }
 
 int rtl_send_smps_action(struct ieee80211_hw *hw,
-		struct ieee80211_sta *sta,
-		enum ieee80211_smps_mode smps)
+			 struct ieee80211_sta *sta,
+			 enum ieee80211_smps_mode smps)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -1590,6 +1776,7 @@
 		struct rtl_sta_info *sta_entry =
 			(struct rtl_sta_info *) sta->drv_priv;
 		sta_entry->mimo_ps = smps;
+		/* rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); */
 
 		info->control.rates[0].idx = 0;
 		info->band = hw->conf.chandef.chan->band;
@@ -1631,10 +1818,10 @@
 }
 EXPORT_SYMBOL(rtl_phy_scan_operation_backup);
 
-/* There seem to be issues in mac80211 regarding when del ba frames can be
- * received. As a work around, we make a fake del_ba if we receive a ba_req;
- * however, rx_agg was opened to let mac80211 release some ba related
- * resources. This del_ba is for tx only.
+/* because mac80211 have issues when can receive del ba
+ * so here we just make a fake del_ba if we receive a ba_req
+ * but rx_agg was opened to let mac80211 release some ba
+ * related resources, so please this del_ba for tx
  */
 struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw,
 				u8 *sa, u8 *bssid, u16 tid)
@@ -1660,7 +1847,7 @@
 	action_frame->u.action.category = WLAN_CATEGORY_BACK;
 	action_frame->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
 	params = (u16)(1 << 11);	/* bit 11 initiator */
-	params |= (u16)(tid << 12);		/* bit 15:12 TID number */
+	params |= (u16)(tid << 12);	/* bit 15:12 TID number */
 
 	action_frame->u.action.u.delba.params = cpu_to_le16(params);
 	action_frame->u.action.u.delba.reason_code =
@@ -1675,7 +1862,7 @@
  *
  *********************************************************/
 static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw,
-		struct octet_string vendor_ie)
+				  struct octet_string vendor_ie)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	bool matched = false;
@@ -1848,11 +2035,13 @@
 
 	ret = kstrtoul(buf, 0, &val);
 	if (ret) {
-		printk(KERN_DEBUG "%s is not in hex or decimal form.\n", buf);
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
+			 "%s is not in hex or decimal form.\n", buf);
 	} else {
 		rtlpriv->dbg.global_debuglevel = val;
-		printk(KERN_DEBUG "debuglevel:%x\n",
-		       rtlpriv->dbg.global_debuglevel);
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
+			 "debuglevel:%x\n",
+			 rtlpriv->dbg.global_debuglevel);
 	}
 
 	return strnlen(buf, count);
@@ -1892,7 +2081,7 @@
 static int __init rtl_core_module_init(void)
 {
 	if (rtl_rate_control_register())
-		pr_err("Unable to register rtl_rc, use default RC !!\n");
+		pr_err("rtl: Unable to register rtl_rc, use default RC !!\n");
 
 	/* init some global vars */
 	INIT_LIST_HEAD(&rtl_global_var.glb_priv_list);
diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h
index 0cd0742..982f245 100644
--- a/drivers/net/wireless/rtlwifi/base.h
+++ b/drivers/net/wireless/rtlwifi/base.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -41,7 +37,7 @@
 	PEER_MARV = 7,
 	PEER_AIRGO = 9,
 	PEER_MAX = 10,
-} ;
+};
 
 #define RTL_DUMMY_OFFSET	0
 #define RTL_DUMMY_UNIT		8
@@ -55,6 +51,16 @@
 #define MAX_BIT_RATE_40MHZ_MCS15	300	/* Mbps */
 #define MAX_BIT_RATE_40MHZ_MCS7		150	/* Mbps */
 
+#define MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9	867	/* Mbps */
+#define MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS7	650	/* Mbps */
+#define MAX_BIT_RATE_LONG_GI_2NSS_80MHZ_MCS9	780	/* Mbps */
+#define MAX_BIT_RATE_LONG_GI_2NSS_80MHZ_MCS7	585	/* Mbps */
+
+#define MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9	434	/* Mbps */
+#define MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS7	325	/* Mbps */
+#define MAX_BIT_RATE_LONG_GI_1NSS_80MHZ_MCS9	390	/* Mbps */
+#define MAX_BIT_RATE_LONG_GI_1NSS_80MHZ_MCS7	293	/* Mbps */
+
 #define RTL_RATE_COUNT_LEGACY		12
 #define RTL_CHANNEL_COUNT		14
 
@@ -78,9 +84,9 @@
 #define SET_80211_PS_POLL_AID(_hdr, _val)		\
 	(*(u16 *)((u8 *)(_hdr) + 2) = _val)
 #define SET_80211_PS_POLL_BSSID(_hdr, _val)		\
-	memcpy(((u8 *)(_hdr)) + 4, (u8 *)(_val), ETH_ALEN)
+	ether_addr_copy(((u8 *)(_hdr)) + 4, (u8 *)(_val))
 #define SET_80211_PS_POLL_TA(_hdr, _val)		\
-	memcpy(((u8 *)(_hdr)) + 10, (u8 *)(_val), ETH_ALEN)
+	ether_addr_copy(((u8 *)(_hdr))+10, (u8 *)(_val))
 
 #define SET_80211_HDR_DURATION(_hdr, _val)	\
 	(*(u16 *)((u8 *)(_hdr) + FRAME_OFFSET_DURATION) = le16_to_cpu(_val))
@@ -113,23 +119,27 @@
 void rtl_init_rfkill(struct ieee80211_hw *hw);
 void rtl_deinit_rfkill(struct ieee80211_hw *hw);
 
-void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb);
+void rtl_watch_dog_timer_callback(unsigned long data);
 void rtl_deinit_deferred_work(struct ieee80211_hw *hw);
 
 bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
+int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
+			 bool isht, u8 desc_rate, bool first_ampdu);
+bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
 u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
 
+void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb);
 void rtl_watch_dog_timer_callback(unsigned long data);
-int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
-		     u16 tid, u16 *ssn);
-int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
-		    u16 tid);
-int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
-		    u16 tid);
-int rtl_rx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
-		     u16 tid);
-int rtl_rx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
-		    u16 tid);
+int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+	struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+	struct ieee80211_sta *sta, u16 tid);
+int rtl_tx_agg_oper(struct ieee80211_hw *hw,
+		    struct ieee80211_sta *sta, u16 tid);
+int rtl_rx_agg_start(struct ieee80211_hw *hw,
+		     struct ieee80211_sta *sta, u16 tid);
+int rtl_rx_agg_stop(struct ieee80211_hw *hw,
+		    struct ieee80211_sta *sta, u16 tid);
 void rtl_watchdog_wq_callback(void *data);
 void rtl_fwevt_wq_callback(void *data);
 
@@ -139,19 +149,14 @@
 		      struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc);
 
 int rtl_send_smps_action(struct ieee80211_hw *hw,
-			 struct ieee80211_sta *sta,
-			 enum ieee80211_smps_mode smps);
+		struct ieee80211_sta *sta,
+		enum ieee80211_smps_mode smps);
 u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie);
 void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
 u8 rtl_tid_to_ac(u8 tid);
 extern struct attribute_group rtl_attribute_group;
 void rtl_easy_concurrent_retrytimer_callback(unsigned long data);
 extern struct rtl_global_var rtl_global_var;
-int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
-			 bool isht, u8 desc_rate, bool first_ampdu);
-bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
-struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw,
-				u8 *sa, u8 *bssid, u16 tid);
 void rtl_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h
index d76684e..39b9a33 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbt_precomp.h
@@ -37,7 +37,13 @@
 
 #include "halbtcoutsrc.h"
 
+#include "halbtc8192e2ant.h"
+#include "halbtc8723b1ant.h"
 #include "halbtc8723b2ant.h"
+#include "halbtc8821a2ant.h"
+#include "halbtc8821a1ant.h"
+
+#define GetDefaultAdapter(padapter)	padapter
 
 #define BIT0	0x00000001
 #define BIT1	0x00000002
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c
new file mode 100644
index 0000000..53261d6
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.c
@@ -0,0 +1,3849 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+/**************************************************************
+ * Description:
+ *
+ * This file is for RTL8192E Co-exist mechanism
+ *
+ * History
+ * 2012/11/15 Cosa first check in.
+ *
+ **************************************************************/
+
+/**************************************************************
+ *   include files
+ **************************************************************/
+#include "halbt_precomp.h"
+/**************************************************************
+ *   Global variables, these are static variables
+ **************************************************************/
+static struct coex_dm_8192e_2ant glcoex_dm_8192e_2ant;
+static struct coex_dm_8192e_2ant *coex_dm = &glcoex_dm_8192e_2ant;
+static struct coex_sta_8192e_2ant glcoex_sta_8192e_2ant;
+static struct coex_sta_8192e_2ant *coex_sta = &glcoex_sta_8192e_2ant;
+
+static const char *const GLBtInfoSrc8192e2Ant[] = {
+	"BT Info[wifi fw]",
+	"BT Info[bt rsp]",
+	"BT Info[bt auto report]",
+};
+
+static u32 glcoex_ver_date_8192e_2ant = 20130902;
+static u32 glcoex_ver_8192e_2ant = 0x34;
+
+/**************************************************************
+ *   local function proto type if needed
+ **************************************************************/
+/**************************************************************
+ *   local function start with halbtc8192e2ant_
+ **************************************************************/
+static u8 halbtc8192e2ant_btrssi_state(u8 level_num, u8 rssi_thresh,
+				       u8 rssi_thresh1)
+{
+	int btrssi = 0;
+	u8 btrssi_state = coex_sta->pre_bt_rssi_state;
+
+	btrssi = coex_sta->bt_rssi;
+
+	if (level_num == 2) {
+		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+				  "BT Rssi pre state = LOW\n");
+			if (btrssi >= (rssi_thresh +
+				       BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+				btrssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "BT Rssi state switch to High\n");
+			} else {
+				btrssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "BT Rssi state stay at Low\n");
+			}
+		} else {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+				  "BT Rssi pre state = HIGH\n");
+			if (btrssi < rssi_thresh) {
+				btrssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "BT Rssi state switch to Low\n");
+			} else {
+				btrssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "BT Rssi state stay at High\n");
+			}
+		}
+	} else if (level_num == 3) {
+		if (rssi_thresh > rssi_thresh1) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+				  "BT Rssi thresh error!!\n");
+			return coex_sta->pre_bt_rssi_state;
+		}
+
+		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+				  "BT Rssi pre state = LOW\n");
+			if (btrssi >= (rssi_thresh +
+				      BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+				btrssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "BT Rssi state switch to Medium\n");
+			} else {
+				btrssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "BT Rssi state stay at Low\n");
+			}
+		} else if ((coex_sta->pre_bt_rssi_state ==
+			    BTC_RSSI_STATE_MEDIUM) ||
+			   (coex_sta->pre_bt_rssi_state ==
+			    BTC_RSSI_STATE_STAY_MEDIUM)) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+				  "[BTCoex], BT Rssi pre state = MEDIUM\n");
+			if (btrssi >= (rssi_thresh1 +
+				       BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+				btrssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "BT Rssi state switch to High\n");
+			} else if (btrssi < rssi_thresh) {
+				btrssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "BT Rssi state switch to Low\n");
+			} else {
+				btrssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "BT Rssi state stay at Medium\n");
+			}
+		} else {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+				  "BT Rssi pre state = HIGH\n");
+			if (btrssi < rssi_thresh1) {
+				btrssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "BT Rssi state switch to Medium\n");
+			} else {
+				btrssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "BT Rssi state stay at High\n");
+			}
+		}
+	}
+
+	coex_sta->pre_bt_rssi_state = btrssi_state;
+
+	return btrssi_state;
+}
+
+static u8 halbtc8192e2ant_wifirssi_state(struct btc_coexist *btcoexist,
+					 u8 index, u8 level_num, u8 rssi_thresh,
+					 u8 rssi_thresh1)
+{
+	int wifirssi = 0;
+	u8 wifirssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi);
+
+	if (level_num == 2) {
+		if ((coex_sta->pre_wifi_rssi_state[index] ==
+		     BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_wifi_rssi_state[index] ==
+		     BTC_RSSI_STATE_STAY_LOW)) {
+			if (wifirssi >= (rssi_thresh +
+					 BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+				wifirssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "wifi RSSI state switch to High\n");
+			} else {
+				wifirssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "wifi RSSI state stay at Low\n");
+			}
+		} else {
+			if (wifirssi < rssi_thresh) {
+				wifirssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "wifi RSSI state switch to Low\n");
+			} else {
+				wifirssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "wifi RSSI state stay at High\n");
+			}
+		}
+	} else if (level_num == 3) {
+		if (rssi_thresh > rssi_thresh1) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+				  "wifi RSSI thresh error!!\n");
+			return coex_sta->pre_wifi_rssi_state[index];
+		}
+
+		if ((coex_sta->pre_wifi_rssi_state[index] ==
+		     BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_wifi_rssi_state[index] ==
+		     BTC_RSSI_STATE_STAY_LOW)) {
+			if (wifirssi >= (rssi_thresh +
+					 BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+				wifirssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "wifi RSSI state switch to Medium\n");
+			} else {
+				wifirssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "wifi RSSI state stay at Low\n");
+			}
+		} else if ((coex_sta->pre_wifi_rssi_state[index] ==
+			    BTC_RSSI_STATE_MEDIUM) ||
+			   (coex_sta->pre_wifi_rssi_state[index] ==
+			    BTC_RSSI_STATE_STAY_MEDIUM)) {
+			if (wifirssi >= (rssi_thresh1 +
+					 BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) {
+				wifirssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "wifi RSSI state switch to High\n");
+			} else if (wifirssi < rssi_thresh) {
+				wifirssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "wifi RSSI state switch to Low\n");
+			} else {
+				wifirssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "wifi RSSI state stay at Medium\n");
+			}
+		} else {
+			if (wifirssi < rssi_thresh1) {
+				wifirssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "wifi RSSI state switch to Medium\n");
+			} else {
+				wifirssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "wifi RSSI state stay at High\n");
+			}
+		}
+	}
+
+	coex_sta->pre_wifi_rssi_state[index] = wifirssi_state;
+
+	return wifirssi_state;
+}
+
+static void btc8192e2ant_monitor_bt_enable_dis(struct btc_coexist *btcoexist)
+{
+	static bool pre_bt_disabled;
+	static u32 bt_disable_cnt;
+	bool bt_active = true, bt_disabled = false;
+
+	/* This function check if bt is disabled */
+
+	if (coex_sta->high_priority_tx == 0 &&
+	    coex_sta->high_priority_rx == 0 &&
+	    coex_sta->low_priority_tx == 0 &&
+	    coex_sta->low_priority_rx == 0)
+		bt_active = false;
+
+	if (coex_sta->high_priority_tx == 0xffff &&
+	    coex_sta->high_priority_rx == 0xffff &&
+	    coex_sta->low_priority_tx == 0xffff &&
+	    coex_sta->low_priority_rx == 0xffff)
+		bt_active = false;
+
+	if (bt_active) {
+		bt_disable_cnt = 0;
+		bt_disabled = false;
+		btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+				   &bt_disabled);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+			  "[BTCoex], BT is enabled !!\n");
+	} else {
+		bt_disable_cnt++;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+			  "[BTCoex], bt all counters = 0, %d times!!\n",
+			  bt_disable_cnt);
+		if (bt_disable_cnt >= 2) {
+			bt_disabled = true;
+			btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+					   &bt_disabled);
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+				  "[BTCoex], BT is disabled !!\n");
+		}
+	}
+	if (pre_bt_disabled != bt_disabled) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+			  "[BTCoex], BT is from %s to %s!!\n",
+			  (pre_bt_disabled ? "disabled" : "enabled"),
+			  (bt_disabled ? "disabled" : "enabled"));
+		pre_bt_disabled = bt_disabled;
+	}
+}
+
+static u32 halbtc8192e2ant_decidera_mask(struct btc_coexist *btcoexist,
+					 u8 sstype, u32 ra_masktype)
+{
+	u32 disra_mask = 0x0;
+
+	switch (ra_masktype) {
+	case 0: /* normal mode */
+		if (sstype == 2)
+			disra_mask = 0x0;	/* enable 2ss */
+		else
+			disra_mask = 0xfff00000;/* disable 2ss */
+		break;
+	case 1: /* disable cck 1/2 */
+		if (sstype == 2)
+			disra_mask = 0x00000003;/* enable 2ss */
+		else
+			disra_mask = 0xfff00003;/* disable 2ss */
+		break;
+	case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */
+		if (sstype == 2)
+			disra_mask = 0x0001f1f7;/* enable 2ss */
+		else
+			disra_mask = 0xfff1f1f7;/* disable 2ss */
+		break;
+	default:
+		break;
+	}
+
+	return disra_mask;
+}
+
+static void halbtc8192e2ant_Updatera_mask(struct btc_coexist *btcoexist,
+					  bool force_exec, u32 dis_ratemask)
+{
+	coex_dm->curra_mask = dis_ratemask;
+
+	if (force_exec || (coex_dm->prera_mask != coex_dm->curra_mask))
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask,
+				   &coex_dm->curra_mask);
+	coex_dm->prera_mask = coex_dm->curra_mask;
+}
+
+static void btc8192e2ant_autorate_fallback_retry(struct btc_coexist *btcoexist,
+						 bool force_exec, u8 type)
+{
+	bool wifi_under_bmode = false;
+
+	coex_dm->cur_arfrtype = type;
+
+	if (force_exec || (coex_dm->pre_arfrtype != coex_dm->cur_arfrtype)) {
+		switch (coex_dm->cur_arfrtype) {
+		case 0:	/* normal mode */
+			btcoexist->btc_write_4byte(btcoexist, 0x430,
+						   coex_dm->backup_arfr_cnt1);
+			btcoexist->btc_write_4byte(btcoexist, 0x434,
+						   coex_dm->backup_arfr_cnt2);
+			break;
+		case 1:
+			btcoexist->btc_get(btcoexist,
+					   BTC_GET_BL_WIFI_UNDER_B_MODE,
+					   &wifi_under_bmode);
+			if (wifi_under_bmode) {
+				btcoexist->btc_write_4byte(btcoexist, 0x430,
+							   0x0);
+				btcoexist->btc_write_4byte(btcoexist, 0x434,
+							   0x01010101);
+			} else {
+				btcoexist->btc_write_4byte(btcoexist, 0x430,
+							   0x0);
+				btcoexist->btc_write_4byte(btcoexist, 0x434,
+							   0x04030201);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	coex_dm->pre_arfrtype = coex_dm->cur_arfrtype;
+}
+
+static void halbtc8192e2ant_retrylimit(struct btc_coexist *btcoexist,
+				       bool force_exec, u8 type)
+{
+	coex_dm->cur_retrylimit_type = type;
+
+	if (force_exec || (coex_dm->pre_retrylimit_type !=
+			   coex_dm->cur_retrylimit_type)) {
+		switch (coex_dm->cur_retrylimit_type) {
+		case 0:	/* normal mode */
+				btcoexist->btc_write_2byte(btcoexist, 0x42a,
+						    coex_dm->backup_retrylimit);
+				break;
+		case 1:	/* retry limit = 8 */
+				btcoexist->btc_write_2byte(btcoexist, 0x42a,
+							   0x0808);
+				break;
+		default:
+				break;
+		}
+	}
+
+	coex_dm->pre_retrylimit_type = coex_dm->cur_retrylimit_type;
+}
+
+static void halbtc8192e2ant_ampdu_maxtime(struct btc_coexist *btcoexist,
+					  bool force_exec, u8 type)
+{
+	coex_dm->cur_ampdutime_type = type;
+
+	if (force_exec || (coex_dm->pre_ampdutime_type !=
+			   coex_dm->cur_ampdutime_type)) {
+		switch (coex_dm->cur_ampdutime_type) {
+		case 0:	/* normal mode */
+			btcoexist->btc_write_1byte(btcoexist, 0x456,
+						coex_dm->backup_ampdu_maxtime);
+			break;
+		case 1:	/* AMPDU timw = 0x38 * 32us */
+			btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38);
+			break;
+		default:
+			break;
+		}
+	}
+
+	coex_dm->pre_ampdutime_type = coex_dm->cur_ampdutime_type;
+}
+
+static void halbtc8192e2ant_limited_tx(struct btc_coexist *btcoexist,
+				       bool force_exec, u8 ra_masktype,
+				       u8 arfr_type, u8 retrylimit_type,
+				       u8 ampdutime_type)
+{
+	u32 disra_mask = 0x0;
+
+	coex_dm->curra_masktype = ra_masktype;
+	disra_mask = halbtc8192e2ant_decidera_mask(btcoexist,
+						   coex_dm->cur_sstype,
+						   ra_masktype);
+	halbtc8192e2ant_Updatera_mask(btcoexist, force_exec, disra_mask);
+btc8192e2ant_autorate_fallback_retry(btcoexist, force_exec, arfr_type);
+	halbtc8192e2ant_retrylimit(btcoexist, force_exec, retrylimit_type);
+	halbtc8192e2ant_ampdu_maxtime(btcoexist, force_exec, ampdutime_type);
+}
+
+static void halbtc8192e2ant_limited_rx(struct btc_coexist *btcoexist,
+				       bool force_exec, bool rej_ap_agg_pkt,
+				       bool bt_ctrl_agg_buf_size,
+				       u8 agg_buf_size)
+{
+	bool reject_rx_agg = rej_ap_agg_pkt;
+	bool bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size;
+	u8 rx_agg_size = agg_buf_size;
+
+	/*********************************************
+	 *	Rx Aggregation related setting
+	 *********************************************/
+	btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT,
+			   &reject_rx_agg);
+	/* decide BT control aggregation buf size or not */
+	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE,
+			   &bt_ctrl_rx_agg_size);
+	/* aggregation buf size, only work
+	 * when BT control Rx aggregation size.
+	 */
+	btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size);
+	/* real update aggregation setting */
+	btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL);
+}
+
+static void halbtc8192e2ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+	u32 reg_hp_txrx, reg_lp_txrx, u32tmp;
+	u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0;
+
+	reg_hp_txrx = 0x770;
+	reg_lp_txrx = 0x774;
+
+	u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx);
+	reg_hp_tx = u32tmp & MASKLWORD;
+	reg_hp_rx = (u32tmp & MASKHWORD)>>16;
+
+	u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx);
+	reg_lp_tx = u32tmp & MASKLWORD;
+	reg_lp_rx = (u32tmp & MASKHWORD)>>16;
+
+	coex_sta->high_priority_tx = reg_hp_tx;
+	coex_sta->high_priority_rx = reg_hp_rx;
+	coex_sta->low_priority_tx = reg_lp_tx;
+	coex_sta->low_priority_rx = reg_lp_rx;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+		  "[BTCoex] High Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
+		  reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx);
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+		  "[BTCoex] Low Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
+		  reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx);
+
+	/* reset counter */
+	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static void halbtc8192e2ant_querybt_info(struct btc_coexist *btcoexist)
+{
+	u8 h2c_parameter[1] = {0};
+
+	coex_sta->c2h_bt_info_req_sent = true;
+
+	h2c_parameter[0] |= BIT0;	/* trigger */
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+		  h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_update_btlink_info(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	bool bt_hson = false;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson);
+
+	bt_link_info->bt_link_exist = coex_sta->bt_link_exist;
+	bt_link_info->sco_exist = coex_sta->sco_exist;
+	bt_link_info->a2dp_exist = coex_sta->a2dp_exist;
+	bt_link_info->pan_exist = coex_sta->pan_exist;
+	bt_link_info->hid_exist = coex_sta->hid_exist;
+
+	/* work around for HS mode. */
+	if (bt_hson) {
+		bt_link_info->pan_exist = true;
+		bt_link_info->bt_link_exist = true;
+	}
+
+	/* check if Sco only */
+	if (bt_link_info->sco_exist &&
+	    !bt_link_info->a2dp_exist &&
+	    !bt_link_info->pan_exist &&
+	    !bt_link_info->hid_exist)
+		bt_link_info->sco_only = true;
+	else
+		bt_link_info->sco_only = false;
+
+	/* check if A2dp only */
+	if (!bt_link_info->sco_exist &&
+	    bt_link_info->a2dp_exist &&
+	    !bt_link_info->pan_exist &&
+	    !bt_link_info->hid_exist)
+		bt_link_info->a2dp_only = true;
+	else
+		bt_link_info->a2dp_only = false;
+
+	/* check if Pan only */
+	if (!bt_link_info->sco_exist &&
+	    !bt_link_info->a2dp_exist &&
+	    bt_link_info->pan_exist &&
+	    !bt_link_info->hid_exist)
+		bt_link_info->pan_only = true;
+	else
+		bt_link_info->pan_only = false;
+
+	/* check if Hid only */
+	if (!bt_link_info->sco_exist &&
+	    !bt_link_info->a2dp_exist &&
+	    !bt_link_info->pan_exist &&
+	    bt_link_info->hid_exist)
+		bt_link_info->hid_only = true;
+	else
+		bt_link_info->hid_only = false;
+}
+
+static u8 halbtc8192e2ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	struct btc_stack_info *stack_info = &btcoexist->stack_info;
+	bool bt_hson = false;
+	u8 algorithm = BT_8192E_2ANT_COEX_ALGO_UNDEFINED;
+	u8 numdiffprofile = 0;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson);
+
+	if (!bt_link_info->bt_link_exist) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "No BT link exists!!!\n");
+		return algorithm;
+	}
+
+	if (bt_link_info->sco_exist)
+		numdiffprofile++;
+	if (bt_link_info->hid_exist)
+		numdiffprofile++;
+	if (bt_link_info->pan_exist)
+		numdiffprofile++;
+	if (bt_link_info->a2dp_exist)
+		numdiffprofile++;
+
+	if (numdiffprofile == 1) {
+		if (bt_link_info->sco_exist) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "SCO only\n");
+			algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+		} else {
+			if (bt_link_info->hid_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "HID only\n");
+				algorithm = BT_8192E_2ANT_COEX_ALGO_HID;
+			} else if (bt_link_info->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "A2DP only\n");
+				algorithm = BT_8192E_2ANT_COEX_ALGO_A2DP;
+			} else if (bt_link_info->pan_exist) {
+				if (bt_hson) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "PAN(HS) only\n");
+					algorithm =
+						BT_8192E_2ANT_COEX_ALGO_PANHS;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "PAN(EDR) only\n");
+					algorithm =
+						BT_8192E_2ANT_COEX_ALGO_PANEDR;
+				}
+			}
+		}
+	} else if (numdiffprofile == 2) {
+		if (bt_link_info->sco_exist) {
+			if (bt_link_info->hid_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "SCO + HID\n");
+				algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+			} else if (bt_link_info->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "SCO + A2DP ==> SCO\n");
+				algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+			} else if (bt_link_info->pan_exist) {
+				if (bt_hson) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "SCO + PAN(HS)\n");
+					algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "SCO + PAN(EDR)\n");
+					algorithm =
+						BT_8192E_2ANT_COEX_ALGO_SCO_PAN;
+				}
+			}
+		} else {
+			if (bt_link_info->hid_exist &&
+			    bt_link_info->a2dp_exist) {
+				if (stack_info->num_of_hid >= 2) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "HID*2 + A2DP\n");
+					algorithm =
+					BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "HID + A2DP\n");
+					algorithm =
+					    BT_8192E_2ANT_COEX_ALGO_HID_A2DP;
+				}
+			} else if (bt_link_info->hid_exist &&
+				   bt_link_info->pan_exist) {
+				if (bt_hson) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "HID + PAN(HS)\n");
+					algorithm = BT_8192E_2ANT_COEX_ALGO_HID;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "HID + PAN(EDR)\n");
+					algorithm =
+					    BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+				}
+			} else if (bt_link_info->pan_exist &&
+				   bt_link_info->a2dp_exist) {
+				if (bt_hson) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "A2DP + PAN(HS)\n");
+					algorithm =
+					    BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "A2DP + PAN(EDR)\n");
+					algorithm =
+					    BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP;
+				}
+			}
+		}
+	} else if (numdiffprofile == 3) {
+		if (bt_link_info->sco_exist) {
+			if (bt_link_info->hid_exist &&
+			    bt_link_info->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "SCO + HID + A2DP ==> HID\n");
+				algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+			} else if (bt_link_info->hid_exist &&
+				   bt_link_info->pan_exist) {
+				if (bt_hson) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "SCO + HID + PAN(HS)\n");
+					algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "SCO + HID + PAN(EDR)\n");
+					algorithm =
+						BT_8192E_2ANT_COEX_ALGO_SCO_PAN;
+				}
+			} else if (bt_link_info->pan_exist &&
+				   bt_link_info->a2dp_exist) {
+				if (bt_hson) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "SCO + A2DP + PAN(HS)\n");
+					algorithm = BT_8192E_2ANT_COEX_ALGO_SCO;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "SCO + A2DP + PAN(EDR)\n");
+					algorithm =
+					    BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+				}
+			}
+		} else {
+			if (bt_link_info->hid_exist &&
+			    bt_link_info->pan_exist &&
+			    bt_link_info->a2dp_exist) {
+				if (bt_hson) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "HID + A2DP + PAN(HS)\n");
+					algorithm =
+					    BT_8192E_2ANT_COEX_ALGO_HID_A2DP;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "HID + A2DP + PAN(EDR)\n");
+					algorithm =
+					BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+				}
+			}
+		}
+	} else if (numdiffprofile >= 3) {
+		if (bt_link_info->sco_exist) {
+			if (bt_link_info->hid_exist &&
+			    bt_link_info->pan_exist &&
+			    bt_link_info->a2dp_exist) {
+				if (bt_hson) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "ErrorSCO+HID+A2DP+PAN(HS)\n");
+
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "SCO+HID+A2DP+PAN(EDR)\n");
+					algorithm =
+					    BT_8192E_2ANT_COEX_ALGO_PANEDR_HID;
+				}
+			}
+		}
+	}
+
+	return algorithm;
+}
+
+static void halbtc8192e2ant_setfw_dac_swinglevel(struct btc_coexist *btcoexist,
+						 u8 dac_swinglvl)
+{
+	u8 h2c_parameter[1] = {0};
+
+	/* There are several type of dacswing
+	 * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6
+	 */
+	h2c_parameter[0] = dac_swinglvl;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swinglvl);
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], FW write 0x64 = 0x%x\n", h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_set_fwdec_btpwr(struct btc_coexist *btcoexist,
+					    u8 dec_btpwr_lvl)
+{
+	u8 h2c_parameter[1] = {0};
+
+	h2c_parameter[0] = dec_btpwr_lvl;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex] decrease Bt Power level = %d, FW write 0x62 = 0x%x\n",
+		  dec_btpwr_lvl, h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_dec_btpwr(struct btc_coexist *btcoexist,
+				      bool force_exec, u8 dec_btpwr_lvl)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s Dec BT power level = %d\n",
+		  (force_exec ? "force to" : ""), dec_btpwr_lvl);
+	coex_dm->cur_dec_bt_pwr = dec_btpwr_lvl;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], preBtDecPwrLvl=%d, curBtDecPwrLvl=%d\n",
+			  coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr);
+	}
+	halbtc8192e2ant_set_fwdec_btpwr(btcoexist, coex_dm->cur_dec_bt_pwr);
+
+	coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr;
+}
+
+static void halbtc8192e2ant_set_bt_autoreport(struct btc_coexist *btcoexist,
+					      bool enable_autoreport)
+{
+	u8 h2c_parameter[1] = {0};
+
+	h2c_parameter[0] = 0;
+
+	if (enable_autoreport)
+		h2c_parameter[0] |= BIT0;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n",
+		  (enable_autoreport ? "Enabled!!" : "Disabled!!"),
+		  h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_bt_autoreport(struct btc_coexist *btcoexist,
+					  bool force_exec,
+					  bool enable_autoreport)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s BT Auto report = %s\n",
+		  (force_exec ? "force to" : ""),
+		  ((enable_autoreport) ? "Enabled" : "Disabled"));
+	coex_dm->cur_bt_auto_report = enable_autoreport;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex] bPreBtAutoReport=%d, bCurBtAutoReport=%d\n",
+			  coex_dm->pre_bt_auto_report,
+			  coex_dm->cur_bt_auto_report);
+
+		if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report)
+			return;
+	}
+	halbtc8192e2ant_set_bt_autoreport(btcoexist,
+					  coex_dm->cur_bt_auto_report);
+
+	coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report;
+}
+
+static void halbtc8192e2ant_fw_dac_swinglvl(struct btc_coexist *btcoexist,
+					    bool force_exec, u8 fw_dac_swinglvl)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s set FW Dac Swing level = %d\n",
+		  (force_exec ? "force to" : ""), fw_dac_swinglvl);
+	coex_dm->cur_fw_dac_swing_lvl = fw_dac_swinglvl;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex] preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n",
+			  coex_dm->pre_fw_dac_swing_lvl,
+			  coex_dm->cur_fw_dac_swing_lvl);
+
+		if (coex_dm->pre_fw_dac_swing_lvl ==
+		    coex_dm->cur_fw_dac_swing_lvl)
+			return;
+	}
+
+	halbtc8192e2ant_setfw_dac_swinglevel(btcoexist,
+					     coex_dm->cur_fw_dac_swing_lvl);
+
+	coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl;
+}
+
+static void btc8192e2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist,
+						 bool rx_rf_shrink_on)
+{
+	if (rx_rf_shrink_on) {
+		/* Shrink RF Rx LPF corner */
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+			  "[BTCoex], Shrink RF Rx LPF corner!!\n");
+		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+					  0xfffff, 0xffffc);
+	} else {
+		/* Resume RF Rx LPF corner
+		 * After initialized, we can use coex_dm->btRf0x1eBackup
+		 */
+		if (btcoexist->initilized) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+				  "[BTCoex], Resume RF Rx LPF corner!!\n");
+			btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+						  0xfffff,
+						  coex_dm->bt_rf0x1e_backup);
+		}
+	}
+}
+
+static void halbtc8192e2ant_rf_shrink(struct btc_coexist *btcoexist,
+				      bool force_exec, bool rx_rf_shrink_on)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+		  "[BTCoex], %s turn Rx RF Shrink = %s\n",
+		  (force_exec ? "force to" : ""),
+		  ((rx_rf_shrink_on) ? "ON" : "OFF"));
+	coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "[BTCoex]bPreRfRxLpfShrink=%d,bCurRfRxLpfShrink=%d\n",
+			  coex_dm->pre_rf_rx_lpf_shrink,
+			  coex_dm->cur_rf_rx_lpf_shrink);
+
+		if (coex_dm->pre_rf_rx_lpf_shrink ==
+		    coex_dm->cur_rf_rx_lpf_shrink)
+			return;
+	}
+	btc8192e2ant_set_sw_rf_rx_lpf_corner(btcoexist,
+					     coex_dm->cur_rf_rx_lpf_shrink);
+
+	coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink;
+}
+
+static void halbtc8192e2ant_set_dac_swingreg(struct btc_coexist *btcoexist,
+					     u32 level)
+{
+	u8 val = (u8)level;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], Write SwDacSwing = 0x%x\n", level);
+	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val);
+}
+
+static void btc8192e2ant_setsw_full_swing(struct btc_coexist *btcoexist,
+					  bool sw_dac_swingon,
+					  u32 sw_dac_swinglvl)
+{
+	if (sw_dac_swingon)
+		halbtc8192e2ant_set_dac_swingreg(btcoexist, sw_dac_swinglvl);
+	else
+		halbtc8192e2ant_set_dac_swingreg(btcoexist, 0x18);
+}
+
+static void halbtc8192e2ant_DacSwing(struct btc_coexist *btcoexist,
+				     bool force_exec, bool dac_swingon,
+				     u32 dac_swinglvl)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+		  "[BTCoex], %s turn DacSwing=%s, dac_swinglvl = 0x%x\n",
+		  (force_exec ? "force to" : ""),
+		  ((dac_swingon) ? "ON" : "OFF"), dac_swinglvl);
+	coex_dm->cur_dac_swing_on = dac_swingon;
+	coex_dm->cur_dac_swing_lvl = dac_swinglvl;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl = 0x%x, ",
+			  coex_dm->pre_dac_swing_on,
+			  coex_dm->pre_dac_swing_lvl);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "bCurDacSwingOn=%d, curDacSwingLvl = 0x%x\n",
+			  coex_dm->cur_dac_swing_on,
+			  coex_dm->cur_dac_swing_lvl);
+
+		if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) &&
+		    (coex_dm->pre_dac_swing_lvl == coex_dm->cur_dac_swing_lvl))
+			return;
+	}
+	mdelay(30);
+	btc8192e2ant_setsw_full_swing(btcoexist, dac_swingon, dac_swinglvl);
+
+	coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on;
+	coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl;
+}
+
+static void halbtc8192e2ant_set_agc_table(struct btc_coexist *btcoexist,
+					  bool agc_table_en)
+{
+	/* BB AGC Gain Table */
+	if (agc_table_en) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+			  "[BTCoex], BB Agc Table On!\n");
+		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x0a1A0001);
+		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x091B0001);
+		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x081C0001);
+		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x071D0001);
+		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x061E0001);
+		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x051F0001);
+	} else {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+			  "[BTCoex], BB Agc Table Off!\n");
+		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001);
+		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001);
+		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001);
+		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001);
+		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001);
+		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001);
+	}
+}
+
+static void halbtc8192e2ant_AgcTable(struct btc_coexist *btcoexist,
+				     bool force_exec, bool agc_table_en)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+		  "[BTCoex], %s %s Agc Table\n",
+		  (force_exec ? "force to" : ""),
+		  ((agc_table_en) ? "Enable" : "Disable"));
+	coex_dm->cur_agc_table_en = agc_table_en;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n",
+			  coex_dm->pre_agc_table_en, coex_dm->cur_agc_table_en);
+
+		if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en)
+			return;
+	}
+	halbtc8192e2ant_set_agc_table(btcoexist, agc_table_en);
+
+	coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en;
+}
+
+static void halbtc8192e2ant_set_coex_table(struct btc_coexist *btcoexist,
+					   u32 val0x6c0, u32 val0x6c4,
+					   u32 val0x6c8, u8 val0x6cc)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0);
+	btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4);
+	btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8);
+	btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc);
+	btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void halbtc8192e2ant_coex_table(struct btc_coexist *btcoexist,
+				       bool force_exec,
+				       u32 val0x6c0, u32 val0x6c4,
+				       u32 val0x6c8, u8 val0x6cc)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+		  "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, ",
+		  (force_exec ? "force to" : ""), val0x6c0);
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+		  "0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n",
+		  val0x6c4, val0x6c8, val0x6cc);
+	coex_dm->cur_val0x6c0 = val0x6c0;
+	coex_dm->cur_val0x6c4 = val0x6c4;
+	coex_dm->cur_val0x6c8 = val0x6c8;
+	coex_dm->cur_val0x6cc = val0x6cc;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "[BTCoex], preVal0x6c0 = 0x%x, preVal0x6c4 = 0x%x, ",
+			  coex_dm->pre_val0x6c0, coex_dm->pre_val0x6c4);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "preVal0x6c8 = 0x%x, preVal0x6cc = 0x%x !!\n",
+			  coex_dm->pre_val0x6c8, coex_dm->pre_val0x6cc);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "[BTCoex], curVal0x6c0 = 0x%x, curVal0x6c4 = 0x%x,\n",
+			  coex_dm->cur_val0x6c0, coex_dm->cur_val0x6c4);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "curVal0x6c8 = 0x%x, curVal0x6cc = 0x%x !!\n",
+			  coex_dm->cur_val0x6c8, coex_dm->cur_val0x6cc);
+
+		if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) &&
+		    (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) &&
+		    (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) &&
+		    (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc))
+			return;
+	}
+	halbtc8192e2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4,
+				       val0x6c8, val0x6cc);
+
+	coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0;
+	coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4;
+	coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8;
+	coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc;
+}
+
+static void btc8192e2ant_coex_tbl_w_type(struct btc_coexist *btcoexist,
+					 bool force_exec, u8 type)
+{
+	switch (type) {
+	case 0:
+		halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x55555555,
+					   0x5a5a5a5a, 0xffffff, 0x3);
+		break;
+	case 1:
+		halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+					   0x5a5a5a5a, 0xffffff, 0x3);
+		break;
+	case 2:
+		halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x55555555,
+					   0x5ffb5ffb, 0xffffff, 0x3);
+		break;
+	case 3:
+		halbtc8192e2ant_coex_table(btcoexist, force_exec, 0xdfffdfff,
+					   0x5fdb5fdb, 0xffffff, 0x3);
+		break;
+	case 4:
+		halbtc8192e2ant_coex_table(btcoexist, force_exec, 0xdfffdfff,
+					   0x5ffb5ffb, 0xffffff, 0x3);
+		break;
+	default:
+		break;
+	}
+}
+
+static void halbtc8192e2ant_set_fw_ignore_wlanact(struct btc_coexist *btcoexist,
+						  bool enable)
+{
+	u8 h2c_parameter[1] = {0};
+
+	if (enable)
+		h2c_parameter[0] |= BIT0; /* function enable */
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex]set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
+		  h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter);
+}
+
+static void halbtc8192e2ant_IgnoreWlanAct(struct btc_coexist *btcoexist,
+					  bool force_exec, bool enable)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s turn Ignore WlanAct %s\n",
+		  (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+	coex_dm->cur_ignore_wlan_act = enable;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], bPreIgnoreWlanAct = %d ",
+			  coex_dm->pre_ignore_wlan_act);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "bCurIgnoreWlanAct = %d!!\n",
+			  coex_dm->cur_ignore_wlan_act);
+
+		if (coex_dm->pre_ignore_wlan_act ==
+		    coex_dm->cur_ignore_wlan_act)
+			return;
+	}
+	halbtc8192e2ant_set_fw_ignore_wlanact(btcoexist, enable);
+
+	coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void halbtc8192e2ant_SetFwPstdma(struct btc_coexist *btcoexist, u8 byte1,
+					u8 byte2, u8 byte3, u8 byte4, u8 byte5)
+{
+	u8 h2c_parameter[5] = {0};
+
+	h2c_parameter[0] = byte1;
+	h2c_parameter[1] = byte2;
+	h2c_parameter[2] = byte3;
+	h2c_parameter[3] = byte4;
+	h2c_parameter[4] = byte5;
+
+	coex_dm->ps_tdma_para[0] = byte1;
+	coex_dm->ps_tdma_para[1] = byte2;
+	coex_dm->ps_tdma_para[2] = byte3;
+	coex_dm->ps_tdma_para[3] = byte4;
+	coex_dm->ps_tdma_para[4] = byte5;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n",
+		  h2c_parameter[0],
+		  h2c_parameter[1] << 24 | h2c_parameter[2] << 16 |
+		  h2c_parameter[3] << 8 | h2c_parameter[4]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void btc8192e2ant_sw_mec1(struct btc_coexist *btcoexist,
+				 bool shrink_rx_lpf, bool low_penalty_ra,
+				 bool limited_dig, bool btlan_constrain)
+{
+	halbtc8192e2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf);
+}
+
+static void btc8192e2ant_sw_mec2(struct btc_coexist *btcoexist,
+				 bool agc_table_shift, bool adc_backoff,
+				 bool sw_dac_swing, u32 dac_swinglvl)
+{
+	halbtc8192e2ant_AgcTable(btcoexist, NORMAL_EXEC, agc_table_shift);
+	halbtc8192e2ant_DacSwing(btcoexist, NORMAL_EXEC, sw_dac_swing,
+				 dac_swinglvl);
+}
+
+static void halbtc8192e2ant_ps_tdma(struct btc_coexist *btcoexist,
+				    bool force_exec, bool turn_on, u8 type)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s turn %s PS TDMA, type=%d\n",
+		  (force_exec ? "force to" : ""),
+		  (turn_on ? "ON" : "OFF"), type);
+	coex_dm->cur_ps_tdma_on = turn_on;
+	coex_dm->cur_ps_tdma = type;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n",
+			  coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n",
+			  coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma);
+
+		if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+		    (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+			return;
+	}
+	if (turn_on) {
+		switch (type) {
+		case 1:
+		default:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+						    0x1a, 0xe1, 0x90);
+			break;
+		case 2:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+						    0x12, 0xe1, 0x90);
+			break;
+		case 3:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c,
+						    0x3, 0xf1, 0x90);
+			break;
+		case 4:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x10,
+						    0x3, 0xf1, 0x90);
+			break;
+		case 5:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+						    0x1a, 0x60, 0x90);
+			break;
+		case 6:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+						    0x12, 0x60, 0x90);
+			break;
+		case 7:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c,
+						    0x3, 0x70, 0x90);
+			break;
+		case 8:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xa3, 0x10,
+						    0x3, 0x70, 0x90);
+			break;
+		case 9:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+						    0x1a, 0xe1, 0x10);
+			break;
+		case 10:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+						    0x12, 0xe1, 0x10);
+			break;
+		case 11:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c,
+						    0x3, 0xf1, 0x10);
+			break;
+		case 12:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x10,
+						    0x3, 0xf1, 0x10);
+			break;
+		case 13:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+						    0x1a, 0xe0, 0x10);
+			break;
+		case 14:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+						    0x12, 0xe0, 0x10);
+			break;
+		case 15:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1c,
+						    0x3, 0xf0, 0x10);
+			break;
+		case 16:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x12,
+						    0x3, 0xf0, 0x10);
+			break;
+		case 17:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0x61, 0x20,
+						    0x03, 0x10, 0x10);
+			break;
+		case 18:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x5,
+						    0x5, 0xe1, 0x90);
+			break;
+		case 19:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x25,
+						    0x25, 0xe1, 0x90);
+			break;
+		case 20:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x25,
+						    0x25, 0x60, 0x90);
+			break;
+		case 21:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x15,
+						    0x03, 0x70, 0x90);
+			break;
+		case 71:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0xe3, 0x1a,
+						    0x1a, 0xe1, 0x90);
+			break;
+		}
+	} else {
+		/* disable PS tdma */
+		switch (type) {
+		default:
+		case 0:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0x8, 0x0, 0x0,
+						    0x0, 0x0);
+			btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x4);
+			break;
+		case 1:
+			halbtc8192e2ant_SetFwPstdma(btcoexist, 0x0, 0x0, 0x0,
+						    0x8, 0x0);
+			mdelay(5);
+			btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20);
+			break;
+		}
+	}
+
+	/* update pre state */
+	coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+	coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static void halbtc8192e2ant_set_switch_sstype(struct btc_coexist *btcoexist,
+					      u8 sstype)
+{
+	u8 mimops = BTC_MIMO_PS_DYNAMIC;
+	u32 disra_mask = 0x0;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], REAL set SS Type = %d\n", sstype);
+
+	disra_mask = halbtc8192e2ant_decidera_mask(btcoexist, sstype,
+						   coex_dm->curra_masktype);
+	halbtc8192e2ant_Updatera_mask(btcoexist, FORCE_EXEC, disra_mask);
+
+	if (sstype == 1) {
+		halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1);
+		/* switch ofdm path */
+		btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x11);
+		btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x1);
+		btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81111111);
+		/* switch cck patch */
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x1);
+		btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x81);
+		mimops = BTC_MIMO_PS_STATIC;
+	} else if (sstype == 2) {
+		halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0);
+		btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x33);
+		btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x3);
+		btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81121313);
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x0);
+		btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x41);
+		mimops = BTC_MIMO_PS_DYNAMIC;
+	}
+	/* set rx 1ss or 2ss */
+	btcoexist->btc_set(btcoexist, BTC_SET_ACT_SEND_MIMO_PS, &mimops);
+}
+
+static void halbtc8192e2ant_switch_sstype(struct btc_coexist *btcoexist,
+					  bool force_exec, u8 new_sstype)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], %s Switch SS Type = %d\n",
+		  (force_exec ? "force to" : ""), new_sstype);
+	coex_dm->cur_sstype = new_sstype;
+
+	if (!force_exec) {
+		if (coex_dm->pre_sstype == coex_dm->cur_sstype)
+			return;
+	}
+	halbtc8192e2ant_set_switch_sstype(btcoexist, coex_dm->cur_sstype);
+
+	coex_dm->pre_sstype = coex_dm->cur_sstype;
+}
+
+static void halbtc8192e2ant_coex_alloff(struct btc_coexist *btcoexist)
+{
+	/* fw all off */
+	halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+	halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+	/* sw all off */
+	btc8192e2ant_sw_mec1(btcoexist, false, false, false, false);
+	btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18);
+
+	/* hw all off */
+	btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 0);
+}
+
+static void halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+	/* force to reset coex mechanism */
+
+	halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1);
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, FORCE_EXEC, 6);
+	halbtc8192e2ant_dec_btpwr(btcoexist, FORCE_EXEC, 0);
+
+	btc8192e2ant_coex_tbl_w_type(btcoexist, FORCE_EXEC, 0);
+	halbtc8192e2ant_switch_sstype(btcoexist, FORCE_EXEC, 2);
+
+	btc8192e2ant_sw_mec1(btcoexist, false, false, false, false);
+	btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18);
+}
+
+static void halbtc8192e2ant_action_bt_inquiry(struct btc_coexist *btcoexist)
+{
+	bool low_pwr_disable = true;
+
+	btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+			   &low_pwr_disable);
+
+	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+
+	btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+	halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+	halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+	btc8192e2ant_sw_mec1(btcoexist, false, false, false, false);
+	btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18);
+}
+
+static bool halbtc8192e2ant_is_common_action(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	bool common = false, wifi_connected = false, wifi_busy = false;
+	bool bt_hson = false, low_pwr_disable = false;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+			   &wifi_connected);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+	if (bt_link_info->sco_exist || bt_link_info->hid_exist)
+		halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 0, 0, 0);
+	else
+		halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+
+	if (!wifi_connected) {
+		low_pwr_disable = false;
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+				   &low_pwr_disable);
+
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi non-connected idle!!\n");
+
+		if ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+		     coex_dm->bt_status) ||
+		    (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE ==
+		     coex_dm->bt_status)) {
+			halbtc8192e2ant_switch_sstype(btcoexist,
+						      NORMAL_EXEC, 2);
+			btc8192e2ant_coex_tbl_w_type(btcoexist,
+						     NORMAL_EXEC, 1);
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 0);
+		} else {
+			halbtc8192e2ant_switch_sstype(btcoexist,
+						      NORMAL_EXEC, 1);
+			btc8192e2ant_coex_tbl_w_type(btcoexist,
+						     NORMAL_EXEC, 0);
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 1);
+		}
+
+		halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+		btc8192e2ant_sw_mec1(btcoexist, false, false, false, false);
+		btc8192e2ant_sw_mec2(btcoexist, false, false, false, 0x18);
+
+		common = true;
+	} else {
+		if (BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+		    coex_dm->bt_status) {
+			low_pwr_disable = false;
+			btcoexist->btc_set(btcoexist,
+					   BTC_SET_ACT_DISABLE_LOW_POWER,
+					   &low_pwr_disable);
+
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Wifi connected + BT non connected-idle!!\n");
+
+			halbtc8192e2ant_switch_sstype(btcoexist,
+						      NORMAL_EXEC, 2);
+			btc8192e2ant_coex_tbl_w_type(btcoexist,
+						     NORMAL_EXEC, 1);
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 0);
+			halbtc8192e2ant_fw_dac_swinglvl(btcoexist,
+							NORMAL_EXEC, 6);
+			halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+			btc8192e2ant_sw_mec1(btcoexist, false, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+
+			common = true;
+		} else if (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE ==
+			   coex_dm->bt_status) {
+			low_pwr_disable = true;
+			btcoexist->btc_set(btcoexist,
+					   BTC_SET_ACT_DISABLE_LOW_POWER,
+					   &low_pwr_disable);
+
+			if (bt_hson)
+				return false;
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Wifi connected + BT connected-idle!!\n");
+
+			halbtc8192e2ant_switch_sstype(btcoexist,
+						      NORMAL_EXEC, 2);
+			btc8192e2ant_coex_tbl_w_type(btcoexist,
+						     NORMAL_EXEC, 1);
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 0);
+			halbtc8192e2ant_fw_dac_swinglvl(btcoexist,
+							NORMAL_EXEC, 6);
+			halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+
+			btc8192e2ant_sw_mec1(btcoexist, true, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+
+			common = true;
+		} else {
+			low_pwr_disable = true;
+			btcoexist->btc_set(btcoexist,
+					   BTC_SET_ACT_DISABLE_LOW_POWER,
+					   &low_pwr_disable);
+
+			if (wifi_busy) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "Wifi Connected-Busy + BT Busy!!\n");
+				common = false;
+			} else {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "Wifi Connected-Idle + BT Busy!!\n");
+
+				halbtc8192e2ant_switch_sstype(btcoexist,
+							      NORMAL_EXEC, 1);
+				btc8192e2ant_coex_tbl_w_type(btcoexist,
+							     NORMAL_EXEC, 2);
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 21);
+				halbtc8192e2ant_fw_dac_swinglvl(btcoexist,
+								NORMAL_EXEC, 6);
+				halbtc8192e2ant_dec_btpwr(btcoexist,
+							  NORMAL_EXEC, 0);
+				btc8192e2ant_sw_mec1(btcoexist, false,
+						     false, false, false);
+				btc8192e2ant_sw_mec2(btcoexist, false,
+						     false, false, 0x18);
+				common = true;
+			}
+		}
+	}
+	return common;
+}
+
+static void btc8192e_int1(struct btc_coexist *btcoexist, bool tx_pause,
+			  int result)
+{
+	if (tx_pause) {
+		BTC_PRINT(BTC_MSG_ALGORITHM,
+			  ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], TxPause = 1\n");
+
+		if (coex_dm->cur_ps_tdma == 71) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 5);
+			coex_dm->tdma_adj_type = 5;
+		} else if (coex_dm->cur_ps_tdma == 1) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 5);
+			coex_dm->tdma_adj_type = 5;
+		} else if (coex_dm->cur_ps_tdma == 2) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 6);
+			coex_dm->tdma_adj_type = 6;
+		} else if (coex_dm->cur_ps_tdma == 3) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 7);
+			coex_dm->tdma_adj_type = 7;
+		} else if (coex_dm->cur_ps_tdma == 4) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 8);
+			coex_dm->tdma_adj_type = 8;
+		}
+		if (coex_dm->cur_ps_tdma == 9) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 13);
+			coex_dm->tdma_adj_type = 13;
+		} else if (coex_dm->cur_ps_tdma == 10) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 14);
+			coex_dm->tdma_adj_type = 14;
+		} else if (coex_dm->cur_ps_tdma == 11) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 15);
+			coex_dm->tdma_adj_type = 15;
+		} else if (coex_dm->cur_ps_tdma == 12) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 16);
+			coex_dm->tdma_adj_type = 16;
+		}
+
+		if (result == -1) {
+			if (coex_dm->cur_ps_tdma == 5) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 6);
+				coex_dm->tdma_adj_type = 6;
+			} else if (coex_dm->cur_ps_tdma == 6) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 7) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 8);
+				coex_dm->tdma_adj_type = 8;
+			} else if (coex_dm->cur_ps_tdma == 13) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 14);
+				coex_dm->tdma_adj_type = 14;
+			} else if (coex_dm->cur_ps_tdma == 14) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 15) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 16);
+				coex_dm->tdma_adj_type = 16;
+			}
+		} else if (result == 1) {
+			if (coex_dm->cur_ps_tdma == 8) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 7) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 6);
+				coex_dm->tdma_adj_type = 6;
+			} else if (coex_dm->cur_ps_tdma == 6) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 5);
+				coex_dm->tdma_adj_type = 5;
+			} else if (coex_dm->cur_ps_tdma == 16) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 15) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 14);
+				coex_dm->tdma_adj_type = 14;
+			} else if (coex_dm->cur_ps_tdma == 14) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 13);
+				coex_dm->tdma_adj_type = 13;
+			}
+		}
+	} else {
+		BTC_PRINT(BTC_MSG_ALGORITHM,
+			  ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], TxPause = 0\n");
+		if (coex_dm->cur_ps_tdma == 5) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 71);
+			coex_dm->tdma_adj_type = 71;
+		} else if (coex_dm->cur_ps_tdma == 6) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 2);
+			coex_dm->tdma_adj_type = 2;
+		} else if (coex_dm->cur_ps_tdma == 7) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 3);
+			coex_dm->tdma_adj_type = 3;
+		} else if (coex_dm->cur_ps_tdma == 8) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 4);
+			coex_dm->tdma_adj_type = 4;
+		}
+		if (coex_dm->cur_ps_tdma == 13) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 9);
+			coex_dm->tdma_adj_type = 9;
+		} else if (coex_dm->cur_ps_tdma == 14) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 10);
+			coex_dm->tdma_adj_type = 10;
+		} else if (coex_dm->cur_ps_tdma == 15) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			coex_dm->tdma_adj_type = 11;
+		} else if (coex_dm->cur_ps_tdma == 16) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 12);
+			coex_dm->tdma_adj_type = 12;
+		}
+
+		if (result == -1) {
+			if (coex_dm->cur_ps_tdma == 71) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 1);
+				coex_dm->tdma_adj_type = 1;
+			} else if (coex_dm->cur_ps_tdma == 1) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 4);
+				coex_dm->tdma_adj_type = 4;
+			} else if (coex_dm->cur_ps_tdma == 9) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 10);
+				coex_dm->tdma_adj_type = 10;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 12);
+				coex_dm->tdma_adj_type = 12;
+			}
+		} else if (result == 1) {
+			if (coex_dm->cur_ps_tdma == 4) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 1);
+				coex_dm->tdma_adj_type = 1;
+			} else if (coex_dm->cur_ps_tdma == 1) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 71);
+				coex_dm->tdma_adj_type = 71;
+			} else if (coex_dm->cur_ps_tdma == 12) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 10);
+				coex_dm->tdma_adj_type = 10;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 9);
+				coex_dm->tdma_adj_type = 9;
+			}
+		}
+	}
+}
+
+static void btc8192e_int2(struct btc_coexist *btcoexist, bool tx_pause,
+			  int result)
+{
+	if (tx_pause) {
+		BTC_PRINT(BTC_MSG_ALGORITHM,
+			  ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], TxPause = 1\n");
+		if (coex_dm->cur_ps_tdma == 1) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 6);
+			coex_dm->tdma_adj_type = 6;
+		} else if (coex_dm->cur_ps_tdma == 2) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 6);
+			coex_dm->tdma_adj_type = 6;
+		} else if (coex_dm->cur_ps_tdma == 3) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 7);
+			coex_dm->tdma_adj_type = 7;
+		} else if (coex_dm->cur_ps_tdma == 4) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 8);
+			coex_dm->tdma_adj_type = 8;
+		}
+		if (coex_dm->cur_ps_tdma == 9) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 14);
+			coex_dm->tdma_adj_type = 14;
+		} else if (coex_dm->cur_ps_tdma == 10) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 14);
+			coex_dm->tdma_adj_type = 14;
+		} else if (coex_dm->cur_ps_tdma == 11) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 15);
+			coex_dm->tdma_adj_type = 15;
+		} else if (coex_dm->cur_ps_tdma == 12) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 16);
+			coex_dm->tdma_adj_type = 16;
+		}
+		if (result == -1) {
+			if (coex_dm->cur_ps_tdma == 5) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 6);
+				coex_dm->tdma_adj_type = 6;
+			} else if (coex_dm->cur_ps_tdma == 6) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 7) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 8);
+				coex_dm->tdma_adj_type = 8;
+			} else if (coex_dm->cur_ps_tdma == 13) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 14);
+				coex_dm->tdma_adj_type = 14;
+			} else if (coex_dm->cur_ps_tdma == 14) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 15) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 16);
+				coex_dm->tdma_adj_type = 16;
+			}
+		} else if (result == 1) {
+			if (coex_dm->cur_ps_tdma == 8) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 7) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 6);
+				coex_dm->tdma_adj_type = 6;
+			} else if (coex_dm->cur_ps_tdma == 6) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 6);
+				coex_dm->tdma_adj_type = 6;
+			} else if (coex_dm->cur_ps_tdma == 16) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 15) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 14);
+				coex_dm->tdma_adj_type = 14;
+			} else if (coex_dm->cur_ps_tdma == 14) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 14);
+				coex_dm->tdma_adj_type = 14;
+			}
+		}
+	} else {
+		BTC_PRINT(BTC_MSG_ALGORITHM,
+			  ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], TxPause = 0\n");
+		if (coex_dm->cur_ps_tdma == 5) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 2);
+			coex_dm->tdma_adj_type = 2;
+		} else if (coex_dm->cur_ps_tdma == 6) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 2);
+			coex_dm->tdma_adj_type = 2;
+		} else if (coex_dm->cur_ps_tdma == 7) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 3);
+			coex_dm->tdma_adj_type = 3;
+		} else if (coex_dm->cur_ps_tdma == 8) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 4);
+			coex_dm->tdma_adj_type = 4;
+		}
+		if (coex_dm->cur_ps_tdma == 13) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 10);
+			coex_dm->tdma_adj_type = 10;
+		} else if (coex_dm->cur_ps_tdma == 14) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 10);
+			coex_dm->tdma_adj_type = 10;
+		} else if (coex_dm->cur_ps_tdma == 15) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			coex_dm->tdma_adj_type = 11;
+		} else if (coex_dm->cur_ps_tdma == 16) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 12);
+			coex_dm->tdma_adj_type = 12;
+		}
+		if (result == -1) {
+			if (coex_dm->cur_ps_tdma == 1) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 4);
+				coex_dm->tdma_adj_type = 4;
+			} else if (coex_dm->cur_ps_tdma == 9) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 10);
+				coex_dm->tdma_adj_type = 10;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 12);
+				coex_dm->tdma_adj_type = 12;
+			}
+		} else if (result == 1) {
+			if (coex_dm->cur_ps_tdma == 4) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 12) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 10);
+				coex_dm->tdma_adj_type = 10;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 10);
+				coex_dm->tdma_adj_type = 10;
+			}
+		}
+	}
+}
+
+static void btc8192e_int3(struct btc_coexist *btcoexist, bool tx_pause,
+			  int result)
+{
+	if (tx_pause) {
+		BTC_PRINT(BTC_MSG_ALGORITHM,
+			  ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], TxPause = 1\n");
+		if (coex_dm->cur_ps_tdma == 1) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 7);
+			coex_dm->tdma_adj_type = 7;
+		} else if (coex_dm->cur_ps_tdma == 2) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 7);
+			coex_dm->tdma_adj_type = 7;
+		} else if (coex_dm->cur_ps_tdma == 3) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 7);
+			coex_dm->tdma_adj_type = 7;
+		} else if (coex_dm->cur_ps_tdma == 4) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 8);
+			coex_dm->tdma_adj_type = 8;
+		}
+		if (coex_dm->cur_ps_tdma == 9) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 15);
+			coex_dm->tdma_adj_type = 15;
+		} else if (coex_dm->cur_ps_tdma == 10) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 15);
+			coex_dm->tdma_adj_type = 15;
+		} else if (coex_dm->cur_ps_tdma == 11) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 15);
+			coex_dm->tdma_adj_type = 15;
+		} else if (coex_dm->cur_ps_tdma == 12) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 16);
+			coex_dm->tdma_adj_type = 16;
+		}
+		if (result == -1) {
+			if (coex_dm->cur_ps_tdma == 5) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 6) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 7) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 8);
+				coex_dm->tdma_adj_type = 8;
+			} else if (coex_dm->cur_ps_tdma == 13) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 14) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 15) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 16);
+				coex_dm->tdma_adj_type = 16;
+			}
+		} else if (result == 1) {
+			if (coex_dm->cur_ps_tdma == 8) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 7) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 6) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 16) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 15) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 14) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			}
+		}
+	} else {
+		BTC_PRINT(BTC_MSG_ALGORITHM,
+			  ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], TxPause = 0\n");
+		if (coex_dm->cur_ps_tdma == 5) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 3);
+			coex_dm->tdma_adj_type = 3;
+		} else if (coex_dm->cur_ps_tdma == 6) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 3);
+			coex_dm->tdma_adj_type = 3;
+		} else if (coex_dm->cur_ps_tdma == 7) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 3);
+			coex_dm->tdma_adj_type = 3;
+		} else if (coex_dm->cur_ps_tdma == 8) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 4);
+			coex_dm->tdma_adj_type = 4;
+		}
+		if (coex_dm->cur_ps_tdma == 13) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			coex_dm->tdma_adj_type = 11;
+		} else if (coex_dm->cur_ps_tdma == 14) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			coex_dm->tdma_adj_type = 11;
+		} else if (coex_dm->cur_ps_tdma == 15) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			coex_dm->tdma_adj_type = 11;
+		} else if (coex_dm->cur_ps_tdma == 16) {
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 12);
+			coex_dm->tdma_adj_type = 12;
+		}
+		if (result == -1) {
+			if (coex_dm->cur_ps_tdma == 1) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 4);
+				coex_dm->tdma_adj_type = 4;
+			} else if (coex_dm->cur_ps_tdma == 9) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 12);
+				coex_dm->tdma_adj_type = 12;
+			}
+		} else if (result == 1) {
+			if (coex_dm->cur_ps_tdma == 4) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 12) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			}
+		}
+	}
+}
+
+static void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist,
+						 bool sco_hid, bool tx_pause,
+						 u8 max_interval)
+{
+	static int up, dn, m, n, wait_cnt;
+	/* 0: no change, +1: increase WiFi duration,
+	 * -1: decrease WiFi duration
+	 */
+	int result;
+	u8 retry_cnt = 0;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], TdmaDurationAdjust()\n");
+
+	if (!coex_dm->auto_tdma_adjust) {
+		coex_dm->auto_tdma_adjust = true;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], first run TdmaDurationAdjust()!!\n");
+		if (sco_hid) {
+			if (tx_pause) {
+				if (max_interval == 1) {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 13);
+					coex_dm->tdma_adj_type = 13;
+				} else if (max_interval == 2) {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 14);
+					coex_dm->tdma_adj_type = 14;
+				} else if (max_interval == 3) {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 15);
+					coex_dm->tdma_adj_type = 15;
+				} else {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 15);
+					coex_dm->tdma_adj_type = 15;
+				}
+			} else {
+				if (max_interval == 1) {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 9);
+					coex_dm->tdma_adj_type = 9;
+				} else if (max_interval == 2) {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 10);
+					coex_dm->tdma_adj_type = 10;
+				} else if (max_interval == 3) {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 11);
+					coex_dm->tdma_adj_type = 11;
+				} else {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 11);
+					coex_dm->tdma_adj_type = 11;
+				}
+			}
+		} else {
+			if (tx_pause) {
+				if (max_interval == 1) {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 5);
+					coex_dm->tdma_adj_type = 5;
+				} else if (max_interval == 2) {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 6);
+					coex_dm->tdma_adj_type = 6;
+				} else if (max_interval == 3) {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 7);
+					coex_dm->tdma_adj_type = 7;
+				} else {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 7);
+					coex_dm->tdma_adj_type = 7;
+				}
+			} else {
+				if (max_interval == 1) {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 1);
+					coex_dm->tdma_adj_type = 1;
+				} else if (max_interval == 2) {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 2);
+					coex_dm->tdma_adj_type = 2;
+				} else if (max_interval == 3) {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 3);
+					coex_dm->tdma_adj_type = 3;
+				} else {
+					halbtc8192e2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 3);
+					coex_dm->tdma_adj_type = 3;
+				}
+			}
+		}
+
+		up = 0;
+		dn = 0;
+		m = 1;
+		n = 3;
+		result = 0;
+		wait_cnt = 0;
+	} else {
+		/* accquire the BT TRx retry count from BT_Info byte2 */
+		retry_cnt = coex_sta->bt_retry_cnt;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], retry_cnt = %d\n", retry_cnt);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_cnt=%d\n",
+			  up, dn, m, n, wait_cnt);
+		result = 0;
+		wait_cnt++;
+		/* no retry in the last 2-second duration */
+		if (retry_cnt == 0) {
+			up++;
+			dn--;
+
+			if (dn <= 0)
+				dn = 0;
+
+			if (up >= n) {
+				wait_cnt = 0;
+				n = 3;
+				up = 0;
+				dn = 0;
+				result = 1;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_TRACE_FW_DETAIL,
+					  "[BTCoex]Increase wifi duration!!\n");
+			}
+		} else if (retry_cnt <= 3) {
+			up--;
+			dn++;
+
+			if (up <= 0)
+				up = 0;
+
+			if (dn == 2) {
+				if (wait_cnt <= 2)
+					m++;
+				else
+					m = 1;
+
+				if (m >= 20)
+					m = 20;
+
+				n = 3 * m;
+				up = 0;
+				dn = 0;
+				wait_cnt = 0;
+				result = -1;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_TRACE_FW_DETAIL,
+					  "Reduce wifi duration for retry<3\n");
+			}
+		} else {
+			if (wait_cnt == 1)
+				m++;
+			else
+				m = 1;
+
+			if (m >= 20)
+				m = 20;
+
+			n = 3*m;
+			up = 0;
+			dn = 0;
+			wait_cnt = 0;
+			result = -1;
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "Decrease wifi duration for retryCounter>3!!\n");
+		}
+
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], max Interval = %d\n", max_interval);
+		if (max_interval == 1)
+			btc8192e_int1(btcoexist, tx_pause, result);
+		else if (max_interval == 2)
+			btc8192e_int2(btcoexist, tx_pause, result);
+		else if (max_interval == 3)
+			btc8192e_int3(btcoexist, tx_pause, result);
+	}
+
+	/* if current PsTdma not match with
+	 * the recorded one (when scan, dhcp...),
+	 * then we have to adjust it back to the previous record one.
+	 */
+	if (coex_dm->cur_ps_tdma != coex_dm->tdma_adj_type) {
+		bool scan = false, link = false, roam = false;
+
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], PsTdma type dismatch!!!, ");
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "curPsTdma=%d, recordPsTdma=%d\n",
+			  coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type);
+
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+		if (!scan && !link && !roam)
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true,
+						coex_dm->tdma_adj_type);
+		else
+			BTC_PRINT(BTC_MSG_ALGORITHM,
+				  ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n");
+	}
+}
+
+/* SCO only or SCO+PAN(HS) */
+static void halbtc8192e2ant_action_sco(struct btc_coexist *btcoexist)
+{
+	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW;
+	u32 wifi_bw;
+
+	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+
+	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+	btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 4);
+
+	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+	if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+	}
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	/* sw mechanism */
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, true, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x6);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, true, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x6);
+		}
+	} else {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, false, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x6);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, false, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x6);
+		}
+	}
+}
+
+static void halbtc8192e2ant_action_sco_pan(struct btc_coexist *btcoexist)
+{
+	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_STAY_LOW;
+	u32 wifi_bw;
+
+	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+
+	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+	btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 4);
+
+	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+	if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
+	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
+	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
+	}
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	/* sw mechanism */
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, true, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x6);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, true, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x6);
+		}
+	} else {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, false, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x6);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, false, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x6);
+		}
+	}
+}
+
+static void halbtc8192e2ant_action_hid(struct btc_coexist *btcoexist)
+{
+	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+	u32 wifi_bw;
+
+	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3);
+
+	if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
+	}
+
+	/* sw mechanism */
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, true, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, true, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	} else {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, false, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, false, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	}
+}
+
+/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */
+static void halbtc8192e2ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+	u32 wifi_bw;
+	bool long_dist = false;
+
+	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+	if ((btrssi_state == BTC_RSSI_STATE_LOW ||
+	     btrssi_state == BTC_RSSI_STATE_STAY_LOW) &&
+	    (wifirssi_state == BTC_RSSI_STATE_LOW ||
+	     wifirssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], A2dp, wifi/bt rssi both LOW!!\n");
+		long_dist = true;
+	}
+	if (long_dist) {
+		halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 2);
+		halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true,
+					   0x4);
+	} else {
+		halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+		halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false,
+					   0x8);
+	}
+
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+	if (long_dist)
+		btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 0);
+	else
+		btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+	if (long_dist) {
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 17);
+		coex_dm->auto_tdma_adjust = false;
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+	} else {
+		if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+		    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+			halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+							     true, 1);
+			halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+		} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+			   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+			halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+							     false, 1);
+			halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+		} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+			   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+							     false, 1);
+			halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+		}
+	}
+
+	/* sw mechanism */
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, true, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, true, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	} else {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, false, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, false, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	}
+}
+
+static void halbtc8192e2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+	u32 wifi_bw;
+
+	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+	btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+	if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+		halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 2);
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+		halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+						     false, 2);
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+		halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+						     false, 2);
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+	}
+
+	/* sw mechanism */
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, true, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     true, 0x6);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, true, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     true, 0x6);
+		}
+	} else {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, false, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     true, 0x6);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, false, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     true, 0x6);
+		}
+	}
+}
+
+static void halbtc8192e2ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+	u32 wifi_bw;
+
+	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+	btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+	if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1);
+	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1);
+	}
+
+	/* sw mechanism */
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, true, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, true, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	} else {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, false, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, false, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	}
+}
+
+/* PAN(HS) only */
+static void halbtc8192e2ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+	u32 wifi_bw;
+
+	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+	btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+	if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+	}
+	halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, true, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, true, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	} else {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, false, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, false, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	}
+}
+
+/* PAN(EDR)+A2DP */
+static void halbtc8192e2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+	u32 wifi_bw;
+
+	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+	btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 2);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+		halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 3);
+	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+		halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+						     false, 3);
+	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+		halbtc8192e2ant_tdma_duration_adjust(btcoexist, false,
+						     false, 3);
+	}
+
+	/* sw mechanism	*/
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, true, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, true, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	} else {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, false, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, false, false,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	}
+}
+
+static void halbtc8192e2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+	u32 wifi_bw;
+
+	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+	btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3);
+
+	if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+		halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
+	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+			halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 10);
+	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+			halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 10);
+	}
+
+	/* sw mechanism */
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, true, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, true, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	} else {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, false, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, false, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	}
+}
+
+/* HID+A2DP+PAN(EDR) */
+static void btc8192e2ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+	u32 wifi_bw;
+
+	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+	halbtc8192e2ant_fw_dac_swinglvl(btcoexist, NORMAL_EXEC, 6);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3);
+
+	if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+		halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 3);
+	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+		halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 3);
+	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+		halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 3);
+	}
+
+	/* sw mechanism */
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, true, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, true, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	} else {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, false, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, false, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	}
+}
+
+static void halbtc8192e2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+	u8 wifirssi_state, btrssi_state = BTC_RSSI_STATE_HIGH;
+	u32 wifi_bw;
+
+	wifirssi_state = halbtc8192e2ant_wifirssi_state(btcoexist, 0, 2, 15, 0);
+	btrssi_state = halbtc8192e2ant_btrssi_state(3, 34, 42);
+
+	halbtc8192e2ant_switch_sstype(btcoexist, NORMAL_EXEC, 1);
+	halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	btc8192e2ant_coex_tbl_w_type(btcoexist, NORMAL_EXEC, 3);
+
+	if ((btrssi_state == BTC_RSSI_STATE_LOW) ||
+	    (btrssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 0);
+		halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, true, 2);
+	} else if ((btrssi_state == BTC_RSSI_STATE_MEDIUM) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_MEDIUM))	{
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 2);
+		halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2);
+	} else if ((btrssi_state == BTC_RSSI_STATE_HIGH) ||
+		   (btrssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+		halbtc8192e2ant_dec_btpwr(btcoexist, NORMAL_EXEC, 4);
+		halbtc8192e2ant_tdma_duration_adjust(btcoexist, true, false, 2);
+	}
+
+	/* sw mechanism */
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, true, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, true, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	} else {
+		if ((wifirssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifirssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8192e2ant_sw_mec1(btcoexist, false, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, true, false,
+					     false, 0x18);
+		} else {
+			btc8192e2ant_sw_mec1(btcoexist, false, true,
+					     false, false);
+			btc8192e2ant_sw_mec2(btcoexist, false, false,
+					     false, 0x18);
+		}
+	}
+}
+
+static void halbtc8192e2ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+	u8 algorithm = 0;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], RunCoexistMechanism()===>\n");
+
+	if (btcoexist->manual_control) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], return for Manual CTRL <===\n");
+		return;
+	}
+
+	if (coex_sta->under_ips) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], wifi is under IPS !!!\n");
+		return;
+	}
+
+	algorithm = halbtc8192e2ant_action_algorithm(btcoexist);
+	if (coex_sta->c2h_bt_inquiry_page &&
+	    (BT_8192E_2ANT_COEX_ALGO_PANHS != algorithm)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BT is under inquiry/page scan !!\n");
+		halbtc8192e2ant_action_bt_inquiry(btcoexist);
+		return;
+	}
+
+	coex_dm->cur_algorithm = algorithm;
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm);
+
+	if (halbtc8192e2ant_is_common_action(btcoexist)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Action 2-Ant common.\n");
+		coex_dm->auto_tdma_adjust = false;
+	} else {
+		if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex] preAlgorithm=%d, curAlgorithm=%d\n",
+				  coex_dm->pre_algorithm,
+				  coex_dm->cur_algorithm);
+			coex_dm->auto_tdma_adjust = false;
+		}
+		switch (coex_dm->cur_algorithm) {
+		case BT_8192E_2ANT_COEX_ALGO_SCO:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Action 2-Ant, algorithm = SCO.\n");
+			halbtc8192e2ant_action_sco(btcoexist);
+			break;
+		case BT_8192E_2ANT_COEX_ALGO_SCO_PAN:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Action 2-Ant, algorithm = SCO+PAN(EDR).\n");
+			halbtc8192e2ant_action_sco_pan(btcoexist);
+			break;
+		case BT_8192E_2ANT_COEX_ALGO_HID:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Action 2-Ant, algorithm = HID.\n");
+			halbtc8192e2ant_action_hid(btcoexist);
+			break;
+		case BT_8192E_2ANT_COEX_ALGO_A2DP:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Action 2-Ant, algorithm = A2DP.\n");
+			halbtc8192e2ant_action_a2dp(btcoexist);
+			break;
+		case BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Action 2-Ant, algorithm = A2DP+PAN(HS).\n");
+			halbtc8192e2ant_action_a2dp_pan_hs(btcoexist);
+			break;
+		case BT_8192E_2ANT_COEX_ALGO_PANEDR:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Action 2-Ant, algorithm = PAN(EDR).\n");
+			halbtc8192e2ant_action_pan_edr(btcoexist);
+			break;
+		case BT_8192E_2ANT_COEX_ALGO_PANHS:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Action 2-Ant, algorithm = HS mode.\n");
+			halbtc8192e2ant_action_pan_hs(btcoexist);
+			break;
+		case BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Action 2-Ant, algorithm = PAN+A2DP.\n");
+			halbtc8192e2ant_action_pan_edr_a2dp(btcoexist);
+			break;
+		case BT_8192E_2ANT_COEX_ALGO_PANEDR_HID:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Action 2-Ant, algorithm = PAN(EDR)+HID.\n");
+			halbtc8192e2ant_action_pan_edr_hid(btcoexist);
+			break;
+		case BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Action 2-Ant, algorithm = HID+A2DP+PAN.\n");
+			btc8192e2ant_action_hid_a2dp_pan_edr(btcoexist);
+			break;
+		case BT_8192E_2ANT_COEX_ALGO_HID_A2DP:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Action 2-Ant, algorithm = HID+A2DP.\n");
+			halbtc8192e2ant_action_hid_a2dp(btcoexist);
+			break;
+		default:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "Action 2-Ant, algorithm = unknown!!\n");
+			/* halbtc8192e2ant_coex_alloff(btcoexist); */
+			break;
+		}
+		coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+	}
+}
+
+static void halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist,
+					  bool backup)
+{
+	u16 u16tmp = 0;
+	u8 u8tmp = 0;
+
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+		  "[BTCoex], 2Ant Init HW Config!!\n");
+
+	if (backup) {
+		/* backup rf 0x1e value */
+		coex_dm->bt_rf0x1e_backup =
+			btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A,
+						  0x1e, 0xfffff);
+
+		coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist,
+								      0x430);
+		coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist,
+								     0x434);
+		coex_dm->backup_retrylimit = btcoexist->btc_read_2byte(
+								    btcoexist,
+								    0x42a);
+		coex_dm->backup_ampdu_maxtime = btcoexist->btc_read_1byte(
+								    btcoexist,
+								    0x456);
+	}
+
+	/* antenna sw ctrl to bt */
+	btcoexist->btc_write_1byte(btcoexist, 0x4f, 0x6);
+	btcoexist->btc_write_1byte(btcoexist, 0x944, 0x24);
+	btcoexist->btc_write_4byte(btcoexist, 0x930, 0x700700);
+	btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20);
+	if (btcoexist->chip_interface == BTC_INTF_USB)
+		btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30430004);
+	else
+		btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30030004);
+
+	btc8192e2ant_coex_tbl_w_type(btcoexist, FORCE_EXEC, 0);
+
+	/* antenna switch control parameter */
+	btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555);
+
+	/* coex parameters */
+	btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3);
+	/* 0x790[5:0] = 0x5 */
+	u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+	u8tmp &= 0xc0;
+	u8tmp |= 0x5;
+	btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp);
+
+	/* enable counter statistics */
+	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4);
+
+	/* enable PTA */
+	btcoexist->btc_write_1byte(btcoexist, 0x40, 0x20);
+	/* enable mailbox interface */
+	u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x40);
+	u16tmp |= BIT9;
+	btcoexist->btc_write_2byte(btcoexist, 0x40, u16tmp);
+
+	/* enable PTA I2C mailbox  */
+	u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x101);
+	u8tmp |= BIT4;
+	btcoexist->btc_write_1byte(btcoexist, 0x101, u8tmp);
+
+	/* enable bt clock when wifi is disabled. */
+	u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x93);
+	u8tmp |= BIT0;
+	btcoexist->btc_write_1byte(btcoexist, 0x93, u8tmp);
+	/* enable bt clock when suspend. */
+	u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x7);
+	u8tmp |= BIT0;
+	btcoexist->btc_write_1byte(btcoexist, 0x7, u8tmp);
+}
+
+/*************************************************************
+ *   work around function start with wa_halbtc8192e2ant_
+ *************************************************************/
+
+/************************************************************
+ *   extern function start with EXhalbtc8192e2ant_
+ ************************************************************/
+
+void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+	halbtc8192e2ant_init_hwconfig(btcoexist, true);
+}
+
+void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+		  "[BTCoex], Coex Mechanism Init!!\n");
+	halbtc8192e2ant_init_coex_dm(btcoexist);
+}
+
+void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist)
+{
+	struct btc_board_info *board_info = &btcoexist->board_info;
+	struct btc_stack_info *stack_info = &btcoexist->stack_info;
+	struct rtl_priv *rtlpriv = btcoexist->adapter;
+	u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0;
+	u16 u16tmp[4];
+	u32 u32tmp[4];
+	bool roam = false, scan = false, link = false, wifi_under_5g = false;
+	bool bt_hson = false, wifi_busy = false;
+	int wifirssi = 0, bt_hs_rssi = 0;
+	u32 wifi_bw, wifi_traffic_dir;
+	u8 wifi_dot11_chnl, wifi_hs_chnl;
+	u32 fw_ver = 0, bt_patch_ver = 0;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n ============[BT Coexist info]============");
+
+	if (btcoexist->manual_control) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n ===========[Under Manual Control]===========");
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n ==========================================");
+	}
+
+	if (!board_info->bt_exist) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!");
+		return;
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:",
+		   board_info->pg_ant_num, board_info->btdm_ant_num);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d",
+		   "BT stack/ hci ext ver",
+		   ((stack_info->profile_notified) ? "Yes" : "No"),
+		   stack_info->hci_version);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)",
+		   "CoexVer/ FwVer/ PatchVer",
+		   glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant,
+		   fw_ver, bt_patch_ver, bt_patch_ver);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hson);
+	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
+			   &wifi_dot11_chnl);
+	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)",
+		   "Dot11 channel / HsMode(HsChnl)",
+		   wifi_dot11_chnl, bt_hson, wifi_hs_chnl);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x ",
+		   "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0],
+		   coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifirssi);
+	btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+		   "Wifi rssi/ HS rssi", wifirssi, bt_hs_rssi);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ",
+		   "Wifi link/ roam/ scan", link, roam, scan);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+			   &wifi_traffic_dir);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %s/ %s ",
+		   "Wifi status", (wifi_under_5g ? "5G" : "2.4G"),
+		   ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+			(((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+		   ((!wifi_busy) ? "idle" :
+			((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+				"uplink" : "downlink")));
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = [%s/ %d/ %d] ",
+		   "BT [status/ rssi/ retryCnt]",
+		   ((btcoexist->bt_info.bt_disabled) ? ("disabled") :
+		    ((coex_sta->c2h_bt_inquiry_page) ?
+		     ("inquiry/page scan") :
+		      ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+			coex_dm->bt_status) ? "non-connected idle" :
+			 ((BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE ==
+			   coex_dm->bt_status) ? "connected-idle" : "busy")))),
+		   coex_sta->bt_rssi, coex_sta->bt_retry_cnt);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d / %d / %d",
+		   "SCO/HID/PAN/A2DP", stack_info->sco_exist,
+		   stack_info->hid_exist, stack_info->pan_exist,
+		   stack_info->a2dp_exist);
+	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
+
+	bt_info_ext = coex_sta->bt_info_ext;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s",
+		   "BT Info A2DP rate",
+		   (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate");
+
+	for (i = 0; i < BT_INFO_SRC_8192E_2ANT_MAX; i++) {
+		if (coex_sta->bt_info_c2h_cnt[i]) {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+				   "\r\n %-35s = %02x %02x %02x %02x ",
+				   GLBtInfoSrc8192e2Ant[i],
+				   coex_sta->bt_info_c2h[i][0],
+				   coex_sta->bt_info_c2h[i][1],
+				   coex_sta->bt_info_c2h[i][2],
+				   coex_sta->bt_info_c2h[i][3]);
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+				   "%02x %02x %02x(%d)",
+				   coex_sta->bt_info_c2h[i][4],
+				   coex_sta->bt_info_c2h[i][5],
+				   coex_sta->bt_info_c2h[i][6],
+				   coex_sta->bt_info_c2h_cnt[i]);
+		}
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/%s",
+		   "PS state, IPS/LPS",
+		   ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+		   ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")));
+	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", "SS Type",
+		   coex_dm->cur_sstype);
+
+	/* Sw mechanism	*/
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+		   "============[Sw mechanism]============");
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ",
+		   "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink,
+		   coex_dm->cur_low_penalty_ra, coex_dm->limited_dig);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d(0x%x) ",
+		   "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]",
+		   coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off,
+		   coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ", "Rate Mask",
+		   btcoexist->bt_info.ra_mask);
+
+	/* Fw mechanism	*/
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+		   "============[Fw mechanism]============");
+
+	ps_tdma_case = coex_dm->cur_ps_tdma;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
+		   "PS TDMA", coex_dm->ps_tdma_para[0],
+		   coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2],
+		   coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4],
+		   ps_tdma_case, coex_dm->auto_tdma_adjust);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ",
+		   "DecBtPwr/ IgnWlanAct",
+		   coex_dm->cur_dec_bt_pwr, coex_dm->cur_ignore_wlan_act);
+
+	/* Hw setting */
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+		   "============[Hw setting]============");
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x",
+		   "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+		   "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1,
+		   coex_dm->backup_arfr_cnt2, coex_dm->backup_retrylimit,
+		   coex_dm->backup_ampdu_maxtime);
+
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430);
+	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434);
+	u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a);
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+		   "0x430/0x434/0x42a/0x456",
+		   u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]);
+
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc04);
+	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xd04);
+	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x90c);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+		   "0xc04/ 0xd04/ 0x90c", u32tmp[0], u32tmp[1], u32tmp[2]);
+
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "0x778",
+		   u8tmp[0]);
+
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x92c);
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x930);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+		   "0x92c/ 0x930", (u8tmp[0]), u32tmp[0]);
+
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x4f);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+		   "0x40/ 0x4f", u8tmp[0], u8tmp[1]);
+
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+		   "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]);
+
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x", "0xc50(dig)",
+		   u32tmp[0]);
+
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+		   "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)",
+		   u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+		   "0x770(hp rx[31:16]/tx[15:0])",
+		   coex_sta->high_priority_rx, coex_sta->high_priority_tx);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+		   "0x774(lp rx[31:16]/tx[15:0])",
+		   coex_sta->low_priority_rx, coex_sta->low_priority_tx);
+#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 1)
+	halbtc8192e2ant_monitor_bt_ctr(btcoexist);
+#endif
+	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	if (BTC_IPS_ENTER == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], IPS ENTER notify\n");
+		coex_sta->under_ips = true;
+		halbtc8192e2ant_coex_alloff(btcoexist);
+	} else if (BTC_IPS_LEAVE == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], IPS LEAVE notify\n");
+		coex_sta->under_ips = false;
+	}
+}
+
+void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	if (BTC_LPS_ENABLE == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], LPS ENABLE notify\n");
+		coex_sta->under_lps = true;
+	} else if (BTC_LPS_DISABLE == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], LPS DISABLE notify\n");
+		coex_sta->under_lps = false;
+	}
+}
+
+void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	if (BTC_SCAN_START == type)
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], SCAN START notify\n");
+	else if (BTC_SCAN_FINISH == type)
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], SCAN FINISH notify\n");
+}
+
+void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	if (BTC_ASSOCIATE_START == type)
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], CONNECT START notify\n");
+	else if (BTC_ASSOCIATE_FINISH == type)
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], CONNECT FINISH notify\n");
+}
+
+void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist,
+					    u8 type)
+{
+	u8 h2c_parameter[3] = {0};
+	u32 wifi_bw;
+	u8 wifi_center_chnl;
+
+	if (btcoexist->manual_control ||
+	    btcoexist->stop_coex_dm ||
+	    btcoexist->bt_info.bt_disabled)
+		return;
+
+	if (BTC_MEDIA_CONNECT == type)
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], MEDIA connect notify\n");
+	else
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], MEDIA disconnect notify\n");
+
+	/* only 2.4G we need to inform bt the chnl mask */
+	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL,
+			   &wifi_center_chnl);
+	if ((BTC_MEDIA_CONNECT == type) &&
+	    (wifi_center_chnl <= 14)) {
+		h2c_parameter[0] = 0x1;
+		h2c_parameter[1] = wifi_center_chnl;
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+		if (BTC_WIFI_BW_HT40 == wifi_bw)
+			h2c_parameter[2] = 0x30;
+		else
+			h2c_parameter[2] = 0x20;
+	}
+
+	coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+	coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+	coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], FW write 0x66 = 0x%x\n",
+		  h2c_parameter[0] << 16 | h2c_parameter[1] << 8 |
+		  h2c_parameter[2]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist,
+					      u8 type)
+{
+	if (type == BTC_PACKET_DHCP)
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], DHCP Packet notify\n");
+}
+
+void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist,
+				       u8 *tmp_buf, u8 length)
+{
+	u8 bt_info = 0;
+	u8 i, rsp_source = 0;
+	bool bt_busy = false, limited_dig = false;
+	bool wifi_connected = false;
+
+	coex_sta->c2h_bt_info_req_sent = false;
+
+	rsp_source = tmp_buf[0] & 0xf;
+	if (rsp_source >= BT_INFO_SRC_8192E_2ANT_MAX)
+		rsp_source = BT_INFO_SRC_8192E_2ANT_WIFI_FW;
+	coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+		  "[BTCoex], Bt info[%d], length=%d, hex data = [",
+		  rsp_source, length);
+	for (i = 0; i < length; i++) {
+		coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
+		if (i == 1)
+			bt_info = tmp_buf[i];
+		if (i == length-1)
+			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+				  "0x%02x]\n", tmp_buf[i]);
+		else
+			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+				  "0x%02x, ", tmp_buf[i]);
+	}
+
+	if (BT_INFO_SRC_8192E_2ANT_WIFI_FW != rsp_source) {
+		coex_sta->bt_retry_cnt =	/* [3:0] */
+			coex_sta->bt_info_c2h[rsp_source][2] & 0xf;
+
+		coex_sta->bt_rssi =
+			coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10;
+
+		coex_sta->bt_info_ext =
+			coex_sta->bt_info_c2h[rsp_source][4];
+
+		/* Here we need to resend some wifi info to BT
+		 * because bt is reset and loss of the info.
+		 */
+		if ((coex_sta->bt_info_ext & BIT1)) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "bit1, send wifi BW&Chnl to BT!!\n");
+			btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+					   &wifi_connected);
+			if (wifi_connected)
+				ex_halbtc8192e2ant_media_status_notify(
+							btcoexist,
+							BTC_MEDIA_CONNECT);
+			else
+				ex_halbtc8192e2ant_media_status_notify(
+							btcoexist,
+							BTC_MEDIA_DISCONNECT);
+		}
+
+		if ((coex_sta->bt_info_ext & BIT3)) {
+			if (!btcoexist->manual_control &&
+			    !btcoexist->stop_coex_dm) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "bit3, BT NOT ignore Wlan active!\n");
+				halbtc8192e2ant_IgnoreWlanAct(btcoexist,
+							      FORCE_EXEC,
+							      false);
+			}
+		} else {
+			/* BT already NOT ignore Wlan active,
+			 * do nothing here.
+			 */
+		}
+
+#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0)
+		if ((coex_sta->bt_info_ext & BIT4)) {
+			/* BT auto report already enabled, do nothing */
+		} else {
+			halbtc8192e2ant_bt_autoreport(btcoexist, FORCE_EXEC,
+						      true);
+		}
+#endif
+	}
+
+	/* check BIT2 first ==> check if bt is under inquiry or page scan */
+	if (bt_info & BT_INFO_8192E_2ANT_B_INQ_PAGE)
+		coex_sta->c2h_bt_inquiry_page = true;
+	else
+		coex_sta->c2h_bt_inquiry_page = false;
+
+	/* set link exist status */
+	if (!(bt_info&BT_INFO_8192E_2ANT_B_CONNECTION)) {
+		coex_sta->bt_link_exist = false;
+		coex_sta->pan_exist = false;
+		coex_sta->a2dp_exist = false;
+		coex_sta->hid_exist = false;
+		coex_sta->sco_exist = false;
+	} else {/* connection exists */
+		coex_sta->bt_link_exist = true;
+		if (bt_info & BT_INFO_8192E_2ANT_B_FTP)
+			coex_sta->pan_exist = true;
+		else
+			coex_sta->pan_exist = false;
+		if (bt_info & BT_INFO_8192E_2ANT_B_A2DP)
+			coex_sta->a2dp_exist = true;
+		else
+			coex_sta->a2dp_exist = false;
+		if (bt_info & BT_INFO_8192E_2ANT_B_HID)
+			coex_sta->hid_exist = true;
+		else
+			coex_sta->hid_exist = false;
+		if (bt_info & BT_INFO_8192E_2ANT_B_SCO_ESCO)
+			coex_sta->sco_exist = true;
+		else
+			coex_sta->sco_exist = false;
+	}
+
+	halbtc8192e2ant_update_btlink_info(btcoexist);
+
+	if (!(bt_info&BT_INFO_8192E_2ANT_B_CONNECTION)) {
+		coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BT Non-Connected idle!!!\n");
+	} else if (bt_info == BT_INFO_8192E_2ANT_B_CONNECTION) {
+		coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], bt_infoNotify(), BT Connected-idle!!!\n");
+	} else if ((bt_info&BT_INFO_8192E_2ANT_B_SCO_ESCO) ||
+		   (bt_info&BT_INFO_8192E_2ANT_B_SCO_BUSY)) {
+		coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_SCO_BUSY;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], bt_infoNotify(), BT SCO busy!!!\n");
+	} else if (bt_info&BT_INFO_8192E_2ANT_B_ACL_BUSY) {
+		coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_ACL_BUSY;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], bt_infoNotify(), BT ACL busy!!!\n");
+	} else {
+		coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_MAX;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex]bt_infoNotify(), BT Non-Defined state!!!\n");
+	}
+
+	if ((BT_8192E_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+	    (BT_8192E_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+	    (BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) {
+		bt_busy = true;
+		limited_dig = true;
+	} else {
+		bt_busy = false;
+		limited_dig = false;
+	}
+
+	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+	coex_dm->limited_dig = limited_dig;
+	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig);
+
+	halbtc8192e2ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist,
+					       u8 type)
+{
+}
+
+void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist)
+{
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n");
+
+	halbtc8192e2ant_IgnoreWlanAct(btcoexist, FORCE_EXEC, true);
+	ex_halbtc8192e2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist)
+{
+	static u8 dis_ver_info_cnt;
+	u32 fw_ver = 0, bt_patch_ver = 0;
+	struct btc_board_info *board_info = &btcoexist->board_info;
+	struct btc_stack_info *stack_info = &btcoexist->stack_info;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "=======================Periodical=======================\n");
+	if (dis_ver_info_cnt <= 5) {
+		dis_ver_info_cnt += 1;
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "************************************************\n");
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n",
+			  board_info->pg_ant_num, board_info->btdm_ant_num,
+			  board_info->btdm_ant_pos);
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "BT stack/ hci ext ver = %s / %d\n",
+			  ((stack_info->profile_notified) ? "Yes" : "No"),
+			  stack_info->hci_version);
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+				   &bt_patch_ver);
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
+			  glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant,
+			  fw_ver, bt_patch_ver, bt_patch_ver);
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "************************************************\n");
+	}
+
+#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0)
+	halbtc8192e2ant_querybt_info(btcoexist);
+	halbtc8192e2ant_monitor_bt_ctr(btcoexist);
+	btc8192e2ant_monitor_bt_enable_dis(btcoexist);
+#else
+	if (halbtc8192e2ant_iswifi_status_changed(btcoexist) ||
+	    coex_dm->auto_tdma_adjust)
+		halbtc8192e2ant_run_coexist_mechanism(btcoexist);
+#endif
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h
new file mode 100644
index 0000000..75e1f7d
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8192e2ant.h
@@ -0,0 +1,185 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+/*****************************************************************
+ *   The following is for 8192E 2Ant BT Co-exist definition
+ *****************************************************************/
+#define	BT_AUTO_REPORT_ONLY_8192E_2ANT			0
+
+#define	BT_INFO_8192E_2ANT_B_FTP			BIT7
+#define	BT_INFO_8192E_2ANT_B_A2DP			BIT6
+#define	BT_INFO_8192E_2ANT_B_HID			BIT5
+#define	BT_INFO_8192E_2ANT_B_SCO_BUSY			BIT4
+#define	BT_INFO_8192E_2ANT_B_ACL_BUSY			BIT3
+#define	BT_INFO_8192E_2ANT_B_INQ_PAGE			BIT2
+#define	BT_INFO_8192E_2ANT_B_SCO_ESCO			BIT1
+#define	BT_INFO_8192E_2ANT_B_CONNECTION			BIT0
+
+#define BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT		2
+
+enum bt_info_src_8192e_2ant {
+	BT_INFO_SRC_8192E_2ANT_WIFI_FW			= 0x0,
+	BT_INFO_SRC_8192E_2ANT_BT_RSP			= 0x1,
+	BT_INFO_SRC_8192E_2ANT_BT_ACTIVE_SEND		= 0x2,
+	BT_INFO_SRC_8192E_2ANT_MAX
+};
+
+enum bt_8192e_2ant_bt_status {
+	BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE	= 0x0,
+	BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE		= 0x1,
+	BT_8192E_2ANT_BT_STATUS_INQ_PAGE		= 0x2,
+	BT_8192E_2ANT_BT_STATUS_ACL_BUSY		= 0x3,
+	BT_8192E_2ANT_BT_STATUS_SCO_BUSY		= 0x4,
+	BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY		= 0x5,
+	BT_8192E_2ANT_BT_STATUS_MAX
+};
+
+enum bt_8192e_2ant_coex_algo {
+	BT_8192E_2ANT_COEX_ALGO_UNDEFINED		= 0x0,
+	BT_8192E_2ANT_COEX_ALGO_SCO			= 0x1,
+	BT_8192E_2ANT_COEX_ALGO_SCO_PAN			= 0x2,
+	BT_8192E_2ANT_COEX_ALGO_HID			= 0x3,
+	BT_8192E_2ANT_COEX_ALGO_A2DP			= 0x4,
+	BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS		= 0x5,
+	BT_8192E_2ANT_COEX_ALGO_PANEDR			= 0x6,
+	BT_8192E_2ANT_COEX_ALGO_PANHS			= 0x7,
+	BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP		= 0x8,
+	BT_8192E_2ANT_COEX_ALGO_PANEDR_HID		= 0x9,
+	BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR		= 0xa,
+	BT_8192E_2ANT_COEX_ALGO_HID_A2DP		= 0xb,
+	BT_8192E_2ANT_COEX_ALGO_MAX			= 0xc
+};
+
+struct coex_dm_8192e_2ant {
+	/* fw mechanism */
+	u8 pre_dec_bt_pwr;
+	u8 cur_dec_bt_pwr;
+	u8 pre_fw_dac_swing_lvl;
+	u8 cur_fw_dac_swing_lvl;
+	bool cur_ignore_wlan_act;
+	bool pre_ignore_wlan_act;
+	u8 pre_ps_tdma;
+	u8 cur_ps_tdma;
+	u8 ps_tdma_para[5];
+	u8 tdma_adj_type;
+	bool reset_tdma_adjust;
+	bool auto_tdma_adjust;
+	bool pre_ps_tdma_on;
+	bool cur_ps_tdma_on;
+	bool pre_bt_auto_report;
+	bool cur_bt_auto_report;
+
+	/* sw mechanism */
+	bool pre_rf_rx_lpf_shrink;
+	bool cur_rf_rx_lpf_shrink;
+	u32 bt_rf0x1e_backup;
+	bool pre_low_penalty_ra;
+	bool cur_low_penalty_ra;
+	bool pre_dac_swing_on;
+	u32 pre_dac_swing_lvl;
+	bool cur_dac_swing_on;
+	u32 cur_dac_swing_lvl;
+	bool pre_adc_back_off;
+	bool cur_adc_back_off;
+	bool pre_agc_table_en;
+	bool cur_agc_table_en;
+	u32 pre_val0x6c0;
+	u32 cur_val0x6c0;
+	u32 pre_val0x6c4;
+	u32 cur_val0x6c4;
+	u32 pre_val0x6c8;
+	u32 cur_val0x6c8;
+	u8 pre_val0x6cc;
+	u8 cur_val0x6cc;
+	bool limited_dig;
+
+	u32 backup_arfr_cnt1;	/* Auto Rate Fallback Retry cnt */
+	u32 backup_arfr_cnt2;	/* Auto Rate Fallback Retry cnt */
+	u16 backup_retrylimit;
+	u8 backup_ampdu_maxtime;
+
+	/* algorithm related */
+	u8 pre_algorithm;
+	u8 cur_algorithm;
+	u8 bt_status;
+	u8 wifi_chnl_info[3];
+
+	u8 pre_sstype;
+	u8 cur_sstype;
+
+	u32 prera_mask;
+	u32 curra_mask;
+	u8 curra_masktype;
+	u8 pre_arfrtype;
+	u8 cur_arfrtype;
+	u8 pre_retrylimit_type;
+	u8 cur_retrylimit_type;
+	u8 pre_ampdutime_type;
+	u8 cur_ampdutime_type;
+};
+
+struct coex_sta_8192e_2ant {
+	bool bt_link_exist;
+	bool sco_exist;
+	bool a2dp_exist;
+	bool hid_exist;
+	bool pan_exist;
+
+	bool under_lps;
+	bool under_ips;
+	u32 high_priority_tx;
+	u32 high_priority_rx;
+	u32 low_priority_tx;
+	u32 low_priority_rx;
+	u8 bt_rssi;
+	u8 pre_bt_rssi_state;
+	u8 pre_wifi_rssi_state[4];
+	bool c2h_bt_info_req_sent;
+	u8 bt_info_c2h[BT_INFO_SRC_8192E_2ANT_MAX][10];
+	u32 bt_info_c2h_cnt[BT_INFO_SRC_8192E_2ANT_MAX];
+	bool c2h_bt_inquiry_page;
+	u8 bt_retry_cnt;
+	u8 bt_info_ext;
+};
+
+/****************************************************************
+ *    The following is interface which will notify coex module.
+ ****************************************************************/
+void ex_halbtc8192e2ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_halbtc8192e2ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_halbtc8192e2ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8192e2ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8192e2ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8192e2ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8192e2ant_media_status_notify(struct btc_coexist *btcoexist,
+					    u8 type);
+void ex_halbtc8192e2ant_special_packet_notify(struct btc_coexist *btcoexist,
+					      u8 type);
+void ex_halbtc8192e2ant_bt_info_notify(struct btc_coexist *btcoexist,
+				       u8 *tmpbuf, u8 length);
+void ex_halbtc8192e2ant_stack_operation_notify(struct btc_coexist *btcoexist,
+					       u8 type);
+void ex_halbtc8192e2ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_halbtc8192e2ant_periodical(struct btc_coexist *btcoexist);
+void ex_halbtc8192e2ant_display_coex_info(struct btc_coexist *btcoexist);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c
new file mode 100644
index 0000000..c4acd40
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.c
@@ -0,0 +1,3170 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/***************************************************************
+ * Description:
+ *
+ * This file is for RTL8723B Co-exist mechanism
+ *
+ * History
+ * 2012/11/15 Cosa first check in.
+ *
+ ***************************************************************/
+
+/***************************************************************
+ * include files
+ ***************************************************************/
+#include "halbt_precomp.h"
+/***************************************************************
+ * Global variables, these are static variables
+ ***************************************************************/
+static struct coex_dm_8723b_1ant glcoex_dm_8723b_1ant;
+static struct coex_dm_8723b_1ant *coex_dm = &glcoex_dm_8723b_1ant;
+static struct coex_sta_8723b_1ant glcoex_sta_8723b_1ant;
+static struct coex_sta_8723b_1ant *coex_sta = &glcoex_sta_8723b_1ant;
+
+static const char *const GLBtInfoSrc8723b1Ant[] = {
+	"BT Info[wifi fw]",
+	"BT Info[bt rsp]",
+	"BT Info[bt auto report]",
+};
+
+static u32 glcoex_ver_date_8723b_1ant = 20130918;
+static u32 glcoex_ver_8723b_1ant = 0x47;
+
+/***************************************************************
+ * local function proto type if needed
+ ***************************************************************/
+/***************************************************************
+ * local function start with halbtc8723b1ant_
+ ***************************************************************/
+static u8 halbtc8723b1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh,
+					u8 rssi_thresh1)
+{
+	s32 bt_rssi = 0;
+	u8 bt_rssi_state = coex_sta->pre_bt_rssi_state;
+
+	bt_rssi = coex_sta->bt_rssi;
+
+	if (level_num == 2) {
+		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+			if (bt_rssi >= rssi_thresh +
+					BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+				bt_rssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to High\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at Low\n");
+			}
+		} else {
+			if (bt_rssi < rssi_thresh) {
+				bt_rssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to Low\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at High\n");
+			}
+		}
+	} else if (level_num == 3) {
+		if (rssi_thresh > rssi_thresh1) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+				  "[BTCoex], BT Rssi thresh error!!\n");
+			return coex_sta->pre_bt_rssi_state;
+		}
+
+		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+			if (bt_rssi >= rssi_thresh +
+					BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+				bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to Medium\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at Low\n");
+			}
+		} else if ((coex_sta->pre_bt_rssi_state ==
+					BTC_RSSI_STATE_MEDIUM) ||
+			  (coex_sta->pre_bt_rssi_state ==
+					BTC_RSSI_STATE_STAY_MEDIUM)) {
+			if (bt_rssi >= rssi_thresh1 +
+					BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+				bt_rssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to High\n");
+			} else if (bt_rssi < rssi_thresh) {
+				bt_rssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to Low\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at Medium\n");
+			}
+		} else {
+			if (bt_rssi < rssi_thresh1) {
+				bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to Medium\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at High\n");
+			}
+		}
+	}
+
+	coex_sta->pre_bt_rssi_state = bt_rssi_state;
+
+	return bt_rssi_state;
+}
+
+static u8 halbtc8723b1ant_wifi_rssi_state(struct btc_coexist *btcoexist,
+					  u8 index, u8 level_num,
+					  u8 rssi_thresh, u8 rssi_thresh1)
+{
+	s32 wifi_rssi = 0;
+	u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+	btcoexist->btc_get(btcoexist,
+		BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+
+	if (level_num == 2) {
+		if ((coex_sta->pre_wifi_rssi_state[index] ==
+					BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_wifi_rssi_state[index] ==
+					BTC_RSSI_STATE_STAY_LOW)) {
+			if (wifi_rssi >= rssi_thresh +
+					BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+				wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to High\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at Low\n");
+			}
+		} else {
+			if (wifi_rssi < rssi_thresh) {
+				wifi_rssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to Low\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at High\n");
+			}
+		}
+	} else if (level_num == 3) {
+		if (rssi_thresh > rssi_thresh1) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+				  "[BTCoex], wifi RSSI thresh error!!\n");
+			return coex_sta->pre_wifi_rssi_state[index];
+		}
+
+		if ((coex_sta->pre_wifi_rssi_state[index] ==
+						BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_wifi_rssi_state[index] ==
+						BTC_RSSI_STATE_STAY_LOW)) {
+			if (wifi_rssi >= rssi_thresh +
+					 BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to Medium\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at Low\n");
+			}
+		} else if ((coex_sta->pre_wifi_rssi_state[index] ==
+						BTC_RSSI_STATE_MEDIUM) ||
+			   (coex_sta->pre_wifi_rssi_state[index] ==
+						BTC_RSSI_STATE_STAY_MEDIUM)) {
+			if (wifi_rssi >= rssi_thresh1 +
+					 BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT) {
+				wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to High\n");
+			} else if (wifi_rssi < rssi_thresh) {
+				wifi_rssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to Low\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at Medium\n");
+			}
+		} else {
+			if (wifi_rssi < rssi_thresh1) {
+				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to Medium\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at High\n");
+			}
+		}
+	}
+
+	coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state;
+
+	return wifi_rssi_state;
+}
+
+static void halbtc8723b1ant_updatera_mask(struct btc_coexist *btcoexist,
+					  bool force_exec, u32 dis_rate_mask)
+{
+	coex_dm->curra_mask = dis_rate_mask;
+
+	if (force_exec || (coex_dm->prera_mask != coex_dm->curra_mask))
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask,
+				   &coex_dm->curra_mask);
+
+	coex_dm->prera_mask = coex_dm->curra_mask;
+}
+
+static void btc8723b1ant_auto_rate_fb_retry(struct btc_coexist *btcoexist,
+					    bool force_exec, u8 type)
+{
+	bool wifi_under_bmode = false;
+
+	coex_dm->cur_arfr_type = type;
+
+	if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) {
+		switch (coex_dm->cur_arfr_type) {
+		case 0:	/* normal mode */
+			btcoexist->btc_write_4byte(btcoexist, 0x430,
+						   coex_dm->backup_arfr_cnt1);
+			btcoexist->btc_write_4byte(btcoexist, 0x434,
+						   coex_dm->backup_arfr_cnt2);
+			break;
+		case 1:
+			btcoexist->btc_get(btcoexist,
+					   BTC_GET_BL_WIFI_UNDER_B_MODE,
+					   &wifi_under_bmode);
+			if (wifi_under_bmode) {
+				btcoexist->btc_write_4byte(btcoexist,
+							   0x430, 0x0);
+				btcoexist->btc_write_4byte(btcoexist,
+							   0x434, 0x01010101);
+			} else {
+				btcoexist->btc_write_4byte(btcoexist,
+							   0x430, 0x0);
+				btcoexist->btc_write_4byte(btcoexist,
+							   0x434, 0x04030201);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	coex_dm->pre_arfr_type = coex_dm->cur_arfr_type;
+}
+
+static void halbtc8723b1ant_retry_limit(struct btc_coexist *btcoexist,
+					bool force_exec, u8 type)
+{
+	coex_dm->cur_retry_limit_type = type;
+
+	if (force_exec || (coex_dm->pre_retry_limit_type !=
+			   coex_dm->cur_retry_limit_type)) {
+		switch (coex_dm->cur_retry_limit_type) {
+		case 0:	/* normal mode */
+			btcoexist->btc_write_2byte(btcoexist, 0x42a,
+						   coex_dm->backup_retry_limit);
+			break;
+		case 1:	/* retry limit = 8 */
+			btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808);
+			break;
+		default:
+			break;
+		}
+	}
+
+	coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type;
+}
+
+static void halbtc8723b1ant_ampdu_maxtime(struct btc_coexist *btcoexist,
+					  bool force_exec, u8 type)
+{
+	coex_dm->cur_ampdu_time_type = type;
+
+	if (force_exec || (coex_dm->pre_ampdu_time_type !=
+		coex_dm->cur_ampdu_time_type)) {
+		switch (coex_dm->cur_ampdu_time_type) {
+		case 0:	/* normal mode */
+				btcoexist->btc_write_1byte(btcoexist, 0x456,
+						coex_dm->backup_ampdu_max_time);
+				break;
+		case 1:	/* AMPDU timw = 0x38 * 32us */
+				btcoexist->btc_write_1byte(btcoexist,
+							   0x456, 0x38);
+				break;
+		default:
+				break;
+		}
+	}
+
+	coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type;
+}
+
+static void halbtc8723b1ant_limited_tx(struct btc_coexist *btcoexist,
+				       bool force_exec, u8 ra_masktype,
+				       u8 arfr_type, u8 retry_limit_type,
+				       u8 ampdu_time_type)
+{
+	switch (ra_masktype) {
+	case 0:	/* normal mode */
+		halbtc8723b1ant_updatera_mask(btcoexist, force_exec, 0x0);
+		break;
+	case 1:	/* disable cck 1/2 */
+		halbtc8723b1ant_updatera_mask(btcoexist, force_exec,
+					      0x00000003);
+		break;
+	/* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4*/
+	case 2:
+		halbtc8723b1ant_updatera_mask(btcoexist, force_exec,
+					      0x0001f1f7);
+		break;
+	default:
+		break;
+	}
+
+	btc8723b1ant_auto_rate_fb_retry(btcoexist, force_exec, arfr_type);
+	halbtc8723b1ant_retry_limit(btcoexist, force_exec, retry_limit_type);
+	halbtc8723b1ant_ampdu_maxtime(btcoexist, force_exec, ampdu_time_type);
+}
+
+static void halbtc8723b1ant_limited_rx(struct btc_coexist *btcoexist,
+				       bool force_exec, bool rej_ap_agg_pkt,
+				       bool bt_ctrl_agg_buf_size,
+				       u8 agg_buf_size)
+{
+	bool reject_rx_agg = rej_ap_agg_pkt;
+	bool bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size;
+	u8 rxaggsize = agg_buf_size;
+
+	/**********************************************
+	 *	Rx Aggregation related setting
+	 **********************************************/
+	btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT,
+			   &reject_rx_agg);
+	/* decide BT control aggregation buf size or not  */
+	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE,
+			   &bt_ctrl_rx_agg_size);
+	/* aggregation buf size, only work
+	 * when BT control Rx aggregation size.
+	 */
+	btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rxaggsize);
+	/* real update aggregation setting  */
+	btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL);
+}
+
+static void halbtc8723b1ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+	u32 reg_hp_txrx, reg_lp_txrx, u32tmp;
+	u32 reg_hp_tx = 0, reg_hp_rx = 0;
+	u32 reg_lp_tx = 0, reg_lp_rx = 0;
+
+	reg_hp_txrx = 0x770;
+	reg_lp_txrx = 0x774;
+
+	u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx);
+	reg_hp_tx = u32tmp & MASKLWORD;
+	reg_hp_rx = (u32tmp & MASKHWORD) >> 16;
+
+	u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx);
+	reg_lp_tx = u32tmp & MASKLWORD;
+	reg_lp_rx = (u32tmp & MASKHWORD) >> 16;
+
+	coex_sta->high_priority_tx = reg_hp_tx;
+	coex_sta->high_priority_rx = reg_hp_rx;
+	coex_sta->low_priority_tx = reg_lp_tx;
+	coex_sta->low_priority_rx = reg_lp_rx;
+
+	/* reset counter */
+	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static void halbtc8723b1ant_query_bt_info(struct btc_coexist *btcoexist)
+{
+	u8 h2c_parameter[1] = {0};
+
+	coex_sta->c2h_bt_info_req_sent = true;
+
+	h2c_parameter[0] |= BIT0;	/* trigger*/
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+		  h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
+static bool btc8723b1ant_is_wifi_status_changed(struct btc_coexist *btcoexist)
+{
+	static bool pre_wifi_busy;
+	static bool pre_under_4way, pre_bt_hs_on;
+	bool wifi_busy = false, under_4way = false, bt_hs_on = false;
+	bool wifi_connected = false;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+			   &wifi_connected);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS,
+			   &under_4way);
+
+	if (wifi_connected) {
+		if (wifi_busy != pre_wifi_busy) {
+			pre_wifi_busy = wifi_busy;
+			return true;
+		}
+		if (under_4way != pre_under_4way) {
+			pre_under_4way = under_4way;
+			return true;
+		}
+		if (bt_hs_on != pre_bt_hs_on) {
+			pre_bt_hs_on = bt_hs_on;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+static void halbtc8723b1ant_update_bt_link_info(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	bool bt_hs_on = false;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+	bt_link_info->bt_link_exist = coex_sta->bt_link_exist;
+	bt_link_info->sco_exist = coex_sta->sco_exist;
+	bt_link_info->a2dp_exist = coex_sta->a2dp_exist;
+	bt_link_info->pan_exist = coex_sta->pan_exist;
+	bt_link_info->hid_exist = coex_sta->hid_exist;
+
+	/* work around for HS mode. */
+	if (bt_hs_on) {
+		bt_link_info->pan_exist = true;
+		bt_link_info->bt_link_exist = true;
+	}
+
+	/* check if Sco only */
+	if (bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+	    !bt_link_info->pan_exist && !bt_link_info->hid_exist)
+		bt_link_info->sco_only = true;
+	else
+		bt_link_info->sco_only = false;
+
+	/* check if A2dp only */
+	if (!bt_link_info->sco_exist && bt_link_info->a2dp_exist &&
+	    !bt_link_info->pan_exist && !bt_link_info->hid_exist)
+		bt_link_info->a2dp_only = true;
+	else
+		bt_link_info->a2dp_only = false;
+
+	/* check if Pan only */
+	if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+	    bt_link_info->pan_exist && !bt_link_info->hid_exist)
+		bt_link_info->pan_only = true;
+	else
+		bt_link_info->pan_only = false;
+
+	/* check if Hid only */
+	if (!bt_link_info->sco_exist && !bt_link_info->a2dp_exist &&
+	    !bt_link_info->pan_exist && bt_link_info->hid_exist)
+		bt_link_info->hid_only = true;
+	else
+		bt_link_info->hid_only = false;
+}
+
+static u8 halbtc8723b1ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	bool bt_hs_on = false;
+	u8 algorithm = BT_8723B_1ANT_COEX_ALGO_UNDEFINED;
+	u8 numdiffprofile = 0;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+	if (!bt_link_info->bt_link_exist) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], No BT link exists!!!\n");
+		return algorithm;
+	}
+
+	if (bt_link_info->sco_exist)
+		numdiffprofile++;
+	if (bt_link_info->hid_exist)
+		numdiffprofile++;
+	if (bt_link_info->pan_exist)
+		numdiffprofile++;
+	if (bt_link_info->a2dp_exist)
+		numdiffprofile++;
+
+	if (numdiffprofile == 1) {
+		if (bt_link_info->sco_exist) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], BT Profile = SCO only\n");
+			algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
+		} else {
+			if (bt_link_info->hid_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT Profile = HID only\n");
+				algorithm = BT_8723B_1ANT_COEX_ALGO_HID;
+			} else if (bt_link_info->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT Profile = A2DP only\n");
+				algorithm = BT_8723B_1ANT_COEX_ALGO_A2DP;
+			} else if (bt_link_info->pan_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = PAN(HS) only\n");
+					algorithm =
+						BT_8723B_1ANT_COEX_ALGO_PANHS;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = PAN(EDR) only\n");
+					algorithm =
+						BT_8723B_1ANT_COEX_ALGO_PANEDR;
+				}
+			}
+		}
+	} else if (numdiffprofile == 2) {
+		if (bt_link_info->sco_exist) {
+			if (bt_link_info->hid_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT Profile = SCO + HID\n");
+				algorithm = BT_8723B_1ANT_COEX_ALGO_HID;
+			} else if (bt_link_info->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n");
+				algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
+			} else if (bt_link_info->pan_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + PAN(HS)\n");
+					algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + PAN(EDR)\n");
+					algorithm =
+					    BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+				}
+			}
+		} else {
+			if (bt_link_info->hid_exist &&
+			    bt_link_info->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT Profile = HID + A2DP\n");
+				algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
+			} else if (bt_link_info->hid_exist &&
+				   bt_link_info->pan_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = HID + PAN(HS)\n");
+					algorithm =
+					    BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = HID + PAN(EDR)\n");
+					algorithm =
+					    BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+				}
+			} else if (bt_link_info->pan_exist &&
+				   bt_link_info->a2dp_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = A2DP + PAN(HS)\n");
+					algorithm =
+					    BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = A2DP + PAN(EDR)\n");
+					algorithm =
+					    BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP;
+				}
+			}
+		}
+	} else if (numdiffprofile == 3) {
+		if (bt_link_info->sco_exist) {
+			if (bt_link_info->hid_exist &&
+			    bt_link_info->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n");
+				algorithm = BT_8723B_1ANT_COEX_ALGO_HID;
+			} else if (bt_link_info->hid_exist &&
+				   bt_link_info->pan_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n");
+					algorithm =
+					    BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n");
+					algorithm =
+					    BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+				}
+			} else if (bt_link_info->pan_exist &&
+				   bt_link_info->a2dp_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n");
+					algorithm = BT_8723B_1ANT_COEX_ALGO_SCO;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n");
+					algorithm =
+					    BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+				}
+			}
+		} else {
+			if (bt_link_info->hid_exist &&
+			    bt_link_info->pan_exist &&
+			    bt_link_info->a2dp_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n");
+					algorithm =
+					    BT_8723B_1ANT_COEX_ALGO_HID_A2DP;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n");
+					algorithm =
+					    BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR;
+				}
+			}
+		}
+	} else if (numdiffprofile >= 3) {
+		if (bt_link_info->sco_exist) {
+			if (bt_link_info->hid_exist &&
+			    bt_link_info->pan_exist &&
+			    bt_link_info->a2dp_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n");
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n");
+					algorithm =
+					    BT_8723B_1ANT_COEX_ALGO_PANEDR_HID;
+				}
+			}
+		}
+	}
+
+	return algorithm;
+}
+
+static void btc8723b1ant_set_sw_pen_tx_rate_adapt(struct btc_coexist *btcoexist,
+						  bool low_penalty_ra)
+{
+	u8 h2c_parameter[6] = {0};
+
+	h2c_parameter[0] = 0x6;	/* opCode, 0x6= Retry_Penalty */
+
+	if (low_penalty_ra) {
+		h2c_parameter[1] |= BIT0;
+		/*normal rate except MCS7/6/5, OFDM54/48/36 */
+		h2c_parameter[2] = 0x00;
+		h2c_parameter[3] = 0xf7;  /*MCS7 or OFDM54 */
+		h2c_parameter[4] = 0xf8;  /*MCS6 or OFDM48 */
+		h2c_parameter[5] = 0xf9;  /*MCS5 or OFDM36 */
+	}
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], set WiFi Low-Penalty Retry: %s",
+		  (low_penalty_ra ? "ON!!" : "OFF!!"));
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter);
+}
+
+static void halbtc8723b1ant_low_penalty_ra(struct btc_coexist *btcoexist,
+					   bool force_exec, bool low_penalty_ra)
+{
+	coex_dm->cur_low_penalty_ra = low_penalty_ra;
+
+	if (!force_exec) {
+		if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra)
+			return;
+	}
+	btc8723b1ant_set_sw_pen_tx_rate_adapt(btcoexist,
+					      coex_dm->cur_low_penalty_ra);
+
+	coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra;
+}
+
+static void halbtc8723b1ant_set_coex_table(struct btc_coexist *btcoexist,
+					   u32 val0x6c0, u32 val0x6c4,
+					   u32 val0x6c8, u8 val0x6cc)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0);
+	btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4);
+	btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8);
+	btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc);
+	btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void halbtc8723b1ant_coex_table(struct btc_coexist *btcoexist,
+				       bool force_exec, u32 val0x6c0,
+				       u32 val0x6c4, u32 val0x6c8,
+				       u8 val0x6cc)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+		  "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6cc = 0x%x\n",
+		  (force_exec ? "force to" : ""),
+		  val0x6c0, val0x6c4, val0x6cc);
+	coex_dm->cur_val0x6c0 = val0x6c0;
+	coex_dm->cur_val0x6c4 = val0x6c4;
+	coex_dm->cur_val0x6c8 = val0x6c8;
+	coex_dm->cur_val0x6cc = val0x6cc;
+
+	if (!force_exec) {
+		if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) &&
+		    (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) &&
+		    (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) &&
+		    (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc))
+			return;
+	}
+	halbtc8723b1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4,
+				       val0x6c8, val0x6cc);
+
+	coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0;
+	coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4;
+	coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8;
+	coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc;
+}
+
+static void halbtc8723b1ant_coex_table_with_type(struct btc_coexist *btcoexist,
+						 bool force_exec, u8 type)
+{
+	switch (type) {
+	case 0:
+		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+					   0x55555555, 0xffffff, 0x3);
+		break;
+	case 1:
+		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+					   0x5a5a5a5a, 0xffffff, 0x3);
+		break;
+	case 2:
+		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+					   0x5a5a5a5a, 0xffffff, 0x3);
+		break;
+	case 3:
+		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+					   0xaaaaaaaa, 0xffffff, 0x3);
+		break;
+	case 4:
+		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+					   0x5aaa5aaa, 0xffffff, 0x3);
+		break;
+	case 5:
+		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+					   0xaaaa5a5a, 0xffffff, 0x3);
+		break;
+	case 6:
+		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555,
+					   0xaaaa5a5a, 0xffffff, 0x3);
+		break;
+	case 7:
+		halbtc8723b1ant_coex_table(btcoexist, force_exec, 0xaaaaaaaa,
+					   0xaaaaaaaa, 0xffffff, 0x3);
+		break;
+	default:
+		break;
+	}
+}
+
+static void halbtc8723b1ant_SetFwIgnoreWlanAct(struct btc_coexist *btcoexist,
+					       bool enable)
+{
+	u8 h2c_parameter[1] = {0};
+
+	if (enable)
+		h2c_parameter[0] |= BIT0;	/* function enable */
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
+		  h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter);
+}
+
+static void halbtc8723b1ant_ignore_wlan_act(struct btc_coexist *btcoexist,
+					    bool force_exec, bool enable)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s turn Ignore WlanAct %s\n",
+		  (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+	coex_dm->cur_ignore_wlan_act = enable;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n",
+			  coex_dm->pre_ignore_wlan_act,
+			  coex_dm->cur_ignore_wlan_act);
+
+		if (coex_dm->pre_ignore_wlan_act ==
+		    coex_dm->cur_ignore_wlan_act)
+			return;
+	}
+	halbtc8723b1ant_SetFwIgnoreWlanAct(btcoexist, enable);
+
+	coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void halbtc8723b1ant_set_fw_ps_tdma(struct btc_coexist *btcoexist,
+					   u8 byte1, u8 byte2, u8 byte3,
+					   u8 byte4, u8 byte5)
+{
+	u8 h2c_parameter[5] = {0};
+	u8 real_byte1 = byte1, real_byte5 = byte5;
+	bool ap_enable = false;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+			   &ap_enable);
+
+	if (ap_enable) {
+		if ((byte1 & BIT4) && !(byte1 & BIT5)) {
+			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+				  "[BTCoex], FW for 1Ant AP mode\n");
+			real_byte1 &= ~BIT4;
+			real_byte1 |= BIT5;
+
+			real_byte5 |= BIT5;
+			real_byte5 &= ~BIT6;
+		}
+	}
+
+	h2c_parameter[0] = real_byte1;
+	h2c_parameter[1] = byte2;
+	h2c_parameter[2] = byte3;
+	h2c_parameter[3] = byte4;
+	h2c_parameter[4] = real_byte5;
+
+	coex_dm->ps_tdma_para[0] = real_byte1;
+	coex_dm->ps_tdma_para[1] = byte2;
+	coex_dm->ps_tdma_para[2] = byte3;
+	coex_dm->ps_tdma_para[3] = byte4;
+	coex_dm->ps_tdma_para[4] = real_byte5;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n",
+		  h2c_parameter[0],
+		  h2c_parameter[1] << 24 |
+		  h2c_parameter[2] << 16 |
+		  h2c_parameter[3] << 8 |
+		  h2c_parameter[4]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void halbtc8723b1ant_set_lps_rpwm(struct btc_coexist *btcoexist,
+					 u8 lps_val, u8 rpwm_val)
+{
+	u8 lps = lps_val;
+	u8 rpwm = rpwm_val;
+
+	btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps);
+	btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm);
+}
+
+static void halbtc8723b1ant_LpsRpwm(struct btc_coexist *btcoexist,
+				    bool force_exec,
+				    u8 lps_val, u8 rpwm_val)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s set lps/rpwm = 0x%x/0x%x\n",
+		  (force_exec ? "force to" : ""), lps_val, rpwm_val);
+	coex_dm->cur_lps = lps_val;
+	coex_dm->cur_rpwm = rpwm_val;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], LPS-RxBeaconMode = 0x%x , LPS-RPWM = 0x%x!!\n",
+			  coex_dm->cur_lps, coex_dm->cur_rpwm);
+
+		if ((coex_dm->pre_lps == coex_dm->cur_lps) &&
+		    (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex], LPS-RPWM_Last = 0x%x , LPS-RPWM_Now = 0x%x!!\n",
+				  coex_dm->pre_rpwm, coex_dm->cur_rpwm);
+
+			return;
+		}
+	}
+	halbtc8723b1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val);
+
+	coex_dm->pre_lps = coex_dm->cur_lps;
+	coex_dm->pre_rpwm = coex_dm->cur_rpwm;
+}
+
+static void halbtc8723b1ant_sw_mechanism(struct btc_coexist *btcoexist,
+					 bool low_penalty_ra)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+		  "[BTCoex], SM[LpRA] = %d\n", low_penalty_ra);
+
+	halbtc8723b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra);
+}
+
+static void halbtc8723b1ant_SetAntPath(struct btc_coexist *btcoexist,
+				       u8 ant_pos_type, bool init_hw_cfg,
+				bool wifi_off)
+{
+	struct btc_board_info *board_info = &btcoexist->board_info;
+	u32 fw_ver = 0, u32tmp = 0;
+	bool pg_ext_switch = false;
+	bool use_ext_switch = false;
+	u8 h2c_parameter[2] = {0};
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch);
+	/* [31:16] = fw ver, [15:0] = fw sub ver */
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+
+	if ((fw_ver < 0xc0000) || pg_ext_switch)
+		use_ext_switch = true;
+
+	if (init_hw_cfg) {
+		/*BT select s0/s1 is controlled by WiFi */
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1);
+
+		/*Force GNT_BT to Normal */
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0);
+	} else if (wifi_off) {
+		/*Force GNT_BT to High */
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3);
+		/*BT select s0/s1 is controlled by BT */
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0);
+
+		/* 0x4c[24:23] = 00, Set Antenna control by BT_RFE_CTRL
+		 * BT Vendor 0xac = 0xf002
+		 */
+		u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+		u32tmp &= ~BIT23;
+		u32tmp &= ~BIT24;
+		btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+	}
+
+	if (use_ext_switch) {
+		if (init_hw_cfg) {
+			/* 0x4c[23] = 0, 0x4c[24] = 1
+			 *	Antenna control by WL/BT
+			 */
+			u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+			u32tmp &= ~BIT23;
+			u32tmp |= BIT24;
+			btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+
+			if (board_info->btdm_ant_pos ==
+			    BTC_ANTENNA_AT_MAIN_PORT) {
+				/* Main Ant to  BT for IPS case 0x4c[23] = 1 */
+				btcoexist->btc_write_1byte_bitmask(btcoexist,
+								   0x64, 0x1,
+								   0x1);
+
+				/*tell firmware "no antenna inverse"*/
+				h2c_parameter[0] = 0;
+				h2c_parameter[1] = 1;  /*ext switch type*/
+				btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+							h2c_parameter);
+			} else {
+				/*Aux Ant to  BT for IPS case 0x4c[23] = 1 */
+				btcoexist->btc_write_1byte_bitmask(btcoexist,
+								   0x64, 0x1,
+								   0x0);
+
+				/*tell firmware "antenna inverse"*/
+				h2c_parameter[0] = 1;
+				h2c_parameter[1] = 1;  /*ext switch type*/
+				btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+							h2c_parameter);
+			}
+		}
+
+		/* fixed internal switch first*/
+		/* fixed internal switch S1->WiFi, S0->BT*/
+		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+			btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+		else/* fixed internal switch S0->WiFi, S1->BT*/
+			btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
+
+		/* ext switch setting */
+		switch (ant_pos_type) {
+		case BTC_ANT_PATH_WIFI:
+			if (board_info->btdm_ant_pos ==
+			    BTC_ANTENNA_AT_MAIN_PORT)
+				btcoexist->btc_write_1byte_bitmask(btcoexist,
+								   0x92c, 0x3,
+								   0x1);
+			else
+				btcoexist->btc_write_1byte_bitmask(btcoexist,
+								   0x92c, 0x3,
+								   0x2);
+			break;
+		case BTC_ANT_PATH_BT:
+			if (board_info->btdm_ant_pos ==
+			    BTC_ANTENNA_AT_MAIN_PORT)
+				btcoexist->btc_write_1byte_bitmask(btcoexist,
+								   0x92c, 0x3,
+								   0x2);
+			else
+				btcoexist->btc_write_1byte_bitmask(btcoexist,
+								   0x92c, 0x3,
+								   0x1);
+			break;
+		default:
+		case BTC_ANT_PATH_PTA:
+			if (board_info->btdm_ant_pos ==
+			    BTC_ANTENNA_AT_MAIN_PORT)
+				btcoexist->btc_write_1byte_bitmask(btcoexist,
+								   0x92c, 0x3,
+								   0x1);
+			else
+				btcoexist->btc_write_1byte_bitmask(btcoexist,
+								   0x92c, 0x3,
+								   0x2);
+			break;
+		}
+
+	} else {
+		if (init_hw_cfg) {
+			/* 0x4c[23] = 1, 0x4c[24] = 0  Antenna control by 0x64*/
+			u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+			u32tmp |= BIT23;
+			u32tmp &= ~BIT24;
+			btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+
+			if (board_info->btdm_ant_pos ==
+			    BTC_ANTENNA_AT_MAIN_PORT) {
+				/*Main Ant to  WiFi for IPS case 0x4c[23] = 1*/
+				btcoexist->btc_write_1byte_bitmask(btcoexist,
+								   0x64, 0x1,
+								   0x0);
+
+				/*tell firmware "no antenna inverse"*/
+				h2c_parameter[0] = 0;
+				h2c_parameter[1] = 0;  /*internal switch type*/
+				btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+							h2c_parameter);
+			} else {
+				/*Aux Ant to  BT for IPS case 0x4c[23] = 1*/
+				btcoexist->btc_write_1byte_bitmask(btcoexist,
+								   0x64, 0x1,
+								   0x1);
+
+				/*tell firmware "antenna inverse"*/
+				h2c_parameter[0] = 1;
+				h2c_parameter[1] = 0;  /*internal switch type*/
+				btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+							h2c_parameter);
+			}
+		}
+
+		/* fixed external switch first*/
+		/*Main->WiFi, Aux->BT*/
+		if (board_info->btdm_ant_pos ==
+			BTC_ANTENNA_AT_MAIN_PORT)
+			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+							   0x3, 0x1);
+		else/*Main->BT, Aux->WiFi */
+			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+							   0x3, 0x2);
+
+		/* internal switch setting*/
+		switch (ant_pos_type) {
+		case BTC_ANT_PATH_WIFI:
+			if (board_info->btdm_ant_pos ==
+				BTC_ANTENNA_AT_MAIN_PORT)
+				btcoexist->btc_write_2byte(btcoexist, 0x948,
+							   0x0);
+			else
+				btcoexist->btc_write_2byte(btcoexist, 0x948,
+							   0x280);
+			break;
+		case BTC_ANT_PATH_BT:
+			if (board_info->btdm_ant_pos ==
+				BTC_ANTENNA_AT_MAIN_PORT)
+				btcoexist->btc_write_2byte(btcoexist, 0x948,
+							   0x280);
+			else
+				btcoexist->btc_write_2byte(btcoexist, 0x948,
+							   0x0);
+			break;
+		default:
+		case BTC_ANT_PATH_PTA:
+			if (board_info->btdm_ant_pos ==
+				BTC_ANTENNA_AT_MAIN_PORT)
+				btcoexist->btc_write_2byte(btcoexist, 0x948,
+							   0x200);
+			else
+				btcoexist->btc_write_2byte(btcoexist, 0x948,
+							   0x80);
+			break;
+		}
+	}
+}
+
+static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist,
+				    bool force_exec, bool turn_on, u8 type)
+{
+	bool wifi_busy = false;
+	u8 rssi_adjust_val = 0;
+
+	coex_dm->cur_ps_tdma_on = turn_on;
+	coex_dm->cur_ps_tdma = type;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+	if (!force_exec) {
+		if (coex_dm->cur_ps_tdma_on)
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex], ******** TDMA(on, %d) *********\n",
+				  coex_dm->cur_ps_tdma);
+		else
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex], ******** TDMA(off, %d) ********\n",
+				  coex_dm->cur_ps_tdma);
+
+		if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+		    (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+			return;
+	}
+	if (turn_on) {
+		switch (type) {
+		default:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1a,
+						       0x1a, 0x0, 0x50);
+			break;
+		case 1:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x3a,
+						       0x03, 0x10, 0x50);
+
+			rssi_adjust_val = 11;
+			break;
+		case 2:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x2b,
+						       0x03, 0x10, 0x50);
+			rssi_adjust_val = 14;
+			break;
+		case 3:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x1d,
+						       0x1d, 0x0, 0x52);
+			break;
+		case 4:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15,
+						       0x3, 0x14, 0x0);
+			rssi_adjust_val = 17;
+			break;
+		case 5:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x15,
+						       0x3, 0x11, 0x10);
+			break;
+		case 6:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x20,
+						       0x3, 0x11, 0x13);
+			break;
+		case 7:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xc,
+						       0x5, 0x0, 0x0);
+			break;
+		case 8:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25,
+						       0x3, 0x10, 0x0);
+			break;
+		case 9:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51,  0x21,
+						       0x3, 0x10, 0x50);
+			rssi_adjust_val = 18;
+			break;
+		case 10:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa,
+						       0xa, 0x0, 0x40);
+			break;
+		case 11:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15,
+						       0x03, 0x10, 0x50);
+			rssi_adjust_val = 20;
+			break;
+		case 12:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x0a,
+						       0x0a, 0x0, 0x50);
+			break;
+		case 13:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x15,
+						       0x15, 0x0, 0x50);
+			break;
+		case 14:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x21,
+						       0x3, 0x10, 0x52);
+			break;
+		case 15:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x13, 0xa,
+						       0x3, 0x8, 0x0);
+			break;
+		case 16:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x15,
+						       0x3, 0x10, 0x0);
+			rssi_adjust_val = 18;
+			break;
+		case 18:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x93, 0x25,
+						       0x3, 0x10, 0x0);
+			rssi_adjust_val = 14;
+			break;
+		case 20:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x35,
+						       0x03, 0x11, 0x10);
+			break;
+		case 21:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25,
+						       0x03, 0x11, 0x11);
+			break;
+		case 22:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0x25,
+						       0x03, 0x11, 0x10);
+			break;
+		case 23:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25,
+						       0x3, 0x31, 0x18);
+			rssi_adjust_val = 22;
+			break;
+		case 24:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x15,
+						       0x3, 0x31, 0x18);
+			rssi_adjust_val = 22;
+			break;
+		case 25:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa,
+						       0x3, 0x31, 0x18);
+			rssi_adjust_val = 22;
+			break;
+		case 26:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0xa,
+						       0x3, 0x31, 0x18);
+			rssi_adjust_val = 22;
+			break;
+		case 27:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xe3, 0x25,
+						       0x3, 0x31, 0x98);
+			rssi_adjust_val = 22;
+			break;
+		case 28:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x69, 0x25,
+						       0x3, 0x31, 0x0);
+			break;
+		case 29:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xab, 0x1a,
+						       0x1a, 0x1, 0x10);
+			break;
+		case 30:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x51, 0x14,
+						       0x3, 0x10, 0x50);
+			break;
+		case 31:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x1a,
+						       0x1a, 0, 0x58);
+			break;
+		case 32:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x61, 0xa,
+						       0x3, 0x10, 0x0);
+			break;
+		case 33:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xa3, 0x25,
+						       0x3, 0x30, 0x90);
+			break;
+		case 34:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x53, 0x1a,
+						       0x1a, 0x0, 0x10);
+			break;
+		case 35:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x63, 0x1a,
+						       0x1a, 0x0, 0x10);
+			break;
+		case 36:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0xd3, 0x12,
+						       0x3, 0x14, 0x50);
+			break;
+		/* SoftAP only with no sta associated,BT disable ,
+		 * TDMA mode for power saving
+		 * here softap mode screen off will cost 70-80mA for phone
+		 */
+		case 40:
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x23, 0x18,
+						       0x00, 0x10, 0x24);
+			break;
+		}
+	} else {
+		switch (type) {
+		case 8: /*PTA Control */
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x8, 0x0,
+						       0x0, 0x0, 0x0);
+			halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_PTA,
+						   false, false);
+			break;
+		case 0:
+		default:  /*Software control, Antenna at BT side */
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0,
+						       0x0, 0x0, 0x0);
+			halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT,
+						   false, false);
+			break;
+		case 9:   /*Software control, Antenna at WiFi side */
+			halbtc8723b1ant_set_fw_ps_tdma(btcoexist, 0x0, 0x0,
+						       0x0, 0x0, 0x0);
+			halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_WIFI,
+						   false, false);
+			break;
+		}
+	}
+	rssi_adjust_val = 0;
+	btcoexist->btc_set(btcoexist,
+			   BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE,
+			   &rssi_adjust_val);
+
+	/* update pre state */
+	coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+	coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static bool halbtc8723b1ant_is_common_action(struct btc_coexist *btcoexist)
+{
+	bool commom = false, wifi_connected = false;
+	bool wifi_busy = false;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+			   &wifi_connected);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+	if (!wifi_connected &&
+	    BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == coex_dm->bt_status) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n");
+		halbtc8723b1ant_sw_mechanism(btcoexist, false);
+		commom = true;
+	} else if (wifi_connected &&
+		   (BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+		    coex_dm->bt_status)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi connected + BT non connected-idle!!\n");
+		halbtc8723b1ant_sw_mechanism(btcoexist, false);
+		commom = true;
+	} else if (!wifi_connected &&
+		   (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE ==
+		    coex_dm->bt_status)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n");
+		halbtc8723b1ant_sw_mechanism(btcoexist, false);
+		commom = true;
+	} else if (wifi_connected &&
+		   (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE ==
+		    coex_dm->bt_status)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi connected + BT connected-idle!!\n");
+		halbtc8723b1ant_sw_mechanism(btcoexist, false);
+		commom = true;
+	} else if (!wifi_connected &&
+		   (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE !=
+		    coex_dm->bt_status)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  ("[BTCoex], Wifi non connected-idle + BT Busy!!\n"));
+		halbtc8723b1ant_sw_mechanism(btcoexist, false);
+		commom = true;
+	} else {
+		if (wifi_busy)
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Wifi Connected-Busy + BT Busy!!\n");
+		else
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Wifi Connected-Idle + BT Busy!!\n");
+
+		commom = false;
+	}
+
+	return commom;
+}
+
+static void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist,
+					      u8 wifi_status)
+{
+	static s32 up, dn, m, n, wait_count;
+	/* 0: no change, +1: increase WiFi duration,
+	 * -1: decrease WiFi duration
+	 */
+	s32 result;
+	u8 retry_count = 0, bt_info_ext;
+	bool wifi_busy = false;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], TdmaDurationAdjustForAcl()\n");
+
+	if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY == wifi_status)
+		wifi_busy = true;
+	else
+		wifi_busy = false;
+
+	if ((BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN ==
+							 wifi_status) ||
+	    (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifi_status) ||
+	    (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifi_status)) {
+		if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 &&
+		    coex_dm->cur_ps_tdma != 3 && coex_dm->cur_ps_tdma != 9) {
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 9);
+			coex_dm->tdma_adj_type = 9;
+
+			up = 0;
+			dn = 0;
+			m = 1;
+			n = 3;
+			result = 0;
+			wait_count = 0;
+		}
+		return;
+	}
+
+	if (!coex_dm->auto_tdma_adjust) {
+		coex_dm->auto_tdma_adjust = true;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], first run TdmaDurationAdjust()!!\n");
+
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2);
+		coex_dm->tdma_adj_type = 2;
+
+		up = 0;
+		dn = 0;
+		m = 1;
+		n = 3;
+		result = 0;
+		wait_count = 0;
+	} else {
+		/*accquire the BT TRx retry count from BT_Info byte2 */
+		retry_count = coex_sta->bt_retry_cnt;
+		bt_info_ext = coex_sta->bt_info_ext;
+		result = 0;
+		wait_count++;
+		/* no retry in the last 2-second duration */
+		if (retry_count == 0) {
+			up++;
+			dn--;
+
+			if (dn <= 0)
+				dn = 0;
+
+			if (up >= n) {
+				wait_count = 0;
+				n = 3;
+				up = 0;
+				dn = 0;
+				result = 1;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_TRACE_FW_DETAIL,
+					  "[BTCoex], Increase wifi duration!!\n");
+			}
+		} else if (retry_count <= 3) {
+			up--;
+			dn++;
+
+			if (up <= 0)
+				up = 0;
+
+			if (dn == 2) {
+				if (wait_count <= 2)
+					m++;
+				else
+					m = 1;
+
+				if (m >= 20)
+					m = 20;
+
+				n = 3 * m;
+				up = 0;
+				dn = 0;
+				wait_count = 0;
+				result = -1;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_TRACE_FW_DETAIL,
+					  "[BTCoex], Decrease wifi duration for retryCounter<3!!\n");
+			}
+		} else {
+			if (wait_count == 1)
+				m++;
+			else
+				m = 1;
+
+			if (m >= 20)
+				m = 20;
+
+			n = 3 * m;
+			up = 0;
+			dn = 0;
+			wait_count = 0;
+			result = -1;
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex], Decrease wifi duration for retryCounter>3!!\n");
+		}
+
+		if (result == -1) {
+			if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) &&
+			    ((coex_dm->cur_ps_tdma == 1) ||
+			     (coex_dm->cur_ps_tdma == 2))) {
+				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 9);
+				coex_dm->tdma_adj_type = 9;
+			} else if (coex_dm->cur_ps_tdma == 1) {
+				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 9);
+				coex_dm->tdma_adj_type = 9;
+			} else if (coex_dm->cur_ps_tdma == 9) {
+				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			}
+		} else if (result == 1) {
+			if ((BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) &&
+			    ((coex_dm->cur_ps_tdma == 1) ||
+			     (coex_dm->cur_ps_tdma == 2))) {
+				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 9);
+				coex_dm->tdma_adj_type = 9;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 9);
+				coex_dm->tdma_adj_type = 9;
+			} else if (coex_dm->cur_ps_tdma == 9) {
+				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 1);
+				coex_dm->tdma_adj_type = 1;
+			}
+		} else {	  /*no change */
+			/*if busy / idle change */
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex],********* TDMA(on, %d) ********\n",
+				  coex_dm->cur_ps_tdma);
+		}
+
+		if (coex_dm->cur_ps_tdma != 1 && coex_dm->cur_ps_tdma != 2 &&
+		    coex_dm->cur_ps_tdma != 9 && coex_dm->cur_ps_tdma != 11) {
+			/* recover to previous adjust type */
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true,
+						coex_dm->tdma_adj_type);
+		}
+	}
+}
+
+static void btc8723b1ant_pstdmachkpwrsave(struct btc_coexist *btcoexist,
+					  bool new_ps_state)
+{
+	u8 lps_mode = 0x0;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode);
+
+	if (lps_mode) {	/* already under LPS state */
+		if (new_ps_state) {
+			/* keep state under LPS, do nothing. */
+		} else {
+			/* will leave LPS state, turn off psTdma first */
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 0);
+		}
+	} else {	/* NO PS state */
+		if (new_ps_state) {
+			/* will enter LPS state, turn off psTdma first */
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 0);
+		} else {
+			/* keep state under NO PS state, do nothing. */
+		}
+	}
+}
+
+static void halbtc8723b1ant_power_save_state(struct btc_coexist *btcoexist,
+					     u8 ps_type, u8 lps_val,
+					     u8 rpwm_val)
+{
+	bool low_pwr_disable = false;
+
+	switch (ps_type) {
+	case BTC_PS_WIFI_NATIVE:
+		/* recover to original 32k low power setting */
+		low_pwr_disable = false;
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+				   &low_pwr_disable);
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL);
+		break;
+	case BTC_PS_LPS_ON:
+		btc8723b1ant_pstdmachkpwrsave(btcoexist, true);
+		halbtc8723b1ant_LpsRpwm(btcoexist, NORMAL_EXEC, lps_val,
+					rpwm_val);
+		/* when coex force to enter LPS, do not enter 32k low power. */
+		low_pwr_disable = true;
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+				   &low_pwr_disable);
+		/* power save must executed before psTdma.	 */
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL);
+		break;
+	case BTC_PS_LPS_OFF:
+		btc8723b1ant_pstdmachkpwrsave(btcoexist, false);
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL);
+		break;
+	default:
+		break;
+	}
+}
+
+/***************************************************
+ *
+ *	Software Coex Mechanism start
+ *
+ ***************************************************/
+/* SCO only or SCO+PAN(HS) */
+static void halbtc8723b1ant_action_sco(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+static void halbtc8723b1ant_action_hid(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */
+static void halbtc8723b1ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8723b1ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8723b1ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+/* PAN(HS) only */
+static void halbtc8723b1ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+/*PAN(EDR)+A2DP */
+static void halbtc8723b1ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8723b1ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+/* HID+A2DP+PAN(EDR) */
+static void btc8723b1ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+static void halbtc8723b1ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_sw_mechanism(btcoexist, true);
+}
+
+/*****************************************************
+ *
+ *	Non-Software Coex Mechanism start
+ *
+ *****************************************************/
+static void halbtc8723b1ant_action_wifi_multiport(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+					 0x0, 0x0);
+
+	halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+	halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+}
+
+static void halbtc8723b1ant_action_hs(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+	halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+}
+
+static void halbtc8723b1ant_action_bt_inquiry(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	bool wifi_connected = false, ap_enable = false;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+			   &ap_enable);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+			   &wifi_connected);
+
+	if (!wifi_connected) {
+		halbtc8723b1ant_power_save_state(btcoexist,
+						 BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+	} else if (bt_link_info->sco_exist || bt_link_info->hid_only) {
+		/* SCO/HID-only busy */
+		halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+						 0x0, 0x0);
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32);
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+	} else {
+		if (ap_enable)
+			halbtc8723b1ant_power_save_state(btcoexist,
+							 BTC_PS_WIFI_NATIVE,
+							 0x0, 0x0);
+		else
+			halbtc8723b1ant_power_save_state(btcoexist,
+							 BTC_PS_LPS_ON,
+							 0x50, 0x4);
+
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30);
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+	}
+}
+
+static void btc8723b1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist,
+						  u8 wifi_status)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	bool wifi_connected = false;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+			   &wifi_connected);
+
+	/* tdma and coex table */
+
+	if (bt_link_info->sco_exist) {
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+	} else { /* HID */
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6);
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5);
+	}
+}
+
+static void halbtc8723b1ant_action_wifi_connected_bt_acl_busy(
+					struct btc_coexist *btcoexist,
+					u8 wifi_status)
+{
+	u8 bt_rssi_state;
+
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+	bt_rssi_state = halbtc8723b1ant_bt_rssi_state(2, 28, 0);
+
+	if (bt_link_info->hid_only) {  /*HID */
+		btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist, wifi_status);
+		coex_dm->auto_tdma_adjust = false;
+		return;
+	} else if (bt_link_info->a2dp_only) { /*A2DP */
+		if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) {
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 8);
+			halbtc8723b1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 2);
+			coex_dm->auto_tdma_adjust = false;
+		} else if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+			   (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8723b1ant_tdma_dur_adj_for_acl(btcoexist,
+							  wifi_status);
+			halbtc8723b1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 1);
+		} else { /*for low BT RSSI */
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			halbtc8723b1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 1);
+			coex_dm->auto_tdma_adjust = false;
+		}
+	} else if (bt_link_info->hid_exist &&
+			bt_link_info->a2dp_exist) { /*HID+A2DP */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 14);
+			coex_dm->auto_tdma_adjust = false;
+		} else { /*for low BT RSSI*/
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 14);
+			coex_dm->auto_tdma_adjust = false;
+		}
+
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6);
+	 /*PAN(OPP,FTP), HID+PAN(OPP,FTP) */
+	} else if (bt_link_info->pan_only ||
+		   (bt_link_info->hid_exist && bt_link_info->pan_exist)) {
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6);
+		coex_dm->auto_tdma_adjust = false;
+	 /*A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP)*/
+	} else if ((bt_link_info->a2dp_exist && bt_link_info->pan_exist) ||
+		   (bt_link_info->hid_exist && bt_link_info->a2dp_exist &&
+		    bt_link_info->pan_exist)) {
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+		coex_dm->auto_tdma_adjust = false;
+	} else {
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+		coex_dm->auto_tdma_adjust = false;
+	}
+}
+
+static void btc8723b1ant_action_wifi_not_conn(struct btc_coexist *btcoexist)
+{
+	/* power save state */
+	halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+					 0x0, 0x0);
+
+	/* tdma and coex table */
+	halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+	halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0);
+}
+
+static void btc8723b1ant_action_wifi_not_conn_scan(struct btc_coexist *btcoex)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoex->bt_link_info;
+
+	halbtc8723b1ant_power_save_state(btcoex, BTC_PS_WIFI_NATIVE,
+					 0x0, 0x0);
+
+	/* tdma and coex table */
+	if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+		if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) {
+			halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC,
+						true, 22);
+			halbtc8723b1ant_coex_table_with_type(btcoex,
+							     NORMAL_EXEC, 1);
+		} else if (bt_link_info->pan_only) {
+			halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC,
+						true, 20);
+			halbtc8723b1ant_coex_table_with_type(btcoex,
+							     NORMAL_EXEC, 2);
+		} else {
+			halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC,
+						true, 20);
+			halbtc8723b1ant_coex_table_with_type(btcoex,
+							     NORMAL_EXEC, 1);
+		}
+	} else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+		   (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+		    coex_dm->bt_status)){
+		btc8723b1ant_act_bt_sco_hid_only_busy(btcoex,
+				BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN);
+	} else {
+		halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 8);
+		halbtc8723b1ant_coex_table_with_type(btcoex, NORMAL_EXEC, 2);
+	}
+}
+
+static void btc8723b1ant_act_wifi_not_conn_asso_auth(struct btc_coexist *btcoex)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoex->bt_link_info;
+
+	halbtc8723b1ant_power_save_state(btcoex, BTC_PS_WIFI_NATIVE,
+					 0x0, 0x0);
+
+	if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ||
+	    (bt_link_info->sco_exist) || (bt_link_info->hid_only) ||
+	    (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) {
+		halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 8);
+		halbtc8723b1ant_coex_table_with_type(btcoex, NORMAL_EXEC, 7);
+	} else {
+		halbtc8723b1ant_ps_tdma(btcoex, NORMAL_EXEC, true, 20);
+		halbtc8723b1ant_coex_table_with_type(btcoex, NORMAL_EXEC, 1);
+	}
+}
+
+static void btc8723b1ant_action_wifi_conn_scan(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+	halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+					 0x0, 0x0);
+
+	/* tdma and coex table */
+	if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+		if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) {
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 22);
+			halbtc8723b1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 1);
+		} else if (bt_link_info->pan_only) {
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 20);
+			halbtc8723b1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 2);
+		} else {
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 20);
+			halbtc8723b1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 1);
+		}
+	} else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+		   (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+		    coex_dm->bt_status)) {
+		btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist,
+				BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN);
+	} else {
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+	}
+}
+
+static void halbtc8723b1ant_action_wifi_connected_special_packet(
+						struct btc_coexist *btcoexist)
+{
+	bool hs_connecting = false;
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting);
+
+	halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+					 0x0, 0x0);
+
+	/* tdma and coex table */
+	if ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) ||
+	    (bt_link_info->sco_exist) || (bt_link_info->hid_only) ||
+	    (bt_link_info->a2dp_only) || (bt_link_info->pan_only)) {
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7);
+	} else {
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20);
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+	}
+}
+
+static void halbtc8723b1ant_action_wifi_connected(struct btc_coexist *btcoexist)
+{
+	bool wifi_busy = false;
+	bool scan = false, link = false, roam = false;
+	bool under_4way = false, ap_enable = false;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], CoexForWifiConnect()===>\n");
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS,
+			   &under_4way);
+	if (under_4way) {
+		halbtc8723b1ant_action_wifi_connected_special_packet(btcoexist);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n");
+		return;
+	}
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+	if (scan || link || roam) {
+		if (scan)
+			btc8723b1ant_action_wifi_conn_scan(btcoexist);
+		else
+			halbtc8723b1ant_action_wifi_connected_special_packet(
+								     btcoexist);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n");
+		return;
+	}
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE,
+			   &ap_enable);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+	/* power save state */
+	if (!ap_enable &&
+	    BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status &&
+	    !btcoexist->bt_link_info.hid_only) {
+		if (!wifi_busy && btcoexist->bt_link_info.a2dp_only)
+			halbtc8723b1ant_power_save_state(btcoexist,
+							 BTC_PS_WIFI_NATIVE,
+							 0x0, 0x0);
+		else
+			halbtc8723b1ant_power_save_state(btcoexist,
+							 BTC_PS_LPS_ON,
+							 0x50, 0x4);
+	} else {
+		halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+						 0x0, 0x0);
+	}
+	/* tdma and coex table */
+	if (!wifi_busy) {
+		if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+			halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist,
+				      BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE);
+		} else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY ==
+						coex_dm->bt_status) ||
+			   (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+						coex_dm->bt_status)) {
+			btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist,
+				     BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE);
+		} else {
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 8);
+			halbtc8723b1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 2);
+		}
+	} else {
+		if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+			halbtc8723b1ant_action_wifi_connected_bt_acl_busy(btcoexist,
+				    BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY);
+		} else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY ==
+			   coex_dm->bt_status) ||
+			   (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+			    coex_dm->bt_status)) {
+			btc8723b1ant_act_bt_sco_hid_only_busy(btcoexist,
+				    BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY);
+		} else {
+			halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 8);
+			halbtc8723b1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 2);
+		}
+	}
+}
+
+static void btc8723b1ant_run_sw_coex_mech(struct btc_coexist *btcoexist)
+{
+	u8 algorithm = 0;
+
+	algorithm = halbtc8723b1ant_action_algorithm(btcoexist);
+	coex_dm->cur_algorithm = algorithm;
+
+	if (!halbtc8723b1ant_is_common_action(btcoexist)) {
+		switch (coex_dm->cur_algorithm) {
+		case BT_8723B_1ANT_COEX_ALGO_SCO:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = SCO.\n");
+			halbtc8723b1ant_action_sco(btcoexist);
+			break;
+		case BT_8723B_1ANT_COEX_ALGO_HID:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = HID.\n");
+			halbtc8723b1ant_action_hid(btcoexist);
+			break;
+		case BT_8723B_1ANT_COEX_ALGO_A2DP:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = A2DP.\n");
+			halbtc8723b1ant_action_a2dp(btcoexist);
+			break;
+		case BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = A2DP+PAN(HS).\n");
+			halbtc8723b1ant_action_a2dp_pan_hs(btcoexist);
+			break;
+		case BT_8723B_1ANT_COEX_ALGO_PANEDR:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = PAN(EDR).\n");
+			halbtc8723b1ant_action_pan_edr(btcoexist);
+			break;
+		case BT_8723B_1ANT_COEX_ALGO_PANHS:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = HS mode.\n");
+			halbtc8723b1ant_action_pan_hs(btcoexist);
+			break;
+		case BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = PAN+A2DP.\n");
+			halbtc8723b1ant_action_pan_edr_a2dp(btcoexist);
+			break;
+		case BT_8723B_1ANT_COEX_ALGO_PANEDR_HID:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = PAN(EDR)+HID.\n");
+			halbtc8723b1ant_action_pan_edr_hid(btcoexist);
+			break;
+		case BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = HID+A2DP+PAN.\n");
+			btc8723b1ant_action_hid_a2dp_pan_edr(btcoexist);
+			break;
+		case BT_8723B_1ANT_COEX_ALGO_HID_A2DP:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = HID+A2DP.\n");
+			halbtc8723b1ant_action_hid_a2dp(btcoexist);
+			break;
+		default:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = coexist All Off!!\n");
+			break;
+		}
+		coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+	}
+}
+
+static void halbtc8723b1ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	bool wifi_connected = false, bt_hs_on = false;
+	bool increase_scan_dev_num = false;
+	bool bt_ctrl_agg_buf_size = false;
+	u8 agg_buf_size = 5;
+	u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+	u32 wifi_link_status = 0;
+	u32 num_of_wifi_link = 0;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], RunCoexistMechanism()===>\n");
+
+	if (btcoexist->manual_control) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n");
+		return;
+	}
+
+	if (btcoexist->stop_coex_dm) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n");
+		return;
+	}
+
+	if (coex_sta->under_ips) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], wifi is under IPS !!!\n");
+		return;
+	}
+
+	if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+	    (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+	    (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) {
+		increase_scan_dev_num = true;
+	}
+
+	btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM,
+			   &increase_scan_dev_num);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+			   &wifi_connected);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+			   &wifi_link_status);
+	num_of_wifi_link = wifi_link_status >> 16;
+	if (num_of_wifi_link >= 2) {
+		halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+		halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+					   bt_ctrl_agg_buf_size,
+					   agg_buf_size);
+		halbtc8723b1ant_action_wifi_multiport(btcoexist);
+		return;
+	}
+
+	if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) {
+		halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+	} else {
+		if (wifi_connected) {
+			wifi_rssi_state =
+				halbtc8723b1ant_wifi_rssi_state(btcoexist,
+								1, 2, 30, 0);
+			if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+			    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+				halbtc8723b1ant_limited_tx(btcoexist,
+							   NORMAL_EXEC,
+							   1, 1, 1, 1);
+			} else {
+				halbtc8723b1ant_limited_tx(btcoexist,
+							   NORMAL_EXEC,
+							   1, 1, 1, 1);
+			}
+		} else {
+			halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC,
+						   0, 0, 0, 0);
+		}
+	}
+
+	if (bt_link_info->sco_exist) {
+		bt_ctrl_agg_buf_size = true;
+		agg_buf_size = 0x3;
+	} else if (bt_link_info->hid_exist) {
+		bt_ctrl_agg_buf_size = true;
+		agg_buf_size = 0x5;
+	} else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) {
+		bt_ctrl_agg_buf_size = true;
+		agg_buf_size = 0x8;
+	}
+	halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+				   bt_ctrl_agg_buf_size, agg_buf_size);
+
+	btc8723b1ant_run_sw_coex_mech(btcoexist);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+	if (coex_sta->c2h_bt_inquiry_page) {
+		halbtc8723b1ant_action_bt_inquiry(btcoexist);
+		return;
+	} else if (bt_hs_on) {
+		halbtc8723b1ant_action_hs(btcoexist);
+		return;
+	}
+
+	if (!wifi_connected) {
+		bool scan = false, link = false, roam = false;
+
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], wifi is non connected-idle !!!\n");
+
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+		if (scan || link || roam) {
+			if (scan)
+				btc8723b1ant_action_wifi_not_conn_scan(
+								     btcoexist);
+			else
+				btc8723b1ant_act_wifi_not_conn_asso_auth(
+								     btcoexist);
+		} else {
+			btc8723b1ant_action_wifi_not_conn(btcoexist);
+		}
+	} else { /* wifi LPS/Busy */
+		halbtc8723b1ant_action_wifi_connected(btcoexist);
+	}
+}
+
+static void halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+	/* sw all off */
+	halbtc8723b1ant_sw_mechanism(btcoexist, false);
+
+	halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8);
+	halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0);
+}
+
+static void halbtc8723b1ant_init_hw_config(struct btc_coexist *btcoexist,
+					   bool backup)
+{
+	u32 u32tmp = 0;
+	u8 u8tmp = 0;
+	u32 cnt_bt_cal_chk = 0;
+
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+		  "[BTCoex], 1Ant Init HW Config!!\n");
+
+	if (backup) {/* backup rf 0x1e value */
+		coex_dm->backup_arfr_cnt1 =
+			btcoexist->btc_read_4byte(btcoexist, 0x430);
+		coex_dm->backup_arfr_cnt2 =
+			btcoexist->btc_read_4byte(btcoexist, 0x434);
+		coex_dm->backup_retry_limit =
+			btcoexist->btc_read_2byte(btcoexist, 0x42a);
+		coex_dm->backup_ampdu_max_time =
+			btcoexist->btc_read_1byte(btcoexist, 0x456);
+	}
+
+	/* WiFi goto standby while GNT_BT 0-->1 */
+	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x780);
+	/* BT goto standby while GNT_BT 1-->0 */
+	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x500);
+
+	btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff);
+	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3);
+	btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77);
+
+	/* BT calibration check */
+	while (cnt_bt_cal_chk <= 20) {
+		u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x49d);
+		cnt_bt_cal_chk++;
+		if (u32tmp & BIT0) {
+			BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+				  "[BTCoex], ########### BT calibration(cnt=%d) ###########\n",
+				  cnt_bt_cal_chk);
+			mdelay(50);
+		} else {
+			BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+				  "[BTCoex], ********** BT NOT calibration (cnt=%d)**********\n",
+				  cnt_bt_cal_chk);
+			break;
+		}
+	}
+
+	/* 0x790[5:0] = 0x5 */
+	u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+	u8tmp &= 0xc0;
+	u8tmp |= 0x5;
+	btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp);
+
+	/* Enable counter statistics */
+	/*0x76e[3] =1, WLAN_Act control by PTA */
+	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+	btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1);
+	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
+
+	/*Antenna config */
+	halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_PTA, true, false);
+	/* PTA parameter */
+	halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0);
+}
+
+static void halbtc8723b1ant_wifi_off_hw_cfg(struct btc_coexist *btcoexist)
+{
+	/* set wlan_act to low */
+	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4);
+}
+
+/**************************************************************
+ * work around function start with wa_halbtc8723b1ant_
+ **************************************************************/
+/**************************************************************
+ * extern function start with EXhalbtc8723b1ant_
+ **************************************************************/
+
+void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+	halbtc8723b1ant_init_hw_config(btcoexist, true);
+}
+
+void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+		  "[BTCoex], Coex Mechanism Init!!\n");
+
+	btcoexist->stop_coex_dm = false;
+
+	halbtc8723b1ant_init_coex_dm(btcoexist);
+
+	halbtc8723b1ant_query_bt_info(btcoexist);
+}
+
+void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist)
+{
+	struct btc_board_info *board_info = &btcoexist->board_info;
+	struct btc_stack_info *stack_info = &btcoexist->stack_info;
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	struct rtl_priv *rtlpriv = btcoexist->adapter;
+	u8 u8tmp[4], i, bt_info_ext, pstdmacase = 0;
+	u16 u16tmp[4];
+	u32 u32tmp[4];
+	bool roam = false, scan = false;
+	bool link = false, wifi_under_5g = false;
+	bool bt_hs_on = false, wifi_busy = false;
+	s32 wifi_rssi = 0, bt_hs_rssi = 0;
+	u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck, wifi_link_status;
+	u8 wifi_dot11_chnl, wifi_hs_chnl;
+	u32 fw_ver = 0, bt_patch_ver = 0;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n ============[BT Coexist info]============");
+
+	if (btcoexist->manual_control) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n ============[Under Manual Control]==========");
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n ==========================================");
+	}
+	if (btcoexist->stop_coex_dm) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n ============[Coex is STOPPED]============");
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n ==========================================");
+	}
+
+	if (!board_info->bt_exist) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!");
+		return;
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d",
+		   "Ant PG Num/ Ant Mech/ Ant Pos:",
+		   board_info->pg_ant_num, board_info->btdm_ant_num,
+		   board_info->btdm_ant_pos);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d",
+		   "BT stack/ hci ext ver",
+		   ((stack_info->profile_notified) ? "Yes" : "No"),
+		   stack_info->hci_version);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)",
+		   "CoexVer/ FwVer/ PatchVer",
+		   glcoex_ver_date_8723b_1ant, glcoex_ver_8723b_1ant,
+		   fw_ver, bt_patch_ver, bt_patch_ver);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
+			   &wifi_dot11_chnl);
+	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)",
+		   "Dot11 channel / HsChnl(HsMode)",
+		   wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x ",
+		   "H2C Wifi inform bt chnl Info",
+		   coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1],
+		   coex_dm->wifi_chnl_info[2]);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+	btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+		   "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ",
+		   "Wifi link/ roam/ scan", link, roam, scan);
+
+	btcoexist->btc_get(btcoexist , BTC_GET_BL_WIFI_UNDER_5G,
+			   &wifi_under_5g);
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+			   &wifi_traffic_dir);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %s/ %s ",
+		   "Wifi status", (wifi_under_5g ? "5G" : "2.4G"),
+		   ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+			(((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+		   ((!wifi_busy) ? "idle" :
+			((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+				"uplink" : "downlink")));
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+			   &wifi_link_status);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d/ %d/ %d",
+		   "sta/vwifi/hs/p2pGo/p2pGc",
+		   ((wifi_link_status & WIFI_STA_CONNECTED) ? 1 : 0),
+		   ((wifi_link_status & WIFI_AP_CONNECTED) ? 1 : 0),
+		   ((wifi_link_status & WIFI_HS_CONNECTED) ? 1 : 0),
+		   ((wifi_link_status & WIFI_P2P_GO_CONNECTED) ? 1 : 0),
+		   ((wifi_link_status & WIFI_P2P_GC_CONNECTED) ? 1 : 0));
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = [%s/ %d/ %d] ",
+		   "BT [status/ rssi/ retryCnt]",
+		   ((btcoexist->bt_info.bt_disabled) ? ("disabled") :
+		    ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") :
+		     ((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+		       coex_dm->bt_status) ?
+		      "non-connected idle" :
+		      ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE ==
+			coex_dm->bt_status) ?
+		       "connected-idle" : "busy")))),
+		     coex_sta->bt_rssi, coex_sta->bt_retry_cnt);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d / %d / %d / %d",
+		   "SCO/HID/PAN/A2DP", bt_link_info->sco_exist,
+		   bt_link_info->hid_exist, bt_link_info->pan_exist,
+		   bt_link_info->a2dp_exist);
+	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
+
+	bt_info_ext = coex_sta->bt_info_ext;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s",
+		   "BT Info A2DP rate",
+		   (bt_info_ext & BIT0) ? "Basic rate" : "EDR rate");
+
+	for (i = 0; i < BT_INFO_SRC_8723B_1ANT_MAX; i++) {
+		if (coex_sta->bt_info_c2h_cnt[i]) {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+				   "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)",
+				   GLBtInfoSrc8723b1Ant[i],
+				   coex_sta->bt_info_c2h[i][0],
+				   coex_sta->bt_info_c2h[i][1],
+				   coex_sta->bt_info_c2h[i][2],
+				   coex_sta->bt_info_c2h[i][3],
+				   coex_sta->bt_info_c2h[i][4],
+				   coex_sta->bt_info_c2h[i][5],
+				   coex_sta->bt_info_c2h[i][6],
+				   coex_sta->bt_info_c2h_cnt[i]);
+		}
+	}
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %s/%s, (0x%x/0x%x)",
+		   "PS state, IPS/LPS, (lps/rpwm)",
+		   ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+		   ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")),
+		   btcoexist->bt_info.lps_val,
+		   btcoexist->bt_info.rpwm_val);
+	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+	if (!btcoexist->manual_control) {
+		/* Sw mechanism	*/
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+			   "============[Sw mechanism]============");
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/",
+			   "SM[LowPenaltyRA]", coex_dm->cur_low_penalty_ra);
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/ %s/ %d ",
+			   "DelBA/ BtCtrlAgg/ AggSize",
+			   (btcoexist->bt_info.reject_agg_pkt ? "Yes" : "No"),
+			   (btcoexist->bt_info.bt_ctrl_buf_size ? "Yes" : "No"),
+			   btcoexist->bt_info.agg_buf_size);
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ",
+			   "Rate Mask", btcoexist->bt_info.ra_mask);
+
+		/* Fw mechanism	*/
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+			   "============[Fw mechanism]============");
+
+		pstdmacase = coex_dm->cur_ps_tdma;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
+			   "PS TDMA", coex_dm->ps_tdma_para[0],
+			   coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2],
+			   coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4],
+			   pstdmacase, coex_dm->auto_tdma_adjust);
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d ",
+			   "IgnWlanAct", coex_dm->cur_ignore_wlan_act);
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x ",
+			   "Latest error condition(should be 0)",
+			   coex_dm->error_condition);
+	}
+
+	/* Hw setting */
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+		   "============[Hw setting]============");
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+		   "backup ARFR1/ARFR2/RL/AMaxTime", coex_dm->backup_arfr_cnt1,
+		   coex_dm->backup_arfr_cnt2, coex_dm->backup_retry_limit,
+		   coex_dm->backup_ampdu_max_time);
+
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430);
+	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434);
+	u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a);
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+		   "0x430/0x434/0x42a/0x456",
+		   u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]);
+
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc);
+	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x880);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+		   "0x778/0x6cc/0x880[29:25]", u8tmp[0], u32tmp[0],
+		   (u32tmp[1] & 0x3e000000) >> 25);
+
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948);
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67);
+	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+		   "0x948/ 0x67[5] / 0x765",
+		   u32tmp[0], ((u8tmp[0] & 0x20) >> 5), u8tmp[1]);
+
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c);
+	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930);
+	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+		   "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]",
+		   u32tmp[0] & 0x3, u32tmp[1] & 0xff, u32tmp[2] & 0x3);
+
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39);
+	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+	u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+		   "0x38[11]/0x40/0x4c[24:23]/0x64[0]",
+		   ((u8tmp[0] & 0x8)>>3), u8tmp[1],
+		   ((u32tmp[0] & 0x01800000) >> 23), u8tmp[2] & 0x1);
+
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+		   "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]);
+
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+		   "0xc50(dig)/0x49c(null-drop)", u32tmp[0] & 0xff, u8tmp[0]);
+
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0);
+	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4);
+	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0xda8);
+	u32tmp[3] = btcoexist->btc_read_4byte(btcoexist, 0xcf0);
+
+	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b);
+	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c);
+
+	fa_ofdm = ((u32tmp[0] & 0xffff0000) >> 16) +
+		  ((u32tmp[1] & 0xffff0000) >> 16) +
+		   (u32tmp[1] & 0xffff) +
+		   (u32tmp[2] & 0xffff) +
+		  ((u32tmp[3] & 0xffff0000) >> 16) +
+		   (u32tmp[3] & 0xffff);
+	fa_cck = (u8tmp[0] << 8) + u8tmp[1];
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+		   "OFDM-CCA/OFDM-FA/CCK-FA",
+		   u32tmp[0] & 0xffff, fa_ofdm, fa_cck);
+
+	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+		   "0x6c0/0x6c4/0x6c8(coexTable)",
+		   u32tmp[0], u32tmp[1], u32tmp[2]);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+		   "0x770(high-pri rx/tx)", coex_sta->high_priority_rx,
+		   coex_sta->high_priority_tx);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+		   "0x774(low-pri rx/tx)", coex_sta->low_priority_rx,
+		   coex_sta->low_priority_tx);
+#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 1)
+	halbtc8723b1ant_monitor_bt_ctr(btcoexist);
+#endif
+	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	if (btcoexist->manual_control || btcoexist->stop_coex_dm)
+		return;
+
+	if (BTC_IPS_ENTER == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], IPS ENTER notify\n");
+		coex_sta->under_ips = true;
+
+		halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT,
+					   false, true);
+		/* set PTA control */
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0);
+		halbtc8723b1ant_coex_table_with_type(btcoexist,
+						     NORMAL_EXEC, 0);
+		halbtc8723b1ant_wifi_off_hw_cfg(btcoexist);
+	} else if (BTC_IPS_LEAVE == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], IPS LEAVE notify\n");
+		coex_sta->under_ips = false;
+
+		halbtc8723b1ant_init_hw_config(btcoexist, false);
+		halbtc8723b1ant_init_coex_dm(btcoexist);
+		halbtc8723b1ant_query_bt_info(btcoexist);
+	}
+}
+
+void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	if (btcoexist->manual_control || btcoexist->stop_coex_dm)
+		return;
+
+	if (BTC_LPS_ENABLE == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], LPS ENABLE notify\n");
+		coex_sta->under_lps = true;
+	} else if (BTC_LPS_DISABLE == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], LPS DISABLE notify\n");
+		coex_sta->under_lps = false;
+	}
+}
+
+void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	bool wifi_connected = false, bt_hs_on = false;
+	u32 wifi_link_status = 0;
+	u32 num_of_wifi_link = 0;
+	bool bt_ctrl_agg_buf_size = false;
+	u8 agg_buf_size = 5;
+
+	if (btcoexist->manual_control || btcoexist->stop_coex_dm ||
+	    btcoexist->bt_info.bt_disabled)
+		return;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+			   &wifi_connected);
+
+	halbtc8723b1ant_query_bt_info(btcoexist);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+			   &wifi_link_status);
+	num_of_wifi_link = wifi_link_status >> 16;
+	if (num_of_wifi_link >= 2) {
+		halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+		halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+					   bt_ctrl_agg_buf_size, agg_buf_size);
+		halbtc8723b1ant_action_wifi_multiport(btcoexist);
+		return;
+	}
+
+	if (coex_sta->c2h_bt_inquiry_page) {
+		halbtc8723b1ant_action_bt_inquiry(btcoexist);
+		return;
+	} else if (bt_hs_on) {
+		halbtc8723b1ant_action_hs(btcoexist);
+		return;
+	}
+
+	if (BTC_SCAN_START == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], SCAN START notify\n");
+		if (!wifi_connected)	/* non-connected scan */
+			btc8723b1ant_action_wifi_not_conn_scan(btcoexist);
+		else	/* wifi is connected */
+			btc8723b1ant_action_wifi_conn_scan(btcoexist);
+	} else if (BTC_SCAN_FINISH == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], SCAN FINISH notify\n");
+		if (!wifi_connected)	/* non-connected scan */
+			btc8723b1ant_action_wifi_not_conn(btcoexist);
+		else
+			halbtc8723b1ant_action_wifi_connected(btcoexist);
+	}
+}
+
+void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	bool wifi_connected = false, bt_hs_on = false;
+	u32 wifi_link_status = 0;
+	u32 num_of_wifi_link = 0;
+	bool bt_ctrl_agg_buf_size = false;
+	u8 agg_buf_size = 5;
+
+	if (btcoexist->manual_control || btcoexist->stop_coex_dm ||
+	    btcoexist->bt_info.bt_disabled)
+		return;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+			   &wifi_link_status);
+	num_of_wifi_link = wifi_link_status>>16;
+	if (num_of_wifi_link >= 2) {
+		halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+		halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+					   bt_ctrl_agg_buf_size, agg_buf_size);
+		halbtc8723b1ant_action_wifi_multiport(btcoexist);
+		return;
+	}
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+	if (coex_sta->c2h_bt_inquiry_page) {
+		halbtc8723b1ant_action_bt_inquiry(btcoexist);
+		return;
+	} else if (bt_hs_on) {
+		halbtc8723b1ant_action_hs(btcoexist);
+		return;
+	}
+
+	if (BTC_ASSOCIATE_START == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], CONNECT START notify\n");
+		btc8723b1ant_act_wifi_not_conn_asso_auth(btcoexist);
+	} else if (BTC_ASSOCIATE_FINISH == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], CONNECT FINISH notify\n");
+
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+				   &wifi_connected);
+		if (!wifi_connected) /* non-connected scan */
+			btc8723b1ant_action_wifi_not_conn(btcoexist);
+		else
+			halbtc8723b1ant_action_wifi_connected(btcoexist);
+	}
+}
+
+void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist,
+					    u8 type)
+{
+	u8 h2c_parameter[3] = {0};
+	u32 wifi_bw;
+	u8 wifiCentralChnl;
+
+	if (btcoexist->manual_control || btcoexist->stop_coex_dm ||
+	    btcoexist->bt_info.bt_disabled)
+		return;
+
+	if (BTC_MEDIA_CONNECT == type)
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], MEDIA connect notify\n");
+	else
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], MEDIA disconnect notify\n");
+
+	/* only 2.4G we need to inform bt the chnl mask */
+	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL,
+			   &wifiCentralChnl);
+
+	if ((BTC_MEDIA_CONNECT == type) &&
+	    (wifiCentralChnl <= 14)) {
+		h2c_parameter[0] = 0x0;
+		h2c_parameter[1] = wifiCentralChnl;
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+		if (BTC_WIFI_BW_HT40 == wifi_bw)
+			h2c_parameter[2] = 0x30;
+		else
+			h2c_parameter[2] = 0x20;
+	}
+
+	coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+	coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+	coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], FW write 0x66 = 0x%x\n",
+		  h2c_parameter[0] << 16 | h2c_parameter[1] << 8 |
+		  h2c_parameter[2]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist,
+					      u8 type)
+{
+	bool bt_hs_on = false;
+	u32 wifi_link_status = 0;
+	u32 num_of_wifi_link = 0;
+	bool bt_ctrl_agg_buf_size = false;
+	u8 agg_buf_size = 5;
+
+	if (btcoexist->manual_control || btcoexist->stop_coex_dm ||
+	    btcoexist->bt_info.bt_disabled)
+		return;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS,
+		&wifi_link_status);
+	num_of_wifi_link = wifi_link_status >> 16;
+	if (num_of_wifi_link >= 2) {
+		halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+		halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+					   bt_ctrl_agg_buf_size, agg_buf_size);
+		halbtc8723b1ant_action_wifi_multiport(btcoexist);
+		return;
+	}
+
+	coex_sta->special_pkt_period_cnt = 0;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+	if (coex_sta->c2h_bt_inquiry_page) {
+		halbtc8723b1ant_action_bt_inquiry(btcoexist);
+		return;
+	} else if (bt_hs_on) {
+		halbtc8723b1ant_action_hs(btcoexist);
+		return;
+	}
+
+	if (BTC_PACKET_DHCP == type ||
+	    BTC_PACKET_EAPOL == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], special Packet(%d) notify\n", type);
+		halbtc8723b1ant_action_wifi_connected_special_packet(btcoexist);
+	}
+}
+
+void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist,
+				       u8 *tmp_buf, u8 length)
+{
+	u8 bt_info = 0;
+	u8 i, rsp_source = 0;
+	bool wifi_connected = false;
+	bool bt_busy = false;
+
+	coex_sta->c2h_bt_info_req_sent = false;
+
+	rsp_source = tmp_buf[0] & 0xf;
+	if (rsp_source >= BT_INFO_SRC_8723B_1ANT_MAX)
+		rsp_source = BT_INFO_SRC_8723B_1ANT_WIFI_FW;
+	coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+		  "[BTCoex], Bt info[%d], length=%d, hex data = [",
+		  rsp_source, length);
+	for (i = 0; i < length; i++) {
+		coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
+		if (i == 1)
+			bt_info = tmp_buf[i];
+		if (i == length - 1)
+			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+				  "0x%02x]\n", tmp_buf[i]);
+		else
+			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+				  "0x%02x, ", tmp_buf[i]);
+	}
+
+	if (BT_INFO_SRC_8723B_1ANT_WIFI_FW != rsp_source) {
+		coex_sta->bt_retry_cnt =	/* [3:0] */
+			coex_sta->bt_info_c2h[rsp_source][2] & 0xf;
+
+		coex_sta->bt_rssi =
+			coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10;
+
+		coex_sta->bt_info_ext =
+			coex_sta->bt_info_c2h[rsp_source][4];
+
+		/* Here we need to resend some wifi info to BT
+		 * because bt is reset and loss of the info.
+		 */
+		if (coex_sta->bt_info_ext & BIT1) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n");
+			btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+					   &wifi_connected);
+			if (wifi_connected)
+				ex_halbtc8723b1ant_media_status_notify(btcoexist,
+							     BTC_MEDIA_CONNECT);
+			else
+				ex_halbtc8723b1ant_media_status_notify(btcoexist,
+							  BTC_MEDIA_DISCONNECT);
+		}
+
+		if (coex_sta->bt_info_ext & BIT3) {
+			if (!btcoexist->manual_control &&
+			    !btcoexist->stop_coex_dm) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT ext info bit3 check, set BT NOT ignore Wlan active!!\n");
+				halbtc8723b1ant_ignore_wlan_act(btcoexist,
+								FORCE_EXEC,
+								false);
+			}
+		} else {
+			/* BT already NOT ignore Wlan active, do nothing here.*/
+		}
+#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0)
+		if (coex_sta->bt_info_ext & BIT4) {
+			/* BT auto report already enabled, do nothing */
+		} else {
+			halbtc8723b1ant_bt_auto_report(btcoexist, FORCE_EXEC,
+						       true);
+		}
+#endif
+	}
+
+	/* check BIT2 first ==> check if bt is under inquiry or page scan */
+	if (bt_info & BT_INFO_8723B_1ANT_B_INQ_PAGE)
+		coex_sta->c2h_bt_inquiry_page = true;
+	else
+		coex_sta->c2h_bt_inquiry_page = false;
+
+	/* set link exist status */
+	if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) {
+		coex_sta->bt_link_exist = false;
+		coex_sta->pan_exist = false;
+		coex_sta->a2dp_exist = false;
+		coex_sta->hid_exist = false;
+		coex_sta->sco_exist = false;
+	} else { /* connection exists */
+		coex_sta->bt_link_exist = true;
+		if (bt_info & BT_INFO_8723B_1ANT_B_FTP)
+			coex_sta->pan_exist = true;
+		else
+			coex_sta->pan_exist = false;
+		if (bt_info & BT_INFO_8723B_1ANT_B_A2DP)
+			coex_sta->a2dp_exist = true;
+		else
+			coex_sta->a2dp_exist = false;
+		if (bt_info & BT_INFO_8723B_1ANT_B_HID)
+			coex_sta->hid_exist = true;
+		else
+			coex_sta->hid_exist = false;
+		if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO)
+			coex_sta->sco_exist = true;
+		else
+			coex_sta->sco_exist = false;
+	}
+
+	halbtc8723b1ant_update_bt_link_info(btcoexist);
+
+	if (!(bt_info&BT_INFO_8723B_1ANT_B_CONNECTION)) {
+		coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BtInfoNotify(), BT Non-Connected idle!\n");
+	/* connection exists but no busy */
+	} else if (bt_info == BT_INFO_8723B_1ANT_B_CONNECTION) {
+		coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n");
+	} else if ((bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) ||
+		(bt_info & BT_INFO_8723B_1ANT_B_SCO_BUSY)) {
+		coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_SCO_BUSY;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n");
+	} else if (bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) {
+		if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status)
+			coex_dm->auto_tdma_adjust = false;
+
+		coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_ACL_BUSY;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n");
+	} else {
+		coex_dm->bt_status =
+			BT_8723B_1ANT_BT_STATUS_MAX;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BtInfoNotify(), BT Non-Defined state!!\n");
+	}
+
+	if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+	    (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+	    (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status))
+		bt_busy = true;
+	else
+		bt_busy = false;
+	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+	halbtc8723b1ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist)
+{
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n");
+
+	btcoexist->stop_coex_dm = true;
+
+	halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, false, true);
+
+	halbtc8723b1ant_wifi_off_hw_cfg(btcoexist);
+	halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+
+	halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+					 0x0, 0x0);
+	halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0);
+
+	ex_halbtc8723b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
+{
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Pnp notify\n");
+
+	if (BTC_WIFI_PNP_SLEEP == pnp_state) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], Pnp notify to SLEEP\n");
+		btcoexist->stop_coex_dm = true;
+		halbtc8723b1ant_SetAntPath(btcoexist, BTC_ANT_PATH_BT, false,
+					   true);
+		halbtc8723b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+						 0x0, 0x0);
+		halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0);
+		halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2);
+		halbtc8723b1ant_wifi_off_hw_cfg(btcoexist);
+	} else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], Pnp notify to WAKE UP\n");
+		btcoexist->stop_coex_dm = false;
+		halbtc8723b1ant_init_hw_config(btcoexist, false);
+		halbtc8723b1ant_init_coex_dm(btcoexist);
+		halbtc8723b1ant_query_bt_info(btcoexist);
+	}
+}
+
+void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], *****************Coex DM Reset****************\n");
+
+	halbtc8723b1ant_init_hw_config(btcoexist, false);
+	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
+	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x0);
+	halbtc8723b1ant_init_coex_dm(btcoexist);
+}
+
+void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist)
+{
+	struct btc_board_info *board_info = &btcoexist->board_info;
+	struct btc_stack_info *stack_info = &btcoexist->stack_info;
+	static u8 dis_ver_info_cnt;
+	u32 fw_ver = 0, bt_patch_ver = 0;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], ==========================Periodical===========================\n");
+
+	if (dis_ver_info_cnt <= 5) {
+		dis_ver_info_cnt += 1;
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], ****************************************************************\n");
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n",
+			  board_info->pg_ant_num, board_info->btdm_ant_num,
+			  board_info->btdm_ant_pos);
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], BT stack/ hci ext ver = %s / %d\n",
+			  ((stack_info->profile_notified) ? "Yes" : "No"),
+			  stack_info->hci_version);
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+				   &bt_patch_ver);
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
+			  glcoex_ver_date_8723b_1ant,
+			  glcoex_ver_8723b_1ant, fw_ver,
+			  bt_patch_ver, bt_patch_ver);
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], ****************************************************************\n");
+	}
+
+#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0)
+	halbtc8723b1ant_query_bt_info(btcoexist);
+	halbtc8723b1ant_monitor_bt_ctr(btcoexist);
+	halbtc8723b1ant_monitor_bt_enable_disable(btcoexist);
+#else
+	if (btc8723b1ant_is_wifi_status_changed(btcoexist) ||
+	    coex_dm->auto_tdma_adjust) {
+		halbtc8723b1ant_run_coexist_mechanism(btcoexist);
+	}
+
+	coex_sta->special_pkt_period_cnt++;
+#endif
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h
new file mode 100644
index 0000000..75f8094
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b1ant.h
@@ -0,0 +1,184 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+/**********************************************************************
+ * The following is for 8723B 1ANT BT Co-exist definition
+ **********************************************************************/
+#define	BT_AUTO_REPORT_ONLY_8723B_1ANT			1
+
+#define	BT_INFO_8723B_1ANT_B_FTP			BIT7
+#define	BT_INFO_8723B_1ANT_B_A2DP			BIT6
+#define	BT_INFO_8723B_1ANT_B_HID			BIT5
+#define	BT_INFO_8723B_1ANT_B_SCO_BUSY			BIT4
+#define	BT_INFO_8723B_1ANT_B_ACL_BUSY			BIT3
+#define	BT_INFO_8723B_1ANT_B_INQ_PAGE			BIT2
+#define	BT_INFO_8723B_1ANT_B_SCO_ESCO			BIT1
+#define	BT_INFO_8723B_1ANT_B_CONNECTION			BIT0
+
+#define	BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_)	\
+		(((_BT_INFO_EXT_&BIT0)) ? true : false)
+
+#define	BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT		2
+
+enum _BT_INFO_SRC_8723B_1ANT {
+	BT_INFO_SRC_8723B_1ANT_WIFI_FW			= 0x0,
+	BT_INFO_SRC_8723B_1ANT_BT_RSP			= 0x1,
+	BT_INFO_SRC_8723B_1ANT_BT_ACTIVE_SEND		= 0x2,
+	BT_INFO_SRC_8723B_1ANT_MAX
+};
+
+enum _BT_8723B_1ANT_BT_STATUS {
+	BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE	= 0x0,
+	BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE		= 0x1,
+	BT_8723B_1ANT_BT_STATUS_INQ_PAGE		= 0x2,
+	BT_8723B_1ANT_BT_STATUS_ACL_BUSY		= 0x3,
+	BT_8723B_1ANT_BT_STATUS_SCO_BUSY		= 0x4,
+	BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY		= 0x5,
+	BT_8723B_1ANT_BT_STATUS_MAX
+};
+
+enum _BT_8723B_1ANT_WIFI_STATUS {
+	BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE			= 0x0,
+	BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN		= 0x1,
+	BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN			= 0x2,
+	BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT			= 0x3,
+	BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE			= 0x4,
+	BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY			= 0x5,
+	BT_8723B_1ANT_WIFI_STATUS_MAX
+};
+
+enum _BT_8723B_1ANT_COEX_ALGO {
+	BT_8723B_1ANT_COEX_ALGO_UNDEFINED		= 0x0,
+	BT_8723B_1ANT_COEX_ALGO_SCO			= 0x1,
+	BT_8723B_1ANT_COEX_ALGO_HID			= 0x2,
+	BT_8723B_1ANT_COEX_ALGO_A2DP			= 0x3,
+	BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS		= 0x4,
+	BT_8723B_1ANT_COEX_ALGO_PANEDR			= 0x5,
+	BT_8723B_1ANT_COEX_ALGO_PANHS			= 0x6,
+	BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP		= 0x7,
+	BT_8723B_1ANT_COEX_ALGO_PANEDR_HID		= 0x8,
+	BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR		= 0x9,
+	BT_8723B_1ANT_COEX_ALGO_HID_A2DP		= 0xa,
+	BT_8723B_1ANT_COEX_ALGO_MAX			= 0xb,
+};
+
+struct coex_dm_8723b_1ant {
+	/* fw mechanism */
+	bool cur_ignore_wlan_act;
+	bool pre_ignore_wlan_act;
+	u8 pre_ps_tdma;
+	u8 cur_ps_tdma;
+	u8 ps_tdma_para[5];
+	u8 tdma_adj_type;
+	bool auto_tdma_adjust;
+	bool pre_ps_tdma_on;
+	bool cur_ps_tdma_on;
+	bool pre_bt_auto_report;
+	bool cur_bt_auto_report;
+	u8 pre_lps;
+	u8 cur_lps;
+	u8 pre_rpwm;
+	u8 cur_rpwm;
+
+	/* sw mechanism */
+	bool pre_low_penalty_ra;
+	bool cur_low_penalty_ra;
+	u32 pre_val0x6c0;
+	u32 cur_val0x6c0;
+	u32 pre_val0x6c4;
+	u32 cur_val0x6c4;
+	u32 pre_val0x6c8;
+	u32 cur_val0x6c8;
+	u8 pre_val0x6cc;
+	u8 cur_val0x6cc;
+	bool limited_dig;
+
+	u32 backup_arfr_cnt1;	/* Auto Rate Fallback Retry cnt */
+	u32 backup_arfr_cnt2;	/* Auto Rate Fallback Retry cnt */
+	u16 backup_retry_limit;
+	u8 backup_ampdu_max_time;
+
+	/* algorithm related */
+	u8 pre_algorithm;
+	u8 cur_algorithm;
+	u8 bt_status;
+	u8 wifi_chnl_info[3];
+
+	u32 prera_mask;
+	u32 curra_mask;
+	u8 pre_arfr_type;
+	u8 cur_arfr_type;
+	u8 pre_retry_limit_type;
+	u8 cur_retry_limit_type;
+	u8 pre_ampdu_time_type;
+	u8 cur_ampdu_time_type;
+
+	u8 error_condition;
+};
+
+struct coex_sta_8723b_1ant {
+	bool bt_link_exist;
+	bool sco_exist;
+	bool a2dp_exist;
+	bool hid_exist;
+	bool pan_exist;
+
+	bool under_lps;
+	bool under_ips;
+	u32 special_pkt_period_cnt;
+	u32 high_priority_tx;
+	u32 high_priority_rx;
+	u32 low_priority_tx;
+	u32 low_priority_rx;
+	u8 bt_rssi;
+	u8 pre_bt_rssi_state;
+	u8 pre_wifi_rssi_state[4];
+	bool c2h_bt_info_req_sent;
+	u8 bt_info_c2h[BT_INFO_SRC_8723B_1ANT_MAX][10];
+	u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_1ANT_MAX];
+	bool c2h_bt_inquiry_page;
+	u8 bt_retry_cnt;
+	u8 bt_info_ext;
+};
+
+/*************************************************************************
+ * The following is interface which will notify coex module.
+ *************************************************************************/
+void ex_halbtc8723b1ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b1ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b1ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b1ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8723b1ant_media_status_notify(struct btc_coexist *btcoexist,
+					    u8 type);
+void ex_halbtc8723b1ant_special_packet_notify(struct btc_coexist *btcoexist,
+					      u8 type);
+void ex_halbtc8723b1ant_bt_info_notify(struct btc_coexist *btcoexist,
+				       u8 *tmpbuf, u8 length);
+void ex_halbtc8723b1ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate);
+void ex_halbtc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_periodical(struct btc_coexist *btcoexist);
+void ex_halbtc8723b1ant_display_coex_info(struct btc_coexist *btcoexist);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
index d916ab9..cefe269 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.c
@@ -49,8 +49,8 @@
 	"BT Info[bt auto report]",
 };
 
-static u32 glcoex_ver_date_8723b_2ant = 20130731;
-static u32 glcoex_ver_8723b_2ant = 0x3b;
+static u32 glcoex_ver_date_8723b_2ant = 20131113;
+static u32 glcoex_ver_8723b_2ant = 0x3f;
 
 /**************************************************************
  * local function proto type if needed
@@ -303,6 +303,21 @@
 	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
 }
 
+static void btc8723b2ant_query_bt_info(struct btc_coexist *btcoexist)
+{
+	u8 h2c_parameter[1] = {0};
+
+	coex_sta->c2h_bt_info_req_sent = true;
+
+	h2c_parameter[0] |= BIT0;	/* trigger */
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+		  h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
 static bool btc8723b2ant_is_wifi_status_changed(struct btc_coexist *btcoexist)
 {
 	static bool pre_wifi_busy;
@@ -604,7 +619,7 @@
 	if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi))
 		return false;
 
-	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
 
 	if (wifi_connected) {
 		if (bt_hs_on) {
@@ -824,7 +839,6 @@
 		btc8723b2ant_set_dac_swing_reg(btcoex, 0x18);
 }
 
-
 static void btc8723b2ant_dac_swing(struct btc_coexist *btcoexist,
 				   bool force_exec, bool dac_swing_on,
 				   u32 dac_swing_lvl)
@@ -884,7 +898,6 @@
 		btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa4200001);
 	}
 
-
 	/* RF Gain */
 	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000);
 	if (agc_table_en) {
@@ -1160,8 +1173,87 @@
 			       dac_swing_lvl);
 }
 
+static void btc8723b2ant_set_ant_path(struct btc_coexist *btcoexist,
+				      u8 antpos_type, bool init_hwcfg,
+				      bool wifi_off)
+{
+	struct btc_board_info *board_info = &btcoexist->board_info;
+	u32 fw_ver = 0, u32tmp = 0;
+	bool pg_ext_switch = false;
+	bool use_ext_switch = false;
+	u8 h2c_parameter[2] = {0};
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch);
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+
+	if ((fw_ver < 0xc0000) || pg_ext_switch)
+		use_ext_switch = true;
+
+	if (init_hwcfg) {
+		/* 0x4c[23] = 0, 0x4c[24] = 1  Antenna control by WL/BT */
+		u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+		u32tmp &= ~BIT23;
+		u32tmp |= BIT24;
+		btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
+
+		btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff);
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3);
+		btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77);
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1);
+
+		/* Force GNT_BT to low */
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0);
+		btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+
+		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+			/* tell firmware "no antenna inverse" */
+			h2c_parameter[0] = 0;
+			h2c_parameter[1] = 1;  /* ext switch type */
+			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+						h2c_parameter);
+		} else {
+			/* tell firmware "antenna inverse" */
+			h2c_parameter[0] = 1;
+			h2c_parameter[1] = 1;  /* ext switch type */
+			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+						h2c_parameter);
+		}
+	}
+
+	/* ext switch setting */
+	if (use_ext_switch) {
+		/* fixed internal switch S1->WiFi, S0->BT */
+		btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+		switch (antpos_type) {
+		case BTC_ANT_WIFI_AT_MAIN:
+			/* ext switch main at wifi */
+			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
+							   0x3, 0x1);
+			break;
+		case BTC_ANT_WIFI_AT_AUX:
+			/* ext switch aux at wifi */
+			btcoexist->btc_write_1byte_bitmask(btcoexist,
+							   0x92c, 0x3, 0x2);
+			break;
+		}
+	} else {	/* internal switch */
+		/* fixed ext switch */
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1);
+		switch (antpos_type) {
+		case BTC_ANT_WIFI_AT_MAIN:
+			/* fixed internal switch S1->WiFi, S0->BT */
+			btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
+			break;
+		case BTC_ANT_WIFI_AT_AUX:
+			/* fixed internal switch S0->WiFi, S1->BT */
+			btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
+			break;
+		}
+	}
+}
+
 static void btc8723b2ant_ps_tdma(struct btc_coexist *btcoexist, bool force_exec,
-			     bool turn_on, u8 type)
+				 bool turn_on, u8 type)
 {
 	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
 		  "[BTCoex], %s turn %s PS TDMA, type=%d\n",
@@ -1351,7 +1443,8 @@
 	coex_dm->need_recover_0x948 = true;
 	coex_dm->backup_0x948 = btcoexist->btc_read_2byte(btcoexist, 0x948);
 
-	btcoexist->btc_write_2byte(btcoexist, 0x948, 0x280);
+	btc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_AUX,
+				  false, false);
 }
 
 static bool btc8723b2ant_is_common_action(struct btc_coexist *btcoexist)
@@ -1520,7 +1613,9 @@
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 					     true, 8);
 			coex_dm->tdma_adj_type = 8;
-		} else if (coex_dm->cur_ps_tdma == 9) {
+		}
+
+		if (coex_dm->cur_ps_tdma == 9) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 					     true, 13);
 			coex_dm->tdma_adj_type = 13;
@@ -1607,7 +1702,9 @@
 		} else if (coex_dm->cur_ps_tdma == 8) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
 			coex_dm->tdma_adj_type = 4;
-		} else if (coex_dm->cur_ps_tdma == 13) {
+		}
+
+		if (coex_dm->cur_ps_tdma == 13) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9);
 			coex_dm->tdma_adj_type = 9;
 		} else if (coex_dm->cur_ps_tdma == 14) {
@@ -1652,23 +1749,34 @@
 				coex_dm->tdma_adj_type = 12;
 			}
 		}  else if (result == 1) {
-			int tmp = coex_dm->cur_ps_tdma;
-			switch (tmp) {
-			case 4:
-			case 3:
-			case 2:
-			case 12:
-			case 11:
-			case 10:
+			if (coex_dm->cur_ps_tdma == 4) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
-						     true, tmp - 1);
-				coex_dm->tdma_adj_type = tmp - 1;
-				break;
-			case 1:
+						     true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						     true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						     true, 1);
+				coex_dm->tdma_adj_type = 1;
+			} else if (coex_dm->cur_ps_tdma == 1) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 71);
 				coex_dm->tdma_adj_type = 71;
-				break;
+			} else if (coex_dm->cur_ps_tdma == 12) {
+				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						     true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						     true, 10);
+				coex_dm->tdma_adj_type = 10;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						     true, 9);
+				coex_dm->tdma_adj_type = 9;
 			}
 		}
 	}
@@ -1694,7 +1802,8 @@
 		} else if (coex_dm->cur_ps_tdma == 4) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8);
 			coex_dm->tdma_adj_type = 8;
-		} else if (coex_dm->cur_ps_tdma == 9) {
+		}
+		if (coex_dm->cur_ps_tdma == 9) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14);
 			coex_dm->tdma_adj_type = 14;
 		} else if (coex_dm->cur_ps_tdma == 10) {
@@ -1776,7 +1885,8 @@
 		} else if (coex_dm->cur_ps_tdma == 8) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
 			coex_dm->tdma_adj_type = 4;
-		} else if (coex_dm->cur_ps_tdma == 13) {
+		}
+		if (coex_dm->cur_ps_tdma == 13) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10);
 			coex_dm->tdma_adj_type = 10;
 		} else if (coex_dm->cur_ps_tdma == 14) {
@@ -1865,7 +1975,8 @@
 		} else if (coex_dm->cur_ps_tdma == 4) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8);
 			coex_dm->tdma_adj_type = 8;
-		} else if (coex_dm->cur_ps_tdma == 9) {
+		}
+		if (coex_dm->cur_ps_tdma == 9) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15);
 			coex_dm->tdma_adj_type = 15;
 		} else if (coex_dm->cur_ps_tdma == 10) {
@@ -1935,101 +2046,80 @@
 		BTC_PRINT(BTC_MSG_ALGORITHM,
 			  ALGO_TRACE_FW_DETAIL,
 			  "[BTCoex], TxPause = 0\n");
-		switch (coex_dm->cur_ps_tdma) {
-		case 5:
+		if (coex_dm->cur_ps_tdma == 5) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
 			coex_dm->tdma_adj_type = 3;
-			break;
-		case 6:
+		} else if (coex_dm->cur_ps_tdma == 6) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
 			coex_dm->tdma_adj_type = 3;
-			break;
-		case 7:
+		} else if (coex_dm->cur_ps_tdma == 7) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
 			coex_dm->tdma_adj_type = 3;
-			break;
-		case 8:
+		} else if (coex_dm->cur_ps_tdma == 8) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4);
 			coex_dm->tdma_adj_type = 4;
-			break;
-		case 13:
+		}
+		if (coex_dm->cur_ps_tdma == 13) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
 			coex_dm->tdma_adj_type = 11;
-			break;
-		case 14:
+		} else if (coex_dm->cur_ps_tdma == 14) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
 			coex_dm->tdma_adj_type = 11;
-			break;
-		case 15:
+		} else if (coex_dm->cur_ps_tdma == 15) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
 			coex_dm->tdma_adj_type = 11;
-			break;
-		case 16:
+		} else if (coex_dm->cur_ps_tdma == 16) {
 			btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 12);
 			coex_dm->tdma_adj_type = 12;
-			break;
 		}
 		if (result == -1) {
-			switch (coex_dm->cur_ps_tdma) {
-			case 1:
+			if (coex_dm->cur_ps_tdma == 1) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 3);
 				coex_dm->tdma_adj_type = 3;
-				break;
-			case 2:
+			} else if (coex_dm->cur_ps_tdma == 2) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 3);
 				coex_dm->tdma_adj_type = 3;
-				break;
-			case 3:
+			} else if (coex_dm->cur_ps_tdma == 3) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 4);
 				coex_dm->tdma_adj_type = 4;
-				break;
-			case 9:
+			} else if (coex_dm->cur_ps_tdma == 9) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 11);
 				coex_dm->tdma_adj_type = 11;
-				break;
-			case 10:
+			} else if (coex_dm->cur_ps_tdma == 10) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 11);
 				coex_dm->tdma_adj_type = 11;
-				break;
-			case 11:
+			} else if (coex_dm->cur_ps_tdma == 11) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 12);
 				coex_dm->tdma_adj_type = 12;
-				break;
 			}
 		} else if (result == 1) {
-			switch (coex_dm->cur_ps_tdma) {
-			case 4:
+			if (coex_dm->cur_ps_tdma == 4) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 3);
 				coex_dm->tdma_adj_type = 3;
-				break;
-			case 3:
+			} else if (coex_dm->cur_ps_tdma == 3) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 3);
 				coex_dm->tdma_adj_type = 3;
-				break;
-			case 2:
+			} else if (coex_dm->cur_ps_tdma == 2) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 3);
 				coex_dm->tdma_adj_type = 3;
-				break;
-			case 12:
+			} else if (coex_dm->cur_ps_tdma == 12) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 11);
 				coex_dm->tdma_adj_type = 11;
-				break;
-			case 11:
+			} else if (coex_dm->cur_ps_tdma == 11) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 11);
 				coex_dm->tdma_adj_type = 11;
-				break;
-			case 10:
+			} else if (coex_dm->cur_ps_tdma == 10) {
 				btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC,
 						     true, 11);
 				coex_dm->tdma_adj_type = 11;
@@ -2328,7 +2418,7 @@
 
 	wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
 						       0, 2, 15, 0);
-	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
 
 	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
 
@@ -2385,12 +2475,43 @@
 /*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/
 static void btc8723b2ant_action_a2dp(struct btc_coexist *btcoexist)
 {
-	u8 wifi_rssi_state, bt_rssi_state;
+	u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state;
 	u32 wifi_bw;
+	u8 ap_num = 0;
 
 	wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
 						       0, 2, 15, 0);
-	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+	wifi_rssi_state1 = btc8723b2ant_wifi_rssi_state(btcoexist,
+							1, 2, 40, 0);
+	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num);
+
+	/* define the office environment */
+	/* driver don't know AP num in Linux, so we will never enter this if */
+	if (ap_num >= 10 && BTC_RSSI_HIGH(wifi_rssi_state1)) {
+		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff,
+					  0x0);
+		btc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+		btc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+		btc8723b_coex_tbl_type(btcoexist, NORMAL_EXEC, 0);
+		btc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+
+		/* sw mechanism */
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+		if (BTC_WIFI_BW_HT40 == wifi_bw) {
+			btc8723b2ant_sw_mechanism1(btcoexist, true, false,
+						   false, false);
+			btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+						   true, 0x18);
+		} else {
+			btc8723b2ant_sw_mechanism1(btcoexist, false, false,
+						   false, false);
+			btc8723b2ant_sw_mechanism2(btcoexist, true, false,
+						   true, 0x18);
+		}
+		return;
+	}
 
 	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
 
@@ -2501,7 +2622,7 @@
 
 	wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
 						       0, 2, 15, 0);
-	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
 
 	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
 
@@ -2612,7 +2733,7 @@
 
 	wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
 						       0, 2, 15, 0);
-	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
 
 	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
 
@@ -2676,7 +2797,7 @@
 
 	wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
 						       0, 2, 15, 0);
-	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
 	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
 
 	if (btc8723b_need_dec_pwr(btcoexist))
@@ -2746,7 +2867,7 @@
 
 	wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
 						       0, 2, 15, 0);
-	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
 
 	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
 
@@ -2809,8 +2930,8 @@
 	u32 wifi_bw;
 
 	wifi_rssi_state = btc8723b2ant_wifi_rssi_state(btcoexist,
-							  0, 2, 15, 0);
-	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 35, 0);
+						       0, 2, 15, 0);
+	bt_rssi_state = btc8723b2ant_bt_rssi_state(2, 29, 0);
 
 	btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0);
 
@@ -2982,7 +3103,15 @@
 	}
 }
 
-
+static void btc8723b2ant_wifioff_hwcfg(struct btc_coexist *btcoexist)
+{
+	/* set wlan_act to low */
+	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4);
+	/* Force GNT_BT to High */
+	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3);
+	/* BT select s0/s1 is controlled by BT */
+	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x0);
+}
 
 /*********************************************************************
  *  work around function start with wa_btc8723b2ant_
@@ -2990,98 +3119,24 @@
 /*********************************************************************
  *  extern function start with EXbtc8723b2ant_
  *********************************************************************/
-void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist)
 {
-	struct btc_board_info *board_info = &btcoexist->board_info;
-	u32 u32tmp = 0, fw_ver;
 	u8 u8tmp = 0;
-	u8 h2c_parameter[2] = {0};
-
 
 	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
 		  "[BTCoex], 2Ant Init HW Config!!\n");
+	coex_dm->bt_rf0x1e_backup =
+		btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff);
 
-	/* backup rf 0x1e value */
-	coex_dm->bt_rf0x1e_backup = btcoexist->btc_get_rf_reg(btcoexist,
-							      BTC_RF_A, 0x1e,
-							      0xfffff);
-
-	/* 0x4c[23]=0, 0x4c[24]=1  Antenna control by WL/BT */
-	u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
-	u32tmp &= ~BIT23;
-	u32tmp |= BIT24;
-	btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp);
-
-	btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff);
-	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3);
-	btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77);
-	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1);
-
-	/* Antenna switch control parameter */
-	/* btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555);*/
-
-	/*Force GNT_BT to low*/
-	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0);
-	btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0);
-
-	/* 0x790[5:0]=0x5 */
+	/* 0x790[5:0] = 0x5 */
 	u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
 	u8tmp &= 0xc0;
 	u8tmp |= 0x5;
 	btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp);
 
-
-	/*Antenna config	*/
-	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
-
- /*ext switch for fw ver < 0xc */
-	if (fw_ver < 0xc00) {
-		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
-			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
-							   0x3, 0x1);
-			/*Main Ant to  BT for IPS case 0x4c[23]=1*/
-			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1,
-							   0x1);
-
-			/*tell firmware "no antenna inverse"*/
-			h2c_parameter[0] = 0;
-			h2c_parameter[1] = 1;  /* ext switch type */
-			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
-						h2c_parameter);
-		} else {
-			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c,
-							   0x3, 0x2);
-			/*Aux Ant to  BT for IPS case 0x4c[23]=1*/
-			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1,
-							   0x0);
-
-			/*tell firmware "antenna inverse"*/
-			h2c_parameter[0] = 1;
-			h2c_parameter[1] = 1;  /*ext switch type*/
-			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
-						h2c_parameter);
-		}
-	} else {
-		/*ext switch always at s1 (if exist) */
-		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x92c, 0x3, 0x1);
-		/*Main Ant to  BT for IPS case 0x4c[23]=1*/
-		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, 0x1);
-
-		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
-			/*tell firmware "no antenna inverse"*/
-			h2c_parameter[0] = 0;
-			h2c_parameter[1] = 0;  /*ext switch type*/
-			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
-						h2c_parameter);
-		} else {
-			/*tell firmware "antenna inverse"*/
-			h2c_parameter[0] = 1;
-			h2c_parameter[1] = 0;  /*ext switch type*/
-			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
-						h2c_parameter);
-		}
-	}
-
+	/*Antenna config */
+	btc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN,
+				  true, false);
 	/* PTA parameter */
 	btc8723b_coex_tbl_type(btcoexist, FORCE_EXEC, 0);
 
@@ -3092,19 +3147,19 @@
 	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
 }
 
-void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist)
 {
 	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
 		  "[BTCoex], Coex Mechanism Init!!\n");
 	btc8723b2ant_init_coex_dm(btcoexist);
 }
 
-void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist)
 {
 	struct btc_board_info *board_info = &btcoexist->board_info;
 	struct btc_stack_info *stack_info = &btcoexist->stack_info;
 	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
-	u8 *cli_buf = btcoexist->cli_buf;
+	struct rtl_priv *rtlpriv = btcoexist->adapter;
 	u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0;
 	u32 u32tmp[4];
 	bool roam = false, scan = false;
@@ -3114,106 +3169,93 @@
 	u32 wifi_bw, wifi_traffic_dir, fa_ofdm, fa_cck;
 	u8 wifi_dot11_chnl, wifi_hs_chnl;
 	u32 fw_ver = 0, bt_patch_ver = 0;
+	u8 ap_num = 0;
 
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 		   "\r\n ============[BT Coexist info]============");
-	CL_PRINTF(cli_buf);
 
 	if (btcoexist->manual_control) {
-		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 			   "\r\n ==========[Under Manual Control]============");
-		CL_PRINTF(cli_buf);
-		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 			   "\r\n ==========================================");
-		CL_PRINTF(cli_buf);
 	}
 
 	if (!board_info->bt_exist) {
-		CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!");
-		CL_PRINTF(cli_buf);
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!");
 		return;
 	}
 
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ",
 		   "Ant PG number/ Ant mechanism:",
 		   board_info->pg_ant_num, board_info->btdm_ant_num);
-	CL_PRINTF(cli_buf);
 
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %d",
 		   "BT stack/ hci ext ver",
 		   ((stack_info->profile_notified) ? "Yes" : "No"),
 		   stack_info->hci_version);
-	CL_PRINTF(cli_buf);
 
 	btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
 	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 		   "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)",
 		   "CoexVer/ FwVer/ PatchVer",
 		   glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant,
 		   fw_ver, bt_patch_ver, bt_patch_ver);
-	CL_PRINTF(cli_buf);
 
 	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
 	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
 			   &wifi_dot11_chnl);
 	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
 
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d(%d)",
 		   "Dot11 channel / HsChnl(HsMode)",
 		   wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on);
-	CL_PRINTF(cli_buf);
 
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %02x %02x %02x ",
 		   "H2C Wifi inform bt chnl Info", coex_dm->wifi_chnl_info[0],
 		   coex_dm->wifi_chnl_info[1], coex_dm->wifi_chnl_info[2]);
-	CL_PRINTF(cli_buf);
 
 	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
 	btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
-		   "Wifi rssi/ HS rssi", wifi_rssi, bt_hs_rssi);
-	CL_PRINTF(cli_buf);
+	btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d",
+		   "Wifi rssi/ HS rssi/ AP#", wifi_rssi, bt_hs_rssi, ap_num);
 
 	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
 	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
 	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ",
 		   "Wifi link/ roam/ scan", link, roam, scan);
-	CL_PRINTF(cli_buf);
 
 	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
 	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
 	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
 	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
 			   &wifi_traffic_dir);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s / %s/ %s ",
 		   "Wifi status", (wifi_under_5g ? "5G" : "2.4G"),
 		   ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
 		   (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
 		   ((!wifi_busy) ? "idle" :
 		   ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
 		   "uplink" : "downlink")));
-	CL_PRINTF(cli_buf);
 
-	CL_PRINTF(cli_buf);
 
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d / %d / %d / %d",
 		   "SCO/HID/PAN/A2DP",
 		   bt_link_info->sco_exist, bt_link_info->hid_exist,
 		   bt_link_info->pan_exist, bt_link_info->a2dp_exist);
-	CL_PRINTF(cli_buf);
 	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
 
 	bt_info_ext = coex_sta->bt_info_ext;
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s",
 		   "BT Info A2DP rate",
 		   (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate");
-	CL_PRINTF(cli_buf);
 
 	for (i = 0; i < BT_INFO_SRC_8723B_2ANT_MAX; i++) {
 		if (coex_sta->bt_info_c2h_cnt[i]) {
-			CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 				   "\r\n %-35s = %02x %02x %02x "
 				   "%02x %02x %02x %02x(%d)",
 				   glbt_info_src_8723b_2ant[i],
@@ -3225,105 +3267,88 @@
 				   coex_sta->bt_info_c2h[i][5],
 				   coex_sta->bt_info_c2h[i][6],
 				   coex_sta->bt_info_c2h_cnt[i]);
-			CL_PRINTF(cli_buf);
 		}
 	}
 
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/%s",
 		   "PS state, IPS/LPS",
 		   ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
 		   ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")));
-	CL_PRINTF(cli_buf);
 	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
 
 	/* Sw mechanism	*/
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 		   "\r\n %-35s", "============[Sw mechanism]============");
-	CL_PRINTF(cli_buf);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d ",
 		   "SM1[ShRf/ LpRA/ LimDig]", coex_dm->cur_rf_rx_lpf_shrink,
 		   coex_dm->cur_low_penalty_ra, coex_dm->limited_dig);
-	CL_PRINTF(cli_buf);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d/ %d(0x%x) ",
 		   "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]",
 		   coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off,
 		   coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl);
-	CL_PRINTF(cli_buf);
 
 	/* Fw mechanism	*/
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
 		   "============[Fw mechanism]============");
-	CL_PRINTF(cli_buf);
 
 	ps_tdma_case = coex_dm->cur_ps_tdma;
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 		   "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
 		   "PS TDMA", coex_dm->ps_tdma_para[0],
 		   coex_dm->ps_tdma_para[1], coex_dm->ps_tdma_para[2],
 		   coex_dm->ps_tdma_para[3], coex_dm->ps_tdma_para[4],
 		   ps_tdma_case, coex_dm->auto_tdma_adjust);
-	CL_PRINTF(cli_buf);
 
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d ",
 		   "DecBtPwr/ IgnWlanAct", coex_dm->cur_dec_bt_pwr,
 		   coex_dm->cur_ignore_wlan_act);
-	CL_PRINTF(cli_buf);
 
 	/* Hw setting */
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
 		   "============[Hw setting]============");
-	CL_PRINTF(cli_buf);
 
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x",
 		   "RF-A, 0x1e initVal", coex_dm->bt_rf0x1e_backup);
-	CL_PRINTF(cli_buf);
 
 	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
 	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x880);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
 		   "0x778/0x880[29:25]", u8tmp[0],
 		   (u32tmp[0]&0x3e000000) >> 25);
-	CL_PRINTF(cli_buf);
 
 	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948);
 	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67);
 	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
 		   "0x948/ 0x67[5] / 0x765",
 		   u32tmp[0], ((u8tmp[0]&0x20) >> 5), u8tmp[1]);
-	CL_PRINTF(cli_buf);
 
 	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c);
 	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930);
 	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
 		   "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]",
 		   u32tmp[0]&0x3, u32tmp[1]&0xff, u32tmp[2]&0x3);
-	CL_PRINTF(cli_buf);
-
 
 	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39);
 	u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40);
 	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
 	u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 		   "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
 		   "0x38[11]/0x40/0x4c[24:23]/0x64[0]",
 		   ((u8tmp[0] & 0x8)>>3), u8tmp[1],
 		   ((u32tmp[0]&0x01800000)>>23), u8tmp[2]&0x1);
-	CL_PRINTF(cli_buf);
 
 	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
 	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
 		   "0x550(bcn ctrl)/0x522", u32tmp[0], u8tmp[0]);
-	CL_PRINTF(cli_buf);
 
 	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
 	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
 		   "0xc50(dig)/0x49c(null-drop)", u32tmp[0]&0xff, u8tmp[0]);
-	CL_PRINTF(cli_buf);
 
 	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0);
 	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4);
@@ -3341,29 +3366,25 @@
 		   (u32tmp[3] & 0xffff);
 	fa_cck = (u8tmp[0] << 8) + u8tmp[1];
 
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
 		   "OFDM-CCA/OFDM-FA/CCK-FA",
 		   u32tmp[0]&0xffff, fa_ofdm, fa_cck);
-	CL_PRINTF(cli_buf);
 
 	u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
 	u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
 	u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
 	u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE,
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 		   "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
 		   "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)",
 		   u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]);
-	CL_PRINTF(cli_buf);
 
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
 		   "0x770(high-pri rx/tx)",
 		   coex_sta->high_priority_rx, coex_sta->high_priority_tx);
-	CL_PRINTF(cli_buf);
-	CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d",
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
 		   "0x774(low-pri rx/tx)", coex_sta->low_priority_rx,
 		   coex_sta->low_priority_tx);
-	CL_PRINTF(cli_buf);
 #if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1)
 	btc8723b2ant_monitor_bt_ctr(btcoexist);
 #endif
@@ -3371,22 +3392,26 @@
 	BTC_DBG_DISP_COEX_STATISTICS);
 }
 
-
-void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+void ex_btc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
 {
 	if (BTC_IPS_ENTER == type) {
 		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
 			  "[BTCoex], IPS ENTER notify\n");
 		coex_sta->under_ips = true;
+		btc8723b2ant_wifioff_hwcfg(btcoexist);
+		btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
 		btc8723b2ant_coex_alloff(btcoexist);
 	} else if (BTC_IPS_LEAVE == type) {
 		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
 			  "[BTCoex], IPS LEAVE notify\n");
 		coex_sta->under_ips = false;
+		ex_btc8723b2ant_init_hwconfig(btcoexist);
+		btc8723b2ant_init_coex_dm(btcoexist);
+		btc8723b2ant_query_bt_info(btcoexist);
 	}
 }
 
-void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+void ex_btc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
 {
 	if (BTC_LPS_ENABLE == type) {
 		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
@@ -3399,7 +3424,7 @@
 	}
 }
 
-void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+void ex_btc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
 {
 	if (BTC_SCAN_START == type)
 		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
@@ -3409,7 +3434,7 @@
 			  "[BTCoex], SCAN FINISH notify\n");
 }
 
-void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+void ex_btc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
 {
 	if (BTC_ASSOCIATE_START == type)
 		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
@@ -3419,8 +3444,8 @@
 			  "[BTCoex], CONNECT FINISH notify\n");
 }
 
-void btc8723b_med_stat_notify(struct btc_coexist *btcoexist,
-					    u8 type)
+void ex_btc8723b2ant_media_status_notify(struct btc_coexist *btcoexist,
+					 u8 type)
 {
 	u8 h2c_parameter[3] = {0};
 	u32 wifi_bw;
@@ -3460,16 +3485,16 @@
 	btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
 }
 
-void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
-					      u8 type)
+void ex_btc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
+					   u8 type)
 {
 	if (type == BTC_PACKET_DHCP)
 		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
 			  "[BTCoex], DHCP Packet notify\n");
 }
 
-void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
-				       u8 *tmpbuf, u8 length)
+void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
+				    u8 *tmpbuf, u8 length)
 {
 	u8 bt_info = 0;
 	u8 i, rsp_source = 0;
@@ -3516,7 +3541,7 @@
 			coex_sta->bt_info_c2h[rsp_source][4];
 
 		/* Here we need to resend some wifi info to BT
-		 * because bt is reset and loss of the info.
+		     because bt is reset and loss of the info.
 		 */
 		if ((coex_sta->bt_info_ext & BIT1)) {
 			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
@@ -3525,11 +3550,13 @@
 			btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
 					   &wifi_connected);
 			if (wifi_connected)
-				btc8723b_med_stat_notify(btcoexist,
-							 BTC_MEDIA_CONNECT);
+				ex_btc8723b2ant_media_status_notify(
+							btcoexist,
+							BTC_MEDIA_CONNECT);
 			else
-				btc8723b_med_stat_notify(btcoexist,
-							 BTC_MEDIA_DISCONNECT);
+				ex_btc8723b2ant_media_status_notify(
+							btcoexist,
+							BTC_MEDIA_DISCONNECT);
 		}
 
 		if ((coex_sta->bt_info_ext & BIT3)) {
@@ -3564,7 +3591,7 @@
 		coex_sta->a2dp_exist = false;
 		coex_sta->hid_exist = false;
 		coex_sta->sco_exist = false;
-	} else { /*  connection exists */
+	} else { /* connection exists */
 		coex_sta->bt_link_exist = true;
 		if (bt_info & BT_INFO_8723B_2ANT_B_FTP)
 			coex_sta->pan_exist = true;
@@ -3601,7 +3628,7 @@
 		coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_SCO_BUSY;
 		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
 			  "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n");
-	} else if (bt_info & BT_INFO_8723B_2ANT_B_ACL_BUSY) {
+	} else if (bt_info&BT_INFO_8723B_2ANT_B_ACL_BUSY) {
 		coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_ACL_BUSY;
 		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
 			  "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n");
@@ -3630,26 +3657,16 @@
 	btc8723b2ant_run_coexist_mechanism(btcoexist);
 }
 
-void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist,
-					       u8 type)
-{
-	if (BTC_STACK_OP_INQ_PAGE_PAIR_START == type)
-		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
-			  "[BTCoex],StackOP Inquiry/page/pair start notify\n");
-	else if (BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type)
-		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
-			  "[BTCoex],StackOP Inquiry/page/pair finish notify\n");
-}
-
-void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist)
 {
 	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, "[BTCoex], Halt notify\n");
 
+	btc8723b2ant_wifioff_hwcfg(btcoexist);
 	btc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
-	btc8723b_med_stat_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+	ex_btc8723b2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT);
 }
 
-void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist)
+void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist)
 {
 	struct btc_board_info *board_info = &btcoexist->board_info;
 	struct btc_stack_info *stack_info = &btcoexist->stack_info;
@@ -3677,8 +3694,7 @@
 				   &bt_patch_ver);
 		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
 		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
-			  "[BTCoex], CoexVer/ FwVer/ PatchVer = "
-			  "%d_%x/ 0x%x/ 0x%x(%d)\n",
+			  "[BTCoex], CoexVer/ fw_ver/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
 			  glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant,
 			  fw_ver, bt_patch_ver, bt_patch_ver);
 		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h
index e0ad8e5..567f354 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8723b2ant.h
@@ -153,21 +153,20 @@
 /*********************************************************************
  * The following is interface which will notify coex module.
  *********************************************************************/
-void ex_halbtc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist);
-void ex_halbtc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist);
-void ex_halbtc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
-void ex_halbtc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
-void ex_halbtc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
-void ex_halbtc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
-void btc8723b_med_stat_notify(struct btc_coexist *btcoexist, u8 type);
-void ex_halbtc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
-					      u8 type);
-void ex_halbtc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
-				       u8 *tmpbuf, u8 length);
-void ex_halbtc8723b2ant_stack_operation_notify(struct btc_coexist *btcoexist,
-					       u8 type);
-void ex_halbtc8723b2ant_halt_notify(struct btc_coexist *btcoexist);
-void ex_halbtc8723b2ant_periodical(struct btc_coexist *btcoexist);
-void ex_halbtc8723b2ant_display_coex_info(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_btc8723b2ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_btc8723b2ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_btc8723b2ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_btc8723b2ant_media_status_notify(struct btc_coexist *btcoexist,
+					 u8 type);
+void ex_btc8723b2ant_special_packet_notify(struct btc_coexist *btcoexist,
+					   u8 type);
+void ex_btc8723b2ant_bt_info_notify(struct btc_coexist *btcoexist,
+				    u8 *tmpbuf, u8 length);
+void ex_btc8723b2ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_periodical(struct btc_coexist *btcoexist);
+void ex_btc8723b2ant_display_coex_info(struct btc_coexist *btcoexist);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c
new file mode 100644
index 0000000..b72e537
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.c
@@ -0,0 +1,2970 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/*============================================================
+ * Description:
+ *
+ * This file is for RTL8821A Co-exist mechanism
+ *
+ * History
+ * 2012/11/15 Cosa first check in.
+ *
+ *============================================================
+*/
+/*============================================================
+ * include files
+ *============================================================
+ */
+#include "halbt_precomp.h"
+/*============================================================
+ * Global variables, these are static variables
+ *============================================================
+ */
+static struct coex_dm_8821a_1ant glcoex_dm_8821a_1ant;
+static struct coex_dm_8821a_1ant *coex_dm = &glcoex_dm_8821a_1ant;
+static struct coex_sta_8821a_1ant glcoex_sta_8821a_1ant;
+static struct coex_sta_8821a_1ant *coex_sta = &glcoex_sta_8821a_1ant;
+
+static const char *const glbt_info_src_8821a_1ant[] = {
+	  "BT Info[wifi fw]",
+	  "BT Info[bt rsp]",
+	  "BT Info[bt auto report]",
+};
+
+static u32	glcoex_ver_date_8821a_1ant = 20130816;
+static u32	glcoex_ver_8821a_1ant = 0x41;
+
+/*============================================================
+ * local function proto type if needed
+ *
+ * local function start with halbtc8821a1ant_
+ *============================================================
+ */
+static u8 halbtc8821a1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh,
+					u8 rssi_thresh1)
+{
+	long	bt_rssi = 0;
+	u8	bt_rssi_state = coex_sta->pre_bt_rssi_state;
+
+	bt_rssi = coex_sta->bt_rssi;
+
+	if (level_num == 2) {
+		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+			if (bt_rssi >= (rssi_thresh +
+					BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+				bt_rssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to High\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at Low\n");
+			}
+		} else {
+			if (bt_rssi < rssi_thresh) {
+				bt_rssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to Low\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at High\n");
+			}
+		}
+	} else if (level_num == 3) {
+		if (rssi_thresh > rssi_thresh1) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+				  "[BTCoex], BT Rssi thresh error!!\n");
+			return coex_sta->pre_bt_rssi_state;
+		}
+
+		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+			if (bt_rssi >= (rssi_thresh +
+					BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+				bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to Medium\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at Low\n");
+			}
+		} else if ((coex_sta->pre_bt_rssi_state ==
+			   BTC_RSSI_STATE_MEDIUM) ||
+			   (coex_sta->pre_bt_rssi_state ==
+			    BTC_RSSI_STATE_STAY_MEDIUM)) {
+			if (bt_rssi >= (rssi_thresh1 +
+					BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+				bt_rssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to High\n");
+			} else if (bt_rssi < rssi_thresh) {
+				bt_rssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to Low\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at Medium\n");
+			}
+		} else {
+			if (bt_rssi < rssi_thresh1) {
+				bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to Medium\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at High\n");
+			}
+		}
+	}
+	coex_sta->pre_bt_rssi_state = bt_rssi_state;
+
+	return bt_rssi_state;
+}
+
+static u8 halbtc8821a1ant_WifiRssiState(struct btc_coexist *btcoexist,
+					u8 index, u8 level_num, u8 rssi_thresh,
+					u8 rssi_thresh1)
+{
+	long	wifi_rssi = 0;
+	u8	wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+
+	if (level_num == 2) {
+		if ((coex_sta->pre_wifi_rssi_state[index] ==
+		     BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_wifi_rssi_state[index] ==
+		     BTC_RSSI_STATE_STAY_LOW)) {
+			if (wifi_rssi >=
+			    (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+				wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to High\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at Low\n");
+			}
+		} else {
+			if (wifi_rssi < rssi_thresh) {
+				wifi_rssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to Low\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at High\n");
+			}
+		}
+	} else if (level_num == 3) {
+		if (rssi_thresh > rssi_thresh1) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+				  "[BTCoex], wifi RSSI thresh error!!\n");
+			return coex_sta->pre_wifi_rssi_state[index];
+		}
+
+		if ((coex_sta->pre_wifi_rssi_state[index] ==
+		     BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_wifi_rssi_state[index] ==
+		     BTC_RSSI_STATE_STAY_LOW)) {
+			if (wifi_rssi >=
+			    (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to Medium\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at Low\n");
+			}
+		} else if ((coex_sta->pre_wifi_rssi_state[index] ==
+			BTC_RSSI_STATE_MEDIUM) ||
+			(coex_sta->pre_wifi_rssi_state[index] ==
+			BTC_RSSI_STATE_STAY_MEDIUM)) {
+			if (wifi_rssi >=
+			    (rssi_thresh1 +
+			     BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) {
+				wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to High\n");
+			} else if (wifi_rssi < rssi_thresh) {
+				wifi_rssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to Low\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at Medium\n");
+			}
+		} else {
+			if (wifi_rssi < rssi_thresh1) {
+				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to Medium\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at High\n");
+			}
+		}
+	}
+	coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state;
+
+	return wifi_rssi_state;
+}
+
+static void halbtc8821a1ant_update_ra_mask(struct btc_coexist *btcoexist,
+					   bool force_exec, u32 dis_rate_mask)
+{
+	coex_dm->cur_ra_mask = dis_rate_mask;
+
+	if (force_exec ||
+	    (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) {
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_ra_mask,
+				   &coex_dm->cur_ra_mask);
+	}
+	coex_dm->pre_ra_mask = coex_dm->cur_ra_mask;
+}
+
+static void btc8821a1ant_auto_rate_fb_retry(struct btc_coexist *btcoexist,
+					    bool force_exec, u8 type)
+{
+	bool	wifi_under_b_mode = false;
+
+	coex_dm->cur_arfr_type = type;
+
+	if (force_exec ||
+	    (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) {
+		switch (coex_dm->cur_arfr_type) {
+		case 0:	/* normal mode*/
+			btcoexist->btc_write_4byte(btcoexist, 0x430,
+						   coex_dm->backup_arfr_cnt1);
+			btcoexist->btc_write_4byte(btcoexist, 0x434,
+						   coex_dm->backup_arfr_cnt2);
+			break;
+		case 1:
+			btcoexist->btc_get(btcoexist,
+					   BTC_GET_BL_WIFI_UNDER_B_MODE,
+					   &wifi_under_b_mode);
+			if (wifi_under_b_mode) {
+				btcoexist->btc_write_4byte(btcoexist, 0x430,
+							   0x0);
+				btcoexist->btc_write_4byte(btcoexist, 0x434,
+							   0x01010101);
+			} else {
+				btcoexist->btc_write_4byte(btcoexist, 0x430,
+							   0x0);
+				btcoexist->btc_write_4byte(btcoexist, 0x434,
+							   0x04030201);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	coex_dm->pre_arfr_type = coex_dm->cur_arfr_type;
+}
+
+static void halbtc8821a1ant_retry_limit(struct btc_coexist *btcoexist,
+					bool force_exec, u8 type)
+{
+	coex_dm->cur_retry_limit_type = type;
+
+	if (force_exec ||
+	    (coex_dm->pre_retry_limit_type != coex_dm->cur_retry_limit_type)) {
+		switch (coex_dm->cur_retry_limit_type) {
+		case 0:	/* normal mode*/
+			btcoexist->btc_write_2byte(btcoexist, 0x42a,
+						   coex_dm->backup_retry_limit);
+			break;
+		case 1:	/* retry limit = 8*/
+			btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808);
+			break;
+		default:
+			break;
+		}
+	}
+	coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type;
+}
+
+static void halbtc8821a1ant_ampdu_max_time(struct btc_coexist *btcoexist,
+					   bool force_exec, u8 type)
+{
+	coex_dm->cur_ampdu_time_type = type;
+
+	if (force_exec ||
+	    (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) {
+		switch (coex_dm->cur_ampdu_time_type) {
+		case 0:	/* normal mode*/
+			btcoexist->btc_write_1byte(btcoexist, 0x456,
+						   coex_dm->backup_ampdu_max_time);
+			break;
+		case 1:	/* AMPDU timw = 0x38 * 32us*/
+			btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38);
+			break;
+		default:
+			break;
+		}
+	}
+
+	coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type;
+}
+
+static void halbtc8821a1ant_limited_tx(struct btc_coexist *btcoexist,
+				       bool force_exec, u8 ra_mask_type,
+				       u8 arfr_type, u8 retry_limit_type,
+				       u8 ampdu_time_type)
+{
+	switch (ra_mask_type) {
+	case 0:	/* normal mode*/
+		halbtc8821a1ant_update_ra_mask(btcoexist, force_exec, 0x0);
+		break;
+	case 1:	/* disable cck 1/2*/
+		halbtc8821a1ant_update_ra_mask(btcoexist, force_exec,
+					       0x00000003);
+		break;
+	case 2:	/* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4*/
+		halbtc8821a1ant_update_ra_mask(btcoexist, force_exec,
+					       0x0001f1f7);
+		break;
+	default:
+		break;
+	}
+
+	btc8821a1ant_auto_rate_fb_retry(btcoexist, force_exec, arfr_type);
+	halbtc8821a1ant_retry_limit(btcoexist, force_exec, retry_limit_type);
+	halbtc8821a1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type);
+}
+
+static void halbtc8821a1ant_limited_rx(struct btc_coexist *btcoexist,
+				       bool force_exec, bool rej_ap_agg_pkt,
+				       bool bt_ctrl_agg_buf_size,
+				       u8 agg_buf_size)
+{
+	bool reject_rx_agg = rej_ap_agg_pkt;
+	bool bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size;
+	u8 rx_agg_size = agg_buf_size;
+
+	/*============================================*/
+	/*	Rx Aggregation related setting*/
+	/*============================================*/
+	btcoexist->btc_set(btcoexist,
+		 BTC_SET_BL_TO_REJ_AP_AGG_PKT, &reject_rx_agg);
+	/* decide BT control aggregation buf size or not*/
+	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE,
+			   &bt_ctrl_rx_agg_size);
+	/* aggregation buf size, only work when BT control Rx agg size.*/
+	btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size);
+	/* real update aggregation setting*/
+	btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL);
+}
+
+static void halbtc8821a1ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+	u32	reg_hp_tx_rx, reg_lp_tx_rx, u4_tmp;
+	u32	reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0;
+
+	reg_hp_tx_rx = 0x770;
+	reg_lp_tx_rx = 0x774;
+
+	u4_tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_tx_rx);
+	reg_hp_tx = u4_tmp & MASKLWORD;
+	reg_hp_rx = (u4_tmp & MASKHWORD)>>16;
+
+	u4_tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_tx_rx);
+	reg_lp_tx = u4_tmp & MASKLWORD;
+	reg_lp_rx = (u4_tmp & MASKHWORD)>>16;
+
+	coex_sta->high_priority_tx = reg_hp_tx;
+	coex_sta->high_priority_rx = reg_hp_rx;
+	coex_sta->low_priority_tx = reg_lp_tx;
+	coex_sta->low_priority_rx = reg_lp_rx;
+
+	/* reset counter*/
+	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static void halbtc8821a1ant_query_bt_info(struct btc_coexist *btcoexist)
+{
+	u8 h2c_parameter[1] = {0};
+
+	coex_sta->c2h_bt_info_req_sent = true;
+
+	h2c_parameter[0] |= BIT0;	/* trigger*/
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+		  h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
+static void halbtc8821a1ant_update_bt_link_info(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info	*bt_link_info = &btcoexist->bt_link_info;
+	bool	bt_hs_on = false;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+	bt_link_info->bt_link_exist = coex_sta->bt_link_exist;
+	bt_link_info->sco_exist = coex_sta->sco_exist;
+	bt_link_info->a2dp_exist = coex_sta->a2dp_exist;
+	bt_link_info->pan_exist = coex_sta->pan_exist;
+	bt_link_info->hid_exist = coex_sta->hid_exist;
+
+	/* work around for HS mode.*/
+	if (bt_hs_on) {
+		bt_link_info->pan_exist = true;
+		bt_link_info->bt_link_exist = true;
+	}
+
+	/* check if Sco only*/
+	if (bt_link_info->sco_exist &&
+	    !bt_link_info->a2dp_exist &&
+	    !bt_link_info->pan_exist &&
+	    !bt_link_info->hid_exist)
+		bt_link_info->sco_only = true;
+	else
+		bt_link_info->sco_only = false;
+
+	/* check if A2dp only*/
+	if (!bt_link_info->sco_exist &&
+	    bt_link_info->a2dp_exist &&
+	    !bt_link_info->pan_exist &&
+	    !bt_link_info->hid_exist)
+		bt_link_info->a2dp_only = true;
+	else
+		bt_link_info->a2dp_only = false;
+
+	/* check if Pan only*/
+	if (!bt_link_info->sco_exist &&
+	    !bt_link_info->a2dp_exist &&
+	    bt_link_info->pan_exist &&
+	    !bt_link_info->hid_exist)
+		bt_link_info->pan_only = true;
+	else
+		bt_link_info->pan_only = false;
+
+	/* check if Hid only*/
+	if (!bt_link_info->sco_exist &&
+	    !bt_link_info->a2dp_exist &&
+	    !bt_link_info->pan_exist &&
+	    bt_link_info->hid_exist)
+		bt_link_info->hid_only = true;
+	else
+		bt_link_info->hid_only = false;
+}
+
+static u8 halbtc8821a1ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	bool	bt_hs_on = false;
+	u8	algorithm = BT_8821A_1ANT_COEX_ALGO_UNDEFINED;
+	u8	num_of_diff_profile = 0;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+	if (!bt_link_info->bt_link_exist) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], No BT link exists!!!\n");
+		return algorithm;
+	}
+
+	if (bt_link_info->sco_exist)
+		num_of_diff_profile++;
+	if (bt_link_info->hid_exist)
+		num_of_diff_profile++;
+	if (bt_link_info->pan_exist)
+		num_of_diff_profile++;
+	if (bt_link_info->a2dp_exist)
+		num_of_diff_profile++;
+
+	if (num_of_diff_profile == 1) {
+		if (bt_link_info->sco_exist) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], BT Profile = SCO only\n");
+			algorithm = BT_8821A_1ANT_COEX_ALGO_SCO;
+		} else {
+			if (bt_link_info->hid_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT Profile = HID only\n");
+				algorithm = BT_8821A_1ANT_COEX_ALGO_HID;
+			} else if (bt_link_info->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT Profile = A2DP only\n");
+				algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP;
+			} else if (bt_link_info->pan_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = PAN(HS) only\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_PANHS;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = PAN(EDR) only\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR;
+				}
+			}
+		}
+	} else if (num_of_diff_profile == 2) {
+		if (bt_link_info->sco_exist) {
+			if (bt_link_info->hid_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT Profile = SCO + HID\n");
+				algorithm = BT_8821A_1ANT_COEX_ALGO_HID;
+			} else if (bt_link_info->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n");
+				algorithm = BT_8821A_1ANT_COEX_ALGO_SCO;
+			} else if (bt_link_info->pan_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + PAN(HS)\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_SCO;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + PAN(EDR)\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+				}
+			}
+		} else {
+			if (bt_link_info->hid_exist &&
+			    bt_link_info->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT Profile = HID + A2DP\n");
+				algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP;
+			} else if (bt_link_info->hid_exist &&
+				   bt_link_info->pan_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = HID + PAN(HS)\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = HID + PAN(EDR)\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+				}
+			} else if (bt_link_info->pan_exist &&
+				   bt_link_info->a2dp_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = A2DP + PAN(HS)\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = A2DP + PAN(EDR)\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP;
+				}
+			}
+		}
+	} else if (num_of_diff_profile == 3) {
+		if (bt_link_info->sco_exist) {
+			if (bt_link_info->hid_exist &&
+			    bt_link_info->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n");
+				algorithm = BT_8821A_1ANT_COEX_ALGO_HID;
+			} else if (bt_link_info->hid_exist &&
+				bt_link_info->pan_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+				}
+			} else if (bt_link_info->pan_exist &&
+				bt_link_info->a2dp_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_SCO;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+				}
+			}
+		} else {
+			if (bt_link_info->hid_exist &&
+			    bt_link_info->pan_exist &&
+			    bt_link_info->a2dp_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR;
+				}
+			}
+		}
+	} else if (num_of_diff_profile >= 3) {
+		if (bt_link_info->sco_exist) {
+			if (bt_link_info->hid_exist &&
+			    bt_link_info->pan_exist &&
+			    bt_link_info->a2dp_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n");
+
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n");
+					algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID;
+				}
+			}
+		}
+	}
+	return algorithm;
+}
+
+static void halbtc8821a1ant_set_bt_auto_report(struct btc_coexist *btcoexist,
+					       bool enable_auto_report)
+{
+	u8 h2c_parameter[1] = {0};
+
+	h2c_parameter[0] = 0;
+
+	if (enable_auto_report)
+		h2c_parameter[0] |= BIT0;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n",
+		  (enable_auto_report ? "Enabled!!" : "Disabled!!"),
+		   h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter);
+}
+
+static void halbtc8821a1ant_bt_auto_report(struct btc_coexist *btcoexist,
+					   bool force_exec,
+					   bool enable_auto_report)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM,
+		  ALGO_TRACE_FW, "[BTCoex], %s BT Auto report = %s\n",
+		  (force_exec ? "force to" : ""), ((enable_auto_report) ?
+		  "Enabled" : "Disabled"));
+	coex_dm->cur_bt_auto_report = enable_auto_report;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], pre_bt_auto_report = %d, cur_bt_auto_report = %d\n",
+			  coex_dm->pre_bt_auto_report,
+			  coex_dm->cur_bt_auto_report);
+
+		if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report)
+			return;
+	}
+	halbtc8821a1ant_set_bt_auto_report(btcoexist, coex_dm->cur_bt_auto_report);
+
+	coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report;
+}
+
+static void btc8821a1ant_set_sw_pen_tx_rate(struct btc_coexist *btcoexist,
+					    bool low_penalty_ra)
+{
+	u8 h2c_parameter[6] = {0};
+
+	h2c_parameter[0] = 0x6;	/* opCode, 0x6= Retry_Penalty*/
+
+	if (low_penalty_ra) {
+		h2c_parameter[1] |= BIT0;
+		/*normal rate except MCS7/6/5, OFDM54/48/36*/
+		h2c_parameter[2] = 0x00;
+		h2c_parameter[3] = 0xf7;  /*MCS7 or OFDM54*/
+		h2c_parameter[4] = 0xf8;  /*MCS6 or OFDM48*/
+		h2c_parameter[5] = 0xf9;	/*MCS5 or OFDM36*/
+	}
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], set WiFi Low-Penalty Retry: %s",
+		  (low_penalty_ra ? "ON!!" : "OFF!!"));
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter);
+}
+
+static void halbtc8821a1ant_low_penalty_ra(struct btc_coexist *btcoexist,
+					   bool force_exec, bool low_penalty_ra)
+{
+	coex_dm->cur_low_penalty_ra = low_penalty_ra;
+
+	if (!force_exec) {
+		if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra)
+			return;
+	}
+	btc8821a1ant_set_sw_pen_tx_rate(btcoexist, coex_dm->cur_low_penalty_ra);
+
+	coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra;
+}
+
+static void halbtc8821a1ant_set_coex_table(struct btc_coexist *btcoexist,
+					   u32 val0x6c0, u32 val0x6c4,
+					   u32 val0x6c8, u8 val0x6cc)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0);
+	btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4);
+	btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8);
+	btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc);
+	btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void halbtc8821a1ant_coex_table(struct btc_coexist *btcoexist,
+				       bool force_exec, u32 val0x6c0,
+				       u32 val0x6c4, u32 val0x6c8, u8 val0x6cc)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+		  "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n",
+		  (force_exec ? "force to" : ""), val0x6c0, val0x6c4,
+		  val0x6c8, val0x6cc);
+	coex_dm->cur_val_0x6c0 = val0x6c0;
+	coex_dm->cur_val_0x6c4 = val0x6c4;
+	coex_dm->cur_val_0x6c8 = val0x6c8;
+	coex_dm->cur_val_0x6cc = val0x6cc;
+
+	if (!force_exec) {
+		if ((coex_dm->pre_val_0x6c0 == coex_dm->cur_val_0x6c0) &&
+		    (coex_dm->pre_val_0x6c4 == coex_dm->cur_val_0x6c4) &&
+		    (coex_dm->pre_val_0x6c8 == coex_dm->cur_val_0x6c8) &&
+		    (coex_dm->pre_val_0x6cc == coex_dm->cur_val_0x6cc))
+			return;
+	}
+	halbtc8821a1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4,
+				       val0x6c8, val0x6cc);
+
+	coex_dm->pre_val_0x6c0 = coex_dm->cur_val_0x6c0;
+	coex_dm->pre_val_0x6c4 = coex_dm->cur_val_0x6c4;
+	coex_dm->pre_val_0x6c8 = coex_dm->cur_val_0x6c8;
+	coex_dm->pre_val_0x6cc = coex_dm->cur_val_0x6cc;
+}
+
+static void halbtc8821a1ant_coex_table_with_type(struct btc_coexist *btcoexist,
+						 bool force_exec, u8 type)
+{
+	switch (type) {
+	case 0:
+		halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x55555555,
+					   0x55555555, 0xffffff, 0x3);
+		break;
+	case 1:
+			halbtc8821a1ant_coex_table(btcoexist, force_exec,
+						   0x55555555, 0x5a5a5a5a,
+						   0xffffff, 0x3);
+			break;
+	case 2:
+		halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a,
+					   0x5a5a5a5a, 0xffffff, 0x3);
+		break;
+	case 3:
+		halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x55555555,
+					   0xaaaaaaaa, 0xffffff, 0x3);
+		break;
+	case 4:
+		halbtc8821a1ant_coex_table(btcoexist, force_exec, 0xffffffff,
+					   0xffffffff, 0xffffff, 0x3);
+		break;
+	case 5:
+		halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x5fff5fff,
+					   0x5fff5fff, 0xffffff, 0x3);
+		break;
+	case 6:
+		halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x55ff55ff,
+					   0x5a5a5a5a, 0xffffff, 0x3);
+		break;
+	case 7:
+		halbtc8821a1ant_coex_table(btcoexist, force_exec, 0x5afa5afa,
+					   0x5afa5afa, 0xffffff, 0x3);
+		break;
+	default:
+		break;
+	}
+}
+
+static void btc8821a1ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoexist,
+						bool enable)
+{
+	u8	h2c_parameter[1] = {0};
+
+	if (enable)
+		h2c_parameter[0] |= BIT0;	/* function enable*/
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
+		  h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter);
+}
+
+static void halbtc8821a1ant_ignore_wlan_act(struct btc_coexist *btcoexist,
+					    bool force_exec, bool enable)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s turn Ignore WlanAct %s\n",
+		  (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+	coex_dm->cur_ignore_wlan_act = enable;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], pre_ignore_wlan_act = %d, cur_ignore_wlan_act = %d!!\n",
+			  coex_dm->pre_ignore_wlan_act,
+			  coex_dm->cur_ignore_wlan_act);
+
+		if (coex_dm->pre_ignore_wlan_act ==
+		    coex_dm->cur_ignore_wlan_act)
+			return;
+	}
+	btc8821a1ant_set_fw_ignore_wlan_act(btcoexist, enable);
+
+	coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void halbtc8821a1ant_set_fw_pstdma(struct btc_coexist *btcoexist,
+					  u8 byte1, u8 byte2, u8 byte3,
+					  u8 byte4, u8 byte5)
+{
+	u8 h2c_parameter[5] = {0};
+
+	h2c_parameter[0] = byte1;
+	h2c_parameter[1] = byte2;
+	h2c_parameter[2] = byte3;
+	h2c_parameter[3] = byte4;
+	h2c_parameter[4] = byte5;
+
+	coex_dm->ps_tdma_para[0] = byte1;
+	coex_dm->ps_tdma_para[1] = byte2;
+	coex_dm->ps_tdma_para[2] = byte3;
+	coex_dm->ps_tdma_para[3] = byte4;
+	coex_dm->ps_tdma_para[4] = byte5;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n",
+		  h2c_parameter[0],
+		  h2c_parameter[1]<<24 |
+		  h2c_parameter[2]<<16 |
+		  h2c_parameter[3]<<8 |
+		  h2c_parameter[4]);
+	btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void halbtc8821a1ant_set_lps_rpwm(struct btc_coexist *btcoexist,
+					 u8 lps_val, u8 rpwm_val)
+{
+	u8	lps = lps_val;
+	u8	rpwm = rpwm_val;
+
+	btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps);
+	btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm);
+}
+
+static void halbtc8821a1ant_lps_rpwm(struct btc_coexist *btcoexist,
+				     bool force_exec, u8 lps_val, u8 rpwm_val)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s set lps/rpwm = 0x%x/0x%x\n",
+		  (force_exec ? "force to" : ""), lps_val, rpwm_val);
+	coex_dm->cur_lps = lps_val;
+	coex_dm->cur_rpwm = rpwm_val;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], LPS-RxBeaconMode = 0x%x, LPS-RPWM = 0x%x!!\n",
+			  coex_dm->cur_lps, coex_dm->cur_rpwm);
+
+		if ((coex_dm->pre_lps == coex_dm->cur_lps) &&
+		    (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex], LPS-RPWM_Last = 0x%x, LPS-RPWM_Now = 0x%x!!\n",
+				  coex_dm->pre_rpwm, coex_dm->cur_rpwm);
+
+			return;
+		}
+	}
+	halbtc8821a1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val);
+
+	coex_dm->pre_lps = coex_dm->cur_lps;
+	coex_dm->pre_rpwm = coex_dm->cur_rpwm;
+}
+
+static void halbtc8821a1ant_sw_mechanism(struct btc_coexist *btcoexist,
+					 bool low_penalty_ra)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+		  "[BTCoex], SM[LpRA] = %d\n", low_penalty_ra);
+
+	halbtc8821a1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra);
+}
+
+static void halbtc8821a1ant_set_ant_path(struct btc_coexist *btcoexist,
+					 u8 ant_pos_type, bool init_hw_cfg,
+					 bool wifi_off)
+{
+	struct btc_board_info *board_info = &btcoexist->board_info;
+	u32 u4_tmp = 0;
+	u8 h2c_parameter[2] = {0};
+
+	if (init_hw_cfg) {
+		/* 0x4c[23] = 0, 0x4c[24] = 1  Antenna control by WL/BT*/
+		u4_tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+		u4_tmp &= ~BIT23;
+		u4_tmp |= BIT24;
+		btcoexist->btc_write_4byte(btcoexist, 0x4c, u4_tmp);
+
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x975, 0x3, 0x3);
+		btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77);
+
+		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+			/*tell firmware "antenna inverse"  ==>
+			 * WRONG firmware antenna control code.==>need fw to fix
+			 */
+			h2c_parameter[0] = 1;
+			h2c_parameter[1] = 1;
+			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+						h2c_parameter);
+			/*Main Ant to  BT for IPS case 0x4c[23] = 1*/
+			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64,
+							   0x1, 0x1);
+		} else {
+			/*tell firmware "no antenna inverse" ==>
+			 * WRONG firmware antenna control code.==>need fw to fix
+			 */
+			h2c_parameter[0] = 0;
+			h2c_parameter[1] = 1;
+			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+						h2c_parameter);
+			/*Aux Ant to  BT for IPS case 0x4c[23] = 1*/
+			btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64,
+							   0x1, 0x0);
+		}
+	} else if (wifi_off) {
+		/* 0x4c[24:23] = 00, Set Antenna control
+		 *	by BT_RFE_CTRL	BT Vendor 0xac = 0xf002
+		 */
+		u4_tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+		u4_tmp &= ~BIT23;
+		u4_tmp &= ~BIT24;
+		btcoexist->btc_write_4byte(btcoexist, 0x4c, u4_tmp);
+	}
+
+	/* ext switch setting*/
+	switch (ant_pos_type) {
+	case BTC_ANT_PATH_WIFI:
+		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+			btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+							   0x30, 0x1);
+		else
+			btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+							   0x30, 0x2);
+		break;
+	case BTC_ANT_PATH_BT:
+		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+			btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+							   0x30, 0x2);
+		else
+			btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+							   0x30, 0x1);
+		break;
+	default:
+	case BTC_ANT_PATH_PTA:
+		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT)
+			btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+							   0x30, 0x1);
+		else
+			btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7,
+							   0x30, 0x2);
+		break;
+	}
+}
+
+static void halbtc8821a1ant_ps_tdma(struct btc_coexist *btcoexist,
+				    bool force_exec, bool turn_on, u8 type)
+{
+	u8 rssi_adjust_val = 0;
+
+	coex_dm->cur_ps_tdma_on = turn_on;
+	coex_dm->cur_ps_tdma = type;
+
+	if (!force_exec) {
+		if (coex_dm->cur_ps_tdma_on) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex], ********** TDMA(on, %d) **********\n",
+				  coex_dm->cur_ps_tdma);
+		} else {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex], ********** TDMA(off, %d) **********\n",
+				  coex_dm->cur_ps_tdma);
+		}
+		if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+		    (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+			return;
+	}
+	if (turn_on) {
+		switch (type) {
+		default:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x1a,
+						      0x1a, 0x0, 0x50);
+			break;
+		case 1:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x3a,
+						      0x03, 0x10, 0x50);
+			rssi_adjust_val = 11;
+			break;
+		case 2:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x2b,
+						      0x03, 0x10, 0x50);
+			rssi_adjust_val = 14;
+			break;
+		case 3:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x1d,
+						      0x1d, 0x0, 0x10);
+			break;
+		case 4:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x15,
+						      0x3, 0x14, 0x0);
+			rssi_adjust_val = 17;
+			break;
+		case 5:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x15,
+						      0x3, 0x11, 0x10);
+			break;
+		case 6:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa,
+						      0x3, 0x0, 0x0);
+			break;
+		case 7:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xc,
+						      0x5, 0x0, 0x0);
+			break;
+		case 8:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x25,
+						      0x3, 0x10, 0x0);
+			break;
+		case 9:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x21,
+						      0x3, 0x10, 0x50);
+			rssi_adjust_val = 18;
+			break;
+		case 10:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa,
+						      0xa, 0x0, 0x40);
+			break;
+		case 11:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x14,
+						      0x03, 0x10, 0x10);
+			rssi_adjust_val = 20;
+			break;
+		case 12:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x0a,
+						      0x0a, 0x0, 0x50);
+			break;
+		case 13:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x18,
+						      0x18, 0x0, 0x10);
+			break;
+		case 14:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x21,
+						      0x3, 0x10, 0x10);
+			break;
+		case 15:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, 0xa,
+						      0x3, 0x8, 0x0);
+			break;
+		case 16:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x15,
+						      0x3, 0x10, 0x0);
+			rssi_adjust_val = 18;
+			break;
+		case 18:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, 0x25,
+						      0x3, 0x10, 0x0);
+			rssi_adjust_val = 14;
+			break;
+		case 20:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x35,
+						      0x03, 0x11, 0x10);
+			break;
+		case 21:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x15,
+						      0x03, 0x11, 0x10);
+			break;
+		case 22:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0x25,
+						      0x03, 0x11, 0x10);
+			break;
+		case 23:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x25,
+						      0x3, 0x31, 0x18);
+			rssi_adjust_val = 22;
+			break;
+		case 24:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x15,
+						      0x3, 0x31, 0x18);
+			rssi_adjust_val = 22;
+			break;
+		case 25:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0xa,
+						      0x3, 0x31, 0x18);
+			rssi_adjust_val = 22;
+			break;
+		case 26:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0xa,
+						      0x3, 0x31, 0x18);
+			rssi_adjust_val = 22;
+			break;
+		case 27:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, 0x25,
+						      0x3, 0x31, 0x98);
+			rssi_adjust_val = 22;
+			break;
+		case 28:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x69, 0x25,
+						      0x3, 0x31, 0x0);
+			break;
+		case 29:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xab, 0x1a,
+						      0x1a, 0x1, 0x10);
+			break;
+		case 30:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, 0x14,
+						      0x3, 0x10, 0x50);
+			break;
+		case 31:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xd3, 0x1a,
+						      0x1a, 0, 0x58);
+			break;
+		case 32:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, 0xa,
+						      0x3, 0x10, 0x0);
+			break;
+		case 33:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xa3, 0x25,
+						      0x3, 0x30, 0x90);
+			break;
+		case 34:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x53, 0x1a,
+						      0x1a, 0x0, 0x10);
+			break;
+		case 35:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x63, 0x1a,
+						      0x1a, 0x0, 0x10);
+			break;
+		case 36:
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xd3, 0x12,
+						      0x3, 0x14, 0x50);
+			break;
+		}
+	} else {
+		/* disable PS tdma*/
+		switch (type) {
+		case 8: /*PTA Control*/
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x8, 0x0, 0x0,
+						      0x0, 0x0);
+			halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA,
+						     false, false);
+			break;
+		case 0:
+		default:  /*Software control, Antenna at BT side*/
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+						      0x0, 0x0);
+			halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT,
+						     false, false);
+			break;
+		case 9:   /*Software control, Antenna at WiFi side*/
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+						      0x0, 0x0);
+			halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI,
+						     false, false);
+			break;
+		case 10:	/* under 5G*/
+			halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+						      0x8, 0x0);
+			halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT,
+						     false, false);
+			break;
+		}
+	}
+	rssi_adjust_val = 0;
+	btcoexist->btc_set(btcoexist,
+		 BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssi_adjust_val);
+
+	/* update pre state*/
+	coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+	coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static bool halbtc8821a1ant_is_common_action(struct btc_coexist *btcoexist)
+{
+	bool	common = false, wifi_connected = false, wifi_busy = false;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+			   &wifi_connected);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+	if (!wifi_connected &&
+	    BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+	    coex_dm->bt_status) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n");
+		halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+		common = true;
+	} else if (wifi_connected &&
+		   (BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+		    coex_dm->bt_status)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi connected + BT non connected-idle!!\n");
+		halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+		common = true;
+	} else if (!wifi_connected &&
+		   (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE ==
+		    coex_dm->bt_status)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n");
+		halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+		common = true;
+	} else if (wifi_connected &&
+		   (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE ==
+		   coex_dm->bt_status)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi connected + BT connected-idle!!\n");
+		halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+		common = true;
+	} else if (!wifi_connected &&
+		   (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE !=
+		    coex_dm->bt_status)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi non connected-idle + BT Busy!!\n");
+		halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+		common = true;
+	} else {
+		if (wifi_busy) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Wifi Connected-Busy + BT Busy!!\n");
+		} else {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Wifi Connected-Idle + BT Busy!!\n");
+		}
+
+		common = false;
+	}
+
+	return common;
+}
+
+static void btc8821a1ant_tdma_dur_adj(struct btc_coexist *btcoexist,
+				      u8 wifi_status)
+{
+	static long		up, dn, m, n, wait_count;
+	/*0: no change, +1: increase WiFi duration, -1: decrease WiFi duration*/
+	long			result;
+	u8			retry_count = 0, bt_info_ext;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], TdmaDurationAdjustForAcl()\n");
+
+	if ((BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN ==
+	     wifi_status) ||
+	    (BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN ==
+	     wifi_status) ||
+	    (BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT ==
+	     wifi_status)) {
+		if (coex_dm->cur_ps_tdma != 1 &&
+		    coex_dm->cur_ps_tdma != 2 &&
+		    coex_dm->cur_ps_tdma != 3 &&
+		    coex_dm->cur_ps_tdma != 9) {
+			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 9);
+			coex_dm->tdma_adj_type = 9;
+
+			up = 0;
+			dn = 0;
+			m = 1;
+			n = 3;
+			result = 0;
+			wait_count = 0;
+		}
+		return;
+	}
+
+	if (!coex_dm->auto_tdma_adjust) {
+		coex_dm->auto_tdma_adjust = true;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], first run TdmaDurationAdjust()!!\n");
+
+		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2);
+		coex_dm->tdma_adj_type = 2;
+		/*============*/
+		up = 0;
+		dn = 0;
+		m = 1;
+		n = 3;
+		result = 0;
+		wait_count = 0;
+	} else {
+		/*accquire the BT TRx retry count from BT_Info byte2*/
+		retry_count = coex_sta->bt_retry_cnt;
+		bt_info_ext = coex_sta->bt_info_ext;
+		result = 0;
+		wait_count++;
+
+		if (retry_count == 0) {
+			/* no retry in the last 2-second duration*/
+			up++;
+			dn--;
+
+			if (dn <= 0)
+				dn = 0;
+
+			if (up >= n) {
+				/* if (retry count == 0) for 2*n seconds ,
+				 * make WiFi duration wider
+				 */
+				wait_count = 0;
+				n = 3;
+				up = 0;
+				dn = 0;
+				result = 1;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_TRACE_FW_DETAIL,
+					  "[BTCoex], Increase wifi duration!!\n");
+			}
+		} else if (retry_count <= 3) {
+			/* <=3 retry in the last 2-second duration*/
+			up--;
+			dn++;
+
+			if (up <= 0)
+				up = 0;
+
+			if (dn == 2) {
+				/* if retry count< 3 for 2*2 seconds,
+				 * shrink wifi duration
+				 */
+				if (wait_count <= 2)
+					m++; /* avoid bounce in two levels */
+				else
+					m = 1;
+
+				if (m >= 20) {
+					/* m max value is 20, max time is 120 s,
+					 *	recheck if adjust WiFi duration.
+					 */
+					m = 20;
+				}
+				n = 3*m;
+				up = 0;
+				dn = 0;
+				wait_count = 0;
+				result = -1;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_TRACE_FW_DETAIL,
+					  "[BTCoex], Decrease wifi duration for retryCounter<3!!\n");
+			}
+		} else {
+			/* retry count > 3, if retry count > 3 happens once,
+			 *	shrink WiFi duration
+			 */
+			if (wait_count == 1)
+				m++; /* avoid bounce in two levels */
+			else
+				m = 1;
+		/* m max value is 20, max time is 120 second,
+		 *	recheck if adjust WiFi duration.
+		*/
+			if (m >= 20)
+				m = 20;
+
+			n = 3*m;
+			up = 0;
+			dn = 0;
+			wait_count = 0;
+			result = -1;
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex], Decrease wifi duration for retryCounter>3!!\n");
+		}
+
+		if (result == -1) {
+			if ((BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) &&
+			    ((coex_dm->cur_ps_tdma == 1) ||
+			     (coex_dm->cur_ps_tdma == 2))) {
+				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 9);
+				coex_dm->tdma_adj_type = 9;
+			} else if (coex_dm->cur_ps_tdma == 1) {
+				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 9);
+				coex_dm->tdma_adj_type = 9;
+			} else if (coex_dm->cur_ps_tdma == 9) {
+				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			}
+		} else if (result == 1) {
+			if ((BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) &&
+			    ((coex_dm->cur_ps_tdma == 1) ||
+			     (coex_dm->cur_ps_tdma == 2))) {
+				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 9);
+				coex_dm->tdma_adj_type = 9;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 9);
+				coex_dm->tdma_adj_type = 9;
+			} else if (coex_dm->cur_ps_tdma == 9) {
+				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 1);
+				coex_dm->tdma_adj_type = 1;
+			}
+		} else {
+			/*no change*/
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex], ********** TDMA(on, %d) **********\n",
+				coex_dm->cur_ps_tdma);
+		}
+
+		if (coex_dm->cur_ps_tdma != 1 &&
+		    coex_dm->cur_ps_tdma != 2 &&
+		    coex_dm->cur_ps_tdma != 9 &&
+		    coex_dm->cur_ps_tdma != 11) {
+			/* recover to previous adjust type*/
+			halbtc8821a1ant_ps_tdma(btcoexist,
+						NORMAL_EXEC, true,
+						coex_dm->tdma_adj_type);
+		}
+	}
+}
+
+static void btc8821a1ant_ps_tdma_check_for_pwr_save(struct btc_coexist *btcoex,
+						    bool new_ps_state)
+{
+	u8	lps_mode = 0x0;
+
+	btcoex->btc_get(btcoex, BTC_GET_U1_LPS_MODE, &lps_mode);
+
+	if (lps_mode) {
+		/* already under LPS state*/
+		if (new_ps_state) {
+			/* keep state under LPS, do nothing.*/
+		} else {
+			/* will leave LPS state, turn off psTdma first*/
+			halbtc8821a1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 0);
+		}
+	} else {
+		/* NO PS state*/
+		if (new_ps_state) {
+			/* will enter LPS state, turn off psTdma first*/
+			halbtc8821a1ant_ps_tdma(btcoex, NORMAL_EXEC, false, 0);
+		} else {
+			/* keep state under NO PS state, do nothing.*/
+		}
+	}
+}
+
+static void halbtc8821a1ant_power_save_state(struct btc_coexist *btcoexist,
+					     u8 ps_type, u8 lps_val,
+					     u8 rpwm_val)
+{
+	bool low_pwr_disable = false;
+
+	switch (ps_type) {
+	case BTC_PS_WIFI_NATIVE:
+		/* recover to original 32k low power setting*/
+		low_pwr_disable = false;
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+				   &low_pwr_disable);
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, NULL);
+		break;
+	case BTC_PS_LPS_ON:
+		btc8821a1ant_ps_tdma_check_for_pwr_save(btcoexist,
+							true);
+		halbtc8821a1ant_lps_rpwm(btcoexist,
+					 NORMAL_EXEC, lps_val, rpwm_val);
+		/* when coex force to enter LPS, do not enter 32k low power.*/
+		low_pwr_disable = true;
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+				   &low_pwr_disable);
+		/* power save must executed before psTdma.*/
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, NULL);
+		break;
+	case BTC_PS_LPS_OFF:
+		btc8821a1ant_ps_tdma_check_for_pwr_save(btcoexist, false);
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, NULL);
+		break;
+	default:
+		break;
+	}
+}
+
+static void halbtc8821a1ant_coex_under_5g(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+					 0x0, 0x0);
+	halbtc8821a1ant_ignore_wlan_act(btcoexist, NORMAL_EXEC, true);
+
+	halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 10);
+
+	halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0);
+
+	halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+
+	halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 5);
+}
+
+static void halbtc8821a1ant_action_wifi_only(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0);
+	halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9);
+}
+
+static void btc8821a1ant_mon_bt_en_dis(struct btc_coexist *btcoexist)
+{
+	static bool	pre_bt_disabled;
+	static u32	bt_disable_cnt;
+	bool		bt_active = true, bt_disabled = false;
+
+	/* This function check if bt is disabled*/
+
+	if (coex_sta->high_priority_tx == 0 &&
+	    coex_sta->high_priority_rx == 0 &&
+	    coex_sta->low_priority_tx == 0 &&
+	    coex_sta->low_priority_rx == 0) {
+		bt_active = false;
+	}
+	if (coex_sta->high_priority_tx == 0xffff &&
+	    coex_sta->high_priority_rx == 0xffff &&
+	    coex_sta->low_priority_tx == 0xffff &&
+	    coex_sta->low_priority_rx == 0xffff) {
+		bt_active = false;
+	}
+	if (bt_active) {
+		bt_disable_cnt = 0;
+		bt_disabled = false;
+		btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+				   &bt_disabled);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+			  "[BTCoex], BT is enabled !!\n");
+	} else {
+		bt_disable_cnt++;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+			  "[BTCoex], bt all counters = 0, %d times!!\n",
+			  bt_disable_cnt);
+		if (bt_disable_cnt >= 2) {
+			bt_disabled = true;
+			btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+					   &bt_disabled);
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+				  "[BTCoex], BT is disabled !!\n");
+			halbtc8821a1ant_action_wifi_only(btcoexist);
+		}
+	}
+	if (pre_bt_disabled != bt_disabled) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+			  "[BTCoex], BT is from %s to %s!!\n",
+			(pre_bt_disabled ? "disabled" : "enabled"),
+			(bt_disabled ? "disabled" : "enabled"));
+		pre_bt_disabled = bt_disabled;
+		if (bt_disabled) {
+			btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS,
+					   NULL);
+			btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS,
+					   NULL);
+		}
+	}
+}
+
+/*=============================================*/
+/**/
+/*	Software Coex Mechanism start*/
+/**/
+/*=============================================*/
+
+/* SCO only or SCO+PAN(HS)*/
+static void halbtc8821a1ant_action_sco(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+static void halbtc8821a1ant_action_hid(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+/*A2DP only / PAN(EDR) only/ A2DP+PAN(HS)*/
+static void halbtc8821a1ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8821a1ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8821a1ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+/*PAN(HS) only*/
+static void halbtc8821a1ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+/*PAN(EDR)+A2DP*/
+static void halbtc8821a1ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_sw_mechanism(btcoexist, false);
+}
+
+static void halbtc8821a1ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+/* HID+A2DP+PAN(EDR)*/
+static void btc8821a1ant_action_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+static void halbtc8821a1ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_sw_mechanism(btcoexist, true);
+}
+
+/*=============================================*/
+/**/
+/*	Non-Software Coex Mechanism start*/
+/**/
+/*=============================================*/
+
+static void halbtc8821a1ant_action_hs(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+	halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2);
+}
+
+static void halbtc8821a1ant_action_bt_inquiry(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	bool wifi_connected = false;
+
+	btcoexist->btc_get(btcoexist,
+		 BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+
+	if (!wifi_connected) {
+		halbtc8821a1ant_power_save_state(btcoexist,
+						 BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+	} else if ((bt_link_info->sco_exist) ||
+		   (bt_link_info->hid_only)) {
+		/* SCO/HID-only busy*/
+		halbtc8821a1ant_power_save_state(btcoexist,
+						 BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32);
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+	} else {
+		halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_LPS_ON,
+						 0x50, 0x4);
+		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 30);
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+	}
+}
+
+static void btc8821a1ant_act_bt_sco_hid_only_busy(struct btc_coexist *btcoexist,
+						  u8 wifi_status) {
+	/* tdma and coex table*/
+	halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+
+	if (BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN ==
+	    wifi_status)
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+	else
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+}
+
+static void btc8821a1ant_act_wifi_con_bt_acl_busy(struct btc_coexist *btcoexist,
+						  u8 wifi_status)
+{
+	u8		bt_rssi_state;
+
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+	bt_rssi_state = halbtc8821a1ant_bt_rssi_state(2, 28, 0);
+
+	if (bt_link_info->hid_only) {
+		/*HID*/
+		btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist,
+						      wifi_status);
+		coex_dm->auto_tdma_adjust = false;
+		return;
+	} else if (bt_link_info->a2dp_only) {
+		/*A2DP*/
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a1ant_tdma_dur_adj(btcoexist, wifi_status);
+		} else {
+			/*for low BT RSSI*/
+			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			coex_dm->auto_tdma_adjust = false;
+		}
+
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+	} else if (bt_link_info->hid_exist && bt_link_info->a2dp_exist) {
+		/*HID+A2DP*/
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 14);
+			coex_dm->auto_tdma_adjust = false;
+		} else {
+			/*for low BT RSSI*/
+			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			coex_dm->auto_tdma_adjust = false;
+		}
+
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+	} else if ((bt_link_info->pan_only) ||
+		(bt_link_info->hid_exist && bt_link_info->pan_exist)) {
+		/*PAN(OPP, FTP), HID+PAN(OPP, FTP)*/
+		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+		coex_dm->auto_tdma_adjust = false;
+	} else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) ||
+		   (bt_link_info->hid_exist && bt_link_info->a2dp_exist &&
+		    bt_link_info->pan_exist)) {
+		/*A2DP+PAN(OPP, FTP), HID+A2DP+PAN(OPP, FTP)*/
+		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13);
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+		coex_dm->auto_tdma_adjust = false;
+	} else {
+		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11);
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+		coex_dm->auto_tdma_adjust = false;
+	}
+}
+
+static void halbtc8821a1ant_action_wifi_not_connected(
+	struct btc_coexist *btcoexist)
+{
+	/* power save state*/
+	halbtc8821a1ant_power_save_state(btcoexist,
+					 BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+
+	/* tdma and coex table*/
+	halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+	halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0);
+}
+
+static void btc8821a1ant_act_wifi_not_conn_scan(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_power_save_state(btcoexist,
+					 BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+
+	halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22);
+	halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+}
+
+static void halbtc8821a1ant_action_wifi_connected_scan(
+	struct btc_coexist *btcoexist) {
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+
+	/* power save state*/
+	halbtc8821a1ant_power_save_state(btcoexist,
+					 BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+
+	/* tdma and coex table*/
+	if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+		if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) {
+			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 22);
+			halbtc8821a1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 1);
+		} else {
+		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20);
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+	}
+	} else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY ==
+		    coex_dm->bt_status) ||
+		   (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+		    coex_dm->bt_status)) {
+		btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist,
+			BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN);
+	} else {
+		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20);
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+	}
+}
+
+static void btc8821a1ant_act_wifi_conn_sp_pkt(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	bool	hs_connecting = false;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_CONNECTING, &hs_connecting);
+
+	halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+					 0x0, 0x0);
+
+	/* tdma and coex table*/
+	if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+		if (bt_link_info->a2dp_exist && bt_link_info->pan_exist) {
+			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 22);
+			halbtc8821a1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 1);
+		} else {
+			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 20);
+			halbtc8821a1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 1);
+		}
+	} else {
+		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20);
+		halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1);
+	}
+}
+
+static void halbtc8821a1ant_action_wifi_connected(struct btc_coexist *btcoexist)
+{
+	bool	wifi_busy = false;
+	bool	scan = false, link = false, roam = false;
+	bool	under_4way = false;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], CoexForWifiConnect()===>\n");
+
+	btcoexist->btc_get(btcoexist,
+		 BTC_GET_BL_WIFI_4_WAY_PROGRESS, &under_4way);
+	if (under_4way) {
+		btc8821a1ant_act_wifi_conn_sp_pkt(btcoexist);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n");
+		return;
+	}
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+	if (scan || link || roam) {
+		halbtc8821a1ant_action_wifi_connected_scan(btcoexist);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n");
+		return;
+	}
+
+	/* power save state*/
+	if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY ==
+			coex_dm->bt_status && !btcoexist->bt_link_info.hid_only)
+		halbtc8821a1ant_power_save_state(btcoexist,
+						 BTC_PS_LPS_ON, 0x50, 0x4);
+	else
+		halbtc8821a1ant_power_save_state(btcoexist,
+						 BTC_PS_WIFI_NATIVE,
+						 0x0, 0x0);
+
+	/* tdma and coex table*/
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+	if (!wifi_busy) {
+		if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+			btc8821a1ant_act_wifi_con_bt_acl_busy(btcoexist,
+				BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE);
+		} else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY ==
+			    coex_dm->bt_status) ||
+			   (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+			    coex_dm->bt_status)) {
+			btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist,
+				BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE);
+		} else {
+			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 5);
+			halbtc8821a1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 2);
+		}
+	} else {
+		if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) {
+			btc8821a1ant_act_wifi_con_bt_acl_busy(btcoexist,
+				BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY);
+		} else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY ==
+			    coex_dm->bt_status) ||
+			   (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY ==
+			    coex_dm->bt_status)) {
+			btc8821a1ant_act_bt_sco_hid_only_busy(btcoexist,
+				BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY);
+		} else {
+			halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 5);
+			halbtc8821a1ant_coex_table_with_type(btcoexist,
+							     NORMAL_EXEC, 2);
+		}
+	}
+}
+
+static void btc8821a1ant_run_sw_coex_mech(struct btc_coexist *btcoexist)
+{
+	u8	algorithm = 0;
+
+	algorithm = halbtc8821a1ant_action_algorithm(btcoexist);
+	coex_dm->cur_algorithm = algorithm;
+
+	if (!halbtc8821a1ant_is_common_action(btcoexist)) {
+		switch (coex_dm->cur_algorithm) {
+		case BT_8821A_1ANT_COEX_ALGO_SCO:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = SCO.\n");
+			halbtc8821a1ant_action_sco(btcoexist);
+			break;
+		case BT_8821A_1ANT_COEX_ALGO_HID:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = HID.\n");
+			halbtc8821a1ant_action_hid(btcoexist);
+			break;
+		case BT_8821A_1ANT_COEX_ALGO_A2DP:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = A2DP.\n");
+			halbtc8821a1ant_action_a2dp(btcoexist);
+			break;
+		case BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = A2DP+PAN(HS).\n");
+			halbtc8821a1ant_action_a2dp_pan_hs(btcoexist);
+			break;
+		case BT_8821A_1ANT_COEX_ALGO_PANEDR:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = PAN(EDR).\n");
+			halbtc8821a1ant_action_pan_edr(btcoexist);
+			break;
+		case BT_8821A_1ANT_COEX_ALGO_PANHS:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = HS mode.\n");
+			halbtc8821a1ant_action_pan_hs(btcoexist);
+			break;
+		case BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = PAN+A2DP.\n");
+			halbtc8821a1ant_action_pan_edr_a2dp(btcoexist);
+			break;
+		case BT_8821A_1ANT_COEX_ALGO_PANEDR_HID:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = PAN(EDR)+HID.\n");
+			halbtc8821a1ant_action_pan_edr_hid(btcoexist);
+			break;
+		case BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = HID+A2DP+PAN.\n");
+			btc8821a1ant_action_hid_a2dp_pan_edr(btcoexist);
+			break;
+		case BT_8821A_1ANT_COEX_ALGO_HID_A2DP:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = HID+A2DP.\n");
+			halbtc8821a1ant_action_hid_a2dp(btcoexist);
+			break;
+		default:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action algorithm = coexist All Off!!\n");
+			/*halbtc8821a1ant_coex_all_off(btcoexist);*/
+			break;
+		}
+		coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+	}
+}
+
+static void halbtc8821a1ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	bool	wifi_connected = false, bt_hs_on = false;
+	bool	increase_scan_dev_num = false;
+	bool	bt_ctrl_agg_buf_size = false;
+	u8	agg_buf_size = 5;
+	u8	wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+	bool	wifi_under_5g = false;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], RunCoexistMechanism()===>\n");
+
+	if (btcoexist->manual_control) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n");
+		return;
+	}
+
+	if (btcoexist->stop_coex_dm) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n");
+		return;
+	}
+
+	if (coex_sta->under_ips) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], wifi is under IPS !!!\n");
+		return;
+	}
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+	if (wifi_under_5g) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], RunCoexistMechanism(), return for 5G <===\n");
+		halbtc8821a1ant_coex_under_5g(btcoexist);
+		return;
+	}
+
+	if ((BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+	    (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+	    (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status))
+		increase_scan_dev_num = true;
+
+	btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM,
+			   &increase_scan_dev_num);
+
+	btcoexist->btc_get(btcoexist,
+		 BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+
+	if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) {
+		halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0);
+	} else {
+		if (wifi_connected) {
+			wifi_rssi_state =
+				 halbtc8821a1ant_WifiRssiState(btcoexist, 1, 2,
+							       30, 0);
+			if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+			    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+				halbtc8821a1ant_limited_tx(btcoexist,
+							   NORMAL_EXEC, 1, 1,
+							   1, 1);
+			} else {
+				halbtc8821a1ant_limited_tx(btcoexist,
+							   NORMAL_EXEC, 1, 1,
+							   1, 1);
+			}
+		} else {
+			halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC,
+						   0, 0, 0, 0);
+		}
+	}
+
+	if (bt_link_info->sco_exist) {
+		bt_ctrl_agg_buf_size = true;
+		agg_buf_size = 0x3;
+	} else if (bt_link_info->hid_exist) {
+		bt_ctrl_agg_buf_size = true;
+		agg_buf_size = 0x5;
+	} else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) {
+		bt_ctrl_agg_buf_size = true;
+		agg_buf_size = 0x8;
+	}
+	halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false,
+				   bt_ctrl_agg_buf_size, agg_buf_size);
+
+	btc8821a1ant_run_sw_coex_mech(btcoexist);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+	if (coex_sta->c2h_bt_inquiry_page) {
+		halbtc8821a1ant_action_bt_inquiry(btcoexist);
+		return;
+	} else if (bt_hs_on) {
+		halbtc8821a1ant_action_hs(btcoexist);
+		return;
+	}
+
+	if (!wifi_connected) {
+		bool	scan = false, link = false, roam = false;
+
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], wifi is non connected-idle !!!\n");
+
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+		if (scan || link || roam)
+			btc8821a1ant_act_wifi_not_conn_scan(btcoexist);
+		else
+			halbtc8821a1ant_action_wifi_not_connected(btcoexist);
+	} else {
+		/* wifi LPS/Busy*/
+		halbtc8821a1ant_action_wifi_connected(btcoexist);
+	}
+}
+
+static void halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+	/* force to reset coex mechanism*/
+	/* sw all off*/
+	halbtc8821a1ant_sw_mechanism(btcoexist, false);
+
+	halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8);
+	halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0);
+}
+
+static void halbtc8821a1ant_init_hw_config(struct btc_coexist *btcoexist,
+					   bool back_up)
+{
+	u8	u1_tmp = 0;
+	bool	wifi_under_5g = false;
+
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+		  "[BTCoex], 1Ant Init HW Config!!\n");
+
+	if (back_up) {
+		coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist,
+								      0x430);
+		coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist,
+								      0x434);
+		coex_dm->backup_retry_limit =
+			 btcoexist->btc_read_2byte(btcoexist, 0x42a);
+		coex_dm->backup_ampdu_max_time =
+			 btcoexist->btc_read_1byte(btcoexist, 0x456);
+	}
+
+	/* 0x790[5:0] = 0x5*/
+	u1_tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+	u1_tmp &= 0xc0;
+	u1_tmp |= 0x5;
+	btcoexist->btc_write_1byte(btcoexist, 0x790, u1_tmp);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+
+	/*Antenna config*/
+	if (wifi_under_5g)
+		halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT,
+					     true, false);
+	else
+		halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA,
+					     true, false);
+	/* PTA parameter*/
+	halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0);
+
+	/* Enable counter statistics*/
+	/*0x76e[3] =1, WLAN_Act control by PTA*/
+	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+	btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3);
+	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
+}
+
+/*============================================================*/
+/* work around function start with wa_halbtc8821a1ant_*/
+/*============================================================*/
+/*============================================================*/
+/* extern function start with EXhalbtc8821a1ant_*/
+/*============================================================*/
+void ex_halbtc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+	halbtc8821a1ant_init_hw_config(btcoexist, true);
+}
+
+void ex_halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+		  "[BTCoex], Coex Mechanism Init!!\n");
+
+	btcoexist->stop_coex_dm = false;
+
+	halbtc8821a1ant_init_coex_dm(btcoexist);
+
+	halbtc8821a1ant_query_bt_info(btcoexist);
+}
+
+void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist)
+{
+	struct btc_board_info *board_info = &btcoexist->board_info;
+	struct btc_stack_info *stack_info = &btcoexist->stack_info;
+	struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info;
+	struct rtl_priv *rtlpriv = btcoexist->adapter;
+	u8 u1_tmp[4], i, bt_info_ext, ps_tdma_case = 0;
+	u16 u2_tmp[4];
+	u32 u4_tmp[4];
+	bool roam = false, scan = false, link = false, wifi_under_5g = false;
+	bool bt_hs_on = false, wifi_busy = false;
+	long wifi_rssi = 0, bt_hs_rssi = 0;
+	u32 wifi_bw, wifi_traffic_dir;
+	u8 wifi_dot11_chnl, wifi_hs_chnl;
+	u32 fw_ver = 0, bt_patch_ver = 0;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n ============[BT Coexist info]============");
+
+	if (btcoexist->manual_control) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n ============[Under Manual Control]============");
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n ==========================================");
+	}
+	if (btcoexist->stop_coex_dm) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n ============[Coex is STOPPED]============");
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n ==========================================");
+	}
+
+	if (!board_info->bt_exist) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!");
+		return;
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d/ %d/ %d",
+		   "Ant PG Num/ Ant Mech/ Ant Pos:",
+		   board_info->pg_ant_num,
+		   board_info->btdm_ant_num,
+		   board_info->btdm_ant_pos);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %s / %d", "BT stack/ hci ext ver",
+		   ((stack_info->profile_notified) ? "Yes" : "No"),
+		stack_info->hci_version);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+			   &bt_patch_ver);
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)",
+		   "CoexVer/ FwVer/ PatchVer",
+		   glcoex_ver_date_8821a_1ant,
+		   glcoex_ver_8821a_1ant,
+		   fw_ver, bt_patch_ver,
+		   bt_patch_ver);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION,
+			   &bt_hs_on);
+	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_DOT11_CHNL,
+			   &wifi_dot11_chnl);
+	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_HS_CHNL,
+			   &wifi_hs_chnl);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d / %d(%d)",
+		   "Dot11 channel / HsChnl(HsMode)",
+		   wifi_dot11_chnl, wifi_hs_chnl, bt_hs_on);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %02x %02x %02x ",
+		   "H2C Wifi inform bt chnl Info",
+		   coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1],
+		   coex_dm->wifi_chnl_info[2]);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+	btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi",
+		   (int)wifi_rssi, (int)bt_hs_rssi);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan",
+		   link, roam, scan);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G,
+			   &wifi_under_5g);
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW,
+			   &wifi_bw);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY,
+			   &wifi_busy);
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
+			   &wifi_traffic_dir);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %s / %s/ %s ", "Wifi status",
+		   (wifi_under_5g ? "5G" : "2.4G"),
+		   ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+		   (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+		   ((!wifi_busy) ? "idle" :
+		   ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+		   "uplink" : "downlink")));
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]",
+		   ((btcoexist->bt_info.bt_disabled) ? ("disabled") :
+		   ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") :
+		   ((BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE ==
+		     coex_dm->bt_status) ?
+		   "non-connected idle" :
+		   ((BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE ==
+		     coex_dm->bt_status) ?
+		   "connected-idle" : "busy")))),
+		   coex_sta->bt_rssi, coex_sta->bt_retry_cnt);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP",
+		   bt_link_info->sco_exist,
+		   bt_link_info->hid_exist,
+		   bt_link_info->pan_exist,
+		   bt_link_info->a2dp_exist);
+	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO);
+
+	bt_info_ext = coex_sta->bt_info_ext;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %s",
+		   "BT Info A2DP rate",
+		   (bt_info_ext&BIT0) ?
+		   "Basic rate" : "EDR rate");
+
+	for (i = 0; i < BT_INFO_SRC_8821A_1ANT_MAX; i++) {
+		if (coex_sta->bt_info_c2h_cnt[i]) {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+				   "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)",
+				   glbt_info_src_8821a_1ant[i],
+				   coex_sta->bt_info_c2h[i][0],
+				   coex_sta->bt_info_c2h[i][1],
+				   coex_sta->bt_info_c2h[i][2],
+				   coex_sta->bt_info_c2h[i][3],
+				   coex_sta->bt_info_c2h[i][4],
+				   coex_sta->bt_info_c2h[i][5],
+				   coex_sta->bt_info_c2h[i][6],
+				   coex_sta->bt_info_c2h_cnt[i]);
+		}
+	}
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %s/%s, (0x%x/0x%x)",
+		   "PS state, IPS/LPS, (lps/rpwm)",
+		   ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+		   ((coex_sta->under_Lps ? "LPS ON" : "LPS OFF")),
+		   btcoexist->bt_info.lps_val,
+		   btcoexist->bt_info.rpwm_val);
+	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+	if (!btcoexist->manual_control) {
+		/* Sw mechanism*/
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n %-35s", "============[Sw mechanism]============");
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n %-35s = %d", "SM[LowPenaltyRA]",
+			   coex_dm->cur_low_penalty_ra);
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n %-35s = %s/ %s/ %d ",
+			   "DelBA/ BtCtrlAgg/ AggSize",
+			   (btcoexist->bt_info.reject_agg_pkt ? "Yes" : "No"),
+			   (btcoexist->bt_info.bt_ctrl_buf_size ? "Yes" : "No"),
+			   btcoexist->bt_info.agg_buf_size);
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n %-35s = 0x%x ", "Rate Mask",
+			   btcoexist->bt_info.ra_mask);
+
+		/* Fw mechanism*/
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+			   "============[Fw mechanism]============");
+
+		ps_tdma_case = coex_dm->cur_ps_tdma;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)",
+			   "PS TDMA",
+			   coex_dm->ps_tdma_para[0],
+			   coex_dm->ps_tdma_para[1],
+			   coex_dm->ps_tdma_para[2],
+			   coex_dm->ps_tdma_para[3],
+			   coex_dm->ps_tdma_para[4],
+			   ps_tdma_case,
+			   coex_dm->auto_tdma_adjust);
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n %-35s = 0x%x ",
+			   "Latest error condition(should be 0)",
+			   coex_dm->error_condition);
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n %-35s = %d ", "IgnWlanAct",
+			   coex_dm->cur_ignore_wlan_act);
+	}
+
+	/* Hw setting*/
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s", "============[Hw setting]============");
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+		   "backup ARFR1/ARFR2/RL/AMaxTime",
+		   coex_dm->backup_arfr_cnt1,
+		   coex_dm->backup_arfr_cnt2,
+		   coex_dm->backup_retry_limit,
+		   coex_dm->backup_ampdu_max_time);
+
+	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430);
+	u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434);
+	u2_tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a);
+	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x",
+		   "0x430/0x434/0x42a/0x456",
+		   u4_tmp[0], u4_tmp[1], u2_tmp[0], u1_tmp[0]);
+
+	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc58);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x/ 0x%x", "0x778/ 0xc58[29:25]",
+		   u1_tmp[0], (u4_tmp[0]&0x3e000000) >> 25);
+
+	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x", "0x8db[6:5]",
+		   ((u1_tmp[0]&0x60)>>5));
+
+	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x975);
+	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+		   "0xcb4[29:28]/0xcb4[7:0]/0x974[9:8]",
+		   (u4_tmp[0] & 0x30000000)>>28,
+		    u4_tmp[0] & 0xff,
+		    u1_tmp[0] & 0x3);
+
+	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+	u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x64);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+		   "0x40/0x4c[24:23]/0x64[0]",
+		   u1_tmp[0], ((u4_tmp[0]&0x01800000)>>23), u1_tmp[1]&0x1);
+
+	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522",
+		   u4_tmp[0], u1_tmp[0]);
+
+	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x", "0xc50(dig)",
+		   u4_tmp[0]&0xff);
+
+	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48);
+	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5d);
+	u1_tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x/ 0x%x", "OFDM-FA/ CCK-FA",
+		   u4_tmp[0], (u1_tmp[0]<<8) + u1_tmp[1]);
+
+	u4_tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+	u4_tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+	u4_tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+	u1_tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x",
+		   "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)",
+		   u4_tmp[0], u4_tmp[1], u4_tmp[2], u1_tmp[0]);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)",
+		   coex_sta->high_priority_rx, coex_sta->high_priority_tx);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)",
+		   coex_sta->low_priority_rx, coex_sta->low_priority_tx);
+#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 1)
+	halbtc8821a1ant_monitor_bt_ctr(btcoexist);
+#endif
+	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+void ex_halbtc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	if (btcoexist->manual_control || btcoexist->stop_coex_dm)
+		return;
+
+	if (BTC_IPS_ENTER == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], IPS ENTER notify\n");
+		coex_sta->under_ips = true;
+		halbtc8821a1ant_set_ant_path(btcoexist,
+					     BTC_ANT_PATH_BT, false, true);
+		/*set PTA control*/
+		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8);
+		halbtc8821a1ant_coex_table_with_type(btcoexist,
+						     NORMAL_EXEC, 0);
+	} else if (BTC_IPS_LEAVE == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], IPS LEAVE notify\n");
+		coex_sta->under_ips = false;
+
+		halbtc8821a1ant_run_coexist_mechanism(btcoexist);
+	}
+}
+
+void ex_halbtc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	if (btcoexist->manual_control || btcoexist->stop_coex_dm)
+		return;
+
+	if (BTC_LPS_ENABLE == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], LPS ENABLE notify\n");
+		coex_sta->under_Lps = true;
+	} else if (BTC_LPS_DISABLE == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], LPS DISABLE notify\n");
+		coex_sta->under_Lps = false;
+	}
+}
+
+void ex_halbtc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	bool wifi_connected = false, bt_hs_on = false;
+
+	if (btcoexist->manual_control ||
+	    btcoexist->stop_coex_dm ||
+	    btcoexist->bt_info.bt_disabled)
+		return;
+
+	btcoexist->btc_get(btcoexist,
+		 BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+	btcoexist->btc_get(btcoexist,
+		 BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+
+	halbtc8821a1ant_query_bt_info(btcoexist);
+
+	if (coex_sta->c2h_bt_inquiry_page) {
+		halbtc8821a1ant_action_bt_inquiry(btcoexist);
+		return;
+	} else if (bt_hs_on) {
+		halbtc8821a1ant_action_hs(btcoexist);
+		return;
+	}
+
+	if (BTC_SCAN_START == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], SCAN START notify\n");
+		if (!wifi_connected) {
+			/* non-connected scan*/
+			btc8821a1ant_act_wifi_not_conn_scan(btcoexist);
+		} else {
+			/* wifi is connected*/
+			halbtc8821a1ant_action_wifi_connected_scan(btcoexist);
+		}
+	} else if (BTC_SCAN_FINISH == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], SCAN FINISH notify\n");
+		if (!wifi_connected) {
+			/* non-connected scan*/
+			halbtc8821a1ant_action_wifi_not_connected(btcoexist);
+		} else {
+			halbtc8821a1ant_action_wifi_connected(btcoexist);
+		}
+	}
+}
+
+void ex_halbtc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	bool	wifi_connected = false, bt_hs_on = false;
+
+	if (btcoexist->manual_control ||
+	    btcoexist->stop_coex_dm ||
+	    btcoexist->bt_info.bt_disabled)
+		return;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+	if (coex_sta->c2h_bt_inquiry_page) {
+		halbtc8821a1ant_action_bt_inquiry(btcoexist);
+		return;
+	} else if (bt_hs_on) {
+		halbtc8821a1ant_action_hs(btcoexist);
+		return;
+	}
+
+	if (BTC_ASSOCIATE_START == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], CONNECT START notify\n");
+		btc8821a1ant_act_wifi_not_conn_scan(btcoexist);
+	} else if (BTC_ASSOCIATE_FINISH == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], CONNECT FINISH notify\n");
+
+		btcoexist->btc_get(btcoexist,
+			 BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+		if (!wifi_connected) {
+			/* non-connected scan*/
+			halbtc8821a1ant_action_wifi_not_connected(btcoexist);
+		} else {
+			halbtc8821a1ant_action_wifi_connected(btcoexist);
+		}
+	}
+}
+
+void ex_halbtc8821a1ant_media_status_notify(struct btc_coexist *btcoexist,
+					    u8 type)
+{
+	u8 h2c_parameter[3] = {0};
+	u32 wifi_bw;
+	u8 wifi_central_chnl;
+
+	if (btcoexist->manual_control ||
+	    btcoexist->stop_coex_dm ||
+	    btcoexist->bt_info.bt_disabled)
+		return;
+
+	if (BTC_MEDIA_CONNECT == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], MEDIA connect notify\n");
+	} else {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], MEDIA disconnect notify\n");
+	}
+
+	/* only 2.4G we need to inform bt the chnl mask*/
+	btcoexist->btc_get(btcoexist,
+			   BTC_GET_U1_WIFI_CENTRAL_CHNL,
+			   &wifi_central_chnl);
+	if ((BTC_MEDIA_CONNECT == type) &&
+	    (wifi_central_chnl <= 14)) {
+		/*h2c_parameter[0] = 0x1;*/
+		h2c_parameter[0] = 0x0;
+		h2c_parameter[1] = wifi_central_chnl;
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+		if (BTC_WIFI_BW_HT40 == wifi_bw)
+			h2c_parameter[2] = 0x30;
+		else
+			h2c_parameter[2] = 0x20;
+	}
+
+	coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+	coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+	coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], FW write 0x66 = 0x%x\n",
+		  h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist,
+					      u8 type)
+{
+	bool bt_hs_on = false;
+
+	if (btcoexist->manual_control ||
+	    btcoexist->stop_coex_dm ||
+	    btcoexist->bt_info.bt_disabled)
+		return;
+
+	coex_sta->special_pkt_period_cnt = 0;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+	if (coex_sta->c2h_bt_inquiry_page) {
+		halbtc8821a1ant_action_bt_inquiry(btcoexist);
+		return;
+	} else if (bt_hs_on) {
+		halbtc8821a1ant_action_hs(btcoexist);
+		return;
+	}
+
+	if (BTC_PACKET_DHCP == type ||
+	    BTC_PACKET_EAPOL == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], special Packet(%d) notify\n", type);
+		btc8821a1ant_act_wifi_conn_sp_pkt(btcoexist);
+	}
+}
+
+void ex_halbtc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist,
+				       u8 *tmp_buf, u8 length)
+{
+	u8 bt_info = 0;
+	u8 i, rsp_source = 0;
+	bool wifi_connected = false;
+	bool bt_busy = false;
+	bool wifi_under_5g = false;
+
+	coex_sta->c2h_bt_info_req_sent = false;
+
+	btcoexist->btc_get(btcoexist,
+		 BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+
+	rsp_source = tmp_buf[0]&0xf;
+	if (rsp_source >= BT_INFO_SRC_8821A_1ANT_MAX)
+		rsp_source = BT_INFO_SRC_8821A_1ANT_WIFI_FW;
+	coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+		  "[BTCoex], Bt info[%d], length = %d, hex data = [",
+		  rsp_source, length);
+	for (i = 0; i < length; i++) {
+		coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
+		if (i == 1)
+			bt_info = tmp_buf[i];
+		if (i == length-1) {
+			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+				  "0x%02x]\n", tmp_buf[i]);
+		} else {
+			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+				  "0x%02x, ", tmp_buf[i]);
+		}
+	}
+
+	if (BT_INFO_SRC_8821A_1ANT_WIFI_FW != rsp_source) {
+		coex_sta->bt_retry_cnt =	/* [3:0]*/
+			coex_sta->bt_info_c2h[rsp_source][2]&0xf;
+
+		coex_sta->bt_rssi =
+			coex_sta->bt_info_c2h[rsp_source][3]*2+10;
+
+		coex_sta->bt_info_ext =
+			coex_sta->bt_info_c2h[rsp_source][4];
+
+		/* Here we need to resend some wifi info to BT*/
+		/* because bt is reset and loss of the info.*/
+		if (coex_sta->bt_info_ext & BIT1) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n");
+			btcoexist->btc_get(btcoexist,
+					   BTC_GET_BL_WIFI_CONNECTED,
+					   &wifi_connected);
+			if (wifi_connected) {
+				ex_halbtc8821a1ant_media_status_notify(btcoexist,
+							       BTC_MEDIA_CONNECT);
+			} else {
+				ex_halbtc8821a1ant_media_status_notify(btcoexist,
+							       BTC_MEDIA_DISCONNECT);
+			}
+		}
+
+		if ((coex_sta->bt_info_ext & BIT3) && !wifi_under_5g) {
+			if (!btcoexist->manual_control &&
+			    !btcoexist->stop_coex_dm) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n");
+				halbtc8821a1ant_ignore_wlan_act(btcoexist,
+								FORCE_EXEC,
+								false);
+			}
+		}
+#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0)
+		if (!(coex_sta->bt_info_ext & BIT4)) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], BT ext info bit4 check, set BT to enable Auto Report!!\n");
+			halbtc8821a1ant_bt_auto_report(btcoexist,
+						       FORCE_EXEC, true);
+		}
+#endif
+	}
+
+	/* check BIT2 first ==> check if bt is under inquiry or page scan*/
+	if (bt_info & BT_INFO_8821A_1ANT_B_INQ_PAGE)
+		coex_sta->c2h_bt_inquiry_page = true;
+	else
+		coex_sta->c2h_bt_inquiry_page = false;
+
+	/* set link exist status*/
+	if (!(bt_info&BT_INFO_8821A_1ANT_B_CONNECTION)) {
+		coex_sta->bt_link_exist = false;
+		coex_sta->pan_exist = false;
+		coex_sta->a2dp_exist = false;
+		coex_sta->hid_exist = false;
+		coex_sta->sco_exist = false;
+	} else {
+		/* connection exists*/
+		coex_sta->bt_link_exist = true;
+		if (bt_info & BT_INFO_8821A_1ANT_B_FTP)
+			coex_sta->pan_exist = true;
+		else
+			coex_sta->pan_exist = false;
+		if (bt_info & BT_INFO_8821A_1ANT_B_A2DP)
+			coex_sta->a2dp_exist = true;
+		else
+			coex_sta->a2dp_exist = false;
+		if (bt_info & BT_INFO_8821A_1ANT_B_HID)
+			coex_sta->hid_exist = true;
+		else
+			coex_sta->hid_exist = false;
+		if (bt_info & BT_INFO_8821A_1ANT_B_SCO_ESCO)
+			coex_sta->sco_exist = true;
+		else
+			coex_sta->sco_exist = false;
+	}
+
+	halbtc8821a1ant_update_bt_link_info(btcoexist);
+
+	if (!(bt_info&BT_INFO_8821A_1ANT_B_CONNECTION)) {
+		coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n");
+	} else if (bt_info == BT_INFO_8821A_1ANT_B_CONNECTION) {
+		/* connection exists but no busy*/
+		coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n");
+	} else if ((bt_info&BT_INFO_8821A_1ANT_B_SCO_ESCO) ||
+		(bt_info&BT_INFO_8821A_1ANT_B_SCO_BUSY)) {
+		coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_SCO_BUSY;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n");
+	} else if (bt_info&BT_INFO_8821A_1ANT_B_ACL_BUSY) {
+		if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status)
+			coex_dm->auto_tdma_adjust = false;
+		coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_ACL_BUSY;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n");
+	} else {
+		coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_MAX;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n");
+	}
+
+	if ((BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) ||
+	    (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) ||
+	    (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status))
+		bt_busy = true;
+	else
+		bt_busy = false;
+	btcoexist->btc_set(btcoexist,
+			   BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+	halbtc8821a1ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8821a1ant_halt_notify(struct btc_coexist *btcoexist)
+{
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+		  "[BTCoex], Halt notify\n");
+
+	btcoexist->stop_coex_dm = true;
+
+	halbtc8821a1ant_set_ant_path(btcoexist,
+				     BTC_ANT_PATH_BT, false, true);
+	halbtc8821a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+
+	halbtc8821a1ant_power_save_state(btcoexist,
+					 BTC_PS_WIFI_NATIVE, 0x0, 0x0);
+	halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0);
+
+	ex_halbtc8821a1ant_media_status_notify(btcoexist,
+					       BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
+{
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+		  "[BTCoex], Pnp notify\n");
+
+	if (BTC_WIFI_PNP_SLEEP == pnp_state) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], Pnp notify to SLEEP\n");
+		btcoexist->stop_coex_dm = true;
+		halbtc8821a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+		halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE,
+						 0x0, 0x0);
+		halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9);
+	} else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], Pnp notify to WAKE UP\n");
+		btcoexist->stop_coex_dm = false;
+		halbtc8821a1ant_init_hw_config(btcoexist, false);
+		halbtc8821a1ant_init_coex_dm(btcoexist);
+		halbtc8821a1ant_query_bt_info(btcoexist);
+	}
+}
+
+void
+ex_halbtc8821a1ant_periodical(
+	struct btc_coexist *btcoexist) {
+	static u8	dis_ver_info_cnt;
+	u32		fw_ver = 0, bt_patch_ver = 0;
+	struct btc_board_info *board_info = &btcoexist->board_info;
+	struct btc_stack_info *stack_info = &btcoexist->stack_info;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], ==========================Periodical===========================\n");
+
+	if (dis_ver_info_cnt <= 5) {
+		dis_ver_info_cnt += 1;
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], ****************************************************************\n");
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n",
+			  board_info->pg_ant_num,
+			  board_info->btdm_ant_num,
+			  board_info->btdm_ant_pos);
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], BT stack/ hci ext ver = %s / %d\n",
+			  ((stack_info->profile_notified) ? "Yes" : "No"),
+			  stack_info->hci_version);
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+				   &bt_patch_ver);
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
+			glcoex_ver_date_8821a_1ant,
+			glcoex_ver_8821a_1ant,
+			fw_ver, bt_patch_ver,
+			bt_patch_ver);
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], ****************************************************************\n");
+	}
+
+#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0)
+	halbtc8821a1ant_query_bt_info(btcoexist);
+	halbtc8821a1ant_monitor_bt_ctr(btcoexist);
+	btc8821a1ant_mon_bt_en_dis(btcoexist);
+#else
+	if (halbtc8821a1ant_Is_wifi_status_changed(btcoexist) ||
+	    coex_dm->auto_tdma_adjust) {
+		if (coex_sta->special_pkt_period_cnt > 2)
+			halbtc8821a1ant_run_coexist_mechanism(btcoexist);
+	}
+
+	coex_sta->special_pkt_period_cnt++;
+#endif
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h
new file mode 100644
index 0000000..20e9048
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a1ant.h
@@ -0,0 +1,188 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/*===========================================
+ * The following is for 8821A 1ANT BT Co-exist definition
+ *===========================================
+ */
+#define	BT_AUTO_REPORT_ONLY_8821A_1ANT				0
+
+#define	BT_INFO_8821A_1ANT_B_FTP	BIT7
+#define	BT_INFO_8821A_1ANT_B_A2DP	BIT6
+#define	BT_INFO_8821A_1ANT_B_HID	BIT5
+#define	BT_INFO_8821A_1ANT_B_SCO_BUSY	BIT4
+#define	BT_INFO_8821A_1ANT_B_ACL_BUSY	BIT3
+#define	BT_INFO_8821A_1ANT_B_INQ_PAGE	BIT2
+#define	BT_INFO_8821A_1ANT_B_SCO_ESCO	BIT1
+#define	BT_INFO_8821A_1ANT_B_CONNECTION	BIT0
+
+#define	BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_)	\
+		(((_BT_INFO_EXT_&BIT0)) ? true : false)
+
+#define	BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT		2
+
+enum _BT_INFO_SRC_8821A_1ANT {
+	BT_INFO_SRC_8821A_1ANT_WIFI_FW			= 0x0,
+	BT_INFO_SRC_8821A_1ANT_BT_RSP			= 0x1,
+	BT_INFO_SRC_8821A_1ANT_BT_ACTIVE_SEND		= 0x2,
+	BT_INFO_SRC_8821A_1ANT_MAX
+};
+
+enum _BT_8821A_1ANT_BT_STATUS {
+	BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE		= 0x0,
+	BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE			= 0x1,
+	BT_8821A_1ANT_BT_STATUS_INQ_PAGE			= 0x2,
+	BT_8821A_1ANT_BT_STATUS_ACL_BUSY			= 0x3,
+	BT_8821A_1ANT_BT_STATUS_SCO_BUSY			= 0x4,
+	BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY			= 0x5,
+	BT_8821A_1ANT_BT_STATUS_MAX
+};
+
+enum _BT_8821A_1ANT_WIFI_STATUS {
+	BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE		= 0x0,
+	BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN	= 0x1,
+	BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN		= 0x2,
+	BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT		= 0x3,
+	BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE		= 0x4,
+	BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY		= 0x5,
+	BT_8821A_1ANT_WIFI_STATUS_MAX
+};
+
+enum BT_8821A_1ANT_COEX_ALGO {
+	BT_8821A_1ANT_COEX_ALGO_UNDEFINED		= 0x0,
+	BT_8821A_1ANT_COEX_ALGO_SCO			= 0x1,
+	BT_8821A_1ANT_COEX_ALGO_HID			= 0x2,
+	BT_8821A_1ANT_COEX_ALGO_A2DP			= 0x3,
+	BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS		= 0x4,
+	BT_8821A_1ANT_COEX_ALGO_PANEDR			= 0x5,
+	BT_8821A_1ANT_COEX_ALGO_PANHS			= 0x6,
+	BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP		= 0x7,
+	BT_8821A_1ANT_COEX_ALGO_PANEDR_HID		= 0x8,
+	BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR		= 0x9,
+	BT_8821A_1ANT_COEX_ALGO_HID_A2DP		= 0xa,
+	BT_8821A_1ANT_COEX_ALGO_MAX			= 0xb,
+};
+
+struct coex_dm_8821a_1ant {
+	/* fw mechanism */
+	bool	cur_ignore_wlan_act;
+	bool	pre_ignore_wlan_act;
+	u8	pre_ps_tdma;
+	u8	cur_ps_tdma;
+	u8	ps_tdma_para[5];
+	u8	tdma_adj_type;
+	bool	auto_tdma_adjust;
+	bool	pre_ps_tdma_on;
+	bool	cur_ps_tdma_on;
+	bool	pre_bt_auto_report;
+	bool	cur_bt_auto_report;
+	u8	pre_lps;
+	u8	cur_lps;
+	u8	pre_rpwm;
+	u8	cur_rpwm;
+
+	/* sw mechanism */
+	bool	pre_low_penalty_ra;
+	bool	cur_low_penalty_ra;
+	u32	pre_val_0x6c0;
+	u32	cur_val_0x6c0;
+	u32	pre_val_0x6c4;
+	u32	cur_val_0x6c4;
+	u32	pre_val_0x6c8;
+	u32	cur_val_0x6c8;
+	u8	pre_val_0x6cc;
+	u8	cur_val_0x6cc;
+	/* Auto Rate Fallback Retry cnt */
+	u32	backup_arfr_cnt1;
+	/* Auto Rate Fallback Retry cnt */
+	u32	backup_arfr_cnt2;
+	u16	backup_retry_limit;
+	u8	backup_ampdu_max_time;
+
+	/* algorithm related */
+	u8	pre_algorithm;
+	u8	cur_algorithm;
+	u8	bt_status;
+	u8	wifi_chnl_info[3];
+
+	u32	pre_ra_mask;
+	u32	cur_ra_mask;
+	u8	pre_arfr_type;
+	u8	cur_arfr_type;
+	u8	pre_retry_limit_type;
+	u8	cur_retry_limit_type;
+	u8	pre_ampdu_time_type;
+	u8	cur_ampdu_time_type;
+
+	u8	error_condition;
+};
+
+struct coex_sta_8821a_1ant {
+	bool	bt_link_exist;
+	bool	sco_exist;
+	bool	a2dp_exist;
+	bool	hid_exist;
+	bool	pan_exist;
+
+	bool	under_Lps;
+	bool	under_ips;
+	u32	special_pkt_period_cnt;
+	u32	high_priority_tx;
+	u32	high_priority_rx;
+	u32	low_priority_tx;
+	u32	low_priority_rx;
+	u8	bt_rssi;
+	u8	pre_bt_rssi_state;
+	u8	pre_wifi_rssi_state[4];
+	bool	c2h_bt_info_req_sent;
+	u8	bt_info_c2h[BT_INFO_SRC_8821A_1ANT_MAX][10];
+	u32	bt_info_c2h_cnt[BT_INFO_SRC_8821A_1ANT_MAX];
+	bool	c2h_bt_inquiry_page;
+	u8	bt_retry_cnt;
+	u8	bt_info_ext;
+};
+
+/*===========================================
+ * The following is interface which will notify coex module.
+ *===========================================
+ */
+void ex_halbtc8821a1ant_init_hwconfig(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_init_coex_dm(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_ips_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8821a1ant_lps_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8821a1ant_scan_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8821a1ant_connect_notify(struct btc_coexist *btcoexist, u8 type);
+void ex_halbtc8821a1ant_media_status_notify(struct btc_coexist *btcoexist,
+					    u8 type);
+void ex_halbtc8821a1ant_special_packet_notify(struct btc_coexist *btcoexist,
+					      u8 type);
+void ex_halbtc8821a1ant_bt_info_notify(struct btc_coexist *btcoexist,
+				       u8 *tmpbuf, u8 length);
+void ex_halbtc8821a1ant_halt_notify(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate);
+void ex_halbtc8821a1ant_periodical(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_display_coex_info(struct btc_coexist *btcoexist);
+void ex_halbtc8821a1ant_dbg_control(struct btc_coexist *btcoexist, u8 op_code,
+				    u8 op_len, u8 *data);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c
new file mode 100644
index 0000000..cf819f0
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.c
@@ -0,0 +1,3879 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/*============================================================
+ * Description:
+ *
+ * This file is for RTL8821A Co-exist mechanism
+ *
+ * History
+ * 2012/08/22 Cosa first check in.
+ * 2012/11/14 Cosa Revise for 8821A 2Ant out sourcing.
+ *
+ *============================================================
+ */
+
+/*============================================================
+ * include files
+ *============================================================
+*/
+#include "halbt_precomp.h"
+/*============================================================
+ * Global variables, these are static variables
+ *============================================================
+ */
+static struct coex_dm_8821a_2ant	glcoex_dm_8821a_2ant;
+static struct coex_dm_8821a_2ant	*coex_dm = &glcoex_dm_8821a_2ant;
+static struct coex_sta_8821a_2ant	glcoex_sta_8821a_2ant;
+static struct coex_sta_8821a_2ant	*coex_sta = &glcoex_sta_8821a_2ant;
+
+static const char *const glbt_info_src_8821a_2ant[] = {
+	"BT Info[wifi fw]",
+	"BT Info[bt rsp]",
+	"BT Info[bt auto report]",
+};
+
+static u32	glcoex_ver_date_8821a_2ant = 20130618;
+static u32	glcoex_ver_8821a_2ant = 0x5050;
+
+/*============================================================
+ * local function proto type if needed
+ *============================================================
+ *============================================================
+ * local function start with halbtc8821a2ant_
+ *============================================================
+ */
+static u8 halbtc8821a2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh,
+					u8 rssi_thresh1)
+{
+	long	bt_rssi = 0;
+	u8	bt_rssi_state = coex_sta->pre_bt_rssi_state;
+
+	bt_rssi = coex_sta->bt_rssi;
+
+	if (level_num == 2) {
+		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+			long tmp = rssi_thresh +
+				   BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT;
+			if (bt_rssi >= tmp) {
+				bt_rssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to High\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at Low\n");
+			}
+		} else {
+			if (bt_rssi < rssi_thresh) {
+				bt_rssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to Low\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at High\n");
+			}
+		}
+	} else if (level_num == 3) {
+		if (rssi_thresh > rssi_thresh1) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+				  "[BTCoex], BT Rssi thresh error!!\n");
+			return coex_sta->pre_bt_rssi_state;
+		}
+
+		if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) {
+			if (bt_rssi >=
+			    (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+				bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to Medium\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at Low\n");
+			}
+		} else if ((coex_sta->pre_bt_rssi_state ==
+			   BTC_RSSI_STATE_MEDIUM) ||
+			   (coex_sta->pre_bt_rssi_state ==
+			    BTC_RSSI_STATE_STAY_MEDIUM)) {
+			if (bt_rssi >=
+			    (rssi_thresh1 +
+			     BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+				bt_rssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to High\n");
+			} else if (bt_rssi < rssi_thresh) {
+				bt_rssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to Low\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at Medium\n");
+			}
+		} else {
+			if (bt_rssi < rssi_thresh1) {
+				bt_rssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state switch to Medium\n");
+			} else {
+				bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE,
+					  "[BTCoex], BT Rssi state stay at High\n");
+			}
+		}
+	}
+
+	coex_sta->pre_bt_rssi_state = bt_rssi_state;
+
+	return bt_rssi_state;
+}
+
+static u8 halbtc8821a2ant_wifi_rssi_state(struct btc_coexist *btcoexist,
+					  u8 index, u8 level_num,
+					  u8 rssi_thresh, u8 rssi_thresh1)
+{
+	long	wifi_rssi = 0;
+	u8	wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index];
+
+	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+
+	if (level_num == 2) {
+		if ((coex_sta->pre_wifi_rssi_state[index] ==
+		     BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_wifi_rssi_state[index] ==
+		     BTC_RSSI_STATE_STAY_LOW)) {
+			if (wifi_rssi >=
+			    (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+				wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to High\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at Low\n");
+			}
+		} else {
+			if (wifi_rssi < rssi_thresh) {
+				wifi_rssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to Low\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at High\n");
+			}
+		}
+	} else if (level_num == 3) {
+		if (rssi_thresh > rssi_thresh1) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE,
+				  "[BTCoex], wifi RSSI thresh error!!\n");
+			return coex_sta->pre_wifi_rssi_state[index];
+		}
+
+		if ((coex_sta->pre_wifi_rssi_state[index] ==
+		    BTC_RSSI_STATE_LOW) ||
+		    (coex_sta->pre_wifi_rssi_state[index] ==
+		     BTC_RSSI_STATE_STAY_LOW)) {
+			if (wifi_rssi >=
+			    (rssi_thresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to Medium\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at Low\n");
+			}
+		} else if ((coex_sta->pre_wifi_rssi_state[index] ==
+			   BTC_RSSI_STATE_MEDIUM) ||
+			   (coex_sta->pre_wifi_rssi_state[index] ==
+			    BTC_RSSI_STATE_STAY_MEDIUM)) {
+			if (wifi_rssi >= (rssi_thresh1 +
+			    BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) {
+				wifi_rssi_state = BTC_RSSI_STATE_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to High\n");
+			} else if (wifi_rssi < rssi_thresh) {
+				wifi_rssi_state = BTC_RSSI_STATE_LOW;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to Low\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at Medium\n");
+			}
+		} else {
+			if (wifi_rssi < rssi_thresh1) {
+				wifi_rssi_state = BTC_RSSI_STATE_MEDIUM;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state switch to Medium\n");
+			} else {
+				wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_WIFI_RSSI_STATE,
+					  "[BTCoex], wifi RSSI state stay at High\n");
+			}
+		}
+	}
+	coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state;
+
+	return wifi_rssi_state;
+}
+
+static void btc8821a2ant_mon_bt_en_dis(struct btc_coexist *btcoexist)
+{
+	static bool	pre_bt_disabled;
+	static u32	bt_disable_cnt;
+	bool		bt_active = true, bt_disabled = false;
+
+	/* This function check if bt is disabled*/
+
+	if (coex_sta->high_priority_tx == 0 &&
+	    coex_sta->high_priority_rx == 0 &&
+	    coex_sta->low_priority_tx == 0 &&
+	    coex_sta->low_priority_rx == 0)
+		bt_active = false;
+	if (coex_sta->high_priority_tx == 0xffff &&
+	    coex_sta->high_priority_rx == 0xffff &&
+	    coex_sta->low_priority_tx == 0xffff &&
+	    coex_sta->low_priority_rx == 0xffff)
+		bt_active = false;
+	if (bt_active) {
+		bt_disable_cnt = 0;
+		bt_disabled = false;
+		btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+				   &bt_disabled);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+			  "[BTCoex], BT is enabled !!\n");
+	} else {
+		bt_disable_cnt++;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+			  "[BTCoex], bt all counters = 0, %d times!!\n",
+			  bt_disable_cnt);
+		if (bt_disable_cnt >= 2) {
+			bt_disabled = true;
+			btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE,
+					   &bt_disabled);
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+				  "[BTCoex], BT is disabled !!\n");
+		}
+	}
+	if (pre_bt_disabled != bt_disabled) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+			  "[BTCoex], BT is from %s to %s!!\n",
+			  (pre_bt_disabled ? "disabled" : "enabled"),
+			  (bt_disabled ? "disabled" : "enabled"));
+		pre_bt_disabled = bt_disabled;
+	}
+}
+
+static void halbtc8821a2ant_monitor_bt_ctr(struct btc_coexist *btcoexist)
+{
+	u32	reg_hp_txrx, reg_lp_txrx, u4tmp;
+	u32	reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0;
+
+	reg_hp_txrx = 0x770;
+	reg_lp_txrx = 0x774;
+
+	u4tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx);
+	reg_hp_tx = u4tmp & MASKLWORD;
+	reg_hp_rx = (u4tmp & MASKHWORD)>>16;
+
+	u4tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx);
+	reg_lp_tx = u4tmp & MASKLWORD;
+	reg_lp_rx = (u4tmp & MASKHWORD)>>16;
+
+	coex_sta->high_priority_tx = reg_hp_tx;
+	coex_sta->high_priority_rx = reg_hp_rx;
+	coex_sta->low_priority_tx = reg_lp_tx;
+	coex_sta->low_priority_rx = reg_lp_rx;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+		  "[BTCoex], High Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
+		  reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx);
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR,
+		  "[BTCoex], Low Priority Tx/Rx (reg 0x%x) = 0x%x(%d)/0x%x(%d)\n",
+		  reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx);
+
+	/* reset counter */
+	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+}
+
+static void halbtc8821a2ant_query_bt_info(struct btc_coexist *btcoexist)
+{
+	u8	h2c_parameter[1] = {0};
+
+	coex_sta->c2h_bt_info_req_sent = true;
+
+	h2c_parameter[0] |= BIT0;	/* trigger */
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], Query Bt Info, FW write 0x61 = 0x%x\n",
+		  h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter);
+}
+
+static u8 halbtc8821a2ant_action_algorithm(struct btc_coexist *btcoexist)
+{
+	struct btc_stack_info *stack_info = &btcoexist->stack_info;
+	bool bt_hs_on = false;
+	u8 algorithm = BT_8821A_2ANT_COEX_ALGO_UNDEFINED;
+	u8 num_of_diff_profile = 0;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+
+	/*for win-8 stack HID report error*/
+	/* sync  BTInfo with BT firmware and stack */
+	if (!stack_info->hid_exist)
+		stack_info->hid_exist = coex_sta->hid_exist;
+	/* when stack HID report error, here we use the info from bt fw. */
+	if (!stack_info->bt_link_exist)
+		stack_info->bt_link_exist = coex_sta->bt_link_exist;
+
+	if (!coex_sta->bt_link_exist) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], No profile exists!!!\n");
+		return algorithm;
+	}
+
+	if (coex_sta->sco_exist)
+		num_of_diff_profile++;
+	if (coex_sta->hid_exist)
+		num_of_diff_profile++;
+	if (coex_sta->pan_exist)
+		num_of_diff_profile++;
+	if (coex_sta->a2dp_exist)
+		num_of_diff_profile++;
+
+	if (num_of_diff_profile == 1) {
+		if (coex_sta->sco_exist) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], SCO only\n");
+			algorithm = BT_8821A_2ANT_COEX_ALGO_SCO;
+		} else {
+			if (coex_sta->hid_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], HID only\n");
+				algorithm = BT_8821A_2ANT_COEX_ALGO_HID;
+			} else if (coex_sta->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], A2DP only\n");
+				algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP;
+			} else if (coex_sta->pan_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], PAN(HS) only\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_PANHS;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], PAN(EDR) only\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR;
+				}
+			}
+		}
+	} else if (num_of_diff_profile == 2) {
+		if (coex_sta->sco_exist) {
+			if (coex_sta->hid_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], SCO + HID\n");
+				algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+			} else if (coex_sta->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], SCO + A2DP ==> SCO\n");
+				algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+			} else if (coex_sta->pan_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], SCO + PAN(HS)\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_SCO;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], SCO + PAN(EDR)\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+				}
+			}
+		} else {
+			if (coex_sta->hid_exist &&
+			    coex_sta->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], HID + A2DP\n");
+				algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP;
+			} else if (coex_sta->hid_exist &&
+				coex_sta->pan_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], HID + PAN(HS)\n");
+					algorithm =  BT_8821A_2ANT_COEX_ALGO_HID;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], HID + PAN(EDR)\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+				}
+			} else if (coex_sta->pan_exist &&
+				coex_sta->a2dp_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], A2DP + PAN(HS)\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], A2DP + PAN(EDR)\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP;
+				}
+			}
+		}
+	} else if (num_of_diff_profile == 3) {
+		if (coex_sta->sco_exist) {
+			if (coex_sta->hid_exist &&
+			    coex_sta->a2dp_exist) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+					  "[BTCoex], SCO + HID + A2DP ==> HID\n");
+				algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+			} else if (coex_sta->hid_exist &&
+				coex_sta->pan_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], SCO + HID + PAN(HS)\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], SCO + HID + PAN(EDR)\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+				}
+			} else if (coex_sta->pan_exist &&
+				   coex_sta->a2dp_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], SCO + A2DP + PAN(HS)\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+				}
+			}
+		} else {
+			if (coex_sta->hid_exist &&
+			    coex_sta->pan_exist &&
+			    coex_sta->a2dp_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], HID + A2DP + PAN(HS)\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP;
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], HID + A2DP + PAN(EDR)\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+				}
+			}
+		}
+	} else if (num_of_diff_profile >= 3) {
+		if (coex_sta->sco_exist) {
+			if (coex_sta->hid_exist &&
+			    coex_sta->pan_exist &&
+			    coex_sta->a2dp_exist) {
+				if (bt_hs_on) {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n");
+
+				} else {
+					BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+						  "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n");
+					algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID;
+				}
+			}
+		}
+	}
+	return algorithm;
+}
+
+static bool halbtc8821a2ant_need_to_dec_bt_pwr(struct btc_coexist *btcoexist)
+{
+	bool ret = false;
+	bool bt_hs_on = false, wifi_connected = false;
+	long bt_hs_rssi = 0;
+	u8 bt_rssi_state;
+
+	if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on))
+		return false;
+	if (!btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+				&wifi_connected))
+		return false;
+	if (!btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi))
+		return false;
+
+	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+	if (wifi_connected) {
+		if (bt_hs_on) {
+			if (bt_hs_rssi > 37) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+					  "[BTCoex], Need to decrease bt power for HS mode!!\n");
+				ret = true;
+			}
+		} else {
+			if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+			    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+				BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+					  "[BTCoex], Need to decrease bt power for Wifi is connected!!\n");
+				ret = true;
+			}
+		}
+	}
+	return ret;
+}
+
+static void btc8821a2ant_set_fw_dac_swing_lev(struct btc_coexist *btcoexist,
+					      u8 dac_swing_lvl)
+{
+	u8	h2c_parameter[1] = {0};
+
+	/* There are several type of dacswing
+	 * 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6
+	 */
+	h2c_parameter[0] = dac_swing_lvl;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swing_lvl);
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], FW write 0x64 = 0x%x\n", h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter);
+}
+
+static void halbtc8821a2ant_set_fw_dec_bt_pwr(struct btc_coexist *btcoexist,
+					      bool dec_bt_pwr)
+{
+	u8			h2c_parameter[1] = {0};
+
+	h2c_parameter[0] = 0;
+
+	if (dec_bt_pwr)
+		h2c_parameter[0] |= BIT1;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], decrease Bt Power : %s, FW write 0x62 = 0x%x\n",
+		  (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter);
+}
+
+static void halbtc8821a2ant_dec_bt_pwr(struct btc_coexist *btcoexist,
+				       bool force_exec, bool dec_bt_pwr)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s Dec BT power = %s\n",
+		  (force_exec ? "force to" : ""),
+		  ((dec_bt_pwr) ? "ON" : "OFF"));
+	coex_dm->cur_dec_bt_pwr = dec_bt_pwr;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], pre_dec_bt_pwr = %d, cur_dec_bt_pwr = %d\n",
+			  coex_dm->pre_dec_bt_pwr, coex_dm->cur_dec_bt_pwr);
+
+		if (coex_dm->pre_dec_bt_pwr == coex_dm->cur_dec_bt_pwr)
+			return;
+	}
+	halbtc8821a2ant_set_fw_dec_bt_pwr(btcoexist, coex_dm->cur_dec_bt_pwr);
+
+	coex_dm->pre_dec_bt_pwr = coex_dm->cur_dec_bt_pwr;
+}
+
+static void btc8821a2ant_set_fw_bt_lna_constr(struct btc_coexist *btcoexist,
+					      bool bt_lna_cons_on)
+{
+	u8 h2c_parameter[2] = {0};
+
+	h2c_parameter[0] = 0x3;	/* opCode, 0x3 = BT_SET_LNA_CONSTRAIN */
+
+	if (bt_lna_cons_on)
+		h2c_parameter[1] |= BIT0;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], set BT LNA Constrain: %s, FW write 0x69 = 0x%x\n",
+		  (bt_lna_cons_on ? "ON!!" : "OFF!!"),
+		  h2c_parameter[0]<<8|h2c_parameter[1]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x69, 2, h2c_parameter);
+}
+
+static void btc8821a2_set_bt_lna_const(struct btc_coexist *btcoexist,
+				       bool force_exec, bool bt_lna_cons_on)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s BT Constrain = %s\n",
+		  (force_exec ? "force" : ""),
+		  ((bt_lna_cons_on) ? "ON" : "OFF"));
+	coex_dm->cur_bt_lna_constrain = bt_lna_cons_on;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], pre_bt_lna_constrain = %d,cur_bt_lna_constrain = %d\n",
+			  coex_dm->pre_bt_lna_constrain,
+			  coex_dm->cur_bt_lna_constrain);
+
+		if (coex_dm->pre_bt_lna_constrain ==
+		    coex_dm->cur_bt_lna_constrain)
+			return;
+	}
+	btc8821a2ant_set_fw_bt_lna_constr(btcoexist,
+					  coex_dm->cur_bt_lna_constrain);
+
+	coex_dm->pre_bt_lna_constrain = coex_dm->cur_bt_lna_constrain;
+}
+
+static void halbtc8821a2ant_set_fw_bt_psd_mode(struct btc_coexist *btcoexist,
+					       u8 bt_psd_mode)
+{
+	u8 h2c_parameter[2] = {0};
+
+	h2c_parameter[0] = 0x2;	/* opCode, 0x2 = BT_SET_PSD_MODE */
+
+	h2c_parameter[1] = bt_psd_mode;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], set BT PSD mode = 0x%x, FW write 0x69 = 0x%x\n",
+		  h2c_parameter[1],
+		  h2c_parameter[0]<<8|h2c_parameter[1]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x69, 2, h2c_parameter);
+}
+
+static void halbtc8821a2ant_set_bt_psd_mode(struct btc_coexist *btcoexist,
+					    bool force_exec, u8 bt_psd_mode)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s BT PSD mode = 0x%x\n",
+		  (force_exec ? "force" : ""), bt_psd_mode);
+	coex_dm->cur_bt_psd_mode = bt_psd_mode;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], pre_bt_psd_mode = 0x%x, cur_bt_psd_mode = 0x%x\n",
+			  coex_dm->pre_bt_psd_mode, coex_dm->cur_bt_psd_mode);
+
+		if (coex_dm->pre_bt_psd_mode == coex_dm->cur_bt_psd_mode)
+			return;
+	}
+	halbtc8821a2ant_set_fw_bt_psd_mode(btcoexist,
+					   coex_dm->cur_bt_psd_mode);
+
+	coex_dm->pre_bt_psd_mode = coex_dm->cur_bt_psd_mode;
+}
+
+static void halbtc8821a2ant_set_bt_auto_report(struct btc_coexist *btcoexist,
+					       bool enable_auto_report)
+{
+	u8 h2c_parameter[1] = {0};
+
+	h2c_parameter[0] = 0;
+
+	if (enable_auto_report)
+		h2c_parameter[0] |= BIT0;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], BT FW auto report : %s, FW write 0x68 = 0x%x\n",
+		  (enable_auto_report ? "Enabled!!" : "Disabled!!"),
+		  h2c_parameter[0]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter);
+}
+
+static void halbtc8821a2ant_bt_auto_report(struct btc_coexist *btcoexist,
+					   bool force_exec,
+					   bool enable_auto_report)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s BT Auto report = %s\n",
+		  (force_exec ? "force to" : ""),
+		  ((enable_auto_report) ? "Enabled" : "Disabled"));
+	coex_dm->cur_bt_auto_report = enable_auto_report;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], pre_bt_auto_report = %d, cur_bt_auto_report = %d\n",
+			  coex_dm->pre_bt_auto_report,
+			  coex_dm->cur_bt_auto_report);
+
+		if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report)
+			return;
+	}
+	halbtc8821a2ant_set_bt_auto_report(btcoexist,
+					   coex_dm->cur_bt_auto_report);
+
+	coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report;
+}
+
+static void halbtc8821a2ant_fw_dac_swing_lvl(struct btc_coexist *btcoexist,
+					     bool force_exec,
+					     u8 fw_dac_swing_lvl)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s set FW Dac Swing level = %d\n",
+		  (force_exec ? "force to" : ""), fw_dac_swing_lvl);
+	coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], pre_fw_dac_swing_lvl = %d, cur_fw_dac_swing_lvl = %d\n",
+			  coex_dm->pre_fw_dac_swing_lvl,
+			  coex_dm->cur_fw_dac_swing_lvl);
+
+		if (coex_dm->pre_fw_dac_swing_lvl ==
+		    coex_dm->cur_fw_dac_swing_lvl)
+			return;
+	}
+
+	btc8821a2ant_set_fw_dac_swing_lev(btcoexist,
+					  coex_dm->cur_fw_dac_swing_lvl);
+
+	coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl;
+}
+
+static void btc8821a2ant_set_sw_rf_rx_lpf_corner(struct btc_coexist *btcoexist,
+						 bool rx_rf_shrink_on)
+{
+	if (rx_rf_shrink_on) {
+		/* Shrink RF Rx LPF corner */
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+			  "[BTCoex], Shrink RF Rx LPF corner!!\n");
+		btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e,
+					  0xfffff, 0xffffc);
+	} else {
+		/* Resume RF Rx LPF corner
+		 * After initialized, we can use coex_dm->bt_rf0x1e_backup
+		 */
+		if (btcoexist->initilized) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+				  "[BTCoex], Resume RF Rx LPF corner!!\n");
+			btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A,
+						  0x1e, 0xfffff,
+						   coex_dm->bt_rf0x1e_backup);
+		}
+	}
+}
+
+static void halbtc8821a2ant_RfShrink(struct btc_coexist *btcoexist,
+				     bool force_exec, bool rx_rf_shrink_on)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+		  "[BTCoex], %s turn Rx RF Shrink = %s\n",
+		  (force_exec ? "force to" : ""),
+		  ((rx_rf_shrink_on) ? "ON" : "OFF"));
+	coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "[BTCoex], pre_rf_rx_lpf_shrink = %d, cur_rf_rx_lpf_shrink = %d\n",
+			  coex_dm->pre_rf_rx_lpf_shrink,
+			  coex_dm->cur_rf_rx_lpf_shrink);
+
+		if (coex_dm->pre_rf_rx_lpf_shrink ==
+		    coex_dm->cur_rf_rx_lpf_shrink)
+			return;
+	}
+	btc8821a2ant_set_sw_rf_rx_lpf_corner(btcoexist,
+					     coex_dm->cur_rf_rx_lpf_shrink);
+
+	coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink;
+}
+
+static void btc8821a2ant_SetSwPenTxRateAdapt(struct btc_coexist *btcoexist,
+					     bool low_penalty_ra)
+{
+	u8 h2c_parameter[6] = {0};
+
+	h2c_parameter[0] = 0x6;	/* opCode, 0x6 = Retry_Penalty */
+
+	if (low_penalty_ra) {
+		h2c_parameter[1] |= BIT0;
+		/*normal rate except MCS7/6/5, OFDM54/48/36 */
+		h2c_parameter[2] = 0x00;
+		/*MCS7 or OFDM54 */
+		h2c_parameter[3] = 0xf7;
+		/*MCS6 or OFDM48 */
+		h2c_parameter[4] = 0xf8;
+		/*MCS5 or OFDM36 */
+		h2c_parameter[5] = 0xf9;
+	}
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], set WiFi Low-Penalty Retry: %s",
+		  (low_penalty_ra ? "ON!!" : "OFF!!"));
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter);
+}
+
+static void halbtc8821a2ant_low_penalty_ra(struct btc_coexist *btcoexist,
+					   bool force_exec, bool low_penalty_ra)
+{
+	/*return;*/
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+		  "[BTCoex], %s turn LowPenaltyRA = %s\n",
+		  (force_exec ? "force to" : ""),
+		  ((low_penalty_ra) ? "ON" : "OFF"));
+	coex_dm->cur_low_penalty_ra = low_penalty_ra;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "[BTCoex], pre_low_penalty_ra = %d, cur_low_penalty_ra = %d\n",
+			  coex_dm->pre_low_penalty_ra,
+			  coex_dm->cur_low_penalty_ra);
+
+		if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra)
+			return;
+	}
+	btc8821a2ant_SetSwPenTxRateAdapt(btcoexist,
+					 coex_dm->cur_low_penalty_ra);
+
+	coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra;
+}
+
+static void halbtc8821a2ant_set_dac_swing_reg(struct btc_coexist *btcoexist,
+					      u32 level)
+{
+	u8 val = (u8)level;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], Write SwDacSwing = 0x%x\n", level);
+	btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc5b, 0x3e, val);
+}
+
+static void btc8821a2ant_set_sw_full_dac_swing(struct btc_coexist *btcoexist,
+					       bool sw_dac_swing_on,
+					       u32 sw_dac_swing_lvl)
+{
+	if (sw_dac_swing_on)
+		halbtc8821a2ant_set_dac_swing_reg(btcoexist, sw_dac_swing_lvl);
+	else
+		halbtc8821a2ant_set_dac_swing_reg(btcoexist, 0x18);
+}
+
+static void halbtc8821a2ant_dac_swing(struct btc_coexist *btcoexist,
+				      bool force_exec, bool dac_swing_on,
+				      u32 dac_swing_lvl)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+		  "[BTCoex], %s turn DacSwing = %s, dac_swing_lvl = 0x%x\n",
+		  (force_exec ? "force to" : ""),
+		  ((dac_swing_on) ? "ON" : "OFF"),
+		  dac_swing_lvl);
+	coex_dm->cur_dac_swing_on = dac_swing_on;
+	coex_dm->cur_dac_swing_lvl = dac_swing_lvl;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "[BTCoex], pre_dac_swing_on = %d, pre_dac_swing_lvl = 0x%x, cur_dac_swing_on = %d, cur_dac_swing_lvl = 0x%x\n",
+			  coex_dm->pre_dac_swing_on,
+			  coex_dm->pre_dac_swing_lvl,
+			  coex_dm->cur_dac_swing_on,
+			  coex_dm->cur_dac_swing_lvl);
+
+		if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) &&
+		    (coex_dm->pre_dac_swing_lvl ==
+		     coex_dm->cur_dac_swing_lvl))
+			return;
+	}
+	mdelay(30);
+	btc8821a2ant_set_sw_full_dac_swing(btcoexist, dac_swing_on,
+					   dac_swing_lvl);
+
+	coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on;
+	coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl;
+}
+
+static void halbtc8821a2ant_set_adc_back_off(struct btc_coexist *btcoexist,
+					     bool adc_back_off)
+{
+	if (adc_back_off) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+			  "[BTCoex], BB BackOff Level On!\n");
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x3);
+	} else {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+			  "[BTCoex], BB BackOff Level Off!\n");
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x1);
+	}
+}
+
+static void halbtc8821a2ant_adc_back_off(struct btc_coexist *btcoexist,
+					 bool force_exec, bool adc_back_off)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+		  "[BTCoex], %s turn AdcBackOff = %s\n",
+		  (force_exec ? "force to" : ""),
+		  ((adc_back_off) ? "ON" : "OFF"));
+	coex_dm->cur_adc_back_off = adc_back_off;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "[BTCoex], pre_adc_back_off = %d, cur_adc_back_off = %d\n",
+			  coex_dm->pre_adc_back_off, coex_dm->cur_adc_back_off);
+
+		if (coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off)
+			return;
+	}
+	halbtc8821a2ant_set_adc_back_off(btcoexist, coex_dm->cur_adc_back_off);
+
+	coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off;
+}
+
+static void halbtc8821a2ant_set_coex_table(struct btc_coexist *btcoexist,
+					   u32 val0x6c0, u32 val0x6c4,
+					   u32 val0x6c8, u8 val0x6cc)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6c0 = 0x%x\n", val0x6c0);
+	btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0);
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6c4 = 0x%x\n", val0x6c4);
+	btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4);
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6c8 = 0x%x\n", val0x6c8);
+	btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8);
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC,
+		  "[BTCoex], set coex table, set 0x6cc = 0x%x\n", val0x6cc);
+	btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc);
+}
+
+static void halbtc8821a2ant_coex_table(struct btc_coexist *btcoexist,
+				       bool force_exec, u32 val0x6c0,
+				       u32 val0x6c4, u32 val0x6c8, u8 val0x6cc)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW,
+		  "[BTCoex], %s write Coex Table 0x6c0 = 0x%x, 0x6c4 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n",
+		  (force_exec ? "force to" : ""),
+		  val0x6c0, val0x6c4, val0x6c8, val0x6cc);
+	coex_dm->cur_val0x6c0 = val0x6c0;
+	coex_dm->cur_val0x6c4 = val0x6c4;
+	coex_dm->cur_val0x6c8 = val0x6c8;
+	coex_dm->cur_val0x6cc = val0x6cc;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "[BTCoex], pre_val0x6c0 = 0x%x, pre_val0x6c4 = 0x%x, pre_val0x6c8 = 0x%x, pre_val0x6cc = 0x%x !!\n",
+			  coex_dm->pre_val0x6c0,
+			  coex_dm->pre_val0x6c4,
+			  coex_dm->pre_val0x6c8,
+			  coex_dm->pre_val0x6cc);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL,
+			  "[BTCoex], cur_val0x6c0 = 0x%x, cur_val0x6c4 = 0x%x, cur_val0x6c8 = 0x%x, cur_val0x6cc = 0x%x !!\n",
+			  coex_dm->cur_val0x6c0,
+			  coex_dm->cur_val0x6c4,
+			  coex_dm->cur_val0x6c8,
+			  coex_dm->cur_val0x6cc);
+
+		if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) &&
+		    (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) &&
+		    (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) &&
+		    (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc))
+			return;
+	}
+	halbtc8821a2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8,
+				       val0x6cc);
+
+	coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0;
+	coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4;
+	coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8;
+	coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc;
+}
+
+static void halbtc8821a2ant_set_fw_ignore_wlan_act(struct btc_coexist *btcoex,
+						   bool enable)
+{
+	u8 h2c_parameter[1] = {0};
+
+	if (enable)
+		h2c_parameter[0] |= BIT0;/* function enable */
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63 = 0x%x\n",
+		  h2c_parameter[0]);
+
+	btcoex->btc_fill_h2c(btcoex, 0x63, 1, h2c_parameter);
+}
+
+static void halbtc8821a2ant_ignore_wlan_act(struct btc_coexist *btcoexist,
+					    bool force_exec, bool enable)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s turn Ignore WlanAct %s\n",
+		  (force_exec ? "force to" : ""), (enable ? "ON" : "OFF"));
+	coex_dm->cur_ignore_wlan_act = enable;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], pre_ignore_wlan_act = %d, cur_ignore_wlan_act = %d!!\n",
+			  coex_dm->pre_ignore_wlan_act,
+			  coex_dm->cur_ignore_wlan_act);
+
+		if (coex_dm->pre_ignore_wlan_act ==
+		    coex_dm->cur_ignore_wlan_act)
+			return;
+	}
+	halbtc8821a2ant_set_fw_ignore_wlan_act(btcoexist, enable);
+
+	coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act;
+}
+
+static void halbtc8821a2ant_set_fw_pstdma(struct btc_coexist *btcoexist,
+					  u8 byte1, u8 byte2, u8 byte3,
+					  u8 byte4, u8 byte5)
+{
+	u8 h2c_parameter[5];
+
+	h2c_parameter[0] = byte1;
+	h2c_parameter[1] = byte2;
+	h2c_parameter[2] = byte3;
+	h2c_parameter[3] = byte4;
+	h2c_parameter[4] = byte5;
+
+	coex_dm->ps_tdma_para[0] = byte1;
+	coex_dm->ps_tdma_para[1] = byte2;
+	coex_dm->ps_tdma_para[2] = byte3;
+	coex_dm->ps_tdma_para[3] = byte4;
+	coex_dm->ps_tdma_para[4] = byte5;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], FW write 0x60(5bytes) = 0x%x%08x\n",
+		  h2c_parameter[0],
+		  h2c_parameter[1]<<24|
+		  h2c_parameter[2]<<16|
+		  h2c_parameter[3]<<8|
+		  h2c_parameter[4]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter);
+}
+
+static void btc8821a2ant_sw_mech1(struct btc_coexist *btcoexist,
+				  bool shrink_rx_lpf,
+				  bool low_penalty_ra, bool limited_dig,
+				  bool bt_lna_constrain)
+{
+	u32 wifi_bw;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	if (BTC_WIFI_BW_HT40 != wifi_bw) {
+		/*only shrink RF Rx LPF for HT40*/
+		if (shrink_rx_lpf)
+			shrink_rx_lpf = false;
+	}
+
+	halbtc8821a2ant_RfShrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf);
+	halbtc8821a2ant_low_penalty_ra(btcoexist,
+				       NORMAL_EXEC, low_penalty_ra);
+
+	/* no limited DIG
+	 * btc8821a2_set_bt_lna_const(btcoexist,
+		NORMAL_EXEC, bBTLNAConstrain);
+	 */
+}
+
+static void btc8821a2ant_sw_mech2(struct btc_coexist *btcoexist,
+				  bool agc_table_shift,
+				  bool adc_back_off, bool sw_dac_swing,
+				  u32 dac_swing_lvl)
+{
+	/* halbtc8821a2ant_AgcTable(btcoexist, NORMAL_EXEC, bAGCTableShift); */
+	halbtc8821a2ant_adc_back_off(btcoexist, NORMAL_EXEC, adc_back_off);
+	halbtc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing,
+				  sw_dac_swing);
+}
+
+static void halbtc8821a2ant_set_ant_path(struct btc_coexist *btcoexist,
+					 u8 ant_pos_type, bool init_hw_cfg,
+					 bool wifi_off)
+{
+	struct btc_board_info *board_info = &btcoexist->board_info;
+	u32 u4tmp = 0;
+	u8 h2c_parameter[2] = {0};
+
+	if (init_hw_cfg) {
+		/*  0x4c[23] = 0, 0x4c[24] = 1  Antenna control by WL/BT */
+		u4tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+		u4tmp &= ~BIT23;
+		u4tmp |= BIT24;
+		btcoexist->btc_write_4byte(btcoexist, 0x4c, u4tmp);
+
+		btcoexist->btc_write_4byte(btcoexist, 0x974, 0x3ff);
+		btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77);
+
+		if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) {
+			/* tell firmware "antenna inverse"  ==>
+			 *	WRONG firmware antenna control code.
+			 *	==>need fw to fix
+			 */
+			h2c_parameter[0] = 1;
+			h2c_parameter[1] = 1;
+			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+						h2c_parameter);
+		} else {
+			/* tell firmware "no antenna inverse"
+			 *	==> WRONG firmware antenna control code.
+			 *	==>need fw to fix
+			 */
+			h2c_parameter[0] = 0;
+			h2c_parameter[1] = 1;
+			btcoexist->btc_fill_h2c(btcoexist, 0x65, 2,
+						h2c_parameter);
+		}
+	}
+
+	/* ext switch setting */
+	switch (ant_pos_type) {
+	case BTC_ANT_WIFI_AT_MAIN:
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x1);
+		break;
+	case BTC_ANT_WIFI_AT_AUX:
+		btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, 0x30, 0x2);
+		break;
+	}
+}
+
+static void halbtc8821a2ant_ps_tdma(struct btc_coexist *btcoexist,
+				    bool force_exec, bool turn_on, u8 type)
+{
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], %s turn %s PS TDMA, type = %d\n",
+		  (force_exec ? "force to" : ""), (turn_on ? "ON" : "OFF"),
+		  type);
+	coex_dm->cur_ps_tdma_on = turn_on;
+	coex_dm->cur_ps_tdma = type;
+
+	if (!force_exec) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], pre_ps_tdma_on = %d, cur_ps_tdma_on = %d!!\n",
+			  coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], pre_ps_tdma = %d, cur_ps_tdma = %d!!\n",
+			  coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma);
+
+		if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) &&
+		    (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma))
+			return;
+	}
+	if (turn_on) {
+		switch (type) {
+		case 1:
+		default:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+						      0x1a, 0xe1, 0x90);
+			break;
+		case 2:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12,
+						      0x12, 0xe1, 0x90);
+			break;
+		case 3:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1c,
+						      0x3, 0xf1, 0x90);
+			break;
+		case 4:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x10,
+						      0x03, 0xf1, 0x90);
+			break;
+		case 5:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+						      0x1a, 0x60, 0x90);
+			break;
+		case 6:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12,
+						      0x12, 0x60, 0x90);
+			break;
+		case 7:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1c,
+						      0x3, 0x70, 0x90);
+			break;
+		case 8:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xa3, 0x10,
+						      0x3, 0x70, 0x90);
+			break;
+		case 9:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+						      0x1a, 0xe1, 0x90);
+			break;
+		case 10:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12,
+						      0x12, 0xe1, 0x90);
+			break;
+		case 11:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0xa,
+						      0xa, 0xe1, 0x90);
+			break;
+		case 12:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5,
+						      0x5, 0xe1, 0x90);
+			break;
+		case 13:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+						      0x1a, 0x60, 0x90);
+			break;
+		case 14:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3,
+						      0x12, 0x12, 0x60, 0x90);
+			break;
+		case 15:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0xa,
+						      0xa, 0x60, 0x90);
+			break;
+		case 16:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5,
+						      0x5, 0x60, 0x90);
+			break;
+		case 17:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xa3, 0x2f,
+						      0x2f, 0x60, 0x90);
+			break;
+		case 18:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5,
+						      0x5, 0xe1, 0x90);
+			break;
+		case 19:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x25,
+						      0x25, 0xe1, 0x90);
+			break;
+		case 20:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x25,
+						      0x25, 0x60, 0x90);
+			break;
+		case 21:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x15,
+						      0x03, 0x70, 0x90);
+			break;
+		case 71:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a,
+						      0x1a, 0xe1, 0x90);
+			break;
+		}
+	} else {
+		/* disable PS tdma */
+		switch (type) {
+		case 0:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+						      0x40, 0x0);
+			break;
+		case 1:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+						      0x48, 0x0);
+			break;
+		default:
+			halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, 0x0, 0x0,
+						      0x40, 0x0);
+			break;
+		}
+	}
+
+	/* update pre state */
+	coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on;
+	coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma;
+}
+
+static void halbtc8821a2ant_coex_all_off(struct btc_coexist *btcoexist)
+{
+	/* fw all off */
+	halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+	halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+	/* sw all off */
+	btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+	btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+
+	/* hw all off */
+	halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC,
+				   0x55555555, 0x55555555, 0xffff, 0x3);
+}
+
+static void halbtc8821a2ant_coex_under_5g(struct btc_coexist *btcoexist)
+{
+	halbtc8821a2ant_coex_all_off(btcoexist);
+}
+
+static void halbtc8821a2ant_init_coex_dm(struct btc_coexist *btcoexist)
+{
+	/* force to reset coex mechanism */
+	halbtc8821a2ant_coex_table(btcoexist, FORCE_EXEC, 0x55555555,
+				   0x55555555, 0xffff, 0x3);
+
+	halbtc8821a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1);
+	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6);
+	halbtc8821a2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, false);
+
+	btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+	btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+}
+
+static void halbtc8821a2ant_bt_inquiry_page(struct btc_coexist *btcoexist)
+{
+	bool low_pwr_disable = true;
+
+	btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+			   &low_pwr_disable);
+
+	halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+				   0x5afa5afa, 0xffff, 0x3);
+	halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3);
+}
+
+static bool halbtc8821a2ant_is_common_action(struct btc_coexist *btcoexist)
+{
+	bool common = false, wifi_connected = false, wifi_busy = false;
+	bool low_pwr_disable = false;
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED,
+			   &wifi_connected);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+
+	halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+				   0x5afa5afa, 0xffff, 0x3);
+
+	if (!wifi_connected &&
+	    BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status) {
+		low_pwr_disable = false;
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+				   &low_pwr_disable);
+
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi IPS + BT IPS!!\n");
+
+		halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+		btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+		btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+
+		common = true;
+	} else if (wifi_connected &&
+		   (BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status)) {
+		low_pwr_disable = false;
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+				   &low_pwr_disable);
+
+		if (wifi_busy) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Wifi Busy + BT IPS!!\n");
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 1);
+		} else {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Wifi LPS + BT IPS!!\n");
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 1);
+		}
+
+		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+		btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+		btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+
+		common = true;
+	} else if (!wifi_connected &&
+		   (BT_8821A_2ANT_BT_STATUS_CON_IDLE == coex_dm->bt_status)) {
+		low_pwr_disable = true;
+		btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER,
+				   &low_pwr_disable);
+
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi IPS + BT LPS!!\n");
+
+		halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+		btc8821a2ant_sw_mech1(btcoexist, false, false, false, false);
+		btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+		common = true;
+	} else if (wifi_connected &&
+		   (BT_8821A_2ANT_BT_STATUS_CON_IDLE == coex_dm->bt_status)) {
+		low_pwr_disable = true;
+		btcoexist->btc_set(btcoexist,
+			BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable);
+
+		if (wifi_busy) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Wifi Busy + BT LPS!!\n");
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 1);
+		} else {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Wifi LPS + BT LPS!!\n");
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 1);
+		}
+
+		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+		btc8821a2ant_sw_mech1(btcoexist, true, true, true, true);
+		btc8821a2ant_sw_mech2(btcoexist, false, false, false, 0x18);
+
+		common = true;
+	} else if (!wifi_connected &&
+		   (BT_8821A_2ANT_BT_STATUS_NON_IDLE ==
+		    coex_dm->bt_status)) {
+		low_pwr_disable = false;
+		btcoexist->btc_set(btcoexist,
+			BTC_SET_ACT_DISABLE_LOW_POWER, &low_pwr_disable);
+
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Wifi IPS + BT Busy!!\n");
+
+		halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+		btc8821a2ant_sw_mech1(btcoexist, false, false,
+				      false, false);
+		btc8821a2ant_sw_mech2(btcoexist, false, false,
+				      false, 0x18);
+
+		common = true;
+	} else {
+		low_pwr_disable = true;
+		btcoexist->btc_set(btcoexist,
+				   BTC_SET_ACT_DISABLE_LOW_POWER,
+				   &low_pwr_disable);
+
+		if (wifi_busy) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Wifi Busy + BT Busy!!\n");
+			common = false;
+		} else {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Wifi LPS + BT Busy!!\n");
+			halbtc8821a2ant_ps_tdma(btcoexist,
+						NORMAL_EXEC, true, 21);
+
+			if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+				halbtc8821a2ant_dec_bt_pwr(btcoexist,
+							   NORMAL_EXEC, true);
+			else
+				halbtc8821a2ant_dec_bt_pwr(btcoexist,
+							   NORMAL_EXEC, false);
+
+			common = true;
+		}
+		btc8821a2ant_sw_mech1(btcoexist, true, true, true, true);
+	}
+	return common;
+}
+
+static void btc8821a2_int1(struct btc_coexist *btcoexist, bool tx_pause,
+			   int result)
+{
+	if (tx_pause) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], TxPause = 1\n");
+
+		if (coex_dm->cur_ps_tdma == 71) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 5);
+			coex_dm->tdma_adj_type = 5;
+		} else if (coex_dm->cur_ps_tdma == 1) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 5);
+			coex_dm->tdma_adj_type = 5;
+		} else if (coex_dm->cur_ps_tdma == 2) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 6);
+			coex_dm->tdma_adj_type = 6;
+		} else if (coex_dm->cur_ps_tdma == 3) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 7);
+			coex_dm->tdma_adj_type = 7;
+		} else if (coex_dm->cur_ps_tdma == 4) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 8);
+			coex_dm->tdma_adj_type = 8;
+		}
+		if (coex_dm->cur_ps_tdma == 9) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 13);
+			coex_dm->tdma_adj_type = 13;
+		} else if (coex_dm->cur_ps_tdma == 10) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 14);
+			coex_dm->tdma_adj_type = 14;
+		} else if (coex_dm->cur_ps_tdma == 11) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 15);
+			coex_dm->tdma_adj_type = 15;
+		} else if (coex_dm->cur_ps_tdma == 12) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 16);
+			coex_dm->tdma_adj_type = 16;
+		}
+
+		if (result == -1) {
+			if (coex_dm->cur_ps_tdma == 5) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 6);
+				coex_dm->tdma_adj_type = 6;
+			} else if (coex_dm->cur_ps_tdma == 6) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 7) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 8);
+				coex_dm->tdma_adj_type = 8;
+			} else if (coex_dm->cur_ps_tdma == 13) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 14);
+				coex_dm->tdma_adj_type = 14;
+			} else if (coex_dm->cur_ps_tdma == 14) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 15) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 16);
+				coex_dm->tdma_adj_type = 16;
+			}
+		} else if (result == 1) {
+			if (coex_dm->cur_ps_tdma == 8) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 7) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 6);
+				coex_dm->tdma_adj_type = 6;
+			} else if (coex_dm->cur_ps_tdma == 6) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 5);
+				coex_dm->tdma_adj_type = 5;
+			} else if (coex_dm->cur_ps_tdma == 16) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 15) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 14);
+				coex_dm->tdma_adj_type = 14;
+			} else if (coex_dm->cur_ps_tdma == 14) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 13);
+				coex_dm->tdma_adj_type = 13;
+			}
+		}
+	} else {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], TxPause = 0\n");
+		if (coex_dm->cur_ps_tdma == 5) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 71);
+			coex_dm->tdma_adj_type = 71;
+		} else if (coex_dm->cur_ps_tdma == 6) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 2);
+			coex_dm->tdma_adj_type = 2;
+		} else if (coex_dm->cur_ps_tdma == 7) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 3);
+			coex_dm->tdma_adj_type = 3;
+		} else if (coex_dm->cur_ps_tdma == 8) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 4);
+			coex_dm->tdma_adj_type = 4;
+		}
+		if (coex_dm->cur_ps_tdma == 13) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 9);
+			coex_dm->tdma_adj_type = 9;
+		} else if (coex_dm->cur_ps_tdma == 14) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 10);
+			coex_dm->tdma_adj_type = 10;
+		} else if (coex_dm->cur_ps_tdma == 15) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			coex_dm->tdma_adj_type = 11;
+		} else if (coex_dm->cur_ps_tdma == 16) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 12);
+			coex_dm->tdma_adj_type = 12;
+		}
+
+		if (result == -1) {
+			if (coex_dm->cur_ps_tdma == 71) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 1);
+				coex_dm->tdma_adj_type = 1;
+			} else if (coex_dm->cur_ps_tdma == 1) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 4);
+				coex_dm->tdma_adj_type = 4;
+			} else if (coex_dm->cur_ps_tdma == 9) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 10);
+				coex_dm->tdma_adj_type = 10;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 12);
+				coex_dm->tdma_adj_type = 12;
+			}
+		} else if (result == 1) {
+			if (coex_dm->cur_ps_tdma == 4) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 1);
+				coex_dm->tdma_adj_type = 1;
+			} else if (coex_dm->cur_ps_tdma == 1) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 71);
+				coex_dm->tdma_adj_type = 71;
+			} else if (coex_dm->cur_ps_tdma == 12) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 10);
+				coex_dm->tdma_adj_type = 10;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 9);
+				coex_dm->tdma_adj_type = 9;
+			}
+		}
+	}
+}
+
+static void btc8821a2_int2(struct btc_coexist *btcoexist, bool tx_pause,
+			   int result)
+{
+	if (tx_pause) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], TxPause = 1\n");
+		if (coex_dm->cur_ps_tdma == 1) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 6);
+			coex_dm->tdma_adj_type = 6;
+		} else if (coex_dm->cur_ps_tdma == 2) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 6);
+			coex_dm->tdma_adj_type = 6;
+		} else if (coex_dm->cur_ps_tdma == 3) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 7);
+			coex_dm->tdma_adj_type = 7;
+		} else if (coex_dm->cur_ps_tdma == 4) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 8);
+			coex_dm->tdma_adj_type = 8;
+		}
+		if (coex_dm->cur_ps_tdma == 9) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 14);
+			coex_dm->tdma_adj_type = 14;
+		} else if (coex_dm->cur_ps_tdma == 10) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 14);
+			coex_dm->tdma_adj_type = 14;
+		} else if (coex_dm->cur_ps_tdma == 11) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 15);
+			coex_dm->tdma_adj_type = 15;
+		} else if (coex_dm->cur_ps_tdma == 12) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 16);
+			coex_dm->tdma_adj_type = 16;
+		}
+		if (result == -1) {
+			if (coex_dm->cur_ps_tdma == 5) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 6);
+				coex_dm->tdma_adj_type = 6;
+			} else if (coex_dm->cur_ps_tdma == 6) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 7) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 8);
+				coex_dm->tdma_adj_type = 8;
+			} else if (coex_dm->cur_ps_tdma == 13) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 14);
+				coex_dm->tdma_adj_type = 14;
+			} else if (coex_dm->cur_ps_tdma == 14) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 15) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 16);
+				coex_dm->tdma_adj_type = 16;
+			}
+		} else if (result == 1) {
+			if (coex_dm->cur_ps_tdma == 8) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 7) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 6);
+				coex_dm->tdma_adj_type = 6;
+			} else if (coex_dm->cur_ps_tdma == 6) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 6);
+				coex_dm->tdma_adj_type = 6;
+			} else if (coex_dm->cur_ps_tdma == 16) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 15) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 14);
+				coex_dm->tdma_adj_type = 14;
+			} else if (coex_dm->cur_ps_tdma == 14) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 14);
+				coex_dm->tdma_adj_type = 14;
+			}
+		}
+	} else {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], TxPause = 0\n");
+		if (coex_dm->cur_ps_tdma == 5) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 2);
+			coex_dm->tdma_adj_type = 2;
+		} else if (coex_dm->cur_ps_tdma == 6) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 2);
+			coex_dm->tdma_adj_type = 2;
+		} else if (coex_dm->cur_ps_tdma == 7) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 3);
+			coex_dm->tdma_adj_type = 3;
+		} else if (coex_dm->cur_ps_tdma == 8) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 4);
+			coex_dm->tdma_adj_type = 4;
+		}
+		if (coex_dm->cur_ps_tdma == 13) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 10);
+			coex_dm->tdma_adj_type = 10;
+		} else if (coex_dm->cur_ps_tdma == 14) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 10);
+			coex_dm->tdma_adj_type = 10;
+		} else if (coex_dm->cur_ps_tdma == 15) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			coex_dm->tdma_adj_type = 11;
+		} else if (coex_dm->cur_ps_tdma == 16) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 12);
+			coex_dm->tdma_adj_type = 12;
+		}
+		if (result == -1) {
+			if (coex_dm->cur_ps_tdma == 1) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 4);
+				coex_dm->tdma_adj_type = 4;
+			} else if (coex_dm->cur_ps_tdma == 9) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 10);
+				coex_dm->tdma_adj_type = 10;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 12);
+				coex_dm->tdma_adj_type = 12;
+			}
+		} else if (result == 1) {
+			if (coex_dm->cur_ps_tdma == 4) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 2);
+				coex_dm->tdma_adj_type = 2;
+			} else if (coex_dm->cur_ps_tdma == 12) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 10);
+				coex_dm->tdma_adj_type = 10;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 10);
+				coex_dm->tdma_adj_type = 10;
+			}
+		}
+	}
+}
+
+static void btc8821a2_int3(struct btc_coexist *btcoexist, bool tx_pause,
+			   int result)
+{
+	if (tx_pause) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], TxPause = 1\n");
+		if (coex_dm->cur_ps_tdma == 1) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 7);
+			coex_dm->tdma_adj_type = 7;
+		} else if (coex_dm->cur_ps_tdma == 2) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 7);
+			coex_dm->tdma_adj_type = 7;
+		} else if (coex_dm->cur_ps_tdma == 3) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 7);
+			coex_dm->tdma_adj_type = 7;
+		} else if (coex_dm->cur_ps_tdma == 4) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 8);
+			coex_dm->tdma_adj_type = 8;
+		}
+		if (coex_dm->cur_ps_tdma == 9) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 15);
+			coex_dm->tdma_adj_type = 15;
+		} else if (coex_dm->cur_ps_tdma == 10) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 15);
+			coex_dm->tdma_adj_type = 15;
+		} else if (coex_dm->cur_ps_tdma == 11) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 15);
+			coex_dm->tdma_adj_type = 15;
+		} else if (coex_dm->cur_ps_tdma == 12) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 16);
+			coex_dm->tdma_adj_type = 16;
+		}
+		if (result == -1) {
+			if (coex_dm->cur_ps_tdma == 5) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 6) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 7) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 8);
+				coex_dm->tdma_adj_type = 8;
+			} else if (coex_dm->cur_ps_tdma == 13) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 14) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 15) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 16);
+				coex_dm->tdma_adj_type = 16;
+			}
+		} else if (result == 1) {
+			if (coex_dm->cur_ps_tdma == 8) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 7) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 6) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 7);
+				coex_dm->tdma_adj_type = 7;
+			} else if (coex_dm->cur_ps_tdma == 16) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 15) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			} else if (coex_dm->cur_ps_tdma == 14) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 15);
+				coex_dm->tdma_adj_type = 15;
+			}
+		}
+	} else {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], TxPause = 0\n");
+		if (coex_dm->cur_ps_tdma == 5) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 3);
+			coex_dm->tdma_adj_type = 3;
+		} else if (coex_dm->cur_ps_tdma == 6) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 3);
+			coex_dm->tdma_adj_type = 3;
+		} else if (coex_dm->cur_ps_tdma == 7) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 3);
+			coex_dm->tdma_adj_type = 3;
+		} else if (coex_dm->cur_ps_tdma == 8) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 4);
+			coex_dm->tdma_adj_type = 4;
+		}
+		if (coex_dm->cur_ps_tdma == 13) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			coex_dm->tdma_adj_type = 11;
+		} else if (coex_dm->cur_ps_tdma == 14) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			coex_dm->tdma_adj_type = 11;
+		} else if (coex_dm->cur_ps_tdma == 15) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 11);
+			coex_dm->tdma_adj_type = 11;
+		} else if (coex_dm->cur_ps_tdma == 16) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 12);
+			coex_dm->tdma_adj_type = 12;
+		}
+		if (result == -1) {
+			if (coex_dm->cur_ps_tdma == 1) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 4);
+				coex_dm->tdma_adj_type = 4;
+			} else if (coex_dm->cur_ps_tdma == 9) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 12);
+				coex_dm->tdma_adj_type = 12;
+			}
+		} else if (result == 1) {
+			if (coex_dm->cur_ps_tdma == 4) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 3) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 2) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 3);
+				coex_dm->tdma_adj_type = 3;
+			} else if (coex_dm->cur_ps_tdma == 12) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 11) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			} else if (coex_dm->cur_ps_tdma == 10) {
+				halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+							true, 11);
+				coex_dm->tdma_adj_type = 11;
+			}
+		}
+	}
+}
+
+static void btc8821a2ant_tdma_dur_adj(struct btc_coexist *btcoexist,
+				      bool sco_hid, bool tx_pause,
+				      u8 max_interval)
+{
+	static long	up, dn, m, n, wait_count;
+	 /* 0: no change, +1: increase WiFi duration,
+	  * -1: decrease WiFi duration
+	  */
+	int		result;
+	u8		retry_count = 0;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW,
+		  "[BTCoex], TdmaDurationAdjust()\n");
+
+	if (coex_dm->reset_tdma_adjust) {
+		coex_dm->reset_tdma_adjust = false;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], first run TdmaDurationAdjust()!!\n");
+		if (sco_hid) {
+			if (tx_pause) {
+				if (max_interval == 1) {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 13);
+					coex_dm->tdma_adj_type = 13;
+				} else if (max_interval == 2) {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 14);
+					coex_dm->tdma_adj_type = 14;
+				} else if (max_interval == 3) {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 15);
+					coex_dm->tdma_adj_type = 15;
+				} else {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 15);
+					coex_dm->tdma_adj_type = 15;
+				}
+			} else {
+				if (max_interval == 1) {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 9);
+					coex_dm->tdma_adj_type = 9;
+				} else if (max_interval == 2) {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 10);
+					coex_dm->tdma_adj_type = 10;
+				} else if (max_interval == 3) {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 11);
+					coex_dm->tdma_adj_type = 11;
+				} else {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 11);
+					coex_dm->tdma_adj_type = 11;
+				}
+			}
+		} else {
+			if (tx_pause) {
+				if (max_interval == 1) {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 5);
+					coex_dm->tdma_adj_type = 5;
+				} else if (max_interval == 2) {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 6);
+					coex_dm->tdma_adj_type = 6;
+				} else if (max_interval == 3) {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 7);
+					coex_dm->tdma_adj_type = 7;
+				} else {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 7);
+					coex_dm->tdma_adj_type = 7;
+				}
+			} else {
+				if (max_interval == 1) {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 1);
+					coex_dm->tdma_adj_type = 1;
+				} else if (max_interval == 2) {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 2);
+					coex_dm->tdma_adj_type = 2;
+				} else if (max_interval == 3) {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 3);
+					coex_dm->tdma_adj_type = 3;
+				} else {
+					halbtc8821a2ant_ps_tdma(btcoexist,
+								NORMAL_EXEC,
+								true, 3);
+					coex_dm->tdma_adj_type = 3;
+				}
+			}
+		}
+
+		up = 0;
+		dn = 0;
+		m = 1;
+		n = 3;
+		result = 0;
+		wait_count = 0;
+	} else {
+		/* accquire the BT TRx retry count from BT_Info byte2 */
+		retry_count = coex_sta->bt_retry_cnt;
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], retry_count = %d\n", retry_count);
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], up = %d, dn = %d, m = %d, n = %d, wait_count = %d\n",
+			  (int)up, (int)dn, (int)m, (int)n, (int)wait_count);
+		result = 0;
+		wait_count++;
+
+		if (retry_count == 0) {
+			/* no retry in the last 2-second duration */
+			up++;
+			dn--;
+
+			if (dn <= 0)
+				dn = 0;
+
+			if (up >= n) {
+				/* if (retry count == 0) for 2*n seconds,
+				 * make WiFi duration wider
+				 */
+				wait_count = 0;
+				n = 3;
+				up = 0;
+				dn = 0;
+				result = 1;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_TRACE_FW_DETAIL,
+					  "[BTCoex], Increase wifi duration!!\n");
+			}
+		} else if (retry_count <= 3) {
+			/* <=3 retry in the last 2-second duration */
+			up--;
+			dn++;
+
+			if (up <= 0)
+				up = 0;
+
+			if (dn == 2) {
+				/* if retry count< 3 for 2*2 seconds,
+				 * shrink wifi duration
+				 */
+				if (wait_count <= 2)
+					m++; /* avoid bounce in two levels */
+				else
+					m = 1;
+				/* m max value is 20, max time is 120 second,
+				 * recheck if adjust WiFi duration.
+				 */
+				if (m >= 20)
+					m = 20;
+
+				n = 3*m;
+				up = 0;
+				dn = 0;
+				wait_count = 0;
+				result = -1;
+				BTC_PRINT(BTC_MSG_ALGORITHM,
+					  ALGO_TRACE_FW_DETAIL,
+					  "[BTCoex], Decrease wifi duration for retryCounter<3!!\n");
+			}
+		} else {
+			/* retry count > 3, if retry count > 3 happens once,
+			 * shrink WiFi duration
+			 */
+			if (wait_count == 1)
+				m++; /* avoid bounce in two levels */
+			else
+				m = 1;
+			/* m max value is 20, max time is 120 second,
+			 * recheck if adjust WiFi duration.
+			 */
+			if (m >= 20)
+				m = 20;
+
+			n = 3*m;
+			up = 0;
+			dn = 0;
+			wait_count = 0;
+			result = -1;
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex], Decrease wifi duration for retryCounter>3!!\n");
+		}
+
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], max Interval = %d\n", max_interval);
+		if (max_interval == 1)
+			btc8821a2_int1(btcoexist, tx_pause, result);
+		else if (max_interval == 2)
+			btc8821a2_int2(btcoexist, tx_pause, result);
+		else if (max_interval == 3)
+			btc8821a2_int3(btcoexist, tx_pause, result);
+	}
+
+	/* if current PsTdma not match with the recorded one
+	 * (when scan, dhcp...), then we have to adjust it back to
+	 * the previous recorded one.
+	 */
+	if (coex_dm->cur_ps_tdma != coex_dm->tdma_adj_type) {
+		bool	scan = false, link = false, roam = false;
+
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+			  "[BTCoex], PsTdma type dismatch!!!, cur_ps_tdma = %d, recordPsTdma = %d\n",
+			  coex_dm->cur_ps_tdma, coex_dm->tdma_adj_type);
+
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+		btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+
+		if (!scan && !link && !roam) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true,
+						coex_dm->tdma_adj_type);
+		} else {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL,
+				  "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n");
+		}
+	}
+
+	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6);
+}
+
+/* SCO only or SCO+PAN(HS)*/
+static void halbtc8821a2ant_action_sco(struct btc_coexist *btcoexist)
+{
+	u8	wifi_rssi_state, bt_rssi_state;
+	u32 wifi_bw;
+
+	wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+							  15, 0);
+	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4);
+
+	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+	else
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+		/* for SCO quality at 11b/g mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC,
+					   0x5a5a5a5a, 0x5a5a5a5a, 0xffff, 0x3);
+	} else {
+		/* for SCO quality & wifi performance balance at 11n mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC,
+					   0x5aea5aea, 0x5aea5aea, 0xffff, 0x3);
+	}
+
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		/* fw mechanism
+		 * halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+		 */
+
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 0); /*for voice quality*/
+		} else {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 0); /*for voice quality*/
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, true, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, true, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	} else {
+		/* fw mechanism
+		 * halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5);
+		 */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 0); /*for voice quality*/
+		} else {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 0); /*for voice quality*/
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, false, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, false, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	}
+}
+
+static void halbtc8821a2ant_action_hid(struct btc_coexist *btcoexist)
+{
+	u8	wifi_rssi_state, bt_rssi_state;
+	u32	wifi_bw;
+
+	wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist,
+							  0, 2, 15, 0);
+	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+	else
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+		/* for HID at 11b/g mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+					   0x5a5a5a5a, 0xffff, 0x3);
+	} else {
+		/* for HID quality & wifi performance balance at 11n mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+					   0x5aea5aea, 0xffff, 0x3);
+	}
+
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 9);
+		} else {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 13);
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, true, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, true, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	} else {
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 9);
+		} else {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 13);
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, false, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, false, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	}
+}
+
+/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */
+static void halbtc8821a2ant_action_a2dp(struct btc_coexist *btcoexist)
+{
+	u8		wifi_rssi_state, bt_rssi_state;
+	u32		wifi_bw;
+
+	wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+							  15, 0);
+	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+	/* fw dac swing is called in btc8821a2ant_tdma_dur_adj()
+	 * halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+	 */
+
+	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+	else
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_tdma_dur_adj(btcoexist, false, false, 1);
+		} else {
+			btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1);
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, true, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, true, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	} else {
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_tdma_dur_adj(btcoexist, false, false, 1);
+		} else {
+			btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1);
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, false, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, false, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	}
+}
+
+static void halbtc8821a2ant_action_a2dp_pan_hs(struct btc_coexist *btcoexist)
+{
+	u8		wifi_rssi_state, bt_rssi_state, bt_info_ext;
+	u32		wifi_bw;
+
+	bt_info_ext = coex_sta->bt_info_ext;
+	wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+							  15, 0);
+	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+	/*fw dac swing is called in btc8821a2ant_tdma_dur_adj()
+	 *halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+	 */
+
+	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+	else
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		/* fw mechanism */
+		if (bt_info_ext&BIT0) {
+			/*a2dp basic rate*/
+			btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 2);
+		} else {
+			/*a2dp edr rate*/
+			btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1);
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, true, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, true, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	} else {
+		/* fw mechanism */
+		if (bt_info_ext&BIT0) {
+			/* a2dp basic rate */
+			btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 2);
+		} else {
+			/* a2dp edr rate */
+			btc8821a2ant_tdma_dur_adj(btcoexist, false, true, 1);
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, false, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, false, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	}
+}
+
+static void halbtc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist)
+{
+	u8		wifi_rssi_state, bt_rssi_state;
+	u32		wifi_bw;
+
+	wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+							  15, 0);
+	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+	else
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+		/* for HID at 11b/g mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+					   0x5aff5aff, 0xffff, 0x3);
+	} else {
+		/* for HID quality & wifi performance balance at 11n mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+					   0x5aff5aff, 0xffff, 0x3);
+	}
+
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 1);
+		} else {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 5);
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, true, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, true, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	} else {
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 1);
+		} else {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 5);
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, false, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, false, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	}
+}
+
+/* PAN(HS) only */
+static void halbtc8821a2ant_action_pan_hs(struct btc_coexist *btcoexist)
+{
+	u8		wifi_rssi_state, bt_rssi_state;
+	u32		wifi_bw;
+
+	wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist,
+							  0, 2, 15, 0);
+	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		/* fw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC,
+						   true);
+		} else {
+			halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC,
+						   false);
+		}
+		halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1);
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, true, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, true, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	} else {
+		/* fw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8821a2ant_dec_bt_pwr(btcoexist,
+						   NORMAL_EXEC, true);
+		} else {
+			halbtc8821a2ant_dec_bt_pwr(btcoexist,
+						   NORMAL_EXEC, false);
+		}
+
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 1);
+		} else {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						false, 1);
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, false, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, false, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	}
+}
+
+/* PAN(EDR)+A2DP */
+static void halbtc8821a2ant_action_pan_edr_a2dp(struct btc_coexist *btcoexist)
+{
+	u8	wifi_rssi_state, bt_rssi_state, bt_info_ext;
+	u32	wifi_bw;
+
+	bt_info_ext = coex_sta->bt_info_ext;
+	wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+							  15, 0);
+	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+	else
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+		/* for HID at 11b/g mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+					   0x5afa5afa, 0xffff, 0x3);
+	} else {
+		/* for HID quality & wifi performance balance at 11n mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+					   0x5afa5afa, 0xffff, 0x3);
+	}
+
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			if (bt_info_ext&BIT0) {
+				/* a2dp basic rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, false,
+							  false, 3);
+			} else {
+				/* a2dp edr rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, false,
+							  false, 3);
+			}
+		} else {
+			if (bt_info_ext&BIT0) {
+				/* a2dp basic rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, false,
+							  true, 3);
+			} else {
+				/* a2dp edr rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, false,
+							  true, 3);
+			}
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, true, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, true, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		};
+	} else {
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			if (bt_info_ext&BIT0) {
+				/* a2dp basic rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, false,
+							  false, 3);
+			} else {
+				/* a2dp edr rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, false,
+							  false, 3);
+			}
+		} else {
+			if (bt_info_ext&BIT0) {
+				/* a2dp basic rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, false,
+							  true, 3);
+			} else {
+				/* a2dp edr rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, false,
+							  true, 3);
+			}
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, false, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, false, false,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	}
+}
+
+static void halbtc8821a2ant_action_pan_edr_hid(struct btc_coexist *btcoexist)
+{
+	u8	wifi_rssi_state, bt_rssi_state;
+	u32	wifi_bw;
+
+	wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+							  15, 0);
+	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+	else
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+		/* for HID at 11b/g mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+					   0x5a5f5a5f, 0xffff, 0x3);
+	} else {
+		/* for HID quality & wifi performance balance at 11n mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+					   0x5a5f5a5f, 0xffff, 0x3);
+	}
+
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 3);
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 10);
+		} else {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 14);
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, true, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, true, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	} else {
+		halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 10);
+		} else {
+			halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC,
+						true, 14);
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, false, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, false, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	}
+}
+
+/* HID+A2DP+PAN(EDR) */
+static void btc8821a2ant_act_hid_a2dp_pan_edr(struct btc_coexist *btcoexist)
+{
+	u8	wifi_rssi_state, bt_rssi_state, bt_info_ext;
+	u32	wifi_bw;
+
+	bt_info_ext = coex_sta->bt_info_ext;
+	wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist,
+							  0, 2, 15, 0);
+	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+	halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6);
+
+	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+	else
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+		/* for HID at 11b/g mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+					   0x5a5a5a5a, 0xffff, 0x3);
+	} else {
+		/* for HID quality & wifi performance balance at 11n mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+					   0x5a5a5a5a, 0xffff, 0x3);
+	}
+
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			if (bt_info_ext&BIT0) {
+				/* a2dp basic rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, true,
+							  true, 3);
+			} else {
+				/* a2dp edr rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, true,
+							  true, 3);
+			}
+		} else {
+			if (bt_info_ext&BIT0) {
+				/* a2dp basic rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, true,
+							  true, 3);
+			} else {
+				/* a2dp edr rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, true,
+							  true, 3);
+			}
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, true, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, true, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	} else {
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			if (bt_info_ext&BIT0) {
+				/* a2dp basic rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, true,
+							  false, 3);
+			} else {
+				/* a2dp edr rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, true,
+							  false, 3);
+			}
+		} else {
+			if (bt_info_ext&BIT0) {
+				/* a2dp basic rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, true,
+							  true, 3);
+			} else {
+				/* a2dp edr rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist, true,
+							  true, 3);
+			}
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, false, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, false, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	}
+}
+
+static void halbtc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist)
+{
+	u8	wifi_rssi_state, bt_rssi_state, bt_info_ext;
+	u32	wifi_bw;
+
+	bt_info_ext = coex_sta->bt_info_ext;
+	wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2,
+							  15, 0);
+	bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 35, 0);
+
+	if (halbtc8821a2ant_need_to_dec_bt_pwr(btcoexist))
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, true);
+	else
+		halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, false);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+
+	if (BTC_WIFI_BW_LEGACY == wifi_bw) {
+		/* for HID at 11b/g mode */
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+					   0x5f5b5f5b, 0xffffff, 0x3);
+	} else {
+		/*for HID quality & wifi performance balance at 11n mode*/
+		halbtc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff,
+					   0x5f5b5f5b, 0xffffff, 0x3);
+	}
+
+	if (BTC_WIFI_BW_HT40 == wifi_bw) {
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			if (bt_info_ext&BIT0) {
+				/* a2dp basic rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist,
+							  true, true, 2);
+			} else {
+				/* a2dp edr rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist,
+							  true, true, 2);
+			}
+		} else {
+			if (bt_info_ext&BIT0) {
+				/* a2dp basic rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist,
+							  true, true, 2);
+			} else {
+				/* a2dp edr rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist,
+							  true, true, 2);
+			}
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, true, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, true, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	} else {
+		/* fw mechanism */
+		if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			if (bt_info_ext&BIT0) {
+				/* a2dp basic rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist,
+							  true, true, 2);
+
+			} else {
+				/* a2dp edr rate */
+				btc8821a2ant_tdma_dur_adj(btcoexist,
+							  true, true, 2);
+			}
+		} else {
+			if (bt_info_ext&BIT0) {
+				/*a2dp basic rate*/
+				btc8821a2ant_tdma_dur_adj(btcoexist,
+							  true, true, 2);
+			} else {
+				/*a2dp edr rate*/
+				btc8821a2ant_tdma_dur_adj(btcoexist,
+							  true, true, 2);
+			}
+		}
+
+		/* sw mechanism */
+		if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) ||
+		    (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) {
+			btc8821a2ant_sw_mech1(btcoexist, false, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, true, false,
+					      false, 0x18);
+		} else {
+			btc8821a2ant_sw_mech1(btcoexist, false, true,
+					      false, false);
+			btc8821a2ant_sw_mech2(btcoexist, false, false,
+					      false, 0x18);
+		}
+	}
+}
+
+static void halbtc8821a2ant_run_coexist_mechanism(struct btc_coexist *btcoexist)
+{
+	bool	wifi_under_5g = false;
+	u8	algorithm = 0;
+
+	if (btcoexist->manual_control) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Manual control!!!\n");
+		return;
+	}
+
+	btcoexist->btc_get(btcoexist,
+		BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+
+	if (wifi_under_5g) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], RunCoexistMechanism(), run 5G coex setting!!<===\n");
+		halbtc8821a2ant_coex_under_5g(btcoexist);
+		return;
+	}
+
+	algorithm = halbtc8821a2ant_action_algorithm(btcoexist);
+	if (coex_sta->c2h_bt_inquiry_page &&
+	    (BT_8821A_2ANT_COEX_ALGO_PANHS != algorithm)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], BT is under inquiry/page scan !!\n");
+		halbtc8821a2ant_bt_inquiry_page(btcoexist);
+		return;
+	}
+
+	coex_dm->cur_algorithm = algorithm;
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], Algorithm = %d\n", coex_dm->cur_algorithm);
+
+	if (halbtc8821a2ant_is_common_action(btcoexist)) {
+		BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+			  "[BTCoex], Action 2-Ant common.\n");
+		coex_dm->reset_tdma_adjust = true;
+	} else {
+		if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) {
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], pre_algorithm = %d, cur_algorithm = %d\n",
+			coex_dm->pre_algorithm, coex_dm->cur_algorithm);
+			coex_dm->reset_tdma_adjust = true;
+		}
+		switch (coex_dm->cur_algorithm) {
+		case BT_8821A_2ANT_COEX_ALGO_SCO:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action 2-Ant, algorithm = SCO.\n");
+			halbtc8821a2ant_action_sco(btcoexist);
+			break;
+		case BT_8821A_2ANT_COEX_ALGO_HID:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action 2-Ant, algorithm = HID.\n");
+			halbtc8821a2ant_action_hid(btcoexist);
+			break;
+		case BT_8821A_2ANT_COEX_ALGO_A2DP:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action 2-Ant, algorithm = A2DP.\n");
+			halbtc8821a2ant_action_a2dp(btcoexist);
+			break;
+		case BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n");
+			halbtc8821a2ant_action_a2dp_pan_hs(btcoexist);
+			break;
+		case BT_8821A_2ANT_COEX_ALGO_PANEDR:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n");
+			halbtc8821a2ant_action_pan_edr(btcoexist);
+			break;
+		case BT_8821A_2ANT_COEX_ALGO_PANHS:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action 2-Ant, algorithm = HS mode.\n");
+			halbtc8821a2ant_action_pan_hs(btcoexist);
+			break;
+		case BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n");
+			halbtc8821a2ant_action_pan_edr_a2dp(btcoexist);
+			break;
+		case BT_8821A_2ANT_COEX_ALGO_PANEDR_HID:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n");
+			halbtc8821a2ant_action_pan_edr_hid(btcoexist);
+			break;
+		case BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n");
+			btc8821a2ant_act_hid_a2dp_pan_edr(btcoexist);
+			break;
+		case BT_8821A_2ANT_COEX_ALGO_HID_A2DP:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n");
+			halbtc8821a2ant_action_hid_a2dp(btcoexist);
+			break;
+		default:
+			BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+				  "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n");
+			halbtc8821a2ant_coex_all_off(btcoexist);
+			break;
+		}
+		coex_dm->pre_algorithm = coex_dm->cur_algorithm;
+	}
+}
+
+/*============================================================
+ *work around function start with wa_halbtc8821a2ant_
+ *============================================================
+ *============================================================
+ * extern function start with EXhalbtc8821a2ant_
+ *============================================================
+ */
+void ex_halbtc8821a2ant_init_hwconfig(struct btc_coexist *btcoexist)
+{
+	u8 u1tmp = 0;
+
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+		  "[BTCoex], 2Ant Init HW Config!!\n");
+
+	/* backup rf 0x1e value */
+	coex_dm->bt_rf0x1e_backup =
+		btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff);
+
+	/* 0x790[5:0] = 0x5 */
+	u1tmp = btcoexist->btc_read_1byte(btcoexist, 0x790);
+	u1tmp &= 0xc0;
+	u1tmp |= 0x5;
+	btcoexist->btc_write_1byte(btcoexist, 0x790, u1tmp);
+
+	/*Antenna config */
+	halbtc8821a2ant_set_ant_path(btcoexist,
+				     BTC_ANT_WIFI_AT_MAIN, true, false);
+
+	/* PTA parameter */
+	halbtc8821a2ant_coex_table(btcoexist,
+				   FORCE_EXEC, 0x55555555, 0x55555555,
+				   0xffff, 0x3);
+
+	/* Enable counter statistics */
+	/*0x76e[3] = 1, WLAN_Act control by PTA*/
+	btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc);
+	btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3);
+	btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1);
+}
+
+void
+ex_halbtc8821a2ant_init_coex_dm(
+	struct btc_coexist *btcoexist
+	)
+{
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+		  "[BTCoex], Coex Mechanism Init!!\n");
+
+	halbtc8821a2ant_init_coex_dm(btcoexist);
+}
+
+void
+ex_halbtc8821a2ant_display_coex_info(
+	struct btc_coexist *btcoexist
+	)
+{
+	struct btc_board_info *board_info = &btcoexist->board_info;
+	struct btc_stack_info *stack_info = &btcoexist->stack_info;
+	struct rtl_priv *rtlpriv = btcoexist->adapter;
+	u8 u1tmp[4], i, bt_info_ext, ps_tdma_case = 0;
+	u32 u4tmp[4];
+	bool roam = false, scan = false, link = false, wifi_under_5g = false;
+	bool bt_hs_on = false, wifi_busy = false;
+	long wifi_rssi = 0, bt_hs_rssi = 0;
+	u32 wifi_bw, wifi_traffic_dir;
+	u8 wifi_dot_11_chnl, wifi_hs_chnl;
+	u32 fw_ver = 0, bt_patch_ver = 0;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n ============[BT Coexist info]============");
+
+	if (!board_info->bt_exist) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n BT not exists !!!");
+		return;
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:",
+		   board_info->pg_ant_num, board_info->btdm_ant_num);
+
+	if (btcoexist->manual_control) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n %-35s", "[Action Manual control]!!");
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %s / %d", "BT stack/ hci ext ver",
+		   ((stack_info->profile_notified) ? "Yes" : "No"),
+		   stack_info->hci_version);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);
+	btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)",
+		   "CoexVer/ FwVer/ PatchVer",
+		   glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant,
+		   fw_ver, bt_patch_ver, bt_patch_ver);
+
+	btcoexist->btc_get(btcoexist,
+		BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+	btcoexist->btc_get(btcoexist,
+		BTC_GET_U1_WIFI_DOT11_CHNL, &wifi_dot_11_chnl);
+	btcoexist->btc_get(btcoexist,
+		BTC_GET_U1_WIFI_HS_CHNL, &wifi_hs_chnl);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d / %d(%d)",
+		   "Dot11 channel / HsMode(HsChnl)",
+		   wifi_dot_11_chnl, bt_hs_on, wifi_hs_chnl);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %02x %02x %02x ",
+		   "H2C Wifi inform bt chnl Info",
+		   coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1],
+		   coex_dm->wifi_chnl_info[2]);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi);
+	btcoexist->btc_get(btcoexist, BTC_GET_S4_HS_RSSI, &bt_hs_rssi);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %ld/ %ld", "Wifi rssi/ HS rssi",
+		   wifi_rssi, bt_hs_rssi);
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link);
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d/ %d/ %d ", "Wifi link/ roam/ scan",
+		   link, roam, scan);
+
+	btcoexist->btc_get(btcoexist,
+		BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g);
+	btcoexist->btc_get(btcoexist,
+		BTC_GET_U4_WIFI_BW, &wifi_bw);
+	btcoexist->btc_get(btcoexist,
+		BTC_GET_BL_WIFI_BUSY, &wifi_busy);
+	btcoexist->btc_get(btcoexist,
+		BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifi_traffic_dir);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %s / %s/ %s ", "Wifi status",
+		   (wifi_under_5g ? "5G" : "2.4G"),
+		   ((BTC_WIFI_BW_LEGACY == wifi_bw) ? "Legacy" :
+		    (((BTC_WIFI_BW_HT40 == wifi_bw) ? "HT40" : "HT20"))),
+		   ((!wifi_busy) ? "idle" :
+		    ((BTC_WIFI_TRAFFIC_TX == wifi_traffic_dir) ?
+		     "uplink" : "downlink")));
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]",
+		   ((coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") :
+		    ((BT_8821A_2ANT_BT_STATUS_IDLE == coex_dm->bt_status)
+		     ? "idle" : ((BT_8821A_2ANT_BT_STATUS_CON_IDLE ==
+		     coex_dm->bt_status) ? "connected-idle" : "busy"))),
+		    coex_sta->bt_rssi, coex_sta->bt_retry_cnt);
+
+	if (stack_info->profile_notified) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP",
+			   stack_info->sco_exist, stack_info->hid_exist,
+			   stack_info->pan_exist, stack_info->a2dp_exist);
+
+		btcoexist->btc_disp_dbg_msg(btcoexist,
+					    BTC_DBG_DISP_BT_LINK_INFO);
+	}
+
+	bt_info_ext = coex_sta->bt_info_ext;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s",
+		   "BT Info A2DP rate",
+		   (bt_info_ext&BIT0) ? "Basic rate" : "EDR rate");
+
+	for (i = 0; i < BT_INFO_SRC_8821A_2ANT_MAX; i++) {
+		if (coex_sta->bt_info_c2h_cnt[i]) {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+				   "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)",
+				   glbt_info_src_8821a_2ant[i],
+				   coex_sta->bt_info_c2h[i][0],
+				   coex_sta->bt_info_c2h[i][1],
+				   coex_sta->bt_info_c2h[i][2],
+				   coex_sta->bt_info_c2h[i][3],
+				   coex_sta->bt_info_c2h[i][4],
+				   coex_sta->bt_info_c2h[i][5],
+				   coex_sta->bt_info_c2h[i][6],
+				   coex_sta->bt_info_c2h_cnt[i]);
+		}
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %s/%s",
+		   "PS state, IPS/LPS",
+		   ((coex_sta->under_ips ? "IPS ON" : "IPS OFF")),
+		   ((coex_sta->under_lps ? "LPS ON" : "LPS OFF")));
+	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD);
+
+	/* Sw mechanism*/
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+		   "============[Sw mechanism]============");
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d/ %d/ %d/ %d ",
+		   "SM1[ShRf/ LpRA/ LimDig/ btLna]",
+		   coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra,
+		   coex_dm->limited_dig, coex_dm->cur_bt_lna_constrain);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = %d/ %d/ %d(0x%x) ",
+		   "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]",
+		   coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off,
+		   coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl);
+
+	/* Fw mechanism*/
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s",
+		   "============[Fw mechanism]============");
+
+	if (!btcoexist->manual_control) {
+		ps_tdma_case = coex_dm->cur_ps_tdma;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n %-35s = %02x %02x %02x %02x %02x case-%d",
+			   "PS TDMA",
+			   coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1],
+			   coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3],
+			   coex_dm->ps_tdma_para[4], ps_tdma_case);
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			   "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct",
+			   coex_dm->cur_dec_bt_pwr,
+			   coex_dm->cur_ignore_wlan_act);
+	}
+
+	/* Hw setting*/
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s", "============[Hw setting]============");
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		   "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal",
+		   coex_dm->bt_rf0x1e_backup);
+
+	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778);
+	u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x6cc);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x ",
+		   "0x778 (W_Act)/ 0x6cc (CoTab Sel)",
+		   u1tmp[0], u1tmp[1]);
+
+	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db);
+	u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xc5b);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+		   "0x8db(ADC)/0xc5b[29:25](DAC)",
+		   ((u1tmp[0]&0x60)>>5), ((u1tmp[1]&0x3e)>>1));
+
+	u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+		   "0xcb4[7:0](ctrl)/ 0xcb4[29:28](val)",
+		   u4tmp[0]&0xff, ((u4tmp[0]&0x30000000)>>28));
+
+	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40);
+	u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c);
+	u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x974);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+		   "0x40/ 0x4c[24:23]/ 0x974",
+		   u1tmp[0], ((u4tmp[0]&0x01800000)>>23), u4tmp[1]);
+
+	u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550);
+	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+		   "0x550(bcn ctrl)/0x522",
+		   u4tmp[0], u1tmp[0]);
+
+	u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50);
+	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa0a);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+		   "0xc50(DIG)/0xa0a(CCK-TH)",
+		   u4tmp[0], u1tmp[0]);
+
+	u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xf48);
+	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b);
+	u1tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x",
+		   "OFDM-FA/ CCK-FA",
+		   u4tmp[0], (u1tmp[0]<<8) + u1tmp[1]);
+
+	u4tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0);
+	u4tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4);
+	u4tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x",
+		   "0x6c0/0x6c4/0x6c8",
+		   u4tmp[0], u4tmp[1], u4tmp[2]);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+		   "0x770 (hi-pri Rx/Tx)",
+		   coex_sta->high_priority_rx, coex_sta->high_priority_tx);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = %d/ %d",
+		   "0x774(low-pri Rx/Tx)",
+		   coex_sta->low_priority_rx, coex_sta->low_priority_tx);
+
+	/* Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang*/
+	u1tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x41b);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "\r\n %-35s = 0x%x",
+		   "0x41b (mgntQ hang chk == 0xf)",
+		   u1tmp[0]);
+
+	btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS);
+}
+
+void ex_halbtc8821a2ant_ips_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	if (BTC_IPS_ENTER == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], IPS ENTER notify\n");
+		coex_sta->under_ips = true;
+		halbtc8821a2ant_coex_all_off(btcoexist);
+	} else if (BTC_IPS_LEAVE == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], IPS LEAVE notify\n");
+		coex_sta->under_ips = false;
+		/*halbtc8821a2ant_init_coex_dm(btcoexist);*/
+	}
+}
+
+void ex_halbtc8821a2ant_lps_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	if (BTC_LPS_ENABLE == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], LPS ENABLE notify\n");
+		coex_sta->under_lps = true;
+	} else if (BTC_LPS_DISABLE == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], LPS DISABLE notify\n");
+		coex_sta->under_lps = false;
+	}
+}
+
+void ex_halbtc8821a2ant_scan_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	if (BTC_SCAN_START == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], SCAN START notify\n");
+	} else if (BTC_SCAN_FINISH == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], SCAN FINISH notify\n");
+	}
+}
+
+void ex_halbtc8821a2ant_connect_notify(struct btc_coexist *btcoexist, u8 type)
+{
+	if (BTC_ASSOCIATE_START == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], CONNECT START notify\n");
+	} else if (BTC_ASSOCIATE_FINISH == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], CONNECT FINISH notify\n");
+	}
+}
+
+void ex_halbtc8821a2ant_media_status_notify(struct btc_coexist *btcoexist,
+					    u8 type)
+{
+	u8	h2c_parameter[3] = {0};
+	u32	wifi_bw;
+	u8	wifi_central_chnl;
+
+	if (BTC_MEDIA_CONNECT == type) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], MEDIA connect notify\n");
+	} else {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], MEDIA disconnect notify\n");
+	}
+
+	/* only 2.4G we need to inform bt the chnl mask*/
+	btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL,
+			   &wifi_central_chnl);
+	if ((BTC_MEDIA_CONNECT == type) &&
+	    (wifi_central_chnl <= 14)) {
+		h2c_parameter[0] = 0x1;
+		h2c_parameter[1] = wifi_central_chnl;
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw);
+		if (BTC_WIFI_BW_HT40 == wifi_bw)
+			h2c_parameter[2] = 0x30;
+		else
+			h2c_parameter[2] = 0x20;
+	}
+
+	coex_dm->wifi_chnl_info[0] = h2c_parameter[0];
+	coex_dm->wifi_chnl_info[1] = h2c_parameter[1];
+	coex_dm->wifi_chnl_info[2] = h2c_parameter[2];
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC,
+		  "[BTCoex], FW write 0x66 = 0x%x\n",
+		h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2]);
+
+	btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter);
+}
+
+void ex_halbtc8821a2ant_special_packet_notify(struct btc_coexist *btcoexist,
+					      u8 type) {
+	if (type == BTC_PACKET_DHCP) {
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+			  "[BTCoex], DHCP Packet notify\n");
+	}
+}
+
+void ex_halbtc8821a2ant_bt_info_notify(struct btc_coexist *btcoexist,
+				       u8 *tmp_buf, u8 length)
+{
+	u8		bt_info = 0;
+	u8		i, rsp_source = 0;
+	static u32	set_bt_lna_cnt, set_bt_psd_mode;
+	bool		bt_busy = false, limited_dig = false;
+	bool		wifi_connected = false, bt_hs_on = false;
+
+	coex_sta->c2h_bt_info_req_sent = false;
+
+	rsp_source = tmp_buf[0]&0xf;
+	if (rsp_source >= BT_INFO_SRC_8821A_2ANT_MAX)
+		rsp_source = BT_INFO_SRC_8821A_2ANT_WIFI_FW;
+	coex_sta->bt_info_c2h_cnt[rsp_source]++;
+
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+		  "[BTCoex], Bt info[%d], length = %d, hex data = [",
+		  rsp_source, length);
+	for (i = 0; i < length; i++) {
+		coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i];
+		if (i == 1)
+			bt_info = tmp_buf[i];
+		if (i == length-1) {
+			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+				  "0x%02x]\n", tmp_buf[i]);
+		} else {
+			BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+				  "0x%02x, ", tmp_buf[i]);
+		}
+	}
+
+	if (BT_INFO_SRC_8821A_2ANT_WIFI_FW != rsp_source) {
+		coex_sta->bt_retry_cnt =	/* [3:0]*/
+			coex_sta->bt_info_c2h[rsp_source][2]&0xf;
+
+		coex_sta->bt_rssi =
+			coex_sta->bt_info_c2h[rsp_source][3]*2+10;
+
+		coex_sta->bt_info_ext =
+			coex_sta->bt_info_c2h[rsp_source][4];
+
+		/* Here we need to resend some wifi info to BT*/
+		/* because bt is reset and loss of the info.*/
+		if ((coex_sta->bt_info_ext & BIT1)) {
+			btcoexist->btc_get(btcoexist,
+				BTC_GET_BL_WIFI_CONNECTED, &wifi_connected);
+			if (wifi_connected) {
+				ex_halbtc8821a2ant_media_status_notify(btcoexist,
+					BTC_MEDIA_CONNECT);
+			} else {
+				ex_halbtc8821a2ant_media_status_notify(btcoexist,
+					BTC_MEDIA_DISCONNECT);
+			}
+
+			set_bt_psd_mode = 0;
+		}
+		if (set_bt_psd_mode <= 3) {
+			halbtc8821a2ant_set_bt_psd_mode(btcoexist, FORCE_EXEC,
+							0x0); /*fix CH-BW mode*/
+			set_bt_psd_mode++;
+		}
+
+		if (coex_dm->cur_bt_lna_constrain) {
+			if (!(coex_sta->bt_info_ext & BIT2)) {
+				if (set_bt_lna_cnt <= 3) {
+					btc8821a2_set_bt_lna_const(btcoexist,
+								   FORCE_EXEC,
+								   true);
+					set_bt_lna_cnt++;
+				}
+			}
+		} else {
+			set_bt_lna_cnt = 0;
+		}
+
+		if ((coex_sta->bt_info_ext & BIT3)) {
+			halbtc8821a2ant_ignore_wlan_act(btcoexist,
+							FORCE_EXEC, false);
+		} else {
+			/* BT already NOT ignore Wlan active, do nothing here.*/
+		}
+
+		if ((coex_sta->bt_info_ext & BIT4)) {
+			/* BT auto report already enabled, do nothing*/
+		} else {
+			halbtc8821a2ant_bt_auto_report(btcoexist,
+						       FORCE_EXEC, true);
+		}
+	}
+
+	btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on);
+	/* check BIT2 first ==> check if bt is under inquiry or page scan*/
+	if (bt_info & BT_INFO_8821A_2ANT_B_INQ_PAGE) {
+		coex_sta->c2h_bt_inquiry_page = true;
+		coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE;
+	} else {
+		coex_sta->c2h_bt_inquiry_page = false;
+		if (bt_info == 0x1) {
+			/* connection exists but not busy*/
+			coex_sta->bt_link_exist = true;
+			coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_CON_IDLE;
+		} else if (bt_info & BT_INFO_8821A_2ANT_B_CONNECTION) {
+			/* connection exists and some link is busy*/
+			coex_sta->bt_link_exist = true;
+			if (bt_info & BT_INFO_8821A_2ANT_B_FTP)
+				coex_sta->pan_exist = true;
+			else
+				coex_sta->pan_exist = false;
+			if (bt_info & BT_INFO_8821A_2ANT_B_A2DP)
+				coex_sta->a2dp_exist = true;
+			else
+				coex_sta->a2dp_exist = false;
+			if (bt_info & BT_INFO_8821A_2ANT_B_HID)
+				coex_sta->hid_exist = true;
+			else
+				coex_sta->hid_exist = false;
+			if (bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO)
+				coex_sta->sco_exist = true;
+			else
+				coex_sta->sco_exist = false;
+			coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE;
+		} else {
+			coex_sta->bt_link_exist = false;
+			coex_sta->pan_exist = false;
+			coex_sta->a2dp_exist = false;
+			coex_sta->hid_exist = false;
+			coex_sta->sco_exist = false;
+			coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_IDLE;
+		}
+
+		if (bt_hs_on)
+			coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_IDLE;
+	}
+
+	if (BT_8821A_2ANT_BT_STATUS_NON_IDLE == coex_dm->bt_status)
+		bt_busy = true;
+	else
+		bt_busy = false;
+	btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy);
+
+	if (BT_8821A_2ANT_BT_STATUS_IDLE != coex_dm->bt_status)
+		limited_dig = true;
+	else
+		limited_dig = false;
+	coex_dm->limited_dig = limited_dig;
+	btcoexist->btc_set(btcoexist,
+		BTC_SET_BL_BT_LIMITED_DIG, &limited_dig);
+
+	halbtc8821a2ant_run_coexist_mechanism(btcoexist);
+}
+
+void ex_halbtc8821a2ant_halt_notify(struct btc_coexist *btcoexist)
+{
+	BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY,
+		  "[BTCoex], Halt notify\n");
+
+	halbtc8821a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true);
+	ex_halbtc8821a2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT);
+}
+
+void ex_halbtc8821a2ant_periodical(struct btc_coexist *btcoexist)
+{
+	static u8	dis_ver_info_cnt;
+	u32		fw_ver = 0, bt_patch_ver = 0;
+	struct btc_board_info *board_info = &btcoexist->board_info;
+	struct btc_stack_info *stack_info = &btcoexist->stack_info;
+
+	BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE,
+		  "[BTCoex], ==========================Periodical===========================\n");
+
+	if (dis_ver_info_cnt <= 5) {
+		dis_ver_info_cnt += 1;
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], ****************************************************************\n");
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n",
+			  board_info->pg_ant_num,
+			  board_info->btdm_ant_num,
+			  board_info->btdm_ant_pos);
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], BT stack/ hci ext ver = %s / %d\n",
+			  ((stack_info->profile_notified) ? "Yes" : "No"),
+			  stack_info->hci_version);
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER,
+				   &bt_patch_ver);
+		btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver);
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n",
+			  glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant,
+			  fw_ver, bt_patch_ver, bt_patch_ver);
+		BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT,
+			  "[BTCoex], ****************************************************************\n");
+	}
+
+	halbtc8821a2ant_query_bt_info(btcoexist);
+	halbtc8821a2ant_monitor_bt_ctr(btcoexist);
+	btc8821a2ant_mon_bt_en_dis(btcoexist);
+}
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h
new file mode 100644
index 0000000..b4cf1f5
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtc8821a2ant.h
@@ -0,0 +1,205 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2012  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+/*===========================================
+ * The following is for 8821A 2Ant BT Co-exist definition
+ *===========================================
+*/
+#define	BT_INFO_8821A_2ANT_B_FTP		BIT7
+#define	BT_INFO_8821A_2ANT_B_A2DP		BIT6
+#define	BT_INFO_8821A_2ANT_B_HID		BIT5
+#define	BT_INFO_8821A_2ANT_B_SCO_BUSY		BIT4
+#define	BT_INFO_8821A_2ANT_B_ACL_BUSY		BIT3
+#define	BT_INFO_8821A_2ANT_B_INQ_PAGE		BIT2
+#define	BT_INFO_8821A_2ANT_B_SCO_ESCO		BIT1
+#define	BT_INFO_8821A_2ANT_B_CONNECTION		BIT0
+
+#define	BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT	2
+
+enum _BT_INFO_SRC_8821A_2ANT {
+	BT_INFO_SRC_8821A_2ANT_WIFI_FW		= 0x0,
+	BT_INFO_SRC_8821A_2ANT_BT_RSP		= 0x1,
+	BT_INFO_SRC_8821A_2ANT_BT_ACTIVE_SEND	= 0x2,
+	BT_INFO_SRC_8821A_2ANT_MAX
+};
+
+enum _BT_8821A_2ANT_BT_STATUS {
+	BT_8821A_2ANT_BT_STATUS_IDLE		= 0x0,
+	BT_8821A_2ANT_BT_STATUS_CON_IDLE	= 0x1,
+	BT_8821A_2ANT_BT_STATUS_NON_IDLE	= 0x2,
+	BT_8821A_2ANT_BT_STATUS_MAX
+};
+
+enum _BT_8821A_2ANT_COEX_ALGO {
+	BT_8821A_2ANT_COEX_ALGO_UNDEFINED		= 0x0,
+	BT_8821A_2ANT_COEX_ALGO_SCO			= 0x1,
+	BT_8821A_2ANT_COEX_ALGO_HID			= 0x2,
+	BT_8821A_2ANT_COEX_ALGO_A2DP			= 0x3,
+	BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS		= 0x4,
+	BT_8821A_2ANT_COEX_ALGO_PANEDR			= 0x5,
+	BT_8821A_2ANT_COEX_ALGO_PANHS			= 0x6,
+	BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP		= 0x7,
+	BT_8821A_2ANT_COEX_ALGO_PANEDR_HID		= 0x8,
+	BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR		= 0x9,
+	BT_8821A_2ANT_COEX_ALGO_HID_A2DP		= 0xa,
+	BT_8821A_2ANT_COEX_ALGO_MAX			= 0xb,
+};
+
+struct coex_dm_8821a_2ant {
+	/* fw mechanism */
+	bool		pre_dec_bt_pwr;
+	bool		cur_dec_bt_pwr;
+	bool		pre_bt_lna_constrain;
+	bool		cur_bt_lna_constrain;
+	u8		pre_bt_psd_mode;
+	u8		cur_bt_psd_mode;
+	u8		pre_fw_dac_swing_lvl;
+	u8		cur_fw_dac_swing_lvl;
+	bool		cur_ignore_wlan_act;
+	bool		pre_ignore_wlan_act;
+	u8		pre_ps_tdma;
+	u8		cur_ps_tdma;
+	u8		ps_tdma_para[5];
+	u8		tdma_adj_type;
+	bool		reset_tdma_adjust;
+	bool		pre_ps_tdma_on;
+	bool		cur_ps_tdma_on;
+	bool		pre_bt_auto_report;
+	bool		cur_bt_auto_report;
+
+	/* sw mechanism */
+	bool		pre_rf_rx_lpf_shrink;
+	bool		cur_rf_rx_lpf_shrink;
+	u32		bt_rf0x1e_backup;
+	bool		pre_low_penalty_ra;
+	bool		cur_low_penalty_ra;
+	bool		pre_dac_swing_on;
+	u32		pre_dac_swing_lvl;
+	bool		cur_dac_swing_on;
+	u32		cur_dac_swing_lvl;
+	bool		pre_adc_back_off;
+	bool		cur_adc_back_off;
+	bool		pre_agc_table_en;
+	bool		cur_agc_table_en;
+	u32		pre_val0x6c0;
+	u32		cur_val0x6c0;
+	u32		pre_val0x6c4;
+	u32		cur_val0x6c4;
+	u32		pre_val0x6c8;
+	u32		cur_val0x6c8;
+	u8		pre_val0x6cc;
+	u8		cur_val0x6cc;
+	bool		limited_dig;
+
+	/* algorithm related */
+	u8		pre_algorithm;
+	u8		cur_algorithm;
+	u8		bt_status;
+	u8		wifi_chnl_info[3];
+};
+
+struct coex_sta_8821a_2ant {
+	bool	bt_link_exist;
+	bool	sco_exist;
+	bool	a2dp_exist;
+	bool	hid_exist;
+	bool	pan_exist;
+	bool	under_lps;
+	bool	under_ips;
+	u32	high_priority_tx;
+	u32	high_priority_rx;
+	u32	low_priority_tx;
+	u32	low_priority_rx;
+	u8	bt_rssi;
+	u8	pre_bt_rssi_state;
+	u8	pre_wifi_rssi_state[4];
+	bool	c2h_bt_info_req_sent;
+	u8	bt_info_c2h[BT_INFO_SRC_8821A_2ANT_MAX][10];
+	u32	bt_info_c2h_cnt[BT_INFO_SRC_8821A_2ANT_MAX];
+	bool	c2h_bt_inquiry_page;
+	u8	bt_retry_cnt;
+	u8	bt_info_ext;
+};
+
+/*===========================================
+ *	The following is interface which will notify coex module.
+ *===========================================
+ */
+void
+ex_halbtc8821a2ant_init_hwconfig(
+	struct btc_coexist *btcoexist
+	);
+void
+ex_halbtc8821a2ant_init_coex_dm(
+	struct btc_coexist *btcoexist
+	);
+void
+ex_halbtc8821a2ant_ips_notify(
+	struct btc_coexist *btcoexist,
+	u8 type
+	);
+void
+ex_halbtc8821a2ant_lps_notify(
+	struct btc_coexist *btcoexist,
+	u8 type
+	);
+void
+ex_halbtc8821a2ant_scan_notify(
+	struct btc_coexist *btcoexist,
+	u8 type
+	);
+void
+ex_halbtc8821a2ant_connect_notify(
+	struct btc_coexist *btcoexist,
+	u8 type
+	);
+void
+ex_halbtc8821a2ant_media_status_notify(
+	struct btc_coexist *btcoexist,
+	u8 type
+	);
+void
+ex_halbtc8821a2ant_special_packet_notify(
+	struct btc_coexist *btcoexist,
+	u8 type
+	);
+void
+ex_halbtc8821a2ant_bt_info_notify(
+	struct btc_coexist *btcoexist,
+	u8 *tmp_buf,
+	u8 length
+	);
+void
+ex_halbtc8821a2ant_halt_notify(
+	struct btc_coexist *btcoexist
+	);
+void
+ex_halbtc8821a2ant_periodical(
+	struct btc_coexist *btcoexist
+	);
+void
+ex_halbtc8821a2ant_display_coex_info(
+	struct btc_coexist *btcoexist
+	);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
index d4bd550..b2791c8 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -32,7 +32,6 @@
 struct btc_coexist gl_bt_coexist;
 
 u32 btc_dbg_type[BTC_MSG_MAX];
-static u8 btc_dbg_buf[100];
 
 /***************************************************
  *		Debug related function
@@ -389,7 +388,7 @@
 		btcoexist->bt_info.reject_agg_pkt = *bool_tmp;
 		break;
 	case BTC_SET_BL_BT_CTRL_AGG_SIZE:
-		btcoexist->bt_info.b_bt_ctrl_buf_size = *bool_tmp;
+		btcoexist->bt_info.bt_ctrl_buf_size = *bool_tmp;
 		break;
 	case BTC_SET_BL_INC_SCAN_DEV_NUM:
 		btcoexist->bt_info.increase_scan_dev_num = *bool_tmp;
@@ -417,10 +416,10 @@
 	/*	rtlpriv->mlmepriv.scan_compensation = *u8_tmp;  */
 		break;
 	case BTC_SET_U1_1ANT_LPS:
-		btcoexist->bt_info.lps_1ant = *u8_tmp;
+		btcoexist->bt_info.lps_val = *u8_tmp;
 		break;
 	case BTC_SET_U1_1ANT_RPWM:
-		btcoexist->bt_info.rpwm_1ant = *u8_tmp;
+		btcoexist->bt_info.rpwm_val = *u8_tmp;
 		break;
 	/* the following are some action which will be triggered  */
 	case BTC_SET_ACT_LEAVE_LPS:
@@ -497,7 +496,7 @@
 	return	rtl_read_dword(rtlpriv, reg_addr);
 }
 
-static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u8 data)
+static void halbtc_write_1byte(void *bt_context, u32 reg_addr, u32 data)
 {
 	struct btc_coexist *btcoexist = (struct btc_coexist *)bt_context;
 	struct rtl_priv *rtlpriv = btcoexist->adapter;
@@ -652,9 +651,7 @@
 	btcoexist->btc_get = halbtc_get;
 	btcoexist->btc_set = halbtc_set;
 
-	btcoexist->cli_buf = &btc_dbg_buf[0];
-
-	btcoexist->bt_info.b_bt_ctrl_buf_size = false;
+	btcoexist->bt_info.bt_ctrl_buf_size = false;
 	btcoexist->bt_info.agg_buf_size = 5;
 
 	btcoexist->bt_info.increase_scan_dev_num = false;
@@ -672,7 +669,7 @@
 	btcoexist->statistics.cnt_init_hw_config++;
 
 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		ex_halbtc8723b2ant_init_hwconfig(btcoexist);
+		ex_btc8723b2ant_init_hwconfig(btcoexist);
 }
 
 void exhalbtc_init_coex_dm(struct btc_coexist *btcoexist)
@@ -686,7 +683,7 @@
 	btcoexist->statistics.cnt_init_coex_dm++;
 
 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		ex_halbtc8723b2ant_init_coex_dm(btcoexist);
+		ex_btc8723b2ant_init_coex_dm(btcoexist);
 
 	btcoexist->initilized = true;
 }
@@ -711,7 +708,7 @@
 	halbtc_leave_low_power();
 
 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		ex_halbtc8723b2ant_ips_notify(btcoexist, ips_type);
+		ex_btc8723b2ant_ips_notify(btcoexist, ips_type);
 
 	halbtc_nomal_low_power();
 }
@@ -734,7 +731,7 @@
 		lps_type = BTC_LPS_ENABLE;
 
 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		ex_halbtc8723b2ant_lps_notify(btcoexist, lps_type);
+		ex_btc8723b2ant_lps_notify(btcoexist, lps_type);
 }
 
 void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type)
@@ -757,7 +754,7 @@
 	halbtc_leave_low_power();
 
 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		ex_halbtc8723b2ant_scan_notify(btcoexist, scan_type);
+		ex_btc8723b2ant_scan_notify(btcoexist, scan_type);
 
 	halbtc_nomal_low_power();
 }
@@ -782,14 +779,12 @@
 	halbtc_leave_low_power();
 
 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		ex_halbtc8723b2ant_connect_notify(btcoexist, asso_type);
+		ex_btc8723b2ant_connect_notify(btcoexist, asso_type);
 }
 
 void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
-				 enum _RT_MEDIA_STATUS media_status)
+				 enum rt_media_status media_status)
 {
-	struct rtl_priv *rtlpriv = btcoexist->adapter;
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	u8 status;
 
 	if (!halbtc_is_bt_coexist_available(btcoexist))
@@ -805,9 +800,6 @@
 
 	halbtc_leave_low_power();
 
-	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		btc8723b_med_stat_notify(btcoexist, status);
-
 	halbtc_nomal_low_power();
 }
 
@@ -828,8 +820,8 @@
 	halbtc_leave_low_power();
 
 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		ex_halbtc8723b2ant_special_packet_notify(btcoexist,
-							 packet_type);
+		ex_btc8723b2ant_special_packet_notify(btcoexist,
+						      packet_type);
 
 	halbtc_nomal_low_power();
 }
@@ -844,13 +836,11 @@
 	btcoexist->statistics.cnt_bt_info_notify++;
 
 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		ex_halbtc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length);
+		ex_btc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length);
 }
 
 void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type)
 {
-	struct rtl_priv *rtlpriv = btcoexist->adapter;
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	u8 stack_op_type;
 
 	if (!halbtc_is_bt_coexist_available(btcoexist))
@@ -863,10 +853,6 @@
 
 	halbtc_leave_low_power();
 
-	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		ex_halbtc8723b2ant_stack_operation_notify(btcoexist,
-							  stack_op_type);
-
 	halbtc_nomal_low_power();
 }
 
@@ -878,7 +864,7 @@
 		return;
 
 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		ex_halbtc8723b2ant_halt_notify(btcoexist);
+		ex_btc8723b2ant_halt_notify(btcoexist);
 }
 
 void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state)
@@ -898,7 +884,7 @@
 	halbtc_leave_low_power();
 
 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		ex_halbtc8723b2ant_periodical(btcoexist);
+		ex_btc8723b2ant_periodical(btcoexist);
 
 	halbtc_nomal_low_power();
 }
@@ -997,5 +983,5 @@
 		return;
 
 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE)
-		ex_halbtc8723b2ant_display_coex_info(btcoexist);
+		ex_btc8723b2ant_display_coex_info(btcoexist);
 }
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h
index 049f4c8..0a903ea 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h
+++ b/drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.h
@@ -55,9 +55,16 @@
 #define		BTC_RATE_DISABLE			0
 #define		BTC_RATE_ENABLE				1
 
+/* single Antenna definition */
 #define		BTC_ANT_PATH_WIFI			0
 #define		BTC_ANT_PATH_BT				1
 #define		BTC_ANT_PATH_PTA			2
+/* dual Antenna definition */
+#define		BTC_ANT_WIFI_AT_MAIN			0
+#define		BTC_ANT_WIFI_AT_AUX			1
+/* coupler Antenna definition */
+#define		BTC_ANT_WIFI_AT_CPL_MAIN		0
+#define		BTC_ANT_WIFI_AT_CPL_AUX			1
 
 enum btc_chip_interface {
 	BTC_INTF_UNKNOWN	= 0,
@@ -68,7 +75,7 @@
 	BTC_INTF_MAX
 };
 
-enum BTC_CHIP_TYPE {
+enum btc_chip_type {
 	BTC_CHIP_UNDEF		= 0,
 	BTC_CHIP_CSR_BC4	= 1,
 	BTC_CHIP_CSR_BC8	= 2,
@@ -78,11 +85,12 @@
 	BTC_CHIP_MAX
 };
 
-enum BTC_MSG_TYPE {
+enum btc_msg_type {
 	BTC_MSG_INTERFACE	= 0x0,
 	BTC_MSG_ALGORITHM	= 0x1,
 	BTC_MSG_MAX
 };
+
 extern u32 btc_dbg_type[];
 
 /* following is for BTC_MSG_INTERFACE */
@@ -101,20 +109,12 @@
 #define		ALGO_TRACE_SW_DETAIL			BIT8
 #define		ALGO_TRACE_SW_EXEC			BIT9
 
-#define		BT_COEX_ANT_TYPE_PG			0
-#define		BT_COEX_ANT_TYPE_ANTDIV			1
-#define		BT_COEX_ANT_TYPE_DETECTED		2
-#define		BTC_MIMO_PS_STATIC			0
-#define		BTC_MIMO_PS_DYNAMIC			1
-#define		BTC_RATE_DISABLE			0
-#define		BTC_RATE_ENABLE				1
-#define		BTC_ANT_PATH_WIFI			0
-#define		BTC_ANT_PATH_BT				1
-#define		BTC_ANT_PATH_PTA			2
-
-
-#define	CL_SPRINTF	snprintf
-#define	CL_PRINTF(buf)	printk("%s", buf)
+/* following is for wifi link status */
+#define		WIFI_STA_CONNECTED			BIT0
+#define		WIFI_AP_CONNECTED			BIT1
+#define		WIFI_HS_CONNECTED			BIT2
+#define		WIFI_P2P_GO_CONNECTED			BIT3
+#define		WIFI_P2P_GC_CONNECTED			BIT4
 
 #define	BTC_PRINT(dbgtype, dbgflag, printstr, ...)		\
 	do {							\
@@ -123,46 +123,15 @@
 		}						\
 	} while (0)
 
-#define	BTC_PRINT_F(dbgtype, dbgflag, printstr, ...)		\
-	do {							\
-		if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {\
-			pr_info("%s: ", __func__);	\
-			printk(printstr, ##__VA_ARGS__);	\
-		}						\
-	} while (0)
-
-#define	BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _ptr)	\
-	do {							\
-		if (unlikely(btc_dbg_type[dbgtype] & dbgflag)) {	\
-			int __i;				\
-			u8 *__ptr = (u8 *)_ptr;			\
-			printk printstr;			\
-			for (__i = 0; __i < 6; __i++)		\
-				printk("%02X%s", __ptr[__i], (__i == 5) ? \
-				       "" : "-");		\
-			pr_info("\n");				\
-		}						\
-	} while (0)
-
-#define BTC_PRINT_DATA(dbgtype, dbgflag, _titlestring, _hexdata, _hexdatalen) \
-	do {								\
-		if (unlikely(btc_dbg_type[dbgtype] & dbgflag))	{	\
-			int __i;					\
-			u8 *__ptr = (u8 *)_hexdata;			\
-			printk(_titlestring);				\
-			for (__i = 0; __i < (int)_hexdatalen; __i++) {	\
-				printk("%02X%s", __ptr[__i], (((__i + 1) % 4) \
-							== 0) ? "  " : " ");\
-				if (((__i + 1) % 16) == 0)		\
-					printk("\n");			\
-			}						\
-			pr_debug("\n");					\
-		}							\
-	} while (0)
-
-#define BTC_ANT_PATH_WIFI	0
-#define BTC_ANT_PATH_BT		1
-#define BTC_ANT_PATH_PTA	2
+#define	BTC_RSSI_HIGH(_rssi_)	\
+	((_rssi_ == BTC_RSSI_STATE_HIGH ||	\
+	  _rssi_ == BTC_RSSI_STATE_STAY_HIGH) ? true : false)
+#define	BTC_RSSI_MEDIUM(_rssi_)	\
+	((_rssi_ == BTC_RSSI_STATE_MEDIUM ||	\
+	  _rssi_ == BTC_RSSI_STATE_STAY_MEDIUM) ? true : false)
+#define	BTC_RSSI_LOW(_rssi_)	\
+	((_rssi_ == BTC_RSSI_STATE_LOW ||	\
+	  _rssi_ == BTC_RSSI_STATE_STAY_LOW) ? true : false)
 
 enum btc_power_save_type {
 	BTC_PS_WIFI_NATIVE = 0,
@@ -224,7 +193,6 @@
 	BTC_WIFI_PNP_MAX
 };
 
-
 enum btc_get_type {
 	/* type bool */
 	BTC_GET_BL_HS_OPERATION,
@@ -253,6 +221,7 @@
 	BTC_GET_U4_WIFI_BW,
 	BTC_GET_U4_WIFI_TRAFFIC_DIRECTION,
 	BTC_GET_U4_WIFI_FW_VER,
+	BTC_GET_U4_WIFI_LINK_STATUS,
 	BTC_GET_U4_BT_PATCH_VER,
 
 	/* type u1Byte */
@@ -260,6 +229,7 @@
 	BTC_GET_U1_WIFI_CENTRAL_CHNL,
 	BTC_GET_U1_WIFI_HS_CHNL,
 	BTC_GET_U1_MAC_PHY_MODE,
+	BTC_GET_U1_AP_NUM,
 
 	/* for 1Ant */
 	BTC_GET_U1_LPS_MODE,
@@ -270,7 +240,6 @@
 	BTC_GET_MAX
 };
 
-
 enum btc_set_type {
 	/* type bool */
 	BTC_SET_BL_BT_DISABLE,
@@ -283,7 +252,6 @@
 
 	/* type u1Byte */
 	BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON,
-	BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE,
 	BTC_SET_UI_SCAN_SIG_COMPENSATION,
 	BTC_SET_U1_AGG_BUF_SIZE,
 
@@ -295,6 +263,9 @@
 	/* type bool */
 	BTC_SET_BL_BT_SCO_BUSY,
 	/* type u1Byte */
+	BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE,
+	BTC_SET_U1_LPS_VAL,
+	BTC_SET_U1_RPWM_VAL,
 	BTC_SET_U1_1ANT_LPS,
 	BTC_SET_U1_1ANT_RPWM,
 	/* type trigger some action */
@@ -358,6 +329,20 @@
 	BTC_PACKET_MAX
 };
 
+enum hci_ext_bt_operation {
+	HCI_BT_OP_NONE = 0x0,
+	HCI_BT_OP_INQUIRY_START = 0x1,
+	HCI_BT_OP_INQUIRY_FINISH = 0x2,
+	HCI_BT_OP_PAGING_START = 0x3,
+	HCI_BT_OP_PAGING_SUCCESS = 0x4,
+	HCI_BT_OP_PAGING_UNSUCCESS = 0x5,
+	HCI_BT_OP_PAIRING_START = 0x6,
+	HCI_BT_OP_PAIRING_FINISH = 0x7,
+	HCI_BT_OP_BT_DEV_ENABLE = 0x8,
+	HCI_BT_OP_BT_DEV_DISABLE = 0x9,
+	HCI_BT_OP_MAX
+};
+
 enum btc_notify_type_stack_operation {
 	BTC_STACK_OP_NONE = 0x0,
 	BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1,
@@ -365,14 +350,13 @@
 	BTC_STACK_OP_MAX
 };
 
-
 typedef u8 (*bfp_btc_r1)(void *btc_context, u32 reg_addr);
 
 typedef u16 (*bfp_btc_r2)(void *btc_context, u32 reg_addr);
 
 typedef u32 (*bfp_btc_r4)(void *btc_context, u32 reg_addr);
 
-typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u8 data);
+typedef void (*bfp_btc_w1)(void *btc_context, u32 reg_addr, u32 data);
 
 typedef void (*bfp_btc_w1_bit_mak)(void *btc_context, u32 reg_addr,
 				   u32 bit_mask, u8 data1b);
@@ -413,20 +397,22 @@
 	u8 agg_buf_size;
 	bool limited_dig;
 	bool reject_agg_pkt;
-	bool b_bt_ctrl_buf_size;
+	bool bt_ctrl_buf_size;
 	bool increase_scan_dev_num;
 	u16 bt_hci_ver;
 	u16 bt_real_fw_ver;
 	u8 bt_fw_ver;
 
+	bool bt_disable_low_pwr;
+
 	/* the following is for 1Ant solution */
 	bool bt_ctrl_lps;
 	bool bt_pwr_save_mode;
 	bool bt_lps_on;
 	bool force_to_roam;
 	u8 force_exec_pwr_cmd_cnt;
-	u8 lps_1ant;
-	u8 rpwm_1ant;
+	u8 lps_val;
+	u8 rpwm_val;
 	u32 ra_mask;
 };
 
@@ -457,6 +443,7 @@
 	u32 cnt_special_packet_notify;
 	u32 cnt_bt_info_notify;
 	u32 cnt_periodical;
+	u32 cnt_coex_dm_switch;
 	u32 cnt_stack_operation_notify;
 	u32 cnt_dbg_ctrl;
 };
@@ -493,7 +480,6 @@
 	bool initilized;
 	bool stop_coex_dm;
 	bool manual_control;
-	u8 *cli_buf;
 	struct btc_statistics statistics;
 	u8 pwr_mode_val[10];
 
@@ -509,7 +495,6 @@
 	bfp_btc_set_bb_reg btc_set_bb_reg;
 	bfp_btc_get_bb_reg btc_get_bb_reg;
 
-
 	bfp_btc_set_rf_reg btc_set_rf_reg;
 	bfp_btc_get_rf_reg btc_get_rf_reg;
 
@@ -533,13 +518,14 @@
 void exhalbtc_scan_notify(struct btc_coexist *btcoexist, u8 type);
 void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action);
 void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist,
-				 enum _RT_MEDIA_STATUS media_status);
+				 enum rt_media_status media_status);
 void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type);
 void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf,
 			     u8 length);
 void exhalbtc_stack_operation_notify(struct btc_coexist *btcoexist, u8 type);
 void exhalbtc_halt_notify(struct btc_coexist *btcoexist);
 void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state);
+void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist);
 void exhalbtc_periodical(struct btc_coexist *btcoexist);
 void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len,
 			  u8 *data);
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c
index 0ab94fe..b9b0cb7 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c
+++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.c
@@ -22,19 +22,19 @@
  * Larry Finger <Larry.Finger@lwfinger.net>
  *
  *****************************************************************************/
-
 #include "../wifi.h"
-#include "rtl_btc.h"
-#include "halbt_precomp.h"
-
 #include <linux/vmalloc.h>
 #include <linux/module.h>
 
+#include "rtl_btc.h"
+#include "halbt_precomp.h"
+
 static struct rtl_btc_ops rtl_btc_operation = {
 	.btc_init_variables = rtl_btc_init_variables,
 	.btc_init_hal_vars = rtl_btc_init_hal_vars,
 	.btc_init_hw_config = rtl_btc_init_hw_config,
 	.btc_ips_notify = rtl_btc_ips_notify,
+	.btc_lps_notify = rtl_btc_lps_notify,
 	.btc_scan_notify = rtl_btc_scan_notify,
 	.btc_connect_notify = rtl_btc_connect_notify,
 	.btc_mediastatus_notify = rtl_btc_mediastatus_notify,
@@ -44,6 +44,7 @@
 	.btc_is_limited_dig = rtl_btc_is_limited_dig,
 	.btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo,
 	.btc_is_bt_disabled = rtl_btc_is_bt_disabled,
+	.btc_special_packet_notify = rtl_btc_special_packet_notify,
 };
 
 void rtl_btc_init_variables(struct rtl_priv *rtlpriv)
@@ -85,6 +86,11 @@
 	exhalbtc_ips_notify(&gl_bt_coexist, type);
 }
 
+void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type)
+{
+	exhalbtc_lps_notify(&gl_bt_coexist, type);
+}
+
 void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype)
 {
 	exhalbtc_scan_notify(&gl_bt_coexist, scantype);
@@ -96,13 +102,14 @@
 }
 
 void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
-				enum _RT_MEDIA_STATUS mstatus)
+				enum rt_media_status mstatus)
 {
 	exhalbtc_mediastatus_notify(&gl_bt_coexist, mstatus);
 }
 
 void rtl_btc_periodical(struct rtl_priv *rtlpriv)
 {
+	/*rtl_bt_dm_monitor();*/
 	exhalbtc_periodical(&gl_bt_coexist);
 }
 
@@ -150,12 +157,18 @@
 
 bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv)
 {
+	/* It seems 'bt_disabled' is never be initialized or set. */
 	if (gl_bt_coexist.bt_info.bt_disabled)
 		return true;
 	else
 		return false;
 }
 
+void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type)
+{
+	return exhalbtc_special_packet_notify(&gl_bt_coexist, pkt_type);
+}
+
 struct rtl_btc_ops *rtl_btc_get_ops_pointer(void)
 {
 	return &rtl_btc_operation;
@@ -174,11 +187,11 @@
 	return num;
 }
 
-enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw)
+enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	enum _RT_MEDIA_STATUS    m_status = RT_MEDIA_DISCONNECT;
+	enum rt_media_status    m_status = RT_MEDIA_DISCONNECT;
 
 	u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
 
diff --git a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h
index 805b22c..ccd5a0f 100644
--- a/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h
+++ b/drivers/net/wireless/rtlwifi/btcoexist/rtl_btc.h
@@ -31,22 +31,24 @@
 void rtl_btc_init_hal_vars(struct rtl_priv *rtlpriv);
 void rtl_btc_init_hw_config(struct rtl_priv *rtlpriv);
 void rtl_btc_ips_notify(struct rtl_priv *rtlpriv, u8 type);
+void rtl_btc_lps_notify(struct rtl_priv *rtlpriv, u8 type);
 void rtl_btc_scan_notify(struct rtl_priv *rtlpriv, u8 scantype);
 void rtl_btc_connect_notify(struct rtl_priv *rtlpriv, u8 action);
 void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv,
-				enum _RT_MEDIA_STATUS mstatus);
+				enum rt_media_status mstatus);
 void rtl_btc_periodical(struct rtl_priv *rtlpriv);
 void rtl_btc_halt_notify(void);
 void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmpbuf, u8 length);
 bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv);
 bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv);
 bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv);
+void rtl_btc_special_packet_notify(struct rtl_priv *rtlpriv, u8 pkt_type);
 
 struct rtl_btc_ops *rtl_btc_get_ops_pointer(void);
 
 u8 rtl_get_hwpg_ant_num(struct rtl_priv *rtlpriv);
 u8 rtl_get_hwpg_bt_exist(struct rtl_priv *rtlpriv);
 u8 rtl_get_hwpg_bt_type(struct rtl_priv *rtlpriv);
-enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw);
+enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/cam.c b/drivers/net/wireless/rtlwifi/cam.c
index 0276153..8fe8b4c 100644
--- a/drivers/net/wireless/rtlwifi/cam.c
+++ b/drivers/net/wireless/rtlwifi/cam.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -26,10 +22,9 @@
  * Larry Finger <Larry.Finger@lwfinger.net>
  *
  *****************************************************************************/
-
-#include <linux/export.h>
 #include "wifi.h"
 #include "cam.h"
+#include <linux/export.h>
 
 void rtl_cam_reset_sec_info(struct ieee80211_hw *hw)
 {
@@ -52,8 +47,8 @@
 	u32 target_content = 0;
 	u8 entry_i;
 
-	RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "key_cont_128: %6phC\n",
-		 key_cont_128);
+	RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_DMESG, "Key content :",
+		      key_cont_128, 16);
 
 	for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
 		target_command = entry_i + CAM_CONTENT_COUNT * entry_no;
@@ -68,11 +63,13 @@
 			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
 					target_command);
 
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE %x: %x\n",
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 "WRITE %x: %x\n",
 				 rtlpriv->cfg->maps[WCAMI], target_content);
 			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
 				 "The Key ID is %d\n", entry_no);
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE %x: %x\n",
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 "WRITE %x: %x\n",
 				 rtlpriv->cfg->maps[RWCAM], target_command);
 
 		} else if (entry_i == 1) {
@@ -87,10 +84,10 @@
 			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
 					target_command);
 
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE A4: %x\n",
-				 target_content);
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE A0: %x\n",
-				 target_command);
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 "WRITE A4: %x\n", target_content);
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 "WRITE A0: %x\n", target_command);
 
 		} else {
 
@@ -107,15 +104,15 @@
 					target_command);
 			udelay(100);
 
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE A4: %x\n",
-				 target_content);
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "WRITE A0: %x\n",
-				 target_command);
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 "WRITE A4: %x\n", target_content);
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+				 "WRITE A0: %x\n", target_command);
 		}
 	}
 
-	RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "after set key, usconfig:%x\n",
-		 us_config);
+	RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+		 "after set key, usconfig:%x\n", us_config);
 }
 
 u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
@@ -125,27 +122,26 @@
 	u32 us_config;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-	RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 		 "EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM\n",
 		 ul_entry_idx, ul_key_id, ul_enc_alg,
 		 ul_default_key, mac_addr);
 
 	if (ul_key_id == TOTAL_CAM_ENTRY) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-			 "<=== ulKeyId exceed!\n");
+			 "ulKeyId exceed!\n");
 		return 0;
 	}
 
-	if (ul_default_key == 1) {
+	if (ul_default_key == 1)
 		us_config = CFG_VALID | ((u16) (ul_enc_alg) << 2);
-	} else {
+	else
 		us_config = CFG_VALID | ((ul_enc_alg) << 2) | ul_key_id;
-	}
 
 	rtl_cam_program_entry(hw, ul_entry_idx, mac_addr,
-			      key_content, us_config);
+			      (u8 *)key_content, us_config);
 
-	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "<===\n");
+	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "end\n");
 
 	return 1;
 
@@ -289,7 +285,8 @@
 	u8 i, *addr;
 
 	if (NULL == sta_addr) {
-		RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, "sta_addr is NULL\n");
+		RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG,
+			 "sta_addr is NULL.\n");
 		return TOTAL_CAM_ENTRY;
 	}
 	/* Does STA already exist? */
@@ -322,7 +319,9 @@
 	u8 i, *addr;
 
 	if (NULL == sta_addr) {
-		RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, "sta_addr is NULL\n");
+		RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG,
+			 "sta_addr is NULL.\n");
+		return;
 	}
 
 	if (is_zero_ether_addr(sta_addr)) {
@@ -339,8 +338,8 @@
 			/* Remove from HW Security CAM */
 			eth_zero_addr(rtlpriv->sec.hwsec_cam_sta_addr[i]);
 			rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i);
-			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
-				 "del CAM entry %d\n", i);
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+				 "&&&&&&&&&del entry %d\n", i);
 		}
 	}
 	return;
diff --git a/drivers/net/wireless/rtlwifi/cam.h b/drivers/net/wireless/rtlwifi/cam.h
index 0105e6c..3550808 100644
--- a/drivers/net/wireless/rtlwifi/cam.h
+++ b/drivers/net/wireless/rtlwifi/cam.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -36,15 +32,15 @@
 #define CFG_VALID					BIT(15)
 
 #define PAIRWISE_KEYIDX					0
-#define CAM_PAIRWISE_KEY_POSITION		4
+#define CAM_PAIRWISE_KEY_POSITION			4
 
 #define	CAM_CONFIG_USEDK				1
 #define	CAM_CONFIG_NO_USEDK				0
 
 void rtl_cam_reset_all_entry(struct ieee80211_hw *hw);
 u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
-			 u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg,
-			 u32 ul_default_key, u8 *key_content);
+				u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg,
+				u32 ul_default_key, u8 *key_content);
 int rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
 			     u32 ul_key_id);
 void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index);
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index 56e218e..f6179bc 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -31,10 +27,13 @@
 #include "core.h"
 #include "cam.h"
 #include "base.h"
-#include "pci.h"
 #include "ps.h"
+#include "pwrseqcmd.h"
 
+#include "btcoexist/rtl_btc.h"
+#include <linux/firmware.h>
 #include <linux/export.h>
+#include <net/cfg80211.h>
 
 void rtl_addr_delay(u32 addr)
 {
@@ -103,7 +102,7 @@
 	int err;
 
 	RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
-			 "Firmware callback routine entered!\n");
+		 "Firmware callback routine entered!\n");
 	complete(&rtlpriv->firmware_loading_complete);
 	if (!firmware) {
 		if (rtlpriv->cfg->alt_fw_name) {
@@ -129,26 +128,13 @@
 	memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
 	rtlpriv->rtlhal.fwsize = firmware->size;
 	release_firmware(firmware);
-
-	err = ieee80211_register_hw(hw);
-	if (err) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Can't register mac80211 hw\n");
-		return;
-	} else {
-		rtlpriv->mac80211.mac80211_registered = 1;
-	}
-	set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
-
-	/*init rfkill */
-	rtl_init_rfkill(hw);
 }
 EXPORT_SYMBOL(rtl_fw_cb);
 
 /*mutex for start & stop is must here. */
 static int rtl_op_start(struct ieee80211_hw *hw)
 {
-	int err;
+	int err = 0;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
@@ -170,28 +156,33 @@
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	bool support_remote_wakeup = false;
 
 	if (is_hal_stop(rtlhal))
 		return;
 
+	rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+				      (u8 *)(&support_remote_wakeup));
 	/* here is must, because adhoc do stop and start,
 	 * but stop with RFOFF may cause something wrong,
 	 * like adhoc TP
 	 */
-	if (unlikely(ppsc->rfpwr_state == ERFOFF)) {
+	if (unlikely(ppsc->rfpwr_state == ERFOFF))
 		rtl_ips_nic_on(hw);
-	}
 
 	mutex_lock(&rtlpriv->locks.conf_mutex);
+	/* if wowlan supported, DON'T clear connected info */
+	if (!(support_remote_wakeup &&
+	      rtlhal->enter_pnp_sleep)) {
+		mac->link_state = MAC80211_NOLINK;
+		memset(mac->bssid, 0, 6);
+		mac->vendor = PEER_UNKNOWN;
 
-	mac->link_state = MAC80211_NOLINK;
-	memset(mac->bssid, 0, ETH_ALEN);
-	mac->vendor = PEER_UNKNOWN;
+		/* reset sec info */
+		rtl_cam_reset_sec_info(hw);
 
-	/*reset sec info */
-	rtl_cam_reset_sec_info(hw);
-
-	rtl_deinit_deferred_work(hw);
+		rtl_deinit_deferred_work(hw);
+	}
 	rtlpriv->intf_ops->adapter_stop(hw);
 
 	mutex_unlock(&rtlpriv->locks.conf_mutex);
@@ -215,7 +206,6 @@
 
 	if (!rtlpriv->intf_ops->waitq_insert(hw, control->sta, skb))
 		rtlpriv->intf_ops->adapter_tx(hw, control->sta, skb, &tcb_desc);
-
 	return;
 
 err_free:
@@ -229,18 +219,17 @@
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	int err = 0;
 
-	vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
-
 	if (mac->vif) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 			 "vif has been set!! mac->vif = 0x%p\n", mac->vif);
 		return -EOPNOTSUPP;
 	}
 
+	vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+
 	rtl_ips_nic_on(hw);
 
 	mutex_lock(&rtlpriv->locks.conf_mutex);
-
 	switch (ieee80211_vif_type_p2p(vif)) {
 	case NL80211_IFTYPE_P2P_CLIENT:
 		mac->p2p = P2P_ROLE_CLIENT;
@@ -251,10 +240,8 @@
 				 "NL80211_IFTYPE_STATION\n");
 			mac->beacon_enabled = 0;
 			rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
-					rtlpriv->cfg->maps
-					[RTL_IBSS_INT_MASKS]);
+					rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]);
 		}
-		mac->link_state = MAC80211_LINKED;
 		break;
 	case NL80211_IFTYPE_ADHOC:
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
@@ -267,7 +254,7 @@
 		else
 			mac->basic_rates = 0xff0;
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
-				(u8 *) (&mac->basic_rates));
+				(u8 *)(&mac->basic_rates));
 
 		break;
 	case NL80211_IFTYPE_P2P_GO:
@@ -284,7 +271,7 @@
 		else
 			mac->basic_rates = 0xff0;
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
-				(u8 *) (&mac->basic_rates));
+					      (u8 *)(&mac->basic_rates));
 		break;
 	case NL80211_IFTYPE_MESH_POINT:
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
@@ -301,7 +288,7 @@
 		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "operation mode %d is not supported!\n", vif->type);
+			 "operation mode %d is not support!\n", vif->type);
 		err = -EOPNOTSUPP;
 		goto out;
 	}
@@ -339,8 +326,7 @@
 		if (mac->beacon_enabled == 1) {
 			mac->beacon_enabled = 0;
 			rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
-					rtlpriv->cfg->maps
-					[RTL_IBSS_INT_MASKS]);
+					rtlpriv->cfg->maps[RTL_IBSS_INT_MASKS]);
 		}
 	}
 
@@ -355,12 +341,12 @@
 	mac->vendor = PEER_UNKNOWN;
 	mac->opmode = NL80211_IFTYPE_UNSPECIFIED;
 	rtlpriv->cfg->ops->set_network_type(hw, mac->opmode);
+
 	mutex_unlock(&rtlpriv->locks.conf_mutex);
 }
-
 static int rtl_op_change_interface(struct ieee80211_hw *hw,
-				      struct ieee80211_vif *vif,
-				      enum nl80211_iftype new_type, bool p2p)
+				   struct ieee80211_vif *vif,
+				   enum nl80211_iftype new_type, bool p2p)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	int ret;
@@ -370,10 +356,221 @@
 	vif->p2p = p2p;
 	ret = rtl_op_add_interface(hw, vif);
 	RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
-		 "p2p %x\n", p2p);
+		 "p2p  %x\n", p2p);
 	return ret;
 }
 
+#ifdef CONFIG_PM
+static u16 crc16_ccitt(u8 data, u16 crc)
+{
+	u8 shift_in, data_bit, crc_bit11, crc_bit4, crc_bit15;
+	u8 i;
+	u16 result;
+
+	for (i = 0; i < 8; i++) {
+		crc_bit15 = ((crc & BIT(15)) ? 1 : 0);
+		data_bit  = (data & (BIT(0) << i) ? 1 : 0);
+		shift_in = crc_bit15 ^ data_bit;
+
+		result = crc << 1;
+		if (shift_in == 0)
+			result &= (~BIT(0));
+		else
+			result |= BIT(0);
+
+		crc_bit11 = ((crc & BIT(11)) ? 1 : 0) ^ shift_in;
+		if (crc_bit11 == 0)
+			result &= (~BIT(12));
+		else
+			result |= BIT(12);
+
+		crc_bit4 = ((crc & BIT(4)) ? 1 : 0) ^ shift_in;
+		if (crc_bit4 == 0)
+			result &= (~BIT(5));
+		else
+			result |= BIT(5);
+
+		crc = result;
+	}
+
+	return crc;
+}
+
+static u16 _calculate_wol_pattern_crc(u8 *pattern, u16 len)
+{
+	u16 crc = 0xffff;
+	u32 i;
+
+	for (i = 0; i < len; i++)
+		crc = crc16_ccitt(pattern[i], crc);
+
+	crc = ~crc;
+
+	return crc;
+}
+
+static void _rtl_add_wowlan_patterns(struct ieee80211_hw *hw,
+				     struct cfg80211_wowlan *wow)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = &rtlpriv->mac80211;
+	struct cfg80211_pkt_pattern *patterns = wow->patterns;
+	struct rtl_wow_pattern rtl_pattern;
+	const u8 *pattern_os, *mask_os;
+	u8 mask[MAX_WOL_BIT_MASK_SIZE] = {0};
+	u8 content[MAX_WOL_PATTERN_SIZE] = {0};
+	u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	u8 multicast_addr1[2] = {0x33, 0x33};
+	u8 multicast_addr2[3] = {0x01, 0x00, 0x5e};
+	u8 i, mask_len;
+	u16 j, len;
+
+	for (i = 0; i < wow->n_patterns; i++) {
+		memset(&rtl_pattern, 0, sizeof(struct rtl_wow_pattern));
+		memset(mask, 0, MAX_WOL_BIT_MASK_SIZE);
+		if (patterns[i].pattern_len > MAX_WOL_PATTERN_SIZE) {
+			RT_TRACE(rtlpriv, COMP_POWER, DBG_WARNING,
+				 "Pattern[%d] is too long\n", i);
+			continue;
+		}
+		pattern_os = patterns[i].pattern;
+		mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8);
+		mask_os = patterns[i].mask;
+		RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+			      "pattern content\n", pattern_os,
+			       patterns[i].pattern_len);
+		RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+			      "mask content\n", mask_os, mask_len);
+		/* 1. unicast? multicast? or broadcast? */
+		if (memcmp(pattern_os, broadcast_addr, 6) == 0)
+			rtl_pattern.type = BROADCAST_PATTERN;
+		else if (memcmp(pattern_os, multicast_addr1, 2) == 0 ||
+			 memcmp(pattern_os, multicast_addr2, 3) == 0)
+			rtl_pattern.type = MULTICAST_PATTERN;
+		else if  (memcmp(pattern_os, mac->mac_addr, 6) == 0)
+			rtl_pattern.type = UNICAST_PATTERN;
+		else
+			rtl_pattern.type = UNKNOWN_TYPE;
+
+		/* 2. translate mask_from_os to mask_for_hw */
+
+/******************************************************************************
+ * pattern from OS uses 'ethenet frame', like this:
+
+		   |    6   |    6   |   2  |     20    |  Variable  |	4  |
+		   |--------+--------+------+-----------+------------+-----|
+		   |    802.3 Mac Header    | IP Header | TCP Packet | FCS |
+		   |   DA   |   SA   | Type |
+
+ * BUT, packet catched by our HW is in '802.11 frame', begin from LLC,
+
+	|     24 or 30      |    6   |   2  |     20    |  Variable  |  4  |
+	|-------------------+--------+------+-----------+------------+-----|
+	| 802.11 MAC Header |       LLC     | IP Header | TCP Packet | FCS |
+			    | Others | Tpye |
+
+ * Therefore, we need translate mask_from_OS to mask_to_hw.
+ * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0,
+ * because new mask[0~5] means 'SA', but our HW packet begins from LLC,
+ * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match.
+ ******************************************************************************/
+
+		/* Shift 6 bits */
+		for (j = 0; j < mask_len - 1; j++) {
+			mask[j] = mask_os[j] >> 6;
+			mask[j] |= (mask_os[j + 1] & 0x3F) << 2;
+		}
+		mask[j] = (mask_os[j] >> 6) & 0x3F;
+		/* Set bit 0-5 to zero */
+		mask[0] &= 0xC0;
+
+		RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+			      "mask to hw\n", mask, mask_len);
+		for (j = 0; j < (MAX_WOL_BIT_MASK_SIZE + 1) / 4; j++) {
+			rtl_pattern.mask[j] = mask[j * 4];
+			rtl_pattern.mask[j] |= (mask[j * 4 + 1] << 8);
+			rtl_pattern.mask[j] |= (mask[j * 4 + 2] << 16);
+			rtl_pattern.mask[j] |= (mask[j * 4 + 3] << 24);
+		}
+
+		/* To get the wake up pattern from the mask.
+		 * We do not count first 12 bits which means
+		 * DA[6] and SA[6] in the pattern to match HW design.
+		 */
+		len = 0;
+		for (j = 12; j < patterns[i].pattern_len; j++) {
+			if ((mask_os[j / 8] >> (j % 8)) & 0x01) {
+				content[len] = pattern_os[j];
+				len++;
+			}
+		}
+
+		RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+			      "pattern to hw\n", content, len);
+		/* 3. calculate crc */
+		rtl_pattern.crc = _calculate_wol_pattern_crc(content, len);
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+			 "CRC_Remainder = 0x%x", rtl_pattern.crc);
+
+		/* 4. write crc & mask_for_hw to hw */
+		rtlpriv->cfg->ops->add_wowlan_pattern(hw, &rtl_pattern, i);
+	}
+	rtl_write_byte(rtlpriv, 0x698, wow->n_patterns);
+}
+
+static int rtl_op_suspend(struct ieee80211_hw *hw,
+			  struct cfg80211_wowlan *wow)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct timeval ts;
+
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "\n");
+	if (WARN_ON(!wow))
+		return -EINVAL;
+
+	/* to resolve s4 can not wake up*/
+	do_gettimeofday(&ts);
+	rtlhal->last_suspend_sec = ts.tv_sec;
+
+	if ((ppsc->wo_wlan_mode & WAKE_ON_PATTERN_MATCH) && wow->n_patterns)
+		_rtl_add_wowlan_patterns(hw, wow);
+
+	rtlhal->driver_is_goingto_unload = true;
+	rtlhal->enter_pnp_sleep = true;
+
+	rtl_lps_leave(hw);
+	rtl_op_stop(hw);
+	device_set_wakeup_enable(wiphy_dev(hw->wiphy), true);
+	return 0;
+}
+
+static int rtl_op_resume(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct timeval ts;
+
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "\n");
+	rtlhal->driver_is_goingto_unload = false;
+	rtlhal->enter_pnp_sleep = false;
+	rtlhal->wake_from_pnp_sleep = true;
+
+	/* to resovle s4 can not wake up*/
+	do_gettimeofday(&ts);
+	if (ts.tv_sec - rtlhal->last_suspend_sec < 5)
+		return -1;
+
+	rtl_op_start(hw);
+	device_set_wakeup_enable(wiphy_dev(hw->wiphy), false);
+	ieee80211_resume_disconnect(mac->vif);
+	rtlhal->wake_from_pnp_sleep = false;
+	return 0;
+}
+#endif
+
 static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -386,7 +583,7 @@
 		return 1;
 
 	mutex_lock(&rtlpriv->locks.conf_mutex);
-	if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {	/*BIT(2)*/
+	if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {	/* BIT(2)*/
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
 			 "IEEE80211_CONF_CHANGE_LISTEN_INTERVAL\n");
 	}
@@ -421,8 +618,8 @@
 			 * is worked very well */
 			if (!rtlpriv->psc.multi_buffered)
 				queue_delayed_work(rtlpriv->works.rtl_wq,
-						&rtlpriv->works.ps_work,
-						MSECS(5));
+						   &rtlpriv->works.ps_work,
+						   MSECS(5));
 		} else {
 			rtl_swlps_rf_awake(hw);
 			rtlpriv->psc.sw_ps_enabled = false;
@@ -436,20 +633,26 @@
 		mac->retry_long = hw->conf.long_frame_max_tx_count;
 		mac->retry_short = hw->conf.long_frame_max_tx_count;
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT,
-					      (u8 *) (&hw->conf.
-						      long_frame_max_tx_count));
+				(u8 *)(&hw->conf.long_frame_max_tx_count));
 	}
 
-	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+	if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
+	    !rtlpriv->proximity.proxim_on) {
 		struct ieee80211_channel *channel = hw->conf.chandef.chan;
+		enum nl80211_chan_width width = hw->conf.chandef.width;
+		enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
 		u8 wide_chan = (u8) channel->hw_value;
 
+		/* channel_type is for 20&40M */
+		if (width < NL80211_CHAN_WIDTH_80)
+			channel_type =
+				cfg80211_get_chandef_type(&hw->conf.chandef);
 		if (mac->act_scanning)
 			mac->n_channels++;
 
 		if (rtlpriv->dm.supp_phymode_switch &&
-		    mac->link_state < MAC80211_LINKED &&
-		    !mac->act_scanning) {
+			mac->link_state < MAC80211_LINKED &&
+			!mac->act_scanning) {
 			if (rtlpriv->cfg->ops->chk_switch_dmdp)
 				rtlpriv->cfg->ops->chk_switch_dmdp(hw);
 		}
@@ -463,48 +666,98 @@
 		 *info for cisco1253 bw20, so we modify
 		 *it here based on UPPER & LOWER
 		 */
-		switch (cfg80211_get_chandef_type(&hw->conf.chandef)) {
-		case NL80211_CHAN_HT20:
-		case NL80211_CHAN_NO_HT:
-			/* SC */
-			mac->cur_40_prime_sc =
-				PRIME_CHNL_OFFSET_DONT_CARE;
-			rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20;
-			mac->bw_40 = false;
-			break;
-		case NL80211_CHAN_HT40MINUS:
-			/* SC */
-			mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER;
-			rtlphy->current_chan_bw =
-				HT_CHANNEL_WIDTH_20_40;
-			mac->bw_40 = true;
 
-			/*wide channel */
-			wide_chan -= 2;
+		if (width >= NL80211_CHAN_WIDTH_80) {
+			if (width == NL80211_CHAN_WIDTH_80) {
+				u32 center = hw->conf.chandef.center_freq1;
+				u32 primary =
+				(u32)hw->conf.chandef.chan->center_freq;
 
-			break;
-		case NL80211_CHAN_HT40PLUS:
-			/* SC */
-			mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER;
-			rtlphy->current_chan_bw =
-				HT_CHANNEL_WIDTH_20_40;
-			mac->bw_40 = true;
+				rtlphy->current_chan_bw =
+					HT_CHANNEL_WIDTH_80;
+				mac->bw_80 = true;
+				mac->bw_40 = true;
+				if (center > primary) {
+					mac->cur_80_prime_sc =
+					PRIME_CHNL_OFFSET_LOWER;
+					if (center - primary == 10) {
+						mac->cur_40_prime_sc =
+						PRIME_CHNL_OFFSET_UPPER;
 
-			/*wide channel */
-			wide_chan += 2;
+						wide_chan += 2;
+					} else if (center - primary == 30) {
+						mac->cur_40_prime_sc =
+						PRIME_CHNL_OFFSET_LOWER;
 
-			break;
-		default:
-			mac->bw_40 = false;
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
-			break;
+						wide_chan += 6;
+					}
+				} else {
+					mac->cur_80_prime_sc =
+					PRIME_CHNL_OFFSET_UPPER;
+					if (primary - center == 10) {
+						mac->cur_40_prime_sc =
+						PRIME_CHNL_OFFSET_LOWER;
+
+						wide_chan -= 2;
+					} else if (primary - center == 30) {
+						mac->cur_40_prime_sc =
+						PRIME_CHNL_OFFSET_UPPER;
+
+						wide_chan -= 6;
+					}
+				}
+			}
+		} else {
+			switch (channel_type) {
+			case NL80211_CHAN_HT20:
+			case NL80211_CHAN_NO_HT:
+					/* SC */
+					mac->cur_40_prime_sc =
+						PRIME_CHNL_OFFSET_DONT_CARE;
+					rtlphy->current_chan_bw =
+						HT_CHANNEL_WIDTH_20;
+					mac->bw_40 = false;
+					mac->bw_80 = false;
+					break;
+			case NL80211_CHAN_HT40MINUS:
+					/* SC */
+					mac->cur_40_prime_sc =
+						PRIME_CHNL_OFFSET_UPPER;
+					rtlphy->current_chan_bw =
+						HT_CHANNEL_WIDTH_20_40;
+					mac->bw_40 = true;
+					mac->bw_80 = false;
+
+					/*wide channel */
+					wide_chan -= 2;
+
+					break;
+			case NL80211_CHAN_HT40PLUS:
+					/* SC */
+					mac->cur_40_prime_sc =
+						PRIME_CHNL_OFFSET_LOWER;
+					rtlphy->current_chan_bw =
+						HT_CHANNEL_WIDTH_20_40;
+					mac->bw_40 = true;
+					mac->bw_80 = false;
+
+					/*wide channel */
+					wide_chan += 2;
+
+					break;
+			default:
+					mac->bw_40 = false;
+					mac->bw_80 = false;
+					RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+						 "switch case not processed\n");
+					break;
+			}
 		}
 
 		if (wide_chan <= 0)
 			wide_chan = 1;
 
-		/* In scanning, before we go offchannel we may send a ps = 1
+		/* In scanning, when before we offchannel we may send a ps=1
 		 * null to AP, and then we may send a ps = 0 null to AP quickly,
 		 * but first null may have caused AP to put lots of packet to
 		 * hw tx buffer. These packets must be tx'd before we go off
@@ -516,12 +769,12 @@
 			rtlpriv->mac80211.offchan_delay = false;
 			mdelay(50);
 		}
+
 		rtlphy->current_channel = wide_chan;
 
 		rtlpriv->cfg->ops->switch_channel(hw);
 		rtlpriv->cfg->ops->set_channel_access(hw);
-		rtlpriv->cfg->ops->set_bw_mode(hw,
-				cfg80211_get_chandef_type(&hw->conf.chandef));
+		rtlpriv->cfg->ops->set_bw_mode(hw, channel_type);
 	}
 
 	mutex_unlock(&rtlpriv->locks.conf_mutex);
@@ -530,45 +783,25 @@
 }
 
 static void rtl_op_configure_filter(struct ieee80211_hw *hw,
-			     unsigned int changed_flags,
-			     unsigned int *new_flags, u64 multicast)
+				    unsigned int changed_flags,
+				    unsigned int *new_flags, u64 multicast)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	u32 rx_conf;
 
 	*new_flags &= RTL_SUPPORTED_FILTERS;
-	if (!changed_flags)
+	if (0 == changed_flags)
 		return;
 
-	/* if ssid not set to hw don't check bssid
-	 * here just used for linked scanning, & linked
-	 * and nolink check bssid is set in set network_type */
-	if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
-		(mac->link_state >= MAC80211_LINKED)) {
-		if (mac->opmode != NL80211_IFTYPE_AP &&
-		    mac->opmode != NL80211_IFTYPE_MESH_POINT) {
-			if (*new_flags & FIF_BCN_PRBRESP_PROMISC) {
-				rtlpriv->cfg->ops->set_chk_bssid(hw, false);
-			} else {
-				rtlpriv->cfg->ops->set_chk_bssid(hw, true);
-			}
-		}
-	}
-
-	/* must be called after set_chk_bssid since that function modifies the
-	 * RCR register too. */
-	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&rx_conf));
-
 	/*TODO: we disable broadcase now, so enable here */
 	if (changed_flags & FIF_ALLMULTI) {
 		if (*new_flags & FIF_ALLMULTI) {
-			rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] |
+			mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AM] |
 			    rtlpriv->cfg->maps[MAC_RCR_AB];
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
 				 "Enable receive multicast frame\n");
 		} else {
-			rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] |
+			mac->rx_conf &= ~(rtlpriv->cfg->maps[MAC_RCR_AM] |
 					  rtlpriv->cfg->maps[MAC_RCR_AB]);
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
 				 "Disable receive multicast frame\n");
@@ -577,43 +810,55 @@
 
 	if (changed_flags & FIF_FCSFAIL) {
 		if (*new_flags & FIF_FCSFAIL) {
-			rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32];
+			mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACRC32];
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
 				 "Enable receive FCS error frame\n");
 		} else {
-			rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32];
+			mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32];
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
 				 "Disable receive FCS error frame\n");
 		}
 	}
 
+	/* if ssid not set to hw don't check bssid
+	 * here just used for linked scanning, & linked
+	 * and nolink check bssid is set in set network_type
+	 */
+	if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
+	    (mac->link_state >= MAC80211_LINKED)) {
+		if (mac->opmode != NL80211_IFTYPE_AP &&
+		    mac->opmode != NL80211_IFTYPE_MESH_POINT) {
+			if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
+				rtlpriv->cfg->ops->set_chk_bssid(hw, false);
+			else
+				rtlpriv->cfg->ops->set_chk_bssid(hw, true);
+		}
+	}
 
 	if (changed_flags & FIF_CONTROL) {
 		if (*new_flags & FIF_CONTROL) {
-			rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF];
+			mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF];
 
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
-				 "Enable receive control frame\n");
+				 "Enable receive control frame.\n");
 		} else {
-			rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF];
+			mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF];
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
-				 "Disable receive control frame\n");
+				 "Disable receive control frame.\n");
 		}
 	}
 
 	if (changed_flags & FIF_OTHER_BSS) {
 		if (*new_flags & FIF_OTHER_BSS) {
-			rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP];
+			mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_AAP];
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
-				 "Enable receive other BSS's frame\n");
+				 "Enable receive other BSS's frame.\n");
 		} else {
-			rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP];
+			mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP];
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
-				 "Disable receive other BSS's frame\n");
+				 "Disable receive other BSS's frame.\n");
 		}
 	}
-
-	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&rx_conf));
 }
 static int rtl_op_sta_add(struct ieee80211_hw *hw,
 			 struct ieee80211_vif *vif,
@@ -625,7 +870,7 @@
 	struct rtl_sta_info *sta_entry;
 
 	if (sta) {
-		sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+		sta_entry = (struct rtl_sta_info *)sta->drv_priv;
 		spin_lock_bh(&rtlpriv->locks.entry_list_lock);
 		list_add_tail(&sta_entry->list, &rtlpriv->entry_list);
 		spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
@@ -633,15 +878,17 @@
 			sta_entry->wireless_mode = WIRELESS_MODE_G;
 			if (sta->supp_rates[0] <= 0xf)
 				sta_entry->wireless_mode = WIRELESS_MODE_B;
-			if (sta->ht_cap.ht_supported == true)
+			if (sta->ht_cap.ht_supported)
 				sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
 
 			if (vif->type == NL80211_IFTYPE_ADHOC)
 				sta_entry->wireless_mode = WIRELESS_MODE_G;
 		} else if (rtlhal->current_bandtype == BAND_ON_5G) {
 			sta_entry->wireless_mode = WIRELESS_MODE_A;
-			if (sta->ht_cap.ht_supported == true)
-				sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
+			if (sta->ht_cap.ht_supported)
+				sta_entry->wireless_mode = WIRELESS_MODE_N_5G;
+			if (sta->vht_cap.vht_supported)
+				sta_entry->wireless_mode = WIRELESS_MODE_AC_5G;
 
 			if (vif->type == NL80211_IFTYPE_ADHOC)
 				sta_entry->wireless_mode = WIRELESS_MODE_A;
@@ -652,9 +899,10 @@
 
 		memcpy(sta_entry->mac_addr, sta->addr, ETH_ALEN);
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
-			 "Add sta addr is %pM\n", sta->addr);
+			"Add sta addr is %pM\n", sta->addr);
 		rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
 	}
+
 	return 0;
 }
 
@@ -667,17 +915,15 @@
 	if (sta) {
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
 			 "Remove sta addr is %pM\n", sta->addr);
-		sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+		sta_entry = (struct rtl_sta_info *)sta->drv_priv;
 		sta_entry->wireless_mode = 0;
 		sta_entry->ratr_index = 0;
-
 		spin_lock_bh(&rtlpriv->locks.entry_list_lock);
 		list_del(&sta_entry->list);
 		spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
 	}
 	return 0;
 }
-
 static int _rtl_get_hal_qnum(u16 queue)
 {
 	int qnum;
@@ -707,8 +953,8 @@
  *for rtl819x  BE = 0, BK = 1, VI = 2, VO = 3
  */
 static int rtl_op_conf_tx(struct ieee80211_hw *hw,
-		   struct ieee80211_vif *vif, u16 queue,
-		   const struct ieee80211_tx_queue_params *param)
+			  struct ieee80211_vif *vif, u16 queue,
+			  const struct ieee80211_tx_queue_params *param)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -731,14 +977,14 @@
 }
 
 static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
-			     struct ieee80211_vif *vif,
-			     struct ieee80211_bss_conf *bss_conf, u32 changed)
+				    struct ieee80211_vif *vif,
+				    struct ieee80211_bss_conf *bss_conf,
+				    u32 changed)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-	struct ieee80211_sta *sta = NULL;
 
 	mutex_lock(&rtlpriv->locks.conf_mutex);
 	if ((vif->type == NL80211_IFTYPE_ADHOC) ||
@@ -756,15 +1002,14 @@
 				mac->beacon_enabled = 1;
 				rtlpriv->cfg->ops->update_interrupt_mask(hw,
 						rtlpriv->cfg->maps
-						[RTL_IBSS_INT_MASKS],
-						0);
+						[RTL_IBSS_INT_MASKS], 0);
 
 				if (rtlpriv->cfg->ops->linked_set_reg)
 					rtlpriv->cfg->ops->linked_set_reg(hw);
 			}
 		}
 		if ((changed & BSS_CHANGED_BEACON_ENABLED &&
-			!bss_conf->enable_beacon)) {
+		    !bss_conf->enable_beacon)) {
 			if (mac->beacon_enabled == 1) {
 				RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
 					 "ADHOC DISABLE BEACON\n");
@@ -785,8 +1030,12 @@
 
 	/*TODO: reference to enum ieee80211_bss_change */
 	if (changed & BSS_CHANGED_ASSOC) {
+		u8 mstatus;
 		if (bss_conf->assoc) {
 			struct ieee80211_sta *sta = NULL;
+			u8 keep_alive = 10;
+
+			mstatus = RT_MEDIA_CONNECT;
 			/* we should reset all sec info & cam
 			 * before set cam after linked, we should not
 			 * reset in disassoc, that will cause tkip->wep
@@ -804,47 +1053,89 @@
 
 			if (rtlpriv->cfg->ops->linked_set_reg)
 				rtlpriv->cfg->ops->linked_set_reg(hw);
+
 			rcu_read_lock();
 			sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
 			if (!sta) {
-				pr_err("ieee80211_find_sta returned NULL\n");
 				rcu_read_unlock();
 				goto out;
 			}
-
-			if (vif->type == NL80211_IFTYPE_STATION && sta)
-				rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
 			RT_TRACE(rtlpriv, COMP_EASY_CONCURRENT, DBG_LOUD,
 				 "send PS STATIC frame\n");
 			if (rtlpriv->dm.supp_phymode_switch) {
 				if (sta->ht_cap.ht_supported)
 					rtl_send_smps_action(hw, sta,
-						 IEEE80211_SMPS_STATIC);
+							IEEE80211_SMPS_STATIC);
 			}
+
+			if (rtlhal->current_bandtype == BAND_ON_5G) {
+				mac->mode = WIRELESS_MODE_A;
+			} else {
+				if (sta->supp_rates[0] <= 0xf)
+					mac->mode = WIRELESS_MODE_B;
+				else
+					mac->mode = WIRELESS_MODE_G;
+			}
+
+			if (sta->ht_cap.ht_supported) {
+				if (rtlhal->current_bandtype == BAND_ON_2_4G)
+					mac->mode = WIRELESS_MODE_N_24G;
+				else
+					mac->mode = WIRELESS_MODE_N_5G;
+			}
+
+			if (sta->vht_cap.vht_supported) {
+				if (rtlhal->current_bandtype == BAND_ON_5G)
+					mac->mode = WIRELESS_MODE_AC_5G;
+				else
+					mac->mode = WIRELESS_MODE_AC_24G;
+			}
+
+			if (vif->type == NL80211_IFTYPE_STATION && sta)
+				rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
 			rcu_read_unlock();
 
+			/* to avoid AP Disassociation caused by inactivity */
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_KEEP_ALIVE,
+						      (u8 *)(&keep_alive));
+
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
 				 "BSS_CHANGED_ASSOC\n");
 		} else {
+			mstatus = RT_MEDIA_DISCONNECT;
+
 			if (mac->link_state == MAC80211_LINKED) {
 				rtlpriv->enter_ps = false;
 				schedule_work(&rtlpriv->works.lps_change_work);
 			}
-
 			if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE)
 				rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
 			mac->link_state = MAC80211_NOLINK;
 			memset(mac->bssid, 0, ETH_ALEN);
 			mac->vendor = PEER_UNKNOWN;
+			mac->mode = 0;
 
 			if (rtlpriv->dm.supp_phymode_switch) {
 				if (rtlpriv->cfg->ops->chk_switch_dmdp)
 					rtlpriv->cfg->ops->chk_switch_dmdp(hw);
 			}
-
 			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
 				 "BSS_CHANGED_UN_ASSOC\n");
 		}
+		rtlpriv->cfg->ops->set_network_type(hw, vif->type);
+		/* For FW LPS:
+		 * To tell firmware we have connected or disconnected
+		 */
+		rtlpriv->cfg->ops->set_hw_reg(hw,
+					      HW_VAR_H2C_FW_JOINBSSRPT,
+					      (u8 *)(&mstatus));
+		ppsc->report_linked = (mstatus == RT_MEDIA_CONNECT) ?
+				      true : false;
+
+		if (rtlpriv->cfg->ops->get_btc_status())
+			rtlpriv->btcoexist.btc_ops->btc_mediastatus_notify(
+							rtlpriv, mstatus);
 	}
 
 	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
@@ -856,11 +1147,11 @@
 	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
 			 "BSS_CHANGED_ERP_PREAMBLE use short preamble:%x\n",
-			 bss_conf->use_short_preamble);
+			  bss_conf->use_short_preamble);
 
 		mac->short_preamble = bss_conf->use_short_preamble;
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACK_PREAMBLE,
-					      &mac->short_preamble);
+					      (u8 *)(&mac->short_preamble));
 	}
 
 	if (changed & BSS_CHANGED_ERP_SLOT) {
@@ -873,13 +1164,17 @@
 			mac->slot_time = RTL_SLOT_TIME_20;
 
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
-					      &mac->slot_time);
+					      (u8 *)(&mac->slot_time));
 	}
 
 	if (changed & BSS_CHANGED_HT) {
-		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, "BSS_CHANGED_HT\n");
+		struct ieee80211_sta *sta = NULL;
+
+		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
+			 "BSS_CHANGED_HT\n");
+
 		rcu_read_lock();
-		sta = get_sta(hw, vif, bss_conf->bssid);
+		sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
 		if (sta) {
 			if (sta->ht_cap.ampdu_density >
 			    mac->current_ampdu_density)
@@ -893,7 +1188,7 @@
 		rcu_read_unlock();
 
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SHORTGI_DENSITY,
-					      &mac->max_mss_density);
+					      (u8 *)(&mac->max_mss_density));
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_FACTOR,
 					      &mac->current_ampdu_factor);
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AMPDU_MIN_SPACE,
@@ -902,19 +1197,19 @@
 
 	if (changed & BSS_CHANGED_BSSID) {
 		u32 basic_rates;
+		struct ieee80211_sta *sta = NULL;
 
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID,
-					      (u8 *) bss_conf->bssid);
+					      (u8 *)bss_conf->bssid);
 
-		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, "%pM\n",
-			 bss_conf->bssid);
+		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
+			 "bssid: %pM\n", bss_conf->bssid);
 
 		mac->vendor = PEER_UNKNOWN;
 		memcpy(mac->bssid, bss_conf->bssid, ETH_ALEN);
-		rtlpriv->cfg->ops->set_network_type(hw, vif->type);
 
 		rcu_read_lock();
-		sta = get_sta(hw, vif, bss_conf->bssid);
+		sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
 		if (!sta) {
 			rcu_read_unlock();
 			goto out;
@@ -936,11 +1231,18 @@
 				mac->mode = WIRELESS_MODE_N_5G;
 		}
 
+		if (sta->vht_cap.vht_supported) {
+			if (rtlhal->current_bandtype == BAND_ON_5G)
+				mac->mode = WIRELESS_MODE_AC_5G;
+			else
+				mac->mode = WIRELESS_MODE_AC_24G;
+		}
+
 		/* just station need it, because ibss & ap mode will
 		 * set in sta_add, and will be NULL here */
-		if (mac->opmode == NL80211_IFTYPE_STATION) {
+		if (vif->type == NL80211_IFTYPE_STATION) {
 			struct rtl_sta_info *sta_entry;
-			sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+			sta_entry = (struct rtl_sta_info *)sta->drv_priv;
 			sta_entry->wireless_mode = mac->mode;
 		}
 
@@ -955,6 +1257,9 @@
 			 * */
 		}
 
+		if (sta->vht_cap.vht_supported)
+			mac->vht_enable = true;
+
 		if (changed & BSS_CHANGED_BASIC_RATES) {
 			/* for 5G must << RATE_6M_INDEX = 4,
 			 * because 5G have no cck rate*/
@@ -969,40 +1274,6 @@
 		}
 		rcu_read_unlock();
 	}
-
-	/*
-	 * For FW LPS:
-	 * To tell firmware we have connected
-	 * to an AP. For 92SE/CE power save v2.
-	 */
-	if (changed & BSS_CHANGED_ASSOC) {
-		if (bss_conf->assoc) {
-			if (ppsc->fwctrl_lps) {
-				u8 mstatus = RT_MEDIA_CONNECT;
-				u8 keep_alive = 10;
-				rtlpriv->cfg->ops->set_hw_reg(hw,
-						 HW_VAR_KEEP_ALIVE,
-						 &keep_alive);
-
-				rtlpriv->cfg->ops->set_hw_reg(hw,
-						      HW_VAR_H2C_FW_JOINBSSRPT,
-						      &mstatus);
-				ppsc->report_linked = true;
-			}
-		} else {
-			if (ppsc->fwctrl_lps) {
-				u8 mstatus = RT_MEDIA_DISCONNECT;
-				rtlpriv->cfg->ops->set_hw_reg(hw,
-						      HW_VAR_H2C_FW_JOINBSSRPT,
-						      &mstatus);
-				ppsc->report_linked = false;
-			}
-		}
-		if (rtlpriv->cfg->ops->bt_wifi_media_status_notify)
-			rtlpriv->cfg->ops->bt_wifi_media_status_notify(hw,
-							 ppsc->report_linked);
-	}
-
 out:
 	mutex_unlock(&rtlpriv->locks.conf_mutex);
 }
@@ -1012,28 +1283,27 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u64 tsf;
 
-	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&tsf));
+	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *)(&tsf));
 	return tsf;
 }
 
-static void rtl_op_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-			   u64 tsf)
+static void rtl_op_set_tsf(struct ieee80211_hw *hw,
+			   struct ieee80211_vif *vif, u64 tsf)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
 
 	mac->tsf = tsf;
-	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, &bibss);
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *)(&bibss));
 }
 
-static void rtl_op_reset_tsf(struct ieee80211_hw *hw,
-			     struct ieee80211_vif *vif)
+static void rtl_op_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 tmp = 0;
 
-	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_DUAL_TSF_RST, &tmp);
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_DUAL_TSF_RST, (u8 *)(&tmp));
 }
 
 static void rtl_op_sta_notify(struct ieee80211_hw *hw,
@@ -1063,13 +1333,13 @@
 	case IEEE80211_AMPDU_TX_START:
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
 			 "IEEE80211_AMPDU_TX_START: TID:%d\n", tid);
-		return rtl_tx_agg_start(hw, sta, tid, ssn);
+		return rtl_tx_agg_start(hw, vif, sta, tid, ssn);
 	case IEEE80211_AMPDU_TX_STOP_CONT:
 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
 			 "IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid);
-		return rtl_tx_agg_stop(hw, sta, tid);
+		return rtl_tx_agg_stop(hw, vif, sta, tid);
 	case IEEE80211_AMPDU_TX_OPERATIONAL:
 		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
 			 "IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid);
@@ -1103,10 +1373,14 @@
 		return;
 	}
 
+	if (rtlpriv->cfg->ops->get_btc_status())
+		rtlpriv->btcoexist.btc_ops->btc_scan_notify(rtlpriv, 1);
+
 	if (rtlpriv->dm.supp_phymode_switch) {
 		if (rtlpriv->cfg->ops->chk_switch_dmdp)
 			rtlpriv->cfg->ops->chk_switch_dmdp(hw);
 	}
+
 	if (mac->link_state == MAC80211_LINKED) {
 		rtlpriv->enter_ps = false;
 		schedule_work(&rtlpriv->works.lps_change_work);
@@ -1115,11 +1389,11 @@
 		rtl_ips_nic_on(hw);
 	}
 
-	/* Dual mac */
+	/* Dul mac */
 	rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false;
 
 	rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY);
-	rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP);
+	rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP_BAND0);
 }
 
 static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw)
@@ -1133,13 +1407,13 @@
 	if (rtlpriv->link_info.higher_busytraffic)
 		return;
 
-	/*p2p will use 1/6/11 to scan */
+	/* p2p will use 1/6/11 to scan */
 	if (mac->n_channels == 3)
 		mac->p2p_in_use = true;
 	else
 		mac->p2p_in_use = false;
 	mac->n_channels = 0;
-	/* Dual mac */
+	/* Dul mac */
 	rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false;
 
 	if (mac->link_state == MAC80211_LINKED_SCANNING) {
@@ -1151,6 +1425,8 @@
 	}
 
 	rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE);
+	if (rtlpriv->cfg->ops->get_btc_status())
+		rtlpriv->btcoexist.btc_ops->btc_scan_notify(rtlpriv, 0);
 }
 
 static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -1158,7 +1434,6 @@
 			  struct ieee80211_key_conf *key)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	u8 key_type = NO_ENCRYPTION;
 	u8 key_idx;
 	bool group_key = false;
@@ -1174,13 +1449,13 @@
 	}
 	/* To support IBSS, use sw-crypto for GTK */
 	if (((vif->type == NL80211_IFTYPE_ADHOC) ||
-	     (vif->type == NL80211_IFTYPE_MESH_POINT)) &&
-	      !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+	    (vif->type == NL80211_IFTYPE_MESH_POINT)) &&
+	   !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
 		return -ENOSPC;
 	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 		 "%s hardware based encryption for keyidx: %d, mac: %pM\n",
-		 cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
-		 sta ? sta->addr : bcast_addr);
+		  cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
+		  sta ? sta->addr : bcast_addr);
 	rtlpriv->sec.being_setkey = true;
 	rtl_ips_nic_on(hw);
 	mutex_lock(&rtlpriv->locks.conf_mutex);
@@ -1204,21 +1479,23 @@
 		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:CCMP\n");
 		break;
 	case WLAN_CIPHER_SUITE_AES_CMAC:
-		/*HW doesn't support CMAC encryption, use software CMAC */
+		/* HW don't support CMAC encryption,
+		 * use software CMAC encryption
+		 */
 		key_type = AESCMAC_ENCRYPTION;
 		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:CMAC\n");
 		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
-			 "HW don't support CMAC encryption, use software CMAC\n");
+			 "HW don't support CMAC encrypiton, use software CMAC encrypiton\n");
 		err = -EOPNOTSUPP;
 		goto out_unlock;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "alg_err:%x!!!!\n",
-			 key->cipher);
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "alg_err:%x!!!!:\n", key->cipher);
 		goto out_unlock;
 	}
 	if (key_type == WEP40_ENCRYPTION ||
-			key_type == WEP104_ENCRYPTION ||
-			mac->opmode == NL80211_IFTYPE_ADHOC)
+	   key_type == WEP104_ENCRYPTION ||
+	   vif->type == NL80211_IFTYPE_ADHOC)
 		rtlpriv->sec.use_defaultkey = true;
 
 	/* <2> get key_idx */
@@ -1232,14 +1509,14 @@
 	 * 1) wep only: is just for wep enc, in this condition
 	 * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION
 	 * will be true & enable_hw_sec will be set when wep
-	 * key setting.
+	 * ke setting.
 	 * 2) wep(group) + AES(pairwise): some AP like cisco
 	 * may use it, in this condition enable_hw_sec will not
 	 * be set when wep key setting */
 	/* we must reset sec_info after lingked before set key,
 	 * or some flag will be wrong*/
 	if (vif->type == NL80211_IFTYPE_AP ||
-	    vif->type == NL80211_IFTYPE_MESH_POINT) {
+		vif->type == NL80211_IFTYPE_MESH_POINT) {
 		if (!group_key || key_type == WEP40_ENCRYPTION ||
 			key_type == WEP104_ENCRYPTION) {
 			if (group_key)
@@ -1247,11 +1524,11 @@
 			rtlpriv->cfg->ops->enable_hw_sec(hw);
 		}
 	} else {
-		if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) ||
-		     rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) {
+		if ((!group_key) || (vif->type == NL80211_IFTYPE_ADHOC) ||
+		    rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) {
 			if (rtlpriv->sec.pairwise_enc_algorithm ==
 			    NO_ENCRYPTION &&
-			    (key_type == WEP40_ENCRYPTION ||
+			   (key_type == WEP40_ENCRYPTION ||
 			    key_type == WEP104_ENCRYPTION))
 				wep_only = true;
 			rtlpriv->sec.pairwise_enc_algorithm = key_type;
@@ -1323,7 +1600,7 @@
 			 "disable key delete one entry\n");
 		/*set local buf about wep key. */
 		if (vif->type == NL80211_IFTYPE_AP ||
-		    vif->type == NL80211_IFTYPE_MESH_POINT) {
+			vif->type == NL80211_IFTYPE_MESH_POINT) {
 			if (sta)
 				rtl_cam_del_entry(hw, sta->addr);
 		}
@@ -1336,13 +1613,10 @@
 		 *or clear all entry here.
 		 */
 		rtl_cam_delete_one_entry(hw, mac_addr, key_idx);
-
-		rtl_cam_reset_sec_info(hw);
-
 		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "cmd_err:%x!!!!\n", cmd);
+			 "cmd_err:%x!!!!:\n", cmd);
 	}
 out_unlock:
 	mutex_unlock(&rtlpriv->locks.conf_mutex);
@@ -1372,7 +1646,7 @@
 
 			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 				 "wireless radio switch turned %s\n",
-				 radio_state ? "on" : "off");
+				  radio_state ? "on" : "off");
 
 			blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1;
 			wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
@@ -1383,18 +1657,148 @@
 }
 
 /* this function is called by mac80211 to flush tx buffer
- * before switch channel or power save, or tx buffer packet
+ * before switch channle or power save, or tx buffer packet
  * maybe send after offchannel or rf sleep, this may cause
  * dis-association by AP */
-static void rtl_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-			 u32 queues, bool drop)
+static void rtl_op_flush(struct ieee80211_hw *hw,
+			 struct ieee80211_vif *vif,
+			 u32 queues,
+			 bool drop)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	if (rtlpriv->intf_ops->flush)
-		rtlpriv->intf_ops->flush(hw, drop);
+		rtlpriv->intf_ops->flush(hw, queues, drop);
 }
 
+/*	Description:
+ *		This routine deals with the Power Configuration CMD
+ *		 parsing for RTL8723/RTL8188E Series IC.
+ *	Assumption:
+ *		We should follow specific format that was released from HW SD.
+ */
+bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+			      u8 faversion, u8 interface_type,
+			      struct wlan_pwr_cfg pwrcfgcmd[])
+{
+	struct wlan_pwr_cfg cfg_cmd = {0};
+	bool polling_bit = false;
+	u32 ary_idx = 0;
+	u8 value = 0;
+	u32 offset = 0;
+	u32 polling_count = 0;
+	u32 max_polling_cnt = 5000;
+
+	do {
+		cfg_cmd = pwrcfgcmd[ary_idx];
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "rtl_hal_pwrseqcmdparsing(): offset(%#x),cut_msk(%#x), famsk(%#x), interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), value(%#x)\n",
+			 GET_PWR_CFG_OFFSET(cfg_cmd),
+					    GET_PWR_CFG_CUT_MASK(cfg_cmd),
+			 GET_PWR_CFG_FAB_MASK(cfg_cmd),
+					      GET_PWR_CFG_INTF_MASK(cfg_cmd),
+			 GET_PWR_CFG_BASE(cfg_cmd), GET_PWR_CFG_CMD(cfg_cmd),
+			 GET_PWR_CFG_MASK(cfg_cmd), GET_PWR_CFG_VALUE(cfg_cmd));
+
+		if ((GET_PWR_CFG_FAB_MASK(cfg_cmd)&faversion) &&
+		    (GET_PWR_CFG_CUT_MASK(cfg_cmd)&cut_version) &&
+		    (GET_PWR_CFG_INTF_MASK(cfg_cmd)&interface_type)) {
+			switch (GET_PWR_CFG_CMD(cfg_cmd)) {
+			case PWR_CMD_READ:
+				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_READ\n");
+				break;
+			case PWR_CMD_WRITE:
+				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n");
+				offset = GET_PWR_CFG_OFFSET(cfg_cmd);
+
+				/*Read the value from system register*/
+				value = rtl_read_byte(rtlpriv, offset);
+				value &= (~(GET_PWR_CFG_MASK(cfg_cmd)));
+				value |= (GET_PWR_CFG_VALUE(cfg_cmd) &
+					  GET_PWR_CFG_MASK(cfg_cmd));
+
+				/*Write the value back to sytem register*/
+				rtl_write_byte(rtlpriv, offset, value);
+				break;
+			case PWR_CMD_POLLING:
+				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n");
+				polling_bit = false;
+				offset = GET_PWR_CFG_OFFSET(cfg_cmd);
+
+				do {
+					value = rtl_read_byte(rtlpriv, offset);
+
+					value &= GET_PWR_CFG_MASK(cfg_cmd);
+					if (value ==
+					    (GET_PWR_CFG_VALUE(cfg_cmd) &
+					     GET_PWR_CFG_MASK(cfg_cmd)))
+						polling_bit = true;
+					else
+						udelay(10);
+
+					if (polling_count++ > max_polling_cnt)
+						return false;
+				} while (!polling_bit);
+				break;
+			case PWR_CMD_DELAY:
+				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+					 "rtl_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n");
+				if (GET_PWR_CFG_VALUE(cfg_cmd) ==
+				    PWRSEQ_DELAY_US)
+					udelay(GET_PWR_CFG_OFFSET(cfg_cmd));
+				else
+					mdelay(GET_PWR_CFG_OFFSET(cfg_cmd));
+				break;
+			case PWR_CMD_END:
+				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+					 "rtl_hal_pwrseqcmdparsing(): PWR_CMD_END\n");
+				return true;
+			default:
+				RT_ASSERT(false,
+					  "rtl_hal_pwrseqcmdparsing(): Unknown CMD!!\n");
+				break;
+			}
+		}
+		ary_idx++;
+	} while (1);
+
+	return true;
+}
+EXPORT_SYMBOL(rtl_hal_pwrseqcmdparsing);
+
+bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl8192_tx_ring *ring;
+	struct rtl_tx_desc *pdesc;
+	unsigned long flags;
+	struct sk_buff *pskb = NULL;
+
+	ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+	pskb = __skb_dequeue(&ring->queue);
+	if (pskb)
+		kfree_skb(pskb);
+
+	/*this is wrong, fill_tx_cmddesc needs update*/
+	pdesc = &ring->desc[0];
+
+	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
+
+	__skb_queue_tail(&ring->queue, skb);
+
+	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
+
+	return true;
+}
+EXPORT_SYMBOL(rtl_cmd_send_packet);
 const struct ieee80211_ops rtl_ops = {
 	.start = rtl_op_start,
 	.stop = rtl_op_stop,
@@ -1402,10 +1806,12 @@
 	.add_interface = rtl_op_add_interface,
 	.remove_interface = rtl_op_remove_interface,
 	.change_interface = rtl_op_change_interface,
+#ifdef CONFIG_PM
+	.suspend = rtl_op_suspend,
+	.resume = rtl_op_resume,
+#endif
 	.config = rtl_op_config,
 	.configure_filter = rtl_op_configure_filter,
-	.sta_add = rtl_op_sta_add,
-	.sta_remove = rtl_op_sta_remove,
 	.set_key = rtl_op_set_key,
 	.conf_tx = rtl_op_conf_tx,
 	.bss_info_changed = rtl_op_bss_info_changed,
@@ -1417,6 +1823,8 @@
 	.sw_scan_start = rtl_op_sw_scan_start,
 	.sw_scan_complete = rtl_op_sw_scan_complete,
 	.rfkill_poll = rtl_op_rfkill_poll,
+	.sta_add = rtl_op_sta_add,
+	.sta_remove = rtl_op_sta_remove,
 	.flush = rtl_op_flush,
 };
 EXPORT_SYMBOL_GPL(rtl_ops);
diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h
index 027e753..59cd3b9 100644
--- a/drivers/net/wireless/rtlwifi/core.h
+++ b/drivers/net/wireless/rtlwifi/core.h
@@ -2,20 +2,16 @@
  *
  * Copyright(c) 2009-2012  Realtek Corporation.
  *
- * Tmis program is free software; you can redistribute it and/or modify it
+ * 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.
  *
- * Tmis program is distributed in the hope that it will be useful, but WITHOUT
+ * 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.
  *
- * You should have received a copy of the GNU General Public License along with
- * tmis program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Tme full GNU General Public License is included in this distribution in the
+ * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
  * Contact Information:
@@ -45,5 +41,6 @@
 void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr,
 		     u32 mask, u32 data);
 void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data);
+bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/debug.c b/drivers/net/wireless/rtlwifi/debug.c
index 76e2086..fd25aba 100644
--- a/drivers/net/wireless/rtlwifi/debug.c
+++ b/drivers/net/wireless/rtlwifi/debug.c
@@ -2,20 +2,16 @@
  *
  * Copyright(c) 2009-2012  Realtek Corporation.
  *
- * Tmis program is free software; you can redistribute it and/or modify it
+ * 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.
  *
- * Tmis program is distributed in the hope that it will be useful, but WITHOUT
+ * 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.
  *
- * You should have received a copy of the GNU General Public License along with
- * tmis program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Tme full GNU General Public License is included in this distribution in the
+ * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
  * Contact Information:
diff --git a/drivers/net/wireless/rtlwifi/debug.h b/drivers/net/wireless/rtlwifi/debug.h
index 2e8950d..31d69b2 100644
--- a/drivers/net/wireless/rtlwifi/debug.h
+++ b/drivers/net/wireless/rtlwifi/debug.h
@@ -2,20 +2,16 @@
  *
  * Copyright(c) 2009-2012  Realtek Corporation.
  *
- * Tmis program is free software; you can redistribute it and/or modify it
+ * 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.
  *
- * Tmis program is distributed in the hope that it will be useful, but WITHOUT
+ * 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.
  *
- * You should have received a copy of the GNU General Public License along with
- * tmis program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Tme full GNU General Public License is included in this distribution in the
+ * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
  * Contact Information:
@@ -108,6 +104,7 @@
 #define COMP_USB			BIT(29)
 #define COMP_EASY_CONCURRENT	COMP_USB /* reuse of this bit is OK */
 #define COMP_BT_COEXIST			BIT(30)
+#define COMP_IQK			BIT(31)
 
 /*--------------------------------------------------------------
 		Define the rt_print components
diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c
index 2ffc729..0b4082c 100644
--- a/drivers/net/wireless/rtlwifi/efuse.c
+++ b/drivers/net/wireless/rtlwifi/efuse.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * tmis program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * Tme full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -26,10 +22,9 @@
  * Larry Finger <Larry.Finger@lwfinger.net>
  *
  *****************************************************************************/
-
-#include <linux/export.h>
 #include "wifi.h"
 #include "efuse.h"
+#include <linux/export.h>
 
 static const u8 MAX_PGPKT_SIZE = 9;
 static const u8 PGPKT_DATA_SIZE = 8;
@@ -63,21 +58,19 @@
 				     u16 value);
 static void efuse_shadow_write_4byte(struct ieee80211_hw *hw, u16 offset,
 				     u32 value);
-static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr,
-					u8 *data);
 static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr,
-					u8 data);
+				u8 data);
 static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse);
 static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset,
-					u8 *data);
+				u8 *data);
 static int efuse_pg_packet_write(struct ieee80211_hw *hw, u8 offset,
 				 u8 word_en, u8 *data);
 static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata,
 					u8 *targetdata);
-static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw,
-				       u16 efuse_addr, u8 word_en, u8 *data);
+static u8 enable_efuse_data_write(struct ieee80211_hw *hw,
+				  u16 efuse_addr, u8 word_en, u8 *data);
 static void efuse_power_switch(struct ieee80211_hw *hw, u8 write,
-					u8 pwrstate);
+			       u8 pwrstate);
 static u16 efuse_get_current_size(struct ieee80211_hw *hw);
 static u8 efuse_calculate_word_cnts(u8 word_en);
 
@@ -258,7 +251,7 @@
 	}
 
 	/* allocate memory for efuse_tbl and efuse_word */
-	efuse_tbl = kmalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE] *
+	efuse_tbl = kzalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE] *
 			    sizeof(u8), GFP_ATOMIC);
 	if (!efuse_tbl)
 		return;
@@ -266,7 +259,7 @@
 	if (!efuse_word)
 		goto out;
 	for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
-		efuse_word[i] = kmalloc(efuse_max_section * sizeof(u16),
+		efuse_word[i] = kzalloc(efuse_max_section * sizeof(u16),
 					GFP_ATOMIC);
 		if (!efuse_word[i])
 			goto done;
@@ -413,8 +406,7 @@
 	efuse_used = rtlefuse->efuse_usedbytes;
 
 	if ((totalbytes + efuse_used) >=
-	    (EFUSE_MAX_SIZE -
-	     rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))
+	    (EFUSE_MAX_SIZE - rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))
 		result = false;
 
 	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
@@ -428,13 +420,14 @@
 		       u16 offset, u32 *value)
 {
 	if (type == 1)
-		efuse_shadow_read_1byte(hw, offset, (u8 *) value);
+		efuse_shadow_read_1byte(hw, offset, (u8 *)value);
 	else if (type == 2)
-		efuse_shadow_read_2byte(hw, offset, (u16 *) value);
+		efuse_shadow_read_2byte(hw, offset, (u16 *)value);
 	else if (type == 4)
 		efuse_shadow_read_4byte(hw, offset, value);
 
 }
+EXPORT_SYMBOL(efuse_shadow_read);
 
 void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset,
 				u32 value)
@@ -456,7 +449,7 @@
 	u8 word_en = 0x0F;
 	u8 first_pg = false;
 
-	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, "--->\n");
+	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, "\n");
 
 	if (!efuse_shadow_update_chk(hw)) {
 		efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);
@@ -465,7 +458,7 @@
 		       rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
 
 		RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
-			 "<---efuse out of capacity!!\n");
+			 "efuse out of capacity!!\n");
 		return false;
 	}
 	efuse_power_switch(hw, true, true);
@@ -477,7 +470,6 @@
 
 		for (i = 0; i < 8; i++) {
 			if (first_pg) {
-
 				word_en &= ~(BIT(i / 2));
 
 				rtlefuse->efuse_map[EFUSE_INIT_MAP][base + i] =
@@ -500,7 +492,7 @@
 			       &rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base],
 			       8);
 			RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD,
-				      "U-efuse", tmpdata, 8);
+				      "U-efuse\n", tmpdata, 8);
 
 			if (!efuse_pg_packet_write(hw, (u8) offset, word_en,
 						   tmpdata)) {
@@ -519,7 +511,7 @@
 	       &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
 	       rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
 
-	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, "<---\n");
+	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, "\n");
 	return true;
 }
 
@@ -529,14 +521,14 @@
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 
 	if (rtlefuse->autoload_failflag)
-		memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF,
-			rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
+		memset((&rtlefuse->efuse_map[EFUSE_INIT_MAP][0]),
+		       0xFF, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
 	else
 		efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);
 
 	memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0],
-	       &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
-	       rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
+			&rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+			rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
 
 }
 EXPORT_SYMBOL(rtl_efuse_shadow_map_update);
@@ -619,7 +611,7 @@
 
 }
 
-static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data)
+int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 tmpidx = 0;
@@ -650,14 +642,15 @@
 	}
 	return result;
 }
+EXPORT_SYMBOL(efuse_one_byte_read);
 
 static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 tmpidx = 0;
 
-	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, "Addr = %x Data=%x\n",
-		 addr, data);
+	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
+		 "Addr = %x Data=%x\n", addr, data);
 
 	rtl_write_byte(rtlpriv,
 		       rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (u8) (addr & 0xff));
@@ -677,11 +670,10 @@
 
 	if (tmpidx < 100)
 		return true;
-
 	return false;
 }
 
-static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse)
+static void efuse_read_all_map(struct ieee80211_hw *hw, u8 *efuse)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	efuse_power_switch(hw, false, true);
@@ -706,14 +698,14 @@
 	if (hoffset == offset) {
 		for (tmpidx = 0; tmpidx < word_cnts * 2; tmpidx++) {
 			if (efuse_one_byte_read(hw, *efuse_addr + 1 + tmpidx,
-			    &efuse_data)) {
+						&efuse_data)) {
 				tmpdata[tmpidx] = efuse_data;
 				if (efuse_data != 0xff)
-					dataempty = true;
+					dataempty = false;
 			}
 		}
 
-		if (dataempty) {
+		if (!dataempty) {
 			*readstate = PG_STATE_DATA;
 		} else {
 			*efuse_addr = *efuse_addr + (word_cnts * 2) + 1;
@@ -729,7 +721,9 @@
 static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data)
 {
 	u8 readstate = PG_STATE_HEADER;
+
 	bool continual = true;
+
 	u8 efuse_data, word_cnts = 0;
 	u16 efuse_addr = 0;
 	u8 tmpdata[8];
@@ -747,9 +741,8 @@
 			if (efuse_one_byte_read(hw, efuse_addr, &efuse_data)
 			    && (efuse_data != 0xFF))
 				efuse_read_data_case1(hw, &efuse_addr,
-						      efuse_data,
-						      offset, tmpdata,
-						      &readstate);
+						      efuse_data, offset,
+						      tmpdata, &readstate);
 			else
 				continual = false;
 		} else if (readstate & PG_STATE_DATA) {
@@ -771,13 +764,14 @@
 }
 
 static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
-			u8 efuse_data, u8 offset, int *continual,
-			u8 *write_state, struct pgpkt_struct *target_pkt,
-			int *repeat_times, int *result, u8 word_en)
+				   u8 efuse_data, u8 offset,
+				   int *continual, u8 *write_state,
+				   struct pgpkt_struct *target_pkt,
+				   int *repeat_times, int *result, u8 word_en)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct pgpkt_struct tmp_pkt;
-	bool dataempty = true;
+	int dataempty = true;
 	u8 originaldata[8 * sizeof(u8)];
 	u8 badworden = 0x0F;
 	u8 match_word_en, tmp_word_en;
@@ -794,9 +788,10 @@
 		*write_state = PG_STATE_HEADER;
 	} else {
 		for (tmpindex = 0; tmpindex < (tmp_word_cnts * 2); tmpindex++) {
-			u16 address = *efuse_addr + 1 + tmpindex;
-			if (efuse_one_byte_read(hw, address,
-			     &efuse_data) && (efuse_data != 0xFF))
+			if (efuse_one_byte_read(hw,
+						(*efuse_addr + 1 + tmpindex),
+						&efuse_data) &&
+			    (efuse_data != 0xFF))
 				dataempty = false;
 		}
 
@@ -806,33 +801,34 @@
 		} else {
 			match_word_en = 0x0F;
 			if (!((target_pkt->word_en & BIT(0)) |
-			     (tmp_pkt.word_en & BIT(0))))
+			    (tmp_pkt.word_en & BIT(0))))
 				match_word_en &= (~BIT(0));
 
 			if (!((target_pkt->word_en & BIT(1)) |
-			     (tmp_pkt.word_en & BIT(1))))
+			    (tmp_pkt.word_en & BIT(1))))
 				match_word_en &= (~BIT(1));
 
 			if (!((target_pkt->word_en & BIT(2)) |
-			     (tmp_pkt.word_en & BIT(2))))
+			    (tmp_pkt.word_en & BIT(2))))
 				match_word_en &= (~BIT(2));
 
 			if (!((target_pkt->word_en & BIT(3)) |
-			     (tmp_pkt.word_en & BIT(3))))
+			    (tmp_pkt.word_en & BIT(3))))
 				match_word_en &= (~BIT(3));
 
 			if ((match_word_en & 0x0F) != 0x0F) {
-				badworden = efuse_word_enable_data_write(
-							    hw, *efuse_addr + 1,
-							    tmp_pkt.word_en,
-							    target_pkt->data);
+				badworden =
+				  enable_efuse_data_write(hw,
+							  *efuse_addr + 1,
+							  tmp_pkt.word_en,
+							  target_pkt->data);
 
-				if (0x0F != (badworden & 0x0F)) {
+				if (0x0F != (badworden & 0x0F))	{
 					u8 reorg_offset = offset;
 					u8 reorg_worden = badworden;
 					efuse_pg_packet_write(hw, reorg_offset,
-							       reorg_worden,
-							       originaldata);
+							      reorg_worden,
+							      originaldata);
 				}
 
 				tmp_word_en = 0x0F;
@@ -845,11 +841,11 @@
 					tmp_word_en &= (~BIT(1));
 
 				if ((target_pkt->word_en & BIT(2)) ^
-				     (match_word_en & BIT(2)))
+				    (match_word_en & BIT(2)))
 					tmp_word_en &= (~BIT(2));
 
 				if ((target_pkt->word_en & BIT(3)) ^
-				     (match_word_en & BIT(3)))
+				    (match_word_en & BIT(3)))
 					tmp_word_en &= (~BIT(3));
 
 				if ((tmp_word_en & 0x0F) != 0x0F) {
@@ -873,7 +869,7 @@
 			}
 		}
 	}
-	RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,  "efuse PG_STATE_HEADER-1\n");
+	RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse PG_STATE_HEADER-1\n");
 }
 
 static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr,
@@ -908,12 +904,13 @@
 
 		tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en);
 
-		memset(originaldata, 0xff, 8 * sizeof(u8));
+		memset(originaldata, 0xff,  8 * sizeof(u8));
 
 		if (efuse_pg_packet_read(hw, tmp_pkt.offset, originaldata)) {
-			badworden = efuse_word_enable_data_write(hw,
-				    *efuse_addr + 1, tmp_pkt.word_en,
-				    originaldata);
+			badworden = enable_efuse_data_write(hw,
+							    *efuse_addr + 1,
+							    tmp_pkt.word_en,
+							    originaldata);
 
 			if (0x0F != (badworden & 0x0F)) {
 				u8 reorg_offset = tmp_pkt.offset;
@@ -923,8 +920,8 @@
 						      originaldata);
 				*efuse_addr = efuse_get_current_size(hw);
 			} else {
-				*efuse_addr = *efuse_addr + (tmp_word_cnts * 2)
-					      + 1;
+				*efuse_addr = *efuse_addr +
+					      (tmp_word_cnts * 2) + 1;
 			}
 		} else {
 			*efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
@@ -948,7 +945,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct pgpkt_struct target_pkt;
 	u8 write_state = PG_STATE_HEADER;
-	int continual = true, result = true;
+	int continual = true, dataempty = true, result = true;
 	u16 efuse_addr = 0;
 	u8 efuse_data;
 	u8 target_word_cnts = 0;
@@ -956,7 +953,7 @@
 	static int repeat_times;
 
 	if (efuse_get_current_size(hw) >= (EFUSE_MAX_SIZE -
-	    rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {
+		rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {
 		RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
 			"efuse_pg_packet_write error\n");
 		return false;
@@ -965,17 +962,18 @@
 	target_pkt.offset = offset;
 	target_pkt.word_en = word_en;
 
-	memset(target_pkt.data, 0xFF, 8 * sizeof(u8));
+	memset(target_pkt.data, 0xFF,  8 * sizeof(u8));
 
 	efuse_word_enable_data_read(word_en, data, target_pkt.data);
 	target_word_cnts = efuse_calculate_word_cnts(target_pkt.word_en);
 
-	RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,  "efuse Power ON\n");
+	RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse Power ON\n");
 
 	while (continual && (efuse_addr < (EFUSE_MAX_SIZE -
-	       rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) {
+		rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) {
 
 		if (write_state == PG_STATE_HEADER) {
+			dataempty = true;
 			badworden = 0x0F;
 			RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
 				"efuse PG_STATE_HEADER\n");
@@ -985,7 +983,8 @@
 				efuse_write_data_case1(hw, &efuse_addr,
 						       efuse_data, offset,
 						       &continual,
-						       &write_state, &target_pkt,
+						       &write_state,
+						       &target_pkt,
 						       &repeat_times, &result,
 						       word_en);
 			else
@@ -999,15 +998,17 @@
 		} else if (write_state == PG_STATE_DATA) {
 			RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
 				"efuse PG_STATE_DATA\n");
+			badworden = 0x0f;
 			badworden =
-			    efuse_word_enable_data_write(hw, efuse_addr + 1,
-							 target_pkt.word_en,
-							 target_pkt.data);
+			    enable_efuse_data_write(hw, efuse_addr + 1,
+						    target_pkt.word_en,
+						    target_pkt.data);
 
 			if ((badworden & 0x0F) == 0x0F) {
 				continual = false;
 			} else {
-				efuse_addr += (2 * target_word_cnts) + 1;
+				efuse_addr =
+				    efuse_addr + (2 * target_word_cnts) + 1;
 
 				target_pkt.offset = offset;
 				target_pkt.word_en = badworden;
@@ -1027,7 +1028,7 @@
 	}
 
 	if (efuse_addr >= (EFUSE_MAX_SIZE -
-	    rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {
+		rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {
 		RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
 			 "efuse_addr(%#x) Out of size!!\n", efuse_addr);
 	}
@@ -1035,8 +1036,8 @@
 	return true;
 }
 
-static void efuse_word_enable_data_read(u8 word_en,
-					u8 *sourdata, u8 *targetdata)
+static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata,
+					u8 *targetdata)
 {
 	if (!(word_en & BIT(0))) {
 		targetdata[0] = sourdata[0];
@@ -1059,8 +1060,8 @@
 	}
 }
 
-static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw,
-				       u16 efuse_addr, u8 word_en, u8 *data)
+static u8 enable_efuse_data_write(struct ieee80211_hw *hw,
+				  u16 efuse_addr, u8 word_en, u8 *data)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u16 tmpaddr;
@@ -1069,8 +1070,8 @@
 	u8 tmpdata[8];
 
 	memset(tmpdata, 0xff, PGPKT_DATA_SIZE);
-	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, "word_en = %x efuse_addr=%x\n",
-		 word_en, efuse_addr);
+	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
+		 "word_en = %x efuse_addr=%x\n", word_en, efuse_addr);
 
 	if (!(word_en & BIT(0))) {
 		tmpaddr = start_addr;
@@ -1127,19 +1128,22 @@
 	u16 tmpV16;
 
 	if (pwrstate && (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)) {
-		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE)
-			rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_ACCESS],
-				       0x69);
 
-		tmpV16 = rtl_read_word(rtlpriv,
-				       rtlpriv->cfg->maps[SYS_ISO_CTRL]);
-		if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) {
-			tmpV16 |= rtlpriv->cfg->maps[EFUSE_PWC_EV12V];
-			rtl_write_word(rtlpriv,
-				       rtlpriv->cfg->maps[SYS_ISO_CTRL],
-				       tmpV16);
+		if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE &&
+		    rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE) {
+			rtl_write_byte(rtlpriv,
+				       rtlpriv->cfg->maps[EFUSE_ACCESS], 0x69);
+		} else {
+			tmpV16 =
+			  rtl_read_word(rtlpriv,
+					rtlpriv->cfg->maps[SYS_ISO_CTRL]);
+			if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) {
+				tmpV16 |= rtlpriv->cfg->maps[EFUSE_PWC_EV12V];
+				rtl_write_word(rtlpriv,
+					       rtlpriv->cfg->maps[SYS_ISO_CTRL],
+					       tmpV16);
+			}
 		}
-
 		tmpV16 = rtl_read_word(rtlpriv,
 				       rtlpriv->cfg->maps[SYS_FUNC_EN]);
 		if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_FEN_ELDR])) {
@@ -1164,7 +1168,10 @@
 						rtlpriv->cfg->maps[EFUSE_TEST] +
 						3);
 
-			if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) {
+			if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+				tempval &= ~(BIT(3) | BIT(4) | BIT(5) | BIT(6));
+				tempval |= (VOLTAGE_V25 << 3);
+			} else if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) {
 				tempval &= 0x0F;
 				tempval |= (VOLTAGE_V25 << 4);
 			}
@@ -1176,11 +1183,11 @@
 
 		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
 			rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK],
-						0x03);
+				       0x03);
 		}
-
 	} else {
-		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE)
+		if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192CE &&
+		    rtlhal->hw_type != HARDWARE_TYPE_RTL8192DE)
 			rtl_write_byte(rtlpriv,
 				       rtlpriv->cfg->maps[EFUSE_ACCESS], 0);
 
@@ -1195,27 +1202,28 @@
 
 		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
 			rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK],
-						0x02);
+				       0x02);
 		}
-
 	}
-
 }
 
 static u16 efuse_get_current_size(struct ieee80211_hw *hw)
 {
+	int continual = true;
 	u16 efuse_addr = 0;
-	u8 hworden;
+	u8 hoffset, hworden;
 	u8 efuse_data, word_cnts;
 
-	while (efuse_one_byte_read(hw, efuse_addr, &efuse_data) &&
-	       efuse_addr < EFUSE_MAX_SIZE) {
-		if (efuse_data == 0xFF)
-			break;
-
-		hworden = efuse_data & 0x0F;
-		word_cnts = efuse_calculate_word_cnts(hworden);
-		efuse_addr = efuse_addr + (word_cnts * 2) + 1;
+	while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) &&
+	       (efuse_addr < EFUSE_MAX_SIZE)) {
+		if (efuse_data != 0xFF) {
+			hoffset = (efuse_data >> 4) & 0x0F;
+			hworden = efuse_data & 0x0F;
+			word_cnts = efuse_calculate_word_cnts(hworden);
+			efuse_addr = efuse_addr + (word_cnts * 2) + 1;
+		} else {
+			continual = false;
+		}
 	}
 
 	return efuse_addr;
diff --git a/drivers/net/wireless/rtlwifi/efuse.h b/drivers/net/wireless/rtlwifi/efuse.h
index 1663b3a..fdab824 100644
--- a/drivers/net/wireless/rtlwifi/efuse.h
+++ b/drivers/net/wireless/rtlwifi/efuse.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -32,7 +28,6 @@
 
 #define EFUSE_IC_ID_OFFSET		506
 
-#define EFUSE_MAP_LEN			128
 #define EFUSE_MAX_WORD_UNIT		4
 
 #define EFUSE_INIT_MAP			0
@@ -107,12 +102,14 @@
 void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf);
 void efuse_initialize(struct ieee80211_hw *hw);
 u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address);
+int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data);
 void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value);
-void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf);
-void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, u16 offset,
-		       u32 *value);
-void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset,
-			u32 value);
+void read_efuse(struct ieee80211_hw *hw, u16 _offset,
+		u16 _size_byte, u8 *pbuf);
+void efuse_shadow_read(struct ieee80211_hw *hw, u8 type,
+		       u16 offset, u32 *value);
+void efuse_shadow_write(struct ieee80211_hw *hw, u8 type,
+			u16 offset, u32 value);
 bool efuse_shadow_update(struct ieee80211_hw *hw);
 bool efuse_shadow_update_chk(struct ieee80211_hw *hw);
 void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 67d1ee6..667aba8 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -33,6 +33,7 @@
 #include "base.h"
 #include "ps.h"
 #include "efuse.h"
+#include <linux/interrupt.h>
 #include <linux/export.h>
 #include <linux/kmemleak.h>
 #include <linux/module.h>
@@ -44,10 +45,10 @@
 MODULE_DESCRIPTION("PCI basic driver for rtlwifi");
 
 static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
-	PCI_VENDOR_ID_INTEL,
-	PCI_VENDOR_ID_ATI,
-	PCI_VENDOR_ID_AMD,
-	PCI_VENDOR_ID_SI
+	INTEL_VENDOR_ID,
+	ATI_VENDOR_ID,
+	AMD_VENDOR_ID,
+	SIS_VENDOR_ID
 };
 
 static const u8 ac_to_hwq[] = {
@@ -566,27 +567,25 @@
 	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio];
 
 	while (skb_queue_len(&ring->queue)) {
-		struct rtl_tx_desc *entry = &ring->desc[ring->idx];
 		struct sk_buff *skb;
 		struct ieee80211_tx_info *info;
 		__le16 fc;
 		u8 tid;
+		u8 *entry;
 
-		u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true,
-							  HW_DESC_OWN);
+		if (rtlpriv->use_new_trx_flow)
+			entry = (u8 *)(&ring->buffer_desc[ring->idx]);
+		else
+			entry = (u8 *)(&ring->desc[ring->idx]);
 
-		/*beacon packet will only use the first
-		 *descriptor by defaut, and the own may not
-		 *be cleared by the hardware
-		 */
-		if (own)
+		if (!rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx))
 			return;
 		ring->idx = (ring->idx + 1) % ring->entries;
 
 		skb = __skb_dequeue(&ring->queue);
 		pci_unmap_single(rtlpci->pdev,
 				 rtlpriv->cfg->ops->
-					     get_desc((u8 *) entry, true,
+					     get_desc((u8 *)entry, true,
 						      HW_DESC_TXBUFF_ADDR),
 				 skb->len, PCI_DMA_TODEVICE);
 
@@ -598,7 +597,7 @@
 			 "new ring->idx:%d, free: skb_queue_len:%d, free: seq:%x\n",
 			 ring->idx,
 			 skb_queue_len(&ring->queue),
-			 *(u16 *) (skb->data + 22));
+			 *(u16 *)(skb->data + 22));
 
 		if (prio == TXCMD_QUEUE) {
 			dev_kfree_skb(skb);
@@ -646,7 +645,7 @@
 				== 2) {
 
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
-				 "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%d\n",
+				 "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%x\n",
 				 prio, ring->idx,
 				 skb_queue_len(&ring->queue));
 
@@ -666,175 +665,276 @@
 	}
 }
 
-static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb,
-			     struct ieee80211_rx_status rx_status)
+static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
+				    u8 *entry, int rxring_idx, int desc_idx)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
-	__le16 fc = rtl_get_fc(skb);
-	bool unicast = false;
-	struct sk_buff *uskb = NULL;
-	u8 *pdata;
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u32 bufferaddress;
+	u8 tmp_one = 1;
+	struct sk_buff *skb;
 
+	skb = dev_alloc_skb(rtlpci->rxbuffersize);
+	if (!skb)
+		return 0;
+	rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;
 
-	memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
-
-	if (is_broadcast_ether_addr(hdr->addr1)) {
-		;/*TODO*/
-	} else if (is_multicast_ether_addr(hdr->addr1)) {
-		;/*TODO*/
+	/* just set skb->cb to mapping addr for pci_unmap_single use */
+	*((dma_addr_t *)skb->cb) =
+		pci_map_single(rtlpci->pdev, skb_tail_pointer(skb),
+			       rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE);
+	bufferaddress = *((dma_addr_t *)skb->cb);
+	if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
+		return 0;
+	if (rtlpriv->use_new_trx_flow) {
+		rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
+					    HW_DESC_RX_PREPARE,
+					    (u8 *)&bufferaddress);
 	} else {
-		unicast = true;
-		rtlpriv->stats.rxbytesunicast += skb->len;
+		rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
+					    HW_DESC_RXBUFF_ADDR,
+					    (u8 *)&bufferaddress);
+		rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
+					    HW_DESC_RXPKT_LEN,
+					    (u8 *)&rtlpci->rxbuffersize);
+		rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
+					    HW_DESC_RXOWN,
+					    (u8 *)&tmp_one);
 	}
+	return 1;
+}
 
-	if (ieee80211_is_data(fc)) {
-		rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX);
+/* inorder to receive 8K AMSDU we have set skb to
+ * 9100bytes in init rx ring, but if this packet is
+ * not a AMSDU, this large packet will be sent to
+ * TCP/IP directly, this cause big packet ping fail
+ * like: "ping -s 65507", so here we will realloc skb
+ * based on the true size of packet, Mac80211
+ * Probably will do it better, but does not yet.
+ *
+ * Some platform will fail when alloc skb sometimes.
+ * in this condition, we will send the old skb to
+ * mac80211 directly, this will not cause any other
+ * issues, but only this packet will be lost by TCP/IP
+ */
+static void _rtl_pci_rx_to_mac80211(struct ieee80211_hw *hw,
+				    struct sk_buff *skb,
+				    struct ieee80211_rx_status rx_status)
+{
+	if (unlikely(!rtl_action_proc(hw, skb, false))) {
+		dev_kfree_skb_any(skb);
+	} else {
+		struct sk_buff *uskb = NULL;
+		u8 *pdata;
 
-		if (unicast)
-			rtlpriv->link_info.num_rx_inperiod++;
+		uskb = dev_alloc_skb(skb->len + 128);
+		if (likely(uskb)) {
+			memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status,
+			       sizeof(rx_status));
+			pdata = (u8 *)skb_put(uskb, skb->len);
+			memcpy(pdata, skb->data, skb->len);
+			dev_kfree_skb_any(skb);
+			ieee80211_rx_irqsafe(hw, uskb);
+		} else {
+			ieee80211_rx_irqsafe(hw, skb);
+		}
 	}
+}
 
-	/* static bcn for roaming */
-	rtl_beacon_statistic(hw, skb);
-	rtl_p2p_info(hw, (void *)skb->data, skb->len);
+/*hsisr interrupt handler*/
+static void _rtl_pci_hs_interrupt(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 
-	/* for sw lps */
-	rtl_swlps_beacon(hw, (void *)skb->data, skb->len);
-	rtl_recognize_peer(hw, (void *)skb->data, skb->len);
-	if ((rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) &&
-	    (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) &&
-	     (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)))
-		return;
-
-	if (unlikely(!rtl_action_proc(hw, skb, false)))
-		return;
-
-	uskb = dev_alloc_skb(skb->len + 128);
-	if (!uskb)
-		return;		/* exit if allocation failed */
-	memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, sizeof(rx_status));
-	pdata = (u8 *)skb_put(uskb, skb->len);
-	memcpy(pdata, skb->data, skb->len);
-
-	ieee80211_rx_irqsafe(hw, uskb);
+	rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR],
+		       rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[MAC_HSISR]) |
+		       rtlpci->sys_irq_mask);
 }
 
 static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-	int rx_queue_idx = RTL_PCI_RX_MPDU_QUEUE;
-
+	int rxring_idx = RTL_PCI_RX_MPDU_QUEUE;
 	struct ieee80211_rx_status rx_status = { 0 };
 	unsigned int count = rtlpci->rxringcount;
 	u8 own;
 	u8 tmp_one;
-	u32 bufferaddress;
-
+	bool unicast = false;
+	u8 hw_queue = 0;
+	unsigned int rx_remained_cnt;
 	struct rtl_stats stats = {
 		.signal = 0,
 		.rate = 0,
 	};
-	int index = rtlpci->rx_ring[rx_queue_idx].idx;
 
-	if (rtlpci->driver_is_goingto_unload)
-		return;
 	/*RX NORMAL PKT */
 	while (count--) {
-		/*rx descriptor */
-		struct rtl_rx_desc *pdesc = &rtlpci->rx_ring[rx_queue_idx].desc[
-				index];
+		struct ieee80211_hdr *hdr;
+		__le16 fc;
+		u16 len;
+		/*rx buffer descriptor */
+		struct rtl_rx_buffer_desc *buffer_desc = NULL;
+		/*if use new trx flow, it means wifi info */
+		struct rtl_rx_desc *pdesc = NULL;
 		/*rx pkt */
-		struct sk_buff *skb = rtlpci->rx_ring[rx_queue_idx].rx_buf[
-				index];
-		struct sk_buff *new_skb = NULL;
+		struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[
+				      rtlpci->rx_ring[rxring_idx].idx];
 
-		own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
-						       false, HW_DESC_OWN);
+		if (rtlpriv->use_new_trx_flow) {
+			rx_remained_cnt =
+				rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw,
+								      hw_queue);
+			if (rx_remained_cnt < 1)
+				return;
 
-		/*wait data to be filled by hardware */
-		if (own)
-			break;
+		} else {	/* rx descriptor */
+			pdesc = &rtlpci->rx_ring[rxring_idx].desc[
+				rtlpci->rx_ring[rxring_idx].idx];
 
-		rtlpriv->cfg->ops->query_rx_desc(hw, &stats,
-						 &rx_status,
-						 (u8 *) pdesc, skb);
-
-		if (stats.crc || stats.hwerror)
-			goto done;
-
-		new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
-		if (unlikely(!new_skb)) {
-			RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), DBG_DMESG,
-				 "can't alloc skb for rx\n");
-			goto done;
+			own = (u8)rtlpriv->cfg->ops->get_desc((u8 *)pdesc,
+							      false,
+							      HW_DESC_OWN);
+			if (own) /* wait data to be filled by hardware */
+				return;
 		}
-		kmemleak_not_leak(new_skb);
 
-		pci_unmap_single(rtlpci->pdev,
-				 *((dma_addr_t *) skb->cb),
-				 rtlpci->rxbuffersize,
-				 PCI_DMA_FROMDEVICE);
+		/* Reaching this point means: data is filled already
+		 * AAAAAAttention !!!
+		 * We can NOT access 'skb' before 'pci_unmap_single'
+		 */
+		pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb),
+				 rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE);
 
-		skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc, false,
-			HW_DESC_RXPKT_LEN));
-		skb_reserve(skb, stats.rx_drvinfo_size + stats.rx_bufshift);
+		if (rtlpriv->use_new_trx_flow) {
+			buffer_desc =
+			  &rtlpci->rx_ring[rxring_idx].buffer_desc
+				[rtlpci->rx_ring[rxring_idx].idx];
+			/*means rx wifi info*/
+			pdesc = (struct rtl_rx_desc *)skb->data;
+		}
+		memset(&rx_status , 0 , sizeof(rx_status));
+		rtlpriv->cfg->ops->query_rx_desc(hw, &stats,
+						 &rx_status, (u8 *)pdesc, skb);
+
+		if (rtlpriv->use_new_trx_flow)
+			rtlpriv->cfg->ops->rx_check_dma_ok(hw,
+							   (u8 *)buffer_desc,
+							   hw_queue);
+
+		len = rtlpriv->cfg->ops->get_desc((u8 *)pdesc, false,
+						  HW_DESC_RXPKT_LEN);
+
+		if (skb->end - skb->tail > len) {
+			skb_put(skb, len);
+			if (rtlpriv->use_new_trx_flow)
+				skb_reserve(skb, stats.rx_drvinfo_size +
+					    stats.rx_bufshift + 24);
+			else
+				skb_reserve(skb, stats.rx_drvinfo_size +
+					    stats.rx_bufshift);
+
+		} else {
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+				 "skb->end - skb->tail = %d, len is %d\n",
+				 skb->end - skb->tail, len);
+			break;
+		}
+		/* handle command packet here */
+		if (rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
+				dev_kfree_skb_any(skb);
+				goto end;
+		}
 
 		/*
 		 * NOTICE This can not be use for mac80211,
 		 * this is done in mac80211 code,
-		 * if you done here sec DHCP will fail
+		 * if done here sec DHCP will fail
 		 * skb_trim(skb, skb->len - 4);
 		 */
 
-		_rtl_receive_one(hw, skb, rx_status);
+		hdr = rtl_get_hdr(skb);
+		fc = rtl_get_fc(skb);
 
+		if (!stats.crc && !stats.hwerror) {
+			memcpy(IEEE80211_SKB_RXCB(skb), &rx_status,
+			       sizeof(rx_status));
+
+			if (is_broadcast_ether_addr(hdr->addr1)) {
+				;/*TODO*/
+			} else if (is_multicast_ether_addr(hdr->addr1)) {
+				;/*TODO*/
+			} else {
+				unicast = true;
+				rtlpriv->stats.rxbytesunicast += skb->len;
+			}
+			rtl_is_special_data(hw, skb, false);
+
+			if (ieee80211_is_data(fc)) {
+				rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX);
+				if (unicast)
+					rtlpriv->link_info.num_rx_inperiod++;
+			}
+			/* static bcn for roaming */
+			rtl_beacon_statistic(hw, skb);
+			rtl_p2p_info(hw, (void *)skb->data, skb->len);
+			/* for sw lps */
+			rtl_swlps_beacon(hw, (void *)skb->data, skb->len);
+			rtl_recognize_peer(hw, (void *)skb->data, skb->len);
+			if ((rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) &&
+			    (rtlpriv->rtlhal.current_bandtype ==
+			     BAND_ON_2_4G) &&
+			    (ieee80211_is_beacon(fc) ||
+			     ieee80211_is_probe_resp(fc))) {
+				dev_kfree_skb_any(skb);
+			} else {
+				_rtl_pci_rx_to_mac80211(hw, skb, rx_status);
+			}
+		} else {
+			dev_kfree_skb_any(skb);
+		}
+		if (rtlpriv->use_new_trx_flow) {
+			rtlpci->rx_ring[hw_queue].next_rx_rp += 1;
+			rtlpci->rx_ring[hw_queue].next_rx_rp %=
+					RTL_PCI_MAX_RX_COUNT;
+
+			rx_remained_cnt--;
+			rtl_write_word(rtlpriv, 0x3B4,
+				       rtlpci->rx_ring[hw_queue].next_rx_rp);
+		}
 		if (((rtlpriv->link_info.num_rx_inperiod +
 		      rtlpriv->link_info.num_tx_inperiod) > 8) ||
 		      (rtlpriv->link_info.num_rx_inperiod > 2)) {
 			rtlpriv->enter_ps = false;
 			schedule_work(&rtlpriv->works.lps_change_work);
 		}
+end:
+		if (rtlpriv->use_new_trx_flow) {
+			_rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc,
+						 rxring_idx,
+					       rtlpci->rx_ring[rxring_idx].idx);
+		} else {
+			_rtl_pci_init_one_rxdesc(hw, (u8 *)pdesc, rxring_idx,
+						 rtlpci->rx_ring[rxring_idx].idx);
 
-		dev_kfree_skb_any(skb);
-		skb = new_skb;
-
-		rtlpci->rx_ring[rx_queue_idx].rx_buf[index] = skb;
-		*((dma_addr_t *) skb->cb) =
-			    pci_map_single(rtlpci->pdev, skb_tail_pointer(skb),
-					   rtlpci->rxbuffersize,
-					   PCI_DMA_FROMDEVICE);
-
-done:
-		bufferaddress = (*((dma_addr_t *)skb->cb));
-		if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
-			return;
-		tmp_one = 1;
-		rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false,
-					    HW_DESC_RXBUFF_ADDR,
-					    (u8 *)&bufferaddress);
-		rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false,
-					    HW_DESC_RXPKT_LEN,
-					    (u8 *)&rtlpci->rxbuffersize);
-
-		if (index == rtlpci->rxringcount - 1)
-			rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false,
-						    HW_DESC_RXERO,
-						    &tmp_one);
-
-		rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false, HW_DESC_RXOWN,
-					    &tmp_one);
-
-		index = (index + 1) % rtlpci->rxringcount;
+			if (rtlpci->rx_ring[rxring_idx].idx ==
+			    rtlpci->rxringcount - 1)
+				rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc,
+							    false,
+							    HW_DESC_RXERO,
+							    (u8 *)&tmp_one);
+		}
+		rtlpci->rx_ring[rxring_idx].idx =
+				(rtlpci->rx_ring[rxring_idx].idx + 1) %
+				rtlpci->rxringcount;
 	}
-
-	rtlpci->rx_ring[rx_queue_idx].idx = index;
 }
 
 static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
 {
 	struct ieee80211_hw *hw = dev_id;
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	unsigned long flags;
@@ -842,16 +942,18 @@
 	u32 intb = 0;
 	irqreturn_t ret = IRQ_HANDLED;
 
-	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+	if (rtlpci->irq_enabled == 0)
+		return ret;
+
+	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock , flags);
+	rtlpriv->cfg->ops->disable_interrupt(hw);
 
 	/*read ISR: 4/8bytes */
 	rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb);
 
 	/*Shared IRQ or HW disappared */
-	if (!inta || inta == 0xffff) {
-		ret = IRQ_NONE;
+	if (!inta || inta == 0xffff)
 		goto done;
-	}
 
 	/*<1> beacon related */
 	if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) {
@@ -874,8 +976,8 @@
 		tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet);
 	}
 
-	/*<3> Tx related */
-	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TXFOVW]))
+	/*<2> Tx related */
+	if (unlikely(intb & rtlpriv->cfg->maps[RTL_IMR_TXFOVW]))
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "IMR_TXFOVW!\n");
 
 	if (inta & rtlpriv->cfg->maps[RTL_IMR_MGNTDOK]) {
@@ -932,7 +1034,7 @@
 		}
 	}
 
-	/*<2> Rx related */
+	/*<3> Rx related */
 	if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) {
 		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, "Rx ok interrupt!\n");
 		_rtl_pci_rx_interrupt(hw);
@@ -944,12 +1046,12 @@
 		_rtl_pci_rx_interrupt(hw);
 	}
 
-	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) {
+	if (unlikely(intb & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "rx overflow !\n");
 		_rtl_pci_rx_interrupt(hw);
 	}
 
-	/*fw related*/
+	/*<4> fw related*/
 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723AE) {
 		if (inta & rtlpriv->cfg->maps[RTL_IMR_C2HCMD]) {
 			RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
@@ -959,10 +1061,26 @@
 		}
 	}
 
+	/*<5> hsisr related*/
+	/* Only 8188EE & 8723BE Supported.
+	 * If Other ICs Come in, System will corrupt,
+	 * because maps[RTL_IMR_HSISR_IND] & maps[MAC_HSISR]
+	 * are not initialized
+	 */
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE ||
+	    rtlhal->hw_type == HARDWARE_TYPE_RTL8723BE) {
+		if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_HSISR_IND])) {
+			RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+				 "hsisr interrupt!\n");
+			_rtl_pci_hs_interrupt(hw);
+		}
+	}
+
 	if (rtlpriv->rtlhal.earlymode_enable)
 		tasklet_schedule(&rtlpriv->works.irq_tasklet);
 
 done:
+	rtlpriv->cfg->ops->enable_interrupt(hw);
 	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
 	return ret;
 }
@@ -990,13 +1108,8 @@
 	memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
 	ring = &rtlpci->tx_ring[BEACON_QUEUE];
 	pskb = __skb_dequeue(&ring->queue);
-	if (pskb) {
-		struct rtl_tx_desc *entry = &ring->desc[ring->idx];
-		pci_unmap_single(rtlpci->pdev, rtlpriv->cfg->ops->get_desc(
-				 (u8 *) entry, true, HW_DESC_TXBUFF_ADDR),
-				 pskb->len, PCI_DMA_TODEVICE);
+	if (pskb)
 		kfree_skb(pskb);
-	}
 
 	/*NB: the beacon data buffer must be 32-bit aligned. */
 	pskb = ieee80211_beacon_get(hw, mac->vif);
@@ -1005,7 +1118,10 @@
 	hdr = rtl_get_hdr(pskb);
 	info = IEEE80211_SKB_CB(pskb);
 	pdesc = &ring->desc[0];
-	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
+	if (rtlpriv->use_new_trx_flow)
+		pbuffer_desc = &ring->buffer_desc[0];
+
+	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc,
 					(u8 *)pbuffer_desc, info, NULL, pskb,
 					BEACON_QUEUE, &tcb_desc);
 
@@ -1020,10 +1136,18 @@
 static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
 {
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	u8 i;
+	u16 desc_num;
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE)
+		desc_num = TX_DESC_NUM_92E;
+	else
+		desc_num = RT_TXDESC_NUM;
 
 	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++)
-		rtlpci->txringcount[i] = RT_TXDESC_NUM;
+		rtlpci->txringcount[i] = desc_num;
 
 	/*
 	 *we just alloc 2 desc for beacon queue,
@@ -1031,12 +1155,12 @@
 	 */
 	rtlpci->txringcount[BEACON_QUEUE] = 2;
 
-	/*
-	 *BE queue need more descriptor for performance
+	/*BE queue need more descriptor for performance
 	 *consideration or, No more tx desc will happen,
 	 *and may cause mac80211 mem leakage.
 	 */
-	rtlpci->txringcount[BE_QUEUE] = RT_TXDESC_NUM_BE_QUEUE;
+	if (!rtl_priv(hw)->use_new_trx_flow)
+		rtlpci->txringcount[BE_QUEUE] = RT_TXDESC_NUM_BE_QUEUE;
 
 	rtlpci->rxbuffersize = 9100;	/*2048/1024; */
 	rtlpci->rxringcount = RTL_PCI_MAX_RX_COUNT;	/*64; */
@@ -1087,113 +1211,124 @@
 {
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_tx_desc *ring;
-	dma_addr_t dma;
+	struct rtl_tx_buffer_desc *buffer_desc;
+	struct rtl_tx_desc *desc;
+	dma_addr_t buffer_desc_dma, desc_dma;
 	u32 nextdescaddress;
 	int i;
 
-	ring = pci_zalloc_consistent(rtlpci->pdev, sizeof(*ring) * entries,
-				     &dma);
-	if (!ring || (unsigned long)ring & 0xFF) {
+	/* alloc tx buffer desc for new trx flow*/
+	if (rtlpriv->use_new_trx_flow) {
+		buffer_desc =
+		   pci_zalloc_consistent(rtlpci->pdev,
+					 sizeof(*buffer_desc) * entries,
+					 &buffer_desc_dma);
+
+		if (!buffer_desc || (unsigned long)buffer_desc & 0xFF) {
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "Cannot allocate TX ring (prio = %d)\n",
+				 prio);
+			return -ENOMEM;
+		}
+
+		rtlpci->tx_ring[prio].buffer_desc = buffer_desc;
+		rtlpci->tx_ring[prio].buffer_desc_dma = buffer_desc_dma;
+
+		rtlpci->tx_ring[prio].cur_tx_rp = 0;
+		rtlpci->tx_ring[prio].cur_tx_wp = 0;
+		rtlpci->tx_ring[prio].avl_desc = entries;
+	}
+
+	/* alloc dma for this ring */
+	desc = pci_zalloc_consistent(rtlpci->pdev,
+				     sizeof(*desc) * entries, &desc_dma);
+
+	if (!desc || (unsigned long)desc & 0xFF) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 "Cannot allocate TX ring (prio = %d)\n", prio);
 		return -ENOMEM;
 	}
 
-	rtlpci->tx_ring[prio].desc = ring;
-	rtlpci->tx_ring[prio].dma = dma;
+	rtlpci->tx_ring[prio].desc = desc;
+	rtlpci->tx_ring[prio].dma = desc_dma;
+
 	rtlpci->tx_ring[prio].idx = 0;
 	rtlpci->tx_ring[prio].entries = entries;
 	skb_queue_head_init(&rtlpci->tx_ring[prio].queue);
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "queue:%d, ring_addr:%p\n",
-		 prio, ring);
+		 prio, desc);
 
-	for (i = 0; i < entries; i++) {
-		nextdescaddress = (u32) dma +
-					      ((i + 1) % entries) *
-					      sizeof(*ring);
+	/* init every desc in this ring */
+	if (!rtlpriv->use_new_trx_flow) {
+		for (i = 0; i < entries; i++) {
+			nextdescaddress = (u32)desc_dma +
+					  ((i +	1) % entries) *
+					  sizeof(*desc);
 
-		rtlpriv->cfg->ops->set_desc(hw, (u8 *)&(ring[i]),
-					    true, HW_DESC_TX_NEXTDESC_ADDR,
-					    (u8 *)&nextdescaddress);
+			rtlpriv->cfg->ops->set_desc(hw, (u8 *)&desc[i],
+						    true,
+						    HW_DESC_TX_NEXTDESC_ADDR,
+						    (u8 *)&nextdescaddress);
+		}
 	}
-
 	return 0;
 }
 
-static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
+static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
 {
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_rx_desc *entry = NULL;
-	int i, rx_queue_idx;
-	u8 tmp_one = 1;
+	int i;
 
-	/*
-	 *rx_queue_idx 0:RX_MPDU_QUEUE
-	 *rx_queue_idx 1:RX_CMD_QUEUE
-	 */
-	for (rx_queue_idx = 0; rx_queue_idx < RTL_PCI_MAX_RX_QUEUE;
-	     rx_queue_idx++) {
-		rtlpci->rx_ring[rx_queue_idx].desc =
-			pci_zalloc_consistent(rtlpci->pdev,
-					      sizeof(*rtlpci->rx_ring[rx_queue_idx].desc) * rtlpci->rxringcount,
-					      &rtlpci->rx_ring[rx_queue_idx].dma);
-
-		if (!rtlpci->rx_ring[rx_queue_idx].desc ||
-		    (unsigned long)rtlpci->rx_ring[rx_queue_idx].desc & 0xFF) {
+	if (rtlpriv->use_new_trx_flow) {
+		struct rtl_rx_buffer_desc *entry = NULL;
+		/* alloc dma for this ring */
+		rtlpci->rx_ring[rxring_idx].buffer_desc =
+		    pci_zalloc_consistent(rtlpci->pdev,
+					  sizeof(*rtlpci->rx_ring[rxring_idx].
+						 buffer_desc) *
+						 rtlpci->rxringcount,
+					  &rtlpci->rx_ring[rxring_idx].dma);
+		if (!rtlpci->rx_ring[rxring_idx].buffer_desc ||
+		    (ulong)rtlpci->rx_ring[rxring_idx].buffer_desc & 0xFF) {
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 				 "Cannot allocate RX ring\n");
 			return -ENOMEM;
 		}
 
-		rtlpci->rx_ring[rx_queue_idx].idx = 0;
+		/* init every desc in this ring */
+		rtlpci->rx_ring[rxring_idx].idx = 0;
+		for (i = 0; i < rtlpci->rxringcount; i++) {
+			entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[i];
+			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
+						      rxring_idx, i))
+				return -ENOMEM;
+		}
+	} else {
+		struct rtl_rx_desc *entry = NULL;
+		u8 tmp_one = 1;
+		/* alloc dma for this ring */
+		rtlpci->rx_ring[rxring_idx].desc =
+		    pci_zalloc_consistent(rtlpci->pdev,
+					  sizeof(*rtlpci->rx_ring[rxring_idx].
+					  desc) * rtlpci->rxringcount,
+					  &rtlpci->rx_ring[rxring_idx].dma);
+		if (!rtlpci->rx_ring[rxring_idx].desc ||
+		    (unsigned long)rtlpci->rx_ring[rxring_idx].desc & 0xFF) {
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "Cannot allocate RX ring\n");
+			return -ENOMEM;
+		}
 
-		/* If amsdu_8k is disabled, set buffersize to 4096. This
-		 * change will reduce memory fragmentation.
-		 */
-		if (rtlpci->rxbuffersize > 4096 &&
-		    rtlpriv->rtlhal.disable_amsdu_8k)
-			rtlpci->rxbuffersize = 4096;
+		/* init every desc in this ring */
+		rtlpci->rx_ring[rxring_idx].idx = 0;
 
 		for (i = 0; i < rtlpci->rxringcount; i++) {
-			struct sk_buff *skb =
-			    dev_alloc_skb(rtlpci->rxbuffersize);
-			u32 bufferaddress;
-			if (!skb)
-				return 0;
-			kmemleak_not_leak(skb);
-			entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
-
-			/*skb->dev = dev; */
-
-			rtlpci->rx_ring[rx_queue_idx].rx_buf[i] = skb;
-
-			/*
-			 *just set skb->cb to mapping addr
-			 *for pci_unmap_single use
-			 */
-			*((dma_addr_t *) skb->cb) =
-			    pci_map_single(rtlpci->pdev, skb_tail_pointer(skb),
-					   rtlpci->rxbuffersize,
-					   PCI_DMA_FROMDEVICE);
-
-			bufferaddress = (*((dma_addr_t *)skb->cb));
-			if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress)) {
-				dev_kfree_skb_any(skb);
-				return 1;
-			}
-			rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
-						    HW_DESC_RXBUFF_ADDR,
-						    (u8 *)&bufferaddress);
-			rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
-						    HW_DESC_RXPKT_LEN,
-						    (u8 *)&rtlpci->
-						    rxbuffersize);
-			rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
-						    HW_DESC_RXOWN,
-						    &tmp_one);
+			entry = &rtlpci->rx_ring[rxring_idx].desc[i];
+			if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
+						      rxring_idx, i))
+				return -ENOMEM;
 		}
 
 		rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
@@ -1209,56 +1344,70 @@
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio];
 
+	/* free every desc in this ring */
 	while (skb_queue_len(&ring->queue)) {
-		struct rtl_tx_desc *entry = &ring->desc[ring->idx];
+		u8 *entry;
 		struct sk_buff *skb = __skb_dequeue(&ring->queue);
 
+		if (rtlpriv->use_new_trx_flow)
+			entry = (u8 *)(&ring->buffer_desc[ring->idx]);
+		else
+			entry = (u8 *)(&ring->desc[ring->idx]);
+
 		pci_unmap_single(rtlpci->pdev,
 				 rtlpriv->cfg->
-					     ops->get_desc((u8 *) entry, true,
+					     ops->get_desc((u8 *)entry, true,
 						   HW_DESC_TXBUFF_ADDR),
 				 skb->len, PCI_DMA_TODEVICE);
 		kfree_skb(skb);
 		ring->idx = (ring->idx + 1) % ring->entries;
 	}
 
-	if (ring->desc) {
+	/* free dma of this ring */
+	pci_free_consistent(rtlpci->pdev,
+			    sizeof(*ring->desc) * ring->entries,
+			    ring->desc, ring->dma);
+	ring->desc = NULL;
+	if (rtlpriv->use_new_trx_flow) {
 		pci_free_consistent(rtlpci->pdev,
 				    sizeof(*ring->desc) * ring->entries,
-				    ring->desc, ring->dma);
+				    ring->buffer_desc, ring->buffer_desc_dma);
 		ring->desc = NULL;
 	}
 }
 
-static void _rtl_pci_free_rx_ring(struct rtl_pci *rtlpci)
+static void _rtl_pci_free_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
 {
-	int i, rx_queue_idx;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	int i;
 
-	/*rx_queue_idx 0:RX_MPDU_QUEUE */
-	/*rx_queue_idx 1:RX_CMD_QUEUE */
-	for (rx_queue_idx = 0; rx_queue_idx < RTL_PCI_MAX_RX_QUEUE;
-	     rx_queue_idx++) {
-		for (i = 0; i < rtlpci->rxringcount; i++) {
-			struct sk_buff *skb =
-			    rtlpci->rx_ring[rx_queue_idx].rx_buf[i];
-			if (!skb)
-				continue;
+	/* free every desc in this ring */
+	for (i = 0; i < rtlpci->rxringcount; i++) {
+		struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[i];
 
-			pci_unmap_single(rtlpci->pdev,
-					 *((dma_addr_t *) skb->cb),
-					 rtlpci->rxbuffersize,
-					 PCI_DMA_FROMDEVICE);
-			kfree_skb(skb);
-		}
+		if (!skb)
+			continue;
+		pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb),
+				 rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE);
+		kfree_skb(skb);
+	}
 
-		if (rtlpci->rx_ring[rx_queue_idx].desc) {
-			pci_free_consistent(rtlpci->pdev,
-				    sizeof(*rtlpci->rx_ring[rx_queue_idx].
-					   desc) * rtlpci->rxringcount,
-				    rtlpci->rx_ring[rx_queue_idx].desc,
-				    rtlpci->rx_ring[rx_queue_idx].dma);
-			rtlpci->rx_ring[rx_queue_idx].desc = NULL;
-		}
+	/* free dma of this ring */
+	if (rtlpriv->use_new_trx_flow) {
+		pci_free_consistent(rtlpci->pdev,
+				    sizeof(*rtlpci->rx_ring[rxring_idx].
+				    buffer_desc) * rtlpci->rxringcount,
+				    rtlpci->rx_ring[rxring_idx].buffer_desc,
+				    rtlpci->rx_ring[rxring_idx].dma);
+		rtlpci->rx_ring[rxring_idx].buffer_desc = NULL;
+	} else {
+		pci_free_consistent(rtlpci->pdev,
+				    sizeof(*rtlpci->rx_ring[rxring_idx].desc) *
+				    rtlpci->rxringcount,
+				    rtlpci->rx_ring[rxring_idx].desc,
+				    rtlpci->rx_ring[rxring_idx].dma);
+		rtlpci->rx_ring[rxring_idx].desc = NULL;
 	}
 }
 
@@ -1266,11 +1415,16 @@
 {
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	int ret;
-	int i;
+	int i, rxring_idx;
 
-	ret = _rtl_pci_init_rx_ring(hw);
-	if (ret)
-		return ret;
+	/* rxring_idx 0:RX_MPDU_QUEUE
+	 * rxring_idx 1:RX_CMD_QUEUE
+	 */
+	for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) {
+		ret = _rtl_pci_init_rx_ring(hw, rxring_idx);
+		if (ret)
+			return ret;
+	}
 
 	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) {
 		ret = _rtl_pci_init_tx_ring(hw, i,
@@ -1282,10 +1436,12 @@
 	return 0;
 
 err_free_rings:
-	_rtl_pci_free_rx_ring(rtlpci);
+	for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++)
+		_rtl_pci_free_rx_ring(hw, rxring_idx);
 
 	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++)
-		if (rtlpci->tx_ring[i].desc)
+		if (rtlpci->tx_ring[i].desc ||
+		    rtlpci->tx_ring[i].buffer_desc)
 			_rtl_pci_free_tx_ring(hw, i);
 
 	return 1;
@@ -1293,11 +1449,11 @@
 
 static int _rtl_pci_deinit_trx_ring(struct ieee80211_hw *hw)
 {
-	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-	u32 i;
+	u32 i, rxring_idx;
 
 	/*free rx rings */
-	_rtl_pci_free_rx_ring(rtlpci);
+	for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++)
+		_rtl_pci_free_rx_ring(hw, rxring_idx);
 
 	/*free tx rings */
 	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++)
@@ -1310,48 +1466,76 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-	int i, rx_queue_idx;
+	int i, rxring_idx;
 	unsigned long flags;
 	u8 tmp_one = 1;
-
-	/*rx_queue_idx 0:RX_MPDU_QUEUE */
-	/*rx_queue_idx 1:RX_CMD_QUEUE */
-	for (rx_queue_idx = 0; rx_queue_idx < RTL_PCI_MAX_RX_QUEUE;
-	     rx_queue_idx++) {
-		/*
-		 *force the rx_ring[RX_MPDU_QUEUE/
-		 *RX_CMD_QUEUE].idx to the first one
-		 */
-		if (rtlpci->rx_ring[rx_queue_idx].desc) {
+	u32 bufferaddress;
+	/* rxring_idx 0:RX_MPDU_QUEUE */
+	/* rxring_idx 1:RX_CMD_QUEUE */
+	for (rxring_idx = 0; rxring_idx < RTL_PCI_MAX_RX_QUEUE; rxring_idx++) {
+		/* force the rx_ring[RX_MPDU_QUEUE/
+		 * RX_CMD_QUEUE].idx to the first one
+		 *new trx flow, do nothing
+		*/
+		if (!rtlpriv->use_new_trx_flow &&
+		    rtlpci->rx_ring[rxring_idx].desc) {
 			struct rtl_rx_desc *entry = NULL;
 
+			rtlpci->rx_ring[rxring_idx].idx = 0;
 			for (i = 0; i < rtlpci->rxringcount; i++) {
-				entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
-				rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry,
-							    false,
-							    HW_DESC_RXOWN,
-							    &tmp_one);
+				entry = &rtlpci->rx_ring[rxring_idx].desc[i];
+				bufferaddress =
+				  rtlpriv->cfg->ops->get_desc((u8 *)entry,
+				  false , HW_DESC_RXBUFF_ADDR);
+				memset((u8 *)entry , 0 ,
+				       sizeof(*rtlpci->rx_ring
+				       [rxring_idx].desc));/*clear one entry*/
+				if (rtlpriv->use_new_trx_flow) {
+					rtlpriv->cfg->ops->set_desc(hw,
+					    (u8 *)entry, false,
+					    HW_DESC_RX_PREPARE,
+					    (u8 *)&bufferaddress);
+				} else {
+					rtlpriv->cfg->ops->set_desc(hw,
+					    (u8 *)entry, false,
+					    HW_DESC_RXBUFF_ADDR,
+					    (u8 *)&bufferaddress);
+					rtlpriv->cfg->ops->set_desc(hw,
+					    (u8 *)entry, false,
+					    HW_DESC_RXPKT_LEN,
+					    (u8 *)&rtlpci->rxbuffersize);
+					rtlpriv->cfg->ops->set_desc(hw,
+					    (u8 *)entry, false,
+					    HW_DESC_RXOWN,
+					    (u8 *)&tmp_one);
+				}
 			}
-			rtlpci->rx_ring[rx_queue_idx].idx = 0;
+			rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
+					    HW_DESC_RXERO, (u8 *)&tmp_one);
 		}
+		rtlpci->rx_ring[rxring_idx].idx = 0;
 	}
 
 	/*
 	 *after reset, release previous pending packet,
 	 *and force the  tx idx to the first one
 	 */
+	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) {
-		if (rtlpci->tx_ring[i].desc) {
+		if (rtlpci->tx_ring[i].desc ||
+		    rtlpci->tx_ring[i].buffer_desc) {
 			struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i];
 
 			while (skb_queue_len(&ring->queue)) {
-				struct rtl_tx_desc *entry;
-				struct sk_buff *skb;
+				u8 *entry;
+				struct sk_buff *skb =
+					__skb_dequeue(&ring->queue);
+				if (rtlpriv->use_new_trx_flow)
+					entry = (u8 *)(&ring->buffer_desc
+								[ring->idx]);
+				else
+					entry = (u8 *)(&ring->desc[ring->idx]);
 
-				spin_lock_irqsave(&rtlpriv->locks.irq_th_lock,
-						  flags);
-				entry = &ring->desc[ring->idx];
-				skb = __skb_dequeue(&ring->queue);
 				pci_unmap_single(rtlpci->pdev,
 						 rtlpriv->cfg->ops->
 							 get_desc((u8 *)
@@ -1360,13 +1544,13 @@
 							 HW_DESC_TXBUFF_ADDR),
 						 skb->len, PCI_DMA_TODEVICE);
 				ring->idx = (ring->idx + 1) % ring->entries;
-				spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
-						  flags);
 				kfree_skb(skb);
+				ring->idx = (ring->idx + 1) % ring->entries;
 			}
 			ring->idx = 0;
 		}
 	}
+	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
 
 	return 0;
 }
@@ -1421,7 +1605,7 @@
 	struct rtl8192_tx_ring *ring;
 	struct rtl_tx_desc *pdesc;
 	struct rtl_tx_buffer_desc *ptx_bd_desc = NULL;
-	u8 idx;
+	u16 idx;
 	u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb);
 	unsigned long flags;
 	struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
@@ -1454,11 +1638,15 @@
 
 	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 	ring = &rtlpci->tx_ring[hw_queue];
-	if (hw_queue != BEACON_QUEUE)
-		idx = (ring->idx + skb_queue_len(&ring->queue)) %
-				ring->entries;
-	else
+	if (hw_queue != BEACON_QUEUE) {
+		if (rtlpriv->use_new_trx_flow)
+			idx = ring->cur_tx_wp;
+		else
+			idx = (ring->idx + skb_queue_len(&ring->queue)) %
+			      ring->entries;
+	} else {
 		idx = 0;
+	}
 
 	pdesc = &ring->desc[idx];
 	if (rtlpriv->use_new_trx_flow) {
@@ -1469,7 +1657,7 @@
 
 		if ((own == 1) && (hw_queue != BEACON_QUEUE)) {
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-				 "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
+				 "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%x\n",
 				 hw_queue, ring->idx, idx,
 				 skb_queue_len(&ring->queue));
 
@@ -1511,7 +1699,7 @@
 	if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
 	    hw_queue != BEACON_QUEUE) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
-			 "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
+			 "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%x\n",
 			 hw_queue, ring->idx, idx,
 			 skb_queue_len(&ring->queue));
 
@@ -1525,7 +1713,7 @@
 	return 0;
 }
 
-static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop)
+static void rtl_pci_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
@@ -1540,6 +1728,11 @@
 
 	for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) {
 		u32 queue_len;
+
+		if (((queues >> queue_id) & 0x1) == 0) {
+			queue_id--;
+			continue;
+		}
 		ring = &pcipriv->dev.tx_ring[queue_id];
 		queue_len = skb_queue_len(&ring->queue);
 		if (queue_len == 0 || queue_id == BEACON_QUEUE ||
@@ -1603,6 +1796,10 @@
 	rtl_pci_reset_trx_ring(hw);
 
 	rtlpci->driver_is_goingto_unload = false;
+	if (rtlpriv->cfg->ops->get_btc_status()) {
+		rtlpriv->btcoexist.btc_ops->btc_init_variables(rtlpriv);
+		rtlpriv->btcoexist.btc_ops->btc_init_hal_vars(rtlpriv);
+	}
 	err = rtlpriv->cfg->ops->hw_init(hw);
 	if (err) {
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
@@ -1622,7 +1819,7 @@
 
 	rtlpci->up_first_time = false;
 
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "OK\n");
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "rtl_pci_start OK\n");
 	return 0;
 }
 
@@ -1635,6 +1832,9 @@
 	unsigned long flags;
 	u8 RFInProgressTimeOut = 0;
 
+	if (rtlpriv->cfg->ops->get_btc_status())
+		rtlpriv->btcoexist.btc_ops->btc_halt_notify();
+
 	/*
 	 *should be before disable interrupt&adapter
 	 *and will do it immediately.
@@ -1753,6 +1953,22 @@
 		rtlhal->hw_type = HARDWARE_TYPE_RTL8188EE;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 			 "Find adapter, Hardware type is 8188EE\n");
+	} else if (deviceid == RTL_PCI_8723BE_DID) {
+			rtlhal->hw_type = HARDWARE_TYPE_RTL8723BE;
+			RT_TRACE(rtlpriv, COMP_INIT , DBG_LOUD,
+				 "Find adapter, Hardware type is 8723BE\n");
+	} else if (deviceid == RTL_PCI_8192EE_DID) {
+			rtlhal->hw_type = HARDWARE_TYPE_RTL8192EE;
+			RT_TRACE(rtlpriv, COMP_INIT , DBG_LOUD,
+				 "Find adapter, Hardware type is 8192EE\n");
+	} else if (deviceid == RTL_PCI_8821AE_DID) {
+			rtlhal->hw_type = HARDWARE_TYPE_RTL8821AE;
+			RT_TRACE(rtlpriv, COMP_INIT , DBG_LOUD,
+				 "Find adapter, Hardware type is 8821AE\n");
+	} else if (deviceid == RTL_PCI_8812AE_DID) {
+			rtlhal->hw_type = HARDWARE_TYPE_RTL8812AE;
+			RT_TRACE(rtlpriv, COMP_INIT , DBG_LOUD,
+				 "Find adapter, Hardware type is 8812AE\n");
 	} else {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 			 "Err: Unknown device - vid/did=%x/%x\n",
@@ -1779,11 +1995,20 @@
 			rtlhal->interfaceindex = 0;
 		}
 	}
+
+	/* 92ee use new trx flow */
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192EE)
+		rtlpriv->use_new_trx_flow = true;
+	else
+		rtlpriv->use_new_trx_flow = false;
+
 	/*find bus info */
 	pcipriv->ndis_adapter.busnumber = pdev->bus->number;
 	pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn);
 	pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn);
 
+	/*find bridge info */
+	pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN;
 	/* some ARM have no bridge_pdev and will crash here
 	 * so we should check if bridge_pdev is NULL
 	 */
@@ -1951,6 +2176,11 @@
 	pcipriv = (void *)rtlpriv->priv;
 	pcipriv->dev.pdev = pdev;
 	init_completion(&rtlpriv->firmware_loading_complete);
+	/*proximity init here*/
+	rtlpriv->proximity.proxim_on = false;
+
+	pcipriv = (void *)rtlpriv->priv;
+	pcipriv->dev.pdev = pdev;
 
 	/* init cfg & intf_ops */
 	rtlpriv->rtlhal.interface = INTF_PCI;
@@ -2013,9 +2243,6 @@
 	/*like read eeprom and so on */
 	rtlpriv->cfg->ops->read_eeprom_info(hw);
 
-	/*aspm */
-	rtl_pci_init_aspm(hw);
-
 	/* Init mac80211 sw */
 	err = rtl_init_core(hw);
 	if (err) {
@@ -2036,9 +2263,20 @@
 		err = -ENODEV;
 		goto fail3;
 	}
-
 	rtlpriv->cfg->ops->init_sw_leds(hw);
 
+	/*aspm */
+	rtl_pci_init_aspm(hw);
+
+	err = ieee80211_register_hw(hw);
+	if (err) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Can't register mac80211 hw.\n");
+		err = -ENODEV;
+		goto fail3;
+	}
+	rtlpriv->mac80211.mac80211_registered = 1;
+
 	err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group);
 	if (err) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -2046,6 +2284,9 @@
 		goto fail3;
 	}
 
+	/*init rfkill */
+	rtl_init_rfkill(hw);	/* Init PCI sw */
+
 	rtlpci = rtl_pcidev(pcipriv);
 	err = rtl_pci_intr_mode_decide(hw);
 	if (err) {
@@ -2056,9 +2297,11 @@
 	}
 	rtlpci->irq_alloc = 1;
 
+	set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
 	return 0;
 
 fail3:
+	pci_set_drvdata(pdev, NULL);
 	rtl_deinit_core(hw);
 
 	if (rtlpriv->io.pci_mem_start != 0)
@@ -2128,6 +2371,8 @@
 
 	rtl_pci_disable_aspm(hw);
 
+	pci_set_drvdata(pdev, NULL);
+
 	ieee80211_free_hw(hw);
 }
 EXPORT_SYMBOL(rtl_pci_disconnect);
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h
index 90174a8..5e83230 100644
--- a/drivers/net/wireless/rtlwifi/pci.h
+++ b/drivers/net/wireless/rtlwifi/pci.h
@@ -39,10 +39,11 @@
 #define RTL_PCI_RX_CMD_QUEUE			1
 #define RTL_PCI_MAX_RX_QUEUE			2
 
-#define RTL_PCI_MAX_RX_COUNT			64
+#define RTL_PCI_MAX_RX_COUNT			512/*64*/
 #define RTL_PCI_MAX_TX_QUEUE_COUNT		9
 
 #define RT_TXDESC_NUM				128
+#define TX_DESC_NUM_92E				512
 #define RT_TXDESC_NUM_BE_QUEUE			256
 
 #define BK_QUEUE				0
@@ -62,6 +63,12 @@
 	.subdevice = PCI_ANY_ID,\
 	.driver_data = (kernel_ulong_t)&(cfg)
 
+#define INTEL_VENDOR_ID				0x8086
+#define SIS_VENDOR_ID				0x1039
+#define ATI_VENDOR_ID				0x1002
+#define ATI_DEVICE_ID				0x7914
+#define AMD_VENDOR_ID				0x1022
+
 #define PCI_MAX_BRIDGE_NUMBER			255
 #define PCI_MAX_DEVICES				32
 #define PCI_MAX_FUNCTION			8
@@ -69,6 +76,11 @@
 #define PCI_CONF_ADDRESS	0x0CF8	/*PCI Configuration Space Address */
 #define PCI_CONF_DATA		0x0CFC	/*PCI Configuration Space Data */
 
+#define PCI_CLASS_BRIDGE_DEV		0x06
+#define PCI_SUBCLASS_BR_PCI_TO_PCI	0x04
+#define PCI_CAPABILITY_ID_PCI_EXPRESS	0x10
+#define PCI_CAP_ID_EXP			0x10
+
 #define U1DONTCARE			0xFF
 #define U2DONTCARE			0xFFFF
 #define U4DONTCARE			0xFFFFFFFF
@@ -87,6 +99,7 @@
 #define RTL_PCI_700F_DID	0x700F
 #define RTL_PCI_701F_DID	0x701F
 #define RTL_PCI_DLINK_DID	0x3304
+#define RTL_PCI_8723AE_DID	0x8723	/*8723e */
 #define RTL_PCI_8192CET_DID	0x8191	/*8192ce */
 #define RTL_PCI_8192CE_DID	0x8178	/*8192ce */
 #define RTL_PCI_8191CE_DID	0x8177	/*8192ce */
@@ -95,6 +108,10 @@
 #define RTL_PCI_8192DE_DID	0x8193	/*8192de */
 #define RTL_PCI_8192DE_DID2	0x002B	/*92DE*/
 #define RTL_PCI_8188EE_DID	0x8179  /*8188ee*/
+#define RTL_PCI_8723BE_DID	0xB723  /*8723be*/
+#define RTL_PCI_8192EE_DID	0x818B	/*8192ee*/
+#define RTL_PCI_8821AE_DID	0x8821	/*8821ae*/
+#define RTL_PCI_8812AE_DID	0x8812	/*8812ae*/
 
 /*8192 support 16 pages of IO registers*/
 #define RTL_MEM_MAPPED_IO_RANGE_8190PCI		0x1000
@@ -125,24 +142,34 @@
 	u8 next;
 };
 
-struct rtl_rx_desc {
-	u32 dword[8];
+/* In new TRX flow, Buffer_desc is new concept
+ * But TX wifi info == TX descriptor in old flow
+ * RX wifi info == RX descriptor in old flow
+ */
+struct rtl_tx_buffer_desc {
+#if (RTL8192EE_SEG_NUM == 2)
+	u32 dword[2*(DMA_IS_64BIT + 1)*8]; /*seg = 8*/
+#elif (RTL8192EE_SEG_NUM == 1)
+	u32 dword[2*(DMA_IS_64BIT + 1)*4]; /*seg = 4*/
+#elif (RTL8192EE_SEG_NUM == 0)
+	u32 dword[2*(DMA_IS_64BIT + 1)*2]; /*seg = 2*/
+#endif
 } __packed;
 
 struct rtl_tx_desc {
 	u32 dword[16];
 } __packed;
 
-struct rtl_tx_cmd_desc {
-	u32 dword[16];
+struct rtl_rx_buffer_desc { /*rx buffer desc*/
+	u32 dword[2];
 } __packed;
 
-/* In new TRX flow, Buffer_desc is new concept
- * But TX wifi info == TX descriptor in old flow
- * RX wifi info == RX descriptor in old flow
- */
-struct rtl_tx_buffer_desc {
-	u32 dword[8]; /*seg = 4*/
+struct rtl_rx_desc { /*old: rx desc new: rx wifi info*/
+	u32 dword[8];
+} __packed;
+
+struct rtl_tx_cmd_desc {
+	u32 dword[16];
 } __packed;
 
 struct rtl8192_tx_ring {
@@ -153,6 +180,10 @@
 	struct sk_buff_head queue;
 	/*add for new trx flow*/
 	struct rtl_tx_buffer_desc *buffer_desc; /*tx buffer descriptor*/
+	dma_addr_t buffer_desc_dma; /*tx bufferd desc dma memory*/
+	u16 avl_desc; /* available_desc_to_write */
+	u16 cur_tx_wp; /* current_tx_write_point */
+	u16 cur_tx_rp; /* current_tx_read_point */
 };
 
 struct rtl8192_rx_ring {
@@ -160,6 +191,9 @@
 	dma_addr_t dma;
 	unsigned int idx;
 	struct sk_buff *rx_buf[RTL_PCI_MAX_RX_COUNT];
+	/*add for new trx flow*/
+	struct rtl_rx_buffer_desc *buffer_desc; /*rx buffer descriptor*/
+	u16 next_rx_rp; /* next_rx_read_point */
 };
 
 struct rtl_pci {
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index 5050494..b69321d 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -27,110 +23,11 @@
  *
  *****************************************************************************/
 
-#include <linux/export.h>
 #include "wifi.h"
 #include "base.h"
 #include "ps.h"
-
-/*	Description:
- *		This routine deals with the Power Configuration CMD
- *		 parsing for RTL8723/RTL8188E Series IC.
- *	Assumption:
- *		We should follow specific format that was released from HW SD.
- */
-bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
-			      u8 faversion, u8 interface_type,
-			      struct wlan_pwr_cfg pwrcfgcmd[])
-{
-	struct wlan_pwr_cfg cfg_cmd = {0};
-	bool polling_bit = false;
-	u32 ary_idx = 0;
-	u8 value = 0;
-	u32 offset = 0;
-	u32 polling_count = 0;
-	u32 max_polling_cnt = 5000;
-
-	do {
-		cfg_cmd = pwrcfgcmd[ary_idx];
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			"rtl_hal_pwrseqcmdparsing(): offset(%#x),cut_msk(%#x), famsk(%#x),"
-			"interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), value(%#x)\n",
-			GET_PWR_CFG_OFFSET(cfg_cmd),
-					   GET_PWR_CFG_CUT_MASK(cfg_cmd),
-			GET_PWR_CFG_FAB_MASK(cfg_cmd),
-					     GET_PWR_CFG_INTF_MASK(cfg_cmd),
-			GET_PWR_CFG_BASE(cfg_cmd), GET_PWR_CFG_CMD(cfg_cmd),
-			GET_PWR_CFG_MASK(cfg_cmd), GET_PWR_CFG_VALUE(cfg_cmd));
-
-		if ((GET_PWR_CFG_FAB_MASK(cfg_cmd)&faversion) &&
-		    (GET_PWR_CFG_CUT_MASK(cfg_cmd)&cut_version) &&
-		    (GET_PWR_CFG_INTF_MASK(cfg_cmd)&interface_type)) {
-			switch (GET_PWR_CFG_CMD(cfg_cmd)) {
-			case PWR_CMD_READ:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_READ\n");
-				break;
-			case PWR_CMD_WRITE:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n");
-				offset = GET_PWR_CFG_OFFSET(cfg_cmd);
-
-				/*Read the value from system register*/
-				value = rtl_read_byte(rtlpriv, offset);
-				value &= (~(GET_PWR_CFG_MASK(cfg_cmd)));
-				value |= (GET_PWR_CFG_VALUE(cfg_cmd) &
-					  GET_PWR_CFG_MASK(cfg_cmd));
-
-				/*Write the value back to sytem register*/
-				rtl_write_byte(rtlpriv, offset, value);
-				break;
-			case PWR_CMD_POLLING:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n");
-				polling_bit = false;
-				offset = GET_PWR_CFG_OFFSET(cfg_cmd);
-
-				do {
-					value = rtl_read_byte(rtlpriv, offset);
-
-					value &= GET_PWR_CFG_MASK(cfg_cmd);
-					if (value ==
-					    (GET_PWR_CFG_VALUE(cfg_cmd)
-					    & GET_PWR_CFG_MASK(cfg_cmd)))
-						polling_bit = true;
-					else
-						udelay(10);
-
-					if (polling_count++ > max_polling_cnt)
-						return false;
-				} while (!polling_bit);
-				break;
-			case PWR_CMD_DELAY:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n");
-				if (GET_PWR_CFG_VALUE(cfg_cmd) ==
-				    PWRSEQ_DELAY_US)
-					udelay(GET_PWR_CFG_OFFSET(cfg_cmd));
-				else
-					mdelay(GET_PWR_CFG_OFFSET(cfg_cmd));
-				break;
-			case PWR_CMD_END:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					 "rtl_hal_pwrseqcmdparsing(): PWR_CMD_END\n");
-				return true;
-			default:
-				RT_ASSERT(false,
-					 "rtl_hal_pwrseqcmdparsing(): Unknown CMD!!\n");
-				break;
-			}
-
-		}
-		ary_idx++;
-	} while (1);
-
-	return true;
-}
-EXPORT_SYMBOL(rtl_hal_pwrseqcmdparsing);
+#include <linux/export.h>
+#include "btcoexist/rtl_btc.h"
 
 bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
 {
@@ -181,11 +78,49 @@
 
 bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
 			 enum rf_pwrstate state_toset,
-			 u32 changesource)
+			 u32 changesource, bool protect_or_not)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	enum rf_pwrstate rtstate;
 	bool actionallowed = false;
+	u16 rfwait_cnt = 0;
+
+	if (protect_or_not)
+		goto no_protect;
+
+	/*Only one thread can change
+	 *the RF state at one time, and others
+	 *should wait to be executed.
+	 */
+	while (true) {
+		spin_lock(&rtlpriv->locks.rf_ps_lock);
+		if (ppsc->rfchange_inprogress) {
+			spin_unlock(&rtlpriv->locks.rf_ps_lock);
+
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+				 "RF Change in progress! Wait to set..state_toset(%d).\n",
+				  state_toset);
+
+			/* Set RF after the previous action is done.  */
+			while (ppsc->rfchange_inprogress) {
+				rfwait_cnt++;
+				mdelay(1);
+				/*Wait too long, return false to avoid
+				 *to be stuck here.
+				 */
+				if (rfwait_cnt > 100)
+					return false;
+			}
+		} else {
+			ppsc->rfchange_inprogress = true;
+			spin_unlock(&rtlpriv->locks.rf_ps_lock);
+			break;
+		}
+	}
+
+no_protect:
+	rtstate = ppsc->rfpwr_state;
 
 	switch (state_toset) {
 	case ERFON:
@@ -227,6 +162,12 @@
 	if (actionallowed)
 		rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
 
+	if (!protect_or_not) {
+		spin_lock(&rtlpriv->locks.rf_ps_lock);
+		ppsc->rfchange_inprogress = false;
+		spin_unlock(&rtlpriv->locks.rf_ps_lock);
+	}
+
 	return actionallowed;
 }
 EXPORT_SYMBOL(rtl_ps_set_rf_state);
@@ -249,12 +190,13 @@
 		}
 	}
 
-	rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate, RF_CHANGE_BY_IPS);
+	rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate,
+			    RF_CHANGE_BY_IPS, false);
 
 	if (ppsc->inactive_pwrstate == ERFOFF &&
 	    rtlhal->interface == INTF_PCI) {
 		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
-			!RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
+		    !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
 			rtlpriv->intf_ops->enable_aspm(hw);
 			RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
 		}
@@ -318,6 +260,11 @@
 			ppsc->inactive_pwrstate = ERFOFF;
 			ppsc->in_powersavemode = true;
 
+			/* call before RF off */
+			if (rtlpriv->cfg->ops->get_btc_status())
+				rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv,
+									ppsc->inactive_pwrstate);
+
 			/*rtl_pci_reset_trx_ring(hw); */
 			_rtl_ps_inactive_ps(hw);
 		}
@@ -328,10 +275,9 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-	/*
-	 *because when link with ap, mac80211 will ask us
-	 *to disable nic quickly after scan before linking,
-	 *this will cause link failed, so we delay 100ms here
+	/* because when link with ap, mac80211 will ask us
+	 * to disable nic quickly after scan before linking,
+	 * this will cause link failed, so we delay 100ms here
 	 */
 	queue_delayed_work(rtlpriv->works.rtl_wq,
 			   &rtlpriv->works.ips_nic_off_wq, MSECS(100));
@@ -343,16 +289,12 @@
 void rtl_ips_nic_on(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	enum rf_pwrstate rtstate;
-	unsigned long flags;
 
-	if (mac->opmode != NL80211_IFTYPE_STATION)
-		return;
+	cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
 
-	spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags);
-
+	spin_lock(&rtlpriv->locks.ips_lock);
 	if (ppsc->inactiveps) {
 		rtstate = ppsc->rfpwr_state;
 
@@ -362,12 +304,14 @@
 
 			ppsc->inactive_pwrstate = ERFON;
 			ppsc->in_powersavemode = false;
-
 			_rtl_ps_inactive_ps(hw);
+			/* call after RF on */
+			if (rtlpriv->cfg->ops->get_btc_status())
+				rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv,
+									ppsc->inactive_pwrstate);
 		}
 	}
-
-	spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags);
+	spin_unlock(&rtlpriv->locks.ips_lock);
 }
 EXPORT_SYMBOL_GPL(rtl_ips_nic_on);
 
@@ -404,7 +348,7 @@
 }
 
 /* Change current and default preamble mode.*/
-static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
+void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -437,21 +381,24 @@
 		if (ppsc->dot11_psmode == EACTIVE) {
 			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 				 "FW LPS leave ps_mode:%x\n",
-				 FW_PS_ACTIVE_MODE);
+				  FW_PS_ACTIVE_MODE);
 			enter_fwlps = false;
 			ppsc->pwr_mode = FW_PS_ACTIVE_MODE;
 			ppsc->smart_ps = 0;
-			rtlpriv->cfg->ops->set_hw_reg(hw,
-						HW_VAR_FW_LPS_ACTION,
-						(u8 *)(&enter_fwlps));
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_LPS_ACTION,
+						      (u8 *)(&enter_fwlps));
 			if (ppsc->p2p_ps_info.opp_ps)
-				rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
+				rtl_p2p_ps_cmd(hw , P2P_PS_ENABLE);
 
+			if (rtlpriv->cfg->ops->get_btc_status())
+				rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode);
 		} else {
 			if (rtl_get_fwlps_doze(hw)) {
 				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 					 "FW LPS enter ps_mode:%x\n",
 					 ppsc->fwctrl_psmode);
+				if (rtlpriv->cfg->ops->get_btc_status())
+					rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode);
 				enter_fwlps = true;
 				ppsc->pwr_mode = ppsc->fwctrl_psmode;
 				ppsc->smart_ps = 2;
@@ -473,6 +420,7 @@
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	unsigned long flag;
 
 	if (!ppsc->fwctrl_lps)
 		return;
@@ -493,7 +441,7 @@
 	if (mac->link_state != MAC80211_LINKED)
 		return;
 
-	mutex_lock(&rtlpriv->locks.ps_mutex);
+	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
 
 	/* Idle for a while if we connect to AP a while ago. */
 	if (mac->cnt_after_linked >= 2) {
@@ -505,8 +453,9 @@
 		}
 	}
 
-	mutex_unlock(&rtlpriv->locks.ps_mutex);
+	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
 }
+EXPORT_SYMBOL(rtl_lps_enter);
 
 /*Leave the leisure power save mode.*/
 void rtl_lps_leave(struct ieee80211_hw *hw)
@@ -514,14 +463,15 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	unsigned long flag;
 
-	mutex_lock(&rtlpriv->locks.ps_mutex);
+	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
 
 	if (ppsc->fwctrl_lps) {
 		if (ppsc->dot11_psmode != EACTIVE) {
 
 			/*FIX ME */
-			rtlpriv->cfg->ops->enable_interrupt(hw);
+			/*rtlpriv->cfg->ops->enable_interrupt(hw); */
 
 			if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
 			    RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
@@ -536,8 +486,9 @@
 			rtl_lps_set_psmode(hw, EACTIVE);
 		}
 	}
-	mutex_unlock(&rtlpriv->locks.ps_mutex);
+	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
 }
+EXPORT_SYMBOL(rtl_lps_leave);
 
 /* For sw LPS*/
 void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
@@ -613,7 +564,7 @@
 		/* back to low-power land. and delay is
 		 * prevent null power save frame tx fail */
 		queue_delayed_work(rtlpriv->works.rtl_wq,
-				&rtlpriv->works.ps_work, MSECS(5));
+				   &rtlpriv->works.ps_work, MSECS(5));
 	} else {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
 			 "u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed);
@@ -626,6 +577,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	unsigned long flag;
 
 	if (!rtlpriv->psc.swctrl_lps)
 		return;
@@ -633,14 +585,14 @@
 		return;
 
 	if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
-		RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
+	    RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
 		rtlpriv->intf_ops->disable_aspm(hw);
 		RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
 	}
 
-	mutex_lock(&rtlpriv->locks.ps_mutex);
-	rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS);
-	mutex_unlock(&rtlpriv->locks.ps_mutex);
+	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+	rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false);
+	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
 }
 
 void rtl_swlps_rfon_wq_callback(void *data)
@@ -657,6 +609,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	unsigned long flag;
 	u8 sleep_intv;
 
 	if (!rtlpriv->psc.sw_ps_enabled)
@@ -673,12 +626,19 @@
 	if (rtlpriv->link_info.busytraffic)
 		return;
 
-	mutex_lock(&rtlpriv->locks.ps_mutex);
-	rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS);
-	mutex_unlock(&rtlpriv->locks.ps_mutex);
+	spin_lock(&rtlpriv->locks.rf_ps_lock);
+	if (rtlpriv->psc.rfchange_inprogress) {
+		spin_unlock(&rtlpriv->locks.rf_ps_lock);
+		return;
+	}
+	spin_unlock(&rtlpriv->locks.rf_ps_lock);
+
+	spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+	rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS , false);
+	spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
 
 	if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
-		!RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
+	    !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
 		rtlpriv->intf_ops->enable_aspm(hw);
 		RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
 	}
@@ -706,7 +666,7 @@
 	 * awake before every dtim */
 	RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
 		 "dtim_counter:%x will sleep :%d beacon_intv\n",
-		 rtlpriv->psc.dtim_counter, sleep_intv);
+		  rtlpriv->psc.dtim_counter, sleep_intv);
 
 	/* we tested that 40ms is enough for sw & hw sw delay */
 	queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq,
@@ -744,7 +704,7 @@
 
 		if (rtlpriv->psc.state && !ps) {
 			rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies -
-					rtlpriv->psc.last_action);
+						 rtlpriv->psc.last_action);
 		}
 
 		if (ps)
@@ -764,7 +724,7 @@
 	u8 *pos, *end, *ie;
 	u16 noa_len;
 	static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
-	u8 noa_num, index, i, noa_index = 0;
+	u8 noa_num, index , i, noa_index = 0;
 	bool find_p2p_ie = false , find_p2p_ps_ie = false;
 	pos = (u8 *)mgmt->u.beacon.variable;
 	end = data + len;
@@ -814,7 +774,7 @@
 				index = 5;
 				for (i = 0; i < noa_num; i++) {
 					p2pinfo->noa_count_type[i] =
-						 READEF1BYTE(ie+index);
+							READEF1BYTE(ie+index);
 					index += 1;
 					p2pinfo->noa_duration[i] =
 						 READEF4BYTE((__le32 *)ie+index);
@@ -842,7 +802,7 @@
 					rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
 				}
 			}
-		break;
+			break;
 		}
 		ie += 3 + noa_len;
 	}
@@ -860,7 +820,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct ieee80211_mgmt *mgmt = data;
 	struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
-	u8 noa_num, index, i, noa_index = 0;
+	u8 noa_num, index , i , noa_index = 0;
 	u8 *pos, *end, *ie;
 	u16 noa_len;
 	static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
@@ -906,7 +866,7 @@
 				index = 5;
 				for (i = 0; i < noa_num; i++) {
 					p2pinfo->noa_count_type[i] =
-							 READEF1BYTE(ie+index);
+							READEF1BYTE(ie+index);
 					index += 1;
 					p2pinfo->noa_duration[i] =
 							 READEF4BYTE((__le32 *)ie+index);
@@ -934,37 +894,37 @@
 					rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
 				}
 			}
-		break;
+			break;
 		}
 		ie += 3 + noa_len;
 	}
 }
 
-void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+void rtl_p2p_ps_cmd(struct ieee80211_hw *hw , u8 p2p_ps_state)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
 	struct rtl_p2p_ps_info  *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
 
-	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, " p2p state %x\n", p2p_ps_state);
+	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, " p2p state %x\n" , p2p_ps_state);
 	switch (p2p_ps_state) {
 	case P2P_PS_DISABLE:
 		p2pinfo->p2p_ps_state = p2p_ps_state;
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
 					      &p2p_ps_state);
-
 		p2pinfo->noa_index = 0;
 		p2pinfo->ctwindow = 0;
 		p2pinfo->opp_ps = 0;
 		p2pinfo->noa_num = 0;
 		p2pinfo->p2p_ps_mode = P2P_PS_NONE;
-		if (rtlps->fw_current_inpsmode == true) {
+		if (rtlps->fw_current_inpsmode) {
 			if (rtlps->smart_ps == 0) {
 				rtlps->smart_ps = 2;
 				rtlpriv->cfg->ops->set_hw_reg(hw,
 					 HW_VAR_H2C_FW_PWRMODE,
 					 &rtlps->pwr_mode);
 			}
+
 		}
 		break;
 	case P2P_PS_ENABLE:
@@ -982,6 +942,7 @@
 			rtlpriv->cfg->ops->set_hw_reg(hw,
 				 HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
 				 &p2p_ps_state);
+
 		}
 		break;
 	case P2P_PS_SCAN:
@@ -998,12 +959,16 @@
 		break;
 	}
 	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
-		 "ctwindow %x oppps %x\n", p2pinfo->ctwindow, p2pinfo->opp_ps);
+		 "ctwindow %x oppps %x\n",
+		 p2pinfo->ctwindow , p2pinfo->opp_ps);
 	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
 		 "count %x duration %x index %x interval %x start time %x noa num %x\n",
-		 p2pinfo->noa_count_type[0], p2pinfo->noa_duration[0],
-		 p2pinfo->noa_index, p2pinfo->noa_interval[0],
-		 p2pinfo->noa_start_time[0], p2pinfo->noa_num);
+		 p2pinfo->noa_count_type[0],
+		 p2pinfo->noa_duration[0],
+		 p2pinfo->noa_index,
+		 p2pinfo->noa_interval[0],
+		 p2pinfo->noa_start_time[0],
+		 p2pinfo->noa_num);
 	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "end\n");
 }
 
@@ -1032,8 +997,8 @@
 		return;
 
 	if (ieee80211_is_action(hdr->frame_control))
-		rtl_p2p_action_ie(hw, data, len - FCS_LEN);
+		rtl_p2p_action_ie(hw , data , len - FCS_LEN);
 	else
-		rtl_p2p_noa_ie(hw, data, len - FCS_LEN);
+		rtl_p2p_noa_ie(hw , data , len - FCS_LEN);
 }
 EXPORT_SYMBOL_GPL(rtl_p2p_info);
diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h
index 3bd41f9..29dfc51 100644
--- a/drivers/net/wireless/rtlwifi/ps.h
+++ b/drivers/net/wireless/rtlwifi/ps.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -32,68 +28,9 @@
 
 #define MAX_SW_LPS_SLEEP_INTV	5
 
-/*---------------------------------------------
- * 3 The value of cmd: 4 bits
- *---------------------------------------------
- */
-#define    PWR_CMD_READ		0x00
-#define    PWR_CMD_WRITE	0x01
-#define    PWR_CMD_POLLING	0x02
-#define    PWR_CMD_DELAY	0x03
-#define    PWR_CMD_END		0x04
-
-/* define the base address of each block */
-#define	PWR_BASEADDR_MAC	0x00
-#define	PWR_BASEADDR_USB	0x01
-#define	PWR_BASEADDR_PCIE	0x02
-#define	PWR_BASEADDR_SDIO	0x03
-
-#define	PWR_FAB_ALL_MSK		(BIT(0)|BIT(1)|BIT(2)|BIT(3))
-#define	PWR_CUT_TESTCHIP_MSK	BIT(0)
-#define	PWR_CUT_A_MSK		BIT(1)
-#define	PWR_CUT_B_MSK		BIT(2)
-#define	PWR_CUT_C_MSK		BIT(3)
-#define	PWR_CUT_D_MSK		BIT(4)
-#define	PWR_CUT_E_MSK		BIT(5)
-#define	PWR_CUT_F_MSK		BIT(6)
-#define	PWR_CUT_G_MSK		BIT(7)
-#define	PWR_CUT_ALL_MSK		0xFF
-#define PWR_INTF_SDIO_MSK	BIT(0)
-#define PWR_INTF_USB_MSK	BIT(1)
-#define PWR_INTF_PCI_MSK	BIT(2)
-#define PWR_INTF_ALL_MSK	(BIT(0)|BIT(1)|BIT(2)|BIT(3))
-
-enum pwrseq_delay_unit {
-	PWRSEQ_DELAY_US,
-	PWRSEQ_DELAY_MS,
-};
-
-struct wlan_pwr_cfg {
-	u16 offset;
-	u8 cut_msk;
-	u8 fab_msk:4;
-	u8 interface_msk:4;
-	u8 base:4;
-	u8 cmd:4;
-	u8 msk;
-	u8 value;
-};
-
-#define	GET_PWR_CFG_OFFSET(__PWR_CMD)	(__PWR_CMD.offset)
-#define	GET_PWR_CFG_CUT_MASK(__PWR_CMD)	(__PWR_CMD.cut_msk)
-#define	GET_PWR_CFG_FAB_MASK(__PWR_CMD)	(__PWR_CMD.fab_msk)
-#define	GET_PWR_CFG_INTF_MASK(__PWR_CMD)	(__PWR_CMD.interface_msk)
-#define	GET_PWR_CFG_BASE(__PWR_CMD)	(__PWR_CMD.base)
-#define	GET_PWR_CFG_CMD(__PWR_CMD)	(__PWR_CMD.cmd)
-#define	GET_PWR_CFG_MASK(__PWR_CMD)	(__PWR_CMD.msk)
-#define	GET_PWR_CFG_VALUE(__PWR_CMD)	(__PWR_CMD.value)
-
-bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
-			      u8 fab_version, u8 interface_type,
-			      struct wlan_pwr_cfg pwrcfgcmd[]);
-
 bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
-			 enum rf_pwrstate state_toset, u32 changesource);
+			 enum rf_pwrstate state_toset, u32 changesource,
+			 bool protect_or_not);
 bool rtl_ps_enable_nic(struct ieee80211_hw *hw);
 bool rtl_ps_disable_nic(struct ieee80211_hw *hw);
 void rtl_ips_nic_off(struct ieee80211_hw *hw);
@@ -102,12 +39,14 @@
 void rtl_lps_enter(struct ieee80211_hw *hw);
 void rtl_lps_leave(struct ieee80211_hw *hw);
 
+void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode);
+
 void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len);
 void rtl_swlps_wq_callback(void *data);
 void rtl_swlps_rfon_wq_callback(void *data);
 void rtl_swlps_rf_awake(struct ieee80211_hw *hw);
 void rtl_swlps_rf_sleep(struct ieee80211_hw *hw);
-void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
+void rtl_p2p_ps_cmd(struct ieee80211_hw *hw , u8 p2p_ps_state);
 void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len);
 void rtl_lps_change_work_callback(struct work_struct *work);
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.h b/drivers/net/wireless/rtlwifi/pwrseqcmd.h
similarity index 92%
rename from drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.h
rename to drivers/net/wireless/rtlwifi/pwrseqcmd.h
index 6e0f3ea..17ce0cb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.h
+++ b/drivers/net/wireless/rtlwifi/pwrseqcmd.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,7 +26,7 @@
 #ifndef __RTL8723E_PWRSEQCMD_H__
 #define __RTL8723E_PWRSEQCMD_H__
 
-#include "../wifi.h"
+#include "wifi.h"
 /*---------------------------------------------
  * 3 The value of cmd: 4 bits
  *---------------------------------------------
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c
index ee28a1a..7863bd2 100644
--- a/drivers/net/wireless/rtlwifi/rc.c
+++ b/drivers/net/wireless/rtlwifi/rc.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -35,13 +31,13 @@
  *Finds the highest rate index we can use
  *if skb is special data like DHCP/EAPOL, we set should
  *it to lowest rate CCK_1M, otherwise we set rate to
- *CCK11M or OFDM_54M based on wireless mode.
+ *highest rate based on wireless mode used for iwconfig
+ *show Tx rate.
  */
 static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,
 				  struct ieee80211_sta *sta,
 				  struct sk_buff *skb, bool not_data)
 {
-	struct rtl_mac *rtlmac = rtl_mac(rtlpriv);
 	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_sta_info *sta_entry = NULL;
@@ -54,21 +50,13 @@
 	 *2.in rtl_get_tcb_desc when we check rate is
 	 *      1M we will not use FW rate but user rate.
 	 */
-	if (rtlmac->opmode == NL80211_IFTYPE_AP ||
-	    rtlmac->opmode == NL80211_IFTYPE_ADHOC ||
-	    rtlmac->opmode == NL80211_IFTYPE_MESH_POINT) {
-		if (sta) {
-			sta_entry = (struct rtl_sta_info *) sta->drv_priv;
-			wireless_mode = sta_entry->wireless_mode;
-		} else {
-			return 0;
-		}
-	} else {
-		wireless_mode = rtlmac->mode;
+
+	if (sta) {
+		sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+		wireless_mode = sta_entry->wireless_mode;
 	}
 
-	if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true) ||
-			not_data) {
+	if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true) || not_data) {
 		return 0;
 	} else {
 		if (rtlhal->current_bandtype == BAND_ON_2_4G) {
@@ -76,21 +64,27 @@
 				return B_MODE_MAX_RIX;
 			} else if (wireless_mode == WIRELESS_MODE_G) {
 				return G_MODE_MAX_RIX;
-			} else {
+			} else if (wireless_mode == WIRELESS_MODE_N_24G) {
 				if (get_rf_type(rtlphy) != RF_2T2R)
 					return N_MODE_MCS7_RIX;
 				else
 					return N_MODE_MCS15_RIX;
+			} else if (wireless_mode == WIRELESS_MODE_AC_24G) {
+				return AC_MODE_MCS9_RIX;
 			}
+			return 0;
 		} else {
 			if (wireless_mode == WIRELESS_MODE_A) {
 				return A_MODE_MAX_RIX;
-			} else {
+			} else if (wireless_mode == WIRELESS_MODE_N_5G) {
 				if (get_rf_type(rtlphy) != RF_2T2R)
 					return N_MODE_MCS7_RIX;
 				else
 					return N_MODE_MCS15_RIX;
+			} else if (wireless_mode == WIRELESS_MODE_AC_5G) {
+				return AC_MODE_MCS9_RIX;
 			}
+			return 0;
 		}
 	}
 }
@@ -103,35 +97,52 @@
 				    bool not_data)
 {
 	struct rtl_mac *mac = rtl_mac(rtlpriv);
-	u8 sgi_20 = 0, sgi_40 = 0;
+	struct rtl_sta_info *sta_entry = NULL;
+	u8 wireless_mode = 0;
+	u8 sgi_20 = 0, sgi_40 = 0, sgi_80 = 0;
 
 	if (sta) {
 		sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
 		sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+		sgi_80 = sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80;
+		sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+		wireless_mode = sta_entry->wireless_mode;
 	}
 	rate->count = tries;
 	rate->idx = rix >= 0x00 ? rix : 0x00;
+	if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE &&
+	    wireless_mode == WIRELESS_MODE_AC_5G)
+		rate->idx += 0x10;/*2NSS for 8812AE*/
 
 	if (!not_data) {
 		if (txrc->short_preamble)
 			rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
 		if (mac->opmode == NL80211_IFTYPE_AP ||
-		    mac->opmode == NL80211_IFTYPE_ADHOC) {
-			if (sta && (sta->bandwidth >= IEEE80211_STA_RX_BW_40))
+			mac->opmode == NL80211_IFTYPE_ADHOC) {
+			if (sta && (sta->ht_cap.cap &
+				    IEEE80211_HT_CAP_SUP_WIDTH_20_40))
 				rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+			if (sta && (sta->vht_cap.vht_supported))
+				rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
 		} else {
 			if (mac->bw_40)
 				rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+			if (mac->bw_80)
+				rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
 		}
-		if (sgi_20 || sgi_40)
+
+		if (sgi_20 || sgi_40 || sgi_80)
 			rate->flags |= IEEE80211_TX_RC_SHORT_GI;
-		if (sta && sta->ht_cap.ht_supported)
+		if (sta && sta->ht_cap.ht_supported &&
+		    ((wireless_mode == WIRELESS_MODE_N_5G) ||
+		     (wireless_mode == WIRELESS_MODE_N_24G)))
 			rate->flags |= IEEE80211_TX_RC_MCS;
 	}
 }
 
 static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta,
-			 void *priv_sta, struct ieee80211_tx_rate_control *txrc)
+			 void *priv_sta,
+			 struct ieee80211_tx_rate_control *txrc)
 {
 	struct rtl_priv *rtlpriv = ppriv;
 	struct sk_buff *skb = txrc->skb;
@@ -158,7 +169,7 @@
 }
 
 static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv,
-		struct rtl_sta_info *sta_entry, u16 tid)
+			       struct rtl_sta_info *sta_entry, u16 tid)
 {
 	struct rtl_mac *mac = rtl_mac(rtlpriv);
 
@@ -166,7 +177,7 @@
 		return false;
 
 	if (mac->opmode == NL80211_IFTYPE_STATION &&
-		mac->cnt_after_linked < 3)
+	    mac->cnt_after_linked < 3)
 		return false;
 
 	if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP)
@@ -193,23 +204,23 @@
 	if (rtl_is_special_data(mac->hw, skb, true))
 		return;
 
-	if (is_multicast_ether_addr(ieee80211_get_DA(hdr))
-	    || is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
+	if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+	    is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
 		return;
 
 	if (sta) {
 		/* Check if aggregation has to be enabled for this tid */
 		sta_entry = (struct rtl_sta_info *) sta->drv_priv;
 		if ((sta->ht_cap.ht_supported) &&
-				!(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+		    !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
 			if (ieee80211_is_data_qos(fc)) {
 				u8 tid = rtl_get_tid(skb);
 				if (_rtl_tx_aggr_check(rtlpriv, sta_entry,
-				    tid)) {
+						       tid)) {
 					sta_entry->tids[tid].agg.agg_state =
-							 RTL_AGG_PROGRESS;
-					ieee80211_start_tx_ba_session(sta,
-								 tid, 5000);
+						RTL_AGG_PROGRESS;
+					ieee80211_start_tx_ba_session(sta, tid,
+								      5000);
 				}
 			}
 		}
@@ -223,8 +234,15 @@
 {
 }
 
-static void *rtl_rate_alloc(struct ieee80211_hw *hw,
-		struct dentry *debugfsdir)
+static void rtl_rate_update(void *ppriv,
+			    struct ieee80211_supported_band *sband,
+			    struct cfg80211_chan_def *chandef,
+			    struct ieee80211_sta *sta, void *priv_sta,
+			    u32 changed)
+{
+}
+
+static void *rtl_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	return rtlpriv;
@@ -260,13 +278,14 @@
 	kfree(rate_priv);
 }
 
-static const struct rate_control_ops rtl_rate_ops = {
+static struct rate_control_ops rtl_rate_ops = {
 	.name = "rtl_rc",
 	.alloc = rtl_rate_alloc,
 	.free = rtl_rate_free,
 	.alloc_sta = rtl_rate_alloc_sta,
 	.free_sta = rtl_rate_free_sta,
 	.rate_init = rtl_rate_init,
+	.rate_update = rtl_rate_update,
 	.tx_status = rtl_tx_status,
 	.get_rate = rtl_get_rate,
 };
diff --git a/drivers/net/wireless/rtlwifi/rc.h b/drivers/net/wireless/rtlwifi/rc.h
index 4d61761..f29643d 100644
--- a/drivers/net/wireless/rtlwifi/rc.h
+++ b/drivers/net/wireless/rtlwifi/rc.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -38,10 +34,15 @@
 #define N_MODE_MCS7_RIX 7
 #define N_MODE_MCS15_RIX 15
 
+#define AC_MODE_MCS7_RIX 7
+#define AC_MODE_MCS8_RIX 8
+#define AC_MODE_MCS9_RIX 9
+
 struct rtl_rate_priv {
 	u8 ht_cap;
 };
 
 int rtl_rate_control_register(void);
 void rtl_rate_control_unregister(void);
+
 #endif
diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c
index a4eb9b2..1893d01 100644
--- a/drivers/net/wireless/rtlwifi/regd.c
+++ b/drivers/net/wireless/rtlwifi/regd.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -59,26 +55,23 @@
  */
 #define RTL819x_2GHZ_CH12_13	\
 	REG_RULE(2467-10, 2472+10, 40, 0, 20,\
-		 NL80211_RRF_NO_IR)
+	NL80211_RRF_PASSIVE_SCAN)
 
 #define RTL819x_2GHZ_CH14	\
 	REG_RULE(2484-10, 2484+10, 40, 0, 20, \
-		 NL80211_RRF_NO_IR | NL80211_RRF_NO_OFDM)
+	NL80211_RRF_PASSIVE_SCAN | \
+	NL80211_RRF_NO_OFDM)
+
 
 /* 5G chan 36 - chan 64*/
 #define RTL819x_5GHZ_5150_5350	\
-	REG_RULE(5150-10, 5350+10, 40, 0, 30, \
-		 NL80211_RRF_NO_IR)
-
+	REG_RULE(5150-10, 5350+10, 80, 0, 30, 0)
 /* 5G chan 100 - chan 165*/
 #define RTL819x_5GHZ_5470_5850	\
-	REG_RULE(5470-10, 5850+10, 40, 0, 30, \
-		 NL80211_RRF_NO_IR)
-
+	REG_RULE(5470-10, 5850+10, 80, 0, 30, 0)
 /* 5G chan 149 - chan 165*/
 #define RTL819x_5GHZ_5725_5850	\
-	REG_RULE(5725-10, 5850+10, 40, 0, 30, \
-		 NL80211_RRF_NO_IR)
+	REG_RULE(5725-10, 5850+10, 80, 0, 30, 0)
 
 #define RTL819x_5GHZ_ALL	\
 	(RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850)
@@ -143,7 +136,7 @@
 
 static bool _rtl_is_radar_freq(u16 center_freq)
 {
-	return (center_freq >= 5260 && center_freq <= 5700);
+	return center_freq >= 5260 && center_freq <= 5700;
 }
 
 static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
@@ -169,10 +162,9 @@
 				continue;
 			if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
 				reg_rule = freq_reg_info(wiphy,
-							 MHZ_TO_KHZ(ch->center_freq));
+							 ch->center_freq);
 				if (IS_ERR(reg_rule))
 					continue;
-
 				/*
 				 *If 11d had a rule for this channel ensure
 				 *we enable adhoc/beaconing if it allows us to
@@ -182,11 +174,16 @@
 				 *regulatory_hint().
 				 */
 
-				if (!(reg_rule->flags & NL80211_RRF_NO_IR))
-					ch->flags &= ~IEEE80211_CHAN_NO_IR;
+				if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
+					ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
+				if (!(reg_rule->flags &
+				      NL80211_RRF_PASSIVE_SCAN))
+					ch->flags &=
+					    ~IEEE80211_CHAN_PASSIVE_SCAN;
 			} else {
 				if (ch->beacon_found)
-					ch->flags &= ~IEEE80211_CHAN_NO_IR;
+					ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
+						   IEEE80211_CHAN_PASSIVE_SCAN);
 			}
 		}
 	}
@@ -211,35 +208,35 @@
 	 */
 	if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
 		ch = &sband->channels[11];	/* CH 12 */
-		if (ch->flags & IEEE80211_CHAN_NO_IR)
-			ch->flags &= ~IEEE80211_CHAN_NO_IR;
+		if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+			ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
 		ch = &sband->channels[12];	/* CH 13 */
-		if (ch->flags & IEEE80211_CHAN_NO_IR)
-			ch->flags &= ~IEEE80211_CHAN_NO_IR;
+		if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+			ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
 		return;
 	}
 
 	/*
-	 *If a country IE has been received check its rule for this
+	 *If a country IE has been recieved check its rule for this
 	 *channel first before enabling active scan. The passive scan
 	 *would have been enforced by the initial processing of our
 	 *custom regulatory domain.
 	 */
 
 	ch = &sband->channels[11];	/* CH 12 */
-	reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq));
+	reg_rule = freq_reg_info(wiphy, ch->center_freq);
 	if (!IS_ERR(reg_rule)) {
-		if (!(reg_rule->flags & NL80211_RRF_NO_IR))
-			if (ch->flags & IEEE80211_CHAN_NO_IR)
-				ch->flags &= ~IEEE80211_CHAN_NO_IR;
+		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
+			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
 	}
 
 	ch = &sband->channels[12];	/* CH 13 */
-	reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq));
+	reg_rule = freq_reg_info(wiphy, ch->center_freq);
 	if (!IS_ERR(reg_rule)) {
-		if (!(reg_rule->flags & NL80211_RRF_NO_IR))
-			if (ch->flags & IEEE80211_CHAN_NO_IR)
-				ch->flags &= ~IEEE80211_CHAN_NO_IR;
+		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
+			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
 	}
 }
 
@@ -276,7 +273,8 @@
 		 */
 		if (!(ch->flags & IEEE80211_CHAN_DISABLED))
 			ch->flags |= IEEE80211_CHAN_RADAR |
-				     IEEE80211_CHAN_NO_IR;
+			    IEEE80211_CHAN_NO_IBSS |
+			    IEEE80211_CHAN_PASSIVE_SCAN;
 	}
 }
 
@@ -289,9 +287,25 @@
 	return;
 }
 
-static void _rtl_reg_notifier_apply(struct wiphy *wiphy,
-				    struct regulatory_request *request,
-				    struct rtl_regulatory *reg)
+static void _rtl_dump_channel_map(struct wiphy *wiphy)
+{
+	enum ieee80211_band band;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_channel *ch;
+	unsigned int i;
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		if (!wiphy->bands[band])
+			continue;
+		sband = wiphy->bands[band];
+		for (i = 0; i < sband->n_channels; i++)
+			ch = &sband->channels[i];
+	}
+}
+
+static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
+				   struct regulatory_request *request,
+				   struct rtl_regulatory *reg)
 {
 	/* We always apply this */
 	_rtl_reg_apply_radar_flags(wiphy);
@@ -305,10 +319,14 @@
 		_rtl_reg_apply_world_flags(wiphy, request->initiator, reg);
 		break;
 	}
+
+	_rtl_dump_channel_map(wiphy);
+
+	return 0;
 }
 
 static const struct ieee80211_regdomain *_rtl_regdomain_select(
-					       struct rtl_regulatory *reg)
+						struct rtl_regulatory *reg)
 {
 	switch (reg->country_code) {
 	case COUNTRY_CODE_FCC:
@@ -337,9 +355,9 @@
 
 static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
 				struct wiphy *wiphy,
-				void (*reg_notifier) (struct wiphy *wiphy,
-						      struct regulatory_request *
-						      request))
+				void (*reg_notifier)(struct wiphy *wiphy,
+						     struct regulatory_request *
+						     request))
 {
 	const struct ieee80211_regdomain *regd;
 
@@ -348,7 +366,6 @@
 	wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
 	wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG;
 	wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS;
-
 	regd = _rtl_regdomain_select(reg);
 	wiphy_apply_custom_regulatory(wiphy, regd);
 	_rtl_reg_apply_radar_flags(wiphy);
@@ -368,7 +385,7 @@
 }
 
 int rtl_regd_init(struct ieee80211_hw *hw,
-		  void (*reg_notifier) (struct wiphy *wiphy,
+		  void (*reg_notifier)(struct wiphy *wiphy,
 				       struct regulatory_request *request))
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -382,7 +399,8 @@
 	rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan;
 
 	RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE,
-		 "rtl: EEPROM regdomain: 0x%0x\n", rtlpriv->regd.country_code);
+		 "rtl: EEPROM regdomain: 0x%0x\n",
+		  rtlpriv->regd.country_code);
 
 	if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) {
 		RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG,
@@ -403,7 +421,7 @@
 
 	RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE,
 		 "rtl: Country alpha2 being used: %c%c\n",
-		 rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1]);
+		  rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1]);
 
 	_rtl_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier);
 
diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h
index 4e1f4f0..3bbbaaa 100644
--- a/drivers/net/wireless/rtlwifi/regd.h
+++ b/drivers/net/wireless/rtlwifi/regd.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,6 +26,10 @@
 #ifndef __RTL_REGD_H__
 #define __RTL_REGD_H__
 
+/* for kernel 3.14 , both value are changed to IEEE80211_CHAN_NO_IR*/
+#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR
+#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR
+
 struct country_code_to_enum_rd {
 	u16 countrycode;
 	const char *iso_name;
@@ -56,6 +56,7 @@
 
 int rtl_regd_init(struct ieee80211_hw *hw,
 		  void (*reg_notifier) (struct wiphy *wiphy,
-					struct regulatory_request *request));
+		  struct regulatory_request *request));
 void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
+
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/def.h b/drivers/net/wireless/rtlwifi/rtl8188ee/def.h
index c764fff..d9ea9d0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/def.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -111,7 +107,6 @@
 
 #define CHIP_BONDING_IDENTIFIER(_value)	(((_value)>>22)&0x3)
 
-
 /* [15:12] IC version(CUT): A-cut=0, B-cut=1, C-cut=2, D-cut=3
  * [7] Manufacturer: TSMC=0, UMC=1
  * [6:4] RF type: 1T1R=0, 1T2R=1, 2T2R=2
@@ -130,7 +125,6 @@
 #define D_CUT_VERSION			((BIT(12)|BIT(13)))
 #define E_CUT_VERSION			BIT(14)
 
-
 /* MASK */
 #define IC_TYPE_MASK			(BIT(0)|BIT(1)|BIT(2))
 #define CHIP_TYPE_MASK			BIT(3)
@@ -147,7 +141,6 @@
 #define GET_CVID_ROM_VERSION(version)	((version) & ROM_VERSION_MASK)
 #define GET_CVID_CUT_VERSION(version)	((version) & CUT_VERSION_MASK)
 
-
 #define IS_81XXC(version)						\
 	((GET_CVID_IC_TYPE(version) == 0) ? true : false)
 #define IS_8723_SERIES(version)						\
@@ -174,7 +167,7 @@
 #define IS_81xxC_VENDOR_UMC_A_CUT(version)				\
 	(IS_81XXC(version) ? ((IS_CHIP_VENDOR_UMC(version)) ?		\
 	 ((GET_CVID_CUT_VERSION(version)) ? false : true) : false) : false)
-#define IS_81xxC_VENDOR_UMC_B_CUT(version)				\
+#define IS_81XXC_VENDOR_UMC_B_CUT(version)				\
 	(IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ?		\
 	((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? true	\
 	: false) : false) : false)
@@ -225,44 +218,37 @@
 };
 
 enum interface_select_pci {
-	INTF_SEL1_MINICARD,
-	INTF_SEL0_PCIE,
-	INTF_SEL2_RSV,
-	INTF_SEL3_RSV,
+	INTF_SEL1_MINICARD = 0,
+	INTF_SEL0_PCIE = 1,
+	INTF_SEL2_RSV = 2,
+	INTF_SEL3_RSV = 3,
 };
 
 enum hal_fw_c2h_cmd_id {
-	HAL_FW_C2H_CMD_Read_MACREG,
-	HAL_FW_C2H_CMD_Read_BBREG,
-	HAL_FW_C2H_CMD_Read_RFREG,
-	HAL_FW_C2H_CMD_Read_EEPROM,
-	HAL_FW_C2H_CMD_Read_EFUSE,
-	HAL_FW_C2H_CMD_Read_CAM,
-	HAL_FW_C2H_CMD_Get_BasicRate,
-	HAL_FW_C2H_CMD_Get_DataRate,
-	HAL_FW_C2H_CMD_Survey,
-	HAL_FW_C2H_CMD_SurveyDone,
-	HAL_FW_C2H_CMD_JoinBss,
-	HAL_FW_C2H_CMD_AddSTA,
-	HAL_FW_C2H_CMD_DelSTA,
-	HAL_FW_C2H_CMD_AtimDone,
-	HAL_FW_C2H_CMD_TX_Report,
-	HAL_FW_C2H_CMD_CCX_Report,
-	HAL_FW_C2H_CMD_DTM_Report,
-	HAL_FW_C2H_CMD_TX_Rate_Statistics,
-	HAL_FW_C2H_CMD_C2HLBK,
-	HAL_FW_C2H_CMD_C2HDBG,
-	HAL_FW_C2H_CMD_C2HFEEDBACK,
+	HAL_FW_C2H_CMD_READ_MACREG = 0,
+	HAL_FW_C2H_CMD_READ_BBREG = 1,
+	HAL_FW_C2H_CMD_READ_RFREG = 2,
+	HAL_FW_C2H_CMD_READ_EEPROM = 3,
+	HAL_FW_C2H_CMD_READ_EFUSE = 4,
+	HAL_FW_C2H_CMD_READ_CAM = 5,
+	HAL_FW_C2H_CMD_GET_BASICRATE = 6,
+	HAL_FW_C2H_CMD_GET_DATARATE = 7,
+	HAL_FW_C2H_CMD_SURVEY = 8,
+	HAL_FW_C2H_CMD_SURVEYDONE = 9,
+	HAL_FW_C2H_CMD_JOINBSS = 10,
+	HAL_FW_C2H_CMD_ADDSTA = 11,
+	HAL_FW_C2H_CMD_DELSTA = 12,
+	HAL_FW_C2H_CMD_ATIMDONE = 13,
+	HAL_FW_C2H_CMD_TX_REPORT = 14,
+	HAL_FW_C2H_CMD_CCX_REPORT = 15,
+	HAL_FW_C2H_CMD_DTM_REPORT = 16,
+	HAL_FW_C2H_CMD_TX_RATE_STATISTICS = 17,
+	HAL_FW_C2H_CMD_C2HLBK = 18,
+	HAL_FW_C2H_CMD_C2HDBG = 19,
+	HAL_FW_C2H_CMD_C2HFEEDBACK = 20,
 	HAL_FW_C2H_CMD_MAX
 };
 
-enum wake_on_wlan_mode {
-	ewowlandisable,
-	ewakeonmagicpacketonly,
-	ewakeonpatternmatchonly,
-	ewakeonbothtypepacket
-};
-
 enum rtl_desc_qsel {
 	QSLT_BK = 0x2,
 	QSLT_BE = 0x0,
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
index f8daa61..2aa34d9 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -188,21 +184,24 @@
 		switch (rfpath) {
 		case RF90_PATH_A:
 			value32 = (ele_d << 22)|((ele_c & 0x3F)<<16) | ele_a;
-			rtl_set_bbreg(hw, ROFDM0_XATXIQIMBAL, MASKDWORD,
-				      value32);
+			rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+				      MASKDWORD, value32);
 			value32 = (ele_c & 0x000003C0) >> 6;
-			rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, value32);
+			rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS,
+				      value32);
 			value32 = ((iqk_result_x * ele_d) >> 7) & 0x01;
-			rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(24), value32);
+			rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(24),
+				      value32);
 			break;
 		case RF90_PATH_B:
 			value32 = (ele_d << 22)|((ele_c & 0x3F)<<16) | ele_a;
-			rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBAL,
-				      MASKDWORD, value32);
+			rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, MASKDWORD,
+				      value32);
 			value32 = (ele_c & 0x000003C0) >> 6;
 			rtl_set_bbreg(hw, ROFDM0_XDTXAFE, MASKH4BITS, value32);
 			value32 = ((iqk_result_x * ele_d) >> 7) & 0x01;
-			rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(28), value32);
+			rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(28),
+				      value32);
 			break;
 		default:
 			break;
@@ -210,16 +209,20 @@
 	} else {
 		switch (rfpath) {
 		case RF90_PATH_A:
-			rtl_set_bbreg(hw, ROFDM0_XATXIQIMBAL, MASKDWORD,
-				      ofdmswing_table[ofdm_index]);
-			rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, 0x00);
-			rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(24), 0x00);
+			rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+				      MASKDWORD, ofdmswing_table[ofdm_index]);
+			rtl_set_bbreg(hw, ROFDM0_XCTXAFE,
+				      MASKH4BITS, 0x00);
+			rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
+				      BIT(24), 0x00);
 			break;
 		case RF90_PATH_B:
-			rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBAL, MASKDWORD,
-				      ofdmswing_table[ofdm_index]);
-			rtl_set_bbreg(hw, ROFDM0_XDTXAFE, MASKH4BITS, 0x00);
-			rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(28), 0x00);
+			rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBALANCE,
+				      MASKDWORD, ofdmswing_table[ofdm_index]);
+			rtl_set_bbreg(hw, ROFDM0_XDTXAFE,
+				      MASKH4BITS, 0x00);
+			rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD,
+				      BIT(28), 0x00);
 			break;
 		default:
 			break;
@@ -244,7 +247,7 @@
 			pwr_val = ofdm_base - ofdm_val;
 		} else {
 			*pdirection = 2;
-			pwr_val = ofdm_val - ofdm_base;
+			pwr_val = ofdm_base - ofdm_val;
 		}
 	} else if (type == 1) {
 		if (cck_val <= cck_base) {
@@ -263,46 +266,75 @@
 			 (pwr_val << 24);
 }
 
-
-static void rtl88e_chk_tx_track(struct ieee80211_hw *hw,
-				enum pwr_track_control_method method,
-				u8 rfpath, u8 index)
+static void dm_tx_pwr_track_set_pwr(struct ieee80211_hw *hw,
+				    enum pwr_track_control_method method,
+				    u8 rfpath, u8 channel_mapped_index)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
-	int jj = rtldm->swing_idx_cck;
-	int i;
 
 	if (method == TXAGC) {
-		if (rtldm->swing_flag_ofdm == true ||
-		    rtldm->swing_flag_cck == true) {
-			u8 chan = rtlphy->current_channel;
-			rtl88e_phy_set_txpower_level(hw, chan);
+		if (rtldm->swing_flag_ofdm ||
+		    rtldm->swing_flag_cck) {
+			rtl88e_phy_set_txpower_level(hw,
+						     rtlphy->current_channel);
 			rtldm->swing_flag_ofdm = false;
 			rtldm->swing_flag_cck = false;
 		}
 	} else if (method == BBSWING) {
 		if (!rtldm->cck_inch14) {
-			for (i = 0; i < 8; i++)
-				rtl_write_byte(rtlpriv, 0xa22 + i,
-					       cck_tbl_ch1_13[jj][i]);
+			rtl_write_byte(rtlpriv, 0xa22,
+				       cck_tbl_ch1_13[rtldm->swing_idx_cck][0]);
+			rtl_write_byte(rtlpriv, 0xa23,
+				       cck_tbl_ch1_13[rtldm->swing_idx_cck][1]);
+			rtl_write_byte(rtlpriv, 0xa24,
+				       cck_tbl_ch1_13[rtldm->swing_idx_cck][2]);
+			rtl_write_byte(rtlpriv, 0xa25,
+				       cck_tbl_ch1_13[rtldm->swing_idx_cck][3]);
+			rtl_write_byte(rtlpriv, 0xa26,
+				       cck_tbl_ch1_13[rtldm->swing_idx_cck][4]);
+			rtl_write_byte(rtlpriv, 0xa27,
+				       cck_tbl_ch1_13[rtldm->swing_idx_cck][5]);
+			rtl_write_byte(rtlpriv, 0xa28,
+				       cck_tbl_ch1_13[rtldm->swing_idx_cck][6]);
+			rtl_write_byte(rtlpriv, 0xa29,
+				       cck_tbl_ch1_13[rtldm->swing_idx_cck][7]);
 		} else {
-			for (i = 0; i < 8; i++)
-				rtl_write_byte(rtlpriv, 0xa22 + i,
-					       cck_tbl_ch14[jj][i]);
+			rtl_write_byte(rtlpriv, 0xa22,
+				       cck_tbl_ch14[rtldm->swing_idx_cck][0]);
+			rtl_write_byte(rtlpriv, 0xa23,
+				       cck_tbl_ch14[rtldm->swing_idx_cck][1]);
+			rtl_write_byte(rtlpriv, 0xa24,
+				       cck_tbl_ch14[rtldm->swing_idx_cck][2]);
+			rtl_write_byte(rtlpriv, 0xa25,
+				       cck_tbl_ch14[rtldm->swing_idx_cck][3]);
+			rtl_write_byte(rtlpriv, 0xa26,
+				       cck_tbl_ch14[rtldm->swing_idx_cck][4]);
+			rtl_write_byte(rtlpriv, 0xa27,
+				       cck_tbl_ch14[rtldm->swing_idx_cck][5]);
+			rtl_write_byte(rtlpriv, 0xa28,
+				       cck_tbl_ch14[rtldm->swing_idx_cck][6]);
+			rtl_write_byte(rtlpriv, 0xa29,
+				       cck_tbl_ch14[rtldm->swing_idx_cck][7]);
 		}
 
 		if (rfpath == RF90_PATH_A) {
-			long x = rtlphy->iqk_matrix[index].value[0][0];
-			long y = rtlphy->iqk_matrix[index].value[0][1];
-			u8 indx = rtldm->swing_idx_ofdm[rfpath];
-			rtl88e_set_iqk_matrix(hw, indx, rfpath, x, y);
+			rtl88e_set_iqk_matrix(hw, rtldm->swing_idx_ofdm[rfpath],
+					      rfpath, rtlphy->iqk_matrix
+					      [channel_mapped_index].
+					      value[0][0],
+					      rtlphy->iqk_matrix
+					      [channel_mapped_index].
+					      value[0][1]);
 		} else if (rfpath == RF90_PATH_B) {
-			u8 indx = rtldm->swing_idx_ofdm[rfpath];
-			long x = rtlphy->iqk_matrix[indx].value[0][4];
-			long y = rtlphy->iqk_matrix[indx].value[0][5];
-			rtl88e_set_iqk_matrix(hw, indx, rfpath, x, y);
+			rtl88e_set_iqk_matrix(hw, rtldm->swing_idx_ofdm[rfpath],
+					      rfpath, rtlphy->iqk_matrix
+					      [channel_mapped_index].
+					      value[0][4],
+					      rtlphy->iqk_matrix
+					      [channel_mapped_index].
+					      value[0][5]);
 		}
 	} else {
 		return;
@@ -317,7 +349,7 @@
 	dm_dig->dig_enable_flag = true;
 	dm_dig->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f);
 	dm_dig->pre_igvalue = 0;
-	dm_dig->cursta_cstate = DIG_STA_DISCONNECT;
+	dm_dig->cur_sta_cstate = DIG_STA_DISCONNECT;
 	dm_dig->presta_cstate = DIG_STA_DISCONNECT;
 	dm_dig->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
 	dm_dig->rssi_lowthresh = DM_DIG_THRESH_LOW;
@@ -348,22 +380,23 @@
 	long rssi_val_min = 0;
 
 	if ((dm_dig->curmultista_cstate == DIG_MULTISTA_CONNECT) &&
-	    (dm_dig->cursta_cstate == DIG_STA_CONNECT)) {
+	    (dm_dig->cur_sta_cstate == DIG_STA_CONNECT)) {
 		if (rtlpriv->dm.entry_min_undec_sm_pwdb != 0)
 			rssi_val_min =
 			    (rtlpriv->dm.entry_min_undec_sm_pwdb >
-			    rtlpriv->dm.undec_sm_pwdb) ?
+			     rtlpriv->dm.undec_sm_pwdb) ?
 			    rtlpriv->dm.undec_sm_pwdb :
 			    rtlpriv->dm.entry_min_undec_sm_pwdb;
 		else
 			rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
-	} else if (dm_dig->cursta_cstate == DIG_STA_CONNECT ||
-		   dm_dig->cursta_cstate == DIG_STA_BEFORE_CONNECT) {
+	} else if (dm_dig->cur_sta_cstate == DIG_STA_CONNECT ||
+		   dm_dig->cur_sta_cstate == DIG_STA_BEFORE_CONNECT) {
 		rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
 	} else if (dm_dig->curmultista_cstate ==
 		DIG_MULTISTA_CONNECT) {
 		rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb;
 	}
+
 	return (u8)rssi_val_min;
 }
 
@@ -371,57 +404,58 @@
 {
 	u32 ret_value;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct false_alarm_statistics *alm_cnt = &(rtlpriv->falsealm_cnt);
+	struct false_alarm_statistics *falsealm_cnt = &rtlpriv->falsealm_cnt;
 
 	rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 1);
 	rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 1);
 
 	ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, MASKDWORD);
-	alm_cnt->cnt_fast_fsync_fail = (ret_value&0xffff);
-	alm_cnt->cnt_sb_search_fail = ((ret_value&0xffff0000)>>16);
+	falsealm_cnt->cnt_fast_fsync_fail = (ret_value&0xffff);
+	falsealm_cnt->cnt_sb_search_fail = ((ret_value&0xffff0000)>>16);
 
 	ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD);
-	alm_cnt->cnt_ofdm_cca = (ret_value&0xffff);
-	alm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16);
+	falsealm_cnt->cnt_ofdm_cca = (ret_value&0xffff);
+	falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16);
 
 	ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD);
-	alm_cnt->cnt_rate_illegal = (ret_value & 0xffff);
-	alm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16);
+	falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff);
+	falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16);
 
 	ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD);
-	alm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
-	alm_cnt->cnt_ofdm_fail = alm_cnt->cnt_parity_fail +
-				 alm_cnt->cnt_rate_illegal +
-				 alm_cnt->cnt_crc8_fail +
-				 alm_cnt->cnt_mcs_fail +
-				 alm_cnt->cnt_fast_fsync_fail +
-				 alm_cnt->cnt_sb_search_fail;
+	falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
+	falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
+		falsealm_cnt->cnt_rate_illegal +
+		falsealm_cnt->cnt_crc8_fail +
+		falsealm_cnt->cnt_mcs_fail +
+		falsealm_cnt->cnt_fast_fsync_fail +
+		falsealm_cnt->cnt_sb_search_fail;
 
 	ret_value = rtl_get_bbreg(hw, REG_SC_CNT, MASKDWORD);
-	alm_cnt->cnt_bw_lsc = (ret_value & 0xffff);
-	alm_cnt->cnt_bw_usc = ((ret_value & 0xffff0000) >> 16);
+	falsealm_cnt->cnt_bw_lsc = (ret_value & 0xffff);
+	falsealm_cnt->cnt_bw_usc = ((ret_value & 0xffff0000) >> 16);
 
 	rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(12), 1);
 	rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(14), 1);
 
 	ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0);
-	alm_cnt->cnt_cck_fail = ret_value;
+	falsealm_cnt->cnt_cck_fail = ret_value;
 
 	ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, MASKBYTE3);
-	alm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8;
+	falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8;
 
 	ret_value = rtl_get_bbreg(hw, RCCK0_CCA_CNT, MASKDWORD);
-	alm_cnt->cnt_cck_cca = ((ret_value & 0xff) << 8) |
-				((ret_value&0xFF00)>>8);
+	falsealm_cnt->cnt_cck_cca = ((ret_value & 0xff) << 8) |
+		((ret_value&0xFF00)>>8);
 
-	alm_cnt->cnt_all = alm_cnt->cnt_fast_fsync_fail +
-			   alm_cnt->cnt_sb_search_fail +
-			   alm_cnt->cnt_parity_fail +
-			   alm_cnt->cnt_rate_illegal +
-			   alm_cnt->cnt_crc8_fail +
-			   alm_cnt->cnt_mcs_fail +
-			   alm_cnt->cnt_cck_fail;
-	alm_cnt->cnt_cca_all = alm_cnt->cnt_ofdm_cca + alm_cnt->cnt_cck_cca;
+	falsealm_cnt->cnt_all = (falsealm_cnt->cnt_fast_fsync_fail +
+				falsealm_cnt->cnt_sb_search_fail +
+				falsealm_cnt->cnt_parity_fail +
+				falsealm_cnt->cnt_rate_illegal +
+				falsealm_cnt->cnt_crc8_fail +
+				falsealm_cnt->cnt_mcs_fail +
+				falsealm_cnt->cnt_cck_fail);
+	falsealm_cnt->cnt_cca_all = falsealm_cnt->cnt_ofdm_cca +
+		falsealm_cnt->cnt_cck_cca;
 
 	rtl_set_bbreg(hw, ROFDM0_TRSWISOLATION, BIT(31), 1);
 	rtl_set_bbreg(hw, ROFDM0_TRSWISOLATION, BIT(31), 0);
@@ -435,16 +469,15 @@
 	rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(15)|BIT(14), 2);
 
 	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
-		 "cnt_parity_fail = %d, cnt_rate_illegal = %d, "
-		 "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
-		 alm_cnt->cnt_parity_fail,
-		 alm_cnt->cnt_rate_illegal,
-		 alm_cnt->cnt_crc8_fail, alm_cnt->cnt_mcs_fail);
+		 "cnt_parity_fail = %d, cnt_rate_illegal = %d, cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
+		 falsealm_cnt->cnt_parity_fail,
+		 falsealm_cnt->cnt_rate_illegal,
+		 falsealm_cnt->cnt_crc8_fail, falsealm_cnt->cnt_mcs_fail);
 
 	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
 		 "cnt_ofdm_fail = %x, cnt_cck_fail = %x, cnt_all = %x\n",
-		 alm_cnt->cnt_ofdm_fail,
-		 alm_cnt->cnt_cck_fail, alm_cnt->cnt_all);
+		 falsealm_cnt->cnt_ofdm_fail,
+		 falsealm_cnt->cnt_cck_fail, falsealm_cnt->cnt_all);
 }
 
 static void rtl88e_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
@@ -453,7 +486,7 @@
 	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
 	u8 cur_cck_cca_thresh;
 
-	if (dm_dig->cursta_cstate == DIG_STA_CONNECT) {
+	if (dm_dig->cur_sta_cstate == DIG_STA_CONNECT) {
 		dm_dig->rssi_val_min = rtl88e_dm_initial_gain_min_pwdb(hw);
 		if (dm_dig->rssi_val_min > 25) {
 			cur_cck_cca_thresh = 0xcd;
@@ -486,10 +519,10 @@
 static void rtl88e_dm_dig(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
-	u8 dig_min, dig_maxofmin;
+	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+	u8 dig_dynamic_min, dig_maxofmin;
 	bool bfirstconnect;
 	u8 dm_dig_max, dm_dig_min;
 	u8 current_igi = dm_dig->cur_igvalue;
@@ -502,19 +535,19 @@
 		return;
 
 	if (mac->link_state >= MAC80211_LINKED)
-		dm_dig->cursta_cstate = DIG_STA_CONNECT;
+		dm_dig->cur_sta_cstate = DIG_STA_CONNECT;
 	else
-		dm_dig->cursta_cstate = DIG_STA_DISCONNECT;
+		dm_dig->cur_sta_cstate = DIG_STA_DISCONNECT;
 	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP ||
 	    rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
-		dm_dig->cursta_cstate = DIG_STA_DISCONNECT;
+		dm_dig->cur_sta_cstate = DIG_STA_DISCONNECT;
 
 	dm_dig_max = DM_DIG_MAX;
 	dm_dig_min = DM_DIG_MIN;
 	dig_maxofmin = DM_DIG_MAX_AP;
-	dig_min = dm_dig->dig_min_0;
+	dig_dynamic_min = dm_dig->dig_min_0;
 	bfirstconnect = ((mac->link_state >= MAC80211_LINKED) ? true : false) &&
-			 (dm_dig->media_connect_0 == false);
+			 !dm_dig->media_connect_0;
 
 	dm_dig->rssi_val_min =
 		rtl88e_dm_initial_gain_min_pwdb(hw);
@@ -528,18 +561,18 @@
 			dm_dig->rx_gain_max = dm_dig->rssi_val_min + 20;
 
 		if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) {
-			dig_min  = dm_dig->antdiv_rssi_max;
+			dig_dynamic_min  = dm_dig->antdiv_rssi_max;
 		} else {
 			if (dm_dig->rssi_val_min < dm_dig_min)
-				dig_min = dm_dig_min;
+				dig_dynamic_min = dm_dig_min;
 			else if (dm_dig->rssi_val_min < dig_maxofmin)
-				dig_min = dig_maxofmin;
+				dig_dynamic_min = dig_maxofmin;
 			else
-				dig_min = dm_dig->rssi_val_min;
+				dig_dynamic_min = dm_dig->rssi_val_min;
 		}
 	} else {
 		dm_dig->rx_gain_max = dm_dig_max;
-		dig_min = dm_dig_min;
+		dig_dynamic_min = dm_dig_min;
 		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n");
 	}
 
@@ -551,10 +584,13 @@
 		}
 
 		if (dm_dig->large_fa_hit >= 3) {
-			if ((dm_dig->forbidden_igi + 1) > dm_dig->rx_gain_max)
-				dm_dig->rx_gain_min = dm_dig->rx_gain_max;
+			if ((dm_dig->forbidden_igi + 1) >
+				dm_dig->rx_gain_max)
+				dm_dig->rx_gain_min =
+					dm_dig->rx_gain_max;
 			else
-				dm_dig->rx_gain_min = dm_dig->forbidden_igi + 1;
+				dm_dig->rx_gain_min =
+					dm_dig->forbidden_igi + 1;
 			dm_dig->recover_cnt = 3600;
 		}
 	} else {
@@ -562,13 +598,14 @@
 			dm_dig->recover_cnt--;
 		} else {
 			if (dm_dig->large_fa_hit == 0) {
-				if ((dm_dig->forbidden_igi - 1) < dig_min) {
-					dm_dig->forbidden_igi = dig_min;
-					dm_dig->rx_gain_min = dig_min;
+				if ((dm_dig->forbidden_igi - 1) <
+				    dig_dynamic_min) {
+					dm_dig->forbidden_igi = dig_dynamic_min;
+					dm_dig->rx_gain_min = dig_dynamic_min;
 				} else {
 					dm_dig->forbidden_igi--;
 					dm_dig->rx_gain_min =
-						 dm_dig->forbidden_igi + 1;
+						dm_dig->forbidden_igi + 1;
 				}
 			} else if (dm_dig->large_fa_hit == 3) {
 				dm_dig->large_fa_hit = 0;
@@ -576,7 +613,7 @@
 		}
 	}
 
-	if (dm_dig->cursta_cstate == DIG_STA_CONNECT) {
+	if (dm_dig->cur_sta_cstate == DIG_STA_CONNECT) {
 		if (bfirstconnect) {
 			current_igi = dm_dig->rssi_val_min;
 		} else {
@@ -606,9 +643,9 @@
 
 	dm_dig->cur_igvalue = current_igi;
 	rtl88e_dm_write_dig(hw);
-	dm_dig->media_connect_0 = ((mac->link_state >= MAC80211_LINKED) ?
-				    true : false);
-	dm_dig->dig_min_0 = dig_min;
+	dm_dig->media_connect_0 =
+		((mac->link_state >= MAC80211_LINKED) ? true : false);
+	dm_dig->dig_min_0 = dig_dynamic_min;
 
 	rtl88e_dm_cck_packet_detection_thresh(hw);
 }
@@ -626,7 +663,7 @@
 static void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	long undec_sm_pwdb;
 
@@ -641,7 +678,7 @@
 	if ((mac->link_state < MAC80211_LINKED) &&
 	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
-			 "Not connected\n");
+			 "Not connected to any\n");
 
 		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
 
@@ -664,10 +701,12 @@
 				  undec_sm_pwdb);
 		}
 	} else {
-		undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
+		undec_sm_pwdb =
+		    rtlpriv->dm.entry_min_undec_sm_pwdb;
 
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
-			 "AP Ext Port PWDB = 0x%lx\n", undec_sm_pwdb);
+			 "AP Ext Port PWDB = 0x%lx\n",
+			  undec_sm_pwdb);
 	}
 
 	if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
@@ -676,17 +715,20 @@
 			 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr = 0x0)\n");
 	} else if ((undec_sm_pwdb <
 		    (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
-		   (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
+		   (undec_sm_pwdb >=
+		    TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
 		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 			 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr = 0x10)\n");
-	} else if (undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
+	} else if (undec_sm_pwdb <
+		   (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
 		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 			 "TXHIGHPWRLEVEL_NORMAL\n");
 	}
 
-	if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) {
+	if ((rtlpriv->dm.dynamic_txhighpower_lvl !=
+		rtlpriv->dm.last_dtp_lvl)) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 			 "PHY_SetTxPowerLevel8192S() Channel = %d\n",
 			  rtlphy->current_channel);
@@ -702,10 +744,9 @@
 	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
 
 	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
-		 "cur_igvalue = 0x%x, "
-		  "pre_igvalue = 0x%x, back_val = %d\n",
-		  dm_dig->cur_igvalue, dm_dig->pre_igvalue,
-		  dm_dig->back_val);
+		 "cur_igvalue = 0x%x, pre_igvalue = 0x%x, backoff_val = %d\n",
+		 dm_dig->cur_igvalue, dm_dig->pre_igvalue,
+		 dm_dig->back_val);
 
 	if (dm_dig->cur_igvalue > 0x3f)
 		dm_dig->cur_igvalue = 0x3f;
@@ -722,17 +763,19 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	struct rtl_sta_info *drv_priv;
-	static u64 last_txok;
-	static u64 last_rx;
+	static u64 last_record_txok_cnt;
+	static u64 last_record_rxok_cnt;
 	long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff;
 
 	if (rtlhal->oem_id == RT_CID_819X_HP) {
 		u64 cur_txok_cnt = 0;
 		u64 cur_rxok_cnt = 0;
-		cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok;
-		cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rx;
-		last_txok = cur_txok_cnt;
-		last_rx = cur_rxok_cnt;
+		cur_txok_cnt = rtlpriv->stats.txbytesunicast -
+			last_record_txok_cnt;
+		cur_rxok_cnt = rtlpriv->stats.rxbytesunicast -
+			last_record_rxok_cnt;
+		last_record_txok_cnt = cur_txok_cnt;
+		last_record_rxok_cnt = cur_rxok_cnt;
 
 		if (cur_rxok_cnt > (cur_txok_cnt * 6))
 			rtl_write_dword(rtlpriv, REG_ARFR0, 0x8f015);
@@ -743,9 +786,11 @@
 	/* AP & ADHOC & MESH */
 	spin_lock_bh(&rtlpriv->locks.entry_list_lock);
 	list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
-		if (drv_priv->rssi_stat.undec_sm_pwdb < tmp_entry_min_pwdb)
+		if (drv_priv->rssi_stat.undec_sm_pwdb <
+			tmp_entry_min_pwdb)
 			tmp_entry_min_pwdb = drv_priv->rssi_stat.undec_sm_pwdb;
-		if (drv_priv->rssi_stat.undec_sm_pwdb > tmp_entry_max_pwdb)
+		if (drv_priv->rssi_stat.undec_sm_pwdb >
+			tmp_entry_max_pwdb)
 			tmp_entry_max_pwdb = drv_priv->rssi_stat.undec_sm_pwdb;
 	}
 	spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
@@ -762,13 +807,19 @@
 	if (tmp_entry_min_pwdb != 0xff) {
 		rtlpriv->dm.entry_min_undec_sm_pwdb = tmp_entry_min_pwdb;
 		RTPRINT(rtlpriv, FDM, DM_PWDB, "EntryMinPWDB = 0x%lx(%ld)\n",
-			tmp_entry_min_pwdb, tmp_entry_min_pwdb);
+					tmp_entry_min_pwdb, tmp_entry_min_pwdb);
 	} else {
 		rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
 	}
 	/* Indicate Rx signal strength to FW. */
-	if (!rtlpriv->dm.useramask)
+	if (rtlpriv->dm.useramask) {
+		u8 h2c_parameter[3] = { 0 };
+
+		h2c_parameter[2] = (u8)(rtlpriv->dm.undec_sm_pwdb & 0xFF);
+		h2c_parameter[0] = 0x20;
+	} else {
 		rtl_write_byte(rtlpriv, 0x4fe, rtlpriv->dm.undec_sm_pwdb);
+	}
 }
 
 void rtl88e_dm_init_edca_turbo(struct ieee80211_hw *hw)
@@ -783,7 +834,6 @@
 static void rtl88e_dm_check_edca_turbo(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	static u64 last_txok_cnt;
 	static u64 last_rxok_cnt;
@@ -793,40 +843,33 @@
 	u64 cur_rxok_cnt = 0;
 	u32 edca_be_ul = 0x5ea42b;
 	u32 edca_be_dl = 0x5ea42b;
-	bool change_edca = false;
+	bool bt_change_edca = false;
 
-	if ((last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) ||
-	    (last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) {
+	if ((last_bt_edca_ul != rtlpriv->btcoexist.bt_edca_ul) ||
+	    (last_bt_edca_dl != rtlpriv->btcoexist.bt_edca_dl)) {
 		rtlpriv->dm.current_turbo_edca = false;
-		last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
-		last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl;
+		last_bt_edca_ul = rtlpriv->btcoexist.bt_edca_ul;
+		last_bt_edca_dl = rtlpriv->btcoexist.bt_edca_dl;
 	}
 
-	if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) {
-		edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
-		change_edca = true;
+	if (rtlpriv->btcoexist.bt_edca_ul != 0) {
+		edca_be_ul = rtlpriv->btcoexist.bt_edca_ul;
+		bt_change_edca = true;
 	}
 
-	if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) {
-		edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl;
-		change_edca = true;
+	if (rtlpriv->btcoexist.bt_edca_dl != 0) {
+		edca_be_ul = rtlpriv->btcoexist.bt_edca_dl;
+		bt_change_edca = true;
 	}
 
 	if (mac->link_state != MAC80211_LINKED) {
 		rtlpriv->dm.current_turbo_edca = false;
 		return;
 	}
+	if ((bt_change_edca) ||
+	    ((!rtlpriv->dm.is_any_nonbepkts) &&
+	     (!rtlpriv->dm.disable_framebursting))) {
 
-	if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) {
-		if (!(edca_be_ul & 0xffff0000))
-			edca_be_ul |= 0x005e0000;
-
-		if (!(edca_be_dl & 0xffff0000))
-			edca_be_dl |= 0x005e0000;
-	}
-
-	if ((change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) &&
-			      (!rtlpriv->dm.disable_framebursting))) {
 		cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
 		cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
 
@@ -851,7 +894,9 @@
 	} else {
 		if (rtlpriv->dm.current_turbo_edca) {
 			u8 tmp = AC0_BE;
-			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_AC_PARAM,
 						      &tmp);
 			rtlpriv->dm.current_turbo_edca = false;
 		}
@@ -862,29 +907,29 @@
 	last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
 }
 
-static void rtl88e_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
-							     *hw)
+static void dm_txpower_track_cb_therm(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	struct rtl_dm	*rtldm = rtl_dm(rtl_priv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	u8 thermalvalue = 0, delta, delta_lck, delta_iqk, off;
-	u8 th_avg_cnt = 0;
+	u8 thermalvalue = 0, delta, delta_lck, delta_iqk, offset;
+	u8 thermalvalue_avg_count = 0;
 	u32 thermalvalue_avg = 0;
 	long  ele_d, temp_cck;
-	char ofdm_index[2], cck_index = 0, ofdm_old[2] = {0, 0}, cck_old = 0;
+	char ofdm_index[2], cck_index = 0,
+		ofdm_index_old[2] = {0, 0}, cck_index_old = 0;
 	int i = 0;
-	bool is2t = false;
+	/*bool is2t = false;*/
 
-	u8 ofdm_min_index = 6, rf = (is2t) ? 2 : 1;
-	u8 index_for_channel;
-	enum _dec_inc {dec, power_inc};
+	u8 ofdm_min_index = 6, rf = 1;
+	/*u8 index_for_channel;*/
+	enum _power_dec_inc {power_dec, power_inc};
 
-	/* 0.1 the following TWO tables decide the final index of
-	 * OFDM/CCK swing table
+	/*0.1 the following TWO tables decide the
+	 *final index of OFDM/CCK swing table
 	 */
-	char del_tbl_idx[2][15] = {
+	char delta_swing_table_idx[2][15]  = {
 		{0, 0, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11},
 		{0, 0, -1, -2, -3, -4, -4, -4, -4, -5, -7, -8, -9, -9, -10}
 	};
@@ -896,9 +941,10 @@
 	/*Initilization (7 steps in total) */
 	rtlpriv->dm.txpower_trackinginit = true;
 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
-		 "rtl88e_dm_txpower_tracking_callback_thermalmeter\n");
+		 "dm_txpower_track_cb_therm\n");
 
-	thermalvalue = (u8) rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0xfc00);
+	thermalvalue = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER,
+					 0xfc00);
 	if (!thermalvalue)
 		return;
 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
@@ -907,55 +953,44 @@
 		 rtlefuse->eeprom_thermalmeter);
 
 	/*1. Query OFDM Default Setting: Path A*/
-	ele_d = rtl_get_bbreg(hw, ROFDM0_XATXIQIMBAL, MASKDWORD) & MASKOFDM_D;
+	ele_d = rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD) &
+			      MASKOFDM_D;
 	for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
 		if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
-			ofdm_old[0] = (u8) i;
-			rtldm->swing_idx_ofdm_base[0] = (u8)i;
+			ofdm_index_old[0] = (u8)i;
+			rtldm->swing_idx_ofdm_base[RF90_PATH_A] = (u8)i;
 			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
 				 "Initial pathA ele_d reg0x%x = 0x%lx, ofdm_index = 0x%x\n",
-				 ROFDM0_XATXIQIMBAL,
-				 ele_d, ofdm_old[0]);
+				 ROFDM0_XATXIQIMBALANCE,
+				 ele_d, ofdm_index_old[0]);
 			break;
 		}
 	}
 
-	if (is2t) {
-		ele_d = rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBAL,
-				      MASKDWORD) & MASKOFDM_D;
-		for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
-			if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
-				ofdm_old[1] = (u8)i;
-
-				RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
-					 DBG_LOUD,
-					 "Initial pathB ele_d reg0x%x = 0x%lx, ofdm_index = 0x%x\n",
-					 ROFDM0_XBTXIQIMBAL, ele_d,
-					 ofdm_old[1]);
-				break;
-			}
-		}
-	}
 	/*2.Query CCK default setting From 0xa24*/
 	temp_cck = rtl_get_bbreg(hw, RCCK0_TXFILTER2, MASKDWORD) & MASKCCK;
 	for (i = 0; i < CCK_TABLE_LENGTH; i++) {
 		if (rtlpriv->dm.cck_inch14) {
 			if (memcmp(&temp_cck, &cck_tbl_ch14[i][2], 4) == 0) {
-				cck_old = (u8)i;
+				cck_index_old = (u8)i;
 				rtldm->swing_idx_cck_base = (u8)i;
-				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
+					 DBG_LOUD,
 					 "Initial reg0x%x = 0x%lx, cck_index = 0x%x, ch 14 %d\n",
-					 RCCK0_TXFILTER2, temp_cck, cck_old,
+					 RCCK0_TXFILTER2, temp_cck,
+					 cck_index_old,
 					 rtlpriv->dm.cck_inch14);
 				break;
 			}
 		} else {
 			if (memcmp(&temp_cck, &cck_tbl_ch1_13[i][2], 4) == 0) {
-				cck_old = (u8)i;
+				cck_index_old = (u8)i;
 				rtldm->swing_idx_cck_base = (u8)i;
-				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
+					 DBG_LOUD,
 					 "Initial reg0x%x = 0x%lx, cck_index = 0x%x, ch14 %d\n",
-					 RCCK0_TXFILTER2, temp_cck, cck_old,
+					 RCCK0_TXFILTER2, temp_cck,
+					 cck_index_old,
 					 rtlpriv->dm.cck_inch14);
 				break;
 			}
@@ -968,8 +1003,8 @@
 		rtlpriv->dm.thermalvalue_lck = thermalvalue;
 		rtlpriv->dm.thermalvalue_iqk = thermalvalue;
 		for (i = 0; i < rf; i++)
-			rtlpriv->dm.ofdm_index[i] = ofdm_old[i];
-		rtlpriv->dm.cck_index = cck_old;
+			rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i];
+		rtlpriv->dm.cck_index = cck_index_old;
 	}
 
 	/*4 Calculate average thermal meter*/
@@ -981,12 +1016,12 @@
 	for (i = 0; i < AVG_THERMAL_NUM_88E; i++) {
 		if (rtldm->thermalvalue_avg[i]) {
 			thermalvalue_avg += rtldm->thermalvalue_avg[i];
-			th_avg_cnt++;
+			thermalvalue_avg_count++;
 		}
 	}
 
-	if (th_avg_cnt)
-		thermalvalue = (u8)(thermalvalue_avg / th_avg_cnt);
+	if (thermalvalue_avg_count)
+		thermalvalue = (u8)(thermalvalue_avg / thermalvalue_avg_count);
 
 	/* 5 Calculate delta, delta_LCK, delta_IQK.*/
 	if (rtlhal->reloadtxpowerindex) {
@@ -997,24 +1032,22 @@
 		rtlpriv->dm.done_txpower = false;
 	} else if (rtlpriv->dm.done_txpower) {
 		delta = (thermalvalue > rtlpriv->dm.thermalvalue) ?
-			(thermalvalue - rtlpriv->dm.thermalvalue) :
-			(rtlpriv->dm.thermalvalue - thermalvalue);
+		    (thermalvalue - rtlpriv->dm.thermalvalue) :
+		    (rtlpriv->dm.thermalvalue - thermalvalue);
 	} else {
 		delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
-			(thermalvalue - rtlefuse->eeprom_thermalmeter) :
-			(rtlefuse->eeprom_thermalmeter - thermalvalue);
+		    (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+		    (rtlefuse->eeprom_thermalmeter - thermalvalue);
 	}
 	delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ?
-		    (thermalvalue - rtlpriv->dm.thermalvalue_lck) :
-		    (rtlpriv->dm.thermalvalue_lck - thermalvalue);
+	    (thermalvalue - rtlpriv->dm.thermalvalue_lck) :
+	    (rtlpriv->dm.thermalvalue_lck - thermalvalue);
 	delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ?
-		    (thermalvalue - rtlpriv->dm.thermalvalue_iqk) :
-		    (rtlpriv->dm.thermalvalue_iqk - thermalvalue);
+	    (thermalvalue - rtlpriv->dm.thermalvalue_iqk) :
+	    (rtlpriv->dm.thermalvalue_iqk - thermalvalue);
 
 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
-		 "Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
-		 "eeprom_thermalmeter 0x%x delta 0x%x "
-		 "delta_lck 0x%x delta_iqk 0x%x\n",
+		 "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x delta 0x%x delta_lck 0x%x delta_iqk 0x%x\n",
 		 thermalvalue, rtlpriv->dm.thermalvalue,
 		 rtlefuse->eeprom_thermalmeter, delta, delta_lck,
 		 delta_iqk);
@@ -1024,28 +1057,35 @@
 		rtl88e_phy_lc_calibrate(hw);
 	}
 
-	/* 7 If necessary, move the index of swing table to adjust Tx power. */
+	/* 7 If necessary, move the index of
+	 * swing table to adjust Tx power.
+	 */
 	if (delta > 0 && rtlpriv->dm.txpower_track_control) {
 		delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
-			(thermalvalue - rtlefuse->eeprom_thermalmeter) :
-			(rtlefuse->eeprom_thermalmeter - thermalvalue);
+		    (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+		    (rtlefuse->eeprom_thermalmeter - thermalvalue);
 
 		/* 7.1 Get the final CCK_index and OFDM_index for each
 		 * swing table.
 		 */
 		if (thermalvalue > rtlefuse->eeprom_thermalmeter) {
-			CAL_SWING_OFF(off, power_inc, IDX_MAP, delta);
+			CAL_SWING_OFF(offset, power_inc, INDEX_MAPPING_NUM,
+				      delta);
 			for (i = 0; i < rf; i++)
-				ofdm_index[i] = rtldm->ofdm_index[i] +
-						del_tbl_idx[power_inc][off];
+				ofdm_index[i] =
+				  rtldm->ofdm_index[i] +
+				  delta_swing_table_idx[power_inc][offset];
 			cck_index = rtldm->cck_index +
-				    del_tbl_idx[power_inc][off];
+				delta_swing_table_idx[power_inc][offset];
 		} else {
-			CAL_SWING_OFF(off, dec, IDX_MAP, delta);
+			CAL_SWING_OFF(offset, power_dec, INDEX_MAPPING_NUM,
+				      delta);
 			for (i = 0; i < rf; i++)
-				ofdm_index[i] = rtldm->ofdm_index[i] +
-						del_tbl_idx[dec][off];
-			cck_index = rtldm->cck_index + del_tbl_idx[dec][off];
+				ofdm_index[i] =
+				  rtldm->ofdm_index[i] +
+				  delta_swing_table_idx[power_dec][offset];
+			cck_index = rtldm->cck_index +
+				delta_swing_table_idx[power_dec][offset];
 		}
 
 		/* 7.2 Handle boundary conditions of index.*/
@@ -1056,8 +1096,8 @@
 				ofdm_index[i] = ofdm_min_index;
 		}
 
-		if (cck_index > CCK_TABLE_SIZE - 1)
-			cck_index = CCK_TABLE_SIZE - 1;
+		if (cck_index > CCK_TABLE_SIZE-1)
+			cck_index = CCK_TABLE_SIZE-1;
 		else if (cck_index < 0)
 			cck_index = 0;
 
@@ -1065,10 +1105,7 @@
 		if (rtlpriv->dm.txpower_track_control) {
 			rtldm->done_txpower = true;
 			rtldm->swing_idx_ofdm[RF90_PATH_A] =
-				 (u8)ofdm_index[RF90_PATH_A];
-			if (is2t)
-				rtldm->swing_idx_ofdm[RF90_PATH_B] =
-					 (u8)ofdm_index[RF90_PATH_B];
+				(u8)ofdm_index[RF90_PATH_A];
 			rtldm->swing_idx_cck = cck_index;
 			if (rtldm->swing_idx_ofdm_cur !=
 			    rtldm->swing_idx_ofdm[0]) {
@@ -1082,12 +1119,7 @@
 				rtldm->swing_flag_cck = true;
 			}
 
-			rtl88e_chk_tx_track(hw, TXAGC, 0, 0);
-
-			if (is2t)
-				rtl88e_chk_tx_track(hw, BBSWING,
-						    RF90_PATH_B,
-						    index_for_channel);
+			dm_tx_pwr_track_set_pwr(hw, TXAGC, 0, 0);
 		}
 	}
 
@@ -1115,7 +1147,7 @@
 	rtlpriv->dm.swing_idx_ofdm_cur = 12;
 	rtlpriv->dm.swing_flag_ofdm = false;
 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
-		 "  rtlpriv->dm.txpower_tracking = %d\n",
+		 "rtlpriv->dm.txpower_tracking = %d\n",
 		 rtlpriv->dm.txpower_tracking);
 }
 
@@ -1137,7 +1169,7 @@
 	} else {
 		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
 			 "Schedule TxPowerTracking !!\n");
-		rtl88e_dm_txpower_tracking_callback_thermalmeter(hw);
+				dm_txpower_track_cb_therm(hw);
 		tm_trigger = 0;
 	}
 }
@@ -1145,7 +1177,7 @@
 void rtl88e_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rate_adaptive *p_ra = &(rtlpriv->ra);
+	struct rate_adaptive *p_ra = &rtlpriv->ra;
 
 	p_ra->ratr_state = DM_RATR_STA_INIT;
 	p_ra->pre_ratr_state = DM_RATR_STA_INIT;
@@ -1161,9 +1193,9 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	struct rate_adaptive *p_ra = &(rtlpriv->ra);
+	struct rate_adaptive *p_ra = &rtlpriv->ra;
+	u32 low_rssithresh_for_ra, high_rssithresh_for_ra;
 	struct ieee80211_sta *sta = NULL;
-	u32 low_rssi, hi_rssi;
 
 	if (is_hal_stop(rtlhal)) {
 		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
@@ -1181,26 +1213,28 @@
 	    mac->opmode == NL80211_IFTYPE_STATION) {
 		switch (p_ra->pre_ratr_state) {
 		case DM_RATR_STA_HIGH:
-			hi_rssi = 50;
-			low_rssi = 20;
+			high_rssithresh_for_ra = 50;
+			low_rssithresh_for_ra = 20;
 			break;
 		case DM_RATR_STA_MIDDLE:
-			hi_rssi = 55;
-			low_rssi = 20;
+			high_rssithresh_for_ra = 55;
+			low_rssithresh_for_ra = 20;
 			break;
 		case DM_RATR_STA_LOW:
-			hi_rssi = 50;
-			low_rssi = 25;
+			high_rssithresh_for_ra = 50;
+			low_rssithresh_for_ra = 25;
 			break;
 		default:
-			hi_rssi = 50;
-			low_rssi = 20;
+			high_rssithresh_for_ra = 50;
+			low_rssithresh_for_ra = 20;
 			break;
 		}
 
-		if (rtlpriv->dm.undec_sm_pwdb > (long)hi_rssi)
+		if (rtlpriv->dm.undec_sm_pwdb >
+		    (long)high_rssithresh_for_ra)
 			p_ra->ratr_state = DM_RATR_STA_HIGH;
-		else if (rtlpriv->dm.undec_sm_pwdb > (long)low_rssi)
+		else if (rtlpriv->dm.undec_sm_pwdb >
+			 (long)low_rssithresh_for_ra)
 			p_ra->ratr_state = DM_RATR_STA_MIDDLE;
 		else
 			p_ra->ratr_state = DM_RATR_STA_LOW;
@@ -1208,7 +1242,7 @@
 		if (p_ra->pre_ratr_state != p_ra->ratr_state) {
 			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
 				 "RSSI = %ld\n",
-				 rtlpriv->dm.undec_sm_pwdb);
+				  rtlpriv->dm.undec_sm_pwdb);
 			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
 				 "RSSI_LEVEL = %d\n", p_ra->ratr_state);
 			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
@@ -1219,7 +1253,7 @@
 			sta = rtl_find_sta(hw, mac->bssid);
 			if (sta)
 				rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
-						   p_ra->ratr_state);
+								   p_ra->ratr_state);
 			rcu_read_unlock();
 
 			p_ra->pre_ratr_state = p_ra->ratr_state;
@@ -1239,56 +1273,62 @@
 	dm_pstable->rssi_val_min = 0;
 }
 
-static void rtl88e_dm_update_rx_idle_ant(struct ieee80211_hw *hw, u8 ant)
+static void rtl88e_dm_update_rx_idle_ant(struct ieee80211_hw *hw,
+					 u8 ant)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
-	struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
-	u32 def_ant, opt_ant;
+	struct fast_ant_training *pfat_table = &rtldm->fat_table;
+	u32 default_ant, optional_ant;
 
-	if (fat_tbl->rx_idle_ant != ant) {
+	if (pfat_table->rx_idle_ant != ant) {
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 			 "need to update rx idle ant\n");
 		if (ant == MAIN_ANT) {
-			def_ant = (fat_tbl->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
-				   MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX;
-			opt_ant = (fat_tbl->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
-				   AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX;
+			default_ant =
+			  (pfat_table->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
+			  MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX;
+			optional_ant =
+			  (pfat_table->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
+			  AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX;
 		} else {
-			def_ant = (fat_tbl->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
-				   AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX;
-			opt_ant = (fat_tbl->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
-				   MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX;
+			default_ant =
+			   (pfat_table->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
+			   AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX;
+			optional_ant =
+			   (pfat_table->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
+			   MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX;
 		}
 
 		if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) {
-			rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(5) |
-				      BIT(4) | BIT(3), def_ant);
-			rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(8) |
-				      BIT(7) | BIT(6), opt_ant);
-			rtl_set_bbreg(hw, DM_REG_ANTSEL_CTRL_11N, BIT(14) |
-				      BIT(13) | BIT(12), def_ant);
-			rtl_set_bbreg(hw, DM_REG_RESP_TX_11N, BIT(6) | BIT(7),
-				      def_ant);
+			rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N,
+				      BIT(5) | BIT(4) | BIT(3), default_ant);
+			rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N,
+				      BIT(8) | BIT(7) | BIT(6), optional_ant);
+			rtl_set_bbreg(hw, DM_REG_ANTSEL_CTRL_11N,
+				      BIT(14) | BIT(13) | BIT(12),
+				      default_ant);
+			rtl_set_bbreg(hw, DM_REG_RESP_TX_11N,
+				      BIT(6) | BIT(7), default_ant);
 		} else if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) {
-			rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(5) |
-				      BIT(4) | BIT(3), def_ant);
-			rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(8) |
-				      BIT(7) | BIT(6), opt_ant);
+			rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N,
+				      BIT(5) | BIT(4) | BIT(3), default_ant);
+			rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N,
+				      BIT(8) | BIT(7) | BIT(6), optional_ant);
 		}
 	}
-	fat_tbl->rx_idle_ant = ant;
+	pfat_table->rx_idle_ant = ant;
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "RxIdleAnt %s\n",
-		 ((ant == MAIN_ANT) ? ("MAIN_ANT") : ("AUX_ANT")));
+		 (ant == MAIN_ANT) ? ("MAIN_ANT") : ("AUX_ANT"));
 }
 
 static void rtl88e_dm_update_tx_ant(struct ieee80211_hw *hw,
-	u8 ant, u32 mac_id)
+				    u8 ant, u32 mac_id)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
-	struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+	struct fast_ant_training *pfat_table = &rtldm->fat_table;
 	u8 target_ant;
 
 	if (ant == MAIN_ANT)
@@ -1296,23 +1336,25 @@
 	else
 		target_ant = AUX_ANT_CG_TRX;
 
-	fat_tbl->antsel_a[mac_id] = target_ant & BIT(0);
-	fat_tbl->antsel_b[mac_id] = (target_ant & BIT(1)) >> 1;
-	fat_tbl->antsel_c[mac_id] = (target_ant & BIT(2)) >> 2;
+	pfat_table->antsel_a[mac_id] = target_ant & BIT(0);
+	pfat_table->antsel_b[mac_id] = (target_ant & BIT(1)) >> 1;
+	pfat_table->antsel_c[mac_id] = (target_ant & BIT(2)) >> 2;
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "txfrominfo target ant %s\n",
-		 ((ant == MAIN_ANT) ? ("MAIN_ANT") : ("AUX_ANT")));
+		(ant == MAIN_ANT) ? ("MAIN_ANT") : ("AUX_ANT"));
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "antsel_tr_mux = 3'b%d%d%d\n",
-		 fat_tbl->antsel_c[mac_id],
-		 fat_tbl->antsel_b[mac_id], fat_tbl->antsel_a[mac_id]);
+		pfat_table->antsel_c[mac_id],
+		pfat_table->antsel_b[mac_id],
+		pfat_table->antsel_a[mac_id]);
 }
 
 static void rtl88e_dm_rx_hw_antena_div_init(struct ieee80211_hw *hw)
 {
 	u32  value32;
+
 	/*MAC Setting*/
 	value32 = rtl_get_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD);
-	rtl_set_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD, value32 |
-		     (BIT(23) | BIT(25)));
+	rtl_set_bbreg(hw, DM_REG_ANTSEL_PIN_11N,
+		      MASKDWORD, value32 | (BIT(23) | BIT(25)));
 	/*Pin Setting*/
 	rtl_set_bbreg(hw, DM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);
 	rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(10), 0);
@@ -1333,8 +1375,8 @@
 
 	/*MAC Setting*/
 	value32 = rtl_get_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD);
-	rtl_set_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD, value32 |
-		     (BIT(23) | BIT(25)));
+	rtl_set_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD,
+		      value32 | (BIT(23) | BIT(25)));
 	/*Pin Setting*/
 	rtl_set_bbreg(hw, DM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);
 	rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(10), 0);
@@ -1354,28 +1396,30 @@
 static void rtl88e_dm_fast_training_init(struct ieee80211_hw *hw)
 {
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
-	struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
-	u32 ant_combo = 2;
+	struct fast_ant_training *pfat_table = &rtldm->fat_table;
+	u32 ant_combination = 2;
 	u32 value32, i;
 
 	for (i = 0; i < 6; i++) {
-		fat_tbl->bssid[i] = 0;
-		fat_tbl->ant_sum[i] = 0;
-		fat_tbl->ant_cnt[i] = 0;
-		fat_tbl->ant_ave[i] = 0;
+		pfat_table->bssid[i] = 0;
+		pfat_table->ant_sum[i] = 0;
+		pfat_table->ant_cnt[i] = 0;
+		pfat_table->ant_ave[i] = 0;
 	}
-	fat_tbl->train_idx = 0;
-	fat_tbl->fat_state = FAT_NORMAL_STATE;
+	pfat_table->train_idx = 0;
+	pfat_table->fat_state = FAT_NORMAL_STATE;
 
 	/*MAC Setting*/
 	value32 = rtl_get_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD);
-	rtl_set_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD, value32 | (BIT(23) |
-		      BIT(25)));
-	value32 = rtl_get_bbreg(hw, DM_REG_ANT_TRAIN_2, MASKDWORD);
-	rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_2, MASKDWORD, value32 | (BIT(16) |
-		      BIT(17)));
-	rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_2, MASKLWORD, 0);
-	rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_1, MASKDWORD, 0);
+	rtl_set_bbreg(hw, DM_REG_ANTSEL_PIN_11N,
+		      MASKDWORD, value32 | (BIT(23) | BIT(25)));
+	value32 = rtl_get_bbreg(hw, DM_REG_ANT_TRAIN_PARA2_11N, MASKDWORD);
+	rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_PARA2_11N,
+		      MASKDWORD, value32 | (BIT(16) | BIT(17)));
+	rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_PARA2_11N,
+		      MASKLWORD, 0);
+	rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_PARA1_11N,
+		      MASKDWORD, 0);
 
 	/*Pin Setting*/
 	rtl_set_bbreg(hw, DM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);
@@ -1386,26 +1430,17 @@
 	/*OFDM Setting*/
 	rtl_set_bbreg(hw, DM_REG_ANTDIV_PARA1_11N, MASKDWORD, 0x000000a0);
 	/*antenna mapping table*/
-	if (ant_combo == 2) {
-		rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE0, 1);
-		rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE1, 2);
-	} else if (ant_combo == 7) {
-		rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE0, 1);
-		rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE1, 2);
-		rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE2, 2);
-		rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE3, 3);
-		rtl_set_bbreg(hw, DM_REG_ANT_MAPPING2_11N, MASKBYTE0, 4);
-		rtl_set_bbreg(hw, DM_REG_ANT_MAPPING2_11N, MASKBYTE1, 5);
-		rtl_set_bbreg(hw, DM_REG_ANT_MAPPING2_11N, MASKBYTE2, 6);
-		rtl_set_bbreg(hw, DM_REG_ANT_MAPPING2_11N, MASKBYTE3, 7);
-	}
+	rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE0, 1);
+	rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE1, 2);
 
 	/*TX Setting*/
 	rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N, BIT(21), 1);
-	rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(5) | BIT(4) | BIT(3), 0);
-	rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(8) | BIT(7) | BIT(6), 1);
-	rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(2) | BIT(1) | BIT(0),
-		      (ant_combo - 1));
+	rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N,
+		      BIT(5) | BIT(4) | BIT(3), 0);
+	rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N,
+		      BIT(8) | BIT(7) | BIT(6), 1);
+	rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N,
+		      BIT(2) | BIT(1) | BIT(0), (ant_combination - 1));
 
 	rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 1);
 }
@@ -1420,6 +1455,7 @@
 		rtl88e_dm_trx_hw_antenna_div_init(hw);
 	else if (rtlefuse->antenna_div_type == CG_TRX_SMART_ANTDIV)
 		rtl88e_dm_fast_training_init(hw);
+
 }
 
 void rtl88e_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw,
@@ -1427,38 +1463,39 @@
 {
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
-	struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+	struct fast_ant_training *pfat_table = &rtldm->fat_table;
 
 	if ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) ||
-	    (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)) {
-		SET_TX_DESC_ANTSEL_A(pdesc, fat_tbl->antsel_a[mac_id]);
-		SET_TX_DESC_ANTSEL_B(pdesc, fat_tbl->antsel_b[mac_id]);
-		SET_TX_DESC_ANTSEL_C(pdesc, fat_tbl->antsel_c[mac_id]);
+	    (rtlefuse->antenna_div_type == CG_TRX_SMART_ANTDIV)) {
+		SET_TX_DESC_ANTSEL_A(pdesc, pfat_table->antsel_a[mac_id]);
+		SET_TX_DESC_ANTSEL_B(pdesc, pfat_table->antsel_b[mac_id]);
+		SET_TX_DESC_ANTSEL_C(pdesc, pfat_table->antsel_c[mac_id]);
 	}
 }
 
 void rtl88e_dm_ant_sel_statistics(struct ieee80211_hw *hw,
-				  u8 antsel_tr_mux, u32 mac_id, u32 rx_pwdb_all)
+				  u8 antsel_tr_mux, u32 mac_id,
+				  u32 rx_pwdb_all)
 {
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
-	struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+	struct fast_ant_training *pfat_table = &rtldm->fat_table;
 
 	if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) {
 		if (antsel_tr_mux == MAIN_ANT_CG_TRX) {
-			fat_tbl->main_ant_sum[mac_id] += rx_pwdb_all;
-			fat_tbl->main_ant_cnt[mac_id]++;
+			pfat_table->main_ant_sum[mac_id] += rx_pwdb_all;
+			pfat_table->main_ant_cnt[mac_id]++;
 		} else {
-			fat_tbl->aux_ant_sum[mac_id] += rx_pwdb_all;
-			fat_tbl->aux_ant_cnt[mac_id]++;
+			pfat_table->aux_ant_sum[mac_id] += rx_pwdb_all;
+			pfat_table->aux_ant_cnt[mac_id]++;
 		}
 	} else if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) {
 		if (antsel_tr_mux == MAIN_ANT_CGCS_RX) {
-			fat_tbl->main_ant_sum[mac_id] += rx_pwdb_all;
-			fat_tbl->main_ant_cnt[mac_id]++;
+			pfat_table->main_ant_sum[mac_id] += rx_pwdb_all;
+			pfat_table->main_ant_cnt[mac_id]++;
 		} else {
-			fat_tbl->aux_ant_sum[mac_id] += rx_pwdb_all;
-			fat_tbl->aux_ant_cnt[mac_id]++;
+			pfat_table->aux_ant_sum[mac_id] += rx_pwdb_all;
+			pfat_table->aux_ant_cnt[mac_id]++;
 		}
 	}
 }
@@ -1466,43 +1503,43 @@
 static void rtl88e_dm_hw_ant_div(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
 	struct rtl_sta_info *drv_priv;
-	struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
-	u32 i, min_rssi = 0xff, ant_div_max_rssi = 0, max_rssi = 0;
-	u32 local_min_rssi, local_max_rssi;
+	struct fast_ant_training *pfat_table = &rtldm->fat_table;
+	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+	u32 i, min_rssi = 0xff, ant_div_max_rssi = 0;
+	u32 max_rssi = 0, local_min_rssi, local_max_rssi;
 	u32 main_rssi, aux_rssi;
 	u8 rx_idle_ant = 0, target_ant = 7;
 
+	/*for sta its self*/
 	i = 0;
-	main_rssi = (fat_tbl->main_ant_cnt[i] != 0) ?
-		    (fat_tbl->main_ant_sum[i] /
-		     fat_tbl->main_ant_cnt[i]) : 0;
-	aux_rssi = (fat_tbl->aux_ant_cnt[i] != 0) ?
-		(fat_tbl->aux_ant_sum[i] / fat_tbl->aux_ant_cnt[i]) : 0;
+	main_rssi = (pfat_table->main_ant_cnt[i] != 0) ?
+		(pfat_table->main_ant_sum[i] / pfat_table->main_ant_cnt[i]) : 0;
+	aux_rssi = (pfat_table->aux_ant_cnt[i] != 0) ?
+		(pfat_table->aux_ant_sum[i] / pfat_table->aux_ant_cnt[i]) : 0;
 	target_ant = (main_rssi == aux_rssi) ?
-		     fat_tbl->rx_idle_ant : ((main_rssi >= aux_rssi) ?
-		     MAIN_ANT : AUX_ANT);
+		pfat_table->rx_idle_ant : ((main_rssi >= aux_rssi) ?
+		MAIN_ANT : AUX_ANT);
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-		 "main_ant_sum %d main_ant_cnt %d\n",
-		 fat_tbl->main_ant_sum[i], fat_tbl->main_ant_cnt[i]);
+		"main_ant_sum %d main_ant_cnt %d\n",
+		pfat_table->main_ant_sum[i],
+		pfat_table->main_ant_cnt[i]);
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 		 "aux_ant_sum %d aux_ant_cnt %d\n",
-		 fat_tbl->aux_ant_sum[i],
-		 fat_tbl->aux_ant_cnt[i]);
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-		 "main_rssi %d aux_rssi%d\n", main_rssi, aux_rssi);
+		 pfat_table->aux_ant_sum[i], pfat_table->aux_ant_cnt[i]);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "main_rssi %d aux_rssi%d\n",
+		 main_rssi, aux_rssi);
 	local_max_rssi = (main_rssi > aux_rssi) ? main_rssi : aux_rssi;
 	if ((local_max_rssi > ant_div_max_rssi) && (local_max_rssi < 40))
 		ant_div_max_rssi = local_max_rssi;
 	if (local_max_rssi > max_rssi)
 		max_rssi = local_max_rssi;
 
-	if ((fat_tbl->rx_idle_ant == MAIN_ANT) && (main_rssi == 0))
+	if ((pfat_table->rx_idle_ant == MAIN_ANT) && (main_rssi == 0))
 		main_rssi = aux_rssi;
-	else if ((fat_tbl->rx_idle_ant == AUX_ANT) && (aux_rssi == 0))
+	else if ((pfat_table->rx_idle_ant == AUX_ANT) && (aux_rssi == 0))
 		aux_rssi = main_rssi;
 
 	local_min_rssi = (main_rssi > aux_rssi) ? aux_rssi : main_rssi;
@@ -1518,32 +1555,33 @@
 		spin_lock_bh(&rtlpriv->locks.entry_list_lock);
 		list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
 			i++;
-			main_rssi = (fat_tbl->main_ant_cnt[i] != 0) ?
-				(fat_tbl->main_ant_sum[i] /
-				 fat_tbl->main_ant_cnt[i]) : 0;
-			aux_rssi = (fat_tbl->aux_ant_cnt[i] != 0) ?
-				   (fat_tbl->aux_ant_sum[i] /
-				    fat_tbl->aux_ant_cnt[i]) : 0;
+			main_rssi = (pfat_table->main_ant_cnt[i] != 0) ?
+				(pfat_table->main_ant_sum[i] /
+				pfat_table->main_ant_cnt[i]) : 0;
+			aux_rssi = (pfat_table->aux_ant_cnt[i] != 0) ?
+				(pfat_table->aux_ant_sum[i] /
+				pfat_table->aux_ant_cnt[i]) : 0;
 			target_ant = (main_rssi == aux_rssi) ?
-				      fat_tbl->rx_idle_ant : ((main_rssi >=
-				      aux_rssi) ? MAIN_ANT : AUX_ANT);
+				pfat_table->rx_idle_ant : ((main_rssi >=
+				aux_rssi) ? MAIN_ANT : AUX_ANT);
 
-
-			local_max_rssi = max_t(u32, main_rssi, aux_rssi);
+			local_max_rssi = (main_rssi > aux_rssi) ?
+					 main_rssi : aux_rssi;
 			if ((local_max_rssi > ant_div_max_rssi) &&
 			    (local_max_rssi < 40))
 				ant_div_max_rssi = local_max_rssi;
 			if (local_max_rssi > max_rssi)
 				max_rssi = local_max_rssi;
 
-			if ((fat_tbl->rx_idle_ant == MAIN_ANT) && !main_rssi)
+			if ((pfat_table->rx_idle_ant == MAIN_ANT) &&
+			    (main_rssi == 0))
 				main_rssi = aux_rssi;
-			else if ((fat_tbl->rx_idle_ant == AUX_ANT) &&
+			else if ((pfat_table->rx_idle_ant == AUX_ANT) &&
 				 (aux_rssi == 0))
 				aux_rssi = main_rssi;
 
 			local_min_rssi = (main_rssi > aux_rssi) ?
-					  aux_rssi : main_rssi;
+				aux_rssi : main_rssi;
 			if (local_min_rssi < min_rssi) {
 				min_rssi = local_min_rssi;
 				rx_idle_ant = target_ant;
@@ -1555,10 +1593,10 @@
 	}
 
 	for (i = 0; i < ASSOCIATE_ENTRY_NUM; i++) {
-		fat_tbl->main_ant_sum[i] = 0;
-		fat_tbl->aux_ant_sum[i] = 0;
-		fat_tbl->main_ant_cnt[i] = 0;
-		fat_tbl->aux_ant_cnt[i] = 0;
+		pfat_table->main_ant_sum[i] = 0;
+		pfat_table->aux_ant_sum[i] = 0;
+		pfat_table->main_ant_cnt[i] = 0;
+		pfat_table->aux_ant_cnt[i] = 0;
 	}
 
 	rtl88e_dm_update_rx_idle_ant(hw, rx_idle_ant);
@@ -1573,27 +1611,27 @@
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
 	struct rtl_sta_info *drv_priv;
-	struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+	struct fast_ant_training *pfat_table = &rtldm->fat_table;
 	u32 value32, i, j = 0;
 
 	if (mac->link_state >= MAC80211_LINKED) {
 		for (i = 0; i < ASSOCIATE_ENTRY_NUM; i++) {
-			if ((fat_tbl->train_idx + 1) == ASSOCIATE_ENTRY_NUM)
-				fat_tbl->train_idx = 0;
+			if ((pfat_table->train_idx + 1) == ASSOCIATE_ENTRY_NUM)
+				pfat_table->train_idx = 0;
 			else
-				fat_tbl->train_idx++;
+				pfat_table->train_idx++;
 
-			if (fat_tbl->train_idx == 0) {
+			if (pfat_table->train_idx == 0) {
 				value32 = (mac->mac_addr[5] << 8) |
-					   mac->mac_addr[4];
-				rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_2,
+					  mac->mac_addr[4];
+				rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_PARA2_11N,
 					      MASKLWORD, value32);
 
 				value32 = (mac->mac_addr[3] << 24) |
 					  (mac->mac_addr[2] << 16) |
 					  (mac->mac_addr[1] << 8) |
-					   mac->mac_addr[0];
-				rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_1,
+					  mac->mac_addr[0];
+				rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_PARA1_11N,
 					      MASKDWORD, value32);
 				break;
 			}
@@ -1602,28 +1640,29 @@
 			    NL80211_IFTYPE_STATION) {
 				spin_lock_bh(&rtlpriv->locks.entry_list_lock);
 				list_for_each_entry(drv_priv,
-						    &rtlpriv->entry_list,
-						    list) {
+						    &rtlpriv->entry_list, list) {
 					j++;
-					if (j != fat_tbl->train_idx)
+					if (j != pfat_table->train_idx)
 						continue;
 
 					value32 = (drv_priv->mac_addr[5] << 8) |
-						   drv_priv->mac_addr[4];
-					rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_2,
+						  drv_priv->mac_addr[4];
+					rtl_set_bbreg(hw,
+						      DM_REG_ANT_TRAIN_PARA2_11N,
 						      MASKLWORD, value32);
 
-					value32 = (drv_priv->mac_addr[3]<<24) |
-						  (drv_priv->mac_addr[2]<<16) |
-						  (drv_priv->mac_addr[1]<<8) |
-						   drv_priv->mac_addr[0];
-					rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_1,
+					value32 = (drv_priv->mac_addr[3] << 24) |
+						  (drv_priv->mac_addr[2] << 16) |
+						  (drv_priv->mac_addr[1] << 8) |
+						  drv_priv->mac_addr[0];
+					rtl_set_bbreg(hw,
+						      DM_REG_ANT_TRAIN_PARA1_11N,
 						      MASKDWORD, value32);
 					break;
 				}
 				spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
 				/*find entry, break*/
-				if (j == fat_tbl->train_idx)
+				if (j == pfat_table->train_idx)
 					break;
 			}
 		}
@@ -1634,23 +1673,24 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
-	struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+	struct fast_ant_training *pfat_table = &rtldm->fat_table;
 	u32 i, max_rssi = 0;
 	u8 target_ant = 2;
 	bool bpkt_filter_match = false;
 
-	if (fat_tbl->fat_state == FAT_TRAINING_STATE) {
+	if (pfat_table->fat_state == FAT_TRAINING_STATE) {
 		for (i = 0; i < 7; i++) {
-			if (fat_tbl->ant_cnt[i] == 0) {
-				fat_tbl->ant_ave[i] = 0;
+			if (pfat_table->ant_cnt[i] == 0) {
+				pfat_table->ant_ave[i] = 0;
 			} else {
-				fat_tbl->ant_ave[i] = fat_tbl->ant_sum[i] /
-					fat_tbl->ant_cnt[i];
+				pfat_table->ant_ave[i] =
+					pfat_table->ant_sum[i] /
+					pfat_table->ant_cnt[i];
 				bpkt_filter_match = true;
 			}
 
-			if (fat_tbl->ant_ave[i] > max_rssi) {
-				max_rssi = fat_tbl->ant_ave[i];
+			if (pfat_table->ant_ave[i] > max_rssi) {
+				max_rssi = pfat_table->ant_ave[i];
 				target_ant = (u8) i;
 			}
 		}
@@ -1664,32 +1704,33 @@
 				      BIT(16), 0);
 			rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(8) |
 				      BIT(7) | BIT(6), target_ant);
-			rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N, BIT(21), 1);
+			rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N,
+				      BIT(21), 1);
 
-			fat_tbl->antsel_a[fat_tbl->train_idx] =
-				  target_ant & BIT(0);
-			fat_tbl->antsel_b[fat_tbl->train_idx] =
-				 (target_ant & BIT(1)) >> 1;
-			fat_tbl->antsel_c[fat_tbl->train_idx] =
-				 (target_ant & BIT(2)) >> 2;
+			pfat_table->antsel_a[pfat_table->train_idx] =
+				target_ant & BIT(0);
+			pfat_table->antsel_b[pfat_table->train_idx] =
+				(target_ant & BIT(1)) >> 1;
+			pfat_table->antsel_c[pfat_table->train_idx] =
+				(target_ant & BIT(2)) >> 2;
 
 			if (target_ant == 0)
 				rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 0);
 		}
 
 		for (i = 0; i < 7; i++) {
-			fat_tbl->ant_sum[i] = 0;
-			fat_tbl->ant_cnt[i] = 0;
+			pfat_table->ant_sum[i] = 0;
+			pfat_table->ant_cnt[i] = 0;
 		}
 
-		fat_tbl->fat_state = FAT_NORMAL_STATE;
+		pfat_table->fat_state = FAT_NORMAL_STATE;
 		return;
 	}
 
-	if (fat_tbl->fat_state == FAT_NORMAL_STATE) {
+	if (pfat_table->fat_state == FAT_NORMAL_STATE) {
 		rtl88e_set_next_mac_address_target(hw);
 
-		fat_tbl->fat_state = FAT_TRAINING_STATE;
+		pfat_table->fat_state = FAT_TRAINING_STATE;
 		rtl_set_bbreg(hw, DM_REG_TXAGC_A_1_MCS32_11N, BIT(16), 1);
 		rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 1);
 
@@ -1711,11 +1752,11 @@
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
-	struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+	struct fast_ant_training *pfat_table = &rtldm->fat_table;
 
 	if (mac->link_state < MAC80211_LINKED) {
 		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "No Link\n");
-		if (fat_tbl->becomelinked == true) {
+		if (pfat_table->becomelinked) {
 			RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
 				 "need to turn off HW AntDiv\n");
 			rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 0);
@@ -1724,12 +1765,13 @@
 			if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
 				rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N,
 					      BIT(21), 0);
-			fat_tbl->becomelinked =
-			  (mac->link_state == MAC80211_LINKED) ? true : false;
+			pfat_table->becomelinked =
+				(mac->link_state == MAC80211_LINKED) ?
+				true : false;
 		}
 		return;
 	} else {
-		if (fat_tbl->becomelinked == false) {
+		if (!pfat_table->becomelinked) {
 			RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
 				 "Need to turn on HW AntDiv\n");
 			rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 1);
@@ -1738,8 +1780,9 @@
 			if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
 				rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N,
 					      BIT(21), 1);
-			fat_tbl->becomelinked =
-			   (mac->link_state >= MAC80211_LINKED) ? true : false;
+			pfat_table->becomelinked =
+				(mac->link_state >= MAC80211_LINKED) ?
+				true : false;
 		}
 	}
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h
index 0e07f72..64f1f3e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h
@@ -156,7 +156,6 @@
 #define	DM_REG_SLEEP_11N				0xEE0
 #define	DM_REG_PMPD_ANAEN_11N				0xEEC
 
-
 /*MAC REG LIST*/
 #define	DM_REG_BB_RST_11N				0x02
 #define	DM_REG_ANTSEL_PIN_11N				0x4C
@@ -168,8 +167,9 @@
 #define	DM_REG_EDCA_BK_11N				0x50C
 #define	DM_REG_TXPAUSE_11N				0x522
 #define	DM_REG_RESP_TX_11N				0x6D8
-#define	DM_REG_ANT_TRAIN_1				0x7b0
-#define	DM_REG_ANT_TRAIN_2				0x7b4
+#define	DM_REG_ANT_TRAIN_PARA1_11N			0x7b0
+#define	DM_REG_ANT_TRAIN_PARA2_11N			0x7b4
+
 
 /*DIG Related*/
 #define	DM_BIT_IGI_11N					0x0000007F
@@ -208,7 +208,7 @@
 #define DM_DIG_BACKOFF_MIN				-4
 #define DM_DIG_BACKOFF_DEFAULT				10
 
-#define RXPATHSELECTION_SS_TH_LOW			30
+#define RXPATHSELECTION_SS_TH_W				30
 #define RXPATHSELECTION_DIFF_TH				18
 
 #define DM_RATR_STA_INIT				0
@@ -232,20 +232,22 @@
 
 #define TX_POWER_NEAR_FIELD_THRESH_LVL2			74
 #define TX_POWER_NEAR_FIELD_THRESH_LVL1			67
-#define TXPWRTRACK_MAX_IDX				6
+#define TXPWRTRACK_MAX_IDX				 6
 
 struct swat_t {
 	u8 failure_cnt;
 	u8 try_flag;
 	u8 stop_trying;
+
 	long pre_rssi;
 	long trying_threshold;
 	u8 cur_antenna;
 	u8 pre_antenna;
+
 };
 
 enum FAT_STATE {
-	FAT_NORMAL_STATE	= 0,
+	FAT_NORMAL_STATE = 0,
 	FAT_TRAINING_STATE = 1,
 };
 
@@ -310,8 +312,9 @@
 
 void rtl88e_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw,
 				     u8 *pdesc, u32 mac_id);
-void rtl88e_dm_ant_sel_statistics(struct ieee80211_hw *hw, u8 antsel_tr_mux,
-				  u32 mac_id, u32 rx_pwdb_all);
+void rtl88e_dm_ant_sel_statistics(struct ieee80211_hw *hw,
+				  u8 antsel_tr_mux, u32 mac_id,
+				  u32 rx_pwdb_all);
 void rtl88e_dm_fast_antenna_training_callback(unsigned long data);
 void rtl88e_dm_init(struct ieee80211_hw *hw);
 void rtl88e_dm_watchdog(struct ieee80211_hw *hw);
@@ -320,7 +323,5 @@
 void rtl88e_dm_check_txpower_tracking(struct ieee80211_hw *hw);
 void rtl88e_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
 void rtl88e_dm_txpower_track_adjust(struct ieee80211_hw *hw,
-				    u8 type, u8 *pdirection,
-				    u32 *poutwrite_val);
-
+	u8 type, u8 *pdirection, u32 *poutwrite_val);
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
index 4f9376a..c8058aa 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,12 +26,11 @@
 #include "../wifi.h"
 #include "../pci.h"
 #include "../base.h"
+#include "../core.h"
 #include "reg.h"
 #include "def.h"
 #include "fw.h"
 
-#include <linux/kmemleak.h>
-
 static void _rtl88e_enable_fw_download(struct ieee80211_hw *hw, bool enable)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -62,26 +57,26 @@
 				   const u8 *buffer, u32 size)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 blk_sz = sizeof(u32);
-	u8 *buf_ptr = (u8 *)buffer;
+	u32 blocksize = sizeof(u32);
+	u8 *bufferptr = (u8 *)buffer;
 	u32 *pu4BytePtr = (u32 *)buffer;
-	u32 i, offset, blk_cnt, remain;
+	u32 i, offset, blockcount, remainsize;
 
-	blk_cnt = size / blk_sz;
-	remain = size % blk_sz;
+	blockcount = size / blocksize;
+	remainsize = size % blocksize;
 
-	for (i = 0; i < blk_cnt; i++) {
-		offset = i * blk_sz;
+	for (i = 0; i < blockcount; i++) {
+		offset = i * blocksize;
 		rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
 				*(pu4BytePtr + i));
 	}
 
-	if (remain) {
-		offset = blk_cnt * blk_sz;
-		buf_ptr += offset;
-		for (i = 0; i < remain; i++) {
+	if (remainsize) {
+		offset = blockcount * blocksize;
+		bufferptr += offset;
+		for (i = 0; i < remainsize; i++) {
 			rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
-						 offset + i), *(buf_ptr + i));
+						 offset + i), *(bufferptr + i));
 		}
 	}
 }
@@ -119,32 +114,33 @@
 			     enum version_8188e version, u8 *buffer, u32 size)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u8 *buf_ptr = buffer;
-	u32 page_no, remain;
+	u8 *bufferptr = (u8 *)buffer;
+	u32 pagenums, remainsize;
 	u32 page, offset;
 
 	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
 
-	_rtl88e_fill_dummy(buf_ptr, &size);
+	_rtl88e_fill_dummy(bufferptr, &size);
 
-	page_no = size / FW_8192C_PAGE_SIZE;
-	remain = size % FW_8192C_PAGE_SIZE;
+	pagenums = size / FW_8192C_PAGE_SIZE;
+	remainsize = size % FW_8192C_PAGE_SIZE;
 
-	if (page_no > 8) {
+	if (pagenums > 8) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 "Page numbers should not greater then 8\n");
 	}
 
-	for (page = 0; page < page_no; page++) {
+	for (page = 0; page < pagenums; page++) {
 		offset = page * FW_8192C_PAGE_SIZE;
-		_rtl88e_fw_page_write(hw, page, (buf_ptr + offset),
+		_rtl88e_fw_page_write(hw, page, (bufferptr + offset),
 				      FW_8192C_PAGE_SIZE);
 	}
 
-	if (remain) {
-		offset = page_no * FW_8192C_PAGE_SIZE;
-		page = page_no;
-		_rtl88e_fw_page_write(hw, page, (buf_ptr + offset), remain);
+	if (remainsize) {
+		offset = pagenums * FW_8192C_PAGE_SIZE;
+		page = pagenums;
+		_rtl88e_fw_page_write(hw, page, (bufferptr + offset),
+				      remainsize);
 	}
 }
 
@@ -199,7 +195,8 @@
 	return err;
 }
 
-int rtl88e_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
+int rtl88e_download_fw(struct ieee80211_hw *hw,
+		       bool buse_wake_on_wlan_fw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -221,8 +218,8 @@
 	if (IS_FW_HEADER_EXIST(pfwheader)) {
 		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 			 "Firmware Version(%d), Signature(%#x), Size(%d)\n",
-			 pfwheader->version, pfwheader->signature,
-			 (int)sizeof(struct rtl92c_firmware_header));
+			  pfwheader->version, pfwheader->signature,
+			  (int)sizeof(struct rtl92c_firmware_header));
 
 		pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
 		fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
@@ -237,9 +234,14 @@
 	_rtl88e_enable_fw_download(hw, false);
 
 	err = _rtl88e_fw_free_to_go(hw);
+	if (err) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Firmware is not ready to run!\n");
+	} else {
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+			 "Firmware is ready to run!\n");
+	}
 
-	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
-		 "Firmware is%s ready to run!\n", err ? " not" : "");
 	return 0;
 }
 
@@ -266,9 +268,9 @@
 	bool isfw_read = false;
 	u8 buf_index = 0;
 	bool write_sucess = false;
-	u8 wait_h2c_limit = 100;
+	u8 wait_h2c_limmit = 100;
 	u8 wait_writeh2c_limit = 100;
-	u8 boxc[4], boxext[2];
+	u8 boxcontent[4], boxextcontent[4];
 	u32 h2c_waitcounter = 0;
 	unsigned long flag;
 	u8 idx;
@@ -331,18 +333,17 @@
 			box_extreg = REG_HMEBOX_EXT_3;
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
 			break;
 		}
-
 		isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
 		while (!isfw_read) {
-			wait_h2c_limit--;
-			if (wait_h2c_limit == 0) {
+			wait_h2c_limmit--;
+			if (wait_h2c_limmit == 0) {
 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
-					 "Waiting too long for FW read "
-					 "clear HMEBox(%d)!\n", boxnum);
+					 "Waiting too long for FW read clear HMEBox(%d)!\n",
+					 boxnum);
 				break;
 			}
 
@@ -351,20 +352,20 @@
 			isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
 			u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
-				 "Waiting for FW read clear HMEBox(%d)!!! "
-				 "0x130 = %2x\n", boxnum, u1b_tmp);
+				 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
+				 boxnum, u1b_tmp);
 		}
 
 		if (!isfw_read) {
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
-				 "Write H2C register BOX[%d] fail!!!!! "
-				 "Fw do not read.\n", boxnum);
+				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
+				 boxnum);
 			break;
 		}
 
-		memset(boxc, 0, sizeof(boxc));
-		memset(boxext, 0, sizeof(boxext));
-		boxc[0] = element_id;
+		memset(boxcontent, 0, sizeof(boxcontent));
+		memset(boxextcontent, 0, sizeof(boxextcontent));
+		boxcontent[0] = element_id;
 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 			 "Write element_id box_reg(%4x) = %2x\n",
 			 box_reg, element_id);
@@ -373,33 +374,38 @@
 		case 1:
 		case 2:
 		case 3:
-			/*boxc[0] &= ~(BIT(7));*/
-			memcpy((u8 *)(boxc) + 1, cmd_b + buf_index, cmd_len);
+			/*boxcontent[0] &= ~(BIT(7));*/
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmd_b + buf_index, cmd_len);
 
-			for (idx = 0; idx < 4; idx++)
-				rtl_write_byte(rtlpriv, box_reg+idx, boxc[idx]);
+			for (idx = 0; idx < 4; idx++) {
+				rtl_write_byte(rtlpriv, box_reg + idx,
+					       boxcontent[idx]);
+			}
 			break;
 		case 4:
 		case 5:
 		case 6:
 		case 7:
-			/*boxc[0] |= (BIT(7));*/
-			memcpy((u8 *)(boxext), cmd_b + buf_index+3, cmd_len-3);
-			memcpy((u8 *)(boxc) + 1, cmd_b + buf_index, 3);
+			/*boxcontent[0] |= (BIT(7));*/
+			memcpy((u8 *)(boxextcontent),
+			       cmd_b + buf_index+3, cmd_len-3);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmd_b + buf_index, 3);
 
 			for (idx = 0; idx < 2; idx++) {
 				rtl_write_byte(rtlpriv, box_extreg + idx,
-					       boxext[idx]);
+					       boxextcontent[idx]);
 			}
 
 			for (idx = 0; idx < 4; idx++) {
 				rtl_write_byte(rtlpriv, box_reg + idx,
-					       boxc[idx]);
+					       boxcontent[idx]);
 			}
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
 			break;
 		}
 
@@ -411,7 +417,7 @@
 
 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 			 "pHalData->last_hmeboxnum  = %d\n",
-			 rtlhal->last_hmeboxnum);
+			  rtlhal->last_hmeboxnum);
 	}
 
 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
@@ -422,18 +428,19 @@
 }
 
 void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw,
-			 u8 element_id, u32 cmd_len, u8 *cmd_b)
+			 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
 {
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u32 tmp_cmdbuf[2];
 
-	if (rtlhal->fw_ready == false) {
-		RT_ASSERT(false, "fail H2C cmd - Fw download fail!!!\n");
+	if (!rtlhal->fw_ready) {
+		RT_ASSERT(false,
+			  "return H2C cmd because of Fw download fail!!!\n");
 		return;
 	}
 
 	memset(tmp_cmdbuf, 0, 8);
-	memcpy(tmp_cmdbuf, cmd_b, cmd_len);
+	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
 	_rtl88e_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
 
 	return;
@@ -448,7 +455,8 @@
 	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
 	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-		 "8051Reset88E(): 8051 reset success.\n");
+		 "8051Reset88E(): 8051 reset success\n");
+
 }
 
 void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
@@ -456,28 +464,29 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 u1_h2c_set_pwrmode[H2C_88E_PWEMODE_LENGTH] = { 0 };
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-	u8 power_state = 0;
-
+	u8 rlbm, power_state = 0;
 	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
+
 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
-	SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, 0);
+	rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM=2.*/
+	SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
-					 (rtlpriv->mac80211.p2p) ?
-					 ppsc->smart_ps : 1);
+		(rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
 	SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
-					       ppsc->reg_max_lps_awakeintvl);
+		ppsc->reg_max_lps_awakeintvl);
 	SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
 	if (mode == FW_PS_ACTIVE_MODE)
 		power_state |= FW_PWR_STATE_ACTIVE;
 	else
 		power_state |= FW_PWR_STATE_RF_OFF;
+
 	SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
 
 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 		      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
 		      u1_h2c_set_pwrmode, H2C_88E_PWEMODE_LENGTH);
-	rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE, H2C_88E_PWEMODE_LENGTH,
-			    u1_h2c_set_pwrmode);
+	rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE,
+			    H2C_88E_PWEMODE_LENGTH, u1_h2c_set_pwrmode);
 }
 
 void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
@@ -499,39 +508,9 @@
 	SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
 	SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
 
-	rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD, H2C_88E_AP_OFFLOAD_LENGTH,
-			    u1_apoffload_parm);
-}
+	rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD,
+			    H2C_88E_AP_OFFLOAD_LENGTH, u1_apoffload_parm);
 
-static bool _rtl88e_cmd_send_packet(struct ieee80211_hw *hw,
-				    struct sk_buff *skb)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-	struct rtl8192_tx_ring *ring;
-	struct rtl_tx_desc *pdesc;
-	struct sk_buff *pskb = NULL;
-	unsigned long flags;
-
-	ring = &rtlpci->tx_ring[BEACON_QUEUE];
-
-	pskb = __skb_dequeue(&ring->queue);
-	if (pskb)
-		kfree_skb(pskb);
-
-	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
-
-	pdesc = &ring->desc[0];
-
-	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
-
-	__skb_queue_tail(&ring->queue, skb);
-
-	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-
-	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
-
-	return true;
 }
 
 #define BEACON_PG		0 /* ->1 */
@@ -656,14 +635,15 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct sk_buff *skb = NULL;
-
 	u32 totalpacketlen;
-	u8 u1RsvdPageLoc[5] = { 0 };
-
+	bool rtstatus;
+	u8 u1rsvdpageloc[5] = { 0 };
+	bool b_dlok = false;
 	u8 *beacon;
-	u8 *pspoll;
+	u8 *p_pspoll;
 	u8 *nullfunc;
-	u8 *probersp;
+	u8 *p_probersp;
+
 	/*---------------------------------------------------------
 	 *			(1) beacon
 	 *---------------------------------------------------------
@@ -676,12 +656,12 @@
 	 *			(2) ps-poll
 	 *--------------------------------------------------------
 	 */
-	pspoll = &reserved_page_packet[PSPOLL_PG * 128];
-	SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
-	SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
-	SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
+	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
+	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
+	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
+	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
 
-	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
+	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
 
 	/*--------------------------------------------------------
 	 *			(3) null data
@@ -692,18 +672,18 @@
 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
 
-	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
+	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
 
 	/*---------------------------------------------------------
 	 *			(4) probe response
 	 *----------------------------------------------------------
 	 */
-	probersp = &reserved_page_packet[PROBERSP_PG * 128];
-	SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
-	SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
-	SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
+	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
+	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
+	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
 
-	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
+	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
 
 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
 
@@ -712,33 +692,36 @@
 		      &reserved_page_packet[0], totalpacketlen);
 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 		      "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
-		      u1RsvdPageLoc, 3);
+		      u1rsvdpageloc, 3);
 
 	skb = dev_alloc_skb(totalpacketlen);
-	if (!skb)
-		return;
-	kmemleak_not_leak(skb);
 	memcpy(skb_put(skb, totalpacketlen),
 	       &reserved_page_packet, totalpacketlen);
 
-	if (_rtl88e_cmd_send_packet(hw, skb)) {
+	rtstatus = rtl_cmd_send_packet(hw, skb);
+
+	if (rtstatus)
+		b_dlok = true;
+
+	if (b_dlok) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 			 "Set RSVD page location to Fw.\n");
 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
-			      "H2C_RSVDPAGE:\n", u1RsvdPageLoc, 3);
+			      "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
 		rtl88e_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE,
-				    sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
+				    sizeof(u1rsvdpageloc), u1rsvdpageloc);
 	} else
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
 }
 
-/*Shoud check FW support p2p or not.*/
+/*Should check FW support p2p or not.*/
 static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
 {
-	u8 u1_ctwindow_period[1] = {ctwindow};
+	u8 u1_ctwindow_period[1] = { ctwindow};
 
 	rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
+
 }
 
 void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
@@ -755,7 +738,7 @@
 	switch (p2p_ps_state) {
 	case P2P_PS_DISABLE:
 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
-		memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
+		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
 		break;
 	case P2P_PS_ENABLE:
 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
@@ -765,8 +748,9 @@
 			ctwindow = p2pinfo->ctwindow;
 			rtl88e_set_p2p_ctw_period_cmd(hw, ctwindow);
 		}
+
 		/* hw only support 2 set of NoA */
-		for (i = 0; i < p2pinfo->noa_num; i++) {
+		for (i = 0 ; i < p2pinfo->noa_num; i++) {
 			/* To control the register setting for which NOA*/
 			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
 			if (i == 0)
@@ -785,7 +769,7 @@
 
 			start_time = p2pinfo->noa_start_time[i];
 			if (p2pinfo->noa_count_type[i] != 1) {
-				while (start_time <= (tsf_low + (50 * 1024))) {
+				while (start_time <= (tsf_low+(50*1024))) {
 					start_time += p2pinfo->noa_interval[i];
 					if (p2pinfo->noa_count_type[i] != 255)
 						p2pinfo->noa_count_type[i]--;
@@ -804,7 +788,7 @@
 
 			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
 				p2p_ps_offload->role = 1;
-				p2p_ps_offload->allstasleep = 0;
+				p2p_ps_offload->allstasleep = -1;
 			} else {
 				p2p_ps_offload->role = 0;
 			}
@@ -827,4 +811,5 @@
 
 	rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1,
 			    (u8 *)p2p_ps_offload);
+
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h
index 854a987..05e944e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h
@@ -55,10 +55,11 @@
 #define H2C_88E_AOAC_RSVDPAGE_LOC_LEN		7
 
 /* Fw PS state for RPWM.
- * BIT[2:0] = HW state
- * BIT[3] = Protocol PS state, 1: register active state, 0: register sleep state
- * BIT[4] = sub-state
- */
+*BIT[2:0] = HW state
+*BIT[3] = Protocol PS state,
+*1: register active state , 0: register sleep state
+*BIT[4] = sub-state
+*/
 #define	FW_PS_GO_ON			BIT(0)
 #define	FW_PS_TX_NULL			BIT(1)
 #define	FW_PS_RF_ON			BIT(2)
@@ -98,10 +99,13 @@
 #define	FW_PS_STATE_S2			(FW_PS_RF_OFF)
 #define	FW_PS_STATE_S3			(FW_PS_ALL_ON)
 #define	FW_PS_STATE_S4			((FW_PS_ST_ACTIVE) | (FW_PS_ALL_ON))
-
+/* ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))*/
 #define	FW_PS_STATE_ALL_ON_88E		(FW_PS_CLOCK_ON)
+/* (FW_PS_RF_ON)*/
 #define	FW_PS_STATE_RF_ON_88E		(FW_PS_CLOCK_ON)
-#define	FW_PS_STATE_RF_OFF_88E		(FW_PS_CLOCK_ON)
+/* 0x0*/
+#define	FW_PS_STATE_RF_OFF_88E	(FW_PS_CLOCK_ON)
+/* (FW_PS_STATE_RF_OFF)*/
 #define	FW_PS_STATE_RF_OFF_LOW_PWR_88E	(FW_PS_CLOCK_OFF)
 
 #define	FW_PS_STATE_ALL_ON_92C		(FW_PS_STATE_S4)
@@ -146,7 +150,7 @@
 	u32 rsvd5;
 };
 
-enum rtl8192c_h2c_cmd {
+enum rtl8188e_h2c_cmd {
 	H2C_88E_RSVDPAGE = 0,
 	H2C_88E_JOINBSSRPT = 1,
 	H2C_88E_SCAN = 2,
@@ -175,7 +179,7 @@
 	H2C_88E_AOAC_GLOBAL_INFO = 0x82,
 	H2C_88E_AOAC_RSVDPAGE = 0x83,
 #endif
-	/* Not defined in new 88E H2C CMD Format */
+	/*Not defined in new 88E H2C CMD Format*/
 	H2C_88E_RA_MASK,
 	H2C_88E_SELECTIVE_SUSPEND_ROF_CMD,
 	H2C_88E_P2P_PS_MODE,
@@ -289,13 +293,12 @@
 int rtl88e_download_fw(struct ieee80211_hw *hw,
 		       bool buse_wake_on_wlan_fw);
 void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
-			 u32 cmd_len, u8 *p_cmdbuffer);
+			 u32 cmd_len, u8 *cmdbuffer);
 void rtl88e_firmware_selfreset(struct ieee80211_hw *hw);
 void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
-void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw,
-				      u8 mstatus);
-void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,  u8 enable);
+void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
+void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
+				   u8 ap_offload_enable);
 void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
 void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
-
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
index d840ad7..f2b9713 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -93,7 +89,9 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
+	unsigned long flags;
 
+	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 	while (skb_queue_len(&ring->queue)) {
 		struct rtl_tx_desc *entry = &ring->desc[ring->idx];
 		struct sk_buff *skb = __skb_dequeue(&ring->queue);
@@ -105,6 +103,7 @@
 		kfree_skb(skb);
 		ring->idx = (ring->idx + 1) % ring->entries;
 	}
+	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
 }
 
 static void _rtl88ee_disable_bcn_sub_func(struct ieee80211_hw *hw)
@@ -113,16 +112,16 @@
 }
 
 static void _rtl88ee_set_fw_clock_on(struct ieee80211_hw *hw,
-				     u8 rpwm_val, bool need_turn_off_ckk)
+				     u8 rpwm_val, bool b_need_turn_off_ckk)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	bool support_remote_wake_up;
+	bool b_support_remote_wake_up;
 	u32 count = 0, isr_regaddr, content;
-	bool schedule_timer = need_turn_off_ckk;
-
+	bool schedule_timer = b_need_turn_off_ckk;
 	rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
-				      (u8 *)(&support_remote_wake_up));
+					(u8 *)(&b_support_remote_wake_up));
+
 	if (!rtlhal->fw_ready)
 		return;
 	if (!rtlpriv->psc.fw_current_inpsmode)
@@ -133,8 +132,9 @@
 		if (rtlhal->fw_clk_change_in_progress) {
 			while (rtlhal->fw_clk_change_in_progress) {
 				spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+				count++;
 				udelay(100);
-				if (++count > 1000)
+				if (count > 1000)
 					return;
 				spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
 			}
@@ -173,6 +173,7 @@
 			mod_timer(&rtlpriv->works.fw_clockoff_timer,
 				  jiffies + MSECS(10));
 		}
+
 	} else  {
 		spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
 		rtlhal->fw_clk_change_in_progress = false;
@@ -247,11 +248,9 @@
 static void _rtl88ee_set_fw_ps_rf_off_low_power(struct ieee80211_hw *hw)
 {
 	u8 rpwm_val = 0;
-
 	rpwm_val |= FW_PS_STATE_RF_OFF_LOW_PWR_88E;
 	_rtl88ee_set_fw_clock_off(hw, rpwm_val);
 }
-
 void rtl88ee_fw_clk_off_timer_callback(unsigned long data)
 {
 	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
@@ -325,23 +324,23 @@
 		*((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
 		break;
 	case HW_VAR_FWLPS_RF_ON:{
-			enum rf_pwrstate rfstate;
-			u32 val_rcr;
+		enum rf_pwrstate rfstate;
+		u32 val_rcr;
 
-			rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE,
-						      (u8 *)(&rfstate));
-			if (rfstate == ERFOFF) {
+		rtlpriv->cfg->ops->get_hw_reg(hw,
+					      HW_VAR_RF_STATE,
+					      (u8 *)(&rfstate));
+		if (rfstate == ERFOFF) {
+			*((bool *)(val)) = true;
+		} else {
+			val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+			val_rcr &= 0x00070000;
+			if (val_rcr)
+				*((bool *)(val)) = false;
+			else
 				*((bool *)(val)) = true;
-			} else {
-				val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
-				val_rcr &= 0x00070000;
-				if (val_rcr)
-					*((bool *)(val)) = false;
-				else
-					*((bool *)(val)) = true;
-			}
-			break;
 		}
+		break; }
 	case HW_VAR_FW_PSMODE_STATUS:
 		*((bool *)(val)) = ppsc->fw_current_inpsmode;
 		break;
@@ -373,25 +372,32 @@
 
 	switch (variable) {
 	case HW_VAR_ETHER_ADDR:
-		for (idx = 0; idx < ETH_ALEN; idx++)
-			rtl_write_byte(rtlpriv, (REG_MACID + idx), val[idx]);
+		for (idx = 0; idx < ETH_ALEN; idx++) {
+			rtl_write_byte(rtlpriv, (REG_MACID + idx),
+				       val[idx]);
+		}
 		break;
 	case HW_VAR_BASIC_RATE:{
-		u16 rate_cfg = ((u16 *)val)[0];
+		u16 b_rate_cfg = ((u16 *)val)[0];
 		u8 rate_index = 0;
-		rate_cfg = rate_cfg & 0x15f;
-		rate_cfg |= 0x01;
-		rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff);
-		rtl_write_byte(rtlpriv, REG_RRSR + 1, (rate_cfg >> 8) & 0xff);
-		while (rate_cfg > 0x1) {
-			rate_cfg = (rate_cfg >> 1);
+		b_rate_cfg = b_rate_cfg & 0x15f;
+		b_rate_cfg |= 0x01;
+		rtl_write_byte(rtlpriv, REG_RRSR, b_rate_cfg & 0xff);
+		rtl_write_byte(rtlpriv, REG_RRSR + 1,
+			       (b_rate_cfg >> 8) & 0xff);
+		while (b_rate_cfg > 0x1) {
+			b_rate_cfg = (b_rate_cfg >> 1);
 			rate_index++;
 		}
-		rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, rate_index);
-		break; }
+		rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL,
+			       rate_index);
+		break;
+		}
 	case HW_VAR_BSSID:
-		for (idx = 0; idx < ETH_ALEN; idx++)
-			rtl_write_byte(rtlpriv, (REG_BSSID + idx), val[idx]);
+		for (idx = 0; idx < ETH_ALEN; idx++) {
+			rtl_write_byte(rtlpriv, (REG_BSSID + idx),
+				       val[idx]);
+		}
 		break;
 	case HW_VAR_SIFS:
 		rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]);
@@ -401,7 +407,8 @@
 		rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]);
 
 		if (!mac->ht_enable)
-			rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, 0x0e0e);
+			rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
+				       0x0e0e);
 		else
 			rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
 				       *((u16 *)val));
@@ -418,17 +425,20 @@
 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
 						      &e_aci);
 		}
-		break; }
+		break;
+		}
 	case HW_VAR_ACK_PREAMBLE:{
 		u8 reg_tmp;
 		u8 short_preamble = (bool)*val;
 		reg_tmp = rtl_read_byte(rtlpriv, REG_TRXPTCL_CTL+2);
 		if (short_preamble) {
 			reg_tmp |= 0x02;
-			rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp);
+			rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL +
+				       2, reg_tmp);
 		} else {
 			reg_tmp |= 0xFD;
-			rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp);
+			rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL +
+				       2, reg_tmp);
 		}
 		break; }
 	case HW_VAR_WPA_CONFIG:
@@ -446,7 +456,8 @@
 				min_spacing_to_set = sec_min_space;
 
 			mac->min_space_cfg = ((mac->min_space_cfg &
-					       0xf8) | min_spacing_to_set);
+					       0xf8) |
+					      min_spacing_to_set);
 
 			*val = min_spacing_to_set;
 
@@ -470,35 +481,44 @@
 
 		rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
 			       mac->min_space_cfg);
-		break; }
+		break;
+		}
 	case HW_VAR_AMPDU_FACTOR:{
 		u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 };
-		u8 factor;
-		u8 *reg = NULL;
-		u8 id = 0;
+		u8 factor_toset;
+		u8 *p_regtoset = NULL;
+		u8 index = 0;
 
-		reg = regtoset_normal;
+		p_regtoset = regtoset_normal;
 
-		factor = *val;
-		if (factor <= 3) {
-			factor = (1 << (factor + 2));
-			if (factor > 0xf)
-				factor = 0xf;
+		factor_toset = *val;
+		if (factor_toset <= 3) {
+			factor_toset = (1 << (factor_toset + 2));
+			if (factor_toset > 0xf)
+				factor_toset = 0xf;
 
-			for (id = 0; id < 4; id++) {
-				if ((reg[id] & 0xf0) > (factor << 4))
-					reg[id] = (reg[id] & 0x0f) |
-						  (factor << 4);
+			for (index = 0; index < 4; index++) {
+				if ((p_regtoset[index] & 0xf0) >
+				    (factor_toset << 4))
+					p_regtoset[index] =
+					    (p_regtoset[index] & 0x0f) |
+					    (factor_toset << 4);
 
-				if ((reg[id] & 0x0f) > factor)
-					reg[id] = (reg[id] & 0xf0) | (factor);
+				if ((p_regtoset[index] & 0x0f) >
+				    factor_toset)
+					p_regtoset[index] =
+					    (p_regtoset[index] & 0xf0) |
+					    (factor_toset);
 
-				rtl_write_byte(rtlpriv, (REG_AGGLEN_LMT + id),
-					       reg[id]);
+				rtl_write_byte(rtlpriv,
+					       (REG_AGGLEN_LMT + index),
+					       p_regtoset[index]);
+
 			}
 
 			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
-				 "Set HW_VAR_AMPDU_FACTOR: %#x\n", factor);
+				 "Set HW_VAR_AMPDU_FACTOR: %#x\n",
+				  factor_toset);
 		}
 		break; }
 	case HW_VAR_AC_PARAM:{
@@ -506,7 +526,8 @@
 		rtl88e_dm_init_edca_turbo(hw);
 
 		if (rtlpci->acm_method != EACMWAY2_SW)
-			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_ACM_CTRL,
 						      &e_aci);
 		break; }
 	case HW_VAR_ACM_CTRL:{
@@ -516,7 +537,8 @@
 		u8 acm = p_aci_aifsn->f.acm;
 		u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL);
 
-		acm_ctrl = acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1);
+		acm_ctrl = acm_ctrl |
+			   ((rtlpci->acm_method == 2) ? 0x0 : 0x1);
 
 		if (acm) {
 			switch (e_aci) {
@@ -609,66 +631,76 @@
 			_rtl88ee_fwlps_enter(hw);
 		 else
 			_rtl88ee_fwlps_leave(hw);
+
 		 break; }
 	case HW_VAR_H2C_FW_JOINBSSRPT:{
 		u8 mstatus = *val;
-		u8 tmp, tmp_reg422, uval;
+		u8 tmp_regcr, tmp_reg422, bcnvalid_reg;
 		u8 count = 0, dlbcn_count = 0;
-		bool recover = false;
+		bool b_recover = false;
 
 		if (mstatus == RT_MEDIA_CONNECT) {
-			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL);
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID,
+						      NULL);
 
-			tmp = rtl_read_byte(rtlpriv, REG_CR + 1);
-			rtl_write_byte(rtlpriv, REG_CR + 1, (tmp | BIT(0)));
+			tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
+			rtl_write_byte(rtlpriv, REG_CR + 1,
+				       (tmp_regcr | BIT(0)));
 
 			_rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(3));
 			_rtl88ee_set_bcn_ctrl_reg(hw, BIT(4), 0);
 
-			tmp_reg422 = rtl_read_byte(rtlpriv,
-						   REG_FWHW_TXQ_CTRL + 2);
+			tmp_reg422 =
+			    rtl_read_byte(rtlpriv,
+					  REG_FWHW_TXQ_CTRL + 2);
 			rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
 				       tmp_reg422 & (~BIT(6)));
 			if (tmp_reg422 & BIT(6))
-				recover = true;
+				b_recover = true;
 
 			do {
-				uval = rtl_read_byte(rtlpriv, REG_TDECTRL+2);
+				bcnvalid_reg = rtl_read_byte(rtlpriv,
+							     REG_TDECTRL+2);
 				rtl_write_byte(rtlpriv, REG_TDECTRL+2,
-					       (uval | BIT(0)));
+					       (bcnvalid_reg | BIT(0)));
 				_rtl88ee_return_beacon_queue_skb(hw);
 
 				rtl88e_set_fw_rsvdpagepkt(hw, 0);
-				uval = rtl_read_byte(rtlpriv, REG_TDECTRL+2);
+				bcnvalid_reg = rtl_read_byte(rtlpriv,
+							     REG_TDECTRL+2);
 				count = 0;
-				while (!(uval & BIT(0)) && count < 20) {
+				while (!(bcnvalid_reg & BIT(0)) && count < 20) {
 					count++;
 					udelay(10);
-					uval = rtl_read_byte(rtlpriv,
-							     REG_TDECTRL+2);
+					bcnvalid_reg =
+					  rtl_read_byte(rtlpriv, REG_TDECTRL+2);
 				}
 				dlbcn_count++;
-			} while (!(uval & BIT(0)) && dlbcn_count < 5);
+			} while (!(bcnvalid_reg & BIT(0)) && dlbcn_count < 5);
 
-			if (uval & BIT(0))
+			if (bcnvalid_reg & BIT(0))
 				rtl_write_byte(rtlpriv, REG_TDECTRL+2, BIT(0));
 
 			_rtl88ee_set_bcn_ctrl_reg(hw, BIT(3), 0);
 			_rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(4));
 
-			if (recover) {
-				rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+			if (b_recover) {
+				rtl_write_byte(rtlpriv,
+					       REG_FWHW_TXQ_CTRL + 2,
 					       tmp_reg422);
 			}
-			rtl_write_byte(rtlpriv, REG_CR + 1, (tmp & ~(BIT(0))));
+
+			rtl_write_byte(rtlpriv, REG_CR + 1,
+				       (tmp_regcr & ~(BIT(0))));
 		}
-		rtl88e_set_fw_joinbss_report_cmd(hw, *val);
+		rtl88e_set_fw_joinbss_report_cmd(hw, (*(u8 *)val));
 		break; }
 	case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
 		rtl88e_set_p2p_ps_offload_cmd(hw, *val);
 		break;
 	case HW_VAR_AID:{
 		u16 u2btmp;
+
 		u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
 		u2btmp &= 0xC000;
 		rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, (u2btmp |
@@ -677,21 +709,29 @@
 	case HW_VAR_CORRECT_TSF:{
 		u8 btype_ibss = *val;
 
-		if (btype_ibss == true)
+		if (btype_ibss)
 			_rtl88ee_stop_tx_beacon(hw);
 
 		_rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(3));
 
 		rtl_write_dword(rtlpriv, REG_TSFTR,
-				(u32) (mac->tsf & 0xffffffff));
+				(u32)(mac->tsf & 0xffffffff));
 		rtl_write_dword(rtlpriv, REG_TSFTR + 4,
-				(u32) ((mac->tsf >> 32) & 0xffffffff));
+				(u32)((mac->tsf >> 32) & 0xffffffff));
 
 		_rtl88ee_set_bcn_ctrl_reg(hw, BIT(3), 0);
 
-		if (btype_ibss == true)
+		if (btype_ibss)
 			_rtl88ee_resume_tx_beacon(hw);
 		break; }
+	case HW_VAR_KEEP_ALIVE: {
+		u8 array[2];
+
+		array[0] = 0xff;
+		array[1] = *((u8 *)val);
+		rtl88e_fill_h2c_cmd(hw, H2C_88E_KEEP_ALIVE_CTRL,
+				    2, array);
+		break; }
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 "switch case not process %x\n", variable);
@@ -740,7 +780,7 @@
 	rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x01);
 	rtl_write_dword(rtlpriv, REG_RQPN, 0x80730d29);
 
-
+	/*0x2600   MaxRxBuff=10k-max(TxReportSize(64*8), WOLPattern(16*24)) */
 	rtl_write_dword(rtlpriv, REG_TRXFF_BNDY, (0x25FF0000 | txpktbuf_bndy));
 	rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy);
 
@@ -797,10 +837,11 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
 	u8 bytetmp;
 	u16 wordtmp;
 
-	/*Disable XTAL OUTPUT for power saving. YJ, add, 111206. */
+	/*Disable XTAL OUTPUT for power saving. YJ,add,111206. */
 	bytetmp = rtl_read_byte(rtlpriv, REG_XCK_OUT_CTRL) & (~BIT(0));
 	rtl_write_byte(rtlpriv, REG_XCK_OUT_CTRL, bytetmp);
 	/*Auto Power Down to CHIP-off State*/
@@ -811,7 +852,7 @@
 	/* HW Power on sequence */
 	if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK,
 				      PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,
-				      Rtl8188E_NIC_ENABLE_FLOW)) {
+				      RTL8188EE_NIC_ENABLE_FLOW)) {
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 			 "init MAC Fail as rtl_hal_pwrseqcmdparsing\n");
 		return false;
@@ -853,8 +894,6 @@
 			return false;
 		}
 	}
-
-
 	rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff);
 	rtl_write_dword(rtlpriv, REG_HISRE, 0xffffffff);
 
@@ -889,9 +928,8 @@
 			DMA_BIT_MASK(32));
 
 	/* if we want to support 64 bit DMA, we should set it here,
-	 * but at the moment we do not support 64 bit DMA
+	 * but now we do not support 64 bit DMA
 	 */
-
 	rtl_write_dword(rtlpriv, REG_INT_MIG, 0);
 
 	rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0);
@@ -910,8 +948,12 @@
 static void _rtl88ee_hw_configure(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 reg_prsr;
+	u8 reg_bw_opmode;
+	u32 reg_ratr, reg_prsr;
 
+	reg_bw_opmode = BW_OPMODE_20MHZ;
+	reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
+	    RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
 	reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
 
 	rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr);
@@ -923,7 +965,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	u8 tmp1byte = 0;
-	u32 tmp4Byte = 0, count;
+	u32 tmp4byte = 0, count = 0;
 
 	rtl_write_word(rtlpriv, 0x354, 0x8104);
 	rtl_write_word(rtlpriv, 0x358, 0x24);
@@ -938,8 +980,8 @@
 		count++;
 	}
 	if (0 == tmp1byte) {
-		tmp4Byte = rtl_read_dword(rtlpriv, 0x34c);
-		rtl_write_dword(rtlpriv, 0x348, tmp4Byte|BIT(31));
+		tmp4byte = rtl_read_dword(rtlpriv, 0x34c);
+		rtl_write_dword(rtlpriv, 0x348, tmp4byte|BIT(31));
 		rtl_write_word(rtlpriv, 0x350, 0xf70c);
 		rtl_write_byte(rtlpriv, 0x352, 0x1);
 	}
@@ -961,12 +1003,14 @@
 		tmp1byte = rtl_read_byte(rtlpriv, 0x352);
 		count++;
 	}
+
 	if (ppsc->support_backdoor || (0 == tmp1byte)) {
-		tmp4Byte = rtl_read_dword(rtlpriv, 0x34c);
-		rtl_write_dword(rtlpriv, 0x348, tmp4Byte|BIT(11)|BIT(12));
+		tmp4byte = rtl_read_dword(rtlpriv, 0x34c);
+		rtl_write_dword(rtlpriv, 0x348, tmp4byte|BIT(11)|BIT(12));
 		rtl_write_word(rtlpriv, 0x350, 0xf718);
 		rtl_write_byte(rtlpriv, 0x352, 0x1);
 	}
+
 	tmp1byte = rtl_read_byte(rtlpriv, 0x352);
 	count = 0;
 	while (tmp1byte && count < 20) {
@@ -983,14 +1027,15 @@
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 		 "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n",
-		 rtlpriv->sec.pairwise_enc_algorithm,
-		 rtlpriv->sec.group_enc_algorithm);
+		  rtlpriv->sec.pairwise_enc_algorithm,
+		  rtlpriv->sec.group_enc_algorithm);
 
 	if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
 		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 			 "not open hw encryption\n");
 		return;
 	}
+
 	sec_reg_value = SCR_TXENCENABLE | SCR_RXDECENABLE;
 
 	if (rtlpriv->sec.use_defaultkey) {
@@ -1004,6 +1049,7 @@
 
 	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 		 "The SECR-value %x\n", sec_reg_value);
+
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
 }
 
@@ -1021,7 +1067,6 @@
 	u8 tmp_u1b, u1byte;
 	unsigned long flags;
 
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Rtl8188EE hw init\n");
 	rtlpriv->rtlhal.being_init_adapter = true;
 	/* As this function can take a very long time (up to 350 ms)
 	 * and can be called with irqs disabled, reenable the irqs
@@ -1032,6 +1077,7 @@
 	 */
 	local_save_flags(flags);
 	local_irq_enable();
+	rtlhal->fw_ready = false;
 
 	rtlpriv->intf_ops->disable_aspm(hw);
 
@@ -1057,9 +1103,8 @@
 			 "Failed to download FW. Init HW without FW now..\n");
 		err = 1;
 		goto exit;
-	} else {
-		rtlhal->fw_ready = true;
 	}
+	rtlhal->fw_ready = true;
 	/*fw related variable initialize */
 	rtlhal->last_hmeboxnum = 0;
 	rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_88E;
@@ -1068,10 +1113,10 @@
 	ppsc->fw_current_inpsmode = false;
 
 	rtl88e_phy_mac_config(hw);
-	/* because last function modifies RCR, we update
-	 * rcr var here, or TP will be unstable for receive_config
-	 * is wrong, RX RCR_ACRC32 will cause TP unstable & Rx
-	 * RCR_APP_ICV will cause mac80211 disassoc for cisco 1252
+	/* because last function modify RCR, so we update
+	 * rcr var here, or TP will unstable for receive_config
+	 * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx
+	 * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252
 	 */
 	rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV);
 	rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
@@ -1101,15 +1146,14 @@
 	if (ppsc->rfpwr_state == ERFON) {
 		if ((rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) ||
 		    ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) &&
-		    (rtlhal->oem_id == RT_CID_819X_HP))) {
+		     (rtlhal->oem_id == RT_CID_819X_HP))) {
 			rtl88e_phy_set_rfpath_switch(hw, true);
 			rtlpriv->dm.fat_table.rx_idle_ant = MAIN_ANT;
 		} else {
 			rtl88e_phy_set_rfpath_switch(hw, false);
 			rtlpriv->dm.fat_table.rx_idle_ant = AUX_ANT;
 		}
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-			 "rx idle ant %s\n",
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "rx idle ant %s\n",
 			 (rtlpriv->dm.fat_table.rx_idle_ant == MAIN_ANT) ?
 			 ("MAIN_ANT") : ("AUX_ANT"));
 
@@ -1119,6 +1163,7 @@
 			rtl88e_phy_iq_calibrate(hw, false);
 			rtlphy->iqk_initialized = true;
 		}
+
 		rtl88e_dm_check_txpower_tracking(hw);
 		rtl88e_phy_lc_calibrate(hw);
 	}
@@ -1142,8 +1187,6 @@
 exit:
 	local_irq_restore(flags);
 	rtlpriv->rtlhal.being_init_adapter = false;
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "end of Rtl8188EE hw init %x\n",
-		 err);
 	return err;
 }
 
@@ -1176,62 +1219,67 @@
 				     enum nl80211_iftype type)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u8 bt_msr = rtl_read_byte(rtlpriv, MSR);
+	u8 bt_msr = rtl_read_byte(rtlpriv, MSR) & 0xfc;
 	enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
-	bt_msr &= 0xfc;
-
-	if (type == NL80211_IFTYPE_UNSPECIFIED ||
-	    type == NL80211_IFTYPE_STATION) {
-		_rtl88ee_stop_tx_beacon(hw);
-		_rtl88ee_enable_bcn_sub_func(hw);
-	} else if (type == NL80211_IFTYPE_ADHOC ||
-		type == NL80211_IFTYPE_AP ||
-		type == NL80211_IFTYPE_MESH_POINT) {
-		_rtl88ee_resume_tx_beacon(hw);
-		_rtl88ee_disable_bcn_sub_func(hw);
-	} else {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-			 "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n",
-			 type);
-	}
+	u8 mode = MSR_NOLINK;
 
 	switch (type) {
 	case NL80211_IFTYPE_UNSPECIFIED:
-		bt_msr |= MSR_NOLINK;
-		ledaction = LED_CTL_LINK;
+		mode = MSR_NOLINK;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "Set Network type to NO LINK!\n");
 		break;
 	case NL80211_IFTYPE_ADHOC:
-		bt_msr |= MSR_ADHOC;
+	case NL80211_IFTYPE_MESH_POINT:
+		mode = MSR_ADHOC;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "Set Network type to Ad Hoc!\n");
 		break;
 	case NL80211_IFTYPE_STATION:
-		bt_msr |= MSR_INFRA;
+		mode = MSR_INFRA;
 		ledaction = LED_CTL_LINK;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "Set Network type to STA!\n");
 		break;
 	case NL80211_IFTYPE_AP:
-		bt_msr |= MSR_AP;
+		mode = MSR_AP;
+		ledaction = LED_CTL_LINK;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "Set Network type to AP!\n");
 		break;
-	case NL80211_IFTYPE_MESH_POINT:
-		bt_msr |= MSR_ADHOC;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "Set Network type to Mesh Point!\n");
-		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 "Network type %d not support!\n", type);
 		return 1;
+		break;
 	}
 
-	rtl_write_byte(rtlpriv, (MSR), bt_msr);
+	/* MSR_INFRA == Link in infrastructure network;
+	 * MSR_ADHOC == Link in ad hoc network;
+	 * Therefore, check link state is necessary.
+	 *
+	 * MSR_AP == AP mode; link state is not cared here.
+	 */
+	if (mode != MSR_AP && rtlpriv->mac80211.link_state < MAC80211_LINKED) {
+		mode = MSR_NOLINK;
+		ledaction = LED_CTL_NO_LINK;
+	}
+
+	if (mode == MSR_NOLINK || mode == MSR_INFRA) {
+		_rtl88ee_stop_tx_beacon(hw);
+		_rtl88ee_enable_bcn_sub_func(hw);
+	} else if (mode == MSR_ADHOC || mode == MSR_AP) {
+		_rtl88ee_resume_tx_beacon(hw);
+		_rtl88ee_disable_bcn_sub_func(hw);
+	} else {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n",
+			 mode);
+	}
+
+	rtl_write_byte(rtlpriv, (MSR), bt_msr | mode);
 	rtlpriv->cfg->ops->led_control(hw, ledaction);
-	if ((bt_msr & MSR_MASK) == MSR_AP)
+	if (mode == MSR_AP)
 		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
 	else
 		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
@@ -1241,13 +1289,12 @@
 void rtl88ee_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 reg_rcr;
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u32 reg_rcr = rtlpci->receive_config;
 
 	if (rtlpriv->psc.rfpwr_state != ERFON)
 		return;
 
-	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
-
 	if (check_bssid == true) {
 		reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
@@ -1259,9 +1306,11 @@
 		rtlpriv->cfg->ops->set_hw_reg(hw,
 			HW_VAR_RCR, (u8 *)(&reg_rcr));
 	}
+
 }
 
-int rtl88ee_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
+int rtl88ee_set_network_type(struct ieee80211_hw *hw,
+			     enum nl80211_iftype type)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
@@ -1279,7 +1328,9 @@
 	return 0;
 }
 
-/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */
+/* don't set REG_EDCA_BE_PARAM here
+ * because mac80211 will send pkt when scan
+ */
 void rtl88ee_set_qos(struct ieee80211_hw *hw, int aci)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1302,22 +1353,41 @@
 	}
 }
 
+static void rtl88ee_clear_interrupt(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 tmp;
+
+	tmp = rtl_read_dword(rtlpriv, REG_HISR);
+	rtl_write_dword(rtlpriv, REG_HISR, tmp);
+
+	tmp = rtl_read_dword(rtlpriv, REG_HISRE);
+	rtl_write_dword(rtlpriv, REG_HISRE, tmp);
+
+	tmp = rtl_read_dword(rtlpriv, REG_HSISR);
+	rtl_write_dword(rtlpriv, REG_HSISR, tmp);
+}
+
 void rtl88ee_enable_interrupt(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 
-	rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
-	rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
+	rtl88ee_clear_interrupt(hw);/*clear it here first*/
+	rtl_write_dword(rtlpriv, REG_HIMR,
+			rtlpci->irq_mask[0] & 0xFFFFFFFF);
+	rtl_write_dword(rtlpriv, REG_HIMRE,
+			rtlpci->irq_mask[1] & 0xFFFFFFFF);
 	rtlpci->irq_enabled = true;
-	/* there are some C2H CMDs have been sent before system interrupt
-	 * is enabled, e.g., C2H, CPWM.
-	 * So we need to clear all C2H events that FW has notified, otherwise
-	 * FW won't schedule any commands anymore.
+	/* there are some C2H CMDs have been sent
+	 * before system interrupt is enabled, e.g., C2H, CPWM.
+	 * So we need to clear all C2H events that FW has notified,
+	 * otherwise FW won't schedule any commands anymore.
 	 */
 	rtl_write_byte(rtlpriv, REG_C2HEVT_CLEAR, 0);
 	/*enable system interrupt*/
-	rtl_write_dword(rtlpriv, REG_HSIMR, rtlpci->sys_irq_mask & 0xFFFFFFFF);
+	rtl_write_dword(rtlpriv, REG_HSIMR,
+			rtlpci->sys_irq_mask & 0xFFFFFFFF);
 }
 
 void rtl88ee_disable_interrupt(struct ieee80211_hw *hw)
@@ -1328,7 +1398,7 @@
 	rtl_write_dword(rtlpriv, REG_HIMR, IMR_DISABLED);
 	rtl_write_dword(rtlpriv, REG_HIMRE, IMR_DISABLED);
 	rtlpci->irq_enabled = false;
-	synchronize_irq(rtlpci->pdev->irq);
+	/*synchronize_irq(rtlpci->pdev->irq);*/
 }
 
 static void _rtl88ee_poweroff_adapter(struct ieee80211_hw *hw)
@@ -1354,7 +1424,7 @@
 
 	rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
 				 PWR_INTF_PCI_MSK,
-				 Rtl8188E_NIC_LPS_ENTER_FLOW);
+				 RTL8188EE_NIC_LPS_ENTER_FLOW);
 
 	rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00);
 
@@ -1369,7 +1439,7 @@
 	rtl_write_byte(rtlpriv, REG_32K_CTRL, (u1b_tmp & (~BIT(0))));
 
 	rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
-				 PWR_INTF_PCI_MSK, Rtl8188E_NIC_DISABLE_FLOW);
+				 PWR_INTF_PCI_MSK, RTL8188EE_NIC_DISABLE_FLOW);
 
 	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1);
 	rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp & (~BIT(3))));
@@ -1426,6 +1496,7 @@
 
 	*p_intb = rtl_read_dword(rtlpriv, REG_HISRE) & rtlpci->irq_mask[1];
 	rtl_write_dword(rtlpriv, REG_HISRE, *p_intb);
+
 }
 
 void rtl88ee_set_beacon_related_registers(struct ieee80211_hw *hw)
@@ -1471,233 +1542,241 @@
 	RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
 		 "add_msr:%x, rm_msr:%x\n", add_msr, rm_msr);
 
-	rtl88ee_disable_interrupt(hw);
 	if (add_msr)
 		rtlpci->irq_mask[0] |= add_msr;
 	if (rm_msr)
 		rtlpci->irq_mask[0] &= (~rm_msr);
+	rtl88ee_disable_interrupt(hw);
 	rtl88ee_enable_interrupt(hw);
 }
 
-static inline u8 get_chnl_group(u8 chnl)
+static u8 _rtl88e_get_chnl_group(u8 chnl)
 {
-	u8 group;
+	u8 group = 0;
 
-	group = chnl / 3;
-	if (chnl == 14)
+	if (chnl < 3)
+		group = 0;
+	else if (chnl < 6)
+		group = 1;
+	else if (chnl < 9)
+		group = 2;
+	else if (chnl < 12)
+		group = 3;
+	else if (chnl < 14)
+		group = 4;
+	else if (chnl == 14)
 		group = 5;
 
 	return group;
 }
 
-static void set_diff0_2g(struct txpower_info_2g *pwr2g, u8 *hwinfo, u32 path,
-			 u32 i, u32 eadr)
+static void set_24g_base(struct txpower_info_2g *pwrinfo24g, u32 rfpath)
 {
-	pwr2g->bw40_diff[path][i] = 0;
-	if (hwinfo[eadr] == 0xFF) {
-		pwr2g->bw20_diff[path][i] = 0x02;
-	} else {
-		pwr2g->bw20_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
-		/*bit sign number to 8 bit sign number*/
-		if (pwr2g->bw20_diff[path][i] & BIT(3))
-			pwr2g->bw20_diff[path][i] |= 0xF0;
-	}
+	int group, txcnt;
 
-	if (hwinfo[eadr] == 0xFF) {
-		pwr2g->ofdm_diff[path][i] = 0x04;
-	} else {
-		pwr2g->ofdm_diff[path][i] = (hwinfo[eadr] & 0x0f);
-		/*bit sign number to 8 bit sign number*/
-		if (pwr2g->ofdm_diff[path][i] & BIT(3))
-			pwr2g->ofdm_diff[path][i] |= 0xF0;
+	for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) {
+		pwrinfo24g->index_cck_base[rfpath][group] = 0x2D;
+		pwrinfo24g->index_bw40_base[rfpath][group] = 0x2D;
 	}
-	pwr2g->cck_diff[path][i] = 0;
-}
-
-static void set_diff0_5g(struct txpower_info_5g *pwr5g, u8 *hwinfo, u32 path,
-			 u32 i, u32 eadr)
-{
-	pwr5g->bw40_diff[path][i] = 0;
-	if (hwinfo[eadr] == 0xFF) {
-		pwr5g->bw20_diff[path][i] = 0;
-	} else {
-		pwr5g->bw20_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
-		/*bit sign number to 8 bit sign number*/
-		if (pwr5g->bw20_diff[path][i] & BIT(3))
-			pwr5g->bw20_diff[path][i] |= 0xF0;
-	}
-
-	if (hwinfo[eadr] == 0xFF) {
-		pwr5g->ofdm_diff[path][i] = 0x04;
-	} else {
-		pwr5g->ofdm_diff[path][i] = (hwinfo[eadr] & 0x0f);
-		/*bit sign number to 8 bit sign number*/
-		if (pwr5g->ofdm_diff[path][i] & BIT(3))
-			pwr5g->ofdm_diff[path][i] |= 0xF0;
+	for (txcnt = 0; txcnt < MAX_TX_COUNT; txcnt++) {
+		if (txcnt == 0) {
+			pwrinfo24g->bw20_diff[rfpath][0] = 0x02;
+			pwrinfo24g->ofdm_diff[rfpath][0] = 0x04;
+		} else {
+			pwrinfo24g->bw20_diff[rfpath][txcnt] = 0xFE;
+			pwrinfo24g->bw40_diff[rfpath][txcnt] = 0xFE;
+			pwrinfo24g->cck_diff[rfpath][txcnt] =	0xFE;
+			pwrinfo24g->ofdm_diff[rfpath][txcnt] = 0xFE;
+		}
 	}
 }
 
-static void set_diff1_2g(struct txpower_info_2g *pwr2g, u8 *hwinfo, u32 path,
-			 u32 i, u32 eadr)
-{
-	if (hwinfo[eadr] == 0xFF) {
-		pwr2g->bw40_diff[path][i] = 0xFE;
-	} else {
-		pwr2g->bw40_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
-		if (pwr2g->bw40_diff[path][i] & BIT(3))
-			pwr2g->bw40_diff[path][i] |= 0xF0;
-	}
-
-	if (hwinfo[eadr] == 0xFF) {
-		pwr2g->bw20_diff[path][i] = 0xFE;
-	} else {
-		pwr2g->bw20_diff[path][i] = (hwinfo[eadr]&0x0f);
-		if (pwr2g->bw20_diff[path][i] & BIT(3))
-			pwr2g->bw20_diff[path][i] |= 0xF0;
-	}
-}
-
-static void set_diff1_5g(struct txpower_info_5g *pwr5g, u8 *hwinfo, u32 path,
-			 u32 i, u32 eadr)
-{
-	if (hwinfo[eadr] == 0xFF) {
-		pwr5g->bw40_diff[path][i] = 0xFE;
-	} else {
-		pwr5g->bw40_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
-		if (pwr5g->bw40_diff[path][i] & BIT(3))
-			pwr5g->bw40_diff[path][i] |= 0xF0;
-	}
-
-	if (hwinfo[eadr] == 0xFF) {
-		pwr5g->bw20_diff[path][i] = 0xFE;
-	} else {
-		pwr5g->bw20_diff[path][i] = (hwinfo[eadr] & 0x0f);
-		if (pwr5g->bw20_diff[path][i] & BIT(3))
-			pwr5g->bw20_diff[path][i] |= 0xF0;
-	}
-}
-
-static void set_diff2_2g(struct txpower_info_2g *pwr2g, u8 *hwinfo, u32 path,
-			 u32 i, u32 eadr)
-{
-	if (hwinfo[eadr] == 0xFF) {
-		pwr2g->ofdm_diff[path][i] = 0xFE;
-	} else {
-		pwr2g->ofdm_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
-		if (pwr2g->ofdm_diff[path][i] & BIT(3))
-			pwr2g->ofdm_diff[path][i] |= 0xF0;
-	}
-
-	if (hwinfo[eadr] == 0xFF) {
-		pwr2g->cck_diff[path][i] = 0xFE;
-	} else {
-		pwr2g->cck_diff[path][i] = (hwinfo[eadr]&0x0f);
-		if (pwr2g->cck_diff[path][i] & BIT(3))
-			pwr2g->cck_diff[path][i] |= 0xF0;
-	}
-}
-
-static void _rtl8188e_read_power_value_fromprom(struct ieee80211_hw *hw,
-						struct txpower_info_2g *pwr2g,
-						struct txpower_info_5g *pwr5g,
-						bool autoload_fail,
-						u8 *hwinfo)
+static void read_power_value_fromprom(struct ieee80211_hw *hw,
+				      struct txpower_info_2g *pwrinfo24g,
+				      struct txpower_info_5g *pwrinfo5g,
+				      bool autoload_fail, u8 *hwinfo)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 path, eadr = EEPROM_TX_PWR_INX, i;
+	u32 rfpath, eeaddr = EEPROM_TX_PWR_INX, group, txcnt = 0;
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-		 "hal_ReadPowerValueFromPROM88E(): PROMContent[0x%x]= 0x%x\n",
-		 (eadr+1), hwinfo[eadr+1]);
-	if (0xFF == hwinfo[eadr+1])
+		 "hal_ReadPowerValueFromPROM88E():PROMContent[0x%x]=0x%x\n",
+		 (eeaddr+1), hwinfo[eeaddr+1]);
+	if (0xFF == hwinfo[eeaddr+1])  /*YJ,add,120316*/
 		autoload_fail = true;
 
 	if (autoload_fail) {
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 			 "auto load fail : Use Default value!\n");
-		for (path = 0; path < MAX_RF_PATH; path++) {
+		for (rfpath = 0 ; rfpath < MAX_RF_PATH ; rfpath++) {
 			/* 2.4G default value */
-			for (i = 0; i < MAX_CHNL_GROUP_24G; i++) {
-				pwr2g->index_cck_base[path][i] = 0x2D;
-				pwr2g->index_bw40_base[path][i] = 0x2D;
-			}
-			for (i = 0; i < MAX_TX_COUNT; i++) {
-				if (i == 0) {
-					pwr2g->bw20_diff[path][0] = 0x02;
-					pwr2g->ofdm_diff[path][0] = 0x04;
-				} else {
-					pwr2g->bw20_diff[path][i] = 0xFE;
-					pwr2g->bw40_diff[path][i] = 0xFE;
-					pwr2g->cck_diff[path][i] = 0xFE;
-					pwr2g->ofdm_diff[path][i] = 0xFE;
-				}
-			}
+			set_24g_base(pwrinfo24g, rfpath);
 		}
 		return;
 	}
 
-	for (path = 0; path < MAX_RF_PATH; path++) {
+	for (rfpath = 0 ; rfpath < MAX_RF_PATH ; rfpath++) {
 		/*2.4G default value*/
-		for (i = 0; i < MAX_CHNL_GROUP_24G; i++) {
-			pwr2g->index_cck_base[path][i] = hwinfo[eadr++];
-			if (pwr2g->index_cck_base[path][i] == 0xFF)
-				pwr2g->index_cck_base[path][i] = 0x2D;
+		for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) {
+			pwrinfo24g->index_cck_base[rfpath][group] =
+			  hwinfo[eeaddr++];
+			if (pwrinfo24g->index_cck_base[rfpath][group] == 0xFF)
+				pwrinfo24g->index_cck_base[rfpath][group] =
+				  0x2D;
 		}
-		for (i = 0; i < MAX_CHNL_GROUP_24G; i++) {
-			pwr2g->index_bw40_base[path][i] = hwinfo[eadr++];
-			if (pwr2g->index_bw40_base[path][i] == 0xFF)
-				pwr2g->index_bw40_base[path][i] = 0x2D;
+		for (group = 0 ; group < MAX_CHNL_GROUP_24G-1; group++) {
+			pwrinfo24g->index_bw40_base[rfpath][group] =
+				hwinfo[eeaddr++];
+			if (pwrinfo24g->index_bw40_base[rfpath][group] == 0xFF)
+				pwrinfo24g->index_bw40_base[rfpath][group] =
+					0x2D;
 		}
-		for (i = 0; i < MAX_TX_COUNT; i++) {
-			if (i == 0) {
-				set_diff0_2g(pwr2g, hwinfo, path, i, eadr);
-				eadr++;
-			} else {
-				set_diff1_2g(pwr2g, hwinfo, path, i, eadr);
-				eadr++;
+		pwrinfo24g->bw40_diff[rfpath][0] = 0;
+		if (hwinfo[eeaddr] == 0xFF) {
+			pwrinfo24g->bw20_diff[rfpath][0] = 0x02;
+		} else {
+			pwrinfo24g->bw20_diff[rfpath][0] =
+				(hwinfo[eeaddr]&0xf0)>>4;
+			/*bit sign number to 8 bit sign number*/
+			if (pwrinfo24g->bw20_diff[rfpath][0] & BIT(3))
+				pwrinfo24g->bw20_diff[rfpath][0] |= 0xF0;
+		}
 
-				set_diff2_2g(pwr2g, hwinfo, path, i, eadr);
-				eadr++;
+		if (hwinfo[eeaddr] == 0xFF) {
+			pwrinfo24g->ofdm_diff[rfpath][0] = 0x04;
+		} else {
+			pwrinfo24g->ofdm_diff[rfpath][0] =
+				(hwinfo[eeaddr]&0x0f);
+				/*bit sign number to 8 bit sign number*/
+			if (pwrinfo24g->ofdm_diff[rfpath][0] & BIT(3))
+				pwrinfo24g->ofdm_diff[rfpath][0] |= 0xF0;
+		}
+		pwrinfo24g->cck_diff[rfpath][0] = 0;
+		eeaddr++;
+		for (txcnt = 1; txcnt < MAX_TX_COUNT; txcnt++) {
+			if (hwinfo[eeaddr] == 0xFF) {
+				pwrinfo24g->bw40_diff[rfpath][txcnt] = 0xFE;
+			} else {
+				pwrinfo24g->bw40_diff[rfpath][txcnt] =
+				  (hwinfo[eeaddr]&0xf0)>>4;
+				if (pwrinfo24g->bw40_diff[rfpath][txcnt] &
+				    BIT(3))
+					pwrinfo24g->bw40_diff[rfpath][txcnt] |=
+					  0xF0;
 			}
+
+			if (hwinfo[eeaddr] == 0xFF) {
+				pwrinfo24g->bw20_diff[rfpath][txcnt] =
+					0xFE;
+			} else {
+				pwrinfo24g->bw20_diff[rfpath][txcnt] =
+				  (hwinfo[eeaddr]&0x0f);
+				if (pwrinfo24g->bw20_diff[rfpath][txcnt] &
+				    BIT(3))
+					pwrinfo24g->bw20_diff[rfpath][txcnt] |=
+					  0xF0;
+			}
+			eeaddr++;
+
+			if (hwinfo[eeaddr] == 0xFF) {
+				pwrinfo24g->ofdm_diff[rfpath][txcnt] = 0xFE;
+			} else {
+				pwrinfo24g->ofdm_diff[rfpath][txcnt] =
+				  (hwinfo[eeaddr]&0xf0)>>4;
+				if (pwrinfo24g->ofdm_diff[rfpath][txcnt] &
+				    BIT(3))
+					pwrinfo24g->ofdm_diff[rfpath][txcnt] |=
+					  0xF0;
+			}
+
+			if (hwinfo[eeaddr] == 0xFF) {
+				pwrinfo24g->cck_diff[rfpath][txcnt] =	0xFE;
+			} else {
+				pwrinfo24g->cck_diff[rfpath][txcnt] =
+				  (hwinfo[eeaddr]&0x0f);
+				if (pwrinfo24g->cck_diff[rfpath][txcnt] &
+				    BIT(3))
+					pwrinfo24g->cck_diff[rfpath][txcnt] |=
+					  0xF0;
+			}
+			eeaddr++;
 		}
 
 		/*5G default value*/
-		for (i = 0; i < MAX_CHNL_GROUP_5G; i++) {
-			pwr5g->index_bw40_base[path][i] = hwinfo[eadr++];
-			if (pwr5g->index_bw40_base[path][i] == 0xFF)
-				pwr5g->index_bw40_base[path][i] = 0xFE;
+		for (group = 0 ; group < MAX_CHNL_GROUP_5G; group++) {
+			pwrinfo5g->index_bw40_base[rfpath][group] =
+				hwinfo[eeaddr++];
+			if (pwrinfo5g->index_bw40_base[rfpath][group] == 0xFF)
+				pwrinfo5g->index_bw40_base[rfpath][group] =
+				  0xFE;
 		}
 
-		for (i = 0; i < MAX_TX_COUNT; i++) {
-			if (i == 0) {
-				set_diff0_5g(pwr5g, hwinfo, path, i, eadr);
-				eadr++;
-			} else {
-				set_diff1_5g(pwr5g, hwinfo, path, i, eadr);
-				eadr++;
-			}
-		}
+		pwrinfo5g->bw40_diff[rfpath][0] = 0;
 
-		if (hwinfo[eadr] == 0xFF) {
-			pwr5g->ofdm_diff[path][1] = 0xFE;
-			pwr5g->ofdm_diff[path][2] = 0xFE;
+		if (hwinfo[eeaddr] == 0xFF) {
+			pwrinfo5g->bw20_diff[rfpath][0] = 0;
 		} else {
-			pwr5g->ofdm_diff[path][1] = (hwinfo[eadr] & 0xf0) >> 4;
-			pwr5g->ofdm_diff[path][2] = (hwinfo[eadr] & 0x0f);
+			pwrinfo5g->bw20_diff[rfpath][0] =
+			  (hwinfo[eeaddr]&0xf0)>>4;
+			if (pwrinfo5g->bw20_diff[rfpath][0] & BIT(3))
+				pwrinfo5g->bw20_diff[rfpath][0] |= 0xF0;
 		}
-		eadr++;
 
-		if (hwinfo[eadr] == 0xFF)
-			pwr5g->ofdm_diff[path][3] = 0xFE;
+		if (hwinfo[eeaddr] == 0xFF) {
+			pwrinfo5g->ofdm_diff[rfpath][0] = 0x04;
+		} else {
+			pwrinfo5g->ofdm_diff[rfpath][0] = (hwinfo[eeaddr]&0x0f);
+			if (pwrinfo5g->ofdm_diff[rfpath][0] & BIT(3))
+				pwrinfo5g->ofdm_diff[rfpath][0] |= 0xF0;
+		}
+		eeaddr++;
+		for (txcnt = 1; txcnt < MAX_TX_COUNT; txcnt++) {
+			if (hwinfo[eeaddr] == 0xFF) {
+				pwrinfo5g->bw40_diff[rfpath][txcnt] =	0xFE;
+			} else {
+				pwrinfo5g->bw40_diff[rfpath][txcnt] =
+				  (hwinfo[eeaddr]&0xf0)>>4;
+				if (pwrinfo5g->bw40_diff[rfpath][txcnt] &
+				    BIT(3))
+					pwrinfo5g->bw40_diff[rfpath][txcnt] |=
+					  0xF0;
+			}
+
+			if (hwinfo[eeaddr] == 0xFF) {
+				pwrinfo5g->bw20_diff[rfpath][txcnt] =	0xFE;
+			} else {
+				pwrinfo5g->bw20_diff[rfpath][txcnt] =
+				  (hwinfo[eeaddr]&0x0f);
+				if (pwrinfo5g->bw20_diff[rfpath][txcnt] &
+				    BIT(3))
+					pwrinfo5g->bw20_diff[rfpath][txcnt] |=
+					  0xF0;
+			}
+			eeaddr++;
+		}
+
+		if (hwinfo[eeaddr] == 0xFF) {
+			pwrinfo5g->ofdm_diff[rfpath][1] = 0xFE;
+			pwrinfo5g->ofdm_diff[rfpath][2] = 0xFE;
+		} else {
+			pwrinfo5g->ofdm_diff[rfpath][1] =
+					(hwinfo[eeaddr]&0xf0)>>4;
+			pwrinfo5g->ofdm_diff[rfpath][2] =
+					(hwinfo[eeaddr]&0x0f);
+		}
+		eeaddr++;
+
+		if (hwinfo[eeaddr] == 0xFF)
+			pwrinfo5g->ofdm_diff[rfpath][3] = 0xFE;
 		else
-			pwr5g->ofdm_diff[path][3] = (hwinfo[eadr]&0x0f);
-		eadr++;
+			pwrinfo5g->ofdm_diff[rfpath][3] = (hwinfo[eeaddr]&0x0f);
+		eeaddr++;
 
-		for (i = 1; i < MAX_TX_COUNT; i++) {
-			if (pwr5g->ofdm_diff[path][i] == 0xFF)
-				pwr5g->ofdm_diff[path][i] = 0xFE;
-			else if (pwr5g->ofdm_diff[path][i] & BIT(3))
-				pwr5g->ofdm_diff[path][i] |= 0xF0;
+		for (txcnt = 1; txcnt < MAX_TX_COUNT; txcnt++) {
+			if (pwrinfo5g->ofdm_diff[rfpath][txcnt] == 0xFF)
+				pwrinfo5g->ofdm_diff[rfpath][txcnt] =	0xFE;
+			else if (pwrinfo5g->ofdm_diff[rfpath][txcnt] & BIT(3))
+				pwrinfo5g->ofdm_diff[rfpath][txcnt] |= 0xF0;
 		}
 	}
 }
@@ -1712,41 +1791,36 @@
 	struct txpower_info_5g pwrinfo5g;
 	u8 rf_path, index;
 	u8 i;
-	int jj = EEPROM_RF_BOARD_OPTION_88E;
-	int kk = EEPROM_THERMAL_METER_88E;
 
-	_rtl8188e_read_power_value_fromprom(hw, &pwrinfo24g, &pwrinfo5g,
-					    autoload_fail, hwinfo);
+	read_power_value_fromprom(hw, &pwrinfo24g,
+				  &pwrinfo5g, autoload_fail, hwinfo);
 
 	for (rf_path = 0; rf_path < 2; rf_path++) {
 		for (i = 0; i < 14; i++) {
-			index = get_chnl_group(i+1);
+			index = _rtl88e_get_chnl_group(i+1);
 
 			rtlefuse->txpwrlevel_cck[rf_path][i] =
-				 pwrinfo24g.index_cck_base[rf_path][index];
-			if (i == 13)
-				rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
-				     pwrinfo24g.index_bw40_base[rf_path][4];
-			else
-				rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
-				     pwrinfo24g.index_bw40_base[rf_path][index];
+				pwrinfo24g.index_cck_base[rf_path][index];
+			rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+				pwrinfo24g.index_bw40_base[rf_path][index];
 			rtlefuse->txpwr_ht20diff[rf_path][i] =
-				 pwrinfo24g.bw20_diff[rf_path][0];
+				pwrinfo24g.bw20_diff[rf_path][0];
 			rtlefuse->txpwr_legacyhtdiff[rf_path][i] =
-				 pwrinfo24g.ofdm_diff[rf_path][0];
+				pwrinfo24g.ofdm_diff[rf_path][0];
 		}
 
 		for (i = 0; i < 14; i++) {
 			RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
-				"RF(%d)-Ch(%d) [CCK / HT40_1S ] = "
-				"[0x%x / 0x%x ]\n", rf_path, i,
+				"RF(%d)-Ch(%d) [CCK / HT40_1S ] = [0x%x / 0x%x ]\n",
+				rf_path, i,
 				rtlefuse->txpwrlevel_cck[rf_path][i],
 				rtlefuse->txpwrlevel_ht40_1s[rf_path][i]);
 		}
 	}
 
 	if (!autoload_fail)
-		rtlefuse->eeprom_thermalmeter = hwinfo[kk];
+		rtlefuse->eeprom_thermalmeter =
+			hwinfo[EEPROM_THERMAL_METER_88E];
 	else
 		rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER;
 
@@ -1760,8 +1834,9 @@
 		"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
 
 	if (!autoload_fail) {
-		rtlefuse->eeprom_regulatory = hwinfo[jj] & 0x07;/*bit0~2*/
-		if (hwinfo[jj] == 0xFF)
+		rtlefuse->eeprom_regulatory =
+			hwinfo[EEPROM_RF_BOARD_OPTION_88E] & 0x07;/*bit0~2*/
+		if (hwinfo[EEPROM_RF_BOARD_OPTION_88E] == 0xFF)
 			rtlefuse->eeprom_regulatory = 0;
 	} else {
 		rtlefuse->eeprom_regulatory = 0;
@@ -1775,12 +1850,9 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
 	u16 i, usvalue;
 	u8 hwinfo[HWSET_MAX_SIZE];
 	u16 eeprom_id;
-	int jj = EEPROM_RF_BOARD_OPTION_88E;
-	int kk = EEPROM_RF_FEATURE_OPTION_88E;
 
 	if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
 		rtl_efuse_shadow_map_update(hw);
@@ -1790,9 +1862,14 @@
 	} else if (rtlefuse->epromtype == EEPROM_93C46) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 "RTL819X Not boot from eeprom, check it !!");
+		return;
+	} else {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "boot from neither eeprom nor efuse, check it !!");
+		return;
 	}
 
-	RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"),
+	RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP\n",
 		      hwinfo, HWSET_MAX_SIZE);
 
 	eeprom_id = *((u16 *)&hwinfo[0]);
@@ -1825,7 +1902,7 @@
 	/*customer ID*/
 	rtlefuse->eeprom_oemid = hwinfo[EEPROM_CUSTOMER_ID];
 	if (rtlefuse->eeprom_oemid == 0xFF)
-		rtlefuse->eeprom_oemid = 0;
+		rtlefuse->eeprom_oemid =	0;
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 		 "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
@@ -1844,34 +1921,40 @@
 	/* set channel paln to world wide 13 */
 	rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
 	/*tx power*/
-	_rtl88ee_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag,
+	_rtl88ee_read_txpower_info_from_hwpg(hw,
+					     rtlefuse->autoload_failflag,
 					     hwinfo);
 	rtlefuse->txpwr_fromeprom = true;
 
 	rtl8188ee_read_bt_coexist_info_from_hwpg(hw,
 						 rtlefuse->autoload_failflag,
 						 hwinfo);
+
 	/*board type*/
-	rtlefuse->board_type = (hwinfo[jj] & 0xE0) >> 5;
+	rtlefuse->board_type =
+		((hwinfo[EEPROM_RF_BOARD_OPTION_88E] & 0xE0) >> 5);
+	rtlhal->board_type = rtlefuse->board_type;
 	/*Wake on wlan*/
-	rtlefuse->wowlan_enable = ((hwinfo[kk] & 0x40) >> 6);
+	rtlefuse->wowlan_enable =
+		((hwinfo[EEPROM_RF_FEATURE_OPTION_88E] & 0x40) >> 6);
 	/*parse xtal*/
 	rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_88E];
 	if (hwinfo[EEPROM_XTAL_88E])
 		rtlefuse->crystalcap = 0x20;
 	/*antenna diversity*/
-	rtlefuse->antenna_div_cfg = (hwinfo[jj] & 0x18) >> 3;
-	if (hwinfo[jj] == 0xFF)
+	rtlefuse->antenna_div_cfg =
+		(hwinfo[EEPROM_RF_BOARD_OPTION_88E] & 0x18) >> 3;
+	if (hwinfo[EEPROM_RF_BOARD_OPTION_88E] == 0xFF)
 		rtlefuse->antenna_div_cfg = 0;
-	if (rppriv->bt_coexist.eeprom_bt_coexist != 0 &&
-	    rppriv->bt_coexist.eeprom_bt_ant_num == ANT_X1)
+	if (rtlpriv->btcoexist.eeprom_bt_coexist != 0 &&
+	    rtlpriv->btcoexist.eeprom_bt_ant_num == ANT_X1)
 		rtlefuse->antenna_div_cfg = 0;
 
 	rtlefuse->antenna_div_type = hwinfo[EEPROM_RF_ANTENNA_OPT_88E];
 	if (rtlefuse->antenna_div_type == 0xFF)
 		rtlefuse->antenna_div_type = 0x01;
 	if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV ||
-	    rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+		rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
 		rtlefuse->antenna_div_cfg = 1;
 
 	if (rtlhal->oem_id == RT_CID_DEFAULT) {
@@ -1881,12 +1964,12 @@
 				if (rtlefuse->eeprom_svid == 0x1025) {
 					rtlhal->oem_id = RT_CID_819X_ACER;
 				} else if ((rtlefuse->eeprom_svid == 0x10EC &&
-					    rtlefuse->eeprom_smid == 0x0179) ||
-					    (rtlefuse->eeprom_svid == 0x17AA &&
-					    rtlefuse->eeprom_smid == 0x0179)) {
+				     rtlefuse->eeprom_smid == 0x0179) ||
+				     (rtlefuse->eeprom_svid == 0x17AA &&
+				     rtlefuse->eeprom_smid == 0x0179)) {
 					rtlhal->oem_id = RT_CID_819X_LENOVO;
 				} else if (rtlefuse->eeprom_svid == 0x103c &&
-					 rtlefuse->eeprom_smid == 0x197d) {
+					   rtlefuse->eeprom_smid == 0x197d) {
 					rtlhal->oem_id = RT_CID_819X_HP;
 				} else {
 					rtlhal->oem_id = RT_CID_DEFAULT;
@@ -1905,6 +1988,7 @@
 		default:
 			rtlhal->oem_id = RT_CID_DEFAULT;
 			break;
+
 		}
 	}
 }
@@ -1943,14 +2027,13 @@
 	u8 tmp_u1b;
 
 	rtlhal->version = _rtl88ee_read_chip_version(hw);
-	if (get_rf_type(rtlphy) == RF_1T1R) {
+	if (get_rf_type(rtlphy) == RF_1T1R)
 		rtlpriv->dm.rfpath_rxenable[0] = true;
-	} else {
-		rtlpriv->dm.rfpath_rxenable[0] = true;
-		rtlpriv->dm.rfpath_rxenable[1] = true;
-	}
+	else
+		rtlpriv->dm.rfpath_rxenable[0] =
+		    rtlpriv->dm.rfpath_rxenable[1] = true;
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n",
-		 rtlhal->version);
+						rtlhal->version);
 	tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR);
 	if (tmp_u1b & BIT(4)) {
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n");
@@ -1970,24 +2053,25 @@
 }
 
 static void rtl88ee_update_hal_rate_table(struct ieee80211_hw *hw,
-					  struct ieee80211_sta *sta)
+		struct ieee80211_sta *sta)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u32 ratr_value;
 	u8 ratr_index = 0;
-	u8 nmode = mac->ht_enable;
-	u8 mimo_ps = IEEE80211_SMPS_OFF;
+	u8 b_nmode = mac->ht_enable;
+	/*u8 mimo_ps = IEEE80211_SMPS_OFF;*/
 	u16 shortgi_rate;
 	u32 tmp_ratr_value;
-	u8 ctx40 = mac->bw_40;
-	u16 cap = sta->ht_cap.cap;
-	u8 short40 = (cap & IEEE80211_HT_CAP_SGI_40) ?  1 : 0;
-	u8 short20 = (cap & IEEE80211_HT_CAP_SGI_20) ?  1 : 0;
+	u8 curtxbw_40mhz = mac->bw_40;
+	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+				1 : 0;
+	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+				1 : 0;
 	enum wireless_mode wirelessmode = mac->mode;
+	u32 ratr_mask;
 
 	if (rtlhal->current_bandtype == BAND_ON_5G)
 		ratr_value = sta->supp_rates[1] << 4;
@@ -1996,7 +2080,7 @@
 	if (mac->opmode == NL80211_IFTYPE_ADHOC)
 		ratr_value = 0xfff;
 	ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
-			sta->ht_cap.mcs.rx_mask[0] << 12);
+		       sta->ht_cap.mcs.rx_mask[0] << 12);
 	switch (wirelessmode) {
 	case WIRELESS_MODE_B:
 		if (ratr_value & 0x0000000c)
@@ -2009,20 +2093,14 @@
 		break;
 	case WIRELESS_MODE_N_24G:
 	case WIRELESS_MODE_N_5G:
-		nmode = 1;
-		if (mimo_ps == IEEE80211_SMPS_STATIC) {
-			ratr_value &= 0x0007F005;
-		} else {
-			u32 ratr_mask;
+		b_nmode = 1;
+		if (get_rf_type(rtlphy) == RF_1T2R ||
+		    get_rf_type(rtlphy) == RF_1T1R)
+			ratr_mask = 0x000ff005;
+		else
+			ratr_mask = 0x0f0ff005;
 
-			if (get_rf_type(rtlphy) == RF_1T2R ||
-			    get_rf_type(rtlphy) == RF_1T1R)
-				ratr_mask = 0x000ff005;
-			else
-				ratr_mask = 0x0f0ff005;
-
-			ratr_value &= ratr_mask;
-		}
+		ratr_value &= ratr_mask;
 		break;
 	default:
 		if (rtlphy->rf_type == RF_1T2R)
@@ -2033,18 +2111,19 @@
 		break;
 	}
 
-	if ((rppriv->bt_coexist.bt_coexistence) &&
-	    (rppriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) &&
-	    (rppriv->bt_coexist.bt_cur_state) &&
-	    (rppriv->bt_coexist.bt_ant_isolation) &&
-	    ((rppriv->bt_coexist.bt_service == BT_SCO) ||
-	    (rppriv->bt_coexist.bt_service == BT_BUSY)))
+	if ((rtlpriv->btcoexist.bt_coexistence) &&
+	    (rtlpriv->btcoexist.bt_coexist_type == BT_CSR_BC4) &&
+	    (rtlpriv->btcoexist.bt_cur_state) &&
+	    (rtlpriv->btcoexist.bt_ant_isolation) &&
+	    ((rtlpriv->btcoexist.bt_service == BT_SCO) ||
+	     (rtlpriv->btcoexist.bt_service == BT_BUSY)))
 		ratr_value &= 0x0fffcfc0;
 	else
 		ratr_value &= 0x0FFFFFFF;
 
-	if (nmode && ((ctx40 && short40) ||
-		      (!ctx40 && short20))) {
+	if (b_nmode &&
+	    ((curtxbw_40mhz && curshortgi_40mhz) ||
+	     (!curtxbw_40mhz && curshortgi_20mhz))) {
 		ratr_value |= 0x10000000;
 		tmp_ratr_value = (ratr_value >> 12);
 
@@ -2064,7 +2143,7 @@
 }
 
 static void rtl88ee_update_hal_rate_mask(struct ieee80211_hw *hw,
-					 struct ieee80211_sta *sta, u8 rssi)
+		struct ieee80211_sta *sta, u8 rssi_level)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -2073,23 +2152,25 @@
 	struct rtl_sta_info *sta_entry = NULL;
 	u32 ratr_bitmap;
 	u8 ratr_index;
-	u16 cap = sta->ht_cap.cap;
-	u8 ctx40 = (cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0;
-	u8 short40 = (cap & IEEE80211_HT_CAP_SGI_40) ?  1 : 0;
-	u8 short20 = (cap & IEEE80211_HT_CAP_SGI_20) ?  1 : 0;
+	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+				? 1 : 0;
+	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+				1 : 0;
+	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+				1 : 0;
 	enum wireless_mode wirelessmode = 0;
-	bool shortgi = false;
+	bool b_shortgi = false;
 	u8 rate_mask[5];
 	u8 macid = 0;
-	u8 mimo_ps = IEEE80211_SMPS_OFF;
+	/*u8 mimo_ps = IEEE80211_SMPS_OFF;*/
 
 	sta_entry = (struct rtl_sta_info *)sta->drv_priv;
 	wirelessmode = sta_entry->wireless_mode;
 	if (mac->opmode == NL80211_IFTYPE_STATION ||
-	    mac->opmode == NL80211_IFTYPE_MESH_POINT)
-		ctx40 = mac->bw_40;
+		mac->opmode == NL80211_IFTYPE_MESH_POINT)
+		curtxbw_40mhz = mac->bw_40;
 	else if (mac->opmode == NL80211_IFTYPE_AP ||
-		 mac->opmode == NL80211_IFTYPE_ADHOC)
+		mac->opmode == NL80211_IFTYPE_ADHOC)
 		macid = sta->aid + 1;
 
 	if (rtlhal->current_bandtype == BAND_ON_5G)
@@ -2111,70 +2192,59 @@
 	case WIRELESS_MODE_G:
 		ratr_index = RATR_INX_WIRELESS_GB;
 
-		if (rssi == 1)
+		if (rssi_level == 1)
 			ratr_bitmap &= 0x00000f00;
-		else if (rssi == 2)
+		else if (rssi_level == 2)
 			ratr_bitmap &= 0x00000ff0;
 		else
 			ratr_bitmap &= 0x00000ff5;
 		break;
-	case WIRELESS_MODE_A:
-		ratr_index = RATR_INX_WIRELESS_A;
-		ratr_bitmap &= 0x00000ff0;
-		break;
 	case WIRELESS_MODE_N_24G:
 	case WIRELESS_MODE_N_5G:
 		ratr_index = RATR_INX_WIRELESS_NGB;
-
-		if (mimo_ps == IEEE80211_SMPS_STATIC) {
-			if (rssi == 1)
-				ratr_bitmap &= 0x00070000;
-			else if (rssi == 2)
-				ratr_bitmap &= 0x0007f000;
-			else
-				ratr_bitmap &= 0x0007f005;
-		} else {
-			if (rtlphy->rf_type == RF_1T2R ||
-			    rtlphy->rf_type == RF_1T1R) {
-				if (ctx40) {
-					if (rssi == 1)
-						ratr_bitmap &= 0x000f0000;
-					else if (rssi == 2)
-						ratr_bitmap &= 0x000ff000;
-					else
-						ratr_bitmap &= 0x000ff015;
-				} else {
-					if (rssi == 1)
-						ratr_bitmap &= 0x000f0000;
-					else if (rssi == 2)
-						ratr_bitmap &= 0x000ff000;
-					else
-						ratr_bitmap &= 0x000ff005;
-				}
+		if (rtlphy->rf_type == RF_1T2R ||
+		    rtlphy->rf_type == RF_1T1R) {
+			if (curtxbw_40mhz) {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x000f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x000ff000;
+				else
+					ratr_bitmap &= 0x000ff015;
 			} else {
-				if (ctx40) {
-					if (rssi == 1)
-						ratr_bitmap &= 0x0f8f0000;
-					else if (rssi == 2)
-						ratr_bitmap &= 0x0f8ff000;
-					else
-						ratr_bitmap &= 0x0f8ff015;
-				} else {
-					if (rssi == 1)
-						ratr_bitmap &= 0x0f8f0000;
-					else if (rssi == 2)
-						ratr_bitmap &= 0x0f8ff000;
-					else
-						ratr_bitmap &= 0x0f8ff005;
-				}
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x000f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x000ff000;
+				else
+					ratr_bitmap &= 0x000ff005;
+			}
+		} else {
+			if (curtxbw_40mhz) {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x0f8f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x0f8ff000;
+				else
+					ratr_bitmap &= 0x0f8ff015;
+			} else {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x0f8f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x0f8ff000;
+				else
+					ratr_bitmap &= 0x0f8ff005;
 			}
 		}
+		/*}*/
 
-		if ((ctx40 && short40) || (!ctx40 && short20)) {
+		if ((curtxbw_40mhz && curshortgi_40mhz) ||
+		    (!curtxbw_40mhz && curshortgi_20mhz)) {
+
 			if (macid == 0)
-				shortgi = true;
+				b_shortgi = true;
 			else if (macid == 1)
-				shortgi = false;
+				b_shortgi = false;
 		}
 		break;
 	default:
@@ -2192,22 +2262,24 @@
 		 "ratr_bitmap :%x\n", ratr_bitmap);
 	*(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
 			     (ratr_index << 28);
-	rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
+	rate_mask[4] = macid | (b_shortgi ? 0x20 : 0x00) | 0x80;
 	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
 		 "Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x\n",
-		 ratr_index, ratr_bitmap, rate_mask[0], rate_mask[1],
-		 rate_mask[2], rate_mask[3], rate_mask[4]);
+		 ratr_index, ratr_bitmap,
+		 rate_mask[0], rate_mask[1],
+		 rate_mask[2], rate_mask[3],
+		 rate_mask[4]);
 	rtl88e_fill_h2c_cmd(hw, H2C_88E_RA_MASK, 5, rate_mask);
 	_rtl88ee_set_bcn_ctrl_reg(hw, BIT(3), 0);
 }
 
 void rtl88ee_update_hal_rate_tbl(struct ieee80211_hw *hw,
-		struct ieee80211_sta *sta, u8 rssi)
+		struct ieee80211_sta *sta, u8 rssi_level)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	if (rtlpriv->dm.useramask)
-		rtl88ee_update_hal_rate_mask(hw, sta, rssi);
+		rtl88ee_update_hal_rate_mask(hw, sta, rssi_level);
 	else
 		rtl88ee_update_hal_rate_table(hw, sta);
 }
@@ -2230,9 +2302,9 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-	enum rf_pwrstate state_toset;
+	enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;
 	u32 u4tmp;
-	bool actuallyset = false;
+	bool b_actuallyset = false;
 
 	if (rtlpriv->rtlhal.being_init_adapter)
 		return false;
@@ -2249,27 +2321,29 @@
 		spin_unlock(&rtlpriv->locks.rf_ps_lock);
 	}
 
+	cur_rfstate = ppsc->rfpwr_state;
+
 	u4tmp = rtl_read_dword(rtlpriv, REG_GPIO_OUTPUT);
-	state_toset = (u4tmp & BIT(31)) ? ERFON : ERFOFF;
+	e_rfpowerstate_toset = (u4tmp & BIT(31)) ? ERFON : ERFOFF;
 
-
-	if ((ppsc->hwradiooff == true) && (state_toset == ERFON)) {
+	if (ppsc->hwradiooff && (e_rfpowerstate_toset == ERFON)) {
 		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 			 "GPIOChangeRF  - HW Radio ON, RF ON\n");
 
-		state_toset = ERFON;
+		e_rfpowerstate_toset = ERFON;
 		ppsc->hwradiooff = false;
-		actuallyset = true;
-	} else if ((ppsc->hwradiooff == false) && (state_toset == ERFOFF)) {
+		b_actuallyset = true;
+	} else if ((!ppsc->hwradiooff) &&
+		   (e_rfpowerstate_toset == ERFOFF)) {
 		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 			 "GPIOChangeRF  - HW Radio OFF, RF OFF\n");
 
-		state_toset = ERFOFF;
+		e_rfpowerstate_toset = ERFOFF;
 		ppsc->hwradiooff = true;
-		actuallyset = true;
+		b_actuallyset = true;
 	}
 
-	if (actuallyset) {
+	if (b_actuallyset) {
 		spin_lock(&rtlpriv->locks.rf_ps_lock);
 		ppsc->rfchange_inprogress = false;
 		spin_unlock(&rtlpriv->locks.rf_ps_lock);
@@ -2284,50 +2358,19 @@
 
 	*valid = 1;
 	return !ppsc->hwradiooff;
+
 }
 
-static void add_one_key(struct ieee80211_hw *hw, u8 *macaddr,
-			struct rtl_mac *mac, u32 key, u32 id,
-			u8 enc_algo, bool is_pairwise)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
-
-	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "add one entry\n");
-	if (is_pairwise) {
-		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "set Pairwise key\n");
-
-		rtl_cam_add_one_entry(hw, macaddr, key, id, enc_algo,
-				      CAM_CONFIG_NO_USEDK,
-				      rtlpriv->sec.key_buf[key]);
-	} else {
-		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "set group key\n");
-
-		if (mac->opmode == NL80211_IFTYPE_ADHOC) {
-			rtl_cam_add_one_entry(hw, rtlefuse->dev_addr,
-					      PAIRWISE_KEYIDX,
-					      CAM_PAIRWISE_KEY_POSITION,
-					      enc_algo,
-					      CAM_CONFIG_NO_USEDK,
-					      rtlpriv->sec.key_buf[id]);
-		}
-
-		rtl_cam_add_one_entry(hw, macaddr, key, id, enc_algo,
-				      CAM_CONFIG_NO_USEDK,
-				      rtlpriv->sec.key_buf[id]);
-	}
-}
-
-void rtl88ee_set_key(struct ieee80211_hw *hw, u32 key,
-		     u8 *mac_ad, bool is_group, u8 enc_algo,
+void rtl88ee_set_key(struct ieee80211_hw *hw, u32 key_index,
+		     u8 *p_macaddr, bool is_group, u8 enc_algo,
 		     bool is_wepkey, bool clear_all)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	u8 *macaddr = mac_ad;
-	u32 id = 0;
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	u8 *macaddr = p_macaddr;
+	u32 entry_id = 0;
 	bool is_pairwise = false;
-
 	static u8 cam_const_addr[4][6] = {
 		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
 		{0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
@@ -2372,122 +2415,176 @@
 			break;
 		default:
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
+				 "switch case not process\n");
 			enc_algo = CAM_TKIP;
 			break;
 		}
 
 		if (is_wepkey || rtlpriv->sec.use_defaultkey) {
-			macaddr = cam_const_addr[key];
-			id = key;
+			macaddr = cam_const_addr[key_index];
+			entry_id = key_index;
 		} else {
 			if (is_group) {
 				macaddr = cam_const_broad;
-				id = key;
+				entry_id = key_index;
 			} else {
 				if (mac->opmode == NL80211_IFTYPE_AP ||
 				    mac->opmode == NL80211_IFTYPE_MESH_POINT) {
-					id = rtl_cam_get_free_entry(hw, mac_ad);
-					if (id >=  TOTAL_CAM_ENTRY) {
+					entry_id =
+					  rtl_cam_get_free_entry(hw, p_macaddr);
+					if (entry_id >=  TOTAL_CAM_ENTRY) {
 						RT_TRACE(rtlpriv, COMP_SEC,
 							 DBG_EMERG,
 							 "Can not find free hw security cam entry\n");
 						return;
 					}
 				} else {
-					id = CAM_PAIRWISE_KEY_POSITION;
+					entry_id = CAM_PAIRWISE_KEY_POSITION;
 				}
-
-				key = PAIRWISE_KEYIDX;
+				key_index = PAIRWISE_KEYIDX;
 				is_pairwise = true;
 			}
 		}
 
-		if (rtlpriv->sec.key_len[key] == 0) {
+		if (rtlpriv->sec.key_len[key_index] == 0) {
 			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
-				 "delete one entry, id is %d\n", id);
+				 "delete one entry, entry_id is %d\n",
+				 entry_id);
 			if (mac->opmode == NL80211_IFTYPE_AP ||
-			    mac->opmode == NL80211_IFTYPE_MESH_POINT)
-				rtl_cam_del_entry(hw, mac_ad);
-			rtl_cam_delete_one_entry(hw, mac_ad, id);
+				mac->opmode == NL80211_IFTYPE_MESH_POINT)
+				rtl_cam_del_entry(hw, p_macaddr);
+			rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
 		} else {
-			add_one_key(hw, macaddr, mac, key, id, enc_algo,
-				    is_pairwise);
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+				 "add one entry\n");
+			if (is_pairwise) {
+				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+					 "set Pairwise key\n");
+
+				rtl_cam_add_one_entry(hw, macaddr, key_index,
+						      entry_id, enc_algo,
+						      CAM_CONFIG_NO_USEDK,
+						      rtlpriv->sec.key_buf[key_index]);
+			} else {
+				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+					 "set group key\n");
+
+				if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+					rtl_cam_add_one_entry(hw,
+							rtlefuse->dev_addr,
+							PAIRWISE_KEYIDX,
+							CAM_PAIRWISE_KEY_POSITION,
+							enc_algo,
+							CAM_CONFIG_NO_USEDK,
+							rtlpriv->sec.key_buf
+							[entry_id]);
+				}
+
+				rtl_cam_add_one_entry(hw, macaddr, key_index,
+						      entry_id, enc_algo,
+						      CAM_CONFIG_NO_USEDK,
+						      rtlpriv->sec.key_buf[entry_id]);
+			}
+
 		}
 	}
 }
 
 static void rtl8188ee_bt_var_init(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
-	struct bt_coexist_info coexist = rppriv->bt_coexist;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-	coexist.bt_coexistence = rppriv->bt_coexist.eeprom_bt_coexist;
-	coexist.bt_ant_num = coexist.eeprom_bt_ant_num;
-	coexist.bt_coexist_type = coexist.eeprom_bt_type;
+	rtlpriv->btcoexist.bt_coexistence =
+		rtlpriv->btcoexist.eeprom_bt_coexist;
+	rtlpriv->btcoexist.bt_ant_num = rtlpriv->btcoexist.eeprom_bt_ant_num;
+	rtlpriv->btcoexist.bt_coexist_type = rtlpriv->btcoexist.eeprom_bt_type;
 
-	if (coexist.reg_bt_iso == 2)
-		coexist.bt_ant_isolation = coexist.eeprom_bt_ant_isol;
+	if (rtlpriv->btcoexist.reg_bt_iso == 2)
+		rtlpriv->btcoexist.bt_ant_isolation =
+				rtlpriv->btcoexist.eeprom_bt_ant_isol;
 	else
-		coexist.bt_ant_isolation = coexist.reg_bt_iso;
+		rtlpriv->btcoexist.bt_ant_isolation =
+				rtlpriv->btcoexist.reg_bt_iso;
 
-	coexist.bt_radio_shared_type = coexist.eeprom_bt_radio_shared;
+	rtlpriv->btcoexist.bt_radio_shared_type =
+		rtlpriv->btcoexist.eeprom_bt_radio_shared;
 
-	if (coexist.bt_coexistence) {
-		if (coexist.reg_bt_sco == 1)
-			coexist.bt_service = BT_OTHER_ACTION;
-		else if (coexist.reg_bt_sco == 2)
-			coexist.bt_service = BT_SCO;
-		else if (coexist.reg_bt_sco == 4)
-			coexist.bt_service = BT_BUSY;
-		else if (coexist.reg_bt_sco == 5)
-			coexist.bt_service = BT_OTHERBUSY;
+	if (rtlpriv->btcoexist.bt_coexistence) {
+		if (rtlpriv->btcoexist.reg_bt_sco == 1)
+			rtlpriv->btcoexist.bt_service = BT_OTHER_ACTION;
+		else if (rtlpriv->btcoexist.reg_bt_sco == 2)
+			rtlpriv->btcoexist.bt_service = BT_SCO;
+		else if (rtlpriv->btcoexist.reg_bt_sco == 4)
+			rtlpriv->btcoexist.bt_service = BT_BUSY;
+		else if (rtlpriv->btcoexist.reg_bt_sco == 5)
+			rtlpriv->btcoexist.bt_service = BT_OTHERBUSY;
 		else
-			coexist.bt_service = BT_IDLE;
+			rtlpriv->btcoexist.bt_service = BT_IDLE;
 
-		coexist.bt_edca_ul = 0;
-		coexist.bt_edca_dl = 0;
-		coexist.bt_rssi_state = 0xff;
+		rtlpriv->btcoexist.bt_edca_ul = 0;
+		rtlpriv->btcoexist.bt_edca_dl = 0;
+		rtlpriv->btcoexist.bt_rssi_state = 0xff;
 	}
 }
 
 void rtl8188ee_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
 					      bool auto_load_fail, u8 *hwinfo)
 {
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 value;
+
+	if (!auto_load_fail) {
+		rtlpriv->btcoexist.eeprom_bt_coexist =
+			((hwinfo[EEPROM_RF_FEATURE_OPTION_88E] & 0xe0) >> 5);
+		if (hwinfo[EEPROM_RF_FEATURE_OPTION_88E] == 0xFF)
+			rtlpriv->btcoexist.eeprom_bt_coexist  = 0;
+		value = hwinfo[EEPROM_RF_BT_SETTING_88E];
+		rtlpriv->btcoexist.eeprom_bt_type = ((value & 0xe) >> 1);
+		rtlpriv->btcoexist.eeprom_bt_ant_num = (value & 0x1);
+		rtlpriv->btcoexist.eeprom_bt_ant_isol = ((value & 0x10) >> 4);
+		rtlpriv->btcoexist.eeprom_bt_radio_shared =
+				 ((value & 0x20) >> 5);
+	} else {
+		rtlpriv->btcoexist.eeprom_bt_coexist = 0;
+		rtlpriv->btcoexist.eeprom_bt_type = BT_2WIRE;
+		rtlpriv->btcoexist.eeprom_bt_ant_num = ANT_X2;
+		rtlpriv->btcoexist.eeprom_bt_ant_isol = 0;
+		rtlpriv->btcoexist.eeprom_bt_radio_shared = BT_RADIO_SHARED;
+	}
+
 	rtl8188ee_bt_var_init(hw);
 }
 
 void rtl8188ee_bt_reg_init(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	/* 0:Low, 1:High, 2:From Efuse. */
-	rppriv->bt_coexist.reg_bt_iso = 2;
+	rtlpriv->btcoexist.reg_bt_iso = 2;
 	/* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */
-	rppriv->bt_coexist.reg_bt_sco = 3;
+	rtlpriv->btcoexist.reg_bt_sco = 3;
 	/* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
-	rppriv->bt_coexist.reg_bt_sco = 0;
+	rtlpriv->btcoexist.reg_bt_sco = 0;
 }
 
 void rtl8188ee_bt_hw_init(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
-	struct bt_coexist_info coexist = rppriv->bt_coexist;
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	u8 u1_tmp;
 
-	if (coexist.bt_coexistence &&
-	    ((coexist.bt_coexist_type == BT_CSR_BC4) ||
-	      coexist.bt_coexist_type == BT_CSR_BC8)) {
-		if (coexist.bt_ant_isolation)
+	if (rtlpriv->btcoexist.bt_coexistence &&
+	    ((rtlpriv->btcoexist.bt_coexist_type == BT_CSR_BC4) ||
+	      rtlpriv->btcoexist.bt_coexist_type == BT_CSR_BC8)) {
+		if (rtlpriv->btcoexist.bt_ant_isolation)
 			rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
 
 		u1_tmp = rtl_read_byte(rtlpriv, 0x4fd) &
-				       BIT_OFFSET_LEN_MASK_32(0, 1);
-		u1_tmp = u1_tmp | ((coexist.bt_ant_isolation == 1) ?
+			 BIT_OFFSET_LEN_MASK_32(0, 1);
+		u1_tmp = u1_tmp |
+			 ((rtlpriv->btcoexist.bt_ant_isolation == 1) ?
 			 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) |
-			 ((coexist.bt_service == BT_SCO) ?
+			 ((rtlpriv->btcoexist.bt_service == BT_SCO) ?
 			 0 : BIT_OFFSET_LEN_MASK_32(2, 1));
 		rtl_write_byte(rtlpriv, 0x4fd, u1_tmp);
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/led.c b/drivers/net/wireless/rtlwifi/rtl8188ee/led.c
index c81a9cb..b504bd0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/led.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/led.c
@@ -32,8 +32,8 @@
 #include "reg.h"
 #include "led.h"
 
-static void rtl88ee_init_led(struct ieee80211_hw *hw,
-			     struct rtl_led *pled, enum rtl_led_pin ledpin)
+static void _rtl88ee_init_led(struct ieee80211_hw *hw,
+			      struct rtl_led *pled, enum rtl_led_pin ledpin)
 {
 	pled->hw = hw;
 	pled->ledpin = ledpin;
@@ -46,23 +46,23 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
-		 "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin);
+		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
 
 	switch (pled->ledpin) {
 	case LED_PIN_GPIO0:
 		break;
 	case LED_PIN_LED0:
 		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
-		rtl_write_byte(rtlpriv, REG_LEDCFG2,
-			       (ledcfg & 0xf0) | BIT(5) | BIT(6));
+		rtl_write_byte(rtlpriv,
+			       REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5) | BIT(6));
 		break;
 	case LED_PIN_LED1:
 		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
 		rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg & 0x10);
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not processed\n");
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
 		break;
 	}
 	pled->ledon = true;
@@ -73,10 +73,9 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	u8 ledcfg;
-	u8 val;
 
 	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
-		 "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin);
+		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
 
 	switch (pled->ledpin) {
 	case LED_PIN_GPIO0:
@@ -84,15 +83,15 @@
 	case LED_PIN_LED0:
 		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
 		ledcfg &= 0xf0;
-		val = ledcfg | BIT(3) | BIT(5) | BIT(6);
-		if (pcipriv->ledctl.led_opendrain == true) {
-			rtl_write_byte(rtlpriv, REG_LEDCFG2, val);
+		if (pcipriv->ledctl.led_opendrain) {
+			rtl_write_byte(rtlpriv, REG_LEDCFG2,
+				       (ledcfg | BIT(3) | BIT(5) | BIT(6)));
 			ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG);
-			val = ledcfg & 0xFE;
-			rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, val);
-		} else {
-			rtl_write_byte(rtlpriv, REG_LEDCFG2, val);
-		}
+			rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG,
+				       (ledcfg & 0xFE));
+		} else
+			rtl_write_byte(rtlpriv, REG_LEDCFG2,
+				       (ledcfg | BIT(3) | BIT(5) | BIT(6)));
 		break;
 	case LED_PIN_LED1:
 		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
@@ -100,8 +99,8 @@
 		rtl_write_byte(rtlpriv, REG_LEDCFG1, (ledcfg | BIT(3)));
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not processed\n");
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
 		break;
 	}
 	pled->ledon = false;
@@ -110,17 +109,15 @@
 void rtl88ee_init_sw_leds(struct ieee80211_hw *hw)
 {
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
-
-	rtl88ee_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0);
-	rtl88ee_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1);
+	_rtl88ee_init_led(hw, &pcipriv->ledctl.sw_led0, LED_PIN_LED0);
+	_rtl88ee_init_led(hw, &pcipriv->ledctl.sw_led1, LED_PIN_LED1);
 }
 
-static void rtl88ee_sw_led_control(struct ieee80211_hw *hw,
+static void _rtl88ee_sw_led_control(struct ieee80211_hw *hw,
 				    enum led_ctl_mode ledaction)
 {
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
-
 	switch (ledaction) {
 	case LED_CTL_POWER_ON:
 	case LED_CTL_LINK:
@@ -152,6 +149,6 @@
 		return;
 	}
 	RT_TRACE(rtlpriv, COMP_LED, DBG_TRACE, "ledaction %d,\n",
-		 ledaction);
-	rtl88ee_sw_led_control(hw, ledaction);
+				ledaction);
+	_rtl88ee_sw_led_control(hw, ledaction);
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/led.h b/drivers/net/wireless/rtlwifi/rtl8188ee/led.h
index 4073f6f..4b325b7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/led.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/led.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c
index 1cd6c16..3f6c59c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -29,7 +25,6 @@
 
 #include "../wifi.h"
 #include "../pci.h"
-#include "../core.h"
 #include "../ps.h"
 #include "reg.h"
 #include "def.h"
@@ -38,443 +33,32 @@
 #include "dm.h"
 #include "table.h"
 
-static void set_baseband_phy_config(struct ieee80211_hw *hw);
-static void set_baseband_agc_config(struct ieee80211_hw *hw);
-static void store_pwrindex_offset(struct ieee80211_hw *hw,
-				  u32 regaddr, u32 bitmask,
-				  u32 data);
-static bool check_cond(struct ieee80211_hw *hw, const u32  condition);
+static u32 _rtl88e_phy_rf_serial_read(struct ieee80211_hw *hw,
+				      enum radio_path rfpath, u32 offset);
+static void _rtl88e_phy_rf_serial_write(struct ieee80211_hw *hw,
+					enum radio_path rfpath, u32 offset,
+					u32 data);
+static u32 _rtl88e_phy_calculate_bit_shift(u32 bitmask);
+static bool _rtl88e_phy_bb8188e_config_parafile(struct ieee80211_hw *hw);
+static bool _rtl88e_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
+static bool phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+					  u8 configtype);
+static bool phy_config_bb_with_pghdr(struct ieee80211_hw *hw,
+				     u8 configtype);
+static void _rtl88e_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw);
+static bool _rtl88e_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+					     u32 cmdtableidx, u32 cmdtablesz,
+					     enum swchnlcmd_id cmdid, u32 para1,
+					     u32 para2, u32 msdelay);
+static bool _rtl88e_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+					     u8 channel, u8 *stage, u8 *step,
+					     u32 *delay);
 
-static u32 rf_serial_read(struct ieee80211_hw *hw,
-			  enum radio_path rfpath, u32 offset)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct bb_reg_def *phreg = &rtlphy->phyreg_def[rfpath];
-	u32 newoffset;
-	u32 tmplong, tmplong2;
-	u8 rfpi_enable = 0;
-	u32 ret;
-	int jj = RF90_PATH_A;
-	int kk = RF90_PATH_B;
-
-	offset &= 0xff;
-	newoffset = offset;
-	if (RT_CANNOT_IO(hw)) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
-		return 0xFFFFFFFF;
-	}
-	tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
-	if (rfpath == jj)
-		tmplong2 = tmplong;
-	else
-		tmplong2 = rtl_get_bbreg(hw, phreg->rfhssi_para2, MASKDWORD);
-	tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
-	    (newoffset << 23) | BLSSIREADEDGE;
-	rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
-		      tmplong & (~BLSSIREADEDGE));
-	mdelay(1);
-	rtl_set_bbreg(hw, phreg->rfhssi_para2, MASKDWORD, tmplong2);
-	mdelay(2);
-	if (rfpath == jj)
-		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
-						 BIT(8));
-	else if (rfpath == kk)
-		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
-						 BIT(8));
-	if (rfpi_enable)
-		ret = rtl_get_bbreg(hw, phreg->rf_rbpi, BLSSIREADBACKDATA);
-	else
-		ret = rtl_get_bbreg(hw, phreg->rf_rb, BLSSIREADBACKDATA);
-	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]= 0x%x\n",
-		 rfpath, phreg->rf_rb, ret);
-	return ret;
-}
-
-static void rf_serial_write(struct ieee80211_hw *hw,
-			    enum radio_path rfpath, u32 offset,
-			    u32 data)
-{
-	u32 data_and_addr;
-	u32 newoffset;
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct bb_reg_def *phreg = &rtlphy->phyreg_def[rfpath];
-
-	if (RT_CANNOT_IO(hw)) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
-		return;
-	}
-	offset &= 0xff;
-	newoffset = offset;
-	data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
-	rtl_set_bbreg(hw, phreg->rf3wire_offset, MASKDWORD, data_and_addr);
-	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]= 0x%x\n",
-		 rfpath, phreg->rf3wire_offset, data_and_addr);
-}
-
-static u32 cal_bit_shift(u32 bitmask)
-{
-	u32 i;
-
-	for (i = 0; i <= 31; i++) {
-		if (((bitmask >> i) & 0x1) == 1)
-			break;
-	}
-	return i;
-}
-
-static bool config_bb_with_header(struct ieee80211_hw *hw,
-				  u8 configtype)
-{
-	if (configtype == BASEBAND_CONFIG_PHY_REG)
-		set_baseband_phy_config(hw);
-	else if (configtype == BASEBAND_CONFIG_AGC_TAB)
-		set_baseband_agc_config(hw);
-	return true;
-}
-
-static bool config_bb_with_pgheader(struct ieee80211_hw *hw,
-				    u8 configtype)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	int i;
-	u32 *table_pg;
-	u16 tbl_page_len;
-	u32 v1 = 0, v2 = 0;
-
-	tbl_page_len = RTL8188EEPHY_REG_ARRAY_PGLEN;
-	table_pg = RTL8188EEPHY_REG_ARRAY_PG;
-
-	if (configtype == BASEBAND_CONFIG_PHY_REG) {
-		for (i = 0; i < tbl_page_len; i = i + 3) {
-			v1 = table_pg[i];
-			v2 = table_pg[i + 1];
-
-			if (v1 < 0xcdcdcdcd) {
-				rtl_addr_delay(table_pg[i]);
-
-				store_pwrindex_offset(hw, table_pg[i],
-						      table_pg[i + 1],
-						      table_pg[i + 2]);
-				continue;
-			} else {
-				if (!check_cond(hw, table_pg[i])) {
-					/*don't need the hw_body*/
-					i += 2; /* skip the pair of expression*/
-					v1 = table_pg[i];
-					v2 = table_pg[i + 1];
-					while (v2 != 0xDEAD) {
-						i += 3;
-						v1 = table_pg[i];
-						v2 = table_pg[i + 1];
-					}
-				}
-			}
-		}
-	} else {
-		RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
-			 "configtype != BaseBand_Config_PHY_REG\n");
-	}
-	return true;
-}
-
-static bool config_parafile(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
-	bool rtstatus;
-
-	rtstatus = config_bb_with_header(hw, BASEBAND_CONFIG_PHY_REG);
-	if (rtstatus != true) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!");
-		return false;
-	}
-
-	if (fuse->autoload_failflag == false) {
-		rtlphy->pwrgroup_cnt = 0;
-		rtstatus = config_bb_with_pgheader(hw, BASEBAND_CONFIG_PHY_REG);
-	}
-	if (rtstatus != true) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!");
-		return false;
-	}
-	rtstatus = config_bb_with_header(hw, BASEBAND_CONFIG_AGC_TAB);
-	if (rtstatus != true) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
-		return false;
-	}
-	rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw,
-				 RFPGA0_XA_HSSIPARAMETER2, 0x200));
-
-	return true;
-}
-
-static void rtl88e_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	int jj = RF90_PATH_A;
-	int kk = RF90_PATH_B;
-
-	rtlphy->phyreg_def[jj].rfintfs = RFPGA0_XAB_RFINTERFACESW;
-	rtlphy->phyreg_def[kk].rfintfs = RFPGA0_XAB_RFINTERFACESW;
-	rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW;
-	rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW;
-
-	rtlphy->phyreg_def[jj].rfintfi = RFPGA0_XAB_RFINTERFACERB;
-	rtlphy->phyreg_def[kk].rfintfi = RFPGA0_XAB_RFINTERFACERB;
-	rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB;
-	rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB;
-
-	rtlphy->phyreg_def[jj].rfintfo = RFPGA0_XA_RFINTERFACEOE;
-	rtlphy->phyreg_def[kk].rfintfo = RFPGA0_XB_RFINTERFACEOE;
-
-	rtlphy->phyreg_def[jj].rfintfe = RFPGA0_XA_RFINTERFACEOE;
-	rtlphy->phyreg_def[kk].rfintfe = RFPGA0_XB_RFINTERFACEOE;
-
-	rtlphy->phyreg_def[jj].rf3wire_offset = RFPGA0_XA_LSSIPARAMETER;
-	rtlphy->phyreg_def[kk].rf3wire_offset = RFPGA0_XB_LSSIPARAMETER;
-
-	rtlphy->phyreg_def[jj].rflssi_select = rFPGA0_XAB_RFPARAMETER;
-	rtlphy->phyreg_def[kk].rflssi_select = rFPGA0_XAB_RFPARAMETER;
-	rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER;
-	rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER;
-
-	rtlphy->phyreg_def[jj].rftxgain_stage = RFPGA0_TXGAINSTAGE;
-	rtlphy->phyreg_def[kk].rftxgain_stage = RFPGA0_TXGAINSTAGE;
-	rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE;
-	rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE;
-
-	rtlphy->phyreg_def[jj].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1;
-	rtlphy->phyreg_def[kk].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1;
-
-	rtlphy->phyreg_def[jj].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
-	rtlphy->phyreg_def[kk].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
-
-	rtlphy->phyreg_def[jj].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
-	rtlphy->phyreg_def[kk].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
-	rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
-	rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
-
-	rtlphy->phyreg_def[jj].rfagc_control1 = ROFDM0_XAAGCCORE1;
-	rtlphy->phyreg_def[kk].rfagc_control1 = ROFDM0_XBAGCCORE1;
-	rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1;
-	rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1;
-
-	rtlphy->phyreg_def[jj].rfagc_control2 = ROFDM0_XAAGCCORE2;
-	rtlphy->phyreg_def[kk].rfagc_control2 = ROFDM0_XBAGCCORE2;
-	rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
-	rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
-
-	rtlphy->phyreg_def[jj].rfrxiq_imbal = ROFDM0_XARXIQIMBAL;
-	rtlphy->phyreg_def[kk].rfrxiq_imbal = ROFDM0_XBRXIQIMBAL;
-	rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBAL;
-	rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBAL;
-
-	rtlphy->phyreg_def[jj].rfrx_afe = ROFDM0_XARXAFE;
-	rtlphy->phyreg_def[kk].rfrx_afe = ROFDM0_XBRXAFE;
-	rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
-	rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
-
-	rtlphy->phyreg_def[jj].rftxiq_imbal = ROFDM0_XATXIQIMBAL;
-	rtlphy->phyreg_def[kk].rftxiq_imbal = ROFDM0_XBTXIQIMBAL;
-	rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBAL;
-	rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBAL;
-
-	rtlphy->phyreg_def[jj].rftx_afe = ROFDM0_XATXAFE;
-	rtlphy->phyreg_def[kk].rftx_afe = ROFDM0_XBTXAFE;
-
-	rtlphy->phyreg_def[jj].rf_rb = RFPGA0_XA_LSSIREADBACK;
-	rtlphy->phyreg_def[kk].rf_rb = RFPGA0_XB_LSSIREADBACK;
-
-	rtlphy->phyreg_def[jj].rf_rbpi = TRANSCEIVEA_HSPI_READBACK;
-	rtlphy->phyreg_def[kk].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;
-}
-
-static bool rtl88e_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
-					    u32 cmdtableidx, u32 cmdtablesz,
-					    enum swchnlcmd_id cmdid,
-					    u32 para1, u32 para2, u32 msdelay)
-{
-	struct swchnlcmd *pcmd;
-
-	if (cmdtable == NULL) {
-		RT_ASSERT(false, "cmdtable cannot be NULL.\n");
-		return false;
-	}
-
-	if (cmdtableidx >= cmdtablesz)
-		return false;
-
-	pcmd = cmdtable + cmdtableidx;
-	pcmd->cmdid = cmdid;
-	pcmd->para1 = para1;
-	pcmd->para2 = para2;
-	pcmd->msdelay = msdelay;
-	return true;
-}
-
-static bool chnl_step_by_step(struct ieee80211_hw *hw,
-			      u8 channel, u8 *stage, u8 *step,
-			      u32 *delay)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
-	u32 precommoncmdcnt;
-	struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
-	u32 postcommoncmdcnt;
-	struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT];
-	u32 rfdependcmdcnt;
-	struct swchnlcmd *currentcmd = NULL;
-	u8 rfpath;
-	u8 num_total_rfpath = rtlphy->num_total_rfpath;
-
-	precommoncmdcnt = 0;
-	rtl88e_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
-					MAX_PRECMD_CNT,
-					CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0);
-	rtl88e_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
-					MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
-
-	postcommoncmdcnt = 0;
-
-	rtl88e_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
-					MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
-
-	rfdependcmdcnt = 0;
-
-	RT_ASSERT((channel >= 1 && channel <= 14),
-		  "illegal channel for Zebra: %d\n", channel);
-
-	rtl88e_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
-					MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
-					RF_CHNLBW, channel, 10);
-
-	rtl88e_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
-					MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0,
-					 0);
-
-	do {
-		switch (*stage) {
-		case 0:
-			currentcmd = &precommoncmd[*step];
-			break;
-		case 1:
-			currentcmd = &rfdependcmd[*step];
-			break;
-		case 2:
-			currentcmd = &postcommoncmd[*step];
-			break;
-		}
-
-		if (currentcmd->cmdid == CMDID_END) {
-			if ((*stage) == 2) {
-				return true;
-			} else {
-				(*stage)++;
-				(*step) = 0;
-				continue;
-			}
-		}
-
-		switch (currentcmd->cmdid) {
-		case CMDID_SET_TXPOWEROWER_LEVEL:
-			rtl88e_phy_set_txpower_level(hw, channel);
-			break;
-		case CMDID_WRITEPORT_ULONG:
-			rtl_write_dword(rtlpriv, currentcmd->para1,
-					currentcmd->para2);
-			break;
-		case CMDID_WRITEPORT_USHORT:
-			rtl_write_word(rtlpriv, currentcmd->para1,
-				       (u16) currentcmd->para2);
-			break;
-		case CMDID_WRITEPORT_UCHAR:
-			rtl_write_byte(rtlpriv, currentcmd->para1,
-				       (u8) currentcmd->para2);
-			break;
-		case CMDID_RF_WRITEREG:
-			for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
-				rtlphy->rfreg_chnlval[rfpath] =
-				    ((rtlphy->rfreg_chnlval[rfpath] &
-				      0xfffffc00) | currentcmd->para2);
-
-				rtl_set_rfreg(hw, (enum radio_path)rfpath,
-					      currentcmd->para1,
-					      RFREG_OFFSET_MASK,
-					      rtlphy->rfreg_chnlval[rfpath]);
-			}
-			break;
-		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
-			break;
-		}
-
-		break;
-	} while (true);
-
-	(*delay) = currentcmd->msdelay;
-	(*step)++;
-	return false;
-}
-
-static long rtl88e_pwr_idx_dbm(struct ieee80211_hw *hw,
-			       enum wireless_mode wirelessmode,
-			       u8 txpwridx)
-{
-	long offset;
-	long pwrout_dbm;
-
-	switch (wirelessmode) {
-	case WIRELESS_MODE_B:
-		offset = -7;
-		break;
-	case WIRELESS_MODE_G:
-	case WIRELESS_MODE_N_24G:
-		offset = -8;
-		break;
-	default:
-		offset = -8;
-		break;
-	}
-	pwrout_dbm = txpwridx / 2 + offset;
-	return pwrout_dbm;
-}
-
-static void rtl88e_phy_set_io(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
-
-	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
-		 "--->Cmd(%#x), set_io_inprogress(%d)\n",
-		 rtlphy->current_io_type, rtlphy->set_io_inprogress);
-	switch (rtlphy->current_io_type) {
-	case IO_CMD_RESUME_DM_BY_SCAN:
-		dm_digtable->cur_igvalue = rtlphy->initgain_backup.xaagccore1;
-		/*rtl92c_dm_write_dig(hw);*/
-		rtl88e_phy_set_txpower_level(hw, rtlphy->current_channel);
-		rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x83);
-		break;
-	case IO_CMD_PAUSE_DM_BY_SCAN:
-		rtlphy->initgain_backup.xaagccore1 = dm_digtable->cur_igvalue;
-		dm_digtable->cur_igvalue = 0x17;
-		rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x40);
-		break;
-	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not processed\n");
-		break;
-	}
-	rtlphy->set_io_inprogress = false;
-	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
-		 "(%#x)\n", rtlphy->current_io_type);
-}
+static long _rtl88e_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+					 enum wireless_mode wirelessmode,
+					 u8 txpwridx);
+static void rtl88ee_phy_set_rf_on(struct ieee80211_hw *hw);
+static void rtl88e_phy_set_io(struct ieee80211_hw *hw);
 
 u32 rtl88e_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
 {
@@ -484,14 +68,15 @@
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
 		 "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask);
 	originalvalue = rtl_read_dword(rtlpriv, regaddr);
-	bitshift = cal_bit_shift(bitmask);
+	bitshift = _rtl88e_phy_calculate_bit_shift(bitmask);
 	returnvalue = (originalvalue & bitmask) >> bitshift;
 
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
-		 "BBR MASK = 0x%x Addr[0x%x]= 0x%x\n", bitmask,
+		 "BBR MASK=0x%x Addr[0x%x]=0x%x\n", bitmask,
 		 regaddr, originalvalue);
 
 	return returnvalue;
+
 }
 
 void rtl88e_phy_set_bb_reg(struct ieee80211_hw *hw,
@@ -501,12 +86,12 @@
 	u32 originalvalue, bitshift;
 
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
-		 "regaddr(%#x), bitmask(%#x),data(%#x)\n",
+		 "regaddr(%#x), bitmask(%#x), data(%#x)\n",
 		 regaddr, bitmask, data);
 
 	if (bitmask != MASKDWORD) {
 		originalvalue = rtl_read_dword(rtlpriv, regaddr);
-		bitshift = cal_bit_shift(bitmask);
+		bitshift = _rtl88e_phy_calculate_bit_shift(bitmask);
 		data = ((originalvalue & (~bitmask)) | (data << bitshift));
 	}
 
@@ -531,8 +116,8 @@
 	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
 
 
-	original_value = rf_serial_read(hw, rfpath, regaddr);
-	bitshift = cal_bit_shift(bitmask);
+	original_value = _rtl88e_phy_rf_serial_read(hw, rfpath, regaddr);
+	bitshift = _rtl88e_phy_calculate_bit_shift(bitmask);
 	readback_value = (original_value & bitmask) >> bitshift;
 
 	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
@@ -540,7 +125,6 @@
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
 		 "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
 		  regaddr, rfpath, bitmask, original_value);
-
 	return readback_value;
 }
 
@@ -559,13 +143,16 @@
 	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
 
 	if (bitmask != RFREG_OFFSET_MASK) {
-			original_value = rf_serial_read(hw, rfpath, regaddr);
-			bitshift = cal_bit_shift(bitmask);
-			data = ((original_value & (~bitmask)) |
-				(data << bitshift));
+			original_value = _rtl88e_phy_rf_serial_read(hw,
+								    rfpath,
+								    regaddr);
+			bitshift = _rtl88e_phy_calculate_bit_shift(bitmask);
+			data =
+			    ((original_value & (~bitmask)) |
+			     (data << bitshift));
 		}
 
-	rf_serial_write(hw, rfpath, regaddr, data);
+	_rtl88e_phy_rf_serial_write(hw, rfpath, regaddr, data);
 
 
 	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
@@ -575,27 +162,91 @@
 		 regaddr, bitmask, data, rfpath);
 }
 
-static bool config_mac_with_header(struct ieee80211_hw *hw)
+static u32 _rtl88e_phy_rf_serial_read(struct ieee80211_hw *hw,
+				      enum radio_path rfpath, u32 offset)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 i;
-	u32 arraylength;
-	u32 *ptrarray;
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+	u32 newoffset;
+	u32 tmplong, tmplong2;
+	u8 rfpi_enable = 0;
+	u32 retvalue;
 
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl8188EMACPHY_Array\n");
-	arraylength = RTL8188EEMAC_1T_ARRAYLEN;
-	ptrarray = RTL8188EEMAC_1T_ARRAY;
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-		 "Img:RTL8188EEMAC_1T_ARRAY LEN %d\n", arraylength);
-	for (i = 0; i < arraylength; i = i + 2)
-		rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]);
-	return true;
+	offset &= 0xff;
+	newoffset = offset;
+	if (RT_CANNOT_IO(hw)) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
+		return 0xFFFFFFFF;
+	}
+	tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
+	if (rfpath == RF90_PATH_A)
+		tmplong2 = tmplong;
+	else
+		tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
+	tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
+	    (newoffset << 23) | BLSSIREADEDGE;
+	rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+		      tmplong & (~BLSSIREADEDGE));
+	mdelay(1);
+	rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
+	mdelay(2);
+	if (rfpath == RF90_PATH_A)
+		rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
+						BIT(8));
+	else if (rfpath == RF90_PATH_B)
+		rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
+						BIT(8));
+	if (rfpi_enable)
+		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,
+					 BLSSIREADBACKDATA);
+	else
+		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
+					 BLSSIREADBACKDATA);
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "RFR-%d Addr[0x%x]=0x%x\n",
+		 rfpath, pphyreg->rf_rb, retvalue);
+	return retvalue;
+}
+
+static void _rtl88e_phy_rf_serial_write(struct ieee80211_hw *hw,
+					enum radio_path rfpath, u32 offset,
+					u32 data)
+{
+	u32 data_and_addr;
+	u32 newoffset;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+
+	if (RT_CANNOT_IO(hw)) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
+		return;
+	}
+	offset &= 0xff;
+	newoffset = offset;
+	data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
+	rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "RFW-%d Addr[0x%x]=0x%x\n",
+		 rfpath, pphyreg->rf3wire_offset, data_and_addr);
+}
+
+static u32 _rtl88e_phy_calculate_bit_shift(u32 bitmask)
+{
+	u32 i;
+
+	for (i = 0; i <= 31; i++) {
+		if (((bitmask >> i) & 0x1) == 1)
+			break;
+	}
+	return i;
 }
 
 bool rtl88e_phy_mac_config(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	bool rtstatus = config_mac_with_header(hw);
+	bool rtstatus = _rtl88e_phy_config_mac_with_headerfile(hw);
 
 	rtl_write_byte(rtlpriv, 0x04CA, 0x0B);
 	return rtstatus;
@@ -606,9 +257,9 @@
 	bool rtstatus = true;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u16 regval;
-	u8 reg_hwparafile = 1;
+	u8 b_reg_hwparafile = 1;
 	u32 tmp;
-	rtl88e_phy_init_bb_rf_register_definition(hw);
+	_rtl88e_phy_init_bb_rf_register_definition(hw);
 	regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
 	rtl_write_word(rtlpriv, REG_SYS_FUNC_EN,
 		       regval | BIT(13) | BIT(0) | BIT(1));
@@ -619,8 +270,8 @@
 		       FEN_BB_GLB_RSTN | FEN_BBRSTB);
 	tmp = rtl_read_dword(rtlpriv, 0x4c);
 	rtl_write_dword(rtlpriv, 0x4c, tmp | BIT(23));
-	if (reg_hwparafile == 1)
-		rtstatus = config_parafile(hw);
+	if (b_reg_hwparafile == 1)
+		rtstatus = _rtl88e_phy_bb8188e_config_parafile(hw);
 	return rtstatus;
 }
 
@@ -629,12 +280,12 @@
 	return rtl88e_phy_rf6052_config(hw);
 }
 
-static bool check_cond(struct ieee80211_hw *hw,
+static bool _rtl88e_check_condition(struct ieee80211_hw *hw,
 				    const u32  condition)
 {
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
-	u32 _board = fuse->board_type; /*need efuse define*/
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	u32 _board = rtlefuse->board_type; /*need efuse define*/
 	u32 _interface = rtlhal->interface;
 	u32 _platform = 0x08;/*SupportPlatform */
 	u32 cond = condition;
@@ -658,314 +309,504 @@
 	return true;
 }
 
-static void _rtl8188e_config_rf_reg(struct ieee80211_hw *hw,
-				    u32 addr, u32 data, enum radio_path rfpath,
+static void _rtl8188e_config_rf_reg(struct ieee80211_hw *hw, u32 addr,
+				    u32 data, enum radio_path rfpath,
 				    u32 regaddr)
 {
-	rtl_rfreg_delay(hw, rfpath, regaddr,
-			RFREG_OFFSET_MASK,
-			data);
+	if (addr == 0xffe) {
+		mdelay(50);
+	} else if (addr == 0xfd) {
+		mdelay(5);
+	} else if (addr == 0xfc) {
+		mdelay(1);
+	} else if (addr == 0xfb) {
+		udelay(50);
+	} else if (addr == 0xfa) {
+		udelay(5);
+	} else if (addr == 0xf9) {
+		udelay(1);
+	} else {
+		rtl_set_rfreg(hw, rfpath, regaddr,
+			      RFREG_OFFSET_MASK,
+			      data);
+		udelay(1);
+	}
 }
 
-static void rtl88_config_s(struct ieee80211_hw *hw,
-	u32 addr, u32 data)
+static void _rtl8188e_config_rf_radio_a(struct ieee80211_hw *hw,
+					u32 addr, u32 data)
 {
 	u32 content = 0x1000; /*RF Content: radio_a_txt*/
 	u32 maskforphyset = (u32)(content & 0xE000);
 
 	_rtl8188e_config_rf_reg(hw, addr, data, RF90_PATH_A,
-				addr | maskforphyset);
+		addr | maskforphyset);
 }
 
-#define NEXT_PAIR(v1, v2, i)				\
+static void _rtl8188e_config_bb_reg(struct ieee80211_hw *hw,
+				    u32 addr, u32 data)
+{
+	if (addr == 0xfe) {
+		mdelay(50);
+	} else if (addr == 0xfd) {
+		mdelay(5);
+	} else if (addr == 0xfc) {
+		mdelay(1);
+	} else if (addr == 0xfb) {
+		udelay(50);
+	} else if (addr == 0xfa) {
+		udelay(5);
+	} else if (addr == 0xf9) {
+		udelay(1);
+	} else {
+		rtl_set_bbreg(hw, addr, MASKDWORD, data);
+		udelay(1);
+	}
+}
+
+static bool _rtl88e_phy_bb8188e_config_parafile(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	bool rtstatus;
+
+	rtstatus = phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_PHY_REG);
+	if (!rtstatus) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!");
+		return false;
+	}
+
+	if (!rtlefuse->autoload_failflag) {
+		rtlphy->pwrgroup_cnt = 0;
+		rtstatus =
+		  phy_config_bb_with_pghdr(hw, BASEBAND_CONFIG_PHY_REG);
+	}
+	if (!rtstatus) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!");
+		return false;
+	}
+	rtstatus =
+	  phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_AGC_TAB);
+	if (!rtstatus) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
+		return false;
+	}
+	rtlphy->cck_high_power =
+	  (bool)(rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, 0x200));
+
+	return true;
+}
+
+static bool _rtl88e_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 i;
+	u32 arraylength;
+	u32 *ptrarray;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl8188EMACPHY_Array\n");
+	arraylength = RTL8188EEMAC_1T_ARRAYLEN;
+	ptrarray = RTL8188EEMAC_1T_ARRAY;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "Img:RTL8188EEMAC_1T_ARRAY LEN %d\n", arraylength);
+	for (i = 0; i < arraylength; i = i + 2)
+		rtl_write_byte(rtlpriv, ptrarray[i], (u8)ptrarray[i + 1]);
+	return true;
+}
+
+#define READ_NEXT_PAIR(v1, v2, i)			\
 	do {						\
 		i += 2; v1 = array_table[i];		\
-		v2 = array_table[i + 1];		\
+		v2 = array_table[i+1];			\
 	} while (0)
 
-static void set_baseband_agc_config(struct ieee80211_hw *hw)
+static void handle_branch1(struct ieee80211_hw *hw, u16 arraylen,
+			   u32 *array_table)
 {
+	u32 v1;
+	u32 v2;
 	int i;
-	u32 *array_table;
-	u16 arraylen;
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 v1 = 0, v2 = 0;
 
-	arraylen = RTL8188EEAGCTAB_1TARRAYLEN;
-	array_table = RTL8188EEAGCTAB_1TARRAY;
-
-	for (i = 0; i < arraylen; i += 2) {
+	for (i = 0; i < arraylen; i = i + 2) {
 		v1 = array_table[i];
-		v2 = array_table[i + 1];
+		v2 = array_table[i+1];
+		if (v1 < 0xcdcdcdcd) {
+			_rtl8188e_config_bb_reg(hw, v1, v2);
+		} else { /*This line is the start line of branch.*/
+			/* to protect READ_NEXT_PAIR not overrun */
+			if (i >= arraylen - 2)
+				break;
+
+			if (!_rtl88e_check_condition(hw, array_table[i])) {
+				/*Discard the following (offset, data) pairs*/
+				READ_NEXT_PAIR(v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < arraylen - 2)
+					READ_NEXT_PAIR(v1, v2, i);
+				i -= 2; /* prevent from for-loop += 2*/
+			} else { /* Configure matched pairs and skip
+				  * to end of if-else.
+				  */
+				READ_NEXT_PAIR(v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < arraylen - 2)
+					_rtl8188e_config_bb_reg(hw, v1, v2);
+					READ_NEXT_PAIR(v1, v2, i);
+
+				while (v2 != 0xDEAD && i < arraylen - 2)
+					READ_NEXT_PAIR(v1, v2, i);
+			}
+		}
+	}
+}
+
+static void handle_branch2(struct ieee80211_hw *hw, u16 arraylen,
+			   u32 *array_table)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 v1;
+	u32 v2;
+	int i;
+
+	for (i = 0; i < arraylen; i = i + 2) {
+		v1 = array_table[i];
+		v2 = array_table[i+1];
 		if (v1 < 0xCDCDCDCD) {
 			rtl_set_bbreg(hw, array_table[i], MASKDWORD,
 				      array_table[i + 1]);
 			udelay(1);
 			continue;
-		} else {/*This line is the start line of branch.*/
-			if (!check_cond(hw, array_table[i])) {
+		} else { /*This line is the start line of branch.*/
+			/* to protect READ_NEXT_PAIR not overrun */
+			if (i >= arraylen - 2)
+				break;
+
+			if (!_rtl88e_check_condition(hw, array_table[i])) {
 				/*Discard the following (offset, data) pairs*/
-				NEXT_PAIR(v1, v2, i);
-				while (v2 != 0xDEAD && v2 != 0xCDEF &&
-				       v2 != 0xCDCD && i < arraylen - 2) {
-					NEXT_PAIR(v1, v2, i);
-				}
-				i -= 2; /* compensate for loop's += 2*/
-			} else {
-				/* Configure matched pairs and skip to end */
-				NEXT_PAIR(v1, v2, i);
-				while (v2 != 0xDEAD && v2 != 0xCDEF &&
+				READ_NEXT_PAIR(v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < arraylen - 2)
+					READ_NEXT_PAIR(v1, v2, i);
+				i -= 2; /* prevent from for-loop += 2*/
+			} else { /* Configure matched pairs and skip
+				  * to end of if-else.
+				  */
+				READ_NEXT_PAIR(v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
 				       v2 != 0xCDCD && i < arraylen - 2) {
 					rtl_set_bbreg(hw, array_table[i],
 						      MASKDWORD,
 						      array_table[i + 1]);
 					udelay(1);
-					NEXT_PAIR(v1, v2, i);
+					READ_NEXT_PAIR(v1, v2, i);
 				}
 
 				while (v2 != 0xDEAD && i < arraylen - 2)
-					NEXT_PAIR(v1, v2, i);
+					READ_NEXT_PAIR(v1, v2, i);
 			}
 		}
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "The agctab_array_table[0] is %x Rtl818EEPHY_REGArray[1] is %x\n",
-			 array_table[i],
-			 array_table[i + 1]);
+			 array_table[i], array_table[i + 1]);
 	}
 }
 
-static void set_baseband_phy_config(struct ieee80211_hw *hw)
+static bool phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+					  u8 configtype)
 {
-	int i;
 	u32 *array_table;
 	u16 arraylen;
-	u32 v1 = 0, v2 = 0;
 
-	arraylen = RTL8188EEPHY_REG_1TARRAYLEN;
-	array_table = RTL8188EEPHY_REG_1TARRAY;
+	if (configtype == BASEBAND_CONFIG_PHY_REG) {
+		arraylen = RTL8188EEPHY_REG_1TARRAYLEN;
+		array_table = RTL8188EEPHY_REG_1TARRAY;
+		handle_branch1(hw, arraylen, array_table);
+	} else if (configtype == BASEBAND_CONFIG_AGC_TAB) {
+		arraylen = RTL8188EEAGCTAB_1TARRAYLEN;
+		array_table = RTL8188EEAGCTAB_1TARRAY;
+		handle_branch2(hw, arraylen, array_table);
+	}
+	return true;
+}
 
-	for (i = 0; i < arraylen; i += 2) {
-		v1 = array_table[i];
-		v2 = array_table[i + 1];
-		if (v1 < 0xcdcdcdcd) {
-			rtl_bb_delay(hw, v1, v2);
-		} else {/*This line is the start line of branch.*/
-			if (!check_cond(hw, array_table[i])) {
-				/*Discard the following (offset, data) pairs*/
-				NEXT_PAIR(v1, v2, i);
-				while (v2 != 0xDEAD &&
-				       v2 != 0xCDEF &&
-				       v2 != 0xCDCD && i < arraylen - 2)
-					NEXT_PAIR(v1, v2, i);
-				i -= 2; /* prevent from for-loop += 2*/
-			} else {
-				/* Configure matched pairs and skip to end */
-				NEXT_PAIR(v1, v2, i);
-				while (v2 != 0xDEAD &&
-				       v2 != 0xCDEF &&
-				       v2 != 0xCDCD && i < arraylen - 2) {
-					rtl_bb_delay(hw, v1, v2);
-					NEXT_PAIR(v1, v2, i);
-				}
+static void store_pwrindex_rate_offset(struct ieee80211_hw *hw,
+				       u32 regaddr, u32 bitmask,
+				       u32 data)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	int count = rtlphy->pwrgroup_cnt;
 
-				while (v2 != 0xDEAD && i < arraylen - 2)
-					NEXT_PAIR(v1, v2, i);
-			}
+	if (regaddr == RTXAGC_A_RATE18_06) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][0] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][0]);
+	}
+	if (regaddr == RTXAGC_A_RATE54_24) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][1] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][1]);
+	}
+	if (regaddr == RTXAGC_A_CCK1_MCS32) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][6] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][6]);
+	}
+	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][7] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][7]);
+	}
+	if (regaddr == RTXAGC_A_MCS03_MCS00) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][2] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][2]);
+	}
+	if (regaddr == RTXAGC_A_MCS07_MCS04) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][3] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][3]);
+	}
+	if (regaddr == RTXAGC_A_MCS11_MCS08) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][4] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][4]);
+	}
+	if (regaddr == RTXAGC_A_MCS15_MCS12) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][5] = data;
+		if (get_rf_type(rtlphy) == RF_1T1R) {
+			count++;
+			rtlphy->pwrgroup_cnt = count;
+		}
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][5]);
+	}
+	if (regaddr == RTXAGC_B_RATE18_06) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][8] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][8]);
+	}
+	if (regaddr == RTXAGC_B_RATE54_24) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][9] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][9]);
+	}
+	if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][14] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][14]);
+	}
+	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][15] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][15]);
+	}
+	if (regaddr == RTXAGC_B_MCS03_MCS00) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][10] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][10]);
+	}
+	if (regaddr == RTXAGC_B_MCS07_MCS04) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][11] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][11]);
+	}
+	if (regaddr == RTXAGC_B_MCS11_MCS08) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][12] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][12]);
+	}
+	if (regaddr == RTXAGC_B_MCS15_MCS12) {
+		rtlphy->mcs_txpwrlevel_origoffset[count][13] = data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
+			  count,
+			  rtlphy->mcs_txpwrlevel_origoffset[count][13]);
+		if (get_rf_type(rtlphy) != RF_1T1R) {
+			count++;
+			rtlphy->pwrgroup_cnt = count;
 		}
 	}
 }
 
-static void store_pwrindex_offset(struct ieee80211_hw *hw,
-				  u32 regaddr, u32 bitmask,
-				  u32 data)
+static bool phy_config_bb_with_pghdr(struct ieee80211_hw *hw, u8 configtype)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	int i;
+	u32 *phy_reg_page;
+	u16 phy_reg_page_len;
+	u32 v1 = 0, v2 = 0, v3 = 0;
 
-	if (regaddr == RTXAGC_A_RATE18_06) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][0] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][0]);
+	phy_reg_page_len = RTL8188EEPHY_REG_ARRAY_PGLEN;
+	phy_reg_page = RTL8188EEPHY_REG_ARRAY_PG;
+
+	if (configtype == BASEBAND_CONFIG_PHY_REG) {
+		for (i = 0; i < phy_reg_page_len; i = i + 3) {
+			v1 = phy_reg_page[i];
+			v2 = phy_reg_page[i+1];
+			v3 = phy_reg_page[i+2];
+
+			if (v1 < 0xcdcdcdcd) {
+				if (phy_reg_page[i] == 0xfe)
+					mdelay(50);
+				else if (phy_reg_page[i] == 0xfd)
+					mdelay(5);
+				else if (phy_reg_page[i] == 0xfc)
+					mdelay(1);
+				else if (phy_reg_page[i] == 0xfb)
+					udelay(50);
+				else if (phy_reg_page[i] == 0xfa)
+					udelay(5);
+				else if (phy_reg_page[i] == 0xf9)
+					udelay(1);
+
+				store_pwrindex_rate_offset(hw, phy_reg_page[i],
+							   phy_reg_page[i + 1],
+							   phy_reg_page[i + 2]);
+				continue;
+			} else {
+				if (!_rtl88e_check_condition(hw,
+							     phy_reg_page[i])) {
+					/*don't need the hw_body*/
+				    i += 2; /* skip the pair of expression*/
+				    /* to protect 'i+1' 'i+2' not overrun */
+				    if (i >= phy_reg_page_len - 2)
+					break;
+
+				    v1 = phy_reg_page[i];
+				    v2 = phy_reg_page[i+1];
+				    v3 = phy_reg_page[i+2];
+				    while (v2 != 0xDEAD &&
+					   i < phy_reg_page_len - 5) {
+					i += 3;
+					v1 = phy_reg_page[i];
+					v2 = phy_reg_page[i+1];
+					v3 = phy_reg_page[i+2];
+				    }
+				}
+			}
+		}
+	} else {
+		RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+			 "configtype != BaseBand_Config_PHY_REG\n");
 	}
-	if (regaddr == RTXAGC_A_RATE54_24) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][1] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][1]);
-	}
-	if (regaddr == RTXAGC_A_CCK1_MCS32) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][6] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][6]);
-	}
-	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][7] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][7]);
-	}
-	if (regaddr == RTXAGC_A_MCS03_MCS00) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][2] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][2]);
-	}
-	if (regaddr == RTXAGC_A_MCS07_MCS04) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][3] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][3]);
-	}
-	if (regaddr == RTXAGC_A_MCS11_MCS08) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][4] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][4]);
-	}
-	if (regaddr == RTXAGC_A_MCS15_MCS12) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][5] = data;
-		if (get_rf_type(rtlphy) == RF_1T1R)
-			rtlphy->pwrgroup_cnt++;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][5]);
-	}
-	if (regaddr == RTXAGC_B_RATE18_06) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][8] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][8]);
-	}
-	if (regaddr == RTXAGC_B_RATE54_24) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][9] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][9]);
-	}
-	if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][14] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][14]);
-	}
-	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][15] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][15]);
-	}
-	if (regaddr == RTXAGC_B_MCS03_MCS00) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][10] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][10]);
-	}
-	if (regaddr == RTXAGC_B_MCS07_MCS04) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][11] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][11]);
-	}
-	if (regaddr == RTXAGC_B_MCS11_MCS08) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][12] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][12]);
-	}
-	if (regaddr == RTXAGC_B_MCS15_MCS12) {
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][13] = data;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][13]);
-		if (get_rf_type(rtlphy) != RF_1T1R)
-			rtlphy->pwrgroup_cnt++;
-	}
+	return true;
 }
 
-#define READ_NEXT_RF_PAIR(v1, v2, i)		\
-	do {					\
-		i += 2; v1 = a_table[i];	\
-		v2 = a_table[i + 1];		\
-	} while (0)
+#define READ_NEXT_RF_PAIR(v1, v2, i) \
+do { \
+	i += 2; \
+	v1 = radioa_array_table[i]; \
+	v2 = radioa_array_table[i+1]; \
+} while (0)
+
+static void process_path_a(struct ieee80211_hw *hw,
+			   u16  radioa_arraylen,
+			   u32 *radioa_array_table)
+{
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u32 v1, v2;
+	int i;
+
+	for (i = 0; i < radioa_arraylen; i = i + 2) {
+		v1 = radioa_array_table[i];
+		v2 = radioa_array_table[i+1];
+		if (v1 < 0xcdcdcdcd) {
+			_rtl8188e_config_rf_radio_a(hw, v1, v2);
+		} else { /*This line is the start line of branch.*/
+			/* to protect READ_NEXT_PAIR not overrun */
+			if (i >= radioa_arraylen - 2)
+				break;
+
+			if (!_rtl88e_check_condition(hw, radioa_array_table[i])) {
+				/*Discard the following (offset, data) pairs*/
+				READ_NEXT_RF_PAIR(v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD &&
+				       i < radioa_arraylen - 2) {
+					READ_NEXT_RF_PAIR(v1, v2, i);
+				}
+				i -= 2; /* prevent from for-loop += 2*/
+			} else { /* Configure matched pairs and
+				  * skip to end of if-else.
+				  */
+				READ_NEXT_RF_PAIR(v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD &&
+				       i < radioa_arraylen - 2) {
+					_rtl8188e_config_rf_radio_a(hw, v1, v2);
+					READ_NEXT_RF_PAIR(v1, v2, i);
+				}
+
+				while (v2 != 0xDEAD &&
+				       i < radioa_arraylen - 2)
+					READ_NEXT_RF_PAIR(v1, v2, i);
+			}
+		}
+	}
+
+	if (rtlhal->oem_id == RT_CID_819X_HP)
+		_rtl8188e_config_rf_radio_a(hw, 0x52, 0x7E4BD);
+}
 
 bool rtl88e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
 					  enum radio_path rfpath)
 {
-	int i;
-	u32 *a_table;
-	u16 a_len;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	u32 v1 = 0, v2 = 0;
+	bool rtstatus = true;
+	u32 *radioa_array_table;
+	u16 radioa_arraylen;
 
-	a_len = RTL8188EE_RADIOA_1TARRAYLEN;
-	a_table = RTL8188EE_RADIOA_1TARRAY;
+	radioa_arraylen = RTL8188EE_RADIOA_1TARRAYLEN;
+	radioa_array_table = RTL8188EE_RADIOA_1TARRAY;
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-		 "Radio_A:RTL8188EE_RADIOA_1TARRAY %d\n", a_len);
+		 "Radio_A:RTL8188EE_RADIOA_1TARRAY %d\n", radioa_arraylen);
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath);
+	rtstatus = true;
 	switch (rfpath) {
 	case RF90_PATH_A:
-		for (i = 0; i < a_len; i = i + 2) {
-			v1 = a_table[i];
-			v2 = a_table[i + 1];
-			if (v1 < 0xcdcdcdcd) {
-				rtl88_config_s(hw, v1, v2);
-			} else {/*This line is the start line of branch.*/
-				if (!check_cond(hw, a_table[i])) {
-					/* Discard the following (offset, data)
-					 * pairs
-					 */
-					READ_NEXT_RF_PAIR(v1, v2, i);
-					while (v2 != 0xDEAD && v2 != 0xCDEF &&
-					       v2 != 0xCDCD && i < a_len - 2)
-						READ_NEXT_RF_PAIR(v1, v2, i);
-					i -= 2; /* prevent from for-loop += 2*/
-				} else {
-					/* Configure matched pairs and skip to
-					 * end of if-else.
-					 */
-					READ_NEXT_RF_PAIR(v1, v2, i);
-					while (v2 != 0xDEAD && v2 != 0xCDEF &&
-					       v2 != 0xCDCD && i < a_len - 2) {
-						rtl88_config_s(hw, v1, v2);
-						READ_NEXT_RF_PAIR(v1, v2, i);
-					}
-
-					while (v2 != 0xDEAD && i < a_len - 2)
-						READ_NEXT_RF_PAIR(v1, v2, i);
-				}
-			}
-		}
-
-		if (rtlhal->oem_id == RT_CID_819X_HP)
-			rtl88_config_s(hw, 0x52, 0x7E4BD);
-
+		process_path_a(hw, radioa_arraylen, radioa_array_table);
 		break;
-
 	case RF90_PATH_B:
 	case RF90_PATH_C:
 	case RF90_PATH_D:
-	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not processed\n");
 		break;
 	}
 	return true;
@@ -974,26 +815,26 @@
 void rtl88e_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 
-	rtlphy->default_initialgain[0] = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1,
-						       MASKBYTE0);
-	rtlphy->default_initialgain[1] = rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1,
-						       MASKBYTE0);
-	rtlphy->default_initialgain[2] = rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1,
-						       MASKBYTE0);
-	rtlphy->default_initialgain[3] = rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1,
-						       MASKBYTE0);
+	rtlphy->default_initialgain[0] =
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
+	rtlphy->default_initialgain[1] =
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
+	rtlphy->default_initialgain[2] =
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
+	rtlphy->default_initialgain[3] =
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-		 "Default initial gain (c50 = 0x%x, c58 = 0x%x, c60 = 0x%x, c68 = 0x%x\n",
-		  rtlphy->default_initialgain[0],
-		  rtlphy->default_initialgain[1],
-		  rtlphy->default_initialgain[2],
-		  rtlphy->default_initialgain[3]);
+		 "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x\n",
+		 rtlphy->default_initialgain[0],
+		 rtlphy->default_initialgain[1],
+		 rtlphy->default_initialgain[2],
+		 rtlphy->default_initialgain[3]);
 
-	rtlphy->framesync = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3,
-					  MASKBYTE0);
+	rtlphy->framesync = (u8)rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3,
+					      MASKBYTE0);
 	rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2,
 					      MASKDWORD);
 
@@ -1002,106 +843,277 @@
 		 ROFDM0_RXDETECTOR3, rtlphy->framesync);
 }
 
+static void _rtl88e_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+	rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+	rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+	rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+	rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+	rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+	rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE;
+	rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE;
+	rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset =
+	    RFPGA0_XA_LSSIPARAMETER;
+	rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset =
+	    RFPGA0_XB_LSSIPARAMETER;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = RFPGA0_XAB_RFPARAMETER;
+	rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = RFPGA0_XAB_RFPARAMETER;
+	rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = RFPGA0_XCD_RFPARAMETER;
+	rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = RFPGA0_XCD_RFPARAMETER;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+	rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+	rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+	rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1;
+	rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
+	rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl =
+	    RFPGA0_XAB_SWITCHCONTROL;
+	rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl =
+	    RFPGA0_XAB_SWITCHCONTROL;
+	rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl =
+	    RFPGA0_XCD_SWITCHCONTROL;
+	rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl =
+	    RFPGA0_XCD_SWITCHCONTROL;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;
+	rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1;
+	rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1;
+	rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2;
+	rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2;
+	rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
+	rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE;
+	rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE;
+	rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBANLANCE;
+	rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;
+	rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE;
+	rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
+	rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE;
+	rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE;
+	rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE;
+	rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE;
+	rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK;
+	rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK;
+	rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;
+}
+
 void rtl88e_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	u8 level;
-	long dbm;
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 txpwr_level;
+	long txpwr_dbm;
 
-	level = rtlphy->cur_cck_txpwridx;
-	dbm = rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_B, level);
-	level = rtlphy->cur_ofdm24g_txpwridx;
-	if (rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_G, level) > dbm)
-		dbm = rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_G, level);
-	level = rtlphy->cur_ofdm24g_txpwridx;
-	if (rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_N_24G, level) > dbm)
-		dbm = rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_N_24G, level);
-	*powerlevel = dbm;
+	txpwr_level = rtlphy->cur_cck_txpwridx;
+	txpwr_dbm = _rtl88e_phy_txpwr_idx_to_dbm(hw,
+						 WIRELESS_MODE_B, txpwr_level);
+	txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
+	if (_rtl88e_phy_txpwr_idx_to_dbm(hw,
+					 WIRELESS_MODE_G,
+					 txpwr_level) > txpwr_dbm)
+		txpwr_dbm =
+		    _rtl88e_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
+						 txpwr_level);
+	txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
+	if (_rtl88e_phy_txpwr_idx_to_dbm(hw,
+					 WIRELESS_MODE_N_24G,
+					 txpwr_level) > txpwr_dbm)
+		txpwr_dbm =
+		    _rtl88e_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
+						 txpwr_level);
+	*powerlevel = txpwr_dbm;
+}
+
+static void handle_path_a(struct rtl_efuse *rtlefuse, u8 index,
+			  u8 *cckpowerlevel, u8 *ofdmpowerlevel,
+			  u8 *bw20powerlevel, u8 *bw40powerlevel)
+{
+	cckpowerlevel[RF90_PATH_A] =
+	    rtlefuse->txpwrlevel_cck[RF90_PATH_A][index];
+		/*-8~7 */
+	if (rtlefuse->txpwr_ht20diff[RF90_PATH_A][index] > 0x0f)
+		bw20powerlevel[RF90_PATH_A] =
+		  rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_A][index] -
+		  (~(rtlefuse->txpwr_ht20diff[RF90_PATH_A][index]) + 1);
+	else
+		bw20powerlevel[RF90_PATH_A] =
+		  rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_A][index] +
+		  rtlefuse->txpwr_ht20diff[RF90_PATH_A][index];
+	if (rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][index] > 0xf)
+		ofdmpowerlevel[RF90_PATH_A] =
+		  rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_A][index] -
+		  (~(rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][index])+1);
+	else
+		ofdmpowerlevel[RF90_PATH_A] =
+		rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_A][index] +
+		  rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][index];
+	bw40powerlevel[RF90_PATH_A] =
+	  rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_A][index];
 }
 
 static void _rtl88e_get_txpower_index(struct ieee80211_hw *hw, u8 channel,
-				      u8 *cckpower, u8 *ofdm, u8 *bw20_pwr,
-				      u8 *bw40_pwr)
+				      u8 *cckpowerlevel, u8 *ofdmpowerlevel,
+				      u8 *bw20powerlevel, u8 *bw40powerlevel)
 {
-	struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
-	u8 i = (channel - 1);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	u8 index = (channel - 1);
 	u8 rf_path = 0;
-	int jj = RF90_PATH_A;
-	int kk = RF90_PATH_B;
 
 	for (rf_path = 0; rf_path < 2; rf_path++) {
-		if (rf_path == jj) {
-			cckpower[jj] = fuse->txpwrlevel_cck[jj][i];
-			if (fuse->txpwr_ht20diff[jj][i] > 0x0f) /*-8~7 */
-				bw20_pwr[jj] = fuse->txpwrlevel_ht40_1s[jj][i] -
-					(~(fuse->txpwr_ht20diff[jj][i]) + 1);
-			else
-				bw20_pwr[jj] = fuse->txpwrlevel_ht40_1s[jj][i] +
-					 fuse->txpwr_ht20diff[jj][i];
-			if (fuse->txpwr_legacyhtdiff[jj][i] > 0xf)
-				ofdm[jj] = fuse->txpwrlevel_ht40_1s[jj][i] -
-					(~(fuse->txpwr_legacyhtdiff[jj][i])+1);
-			else
-				ofdm[jj] = fuse->txpwrlevel_ht40_1s[jj][i] +
-					   fuse->txpwr_legacyhtdiff[jj][i];
-			bw40_pwr[jj] = fuse->txpwrlevel_ht40_1s[jj][i];
-
-		} else if (rf_path == kk) {
-			cckpower[kk] = fuse->txpwrlevel_cck[kk][i];
-			bw20_pwr[kk] = fuse->txpwrlevel_ht40_1s[kk][i] +
-				       fuse->txpwr_ht20diff[kk][i];
-			ofdm[kk] = fuse->txpwrlevel_ht40_1s[kk][i] +
-					fuse->txpwr_legacyhtdiff[kk][i];
-			bw40_pwr[kk] = fuse->txpwrlevel_ht40_1s[kk][i];
+		if (rf_path == RF90_PATH_A) {
+			handle_path_a(rtlefuse, index, cckpowerlevel,
+				      ofdmpowerlevel, bw20powerlevel,
+				      bw40powerlevel);
+		} else if (rf_path == RF90_PATH_B) {
+			cckpowerlevel[RF90_PATH_B] =
+			  rtlefuse->txpwrlevel_cck[RF90_PATH_B][index];
+			bw20powerlevel[RF90_PATH_B] =
+			  rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_B][index] +
+			  rtlefuse->txpwr_ht20diff[RF90_PATH_B][index];
+			ofdmpowerlevel[RF90_PATH_B] =
+			  rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_B][index] +
+			  rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][index];
+			bw40powerlevel[RF90_PATH_B] =
+			  rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_B][index];
 		}
 	}
+
 }
 
 static void _rtl88e_ccxpower_index_check(struct ieee80211_hw *hw,
-					 u8 channel, u8 *cckpower,
-					 u8 *ofdm, u8 *bw20_pwr,
-					 u8 *bw40_pwr)
+					 u8 channel, u8 *cckpowerlevel,
+					 u8 *ofdmpowerlevel, u8 *bw20powerlevel,
+					 u8 *bw40powerlevel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 
-	rtlphy->cur_cck_txpwridx = cckpower[0];
-	rtlphy->cur_ofdm24g_txpwridx = ofdm[0];
-	rtlphy->cur_bw20_txpwridx = bw20_pwr[0];
-	rtlphy->cur_bw40_txpwridx = bw40_pwr[0];
+	rtlphy->cur_cck_txpwridx = cckpowerlevel[0];
+	rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0];
+	rtlphy->cur_bw20_txpwridx = bw20powerlevel[0];
+	rtlphy->cur_bw40_txpwridx = bw40powerlevel[0];
+
 }
 
 void rtl88e_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
 {
-	struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
-	u8 cckpower[MAX_TX_COUNT]  = {0}, ofdm[MAX_TX_COUNT] = {0};
-	u8 bw20_pwr[MAX_TX_COUNT] = {0}, bw40_pwr[MAX_TX_COUNT] = {0};
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	u8 cckpowerlevel[MAX_TX_COUNT]  = {0};
+	u8 ofdmpowerlevel[MAX_TX_COUNT] = {0};
+	u8 bw20powerlevel[MAX_TX_COUNT] = {0};
+	u8 bw40powerlevel[MAX_TX_COUNT] = {0};
 
-	if (fuse->txpwr_fromeprom == false)
+	if (!rtlefuse->txpwr_fromeprom)
 		return;
-	_rtl88e_get_txpower_index(hw, channel, &cckpower[0], &ofdm[0],
-				  &bw20_pwr[0], &bw40_pwr[0]);
-	_rtl88e_ccxpower_index_check(hw, channel, &cckpower[0], &ofdm[0],
-				     &bw20_pwr[0], &bw40_pwr[0]);
-	rtl88e_phy_rf6052_set_cck_txpower(hw, &cckpower[0]);
-	rtl88e_phy_rf6052_set_ofdm_txpower(hw, &ofdm[0], &bw20_pwr[0],
-					   &bw40_pwr[0], channel);
+	_rtl88e_get_txpower_index(hw, channel,
+				  &cckpowerlevel[0], &ofdmpowerlevel[0],
+				  &bw20powerlevel[0], &bw40powerlevel[0]);
+	_rtl88e_ccxpower_index_check(hw, channel,
+				     &cckpowerlevel[0], &ofdmpowerlevel[0],
+				     &bw20powerlevel[0], &bw40powerlevel[0]);
+	rtl88e_phy_rf6052_set_cck_txpower(hw, &cckpowerlevel[0]);
+	rtl88e_phy_rf6052_set_ofdm_txpower(hw, &ofdmpowerlevel[0],
+					   &bw20powerlevel[0],
+					   &bw40powerlevel[0], channel);
+}
+
+static long _rtl88e_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+					 enum wireless_mode wirelessmode,
+					 u8 txpwridx)
+{
+	long offset;
+	long pwrout_dbm;
+
+	switch (wirelessmode) {
+	case WIRELESS_MODE_B:
+		offset = -7;
+		break;
+	case WIRELESS_MODE_G:
+	case WIRELESS_MODE_N_24G:
+		offset = -8;
+		break;
+	default:
+		offset = -8;
+		break;
+	}
+	pwrout_dbm = txpwridx / 2 + offset;
+	return pwrout_dbm;
+}
+
+void rtl88e_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	enum io_type iotype;
+
+	if (!is_hal_stop(rtlhal)) {
+		switch (operation) {
+		case SCAN_OPT_BACKUP_BAND0:
+			iotype = IO_CMD_PAUSE_BAND0_DM_BY_SCAN;
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_IO_CMD,
+						      (u8 *)&iotype);
+
+			break;
+		case SCAN_OPT_RESTORE:
+			iotype = IO_CMD_RESUME_DM_BY_SCAN;
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_IO_CMD,
+						      (u8 *)&iotype);
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "Unknown Scan Backup operation.\n");
+			break;
+		}
+	}
 }
 
 void rtl88e_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	u8 reg_bw_opmode;
 	u8 reg_prsr_rsc;
 
 	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
 		 "Switch to %s bandwidth\n",
-		 rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
-		 "20MHz" : "40MHz");
+		  rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+		  "20MHz" : "40MHz");
 
 	if (is_hal_stop(rtlhal)) {
 		rtlphy->set_bwmode_inprogress = false;
@@ -1162,7 +1174,7 @@
 			    enum nl80211_channel_type ch_type)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u8 tmp_bw = rtlphy->current_chan_bw;
 
@@ -1173,7 +1185,7 @@
 		rtl88e_phy_set_bw_mode_callback(hw);
 	} else {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-			 "FALSE driver sleep or unload\n");
+			 "false driver sleep or unload\n");
 		rtlphy->set_bwmode_inprogress = false;
 		rtlphy->current_chan_bw = tmp_bw;
 	}
@@ -1183,7 +1195,7 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	u32 delay;
 
 	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
@@ -1193,9 +1205,9 @@
 	do {
 		if (!rtlphy->sw_chnl_inprogress)
 			break;
-		if (!chnl_step_by_step(hw, rtlphy->current_channel,
-				       &rtlphy->sw_chnl_stage,
-				       &rtlphy->sw_chnl_step, &delay)) {
+		if (!_rtl88e_phy_sw_chnl_step_by_step
+		    (hw, rtlphy->current_channel, &rtlphy->sw_chnl_stage,
+		     &rtlphy->sw_chnl_step, &delay)) {
 			if (delay > 0)
 				mdelay(delay);
 			else
@@ -1211,7 +1223,7 @@
 u8 rtl88e_phy_sw_chnl(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
 	if (rtlphy->sw_chnl_inprogress)
@@ -1237,9 +1249,140 @@
 	return 1;
 }
 
+static bool _rtl88e_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+					     u8 channel, u8 *stage, u8 *step,
+					     u32 *delay)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
+	u32 precommoncmdcnt;
+	struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
+	u32 postcommoncmdcnt;
+	struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT];
+	u32 rfdependcmdcnt;
+	struct swchnlcmd *currentcmd = NULL;
+	u8 rfpath;
+	u8 num_total_rfpath = rtlphy->num_total_rfpath;
+
+	precommoncmdcnt = 0;
+	_rtl88e_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+					 MAX_PRECMD_CNT,
+					 CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0);
+	_rtl88e_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+					 MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+
+	postcommoncmdcnt = 0;
+
+	_rtl88e_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
+					 MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
+
+	rfdependcmdcnt = 0;
+
+	RT_ASSERT((channel >= 1 && channel <= 14),
+		  "illegal channel for Zebra: %d\n", channel);
+
+	_rtl88e_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+					 MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
+					 RF_CHNLBW, channel, 10);
+
+	_rtl88e_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+					 MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0,
+					 0);
+
+	do {
+		switch (*stage) {
+		case 0:
+			currentcmd = &precommoncmd[*step];
+			break;
+		case 1:
+			currentcmd = &rfdependcmd[*step];
+			break;
+		case 2:
+			currentcmd = &postcommoncmd[*step];
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "Invalid 'stage' = %d, Check it!\n", *stage);
+			return true;
+		}
+
+		if (currentcmd->cmdid == CMDID_END) {
+			if ((*stage) == 2)
+				return true;
+			(*stage)++;
+			(*step) = 0;
+			continue;
+		}
+
+		switch (currentcmd->cmdid) {
+		case CMDID_SET_TXPOWEROWER_LEVEL:
+			rtl88e_phy_set_txpower_level(hw, channel);
+			break;
+		case CMDID_WRITEPORT_ULONG:
+			rtl_write_dword(rtlpriv, currentcmd->para1,
+					currentcmd->para2);
+			break;
+		case CMDID_WRITEPORT_USHORT:
+			rtl_write_word(rtlpriv, currentcmd->para1,
+				       (u16)currentcmd->para2);
+			break;
+		case CMDID_WRITEPORT_UCHAR:
+			rtl_write_byte(rtlpriv, currentcmd->para1,
+				       (u8)currentcmd->para2);
+			break;
+		case CMDID_RF_WRITEREG:
+			for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
+				rtlphy->rfreg_chnlval[rfpath] =
+				    ((rtlphy->rfreg_chnlval[rfpath] &
+				      0xfffffc00) | currentcmd->para2);
+
+				rtl_set_rfreg(hw, (enum radio_path)rfpath,
+					      currentcmd->para1,
+					      RFREG_OFFSET_MASK,
+					      rtlphy->rfreg_chnlval[rfpath]);
+			}
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
+			break;
+		}
+
+		break;
+	} while (true);
+
+	(*delay) = currentcmd->msdelay;
+	(*step)++;
+	return false;
+}
+
+static bool _rtl88e_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+					     u32 cmdtableidx, u32 cmdtablesz,
+					     enum swchnlcmd_id cmdid,
+					     u32 para1, u32 para2, u32 msdelay)
+{
+	struct swchnlcmd *pcmd;
+
+	if (cmdtable == NULL) {
+		RT_ASSERT(false, "cmdtable cannot be NULL.\n");
+		return false;
+	}
+
+	if (cmdtableidx >= cmdtablesz)
+		return false;
+
+	pcmd = cmdtable + cmdtableidx;
+	pcmd->cmdid = cmdid;
+	pcmd->para1 = para1;
+	pcmd->para2 = para2;
+	pcmd->msdelay = msdelay;
+	return true;
+}
+
 static u8 _rtl88e_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
 {
-	u32 reg_eac, reg_e94, reg_e9c;
+	u32 reg_eac, reg_e94, reg_e9c, reg_ea4;
 	u8 result = 0x00;
 
 	rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1c);
@@ -1256,6 +1399,7 @@
 	reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
 	reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
 	reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
+	reg_ea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD);
 
 	if (!(reg_eac & BIT(28)) &&
 	    (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
@@ -1295,15 +1439,14 @@
 {
 	u32 reg_eac, reg_e94, reg_e9c, reg_ea4, u32temp;
 	u8 result = 0x00;
-	int jj = RF90_PATH_A;
 
 	/*Get TXIMR Setting*/
 	/*Modify RX IQK mode table*/
 	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
-	rtl_set_rfreg(hw, jj, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
-	rtl_set_rfreg(hw, jj, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
-	rtl_set_rfreg(hw, jj, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f);
-	rtl_set_rfreg(hw, jj, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf117b);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf117b);
 	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
 
 	/*IQK Setting*/
@@ -1318,7 +1461,7 @@
 
 	/*LO calibration Setting*/
 	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a911);
-	/*one shot, path A LOK & iqk*/
+	/*one shot,path A LOK & iqk*/
 	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
 	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
 
@@ -1336,16 +1479,16 @@
 	else
 		return result;
 
-	u32temp = 0x80007C00 | (reg_e94&0x3FF0000)  |
+	u32temp = 0x80007C00 | (reg_e94&0x3FF0000) |
 		  ((reg_e9c&0x3FF0000) >> 16);
 	rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, u32temp);
 	/*RX IQK*/
 	/*Modify RX IQK mode table*/
 	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
-	rtl_set_rfreg(hw, jj, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
-	rtl_set_rfreg(hw, jj, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
-	rtl_set_rfreg(hw, jj, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f);
-	rtl_set_rfreg(hw, jj, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7ffa);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7ffa);
 	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
 
 	/*IQK Setting*/
@@ -1359,7 +1502,7 @@
 
 	/*LO calibration Setting*/
 	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a911);
-	/*one shot, path A LOK & iqk*/
+	/*one shot,path A LOK & iqk*/
 	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
 	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
 
@@ -1377,57 +1520,58 @@
 	return result;
 }
 
-static void fill_iqk(struct ieee80211_hw *hw, bool iqk_ok, long result[][8],
-		     u8 final, bool btxonly)
+static void _rtl88e_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw,
+					       bool iqk_ok, long result[][8],
+					       u8 final_candidate, bool btxonly)
 {
 	u32 oldval_0, x, tx0_a, reg;
 	long y, tx0_c;
 
-	if (final == 0xFF) {
+	if (final_candidate == 0xFF) {
 		return;
 	} else if (iqk_ok) {
-		oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBAL,
+		oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
 					  MASKDWORD) >> 22) & 0x3FF;
-		x = result[final][0];
+		x = result[final_candidate][0];
 		if ((x & 0x00000200) != 0)
 			x = x | 0xFFFFFC00;
 		tx0_a = (x * oldval_0) >> 8;
-		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBAL, 0x3FF, tx0_a);
-		rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(31),
+		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a);
+		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(31),
 			      ((x * oldval_0 >> 7) & 0x1));
-		y = result[final][1];
+		y = result[final_candidate][1];
 		if ((y & 0x00000200) != 0)
-			y |= 0xFFFFFC00;
+			y = y | 0xFFFFFC00;
 		tx0_c = (y * oldval_0) >> 8;
 		rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000,
 			      ((tx0_c & 0x3C0) >> 6));
-		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBAL, 0x003F0000,
+		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000,
 			      (tx0_c & 0x3F));
-		rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(29),
+		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29),
 			      ((y * oldval_0 >> 7) & 0x1));
 		if (btxonly)
 			return;
-		reg = result[final][2];
-		rtl_set_bbreg(hw, ROFDM0_XARXIQIMBAL, 0x3FF, reg);
-		reg = result[final][3] & 0x3F;
-		rtl_set_bbreg(hw, ROFDM0_XARXIQIMBAL, 0xFC00, reg);
-		reg = (result[final][3] >> 6) & 0xF;
+		reg = result[final_candidate][2];
+		rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg);
+		reg = result[final_candidate][3] & 0x3F;
+		rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg);
+		reg = (result[final_candidate][3] >> 6) & 0xF;
 		rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg);
 	}
 }
 
-static void save_adda_reg(struct ieee80211_hw *hw,
-			  const u32 *addareg, u32 *backup,
-			  u32 registernum)
+static void _rtl88e_phy_save_adda_registers(struct ieee80211_hw *hw,
+					    u32 *addareg, u32 *addabackup,
+					    u32 registernum)
 {
 	u32 i;
 
 	for (i = 0; i < registernum; i++)
-		backup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD);
+		addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD);
 }
 
-static void save_mac_reg(struct ieee80211_hw *hw, const u32 *macreg,
-			 u32 *macbackup)
+static void _rtl88e_phy_save_mac_registers(struct ieee80211_hw *hw,
+					   u32 *macreg, u32 *macbackup)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u32 i;
@@ -1437,17 +1581,18 @@
 	macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]);
 }
 
-static void reload_adda(struct ieee80211_hw *hw, const u32 *addareg,
-		        u32 *backup, u32 reg_num)
+static void _rtl88e_phy_reload_adda_registers(struct ieee80211_hw *hw,
+					      u32 *addareg, u32 *addabackup,
+					      u32 regiesternum)
 {
 	u32 i;
 
-	for (i = 0; i < reg_num; i++)
-		rtl_set_bbreg(hw, addareg[i], MASKDWORD, backup[i]);
+	for (i = 0; i < regiesternum; i++)
+		rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]);
 }
 
-static void reload_mac(struct ieee80211_hw *hw, const u32 *macreg,
-		       u32 *macbackup)
+static void _rtl88e_phy_reload_mac_registers(struct ieee80211_hw *hw,
+					     u32 *macreg, u32 *macbackup)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u32 i;
@@ -1458,8 +1603,7 @@
 }
 
 static void _rtl88e_phy_path_adda_on(struct ieee80211_hw *hw,
-				     const u32 *addareg, bool is_patha_on,
-				     bool is2t)
+				     u32 *addareg, bool is_patha_on, bool is2t)
 {
 	u32 pathon;
 	u32 i;
@@ -1477,8 +1621,7 @@
 }
 
 static void _rtl88e_phy_mac_setting_calibration(struct ieee80211_hw *hw,
-						const u32 *macreg,
-						u32 *macbackup)
+						u32 *macreg, u32 *macbackup)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u32 i = 0;
@@ -1507,12 +1650,13 @@
 	rtl_set_bbreg(hw, 0x828, MASKDWORD, mode);
 }
 
-static bool sim_comp(struct ieee80211_hw *hw, long result[][8], u8 c1, u8 c2)
+static bool _rtl88e_phy_simularity_compare(struct ieee80211_hw *hw,
+					   long result[][8], u8 c1, u8 c2)
 {
-	u32 i, j, diff, bitmap, bound;
+	u32 i, j, diff, simularity_bitmap, bound;
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
-	u8 final[2] = {0xFF, 0xFF};
+	u8 final_candidate[2] = { 0xFF, 0xFF };
 	bool bresult = true, is2t = IS_92C_SERIAL(rtlhal->version);
 
 	if (is2t)
@@ -1520,81 +1664,88 @@
 	else
 		bound = 4;
 
-	bitmap = 0;
+	simularity_bitmap = 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]);
+		    (result[c1][i] - result[c2][i]) :
+		    (result[c2][i] - result[c1][i]);
 
 		if (diff > MAX_TOLERANCE) {
-			if ((i == 2 || i == 6) && !bitmap) {
+			if ((i == 2 || i == 6) && !simularity_bitmap) {
 				if (result[c1][i] + result[c1][i + 1] == 0)
-					final[(i / 4)] = c2;
+					final_candidate[(i / 4)] = c2;
 				else if (result[c2][i] + result[c2][i + 1] == 0)
-					final[(i / 4)] = c1;
+					final_candidate[(i / 4)] = c1;
 				else
-					bitmap = bitmap | (1 << i);
-			} else {
-				bitmap = bitmap | (1 << i);
-			}
+					simularity_bitmap = simularity_bitmap |
+					    (1 << i);
+			} else
+				simularity_bitmap =
+				    simularity_bitmap | (1 << i);
 		}
 	}
 
-	if (bitmap == 0) {
+	if (simularity_bitmap == 0) {
 		for (i = 0; i < (bound / 4); i++) {
-			if (final[i] != 0xFF) {
+			if (final_candidate[i] != 0xFF) {
 				for (j = i * 4; j < (i + 1) * 4 - 2; j++)
-					result[3][j] = result[final[i]][j];
+					result[3][j] =
+					    result[final_candidate[i]][j];
 				bresult = false;
 			}
 		}
 		return bresult;
-	} else if (!(bitmap & 0x0F)) {
+	} else if (!(simularity_bitmap & 0x0F)) {
 		for (i = 0; i < 4; i++)
 			result[3][i] = result[c1][i];
 		return false;
-	} else if (!(bitmap & 0xF0) && is2t) {
+	} else if (!(simularity_bitmap & 0xF0) && is2t) {
 		for (i = 4; i < 8; i++)
 			result[3][i] = result[c1][i];
 		return false;
 	} else {
 		return false;
 	}
+
 }
 
 static void _rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw,
 				     long result[][8], u8 t, bool is2t)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	u32 i;
 	u8 patha_ok, pathb_ok;
-	const u32 adda_reg[IQK_ADDA_REG_NUM] = {
+	u32 adda_reg[IQK_ADDA_REG_NUM] = {
 		0x85c, 0xe6c, 0xe70, 0xe74,
 		0xe78, 0xe7c, 0xe80, 0xe84,
 		0xe88, 0xe8c, 0xed0, 0xed4,
 		0xed8, 0xedc, 0xee0, 0xeec
 	};
-	const u32 iqk_mac_reg[IQK_MAC_REG_NUM] = {
+	u32 iqk_mac_reg[IQK_MAC_REG_NUM] = {
 		0x522, 0x550, 0x551, 0x040
 	};
-	const u32 iqk_bb_reg[IQK_BB_REG_NUM] = {
-		ROFDM0_TRXPATHENABLE, ROFDM0_TRMUXPAR, RFPGA0_XCD_RFINTERFACESW,
-		0xb68, 0xb6c, 0x870, 0x860, 0x864, 0x800
+	u32 iqk_bb_reg[IQK_BB_REG_NUM] = {
+		ROFDM0_TRXPATHENABLE, ROFDM0_TRMUXPAR,
+		RFPGA0_XCD_RFINTERFACESW, 0xb68, 0xb6c,
+		0x870, 0x860, 0x864, 0x800
 	};
 	const u32 retrycount = 2;
 
 	if (t == 0) {
-		save_adda_reg(hw, adda_reg, rtlphy->adda_backup, 16);
-		save_mac_reg(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
-		save_adda_reg(hw, iqk_bb_reg, rtlphy->iqk_bb_backup,
-			      IQK_BB_REG_NUM);
+		_rtl88e_phy_save_adda_registers(hw, adda_reg,
+						rtlphy->adda_backup, 16);
+		_rtl88e_phy_save_mac_registers(hw, iqk_mac_reg,
+					       rtlphy->iqk_mac_backup);
+		_rtl88e_phy_save_adda_registers(hw, iqk_bb_reg,
+						rtlphy->iqk_bb_backup,
+						IQK_BB_REG_NUM);
 	}
 	_rtl88e_phy_path_adda_on(hw, adda_reg, true, is2t);
 	if (t == 0) {
-		rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw,
-					   RFPGA0_XA_HSSIPARAMETER1, BIT(8));
+		rtlphy->rfpi_enable =
+		  (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, BIT(8));
 	}
 
 	if (!rtlphy->rfpi_enable)
@@ -1652,10 +1803,9 @@
 		}
 	}
 
-	if (0 == patha_ok) {
+	if (0 == patha_ok)
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 			 "Path A IQK Success!!\n");
-	}
 	if (is2t) {
 		_rtl88e_phy_path_a_standby(hw);
 		_rtl88e_phy_path_adda_on(hw, adda_reg, false, is2t);
@@ -1663,21 +1813,23 @@
 			pathb_ok = _rtl88e_phy_path_b_iqk(hw);
 			if (pathb_ok == 0x03) {
 				result[t][4] = (rtl_get_bbreg(hw,
-						0xeb4, MASKDWORD) &
+							      0xeb4,
+							      MASKDWORD) &
 						0x3FF0000) >> 16;
 				result[t][5] =
 				    (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
-						   0x3FF0000) >> 16;
+				     0x3FF0000) >> 16;
 				result[t][6] =
 				    (rtl_get_bbreg(hw, 0xec4, MASKDWORD) &
-						   0x3FF0000) >> 16;
+				     0x3FF0000) >> 16;
 				result[t][7] =
 				    (rtl_get_bbreg(hw, 0xecc, MASKDWORD) &
-						   0x3FF0000) >> 16;
+				     0x3FF0000) >> 16;
 				break;
 			} else if (i == (retrycount - 1) && pathb_ok == 0x01) {
 				result[t][4] = (rtl_get_bbreg(hw,
-						0xeb4, MASKDWORD) &
+							      0xeb4,
+							      MASKDWORD) &
 						0x3FF0000) >> 16;
 			}
 			result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
@@ -1690,10 +1842,13 @@
 	if (t != 0) {
 		if (!rtlphy->rfpi_enable)
 			_rtl88e_phy_pi_mode_switch(hw, false);
-		reload_adda(hw, adda_reg, rtlphy->adda_backup, 16);
-		reload_mac(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
-		reload_adda(hw, iqk_bb_reg, rtlphy->iqk_bb_backup,
-			    IQK_BB_REG_NUM);
+		_rtl88e_phy_reload_adda_registers(hw, adda_reg,
+						  rtlphy->adda_backup, 16);
+		_rtl88e_phy_reload_mac_registers(hw, iqk_mac_reg,
+						 rtlphy->iqk_mac_backup);
+		_rtl88e_phy_reload_adda_registers(hw, iqk_bb_reg,
+						  rtlphy->iqk_bb_backup,
+						  IQK_BB_REG_NUM);
 
 		rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3);
 		if (is2t)
@@ -1709,8 +1864,6 @@
 	u8 tmpreg;
 	u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	int jj = RF90_PATH_A;
-	int kk = RF90_PATH_B;
 
 	tmpreg = rtl_read_byte(rtlpriv, 0xd03);
 
@@ -1720,51 +1873,52 @@
 		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
 
 	if ((tmpreg & 0x70) != 0) {
-		rf_a_mode = rtl_get_rfreg(hw, jj, 0x00, MASK12BITS);
+		rf_a_mode = rtl_get_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS);
 
 		if (is2t)
-			rf_b_mode = rtl_get_rfreg(hw, kk, 0x00,
+			rf_b_mode = rtl_get_rfreg(hw, RF90_PATH_B, 0x00,
 						  MASK12BITS);
 
-		rtl_set_rfreg(hw, jj, 0x00, MASK12BITS,
+		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS,
 			      (rf_a_mode & 0x8FFFF) | 0x10000);
 
 		if (is2t)
-			rtl_set_rfreg(hw, kk, 0x00, MASK12BITS,
+			rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS,
 				      (rf_b_mode & 0x8FFFF) | 0x10000);
 	}
-	lc_cal = rtl_get_rfreg(hw, jj, 0x18, MASK12BITS);
+	lc_cal = rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS);
 
-	rtl_set_rfreg(hw, jj, 0x18, MASK12BITS, lc_cal | 0x08000);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, lc_cal | 0x08000);
 
 	mdelay(100);
 
 	if ((tmpreg & 0x70) != 0) {
 		rtl_write_byte(rtlpriv, 0xd03, tmpreg);
-		rtl_set_rfreg(hw, jj, 0x00, MASK12BITS, rf_a_mode);
+		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, rf_a_mode);
 
 		if (is2t)
-			rtl_set_rfreg(hw, kk, 0x00, MASK12BITS,
+			rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS,
 				      rf_b_mode);
 	} else {
 		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
 	}
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+
 }
 
-static void rfpath_switch(struct ieee80211_hw *hw,
-			  bool bmain, bool is2t)
+static void _rtl88e_phy_set_rfpath_switch(struct ieee80211_hw *hw,
+					  bool bmain, bool is2t)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
 
 	if (is_hal_stop(rtlhal)) {
 		u8 u1btmp;
 		u1btmp = rtl_read_byte(rtlpriv, REG_LEDCFG0);
 		rtl_write_byte(rtlpriv, REG_LEDCFG0, u1btmp | BIT(7));
-		rtl_set_bbreg(hw, rFPGA0_XAB_RFPARAMETER, BIT(13), 0x01);
+		rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(13), 0x01);
 	}
 	if (is2t) {
 		if (bmain)
@@ -1777,24 +1931,24 @@
 		rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(8) | BIT(9), 0);
 		rtl_set_bbreg(hw, 0x914, MASKLWORD, 0x0201);
 
-		/* We use the RF definition of MAIN and AUX, left antenna and
-		 * right antenna repectively.
+		/* We use the RF definition of MAIN and AUX,
+		 * left antenna and right antenna repectively.
 		 * Default output at AUX.
 		 */
 		if (bmain) {
-			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BIT(14) |
-				      BIT(13) | BIT(12), 0);
-			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BIT(5) |
-				      BIT(4) | BIT(3), 0);
-			if (fuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
-				rtl_set_bbreg(hw, RCONFIG_RAM64X16, BIT(31), 0);
+			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE,
+				      BIT(14) | BIT(13) | BIT(12), 0);
+			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+				      BIT(5) | BIT(4) | BIT(3), 0);
+			if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+				rtl_set_bbreg(hw, RCONFIG_RAM64x16, BIT(31), 0);
 		} else {
-			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BIT(14) |
-				      BIT(13) | BIT(12), 1);
-			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BIT(5) |
-				      BIT(4) | BIT(3), 1);
-			if (fuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
-				rtl_set_bbreg(hw, RCONFIG_RAM64X16, BIT(31), 1);
+			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE,
+				      BIT(14) | BIT(13) | BIT(12), 1);
+			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+				      BIT(5) | BIT(4) | BIT(3), 1);
+			if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+				rtl_set_bbreg(hw, RCONFIG_RAM64x16, BIT(31), 1);
 		}
 	}
 }
@@ -1802,35 +1956,44 @@
 #undef IQK_ADDA_REG_NUM
 #undef IQK_DELAY_TIME
 
-void rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
+void rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	long result[4][8];
-	u8 i, final;
-	bool patha_ok;
-	long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_tmp = 0;
+	u8 i, final_candidate;
+	bool b_patha_ok, b_pathb_ok;
+	long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4,
+	    reg_ecc, reg_tmp = 0;
 	bool is12simular, is13simular, is23simular;
 	u32 iqk_bb_reg[9] = {
-		ROFDM0_XARXIQIMBAL,
-		ROFDM0_XBRXIQIMBAL,
-		ROFDM0_ECCATHRES,
+		ROFDM0_XARXIQIMBALANCE,
+		ROFDM0_XBRXIQIMBALANCE,
+		ROFDM0_ECCATHRESHOLD,
 		ROFDM0_AGCRSSITABLE,
-		ROFDM0_XATXIQIMBAL,
-		ROFDM0_XBTXIQIMBAL,
+		ROFDM0_XATXIQIMBALANCE,
+		ROFDM0_XBTXIQIMBALANCE,
 		ROFDM0_XCTXAFE,
 		ROFDM0_XDTXAFE,
 		ROFDM0_RXIQEXTANTA
 	};
 
-	if (recovery) {
-		reload_adda(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 9);
+	if (b_recovery) {
+		_rtl88e_phy_reload_adda_registers(hw,
+						  iqk_bb_reg,
+						  rtlphy->iqk_bb_backup, 9);
 		return;
 	}
 
-	memset(result, 0, 32 * sizeof(long));
-	final = 0xff;
-	patha_ok = false;
+	for (i = 0; i < 8; i++) {
+		result[0][i] = 0;
+		result[1][i] = 0;
+		result[2][i] = 0;
+		result[3][i] = 0;
+	}
+	final_candidate = 0xff;
+	b_patha_ok = false;
+	b_pathb_ok = false;
 	is12simular = false;
 	is23simular = false;
 	is13simular = false;
@@ -1840,29 +2003,32 @@
 		else
 			_rtl88e_phy_iq_calibrate(hw, result, i, false);
 		if (i == 1) {
-			is12simular = sim_comp(hw, result, 0, 1);
+			is12simular =
+			  _rtl88e_phy_simularity_compare(hw, result, 0, 1);
 			if (is12simular) {
-				final = 0;
+				final_candidate = 0;
 				break;
 			}
 		}
 		if (i == 2) {
-			is13simular = sim_comp(hw, result, 0, 2);
+			is13simular =
+			  _rtl88e_phy_simularity_compare(hw, result, 0, 2);
 			if (is13simular) {
-				final = 0;
+				final_candidate = 0;
 				break;
 			}
-			is23simular = sim_comp(hw, result, 1, 2);
+			is23simular =
+			   _rtl88e_phy_simularity_compare(hw, result, 1, 2);
 			if (is23simular) {
-				final = 1;
+				final_candidate = 1;
 			} else {
 				for (i = 0; i < 8; i++)
 					reg_tmp += result[3][i];
 
 				if (reg_tmp != 0)
-					final = 3;
+					final_candidate = 3;
 				else
-					final = 0xFF;
+					final_candidate = 0xFF;
 			}
 		}
 	}
@@ -1870,47 +2036,55 @@
 		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 (final != 0xff) {
-		reg_e94 = result[final][0];
-		rtlphy->reg_e94 = reg_e94;
-		reg_e9c = result[final][1];
-		rtlphy->reg_e9c = reg_e9c;
-		reg_ea4 = result[final][2];
-		reg_eb4 = result[final][4];
+	if (final_candidate != 0xff) {
+		reg_e94 = result[final_candidate][0];
+		reg_e9c = result[final_candidate][1];
+		reg_ea4 = result[final_candidate][2];
+		reg_eac = result[final_candidate][3];
+		reg_eb4 = result[final_candidate][4];
+		reg_ebc = result[final_candidate][5];
+		reg_ec4 = result[final_candidate][6];
+		reg_ecc = result[final_candidate][7];
 		rtlphy->reg_eb4 = reg_eb4;
-		reg_ebc = result[final][5];
 		rtlphy->reg_ebc = reg_ebc;
-		patha_ok = true;
+		rtlphy->reg_e94 = reg_e94;
+		rtlphy->reg_e9c = reg_e9c;
+		b_patha_ok = true;
+		b_pathb_ok = true;
 	} else {
 		rtlphy->reg_e94 = 0x100;
 		rtlphy->reg_eb4 = 0x100;
-		rtlphy->reg_ebc = 0x0;
 		rtlphy->reg_e9c = 0x0;
+		rtlphy->reg_ebc = 0x0;
 	}
 	if (reg_e94 != 0) /*&&(reg_ea4 != 0) */
-		fill_iqk(hw, patha_ok, result, final, (reg_ea4 == 0));
-	if (final != 0xFF) {
+		_rtl88e_phy_path_a_fill_iqk_matrix(hw, b_patha_ok, result,
+						   final_candidate,
+						   (reg_ea4 == 0));
+	if (final_candidate != 0xFF) {
 		for (i = 0; i < IQK_MATRIX_REG_NUM; i++)
-			rtlphy->iqk_matrix[0].value[0][i] = result[final][i];
+			rtlphy->iqk_matrix[0].value[0][i] =
+				result[final_candidate][i];
 		rtlphy->iqk_matrix[0].iqk_done = true;
+
 	}
-	save_adda_reg(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 9);
+	_rtl88e_phy_save_adda_registers(hw, iqk_bb_reg,
+					rtlphy->iqk_bb_backup, 9);
 }
 
 void rtl88e_phy_lc_calibrate(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct rtl_hal *rtlhal = &(rtlpriv->rtlhal);
-	bool start_conttx = false, singletone = false;
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = &rtlpriv->rtlhal;
 	u32 timeout = 2000, timecount = 0;
 
-	if (start_conttx || singletone)
-		return;
-
 	while (rtlpriv->mac80211.act_scanning && timecount < timeout) {
 		udelay(50);
 		timecount += 50;
@@ -1928,18 +2102,18 @@
 
 void rtl88e_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
 {
-	rfpath_switch(hw, bmain, false);
+	_rtl88e_phy_set_rfpath_switch(hw, bmain, false);
 }
 
 bool rtl88e_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	bool postprocessing = false;
 
 	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
 		 "-->IO Cmd(%#x), set_io_inprogress(%d)\n",
-		 iotype, rtlphy->set_io_inprogress);
+		  iotype, rtlphy->set_io_inprogress);
 	do {
 		switch (iotype) {
 		case IO_CMD_RESUME_DM_BY_SCAN:
@@ -1947,14 +2121,14 @@
 				 "[IO CMD] Resume DM after scan.\n");
 			postprocessing = true;
 			break;
-		case IO_CMD_PAUSE_DM_BY_SCAN:
+		case IO_CMD_PAUSE_BAND0_DM_BY_SCAN:
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
 				 "[IO CMD] Pause DM before scan.\n");
 			postprocessing = true;
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
 			break;
 		}
 	} while (false);
@@ -1969,6 +2143,37 @@
 	return true;
 }
 
+static void rtl88e_phy_set_io(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+		 "--->Cmd(%#x), set_io_inprogress(%d)\n",
+		  rtlphy->current_io_type, rtlphy->set_io_inprogress);
+	switch (rtlphy->current_io_type) {
+	case IO_CMD_RESUME_DM_BY_SCAN:
+		dm_digtable->cur_igvalue = rtlphy->initgain_backup.xaagccore1;
+		/*rtl92c_dm_write_dig(hw);*/
+		rtl88e_phy_set_txpower_level(hw, rtlphy->current_channel);
+		rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x83);
+		break;
+	case IO_CMD_PAUSE_BAND0_DM_BY_SCAN:
+		rtlphy->initgain_backup.xaagccore1 = dm_digtable->cur_igvalue;
+		dm_digtable->cur_igvalue = 0x17;
+		rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x40);
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
+		break;
+	}
+	rtlphy->set_io_inprogress = false;
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+		 "(%#x)\n", rtlphy->current_io_type);
+}
+
 static void rtl88ee_phy_set_rf_on(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1984,10 +2189,9 @@
 static void _rtl88ee_phy_set_rf_sleep(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	int jj = RF90_PATH_A;
 
 	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
-	rtl_set_rfreg(hw, jj, 0x00, RFREG_OFFSET_MASK, 0x00);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
 	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
 	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22);
 }
@@ -1999,42 +2203,49 @@
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-	struct rtl8192_tx_ring *ring = NULL;
 	bool bresult = true;
 	u8 i, queue_id;
+	struct rtl8192_tx_ring *ring = NULL;
 
 	switch (rfpwr_state) {
-	case ERFON:{
+	case ERFON:
 		if ((ppsc->rfpwr_state == ERFOFF) &&
 		    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
 			bool rtstatus;
-			u32 init = 0;
+			u32 initializecount = 0;
+
 			do {
-				init++;
+				initializecount++;
 				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 					 "IPS Set eRf nic enable\n");
 				rtstatus = rtl_ps_enable_nic(hw);
-			} while ((rtstatus != true) && (init < 10));
+			} while (!rtstatus &&
+				 (initializecount < 10));
 			RT_CLEAR_PS_LEVEL(ppsc,
 					  RT_RF_OFF_LEVL_HALT_NIC);
 		} else {
 			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 				 "Set ERFON sleeped:%d ms\n",
-				 jiffies_to_msecs(jiffies - ppsc->
-						  last_sleep_jiffies));
+				  jiffies_to_msecs(jiffies -
+						   ppsc->
+						   last_sleep_jiffies));
 			ppsc->last_awake_jiffies = jiffies;
 			rtl88ee_phy_set_rf_on(hw);
 		}
-		if (mac->link_state == MAC80211_LINKED)
-			rtlpriv->cfg->ops->led_control(hw, LED_CTL_LINK);
-		else
-			rtlpriv->cfg->ops->led_control(hw, LED_CTL_NO_LINK);
-		break; }
-	case ERFOFF:{
+		if (mac->link_state == MAC80211_LINKED) {
+			rtlpriv->cfg->ops->led_control(hw,
+						       LED_CTL_LINK);
+		} else {
+			rtlpriv->cfg->ops->led_control(hw,
+						       LED_CTL_NO_LINK);
+		}
+		break;
+	case ERFOFF:
 		for (queue_id = 0, i = 0;
 		     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
 			ring = &pcipriv->dev.tx_ring[queue_id];
-			if (skb_queue_len(&ring->queue) == 0) {
+			if (queue_id == BEACON_QUEUE ||
+			    skb_queue_len(&ring->queue) == 0) {
 				queue_id++;
 				continue;
 			} else {
@@ -2055,6 +2266,7 @@
 				break;
 			}
 		}
+
 		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
 			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 				 "IPS Set eRf nic disable\n");
@@ -2063,49 +2275,51 @@
 		} else {
 			if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) {
 				rtlpriv->cfg->ops->led_control(hw,
-						LED_CTL_NO_LINK);
+							       LED_CTL_NO_LINK);
 			} else {
 				rtlpriv->cfg->ops->led_control(hw,
-						LED_CTL_POWER_OFF);
+							       LED_CTL_POWER_OFF);
 			}
 		}
-		break; }
+		break;
 	case ERFSLEEP:{
-		if (ppsc->rfpwr_state == ERFOFF)
-			break;
-		for (queue_id = 0, i = 0;
-		     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
-			ring = &pcipriv->dev.tx_ring[queue_id];
-			if (skb_queue_len(&ring->queue) == 0) {
-				queue_id++;
-				continue;
-			} else {
-				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-					 "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n",
-					 (i + 1), queue_id,
-					 skb_queue_len(&ring->queue));
-
-				udelay(10);
-				i++;
-			}
-			if (i >= MAX_DOZE_WAITING_TIMES_9x) {
-				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-					 "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
-					 MAX_DOZE_WAITING_TIMES_9x,
-					 queue_id,
-					 skb_queue_len(&ring->queue));
+			if (ppsc->rfpwr_state == ERFOFF)
 				break;
+			for (queue_id = 0, i = 0;
+			     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+				ring = &pcipriv->dev.tx_ring[queue_id];
+				if (skb_queue_len(&ring->queue) == 0) {
+					queue_id++;
+					continue;
+				} else {
+					RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+						 "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n",
+						 (i + 1), queue_id,
+						 skb_queue_len(&ring->queue));
+
+					udelay(10);
+					i++;
+				}
+				if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+					RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+						 "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
+						 MAX_DOZE_WAITING_TIMES_9x,
+						 queue_id,
+						 skb_queue_len(&ring->queue));
+					break;
+				}
 			}
+			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+				 "Set ERFSLEEP awaked:%d ms\n",
+				  jiffies_to_msecs(jiffies -
+				  ppsc->last_awake_jiffies));
+			ppsc->last_sleep_jiffies = jiffies;
+			_rtl88ee_phy_set_rf_sleep(hw);
+			break;
 		}
-		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
-			 "Set ERFSLEEP awaked:%d ms\n",
-			 jiffies_to_msecs(jiffies - ppsc->last_awake_jiffies));
-		ppsc->last_sleep_jiffies = jiffies;
-		_rtl88ee_phy_set_rf_sleep(hw);
-		break; }
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not processed\n");
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
 		bresult = false;
 		break;
 	}
@@ -2118,10 +2332,11 @@
 				   enum rf_pwrstate rfpwr_state)
 {
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-	bool bresult;
+
+	bool bresult = false;
 
 	if (rfpwr_state == ppsc->rfpwr_state)
-		return false;
+		return bresult;
 	bresult = _rtl88ee_phy_set_rf_power_state(hw, rfpwr_state);
 	return bresult;
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.h b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.h
index 89f0f1e..b29bd77 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,33 +26,35 @@
 #ifndef __RTL92C_PHY_H__
 #define __RTL92C_PHY_H__
 
-/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/
-#define	MAX_TX_COUNT				4
+/* MAX_TX_COUNT must always set to 4, otherwise read efuse
+ * table secquence will be wrong.
+ */
+#define		MAX_TX_COUNT				4
 
 #define MAX_PRECMD_CNT				16
-#define MAX_RFDEPENDCMD_CNT			16
+#define MAX_RFDEPENDCMD_CNT		16
 #define MAX_POSTCMD_CNT				16
 
-#define MAX_DOZE_WAITING_TIMES_9x		64
+#define MAX_DOZE_WAITING_TIMES_9x	64
 
 #define RT_CANNOT_IO(hw)			false
-#define HIGHPOWER_RADIOA_ARRAYLEN		22
+#define HIGHPOWER_RADIOA_ARRAYLEN	22
 
 #define IQK_ADDA_REG_NUM			16
 #define IQK_BB_REG_NUM				9
 #define MAX_TOLERANCE				5
 #define	IQK_DELAY_TIME				10
-#define	IDX_MAP					15
+#define	INDEX_MAPPING_NUM	15
 
 #define	APK_BB_REG_NUM				5
 #define	APK_AFE_REG_NUM				16
 #define	APK_CURVE_REG_NUM			4
-#define	PATH_NUM				2
+#define	PATH_NUM					2
 
-#define LOOP_LIMIT				5
+#define LOOP_LIMIT					5
 #define MAX_STALL_TIME				50
-#define ANTENNADIVERSITYVALUE			0x80
-#define MAX_TXPWR_IDX_NMODE_92S			63
+#define ANTENNADIVERSITYVALUE		0x80
+#define MAX_TXPWR_IDX_NMODE_92S		63
 #define RESET_CNT_LIMIT				3
 
 #define IQK_ADDA_REG_NUM			16
@@ -66,8 +64,8 @@
 
 #define CT_OFFSET_MAC_ADDR			0X16
 
-#define CT_OFFSET_CCK_TX_PWR_IDX		0x5A
-#define CT_OFFSET_HT401S_TX_PWR_IDX		0x60
+#define CT_OFFSET_CCK_TX_PWR_IDX			0x5A
+#define CT_OFFSET_HT401S_TX_PWR_IDX			0x60
 #define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF	0x66
 #define CT_OFFSET_HT20_TX_PWR_IDX_DIFF		0x69
 #define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF		0x6C
@@ -75,13 +73,13 @@
 #define CT_OFFSET_HT40_MAX_PWR_OFFSET		0x6F
 #define CT_OFFSET_HT20_MAX_PWR_OFFSET		0x72
 
-#define CT_OFFSET_CHANNEL_PLAH			0x75
-#define CT_OFFSET_THERMAL_METER			0x78
-#define CT_OFFSET_RF_OPTION			0x79
-#define CT_OFFSET_VERSION			0x7E
-#define CT_OFFSET_CUSTOMER_ID			0x7F
+#define CT_OFFSET_CHANNEL_PLAH				0x75
+#define CT_OFFSET_THERMAL_METER				0x78
+#define CT_OFFSET_RF_OPTION					0x79
+#define CT_OFFSET_VERSION					0x7E
+#define CT_OFFSET_CUSTOMER_ID				0x7F
 
-#define RTL92C_MAX_PATH_NUM			2
+#define RTL92C_MAX_PATH_NUM					2
 
 enum swchnlcmd_id {
 	CMDID_END,
@@ -160,7 +158,6 @@
 	u8 r_ccktx_enable:4;
 };
 
-
 struct efuse_contents {
 	u8 mac_addr[ETH_ALEN];
 	u8 cck_tx_power_idx[6];
@@ -192,10 +189,10 @@
 };
 
 enum _ANT_DIV_TYPE {
-	NO_ANTDIV			= 0xFF,
+	NO_ANTDIV				= 0xFF,
 	CG_TRX_HW_ANTDIV		= 0x01,
 	CGCS_RX_HW_ANTDIV		= 0x02,
-	FIXED_HW_ANTDIV			= 0x03,
+	FIXED_HW_ANTDIV         = 0x03,
 	CG_TRX_SMART_ANTDIV		= 0x04,
 	CGCS_RX_SW_ANTDIV		= 0x05,
 };
@@ -217,6 +214,8 @@
 void rtl88e_phy_get_txpower_level(struct ieee80211_hw *hw,
 				  long *powerlevel);
 void rtl88e_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
+void rtl88e_phy_scan_operation_backup(struct ieee80211_hw *hw,
+				      u8 operation);
 void rtl88e_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
 void rtl88e_phy_set_bw_mode(struct ieee80211_hw *hw,
 			    enum nl80211_channel_type ch_type);
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
index 6dc4e3a..ef28c8e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -32,78 +28,78 @@
 
 /* drivers should parse below arrays and do the corresponding actions */
 /*3 Power on  Array*/
-struct wlan_pwr_cfg rtl8188e_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS +
-					   RTL8188E_TRANS_END_STEPS] = {
-	RTL8188E_TRANS_CARDEMU_TO_ACT
-	RTL8188E_TRANS_END
+struct wlan_pwr_cfg rtl8188ee_power_on_flow[RTL8188EE_TRANS_CARDEMU_TO_ACT_STEPS
+					+ RTL8188EE_TRANS_END_STEPS] = {
+	RTL8188EE_TRANS_CARDEMU_TO_ACT
+	RTL8188EE_TRANS_END
 };
 
 /*3Radio off GPIO Array */
-struct wlan_pwr_cfg rtl8188e_radio_off_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS
-					    + RTL8188E_TRANS_END_STEPS] = {
-	RTL8188E_TRANS_ACT_TO_CARDEMU
-	RTL8188E_TRANS_END
+struct wlan_pwr_cfg rtl8188ee_radio_off_flow[RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS
+					+ RTL8188EE_TRANS_END_STEPS] = {
+	RTL8188EE_TRANS_ACT_TO_CARDEMU
+	RTL8188EE_TRANS_END
 };
 
 /*3Card Disable Array*/
-struct wlan_pwr_cfg rtl8188e_card_disable_flow
-	[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
-	RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
-	RTL8188E_TRANS_END_STEPS] = {
-		RTL8188E_TRANS_ACT_TO_CARDEMU
-		RTL8188E_TRANS_CARDEMU_TO_CARDDIS
-		RTL8188E_TRANS_END
+struct wlan_pwr_cfg rtl8188ee_card_disable_flow
+		[RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8188EE_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8188EE_TRANS_END_STEPS] = {
+	RTL8188EE_TRANS_ACT_TO_CARDEMU
+	RTL8188EE_TRANS_CARDEMU_TO_CARDDIS
+	RTL8188EE_TRANS_END
 };
 
 /*3 Card Enable Array*/
-struct wlan_pwr_cfg rtl8188e_card_enable_flow
-	[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
-	RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
-	RTL8188E_TRANS_END_STEPS] = {
-		RTL8188E_TRANS_CARDDIS_TO_CARDEMU
-		RTL8188E_TRANS_CARDEMU_TO_ACT
-		RTL8188E_TRANS_END
+struct wlan_pwr_cfg rtl8188ee_card_enable_flow
+		[RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8188EE_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8188EE_TRANS_END_STEPS] = {
+	RTL8188EE_TRANS_CARDDIS_TO_CARDEMU
+	RTL8188EE_TRANS_CARDEMU_TO_ACT
+	RTL8188EE_TRANS_END
 };
 
 /*3Suspend Array*/
-struct wlan_pwr_cfg rtl8188e_suspend_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS
-					+ RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS
-					+ RTL8188E_TRANS_END_STEPS] = {
-	RTL8188E_TRANS_ACT_TO_CARDEMU
-	RTL8188E_TRANS_CARDEMU_TO_SUS
-	RTL8188E_TRANS_END
+struct wlan_pwr_cfg rtl8188ee_suspend_flow[RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS
+					+ RTL8188EE_TRANS_CARDEMU_TO_SUS_STEPS
+					+ RTL8188EE_TRANS_END_STEPS] = {
+	RTL8188EE_TRANS_ACT_TO_CARDEMU
+	RTL8188EE_TRANS_CARDEMU_TO_SUS
+	RTL8188EE_TRANS_END
 };
 
 /*3 Resume Array*/
-struct wlan_pwr_cfg rtl8188e_resume_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS
-					+ RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS
-					+ RTL8188E_TRANS_END_STEPS] = {
-	RTL8188E_TRANS_SUS_TO_CARDEMU
-	RTL8188E_TRANS_CARDEMU_TO_ACT
-	RTL8188E_TRANS_END
+struct wlan_pwr_cfg rtl8188ee_resume_flow[RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS
+					+ RTL8188EE_TRANS_CARDEMU_TO_SUS_STEPS
+					+ RTL8188EE_TRANS_END_STEPS] = {
+	RTL8188EE_TRANS_SUS_TO_CARDEMU
+	RTL8188EE_TRANS_CARDEMU_TO_ACT
+	RTL8188EE_TRANS_END
 };
 
 /*3HWPDN Array*/
-struct wlan_pwr_cfg rtl8188e_hwpdn_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS
-				+ RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS
-				+ RTL8188E_TRANS_END_STEPS] = {
-	RTL8188E_TRANS_ACT_TO_CARDEMU
-	RTL8188E_TRANS_CARDEMU_TO_PDN
-	RTL8188E_TRANS_END
+struct wlan_pwr_cfg rtl8188ee_hwpdn_flow[RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS
+				+ RTL8188EE_TRANS_CARDEMU_TO_PDN_STEPS
+				+ RTL8188EE_TRANS_END_STEPS] = {
+	RTL8188EE_TRANS_ACT_TO_CARDEMU
+	RTL8188EE_TRANS_CARDEMU_TO_PDN
+	RTL8188EE_TRANS_END
 };
 
 /*3 Enter LPS */
-struct wlan_pwr_cfg rtl8188e_enter_lps_flow[RTL8188E_TRANS_ACT_TO_LPS_STEPS
-					+ RTL8188E_TRANS_END_STEPS] = {
+struct wlan_pwr_cfg rtl8188ee_enter_lps_flow[RTL8188EE_TRANS_ACT_TO_LPS_STEPS
+					+ RTL8188EE_TRANS_END_STEPS] = {
 	/*FW behavior*/
-	RTL8188E_TRANS_ACT_TO_LPS
-	RTL8188E_TRANS_END
+	RTL8188EE_TRANS_ACT_TO_LPS
+	RTL8188EE_TRANS_END
 };
 
 /*3 Leave LPS */
-struct wlan_pwr_cfg rtl8188e_leave_lps_flow[RTL8188E_TRANS_LPS_TO_ACT_STEPS
-					+ RTL8188E_TRANS_END_STEPS] = {
+struct wlan_pwr_cfg rtl8188ee_leave_lps_flow[RTL8188EE_TRANS_LPS_TO_ACT_STEPS
+					+ RTL8188EE_TRANS_END_STEPS] = {
 	/*FW behavior*/
-	RTL8188E_TRANS_LPS_TO_ACT
-	RTL8188E_TRANS_END
+	RTL8188EE_TRANS_LPS_TO_ACT
+	RTL8188EE_TRANS_END
 };
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
index 32e135a..7910334 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,297 +26,286 @@
 #ifndef __RTL8723E_PWRSEQ_H__
 #define __RTL8723E_PWRSEQ_H__
 
-/*
-	Check document WM-20110607-Paul-RTL8188E_Power_Architecture-R02.vsd
-	There are 6 HW Power States:
-	0: POFF--Power Off
-	1: PDN--Power Down
-	2: CARDEMU--Card Emulation
-	3: ACT--Active Mode
-	4: LPS--Low Power State
-	5: SUS--Suspend
+#include "pwrseqcmd.h"
+/* Check document WM-20110607-Paul-RTL8188EE_Power_Architecture-R02.vsd
+ *	There are 6 HW Power States:
+ *	0: POFF--Power Off
+ *	1: PDN--Power Down
+ *	2: CARDEMU--Card Emulation
+ *	3: ACT--Active Mode
+ *	4: LPS--Low Power State
+ *	5: SUS--Suspend
+ *
+ *	The transision from different states are defined below
+ *	TRANS_CARDEMU_TO_ACT
+ *	TRANS_ACT_TO_CARDEMU
+ *	TRANS_CARDEMU_TO_SUS
+ *	TRANS_SUS_TO_CARDEMU
+ *	TRANS_CARDEMU_TO_PDN
+ *	TRANS_ACT_TO_LPS
+ *	TRANS_LPS_TO_ACT
+ *
+ *	TRANS_END
+ *	PWR SEQ Version: rtl8188ee_PwrSeq_V09.h
+ */
 
-	The transision from different states are defined below
-	TRANS_CARDEMU_TO_ACT
-	TRANS_ACT_TO_CARDEMU
-	TRANS_CARDEMU_TO_SUS
-	TRANS_SUS_TO_CARDEMU
-	TRANS_CARDEMU_TO_PDN
-	TRANS_ACT_TO_LPS
-	TRANS_LPS_TO_ACT
+#define	RTL8188EE_TRANS_CARDEMU_TO_ACT_STEPS	10
+#define	RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS	10
+#define	RTL8188EE_TRANS_CARDEMU_TO_SUS_STEPS	10
+#define	RTL8188EE_TRANS_SUS_TO_CARDEMU_STEPS	10
+#define	RTL8188EE_TRANS_CARDEMU_TO_PDN_STEPS	10
+#define	RTL8188EE_TRANS_PDN_TO_CARDEMU_STEPS	10
+#define	RTL8188EE_TRANS_ACT_TO_LPS_STEPS		15
+#define	RTL8188EE_TRANS_LPS_TO_ACT_STEPS		15
+#define	RTL8188EE_TRANS_END_STEPS		1
 
-	TRANS_END
-	PWR SEQ Version: rtl8188e_PwrSeq_V09.h
-*/
-
-#define	RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS	10
-#define	RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS	10
-#define	RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS	10
-#define	RTL8188E_TRANS_SUS_TO_CARDEMU_STEPS	10
-#define	RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS	10
-#define	RTL8188E_TRANS_PDN_TO_CARDEMU_STEPS	10
-#define	RTL8188E_TRANS_ACT_TO_LPS_STEPS		15
-#define	RTL8188E_TRANS_LPS_TO_ACT_STEPS		15
-#define	RTL8188E_TRANS_END_STEPS		1
-
-
-#define RTL8188E_TRANS_CARDEMU_TO_ACT					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+/* The following macros have the following format:
+ * { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value
+ *   comments },
+ */
+#define RTL8188EE_TRANS_CARDEMU_TO_ACT					\
 	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/* wait till 0x04[17] = 1    power ready*/			\
-	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)},		\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)		\
+	/* wait till 0x04[17] = 1    power ready*/},			\
 	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/* 0x02[1:0] = 0	reset BB*/				\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0)|BIT(1), 0},		\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0)|BIT(1), 0		\
+	/* 0x02[1:0] = 0	reset BB*/},				\
 	{0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*0x24[23] = 2b'01 schmit trigger */				\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)},		\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)			\
+	/*0x24[23] = 2b'01 schmit trigger */},				\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/* 0x04[15] = 0 disable HWPDN (control by DRV)*/		\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0			\
+	/* 0x04[15] = 0 disable HWPDN (control by DRV)*/},		\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*0x04[12:11] = 2b'00 disable WL suspend*/			\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4)|BIT(3), 0},		\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4)|BIT(3), 0		\
+	/*0x04[12:11] = 2b'00 disable WL suspend*/},			\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*0x04[8] = 1 polling until return 0*/				\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)			\
+	/*0x04[8] = 1 polling until return 0*/},			\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*wait till 0x04[8] = 0*/					\
-	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0			\
+	/*wait till 0x04[8] = 0*/},					\
 	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*LDO normal mode*/\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0			\
+	/*LDO normal mode*/},						\
 	{0x0074, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*SDIO Driving*/\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)			\
+	/*SDIO Driving*/},
 
-#define RTL8188E_TRANS_ACT_TO_CARDEMU					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+#define RTL8188EE_TRANS_ACT_TO_CARDEMU					\
 	{0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0			\
+	/*0x1F[7:0] = 0 turn off RF*/},					\
 	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*LDO Sleep mode*/\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)			\
+	/*LDO Sleep mode*/},						\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*0x04[9] = 1 turn off MAC by HW state machine*/		\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},		\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)			\
+	/*0x04[9] = 1 turn off MAC by HW state machine*/},		\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*wait till 0x04[9] = 0 polling until return 0 to disable*/	\
-	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0			\
+	/*wait till 0x04[9] = 0 polling until return 0 to disable*/},
 
-
-#define RTL8188E_TRANS_CARDEMU_TO_SUS					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+#define RTL8188EE_TRANS_CARDEMU_TO_SUS					\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,				\
-	/*0x04[12:11] = 2b'01enable WL suspend*/			\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},	\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)		\
+	/*0x04[12:11] = 2b'01enable WL suspend*/},			\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
-	/*0x04[12:11] = 2b'11enable WL suspend for PCIe*/		\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)|BIT(4)},\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)|BIT(4)	\
+	/*0x04[12:11] = 2b'11enable WL suspend for PCIe*/},		\
 	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,				\
-	/*  0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, BIT(7)},			\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, BIT(7)			\
+	/*  0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */},\
 	{0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,				\
-	/*Clear SIC_EN register 0x40[12] = 1'b0 */			\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0			\
+	/*Clear SIC_EN register 0x40[12] = 1'b0 */},			\
 	{0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,				\
-	/*Set USB suspend enable local register  0xfe10[4]= 1 */	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)},		\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)			\
+	/*Set USB suspend enable local register  0xfe10[4]=1 */},	\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-	/*Set SDIO suspend local register*/				\
-	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)		\
+	/*Set SDIO suspend local register*/},				\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-	/*wait power state to suspend*/					\
-	PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0},
+	PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0			\
+	/*wait power state to suspend*/},
 
-#define RTL8188E_TRANS_SUS_TO_CARDEMU					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+#define RTL8188EE_TRANS_SUS_TO_CARDEMU					\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-	/*Set SDIO suspend local register*/				\
-	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0},			\
+	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0			\
+	/*Set SDIO suspend local register*/},				\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-	/*wait power state to suspend*/					\
-	PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},		\
+	PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)		\
+	/*wait power state to suspend*/},				\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*0x04[12:11] = 2b'01enable WL suspend*/			\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(4), 0		\
+	/*0x04[12:11] = 2b'01enable WL suspend*/},
 
-#define RTL8188E_TRANS_CARDEMU_TO_CARDDIS				\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+#define RTL8188EE_TRANS_CARDEMU_TO_CARDDIS				\
 	{0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*0x24[23] = 2b'01 schmit trigger */				\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)},		\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)			\
+	/*0x24[23] = 2b'01 schmit trigger */},				\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,				\
-	/*0x04[12:11] = 2b'01 enable WL suspend*/			\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},	\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)	\
+	/*0x04[12:11] = 2b'01 enable WL suspend*/},			\
 	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,				\
-	/*  0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0			\
+	/*  0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */},\
 	{0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,				\
-	/*Clear SIC_EN register 0x40[12] = 1'b0 */			\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0			\
+	/*Clear SIC_EN register 0x40[12] = 1'b0 */},			\
 	{0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,	\
-	/*Set USB suspend enable local register  0xfe10[4]= 1 */	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)},		\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)			\
+	/*Set USB suspend enable local register  0xfe10[4]=1 */},	\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-	/*Set SDIO suspend local register*/				\
-	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)		\
+	/*Set SDIO suspend local register*/},				\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-	PWR_CMD_POLLING, BIT(1), 0}, /*wait power state to suspend*/
+	PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0			\
+	/*wait power state to suspend*/},
 
-#define RTL8188E_TRANS_CARDDIS_TO_CARDEMU				\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+#define RTL8188EE_TRANS_CARDDIS_TO_CARDEMU				\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-	PWR_BASEADDR_SDIO,\
-	PWR_CMD_WRITE, BIT(0), 0}, /*Set SDIO suspend local register*/	\
+	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0			\
+	/*Set SDIO suspend local register*/},				\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-	PWR_BASEADDR_SDIO,\
-	PWR_CMD_POLLING, BIT(1), BIT(1)}, /*wait power state to suspend*/\
+	PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)		\
+	/*wait power state to suspend*/},				\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	PWR_BASEADDR_MAC,						\
-	PWR_CMD_WRITE, BIT(3)|BIT(4), 0},				\
-	/*0x04[12:11] = 2b'01enable WL suspend*/
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0		\
+	/*0x04[12:11] = 2b'01enable WL suspend*/},
 
-
-#define RTL8188E_TRANS_CARDEMU_TO_PDN					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+#define RTL8188EE_TRANS_CARDEMU_TO_PDN					\
 	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},/* 0x04[16] = 0*/	\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0/* 0x04[16] = 0*/},	\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)},/* 0x04[15] = 1*/
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)			\
+	/* 0x04[15] = 1*/},
 
-
-#define RTL8188E_TRANS_PDN_TO_CARDEMU					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+#define RTL8188EE_TRANS_PDN_TO_CARDEMU					\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},/* 0x04[15] = 0*/
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0/* 0x04[15] = 0*/},
 
-
-#define RTL8188E_TRANS_ACT_TO_LPS					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+#define RTL8188EE_TRANS_ACT_TO_LPS					\
 	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F},/*Tx Pause*/	\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F			\
+	/*Tx Pause*/},							\
 	{0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*zero if no pkt is tx*/\
-	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0			\
+	/*Should be zero if no packet is transmitting*/},		\
 	{0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*Should be zero if no packet is transmitting*/	\
-	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0			\
+	/*Should be zero if no packet is transmitting*/},		\
 	{0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*Should be zero if no packet is transmitting*/			\
-	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0			\
+	/*Should be zero if no packet is transmitting*/},		\
 	{0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*Should be zero if no packet is transmitting*/			\
-	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0			\
+	/*Should be zero if no packet is transmitting*/},		\
 	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*CCK and OFDM are disabled, and clock are gated*/		\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0			\
+	/*CCK and OFDM are disabled,and clock are gated*/},		\
 	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/\
+	PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US		\
+	/*Delay 1us*/},							\
 	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3F},/*Reset MAC TRX*/	\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3F			\
+	/*Reset MAC TRX*/},						\
 	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*check if removed later*/					\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0			\
+	/*check if removed later*/},					\
 	{0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*Respond TxOK to scheduler*/					\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)},		\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)			\
+	/*Respond TxOK to scheduler*/},
 
 
-#define RTL8188E_TRANS_LPS_TO_ACT					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+#define RTL8188EE_TRANS_LPS_TO_ACT					\
 	{0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/	\
+	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84			\
+	/*SDIO RPWM*/},							\
 	{0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/	\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84			\
+	/*USB RPWM*/},							\
 	{0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/	\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84			\
+	/*PCIe RPWM*/},							\
 	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/	\
+	PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS		\
+	/*Delay*/},							\
 	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*.	0x08[4] = 0		 switch TSF to 40M*/		\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0			\
+	/*.	0x08[4] = 0		 switch TSF to 40M*/},		\
 	{0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*Polling 0x109[7]= 0  TSF in 40M*/				\
-	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0},			\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0			\
+	/*Polling 0x109[7]=0  TSF in 40M*/},				\
 	{0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*. 0x29[7:6] = 2b'00	 enable BB clock*/			\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6)|BIT(7), 0},		\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6)|BIT(7), 0		\
+	/*.	0x29[7:6] = 2b'00	 enable BB clock*/},		\
 	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*.	0x101[1] = 1*/\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},		\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)			\
+	/*.	0x101[1] = 1*/},					\
 	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*.	0x100[7:0] = 0xFF	 enable WMAC TRX*/\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},			\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF			\
+	/*.	0x100[7:0] = 0xFF	 enable WMAC TRX*/},		\
 	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	/*. 0x02[1:0] = 2b'11  enable BB macro*/\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1)|BIT(0), BIT(1)|BIT(0)},	\
-	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
-	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*.	0x522 = 0*/
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1)|BIT(0), BIT(1)|BIT(0)	\
+	/*.	0x02[1:0] = 2b'11	 enable BB macro*/},		\
+	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0			\
+	/*.	0x522 = 0*/},
 
-
-#define RTL8188E_TRANS_END						\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+#define RTL8188EE_TRANS_END		\
 	{0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
 	0, PWR_CMD_END, 0, 0}
 
-extern struct wlan_pwr_cfg rtl8188e_power_on_flow
-		[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS +
-		RTL8188E_TRANS_END_STEPS];
-extern struct wlan_pwr_cfg rtl8188e_radio_off_flow
-		[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
-		RTL8188E_TRANS_END_STEPS];
-extern struct wlan_pwr_cfg rtl8188e_card_disable_flow
-		[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
-		RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
-		RTL8188E_TRANS_END_STEPS];
-extern struct wlan_pwr_cfg rtl8188e_card_enable_flow
-		[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
-		RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
-		RTL8188E_TRANS_END_STEPS];
-extern struct wlan_pwr_cfg rtl8188e_suspend_flow
-		[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
-		RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS +
-		RTL8188E_TRANS_END_STEPS];
-extern struct wlan_pwr_cfg rtl8188e_resume_flow
-		[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
-		RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS +
-		RTL8188E_TRANS_END_STEPS];
-extern struct wlan_pwr_cfg rtl8188e_hwpdn_flow
-		[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
-		RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
-		RTL8188E_TRANS_END_STEPS];
-extern struct wlan_pwr_cfg rtl8188e_enter_lps_flow
-		[RTL8188E_TRANS_ACT_TO_LPS_STEPS +
-		RTL8188E_TRANS_END_STEPS];
-extern struct wlan_pwr_cfg rtl8188e_leave_lps_flow
-		[RTL8188E_TRANS_LPS_TO_ACT_STEPS +
-		RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188ee_power_on_flow
+		[RTL8188EE_TRANS_CARDEMU_TO_ACT_STEPS +
+		 RTL8188EE_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188ee_radio_off_flow
+		[RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8188EE_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188ee_card_disable_flow
+		[RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8188EE_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8188EE_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188ee_card_enable_flow
+		[RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8188EE_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8188EE_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188ee_suspend_flow
+		[RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8188EE_TRANS_CARDEMU_TO_SUS_STEPS +
+		 RTL8188EE_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188ee_resume_flow
+		[RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8188EE_TRANS_CARDEMU_TO_SUS_STEPS +
+		 RTL8188EE_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188ee_hwpdn_flow
+		[RTL8188EE_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8188EE_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8188EE_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188ee_enter_lps_flow
+		[RTL8188EE_TRANS_ACT_TO_LPS_STEPS +
+		 RTL8188EE_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188ee_leave_lps_flow
+		[RTL8188EE_TRANS_LPS_TO_ACT_STEPS +
+		 RTL8188EE_TRANS_END_STEPS];
 
 /* RTL8723 Power Configuration CMDs for PCIe interface */
-#define Rtl8188E_NIC_PWR_ON_FLOW	rtl8188e_power_on_flow
-#define Rtl8188E_NIC_RF_OFF_FLOW	rtl8188e_radio_off_flow
-#define Rtl8188E_NIC_DISABLE_FLOW	rtl8188e_card_disable_flow
-#define Rtl8188E_NIC_ENABLE_FLOW	rtl8188e_card_enable_flow
-#define Rtl8188E_NIC_SUSPEND_FLOW	rtl8188e_suspend_flow
-#define Rtl8188E_NIC_RESUME_FLOW	rtl8188e_resume_flow
-#define Rtl8188E_NIC_PDN_FLOW		rtl8188e_hwpdn_flow
-#define Rtl8188E_NIC_LPS_ENTER_FLOW	rtl8188e_enter_lps_flow
-#define Rtl8188E_NIC_LPS_LEAVE_FLOW	rtl8188e_leave_lps_flow
+#define RTL8188EE_NIC_PWR_ON_FLOW	rtl8188ee_power_on_flow
+#define RTL8188EE_NIC_RF_OFF_FLOW	rtl8188ee_radio_off_flow
+#define RTL8188EE_NIC_DISABLE_FLOW	rtl8188ee_card_disable_flow
+#define RTL8188EE_NIC_ENABLE_FLOW	rtl8188ee_card_enable_flow
+#define RTL8188EE_NIC_SUSPEND_FLOW	rtl8188ee_suspend_flow
+#define RTL8188EE_NIC_RESUME_FLOW	rtl8188ee_resume_flow
+#define RTL8188EE_NIC_PDN_FLOW		rtl8188ee_hwpdn_flow
+#define RTL8188EE_NIC_LPS_ENTER_FLOW	rtl8188ee_enter_lps_flow
+#define RTL8188EE_NIC_LPS_LEAVE_FLOW	rtl8188ee_leave_lps_flow
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c
deleted file mode 100644
index 0f93142..0000000
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2009-2013  Realtek Corporation.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * wlanfae <wlanfae@realtek.com>
- * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
- * Hsinchu 300, Taiwan.
- *
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- *****************************************************************************/
-
-#include "pwrseq.h"
-
-
-/*	Description:
- *		This routine deal with the Power Configuration CMDs
- *		 parsing for RTL8723/RTL8188E Series IC.
- *	Assumption:
- *		We should follow specific format which was released from HW SD.
- *
- *	2011.07.07, added by Roger.
- */
-
-bool rtl88_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
-				u8 fab_version, u8 interface_type,
-				struct wlan_pwr_cfg pwrcfgcmd[])
-{
-	struct wlan_pwr_cfg cmd = {0};
-	bool polling_bit = false;
-	u32 ary_idx = 0;
-	u8 val = 0;
-	u32 offset = 0;
-	u32 polling_count = 0;
-	u32 max_polling_cnt = 5000;
-
-	do {
-		cmd = pwrcfgcmd[ary_idx];
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "rtl88_hal_pwrseqcmdparsing(): offset(%#x), cut_msk(%#x), fab_msk(%#x),"
-			 "interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), val(%#x)\n",
-			 GET_PWR_CFG_OFFSET(cmd),
-			 GET_PWR_CFG_CUT_MASK(cmd),
-			 GET_PWR_CFG_FAB_MASK(cmd),
-			 GET_PWR_CFG_INTF_MASK(cmd),
-			 GET_PWR_CFG_BASE(cmd),
-			 GET_PWR_CFG_CMD(cmd),
-			 GET_PWR_CFG_MASK(cmd),
-			 GET_PWR_CFG_VALUE(cmd));
-
-		if ((GET_PWR_CFG_FAB_MASK(cmd) & fab_version) &&
-		    (GET_PWR_CFG_CUT_MASK(cmd) & cut_version) &&
-		    (GET_PWR_CFG_INTF_MASK(cmd) & interface_type)) {
-			switch (GET_PWR_CFG_CMD(cmd)) {
-			case PWR_CMD_READ:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					 "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_READ\n");
-				break;
-			case PWR_CMD_WRITE: {
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					 "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n");
-				offset = GET_PWR_CFG_OFFSET(cmd);
-
-					/*Read the val from system register*/
-					val = rtl_read_byte(rtlpriv, offset);
-					val &= (~(GET_PWR_CFG_MASK(cmd)));
-					val |= (GET_PWR_CFG_VALUE(cmd) &
-						GET_PWR_CFG_MASK(cmd));
-
-					/*Write the val back to sytem register*/
-					rtl_write_byte(rtlpriv, offset, val);
-				}
-				break;
-			case PWR_CMD_POLLING:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					 "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n");
-				polling_bit = false;
-				offset = GET_PWR_CFG_OFFSET(cmd);
-
-				do {
-					val = rtl_read_byte(rtlpriv, offset);
-
-					val = val & GET_PWR_CFG_MASK(cmd);
-					if (val == (GET_PWR_CFG_VALUE(cmd) &
-						    GET_PWR_CFG_MASK(cmd)))
-						polling_bit = true;
-					else
-						udelay(10);
-
-					if (polling_count++ > max_polling_cnt) {
-						RT_TRACE(rtlpriv, COMP_INIT,
-							 DBG_LOUD,
-							 "polling fail in pwrseqcmd\n");
-						return false;
-					}
-				} while (!polling_bit);
-
-				break;
-			case PWR_CMD_DELAY:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					 "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n");
-				if (GET_PWR_CFG_VALUE(cmd) == PWRSEQ_DELAY_US)
-					udelay(GET_PWR_CFG_OFFSET(cmd));
-				else
-					mdelay(GET_PWR_CFG_OFFSET(cmd));
-				break;
-			case PWR_CMD_END:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					 "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_END\n");
-				return true;
-			default:
-				RT_ASSERT(false,
-					  "rtl88_hal_pwrseqcmdparsing(): Unknown CMD!!\n");
-				break;
-			}
-		}
-
-		ary_idx++;
-	} while (1);
-
-	return true;
-}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.h b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.h
deleted file mode 100644
index d9ae280..0000000
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2009-2013  Realtek Corporation.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * wlanfae <wlanfae@realtek.com>
- * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
- * Hsinchu 300, Taiwan.
- *
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- *****************************************************************************/
-
-#ifndef __RTL8723E_PWRSEQCMD_H__
-#define __RTL8723E_PWRSEQCMD_H__
-
-#include "../wifi.h"
-/*---------------------------------------------*/
-/* The value of cmd: 4 bits */
-/*---------------------------------------------*/
-#define PWR_CMD_READ		0x00
-#define PWR_CMD_WRITE		0x01
-#define PWR_CMD_POLLING		0x02
-#define PWR_CMD_DELAY		0x03
-#define PWR_CMD_END		0x04
-
-/* define the base address of each block */
-#define PWR_BASEADDR_MAC	0x00
-#define PWR_BASEADDR_USB	0x01
-#define PWR_BASEADDR_PCIE	0x02
-#define PWR_BASEADDR_SDIO	0x03
-
-#define PWR_INTF_SDIO_MSK	BIT(0)
-#define PWR_INTF_USB_MSK	BIT(1)
-#define PWR_INTF_PCI_MSK	BIT(2)
-#define PWR_INTF_ALL_MSK	(BIT(0)|BIT(1)|BIT(2)|BIT(3))
-
-#define	PWR_FAB_TSMC_MSK	BIT(0)
-#define	PWR_FAB_UMC_MSK		BIT(1)
-#define	PWR_FAB_ALL_MSK		(BIT(0)|BIT(1)|BIT(2)|BIT(3))
-
-#define	PWR_CUT_TESTCHIP_MSK	BIT(0)
-#define	PWR_CUT_A_MSK		BIT(1)
-#define	PWR_CUT_B_MSK		BIT(2)
-#define	PWR_CUT_C_MSK		BIT(3)
-#define	PWR_CUT_D_MSK		BIT(4)
-#define	PWR_CUT_E_MSK		BIT(5)
-#define	PWR_CUT_F_MSK		BIT(6)
-#define	PWR_CUT_G_MSK		BIT(7)
-#define	PWR_CUT_ALL_MSK		0xFF
-
-enum pwrseq_delay_unit {
-	PWRSEQ_DELAY_US,
-	PWRSEQ_DELAY_MS,
-};
-
-struct wlan_pwr_cfg {
-	u16 offset;
-	u8 cut_msk;
-	u8 fab_msk:4;
-	u8 interface_msk:4;
-	u8 base:4;
-	u8 cmd:4;
-	u8 msk;
-	u8 value;
-};
-
-#define	GET_PWR_CFG_OFFSET(__PWR)	(__PWR.offset)
-#define	GET_PWR_CFG_CUT_MASK(__PWR)	(__PWR.cut_msk)
-#define	GET_PWR_CFG_FAB_MASK(__PWR)	(__PWR.fab_msk)
-#define	GET_PWR_CFG_INTF_MASK(__PWR)	(__PWR.interface_msk)
-#define	GET_PWR_CFG_BASE(__PWR)		(__PWR.base)
-#define	GET_PWR_CFG_CMD(__PWR)		(__PWR.cmd)
-#define	GET_PWR_CFG_MASK(__PWR)		(__PWR.msk)
-#define	GET_PWR_CFG_VALUE(__PWR)	(__PWR.value)
-
-bool rtl88_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
-				u8 fab_version, u8 interface_type,
-				struct wlan_pwr_cfg pwrcfgcmd[]);
-
-#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h
index cd7e7a5..15400ee 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,62 +26,60 @@
 #ifndef __RTL92C_REG_H__
 #define __RTL92C_REG_H__
 
-#define TXPKT_BUF_SELECT			0x69
-#define RXPKT_BUF_SELECT			0xA5
-#define DISABLE_TRXPKT_BUF_ACCESS		0x0
+#define TXPKT_BUF_SELECT				0x69
+#define RXPKT_BUF_SELECT				0xA5
+#define DISABLE_TRXPKT_BUF_ACCESS			0x0
 
 #define REG_SYS_ISO_CTRL			0x0000
 #define REG_SYS_FUNC_EN				0x0002
 #define REG_APS_FSMCO				0x0004
 #define REG_SYS_CLKR				0x0008
-#define REG_9346CR				0x000A
-#define REG_EE_VPD				0x000C
+#define REG_9346CR					0x000A
+#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 REG_RF_CTRL					0x001F
 #define REG_LDOA15_CTRL				0x0020
 #define REG_LDOV12D_CTRL			0x0021
 #define REG_LDOHCI12_CTRL			0x0022
 #define REG_LPLDO_CTRL				0x0023
 #define REG_AFE_XTAL_CTRL			0x0024
-#define REG_AFE_LDO_CTRL			0x0027 /* 1.5v for 8188EE test
-							* chip, 1.4v for MP chip
-							*/
+/* 1.5v for 8188EE test chip, 1.4v for MP chip */
+#define REG_AFE_LDO_CTRL			0x0027
 #define REG_AFE_PLL_CTRL			0x0028
 #define REG_EFUSE_CTRL				0x0030
 #define REG_EFUSE_TEST				0x0034
 #define REG_PWR_DATA				0x0038
 #define REG_CAL_TIMER				0x003C
 #define REG_ACLK_MON				0x003E
-#define REG_GPIO_MUXCFG				0x0040
+#define REG_GPIO_MUXCFG			0x0040
 #define REG_GPIO_IO_SEL				0x0042
-#define REG_MAC_PINMUX_CFG			0x0043
+#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 REG_LEDCFG3				0x004F
-#define REG_FSIMR				0x0050
-#define REG_FSISR				0x0054
-#define REG_HSIMR				0x0058
-#define REG_HSISR				0x005c
-#define REG_GPIO_PIN_CTRL_2			0x0060
+#define REG_LEDCFG0					0x004C
+#define REG_LEDCFG1					0x004D
+#define REG_LEDCFG2					0x004E
+#define REG_LEDCFG3					0x004F
+#define REG_FSIMR					0x0050
+#define REG_FSISR					0x0054
+#define REG_HSIMR					0x0058
+#define REG_HSISR					0x005c
+#define REG_GPIO_PIN_CTRL_2		0x0060
 #define REG_GPIO_IO_SEL_2			0x0062
-#define REG_GPIO_OUTPUT				0x006c
-#define REG_AFE_XTAL_CTRL_EXT			0x0078
+#define REG_GPIO_OUTPUT			0x006c
+#define REG_AFE_XTAL_CTRL_EXT		0x0078
 #define REG_XCK_OUT_CTRL			0x007c
 #define REG_MCUFWDL				0x0080
 #define REG_WOL_EVENT				0x0081
 #define REG_MCUTSTCFG				0x0084
 
-
-#define REG_HIMR				0x00B0
-#define REG_HISR				0x00B4
-#define REG_HIMRE				0x00B8
-#define REG_HISRE				0x00BC
+#define REG_HIMR					0x00B0
+#define REG_HISR					0x00B4
+#define REG_HIMRE					0x00B8
+#define REG_HISRE					0x00BC
 
 #define REG_EFUSE_ACCESS			0x00CF
 
@@ -96,23 +90,23 @@
 #define REG_PCIE_MIO_INTF			0x00E4
 #define REG_PCIE_MIO_INTD			0x00E8
 #define REG_HPON_FSM				0x00EC
-#define REG_SYS_CFG				0x00F0
+#define REG_SYS_CFG					0x00F0
 
-#define REG_CR					0x0100
-#define REG_PBP					0x0104
-#define REG_PKT_BUFF_ACCESS_CTRL		0x0106
+#define REG_CR						0x0100
+#define REG_PBP						0x0104
+#define REG_PKT_BUFF_ACCESS_CTRL	0x0106
 #define REG_TRXDMA_CTRL				0x010C
 #define REG_TRXFF_BNDY				0x0114
 #define REG_TRXFF_STATUS			0x0118
 #define REG_RXFF_PTR				0x011C
 
-#define REG_CPWM				0x012F
-#define REG_FWIMR				0x0130
-#define REG_FWISR				0x0134
+#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_RXPKTBUF_CTRL			(REG_PKTBUF_DBG_CTRL+2)
+#define REG_PKTBUF_DBG_DATA_L		0x0144
+#define REG_PKTBUF_DBG_DATA_H		0x0148
+#define REG_RXPKTBUF_CTRL	(REG_PKTBUF_DBG_CTRL+2)
 
 #define REG_TC0_CTRL				0x0150
 #define REG_TC1_CTRL				0x0154
@@ -123,13 +117,13 @@
 #define REG_MBIST_START				0x0174
 #define REG_MBIST_DONE				0x0178
 #define REG_MBIST_FAIL				0x017C
-#define REG_32K_CTRL				0x0194
-#define REG_C2HEVT_MSG_NORMAL			0x01A0
+#define REG_32K_CTRL					0x0194
+#define REG_C2HEVT_MSG_NORMAL		0x01A0
 #define REG_C2HEVT_CLEAR			0x01AF
 #define REG_C2HEVT_MSG_TEST			0x01B8
 #define REG_MCUTST_1				0x01c0
-#define REG_FMETHR				0x01C8
-#define REG_HMETFR				0x01CC
+#define REG_FMETHR					0x01C8
+#define REG_HMETFR					0x01CC
 #define REG_HMEBOX_0				0x01D0
 #define REG_HMEBOX_1				0x01D4
 #define REG_HMEBOX_2				0x01D8
@@ -144,36 +138,37 @@
 #define REG_HMEBOX_EXT_2			0x01F8
 #define REG_HMEBOX_EXT_3			0x01FC
 
-#define REG_RQPN				0x0200
+#define REG_RQPN					0x0200
 #define REG_FIFOPAGE				0x0204
-#define REG_TDECTRL				0x0208
-#define REG_TXDMA_OFFSET_CHK			0x020C
+#define REG_TDECTRL					0x0208
+#define REG_TXDMA_OFFSET_CHK		0x020C
 #define REG_TXDMA_STATUS			0x0210
 #define REG_RQPN_NPQ				0x0214
 
-#define REG_RXDMA_AGG_PG_TH			0x0280
-#define REG_FW_UPD_RDPTR			0x0284 /* FW shall update this
-						* register before FW * write
-						* RXPKT_RELEASE_POLL to 1
-						*/
-#define REG_RXDMA_CONTROL			0x0286 /* Control the RX DMA.*/
-#define REG_RXPKT_NUM				0x0287 /* The number of packets
-							* in RXPKTBUF.
-							 */
+#define REG_RXDMA_AGG_PG_TH		0x0280
+/* FW shall update this register before
+ * FW write RXPKT_RELEASE_POLL to 1
+ */
+#define REG_FW_UPD_RDPTR			0x0284
+/* Control the RX DMA.*/
+#define REG_RXDMA_CONTROL			0x0286
+/* The number of packets in RXPKTBUF.	*/
+#define REG_RXPKT_NUM				0x0287
+
 #define	REG_PCIE_CTRL_REG			0x0300
-#define	REG_INT_MIG				0x0304
+#define	REG_INT_MIG					0x0304
 #define	REG_BCNQ_DESA				0x0308
-#define	REG_HQ_DESA				0x0310
+#define	REG_HQ_DESA					0x0310
 #define	REG_MGQ_DESA				0x0318
 #define	REG_VOQ_DESA				0x0320
 #define	REG_VIQ_DESA				0x0328
 #define	REG_BEQ_DESA				0x0330
 #define	REG_BKQ_DESA				0x0338
-#define	REG_RX_DESA				0x0340
+#define	REG_RX_DESA					0x0340
 
-#define	REG_DBI					0x0348
-#define	REG_MDIO				0x0354
-#define	REG_DBG_SEL				0x0360
+#define	REG_DBI						0x0348
+#define	REG_MDIO					0x0354
+#define	REG_DBG_SEL					0x0360
 #define	REG_PCIE_HRPWM				0x0361
 #define	REG_PCIE_HCPWM				0x0363
 #define	REG_UART_CTRL				0x0364
@@ -181,7 +176,6 @@
 #define	REG_UART_TX_DESA			0x0370
 #define	REG_UART_RX_DESA			0x0378
 
-
 #define	REG_HDAQ_DESA_NODEF			0x0000
 #define	REG_CMDQ_DESA_NODEF			0x0000
 
@@ -191,33 +185,32 @@
 #define REG_BKQ_INFORMATION			0x040C
 #define REG_MGQ_INFORMATION			0x0410
 #define REG_HGQ_INFORMATION			0x0414
-#define REG_BCNQ_INFORMATION			0x0418
+#define REG_BCNQ_INFORMATION		0x0418
 #define REG_TXPKT_EMPTY				0x041A
 
-
-#define REG_CPU_MGQ_INFORMATION			0x041C
+#define REG_CPU_MGQ_INFORMATION		0x041C
 #define REG_FWHW_TXQ_CTRL			0x0420
 #define REG_HWSEQ_CTRL				0x0423
-#define REG_TXPKTBUF_BCNQ_BDNY			0x0424
-#define REG_TXPKTBUF_MGQ_BDNY			0x0425
+#define REG_TXPKTBUF_BCNQ_BDNY		0x0424
+#define REG_TXPKTBUF_MGQ_BDNY		0x0425
 #define REG_MULTI_BCNQ_EN			0x0426
-#define REG_MULTI_BCNQ_OFFSET			0x0427
+#define REG_MULTI_BCNQ_OFFSET		0x0427
 #define REG_SPEC_SIFS				0x0428
-#define REG_RL					0x042A
-#define REG_DARFRC				0x0430
-#define REG_RARFRC				0x0438
-#define REG_RRSR				0x0440
-#define REG_ARFR0				0x0444
-#define REG_ARFR1				0x0448
-#define REG_ARFR2				0x044C
-#define REG_ARFR3				0x0450
+#define REG_RL						0x042A
+#define REG_DARFRC					0x0430
+#define REG_RARFRC					0x0438
+#define REG_RRSR					0x0440
+#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_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_INIDATA_RATE_SEL		0x0484
 #define REG_POWER_STATUS			0x04A4
 #define REG_POWER_STAGE1			0x04B4
 #define REG_POWER_STAGE2			0x04B8
@@ -225,32 +218,32 @@
 #define REG_STBC_SETTING			0x04C4
 #define REG_PROT_MODE_CTRL			0x04C8
 #define REG_BAR_MODE_CTRL			0x04CC
-#define REG_RA_TRY_RATE_AGG_LMT			0x04CF
-#define REG_EARLY_MODE_CONTROL			0x04D0
+#define REG_RA_TRY_RATE_AGG_LMT		0x04CF
+#define REG_EARLY_MODE_CONTROL		0x04D0
 #define REG_NQOS_SEQ				0x04DC
-#define REG_QOS_SEQ				0x04DE
+#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_TX_RPT_CTRL				0x04EC
 #define REG_TX_RPT_TIME				0x04F0
-#define REG_DUMMY				0x04FC
+#define REG_DUMMY					0x04FC
 
 #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 REG_BCNTCFG				0x0510
-#define REG_PIFS				0x0512
+#define REG_BCNTCFG					0x0510
+#define REG_PIFS					0x0512
 #define REG_RDG_PIFS				0x0513
 #define REG_SIFS_CTX				0x0514
 #define REG_SIFS_TRX				0x0516
 #define REG_AGGR_BREAK_TIME			0x051A
-#define REG_SLOT				0x051B
+#define REG_SLOT					0x051B
 #define REG_TX_PTCL_CTRL			0x0520
-#define REG_TXPAUSE				0x0522
+#define REG_TXPAUSE					0x0522
 #define REG_DIS_TXREQ_CLR			0x0523
-#define REG_RD_CTRL				0x0524
+#define REG_RD_CTRL					0x0524
 #define REG_TBTT_PROHIBIT			0x0540
 #define REG_RD_NAV_NXT				0x0544
 #define REG_NAV_PROT_LEN			0x0546
@@ -259,21 +252,21 @@
 #define REG_MBID_NUM				0x0552
 #define REG_DUAL_TSF_RST			0x0553
 #define REG_BCN_INTERVAL			0x0554
-#define REG_MBSSID_BCN_SPACE			0x0554
+#define REG_MBSSID_BCN_SPACE		0x0554
 #define REG_DRVERLYINT				0x0558
 #define REG_BCNDMATIM				0x0559
-#define REG_ATIMWND				0x055A
+#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_RXTSF_OFFSET_CCK		0x055E
+#define REG_RXTSF_OFFSET_OFDM		0x055F
+#define REG_TSFTR					0x0560
 #define REG_INIT_TSFTR				0x0564
-#define REG_PSTIMER				0x0580
-#define REG_TIMER0				0x0584
-#define REG_TIMER1				0x0588
+#define REG_PSTIMER					0x0580
+#define REG_TIMER0					0x0584
+#define REG_TIMER1					0x0588
 #define REG_ACMHWCTRL				0x05C0
 #define REG_ACMRSTCTRL				0x05C1
-#define REG_ACMAVG				0x05C2
+#define REG_ACMAVG					0x05C2
 #define REG_VO_ADMTIME				0x05C4
 #define REG_VI_ADMTIME				0x05C6
 #define REG_BE_ADMTIME				0x05C8
@@ -282,38 +275,38 @@
 
 #define REG_APSD_CTRL				0x0600
 #define REG_BWOPMODE				0x0603
-#define REG_TCR					0x0604
-#define REG_RCR					0x0608
+#define REG_TCR						0x0604
+#define REG_RCR						0x0608
 #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_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
 #define REG_RESP_SIFS_CCK			0x063C
 #define REG_RESP_SIFS_OFDM			0x063E
-#define REG_ACKTO				0x0640
-#define REG_CTS2TO				0x0641
-#define REG_EIFS				0x0642
+#define REG_ACKTO					0x0640
+#define REG_CTS2TO					0x0641
+#define REG_EIFS					0x0642
 
 #define REG_NAV_CTRL				0x0650
 #define REG_BACAMCMD				0x0654
 #define REG_BACAMCONTENT			0x0658
-#define REG_LBDLY				0x0660
-#define REG_FWDLY				0x0661
+#define REG_LBDLY					0x0660
+#define REG_FWDLY					0x0661
 #define REG_RXERR_RPT				0x0664
 #define REG_TRXPTCL_CTL				0x0668
 
-#define REG_CAMCMD				0x0670
+#define REG_CAMCMD					0x0670
 #define REG_CAMWRITE				0x0674
-#define REG_CAMREAD				0x0678
-#define REG_CAMDBG				0x067C
-#define REG_SECCFG				0x0680
+#define REG_CAMREAD					0x0678
+#define REG_CAMDBG					0x067C
+#define REG_SECCFG					0x0680
 
 #define REG_WOW_CTRL				0x0690
 #define REG_PSSTATUS				0x0691
@@ -329,10 +322,10 @@
 #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_WMAC_RESP_TXINFO		0x06D8
 
 #define REG_USB_INFO				0xFE17
-#define REG_USB_SPECIAL_OPTION			0xFE55
+#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
@@ -340,523 +333,545 @@
 #define REG_TEST_USB_TXQS			0xFE48
 #define REG_TEST_SIE_VID			0xFE60
 #define REG_TEST_SIE_PID			0xFE62
-#define REG_TEST_SIE_OPTIONAL			0xFE64
-#define REG_TEST_SIE_CHIRP_K			0xFE65
+#define REG_TEST_SIE_OPTIONAL		0xFE64
+#define REG_TEST_SIE_CHIRP_K		0xFE65
 #define REG_TEST_SIE_PHY			0xFE66
-#define REG_TEST_SIE_MAC_ADDR			0xFE70
+#define REG_TEST_SIE_MAC_ADDR		0xFE70
 #define REG_TEST_SIE_STRING			0xFE80
 
 #define REG_NORMAL_SIE_VID			0xFE60
 #define REG_NORMAL_SIE_PID			0xFE62
-#define REG_NORMAL_SIE_OPTIONAL			0xFE64
+#define REG_NORMAL_SIE_OPTIONAL		0xFE64
 #define REG_NORMAL_SIE_EP			0xFE65
 #define REG_NORMAL_SIE_PHY			0xFE68
-#define REG_NORMAL_SIE_MAC_ADDR			0xFE70
-#define REG_NORMAL_SIE_STRING			0xFE80
+#define REG_NORMAL_SIE_MAC_ADDR		0xFE70
+#define REG_NORMAL_SIE_STRING		0xFE80
 
-#define	CR9346					REG_9346CR
-#define	MSR					(REG_CR + 2)
-#define	ISR					REG_HISR
-#define	TSFR					REG_TSFTR
+#define	CR9346				REG_9346CR
+#define	MSR				(REG_CR + 2)
+#define	ISR				REG_HISR
+#define	TSFR				REG_TSFTR
 
-#define	MACIDR0					REG_MACID
-#define	MACIDR4					(REG_MACID + 4)
+#define	MACIDR0				REG_MACID
+#define	MACIDR4				(REG_MACID + 4)
 
-#define PBP					REG_PBP
+#define PBP				REG_PBP
 
-#define	IDR0					MACIDR0
-#define	IDR4					MACIDR4
+#define	IDR0				MACIDR0
+#define	IDR4				MACIDR4
 
-#define	UNUSED_REGISTER				0x1BF
-#define	DCAM					UNUSED_REGISTER
-#define	PSR					UNUSED_REGISTER
-#define BBADDR					UNUSED_REGISTER
-#define	PHYDATAR				UNUSED_REGISTER
+#define	UNUSED_REGISTER			0x1BF
+#define	DCAM				UNUSED_REGISTER
+#define	PSR				UNUSED_REGISTER
+#define BBADDR				UNUSED_REGISTER
+#define	PHYDATAR			UNUSED_REGISTER
 
-#define	INVALID_BBRF_VALUE			0x12345678
+#define	INVALID_BBRF_VALUE		0x12345678
 
-#define	MAX_MSS_DENSITY_2T			0x13
-#define	MAX_MSS_DENSITY_1T			0x0A
+#define	MAX_MSS_DENSITY_2T		0x13
+#define	MAX_MSS_DENSITY_1T		0x0A
 
-#define	CMDEEPROM_EN				BIT(5)
-#define	CMDEEPROM_SEL				BIT(4)
-#define	CMD9346CR_9356SEL			BIT(4)
-#define	AUTOLOAD_EEPROM				(CMDEEPROM_EN|CMDEEPROM_SEL)
-#define	AUTOLOAD_EFUSE				CMDEEPROM_EN
+#define	CMDEEPROM_EN			BIT(5)
+#define	CMDEEPROM_SEL			BIT(4)
+#define	CMD9346CR_9356SEL		BIT(4)
+#define	AUTOLOAD_EEPROM			(CMDEEPROM_EN|CMDEEPROM_SEL)
+#define	AUTOLOAD_EFUSE			CMDEEPROM_EN
 
-#define	GPIOSEL_GPIO				0
-#define	GPIOSEL_ENBT				BIT(5)
+#define	GPIOSEL_GPIO			0
+#define	GPIOSEL_ENBT			BIT(5)
 
-#define	GPIO_IN					REG_GPIO_PIN_CTRL
-#define	GPIO_OUT				(REG_GPIO_PIN_CTRL+1)
-#define	GPIO_IO_SEL				(REG_GPIO_PIN_CTRL+2)
-#define	GPIO_MOD				(REG_GPIO_PIN_CTRL+3)
+#define	GPIO_IN				REG_GPIO_PIN_CTRL
+#define	GPIO_OUT			(REG_GPIO_PIN_CTRL+1)
+#define	GPIO_IO_SEL			(REG_GPIO_PIN_CTRL+2)
+#define	GPIO_MOD			(REG_GPIO_PIN_CTRL+3)
 
-/* 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */
+/*8723/8188E Host System Interrupt
+ *Mask Register (offset 0x58, 32 byte)
+ */
 #define	HSIMR_GPIO12_0_INT_EN			BIT(0)
 #define	HSIMR_SPS_OCP_INT_EN			BIT(5)
 #define	HSIMR_RON_INT_EN			BIT(6)
 #define	HSIMR_PDN_INT_EN			BIT(7)
 #define	HSIMR_GPIO9_INT_EN			BIT(25)
 
-
-/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */
+/*       8723/8188E Host System Interrupt
+ *		Status Register (offset 0x5C, 32 byte)
+ */
 #define	HSISR_GPIO12_0_INT			BIT(0)
 #define	HSISR_SPS_OCP_INT			BIT(5)
 #define	HSISR_RON_INT_EN			BIT(6)
 #define	HSISR_PDNINT				BIT(7)
 #define	HSISR_GPIO9_INT				BIT(25)
 
-#define	MSR_NOLINK				0x00
-#define	MSR_ADHOC				0x01
-#define	MSR_INFRA				0x02
-#define	MSR_AP					0x03
-#define	MSR_MASK				0x03
+#define	MSR_NOLINK					0x00
+#define	MSR_ADHOC					0x01
+#define	MSR_INFRA					0x02
+#define	MSR_AP						0x03
 
 #define	RRSR_RSC_OFFSET				21
 #define	RRSR_SHORT_OFFSET			23
 #define	RRSR_RSC_BW_40M				0x600000
 #define	RRSR_RSC_UPSUBCHNL			0x400000
 #define	RRSR_RSC_LOWSUBCHNL			0x200000
-#define	RRSR_SHORT				0x800000
-#define	RRSR_1M					BIT(0)
-#define	RRSR_2M					BIT(1)
-#define	RRSR_5_5M				BIT(2)
-#define	RRSR_11M				BIT(3)
-#define	RRSR_6M					BIT(4)
-#define	RRSR_9M					BIT(5)
-#define	RRSR_12M				BIT(6)
-#define	RRSR_18M				BIT(7)
-#define	RRSR_24M				BIT(8)
-#define	RRSR_36M				BIT(9)
-#define	RRSR_48M				BIT(10)
-#define	RRSR_54M				BIT(11)
-#define	RRSR_MCS0				BIT(12)
-#define	RRSR_MCS1				BIT(13)
-#define	RRSR_MCS2				BIT(14)
-#define	RRSR_MCS3				BIT(15)
-#define	RRSR_MCS4				BIT(16)
-#define	RRSR_MCS5				BIT(17)
-#define	RRSR_MCS6				BIT(18)
-#define	RRSR_MCS7				BIT(19)
+#define	RRSR_SHORT					0x800000
+#define	RRSR_1M						BIT(0)
+#define	RRSR_2M						BIT(1)
+#define	RRSR_5_5M					BIT(2)
+#define	RRSR_11M					BIT(3)
+#define	RRSR_6M						BIT(4)
+#define	RRSR_9M						BIT(5)
+#define	RRSR_12M					BIT(6)
+#define	RRSR_18M					BIT(7)
+#define	RRSR_24M					BIT(8)
+#define	RRSR_36M					BIT(9)
+#define	RRSR_48M					BIT(10)
+#define	RRSR_54M					BIT(11)
+#define	RRSR_MCS0					BIT(12)
+#define	RRSR_MCS1					BIT(13)
+#define	RRSR_MCS2					BIT(14)
+#define	RRSR_MCS3					BIT(15)
+#define	RRSR_MCS4					BIT(16)
+#define	RRSR_MCS5					BIT(17)
+#define	RRSR_MCS6					BIT(18)
+#define	RRSR_MCS7					BIT(19)
 #define	BRSR_ACKSHORTPMB			BIT(23)
 
-#define	RATR_1M					0x00000001
-#define	RATR_2M					0x00000002
-#define	RATR_55M				0x00000004
-#define	RATR_11M				0x00000008
-#define	RATR_6M					0x00000010
-#define	RATR_9M					0x00000020
-#define	RATR_12M				0x00000040
-#define	RATR_18M				0x00000080
-#define	RATR_24M				0x00000100
-#define	RATR_36M				0x00000200
-#define	RATR_48M				0x00000400
-#define	RATR_54M				0x00000800
-#define	RATR_MCS0				0x00001000
-#define	RATR_MCS1				0x00002000
-#define	RATR_MCS2				0x00004000
-#define	RATR_MCS3				0x00008000
-#define	RATR_MCS4				0x00010000
-#define	RATR_MCS5				0x00020000
-#define	RATR_MCS6				0x00040000
-#define	RATR_MCS7				0x00080000
-#define	RATR_MCS8				0x00100000
-#define	RATR_MCS9				0x00200000
-#define	RATR_MCS10				0x00400000
-#define	RATR_MCS11				0x00800000
-#define	RATR_MCS12				0x01000000
-#define	RATR_MCS13				0x02000000
-#define	RATR_MCS14				0x04000000
-#define	RATR_MCS15				0x08000000
+#define	RATR_1M						0x00000001
+#define	RATR_2M						0x00000002
+#define	RATR_55M					0x00000004
+#define	RATR_11M					0x00000008
+#define	RATR_6M						0x00000010
+#define	RATR_9M						0x00000020
+#define	RATR_12M					0x00000040
+#define	RATR_18M					0x00000080
+#define	RATR_24M					0x00000100
+#define	RATR_36M					0x00000200
+#define	RATR_48M					0x00000400
+#define	RATR_54M					0x00000800
+#define	RATR_MCS0					0x00001000
+#define	RATR_MCS1					0x00002000
+#define	RATR_MCS2					0x00004000
+#define	RATR_MCS3					0x00008000
+#define	RATR_MCS4					0x00010000
+#define	RATR_MCS5					0x00020000
+#define	RATR_MCS6					0x00040000
+#define	RATR_MCS7					0x00080000
+#define	RATR_MCS8					0x00100000
+#define	RATR_MCS9					0x00200000
+#define	RATR_MCS10					0x00400000
+#define	RATR_MCS11					0x00800000
+#define	RATR_MCS12					0x01000000
+#define	RATR_MCS13					0x02000000
+#define	RATR_MCS14					0x04000000
+#define	RATR_MCS15					0x08000000
 
-#define RATE_1M					BIT(0)
-#define RATE_2M					BIT(1)
-#define RATE_5_5M				BIT(2)
-#define RATE_11M				BIT(3)
-#define RATE_6M					BIT(4)
-#define RATE_9M					BIT(5)
-#define RATE_12M				BIT(6)
-#define RATE_18M				BIT(7)
-#define RATE_24M				BIT(8)
-#define RATE_36M				BIT(9)
-#define RATE_48M				BIT(10)
-#define RATE_54M				BIT(11)
-#define RATE_MCS0				BIT(12)
-#define RATE_MCS1				BIT(13)
-#define RATE_MCS2				BIT(14)
-#define RATE_MCS3				BIT(15)
-#define RATE_MCS4				BIT(16)
-#define RATE_MCS5				BIT(17)
-#define RATE_MCS6				BIT(18)
-#define RATE_MCS7				BIT(19)
-#define RATE_MCS8				BIT(20)
-#define RATE_MCS9				BIT(21)
-#define RATE_MCS10				BIT(22)
-#define RATE_MCS11				BIT(23)
-#define RATE_MCS12				BIT(24)
-#define RATE_MCS13				BIT(25)
-#define RATE_MCS14				BIT(26)
-#define RATE_MCS15				BIT(27)
+#define RATE_1M						BIT(0)
+#define RATE_2M						BIT(1)
+#define RATE_5_5M					BIT(2)
+#define RATE_11M					BIT(3)
+#define RATE_6M						BIT(4)
+#define RATE_9M						BIT(5)
+#define RATE_12M					BIT(6)
+#define RATE_18M					BIT(7)
+#define RATE_24M					BIT(8)
+#define RATE_36M					BIT(9)
+#define RATE_48M					BIT(10)
+#define RATE_54M					BIT(11)
+#define RATE_MCS0					BIT(12)
+#define RATE_MCS1					BIT(13)
+#define RATE_MCS2					BIT(14)
+#define RATE_MCS3					BIT(15)
+#define RATE_MCS4					BIT(16)
+#define RATE_MCS5					BIT(17)
+#define RATE_MCS6					BIT(18)
+#define RATE_MCS7					BIT(19)
+#define RATE_MCS8					BIT(20)
+#define RATE_MCS9					BIT(21)
+#define RATE_MCS10					BIT(22)
+#define RATE_MCS11					BIT(23)
+#define RATE_MCS12					BIT(24)
+#define RATE_MCS13					BIT(25)
+#define RATE_MCS14					BIT(26)
+#define RATE_MCS15					BIT(27)
 
 #define	RATE_ALL_CCK		(RATR_1M | RATR_2M | RATR_55M | RATR_11M)
-#define	RATE_ALL_OFDM_AG	(RATR_6M | RATR_9M | RATR_12M | RATR_18M | \
+#define	RATE_ALL_OFDM_AG	(RATR_6M | RATR_9M | RATR_12M | RATR_18M |\
 				RATR_24M | RATR_36M | RATR_48M | RATR_54M)
-#define	RATE_ALL_OFDM_1SS	(RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | \
-				RATR_MCS3 | RATR_MCS4 | RATR_MCS5 | \
+#define	RATE_ALL_OFDM_1SS	(RATR_MCS0 | RATR_MCS1 | RATR_MCS2 |\
+				RATR_MCS3 | RATR_MCS4 | RATR_MCS5 |\
 				RATR_MCS6 | RATR_MCS7)
-#define	RATE_ALL_OFDM_2SS	(RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | \
-				RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \
+#define	RATE_ALL_OFDM_2SS	(RATR_MCS8 | RATR_MCS9 | RATR_MCS10 |\
+				RATR_MCS11 | RATR_MCS12 | RATR_MCS13 |\
 				RATR_MCS14 | RATR_MCS15)
 
 #define	BW_OPMODE_20MHZ				BIT(2)
 #define	BW_OPMODE_5G				BIT(1)
 #define	BW_OPMODE_11J				BIT(0)
 
-#define	CAM_VALID				BIT(15)
+#define	CAM_VALID					BIT(15)
 #define	CAM_NOTVALID				0x0000
-#define	CAM_USEDK				BIT(5)
+#define	CAM_USEDK					BIT(5)
 
-#define	CAM_NONE				0x0
-#define	CAM_WEP40				0x01
-#define	CAM_TKIP				0x02
-#define	CAM_AES					0x04
-#define	CAM_WEP104				0x05
+#define	CAM_NONE					0x0
+#define	CAM_WEP40					0x01
+#define	CAM_TKIP					0x02
+#define	CAM_AES						0x04
+#define	CAM_WEP104					0x05
 
 #define	TOTAL_CAM_ENTRY				32
 #define	HALF_CAM_ENTRY				16
 
-#define	CAM_WRITE				BIT(16)
-#define	CAM_READ				0x00000000
+#define	CAM_WRITE					BIT(16)
+#define	CAM_READ					0x00000000
 #define	CAM_POLLINIG				BIT(31)
 
-#define	SCR_USEDK				0x01
+#define	SCR_USEDK					0x01
 #define	SCR_TXSEC_ENABLE			0x02
 #define	SCR_RXSEC_ENABLE			0x04
 
-#define	WOW_PMEN				BIT(0)
-#define	WOW_WOMEN				BIT(1)
-#define	WOW_MAGIC				BIT(2)
-#define	WOW_UWF					BIT(3)
+#define	WOW_PMEN					BIT(0)
+#define	WOW_WOMEN					BIT(1)
+#define	WOW_MAGIC					BIT(2)
+#define	WOW_UWF						BIT(3)
 
 /*********************************************
 *       8188 IMR/ISR bits
 **********************************************/
-#define	IMR_DISABLED				0x0
+#define	IMR_DISABLED			0x0
 /* IMR DW0(0x0060-0063) Bit 0-31 */
-#define	IMR_TXCCK		BIT(30) /* TXRPT interrupt when CCX bit of
-					 * the packet is set
-					 */
-#define	IMR_PSTIMEOUT		BIT(29)	/* Power Save Time Out Interrupt */
-#define	IMR_GTINT4		BIT(28)	/* When GTIMER4 expires,
-					 * this bit is set to 1
-					 */
-#define	IMR_GTINT3		BIT(27)	/* When GTIMER3 expires,
-					 * this bit is set to 1
-					 */
-#define	IMR_TBDER		BIT(26)	/* Transmit Beacon0 Error */
-#define	IMR_TBDOK		BIT(25)	/* Transmit Beacon0 OK	*/
-#define	IMR_TSF_BIT32_TOGGLE	BIT(24)	/* TSF Timer BIT32 toggle ind int */
-#define	IMR_BCNDMAINT0		BIT(20)	/* Beacon DMA Interrupt 0 */
-#define	IMR_BCNDOK0		BIT(16)	/* Beacon Queue DMA OK0	*/
-#define	IMR_HSISR_IND_ON_INT	BIT(15)	/* HSISR Indicator (HSIMR & HSISR is
-					 * true, this bit is set to 1)
-					 */
-#define	IMR_BCNDMAINT_E		BIT(14)	/* Beacon DMA Int Extension for Win7 */
-#define	IMR_ATIMEND		BIT(12)	/* CTWidnow End or ATIM Window End */
-#define	IMR_HISR1_IND_INT	BIT(11)	/* HISR1 Indicator (HISR1 & HIMR1 is
-					 * true, this bit is set to 1)
-					 */
-#define	IMR_C2HCMD		BIT(10)	/* CPU to Host Command INT Status,
-					 * Write 1 clear
-					 */
-#define	IMR_CPWM2		BIT(9)	/* CPU power Mode exchange INT Status,
-					 * Write 1 clear
-					 */
-#define	IMR_CPWM		BIT(8)	/* CPU power Mode exchange INT Status,
-					 * Write 1 clear
-					 */
-#define	IMR_HIGHDOK		BIT(7)	/* High Queue DMA OK	*/
-#define	IMR_MGNTDOK		BIT(6)	/* Management Queue DMA OK */
-#define	IMR_BKDOK		BIT(5)	/* AC_BK DMA OK		*/
-#define	IMR_BEDOK		BIT(4)	/* AC_BE DMA OK	*/
-#define	IMR_VIDOK		BIT(3)	/* AC_VI DMA OK	*/
-#define	IMR_VODOK		BIT(2)	/* AC_VO DMA OK	*/
-#define	IMR_RDU			BIT(1)	/* Rx Descriptor Unavailable */
-#define	IMR_ROK			BIT(0)	/* Receive DMA OK */
+/* TXRPT interrupt when CCX bit of the packet is set	*/
+#define	IMR_TXCCK				BIT(30)
+/* Power Save Time Out Interrupt */
+#define	IMR_PSTIMEOUT			BIT(29)
+/* When GTIMER4 expires, this bit is set to 1	*/
+#define	IMR_GTINT4				BIT(28)
+/* When GTIMER3 expires, this bit is set to 1	*/
+#define	IMR_GTINT3				BIT(27)
+/* Transmit Beacon0 Error			*/
+#define	IMR_TBDER				BIT(26)
+/* Transmit Beacon0 OK			*/
+#define	IMR_TBDOK				BIT(25)
+/* TSF Timer BIT32 toggle indication interrupt	*/
+#define	IMR_TSF_BIT32_TOGGLE		BIT(24)
+/* Beacon DMA Interrupt 0			*/
+#define	IMR_BCNDMAINT0			BIT(20)
+/* Beacon Queue DMA OK0			*/
+#define	IMR_BCNDOK0				BIT(16)
+/* HSISR Indicator (HSIMR & HSISR is true, this bit is set to 1)	*/
+#define	IMR_HSISR_IND_ON_INT		BIT(15)
+/* Beacon DMA Interrupt Extension for Win7			*/
+#define	IMR_BCNDMAINT_E			BIT(14)
+/* CTWidnow End or ATIM Window End */
+#define	IMR_ATIMEND				BIT(12)
+/* HISR1 Indicator (HISR1 & HIMR1 is true, this bit is set to 1)*/
+#define	IMR_HISR1_IND_INT			BIT(11)
+/* CPU to Host Command INT Status, Write 1 clear	*/
+#define	IMR_C2HCMD				BIT(10)
+/* CPU power Mode exchange INT Status, Write 1 clear	*/
+#define	IMR_CPWM2			BIT(9)
+/* CPU power Mode exchange INT Status, Write 1 clear	*/
+#define	IMR_CPWM				BIT(8)
+/* High Queue DMA OK	*/
+#define	IMR_HIGHDOK				BIT(7)
+/* Management Queue DMA OK	*/
+#define	IMR_MGNTDOK				BIT(6)
+/* AC_BK DMA OK		*/
+#define	IMR_BKDOK				BIT(5)
+/* AC_BE DMA OK	*/
+#define	IMR_BEDOK				BIT(4)
+/* AC_VI DMA OK	*/
+#define	IMR_VIDOK				BIT(3)
+/* AC_VO DMA OK	*/
+#define	IMR_VODOK				BIT(2)
+/* Rx Descriptor Unavailable	*/
+#define	IMR_RDU				BIT(1)
+/* Receive DMA OK */
+#define	IMR_ROK				BIT(0)
 
 /* IMR DW1(0x00B4-00B7) Bit 0-31 */
-#define	IMR_BCNDMAINT7		BIT(27)	/* Beacon DMA Interrupt 7 */
-#define	IMR_BCNDMAINT6		BIT(26)	/* Beacon DMA Interrupt 6 */
-#define	IMR_BCNDMAINT5		BIT(25)	/* Beacon DMA Interrupt 5 */
-#define	IMR_BCNDMAINT4		BIT(24)	/* Beacon DMA Interrupt 4 */
-#define	IMR_BCNDMAINT3		BIT(23)	/* Beacon DMA Interrupt 3 */
-#define	IMR_BCNDMAINT2		BIT(22)	/* Beacon DMA Interrupt 2 */
-#define	IMR_BCNDMAINT1		BIT(21)	/* Beacon DMA Interrupt 1 */
-#define	IMR_BCNDOK7		BIT(20)	/* Beacon Queue DMA OK Interrup 7 */
-#define	IMR_BCNDOK6		BIT(19)	/* Beacon Queue DMA OK Interrup 6 */
-#define	IMR_BCNDOK5		BIT(18)	/* Beacon Queue DMA OK Interrup 5 */
-#define	IMR_BCNDOK4		BIT(17)	/* Beacon Queue DMA OK Interrup 4 */
-#define	IMR_BCNDOK3		BIT(16)	/* Beacon Queue DMA OK Interrup 3 */
-#define	IMR_BCNDOK2		BIT(15)	/* Beacon Queue DMA OK Interrup 2 */
-#define	IMR_BCNDOK1		BIT(14)	/* Beacon Queue DMA OK Interrup 1 */
-#define	IMR_ATIMEND_E		BIT(13)	/* ATIM Window End Extension for Win7 */
-#define	IMR_TXERR		BIT(11)	/* Tx Err Flag Int Status,
-					 * write 1 clear.
-					 */
-#define	IMR_RXERR		BIT(10)	/* Rx Err Flag INT Status,
-					 * Write 1 clear
-					 */
-#define	IMR_TXFOVW		BIT(9)	/* Transmit FIFO Overflow */
-#define	IMR_RXFOVW		BIT(8)	/* Receive FIFO Overflow */
-
+/* Beacon DMA Interrupt 7	*/
+#define	IMR_BCNDMAINT7			BIT(27)
+/* Beacon DMA Interrupt 6		*/
+#define	IMR_BCNDMAINT6			BIT(26)
+/* Beacon DMA Interrupt 5		*/
+#define	IMR_BCNDMAINT5			BIT(25)
+/* Beacon DMA Interrupt 4		*/
+#define	IMR_BCNDMAINT4			BIT(24)
+/* Beacon DMA Interrupt 3		*/
+#define	IMR_BCNDMAINT3			BIT(23)
+/* Beacon DMA Interrupt 2		*/
+#define	IMR_BCNDMAINT2			BIT(22)
+/* Beacon DMA Interrupt 1		*/
+#define	IMR_BCNDMAINT1			BIT(21)
+/* Beacon Queue DMA OK Interrup 7 */
+#define	IMR_BCNDOK7				BIT(20)
+/* Beacon Queue DMA OK Interrup 6 */
+#define	IMR_BCNDOK6				BIT(19)
+/* Beacon Queue DMA OK Interrup 5 */
+#define	IMR_BCNDOK5				BIT(18)
+/* Beacon Queue DMA OK Interrup 4 */
+#define	IMR_BCNDOK4				BIT(17)
+/* Beacon Queue DMA OK Interrup 3 */
+#define	IMR_BCNDOK3				BIT(16)
+/* Beacon Queue DMA OK Interrup 2 */
+#define	IMR_BCNDOK2				BIT(15)
+/* Beacon Queue DMA OK Interrup 1 */
+#define	IMR_BCNDOK1				BIT(14)
+/* ATIM Window End Extension for Win7 */
+#define	IMR_ATIMEND_E		BIT(13)
+/* Tx Error Flag Interrupt Status, write 1 clear. */
+#define	IMR_TXERR				BIT(11)
+/* Rx Error Flag INT Status, Write 1 clear */
+#define	IMR_RXERR				BIT(10)
+/* Transmit FIFO Overflow */
+#define	IMR_TXFOVW				BIT(9)
+/* Receive FIFO Overflow */
+#define	IMR_RXFOVW				BIT(8)
 
 #define	HWSET_MAX_SIZE				512
 #define   EFUSE_MAX_SECTION			64
-#define   EFUSE_REAL_CONTENT_LEN		256
-#define	EFUSE_OOB_PROTECT_BYTES			18 /* PG data exclude header,
-						    * dummy 7 bytes frome CP
-						    * test and reserved 1byte.
-						    */
+#define   EFUSE_REAL_CONTENT_LEN			256
+/* PG data exclude header, dummy 7 bytes frome CP test and reserved 1byte.*/
+#define		EFUSE_OOB_PROTECT_BYTES		18
 
-#define	EEPROM_DEFAULT_TSSI			0x0
-#define EEPROM_DEFAULT_TXPOWERDIFF		0x0
-#define EEPROM_DEFAULT_CRYSTALCAP		0x5
-#define EEPROM_DEFAULT_BOARDTYPE		0x02
-#define EEPROM_DEFAULT_TXPOWER			0x1010
-#define	EEPROM_DEFAULT_HT2T_TXPWR		0x10
+#define	EEPROM_DEFAULT_TSSI					0x0
+#define EEPROM_DEFAULT_TXPOWERDIFF			0x0
+#define EEPROM_DEFAULT_CRYSTALCAP			0x5
+#define EEPROM_DEFAULT_BOARDTYPE			0x02
+#define EEPROM_DEFAULT_TXPOWER				0x1010
+#define	EEPROM_DEFAULT_HT2T_TXPWR			0x10
 
 #define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3
-#define	EEPROM_DEFAULT_THERMALMETER		0x18
+#define	EEPROM_DEFAULT_THERMALMETER			0x18
 #define	EEPROM_DEFAULT_ANTTXPOWERDIFF		0x0
 #define	EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP	0x5
-#define	EEPROM_DEFAULT_TXPOWERLEVEL		0x22
-#define	EEPROM_DEFAULT_HT40_2SDIFF		0x0
-#define EEPROM_DEFAULT_HT20_DIFF		2
+#define	EEPROM_DEFAULT_TXPOWERLEVEL			0x22
+#define	EEPROM_DEFAULT_HT40_2SDIFF			0x0
+#define EEPROM_DEFAULT_HT20_DIFF			2
 #define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3
 #define EEPROM_DEFAULT_HT40_PWRMAXOFFSET	0
 #define EEPROM_DEFAULT_HT20_PWRMAXOFFSET	0
 
-#define RF_OPTION1				0x79
-#define RF_OPTION2				0x7A
-#define RF_OPTION3				0x7B
-#define RF_OPTION4				0x7C
+#define RF_OPTION1							0x79
+#define RF_OPTION2							0x7A
+#define RF_OPTION3							0x7B
+#define RF_OPTION4							0x7C
 
-#define EEPROM_DEFAULT_PID			0x1234
-#define EEPROM_DEFAULT_VID			0x5678
-#define EEPROM_DEFAULT_CUSTOMERID		0xAB
+#define EEPROM_DEFAULT_PID					0x1234
+#define EEPROM_DEFAULT_VID					0x5678
+#define EEPROM_DEFAULT_CUSTOMERID			0xAB
 #define EEPROM_DEFAULT_SUBCUSTOMERID		0xCD
-#define EEPROM_DEFAULT_VERSION			0
+#define EEPROM_DEFAULT_VERSION				0
 
-#define	EEPROM_CHANNEL_PLAN_FCC			0x0
-#define	EEPROM_CHANNEL_PLAN_IC			0x1
-#define	EEPROM_CHANNEL_PLAN_ETSI		0x2
-#define	EEPROM_CHANNEL_PLAN_SPAIN		0x3
-#define	EEPROM_CHANNEL_PLAN_FRANCE		0x4
-#define	EEPROM_CHANNEL_PLAN_MKK			0x5
-#define	EEPROM_CHANNEL_PLAN_MKK1		0x6
-#define	EEPROM_CHANNEL_PLAN_ISRAEL		0x7
-#define	EEPROM_CHANNEL_PLAN_TELEC		0x8
+#define	EEPROM_CHANNEL_PLAN_FCC				0x0
+#define	EEPROM_CHANNEL_PLAN_IC				0x1
+#define	EEPROM_CHANNEL_PLAN_ETSI			0x2
+#define	EEPROM_CHANNEL_PLAN_SPAIN			0x3
+#define	EEPROM_CHANNEL_PLAN_FRANCE			0x4
+#define	EEPROM_CHANNEL_PLAN_MKK				0x5
+#define	EEPROM_CHANNEL_PLAN_MKK1			0x6
+#define	EEPROM_CHANNEL_PLAN_ISRAEL			0x7
+#define	EEPROM_CHANNEL_PLAN_TELEC			0x8
 #define	EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN	0x9
 #define	EEPROM_CHANNEL_PLAN_WORLD_WIDE_13	0xA
-#define	EEPROM_CHANNEL_PLAN_NCC			0xB
+#define	EEPROM_CHANNEL_PLAN_NCC				0xB
 #define	EEPROM_CHANNEL_PLAN_BY_HW_MASK		0x80
 
-#define EEPROM_CID_DEFAULT			0x0
-#define EEPROM_CID_TOSHIBA			0x4
-#define	EEPROM_CID_CCX				0x10
-#define	EEPROM_CID_QMI				0x0D
-#define EEPROM_CID_WHQL				0xFE
+#define EEPROM_CID_DEFAULT					0x0
+#define EEPROM_CID_TOSHIBA					0x4
+#define	EEPROM_CID_CCX						0x10
+#define	EEPROM_CID_QMI						0x0D
+#define EEPROM_CID_WHQL						0xFE
 
-#define	RTL8188E_EEPROM_ID			0x8129
+#define	RTL8188E_EEPROM_ID					0x8129
 
-#define EEPROM_HPON				0x02
-#define EEPROM_CLK				0x06
-#define EEPROM_TESTR				0x08
+#define EEPROM_HPON							0x02
+#define EEPROM_CLK							0x06
+#define EEPROM_TESTR						0x08
 
 #define EEPROM_TXPOWERCCK			0x10
-#define	EEPROM_TXPOWERHT40_1S			0x16
-#define EEPROM_TXPOWERHT20DIFF			0x1B
-#define EEPROM_TXPOWER_OFDMDIFF			0x1B
+#define	EEPROM_TXPOWERHT40_1S		0x16
+#define EEPROM_TXPOWERHT20DIFF		0x1B
+#define EEPROM_TXPOWER_OFDMDIFF		0x1B
 
-#define	EEPROM_TX_PWR_INX			0x10
+#define	EEPROM_TX_PWR_INX				0x10
 
-#define	EEPROM_CHANNELPLAN			0xB8
-#define	EEPROM_XTAL_88E				0xB9
-#define	EEPROM_THERMAL_METER_88E		0xBA
-#define	EEPROM_IQK_LCK_88E			0xBB
+#define	EEPROM_CHANNELPLAN					0xB8
+#define	EEPROM_XTAL_88E						0xB9
+#define	EEPROM_THERMAL_METER_88E			0xBA
+#define	EEPROM_IQK_LCK_88E					0xBB
 
-#define	EEPROM_RF_BOARD_OPTION_88E		0xC1
+#define	EEPROM_RF_BOARD_OPTION_88E			0xC1
 #define	EEPROM_RF_FEATURE_OPTION_88E		0xC2
-#define	EEPROM_RF_BT_SETTING_88E		0xC3
-#define	EEPROM_VERSION				0xC4
-#define	EEPROM_CUSTOMER_ID			0xC5
-#define	EEPROM_RF_ANTENNA_OPT_88E		0xC9
+#define	EEPROM_RF_BT_SETTING_88E				0xC3
+#define	EEPROM_VERSION					0xC4
+#define	EEPROM_CUSTOMER_ID					0xC5
+#define	EEPROM_RF_ANTENNA_OPT_88E			0xC9
 
-#define	EEPROM_MAC_ADDR				0xD0
-#define EEPROM_VID				0xD6
-#define EEPROM_DID				0xD8
-#define EEPROM_SVID				0xDA
-#define EEPROM_SMID				0xDC
+#define	EEPROM_MAC_ADDR					0xD0
+#define EEPROM_VID							0xD6
+#define EEPROM_DID							0xD8
+#define EEPROM_SVID							0xDA
+#define EEPROM_SMID						0xDC
 
-#define	STOPBECON				BIT(6)
-#define	STOPHIGHT				BIT(5)
-#define	STOPMGT					BIT(4)
-#define	STOPVO					BIT(3)
-#define	STOPVI					BIT(2)
-#define	STOPBE					BIT(1)
-#define	STOPBK					BIT(0)
+#define	STOPBECON					BIT(6)
+#define	STOPHIGHT					BIT(5)
+#define	STOPMGT						BIT(4)
+#define	STOPVO						BIT(3)
+#define	STOPVI						BIT(2)
+#define	STOPBE						BIT(1)
+#define	STOPBK						BIT(0)
 
-#define	RCR_APPFCS				BIT(31)
-#define	RCR_APP_MIC				BIT(30)
-#define	RCR_APP_ICV				BIT(29)
+#define	RCR_APPFCS					BIT(31)
+#define	RCR_APP_MIC					BIT(30)
+#define	RCR_APP_ICV					BIT(29)
 #define	RCR_APP_PHYST_RXFF			BIT(28)
 #define	RCR_APP_BA_SSN				BIT(27)
-#define	RCR_ENMBID				BIT(24)
-#define	RCR_LSIGEN				BIT(23)
-#define	RCR_MFBEN				BIT(22)
+#define	RCR_ENMBID					BIT(24)
+#define	RCR_LSIGEN					BIT(23)
+#define	RCR_MFBEN					BIT(22)
 #define	RCR_HTC_LOC_CTRL			BIT(14)
-#define	RCR_AMF					BIT(13)
-#define	RCR_ACF					BIT(12)
-#define	RCR_ADF					BIT(11)
-#define	RCR_AICV				BIT(9)
-#define	RCR_ACRC32				BIT(8)
+#define	RCR_AMF						BIT(13)
+#define	RCR_ACF						BIT(12)
+#define	RCR_ADF						BIT(11)
+#define	RCR_AICV					BIT(9)
+#define	RCR_ACRC32					BIT(8)
 #define	RCR_CBSSID_BCN				BIT(7)
 #define	RCR_CBSSID_DATA				BIT(6)
-#define	RCR_CBSSID				RCR_CBSSID_DATA
-#define	RCR_APWRMGT				BIT(5)
-#define	RCR_ADD3				BIT(4)
-#define	RCR_AB					BIT(3)
-#define	RCR_AM					BIT(2)
-#define	RCR_APM					BIT(1)
-#define	RCR_AAP					BIT(0)
+#define	RCR_CBSSID					RCR_CBSSID_DATA
+#define	RCR_APWRMGT					BIT(5)
+#define	RCR_ADD3					BIT(4)
+#define	RCR_AB						BIT(3)
+#define	RCR_AM						BIT(2)
+#define	RCR_APM						BIT(1)
+#define	RCR_AAP						BIT(0)
 #define	RCR_MXDMA_OFFSET			8
 #define	RCR_FIFO_OFFSET				13
 
-#define RSV_CTRL				0x001C
-#define RD_CTRL					0x0524
+#define RSV_CTRL					0x001C
+#define RD_CTRL						0x0524
 
 #define REG_USB_INFO				0xFE17
-#define REG_USB_SPECIAL_OPTION			0xFE55
+#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_USB_VID				0xFE60
-#define REG_USB_PID				0xFE62
+#define REG_USB_VID					0xFE60
+#define REG_USB_PID					0xFE62
 #define REG_USB_OPTIONAL			0xFE64
 #define REG_USB_CHIRP_K				0xFE65
-#define REG_USB_PHY				0xFE66
+#define REG_USB_PHY					0xFE66
 #define REG_USB_MAC_ADDR			0xFE70
 #define REG_USB_HRPWM				0xFE58
 #define REG_USB_HCPWM				0xFE57
 
-#define SW18_FPWM				BIT(3)
+#define SW18_FPWM					BIT(3)
 
-#define ISO_MD2PP				BIT(0)
-#define ISO_UA2USB				BIT(1)
-#define ISO_UD2CORE				BIT(2)
-#define ISO_PA2PCIE				BIT(3)
-#define ISO_PD2CORE				BIT(4)
-#define ISO_IP2MAC				BIT(5)
-#define ISO_DIOP				BIT(6)
-#define ISO_DIOE				BIT(7)
-#define ISO_EB2CORE				BIT(8)
-#define ISO_DIOR				BIT(9)
+#define ISO_MD2PP					BIT(0)
+#define ISO_UA2USB					BIT(1)
+#define ISO_UD2CORE					BIT(2)
+#define ISO_PA2PCIE					BIT(3)
+#define ISO_PD2CORE					BIT(4)
+#define ISO_IP2MAC					BIT(5)
+#define ISO_DIOP					BIT(6)
+#define ISO_DIOE					BIT(7)
+#define ISO_EB2CORE					BIT(8)
+#define ISO_DIOR					BIT(9)
 
-#define PWC_EV25V				BIT(14)
-#define PWC_EV12V				BIT(15)
+#define PWC_EV25V					BIT(14)
+#define PWC_EV12V					BIT(15)
 
-#define FEN_BBRSTB				BIT(0)
+#define FEN_BBRSTB					BIT(0)
 #define FEN_BB_GLB_RSTN				BIT(1)
-#define FEN_USBA				BIT(2)
-#define FEN_UPLL				BIT(3)
-#define FEN_USBD				BIT(4)
+#define FEN_USBA					BIT(2)
+#define FEN_UPLL					BIT(3)
+#define FEN_USBD					BIT(4)
 #define FEN_DIO_PCIE				BIT(5)
-#define FEN_PCIEA				BIT(6)
-#define FEN_PPLL				BIT(7)
-#define FEN_PCIED				BIT(8)
-#define FEN_DIOE				BIT(9)
-#define FEN_CPUEN				BIT(10)
-#define FEN_DCORE				BIT(11)
-#define FEN_ELDR				BIT(12)
-#define FEN_DIO_RF				BIT(13)
-#define FEN_HWPDN				BIT(14)
-#define FEN_MREGEN				BIT(15)
+#define FEN_PCIEA					BIT(6)
+#define FEN_PPLL					BIT(7)
+#define FEN_PCIED					BIT(8)
+#define FEN_DIOE					BIT(9)
+#define FEN_CPUEN					BIT(10)
+#define FEN_DCORE					BIT(11)
+#define FEN_ELDR					BIT(12)
+#define FEN_DIO_RF					BIT(13)
+#define FEN_HWPDN					BIT(14)
+#define FEN_MREGEN					BIT(15)
 
-#define PFM_LDALL				BIT(0)
-#define PFM_ALDN				BIT(1)
-#define PFM_LDKP				BIT(2)
-#define PFM_WOWL				BIT(3)
-#define ENPDN					BIT(4)
-#define PDN_PL					BIT(5)
-#define APFM_ONMAC				BIT(8)
-#define APFM_OFF				BIT(9)
-#define APFM_RSM				BIT(10)
-#define AFSM_HSUS				BIT(11)
-#define AFSM_PCIE				BIT(12)
-#define APDM_MAC				BIT(13)
-#define APDM_HOST				BIT(14)
-#define APDM_HPDN				BIT(15)
-#define RDY_MACON				BIT(16)
-#define SUS_HOST				BIT(17)
-#define ROP_ALD					BIT(20)
-#define ROP_PWR					BIT(21)
-#define ROP_SPS					BIT(22)
-#define SOP_MRST				BIT(25)
-#define SOP_FUSE				BIT(26)
-#define SOP_ABG					BIT(27)
-#define SOP_AMB					BIT(28)
-#define SOP_RCK					BIT(29)
-#define SOP_A8M					BIT(30)
-#define XOP_BTCK				BIT(31)
+#define PFM_LDALL					BIT(0)
+#define PFM_ALDN					BIT(1)
+#define PFM_LDKP					BIT(2)
+#define PFM_WOWL					BIT(3)
+#define ENPDN						BIT(4)
+#define PDN_PL						BIT(5)
+#define APFM_ONMAC					BIT(8)
+#define APFM_OFF					BIT(9)
+#define APFM_RSM					BIT(10)
+#define AFSM_HSUS					BIT(11)
+#define AFSM_PCIE					BIT(12)
+#define APDM_MAC					BIT(13)
+#define APDM_HOST					BIT(14)
+#define APDM_HPDN					BIT(15)
+#define RDY_MACON					BIT(16)
+#define SUS_HOST					BIT(17)
+#define ROP_ALD						BIT(20)
+#define ROP_PWR						BIT(21)
+#define ROP_SPS						BIT(22)
+#define SOP_MRST					BIT(25)
+#define SOP_FUSE					BIT(26)
+#define SOP_ABG						BIT(27)
+#define SOP_AMB						BIT(28)
+#define SOP_RCK						BIT(29)
+#define SOP_A8M						BIT(30)
+#define XOP_BTCK					BIT(31)
 
-#define ANAD16V_EN				BIT(0)
-#define ANA8M					BIT(1)
-#define MACSLP					BIT(4)
+#define ANAD16V_EN					BIT(0)
+#define ANA8M						BIT(1)
+#define MACSLP						BIT(4)
 #define LOADER_CLK_EN				BIT(5)
 #define _80M_SSC_DIS				BIT(7)
 #define _80M_SSC_EN_HO				BIT(8)
 #define PHY_SSC_RSTB				BIT(9)
-#define SEC_CLK_EN				BIT(10)
-#define MAC_CLK_EN				BIT(11)
-#define SYS_CLK_EN				BIT(12)
-#define RING_CLK_EN				BIT(13)
+#define SEC_CLK_EN					BIT(10)
+#define MAC_CLK_EN					BIT(11)
+#define SYS_CLK_EN					BIT(12)
+#define RING_CLK_EN					BIT(13)
 
 #define	BOOT_FROM_EEPROM			BIT(4)
-#define	EEPROM_EN				BIT(5)
+#define	EEPROM_EN					BIT(5)
 
-#define AFE_BGEN				BIT(0)
-#define AFE_MBEN				BIT(1)
-#define MAC_ID_EN				BIT(7)
+#define AFE_BGEN					BIT(0)
+#define AFE_MBEN					BIT(1)
+#define MAC_ID_EN					BIT(7)
 
-#define WLOCK_ALL				BIT(0)
-#define WLOCK_00				BIT(1)
-#define WLOCK_04				BIT(2)
-#define WLOCK_08				BIT(3)
-#define WLOCK_40				BIT(4)
+#define WLOCK_ALL					BIT(0)
+#define WLOCK_00					BIT(1)
+#define WLOCK_04					BIT(2)
+#define WLOCK_08					BIT(3)
+#define WLOCK_40					BIT(4)
 #define R_DIS_PRST_0				BIT(5)
 #define R_DIS_PRST_1				BIT(6)
-#define LOCK_ALL_EN				BIT(7)
+#define LOCK_ALL_EN					BIT(7)
 
-#define RF_EN					BIT(0)
-#define RF_RSTB					BIT(1)
-#define RF_SDMRSTB				BIT(2)
+#define RF_EN						BIT(0)
+#define RF_RSTB						BIT(1)
+#define RF_SDMRSTB					BIT(2)
 
-#define LDA15_EN				BIT(0)
-#define LDA15_STBY				BIT(1)
-#define LDA15_OBUF				BIT(2)
+#define LDA15_EN					BIT(0)
+#define LDA15_STBY					BIT(1)
+#define LDA15_OBUF					BIT(2)
 #define LDA15_REG_VOS				BIT(3)
 #define _LDA15_VOADJ(x)				(((x) & 0x7) << 4)
 
-#define LDV12_EN				BIT(0)
-#define LDV12_SDBY				BIT(1)
-#define LPLDO_HSM				BIT(2)
+#define LDV12_EN					BIT(0)
+#define LDV12_SDBY					BIT(1)
+#define LPLDO_HSM					BIT(2)
 #define LPLDO_LSM_DIS				BIT(3)
 #define _LDV12_VADJ(x)				(((x) & 0xF) << 4)
 
-#define XTAL_EN					BIT(0)
-#define XTAL_BSEL				BIT(1)
+#define XTAL_EN						BIT(0)
+#define XTAL_BSEL					BIT(1)
 #define _XTAL_BOSC(x)				(((x) & 0x3) << 2)
 #define _XTAL_CADJ(x)				(((x) & 0xF) << 4)
 #define XTAL_GATE_USB				BIT(8)
@@ -871,145 +886,145 @@
 #define _XTAL_BT_DRV(x)				(((x) & 0x3) << 21)
 #define _XTAL_GPIO(x)				(((x) & 0x7) << 23)
 
-#define CKDLY_AFE				BIT(26)
-#define CKDLY_USB				BIT(27)
-#define CKDLY_DIG				BIT(28)
-#define CKDLY_BT				BIT(29)
+#define CKDLY_AFE					BIT(26)
+#define CKDLY_USB					BIT(27)
+#define CKDLY_DIG					BIT(28)
+#define CKDLY_BT					BIT(29)
 
-#define APLL_EN					BIT(0)
-#define APLL_320_EN				BIT(1)
+#define APLL_EN						BIT(0)
+#define APLL_320_EN					BIT(1)
 #define APLL_FREF_SEL				BIT(2)
 #define APLL_EDGE_SEL				BIT(3)
-#define APLL_WDOGB				BIT(4)
-#define APLL_LPFEN				BIT(5)
+#define APLL_WDOGB					BIT(4)
+#define APLL_LPFEN					BIT(5)
 
 #define APLL_REF_CLK_13MHZ			0x1
-#define APLL_REF_CLK_19_2MHZ			0x2
+#define APLL_REF_CLK_19_2MHZ		0x2
 #define APLL_REF_CLK_20MHZ			0x3
 #define APLL_REF_CLK_25MHZ			0x4
 #define APLL_REF_CLK_26MHZ			0x5
-#define APLL_REF_CLK_38_4MHZ			0x6
+#define APLL_REF_CLK_38_4MHZ		0x6
 #define APLL_REF_CLK_40MHZ			0x7
 
-#define APLL_320EN				BIT(14)
-#define APLL_80EN				BIT(15)
-#define APLL_1MEN				BIT(24)
+#define APLL_320EN					BIT(14)
+#define APLL_80EN					BIT(15)
+#define APLL_1MEN					BIT(24)
 
-#define ALD_EN					BIT(18)
-#define EF_PD					BIT(19)
-#define EF_FLAG					BIT(31)
+#define ALD_EN						BIT(18)
+#define EF_PD						BIT(19)
+#define EF_FLAG						BIT(31)
 
-#define EF_TRPT					BIT(7)
-#define LDOE25_EN				BIT(31)
+#define EF_TRPT						BIT(7)
+#define LDOE25_EN					BIT(31)
 
-#define RSM_EN					BIT(0)
-#define TIMER_EN				BIT(4)
+#define RSM_EN						BIT(0)
+#define TIMER_EN					BIT(4)
 
-#define TRSW0EN					BIT(2)
-#define TRSW1EN					BIT(3)
-#define EROM_EN					BIT(4)
-#define ENBT					BIT(5)
-#define ENUART					BIT(8)
-#define UART_910				BIT(9)
-#define ENPMAC					BIT(10)
-#define SIC_SWRST				BIT(11)
-#define ENSIC					BIT(12)
-#define SIC_23					BIT(13)
-#define ENHDP					BIT(14)
-#define SIC_LBK					BIT(15)
+#define TRSW0EN						BIT(2)
+#define TRSW1EN						BIT(3)
+#define EROM_EN						BIT(4)
+#define ENBT						BIT(5)
+#define ENUART						BIT(8)
+#define UART_910					BIT(9)
+#define ENPMAC						BIT(10)
+#define SIC_SWRST					BIT(11)
+#define ENSIC						BIT(12)
+#define SIC_23						BIT(13)
+#define ENHDP						BIT(14)
+#define SIC_LBK						BIT(15)
 
-#define LED0PL					BIT(4)
-#define LED1PL					BIT(12)
-#define LED0DIS					BIT(7)
+#define LED0PL						BIT(4)
+#define LED1PL						BIT(12)
+#define LED0DIS						BIT(7)
 
-#define MCUFWDL_EN				BIT(0)
-#define MCUFWDL_RDY				BIT(1)
+#define MCUFWDL_EN					BIT(0)
+#define MCUFWDL_RDY					BIT(1)
 #define FWDL_CHKSUM_RPT				BIT(2)
-#define MACINI_RDY				BIT(3)
-#define BBINI_RDY				BIT(4)
-#define RFINI_RDY				BIT(5)
-#define WINTINI_RDY				BIT(6)
-#define CPRST					BIT(23)
+#define MACINI_RDY					BIT(3)
+#define BBINI_RDY					BIT(4)
+#define RFINI_RDY					BIT(5)
+#define WINTINI_RDY					BIT(6)
+#define CPRST						BIT(23)
 
-#define XCLK_VLD				BIT(0)
-#define ACLK_VLD				BIT(1)
-#define UCLK_VLD				BIT(2)
-#define PCLK_VLD				BIT(3)
-#define PCIRSTB					BIT(4)
-#define V15_VLD					BIT(5)
-#define TRP_B15V_EN				BIT(7)
-#define SIC_IDLE				BIT(8)
-#define BD_MAC2					BIT(9)
-#define BD_MAC1					BIT(10)
+#define XCLK_VLD					BIT(0)
+#define ACLK_VLD					BIT(1)
+#define UCLK_VLD					BIT(2)
+#define PCLK_VLD					BIT(3)
+#define PCIRSTB						BIT(4)
+#define V15_VLD						BIT(5)
+#define TRP_B15V_EN					BIT(7)
+#define SIC_IDLE					BIT(8)
+#define BD_MAC2						BIT(9)
+#define BD_MAC1						BIT(10)
 #define IC_MACPHY_MODE				BIT(11)
-#define VENDOR_ID				BIT(19)
+#define VENDOR_ID					BIT(19)
 #define PAD_HWPD_IDN				BIT(22)
-#define TRP_VAUX_EN				BIT(23)
-#define TRP_BT_EN				BIT(24)
-#define BD_PKG_SEL				BIT(25)
-#define BD_HCI_SEL				BIT(26)
-#define TYPE_ID					BIT(27)
+#define TRP_VAUX_EN					BIT(23)
+#define TRP_BT_EN					BIT(24)
+#define BD_PKG_SEL					BIT(25)
+#define BD_HCI_SEL					BIT(26)
+#define TYPE_ID						BIT(27)
 
 #define CHIP_VER_RTL_MASK			0xF000
 #define CHIP_VER_RTL_SHIFT			12
 
-#define REG_LBMODE				(REG_CR + 3)
+#define REG_LBMODE					(REG_CR + 3)
 
 #define HCI_TXDMA_EN				BIT(0)
 #define HCI_RXDMA_EN				BIT(1)
-#define TXDMA_EN				BIT(2)
-#define RXDMA_EN				BIT(3)
-#define PROTOCOL_EN				BIT(4)
-#define SCHEDULE_EN				BIT(5)
-#define MACTXEN					BIT(6)
-#define MACRXEN					BIT(7)
-#define ENSWBCN					BIT(8)
-#define ENSEC					BIT(9)
+#define TXDMA_EN					BIT(2)
+#define RXDMA_EN					BIT(3)
+#define PROTOCOL_EN					BIT(4)
+#define SCHEDULE_EN					BIT(5)
+#define MACTXEN						BIT(6)
+#define MACRXEN						BIT(7)
+#define ENSWBCN						BIT(8)
+#define ENSEC						BIT(9)
 
-#define _NETTYPE(x)				(((x) & 0x3) << 16)
+#define _NETTYPE(x)					(((x) & 0x3) << 16)
 #define MASK_NETTYPE				0x30000
-#define NT_NO_LINK				0x0
+#define NT_NO_LINK					0x0
 #define NT_LINK_AD_HOC				0x1
-#define NT_LINK_AP				0x2
-#define NT_AS_AP				0x3
+#define NT_LINK_AP					0x2
+#define NT_AS_AP					0x3
 
-#define _LBMODE(x)				(((x) & 0xF) << 24)
-#define MASK_LBMODE				0xF000000
+#define _LBMODE(x)					(((x) & 0xF) << 24)
+#define MASK_LBMODE					0xF000000
 #define LOOPBACK_NORMAL				0x0
-#define LOOPBACK_IMMEDIATELY			0xB
+#define LOOPBACK_IMMEDIATELY		0xB
 #define LOOPBACK_MAC_DELAY			0x3
 #define LOOPBACK_PHY				0x1
 #define LOOPBACK_DMA				0x7
 
 #define GET_RX_PAGE_SIZE(value)		((value) & 0xF)
 #define GET_TX_PAGE_SIZE(value)		(((value) & 0xF0) >> 4)
-#define _PSRX_MASK				0xF
-#define _PSTX_MASK				0xF0
-#define _PSRX(x)				(x)
-#define _PSTX(x)				((x) << 4)
+#define _PSRX_MASK					0xF
+#define _PSTX_MASK					0xF0
+#define _PSRX(x)					(x)
+#define _PSTX(x)					((x) << 4)
 
-#define PBP_64					0x0
-#define PBP_128					0x1
-#define PBP_256					0x2
-#define PBP_512					0x3
-#define PBP_1024				0x4
+#define PBP_64						0x0
+#define PBP_128						0x1
+#define PBP_256						0x2
+#define PBP_512						0x3
+#define PBP_1024					0x4
 
 #define RXDMA_ARBBW_EN				BIT(0)
-#define RXSHFT_EN				BIT(1)
+#define RXSHFT_EN					BIT(1)
 #define RXDMA_AGG_EN				BIT(2)
-#define QS_VO_QUEUE				BIT(8)
-#define QS_VI_QUEUE				BIT(9)
-#define QS_BE_QUEUE				BIT(10)
-#define QS_BK_QUEUE				BIT(11)
+#define QS_VO_QUEUE					BIT(8)
+#define QS_VI_QUEUE					BIT(9)
+#define QS_BE_QUEUE					BIT(10)
+#define QS_BK_QUEUE					BIT(11)
 #define QS_MANAGER_QUEUE			BIT(12)
 #define QS_HIGH_QUEUE				BIT(13)
 
-#define HQSEL_VOQ				BIT(0)
-#define HQSEL_VIQ				BIT(1)
-#define HQSEL_BEQ				BIT(2)
-#define HQSEL_BKQ				BIT(3)
-#define HQSEL_MGTQ				BIT(4)
-#define HQSEL_HIQ				BIT(5)
+#define HQSEL_VOQ					BIT(0)
+#define HQSEL_VIQ					BIT(1)
+#define HQSEL_BEQ					BIT(2)
+#define HQSEL_BKQ					BIT(3)
+#define HQSEL_MGTQ					BIT(4)
+#define HQSEL_HIQ					BIT(5)
 
 #define _TXDMA_HIQ_MAP(x)			(((x)&0x3) << 14)
 #define _TXDMA_MGQ_MAP(x)			(((x)&0x3) << 12)
@@ -1018,9 +1033,9 @@
 #define _TXDMA_VIQ_MAP(x)			(((x)&0x3) << 6)
 #define _TXDMA_VOQ_MAP(x)			(((x)&0x3) << 4)
 
-#define QUEUE_LOW				1
+#define QUEUE_LOW					1
 #define QUEUE_NORMAL				2
-#define QUEUE_HIGH				3
+#define QUEUE_HIGH					3
 
 #define _LLT_NO_ACTIVE				0x0
 #define _LLT_WRITE_ACCESS			0x1
@@ -1028,25 +1043,25 @@
 
 #define _LLT_INIT_DATA(x)			((x) & 0xFF)
 #define _LLT_INIT_ADDR(x)			(((x) & 0xFF) << 8)
-#define _LLT_OP(x)				(((x) & 0x3) << 30)
+#define _LLT_OP(x)					(((x) & 0x3) << 30)
 #define _LLT_OP_VALUE(x)			(((x) >> 30) & 0x3)
 
 #define BB_WRITE_READ_MASK			(BIT(31) | BIT(30))
-#define BB_WRITE_EN				BIT(30)
-#define BB_READ_EN				BIT(31)
+#define BB_WRITE_EN					BIT(30)
+#define BB_READ_EN					BIT(31)
 
-#define _HPQ(x)					((x) & 0xFF)
-#define _LPQ(x)					(((x) & 0xFF) << 8)
-#define _PUBQ(x)				(((x) & 0xFF) << 16)
-#define _NPQ(x)					((x) & 0xFF)
+#define _HPQ(x)			((x) & 0xFF)
+#define _LPQ(x)			(((x) & 0xFF) << 8)
+#define _PUBQ(x)		(((x) & 0xFF) << 16)
+#define _NPQ(x)			((x) & 0xFF)
 
-#define HPQ_PUBLIC_DIS				BIT(24)
-#define LPQ_PUBLIC_DIS				BIT(25)
-#define LD_RQPN					BIT(31)
+#define HPQ_PUBLIC_DIS		BIT(24)
+#define LPQ_PUBLIC_DIS		BIT(25)
+#define LD_RQPN			BIT(31)
 
-#define BCN_VALID				BIT(16)
-#define BCN_HEAD(x)				(((x) & 0xFF) << 8)
-#define	BCN_HEAD_MASK				0xFF00
+#define BCN_VALID		BIT(16)
+#define BCN_HEAD(x)		(((x) & 0xFF) << 8)
+#define	BCN_HEAD_MASK		0xFF00
 
 #define BLK_DESC_NUM_SHIFT			4
 #define BLK_DESC_NUM_MASK			0xF
@@ -1066,9 +1081,9 @@
 
 #define _RRSR_RSC(x)				(((x) & 0x3) << 21)
 #define RRSR_RSC_RESERVED			0x0
-#define RRSR_RSC_UPPER_SUBCHANNEL		0x1
-#define RRSR_RSC_LOWER_SUBCHANNEL		0x2
-#define RRSR_RSC_DUPLICATE_MODE			0x3
+#define RRSR_RSC_UPPER_SUBCHANNEL	0x1
+#define RRSR_RSC_LOWER_SUBCHANNEL	0x2
+#define RRSR_RSC_DUPLICATE_MODE		0x3
 
 #define USE_SHORT_G1				BIT(20)
 
@@ -1081,8 +1096,8 @@
 #define _AGGLMT_MCS6(x)				(((x) & 0xF) << 24)
 #define _AGGLMT_MCS7(x)				(((x) & 0xF) << 28)
 
-#define	RETRY_LIMIT_SHORT_SHIFT			8
-#define	RETRY_LIMIT_LONG_SHIFT			0
+#define	RETRY_LIMIT_SHORT_SHIFT		8
+#define	RETRY_LIMIT_LONG_SHIFT		0
 
 #define _DARF_RC1(x)				((x) & 0x1F)
 #define _DARF_RC2(x)				(((x) & 0x1F) << 8)
@@ -1102,20 +1117,20 @@
 #define _RARF_RC7(x)				(((x) & 0x1F) << 16)
 #define _RARF_RC8(x)				(((x) & 0x1F) << 24)
 
-#define AC_PARAM_TXOP_LIMIT_OFFSET		16
-#define AC_PARAM_ECW_MAX_OFFSET			12
-#define AC_PARAM_ECW_MIN_OFFSET			8
-#define AC_PARAM_AIFS_OFFSET			0
+#define AC_PARAM_TXOP_LIMIT_OFFSET	16
+#define AC_PARAM_ECW_MAX_OFFSET		12
+#define AC_PARAM_ECW_MIN_OFFSET		8
+#define AC_PARAM_AIFS_OFFSET		0
 
-#define _AIFS(x)				(x)
+#define _AIFS(x)					(x)
 #define _ECW_MAX_MIN(x)				((x) << 8)
 #define _TXOP_LIMIT(x)				((x) << 16)
 
-#define _BCNIFS(x)				((x) & 0xFF)
-#define _BCNECW(x)				((((x) & 0xF)) << 8)
+#define _BCNIFS(x)					((x) & 0xFF)
+#define _BCNECW(x)					((((x) & 0xF)) << 8)
 
-#define _LRL(x)					((x) & 0x3F)
-#define _SRL(x)					(((x) & 0x3F) << 8)
+#define _LRL(x)						((x) & 0x3F)
+#define _SRL(x)						(((x) & 0x3F) << 8)
 
 #define _SIFS_CCK_CTX(x)			((x) & 0xFF)
 #define _SIFS_CCK_TRX(x)			(((x) & 0xFF) << 8);
@@ -1123,102 +1138,102 @@
 #define _SIFS_OFDM_CTX(x)			((x) & 0xFF)
 #define _SIFS_OFDM_TRX(x)			(((x) & 0xFF) << 8);
 
-#define _TBTT_PROHIBIT_HOLD(x)			(((x) & 0xFF) << 8)
+#define _TBTT_PROHIBIT_HOLD(x)		(((x) & 0xFF) << 8)
 
 #define DIS_EDCA_CNT_DWN			BIT(11)
 
-#define EN_MBSSID				BIT(1)
+#define EN_MBSSID					BIT(1)
 #define EN_TXBCN_RPT				BIT(2)
 #define	EN_BCN_FUNCTION				BIT(3)
 
-#define TSFTR_RST				BIT(0)
-#define TSFTR1_RST				BIT(1)
+#define TSFTR_RST					BIT(0)
+#define TSFTR1_RST					BIT(1)
 
-#define STOP_BCNQ				BIT(6)
+#define STOP_BCNQ					BIT(6)
 
-#define	DIS_TSF_UDT0_NORMAL_CHIP		BIT(4)
-#define	DIS_TSF_UDT0_TEST_CHIP			BIT(5)
+#define	DIS_TSF_UDT0_NORMAL_CHIP	BIT(4)
+#define	DIS_TSF_UDT0_TEST_CHIP		BIT(5)
 
-#define	ACMHW_HWEN				BIT(0)
-#define	ACMHW_BEQEN				BIT(1)
-#define	ACMHW_VIQEN				BIT(2)
-#define	ACMHW_VOQEN				BIT(3)
+#define	ACMHW_HWEN					BIT(0)
+#define	ACMHW_BEQEN					BIT(1)
+#define	ACMHW_VIQEN					BIT(2)
+#define	ACMHW_VOQEN					BIT(3)
 #define	ACMHW_BEQSTATUS				BIT(4)
 #define	ACMHW_VIQSTATUS				BIT(5)
 #define	ACMHW_VOQSTATUS				BIT(6)
 
-#define APSDOFF					BIT(6)
+#define APSDOFF						BIT(6)
 #define APSDOFF_STATUS				BIT(7)
 
-#define BW_20MHZ				BIT(2)
+#define BW_20MHZ					BIT(2)
 
 #define RATE_BITMAP_ALL				0xFFFFF
 
-#define RATE_RRSR_CCK_ONLY_1M			0xFFFF1
+#define RATE_RRSR_CCK_ONLY_1M		0xFFFF1
 
-#define TSFRST					BIT(0)
-#define DIS_GCLK				BIT(1)
-#define PAD_SEL					BIT(2)
-#define PWR_ST					BIT(6)
+#define TSFRST						BIT(0)
+#define DIS_GCLK					BIT(1)
+#define PAD_SEL						BIT(2)
+#define PWR_ST						BIT(6)
 #define PWRBIT_OW_EN				BIT(7)
-#define ACRC					BIT(8)
-#define CFENDFORM				BIT(9)
-#define ICV					BIT(10)
+#define ACRC						BIT(8)
+#define CFENDFORM					BIT(9)
+#define ICV							BIT(10)
 
-#define AAP					BIT(0)
-#define APM					BIT(1)
-#define AM					BIT(2)
-#define AB					BIT(3)
-#define ADD3					BIT(4)
-#define APWRMGT					BIT(5)
-#define CBSSID					BIT(6)
-#define CBSSID_DATA				BIT(6)
-#define CBSSID_BCN				BIT(7)
-#define ACRC32					BIT(8)
-#define AICV					BIT(9)
-#define ADF					BIT(11)
-#define ACF					BIT(12)
-#define AMF					BIT(13)
+#define AAP							BIT(0)
+#define APM							BIT(1)
+#define AM							BIT(2)
+#define AB							BIT(3)
+#define ADD3						BIT(4)
+#define APWRMGT						BIT(5)
+#define CBSSID						BIT(6)
+#define CBSSID_DATA					BIT(6)
+#define CBSSID_BCN					BIT(7)
+#define ACRC32						BIT(8)
+#define AICV						BIT(9)
+#define ADF							BIT(11)
+#define ACF							BIT(12)
+#define AMF							BIT(13)
 #define HTC_LOC_CTRL				BIT(14)
-#define UC_DATA_EN				BIT(16)
-#define BM_DATA_EN				BIT(17)
-#define MFBEN					BIT(22)
-#define LSIGEN					BIT(23)
-#define ENMBID					BIT(24)
-#define APP_BASSN				BIT(27)
-#define APP_PHYSTS				BIT(28)
-#define APP_ICV					BIT(29)
-#define APP_MIC					BIT(30)
-#define APP_FCS					BIT(31)
+#define UC_DATA_EN					BIT(16)
+#define BM_DATA_EN					BIT(17)
+#define MFBEN						BIT(22)
+#define LSIGEN						BIT(23)
+#define ENMBID						BIT(24)
+#define APP_BASSN					BIT(27)
+#define APP_PHYSTS					BIT(28)
+#define APP_ICV						BIT(29)
+#define APP_MIC						BIT(30)
+#define APP_FCS						BIT(31)
 
 #define _MIN_SPACE(x)				((x) & 0x7)
-#define _SHORT_GI_PADDING(x)			(((x) & 0x1F) << 3)
+#define _SHORT_GI_PADDING(x)		(((x) & 0x1F) << 3)
 
-#define RXERR_TYPE_OFDM_PPDU			0
-#define RXERR_TYPE_OFDM_FALSE_ALARM		1
-#define	RXERR_TYPE_OFDM_MPDU_OK			2
-#define RXERR_TYPE_OFDM_MPDU_FAIL		3
+#define RXERR_TYPE_OFDM_PPDU		0
+#define RXERR_TYPE_OFDM_FALSE_ALARM	1
+#define	RXERR_TYPE_OFDM_MPDU_OK		2
+#define RXERR_TYPE_OFDM_MPDU_FAIL	3
 #define RXERR_TYPE_CCK_PPDU			4
-#define RXERR_TYPE_CCK_FALSE_ALARM		5
-#define RXERR_TYPE_CCK_MPDU_OK			6
-#define RXERR_TYPE_CCK_MPDU_FAIL		7
+#define RXERR_TYPE_CCK_FALSE_ALARM	5
+#define RXERR_TYPE_CCK_MPDU_OK		6
+#define RXERR_TYPE_CCK_MPDU_FAIL	7
 #define RXERR_TYPE_HT_PPDU			8
-#define RXERR_TYPE_HT_FALSE_ALARM		9
-#define RXERR_TYPE_HT_MPDU_TOTAL		10
-#define RXERR_TYPE_HT_MPDU_OK			11
-#define RXERR_TYPE_HT_MPDU_FAIL			12
-#define RXERR_TYPE_RX_FULL_DROP			15
+#define RXERR_TYPE_HT_FALSE_ALARM	9
+#define RXERR_TYPE_HT_MPDU_TOTAL	10
+#define RXERR_TYPE_HT_MPDU_OK		11
+#define RXERR_TYPE_HT_MPDU_FAIL		12
+#define RXERR_TYPE_RX_FULL_DROP		15
 
 #define RXERR_COUNTER_MASK			0xFFFFF
 #define RXERR_RPT_RST				BIT(27)
-#define _RXERR_RPT_SEL(type)			((type) << 28)
+#define _RXERR_RPT_SEL(type)		((type) << 28)
 
-#define	SCR_TXUSEDK				BIT(0)
-#define	SCR_RXUSEDK				BIT(1)
+#define	SCR_TXUSEDK					BIT(0)
+#define	SCR_RXUSEDK					BIT(1)
 #define	SCR_TXENCENABLE				BIT(2)
 #define	SCR_RXDECENABLE				BIT(3)
-#define	SCR_SKBYA2				BIT(4)
-#define	SCR_NOSKMC				BIT(5)
+#define	SCR_SKBYA2					BIT(4)
+#define	SCR_NOSKMC					BIT(5)
 #define SCR_TXBCUSEDK				BIT(6)
 #define SCR_RXBCUSEDK				BIT(7)
 
@@ -1226,32 +1241,32 @@
 #define USB_IS_FULL_SPEED			1
 #define USB_SPEED_MASK				BIT(5)
 
-#define USB_NORMAL_SIE_EP_MASK			0xF
-#define USB_NORMAL_SIE_EP_SHIFT			4
+#define USB_NORMAL_SIE_EP_MASK		0xF
+#define USB_NORMAL_SIE_EP_SHIFT		4
 
 #define USB_TEST_EP_MASK			0x30
 #define USB_TEST_EP_SHIFT			4
 
-#define USB_AGG_EN				BIT(3)
+#define USB_AGG_EN					BIT(3)
 
 #define MAC_ADDR_LEN				6
-#define LAST_ENTRY_OF_TX_PKT_BUFFER		175/*255    88e*/
+#define LAST_ENTRY_OF_TX_PKT_BUFFER	175/*255    88e*/
 
-#define POLLING_LLT_THRESHOLD			20
+#define POLLING_LLT_THRESHOLD		20
 #define POLLING_READY_TIMEOUT_COUNT		3000
 
 #define	MAX_MSS_DENSITY_2T			0x13
 #define	MAX_MSS_DENSITY_1T			0x0A
 
-#define EPROM_CMD_OPERATING_MODE_MASK		((1<<7)|(1<<6))
+#define EPROM_CMD_OPERATING_MODE_MASK	((1<<7)|(1<<6))
 #define EPROM_CMD_CONFIG			0x3
 #define EPROM_CMD_LOAD				1
 
 #define	HWSET_MAX_SIZE_92S			HWSET_MAX_SIZE
 
-#define	HAL_8192C_HW_GPIO_WPS_BIT		BIT(2)
+#define	HAL_8192C_HW_GPIO_WPS_BIT	BIT(2)
 
-#define	RPMAC_RESET				0x100
+#define	RPMAC_RESET					0x100
 #define	RPMAC_TXSTART				0x104
 #define	RPMAC_TXLEGACYSIG			0x108
 #define	RPMAC_TXHTSIG1				0x10c
@@ -1267,12 +1282,12 @@
 #define	RPMAC_TXMACHEADER5			0x134
 #define	RPMAC_TXDADATYPE			0x138
 #define	RPMAC_TXRANDOMSEED			0x13c
-#define	RPMAC_CCKPLCPPREAMBLE			0x140
+#define	RPMAC_CCKPLCPPREAMBLE		0x140
 #define	RPMAC_CCKPLCPHEADER			0x144
 #define	RPMAC_CCKCRC16				0x148
 #define	RPMAC_OFDMRXCRC32OK			0x170
-#define	RPMAC_OFDMRXCRC32Er			0x174
-#define	RPMAC_OFDMRXPARITYER			0x178
+#define	RPMAC_OFDMRXCRC32ER			0x174
+#define	RPMAC_OFDMRXPARITYER		0x178
 #define	RPMAC_OFDMRXCRC8ER			0x17c
 #define	RPMAC_CCKCRXRC16ER			0x180
 #define	RPMAC_CCKCRXRC32ER			0x184
@@ -1289,45 +1304,45 @@
 #define	RFPGA0_RFTIMING1			0x810
 #define	RFPGA0_RFTIMING2			0x814
 
-#define	RFPGA0_XA_HSSIPARAMETER1		0x820
-#define	RFPGA0_XA_HSSIPARAMETER2		0x824
-#define	RFPGA0_XB_HSSIPARAMETER1		0x828
-#define	RFPGA0_XB_HSSIPARAMETER2		0x82c
+#define	RFPGA0_XA_HSSIPARAMETER1	0x820
+#define	RFPGA0_XA_HSSIPARAMETER2	0x824
+#define	RFPGA0_XB_HSSIPARAMETER1	0x828
+#define	RFPGA0_XB_HSSIPARAMETER2	0x82c
 
-#define	RFPGA0_XA_LSSIPARAMETER			0x840
-#define	RFPGA0_XB_LSSIPARAMETER			0x844
+#define	RFPGA0_XA_LSSIPARAMETER		0x840
+#define	RFPGA0_XB_LSSIPARAMETER		0x844
 
-#define	RFPGA0_RFWAKEUPPARAMETER		0x850
-#define	RFPGA0_RFSLEEPUPPARAMETER		0x854
+#define	RFPGA0_RFWAKEUPPARAMETER	0x850
+#define	RFPGA0_RFSLEEPUPPARAMETER	0x854
 
-#define	RFPGA0_XAB_SWITCHCONTROL		0x858
-#define	RFPGA0_XCD_SWITCHCONTROL		0x85c
+#define	RFPGA0_XAB_SWITCHCONTROL	0x858
+#define	RFPGA0_XCD_SWITCHCONTROL	0x85c
 
-#define	RFPGA0_XA_RFINTERFACEOE			0x860
-#define	RFPGA0_XB_RFINTERFACEOE			0x864
+#define	RFPGA0_XA_RFINTERFACEOE		0x860
+#define	RFPGA0_XB_RFINTERFACEOE		0x864
 
-#define	RFPGA0_XAB_RFINTERFACESW		0x870
-#define	RFPGA0_XCD_RFINTERFACESW		0x874
+#define	RFPGA0_XAB_RFINTERFACESW	0x870
+#define	RFPGA0_XCD_RFINTERFACESW	0x874
 
-#define	rFPGA0_XAB_RFPARAMETER			0x878
-#define	rFPGA0_XCD_RFPARAMETER			0x87c
+#define	RFPGA0_XAB_RFPARAMETER		0x878
+#define	RFPGA0_XCD_RFPARAMETER		0x87c
 
-#define	RFPGA0_ANALOGPARAMETER1			0x880
-#define	RFPGA0_ANALOGPARAMETER2			0x884
-#define	RFPGA0_ANALOGPARAMETER3			0x888
-#define	RFPGA0_ANALOGPARAMETER4			0x88c
+#define	RFPGA0_ANALOGPARAMETER1		0x880
+#define	RFPGA0_ANALOGPARAMETER2		0x884
+#define	RFPGA0_ANALOGPARAMETER3		0x888
+#define	RFPGA0_ANALOGPARAMETER4		0x88c
 
-#define	RFPGA0_XA_LSSIREADBACK			0x8a0
-#define	RFPGA0_XB_LSSIREADBACK			0x8a4
-#define	RFPGA0_XC_LSSIREADBACK			0x8a8
-#define	RFPGA0_XD_LSSIREADBACK			0x8ac
+#define	RFPGA0_XA_LSSIREADBACK		0x8a0
+#define	RFPGA0_XB_LSSIREADBACK		0x8a4
+#define	RFPGA0_XC_LSSIREADBACK		0x8a8
+#define	RFPGA0_XD_LSSIREADBACK		0x8ac
 
 #define	RFPGA0_PSDREPORT			0x8b4
-#define	TRANSCEIVEA_HSPI_READBACK		0x8b8
-#define	TRANSCEIVEB_HSPI_READBACK		0x8bc
-#define	REG_SC_CNT				0x8c4
-#define	RFPGA0_XAB_RFINTERFACERB		0x8e0
-#define	RFPGA0_XCD_RFINTERFACERB		0x8e4
+#define	TRANSCEIVEA_HSPI_READBACK	0x8b8
+#define	TRANSCEIVEB_HSPI_READBACK	0x8bc
+#define	REG_SC_CNT						0x8c4
+#define	RFPGA0_XAB_RFINTERFACERB	0x8e0
+#define	RFPGA0_XCD_RFINTERFACERB	0x8e4
 
 #define	RFPGA1_RFMOD				0x900
 
@@ -1338,12 +1353,12 @@
 #define	RCCK0_SYSTEM				0xa00
 
 #define	RCCK0_AFESETTING			0xa04
-#define	RCCK0_CCA				0xa08
+#define	RCCK0_CCA					0xa08
 
 #define	RCCK0_RXAGC1				0xa0c
 #define	RCCK0_RXAGC2				0xa10
 
-#define	RCCK0_RXHP				0xa14
+#define	RCCK0_RXHP					0xa14
 
 #define	RCCK0_DSPPARAMETER1			0xa18
 #define	RCCK0_DSPPARAMETER2			0xa1c
@@ -1351,75 +1366,74 @@
 #define	RCCK0_TXFILTER1				0xa20
 #define	RCCK0_TXFILTER2				0xa24
 #define	RCCK0_DEBUGPORT				0xa28
-#define	RCCK0_FALSEALARMREPORT			0xa2c
-#define	RCCK0_TRSSIREPORT			0xa50
-#define	RCCK0_RXREPORT				0xa54
-#define	RCCK0_FACOUNTERLOWER			0xa5c
-#define	RCCK0_FACOUNTERUPPER			0xa58
-#define	RCCK0_CCA_CNT				0xa60
-
+#define	RCCK0_FALSEALARMREPORT		0xa2c
+#define	RCCK0_TRSSIREPORT		0xa50
+#define	RCCK0_RXREPORT			0xa54
+#define	RCCK0_FACOUNTERLOWER		0xa5c
+#define	RCCK0_FACOUNTERUPPER		0xa58
+#define	RCCK0_CCA_CNT			0xa60
 
 /* PageB(0xB00) */
-#define	RPDP_ANTA				0xb00
+#define	RPDP_ANTA					0xb00
 #define	RPDP_ANTA_4				0xb04
 #define	RPDP_ANTA_8				0xb08
 #define	RPDP_ANTA_C				0xb0c
-#define	RPDP_ANTA_10				0xb10
-#define	RPDP_ANTA_14				0xb14
-#define	RPDP_ANTA_18				0xb18
-#define	RPDP_ANTA_1C				0xb1c
-#define	RPDP_ANTA_20				0xb20
-#define	RPDP_ANTA_24				0xb24
+#define	RPDP_ANTA_10					0xb10
+#define	RPDP_ANTA_14					0xb14
+#define	RPDP_ANTA_18					0xb18
+#define	RPDP_ANTA_1C					0xb1c
+#define	RPDP_ANTA_20					0xb20
+#define	RPDP_ANTA_24					0xb24
 
 #define	RCONFIG_PMPD_ANTA			0xb28
-#define	RCONFIG_RAM64X16			0xb2c
+#define	RCONFIG_RAM64x16				0xb2c
 
-#define	RBNDA					0xb30
-#define	RHSSIPAR				0xb34
+#define	RBNDA						0xb30
+#define	RHSSIPAR						0xb34
 
-#define	RCONFIG_ANTA				0xb68
-#define	RCONFIG_ANTB				0xb6c
+#define	RCONFIG_ANTA					0xb68
+#define	RCONFIG_ANTB					0xb6c
 
-#define	RPDP_ANTB				0xb70
-#define	RPDP_ANTB_4				0xb74
-#define	RPDP_ANTB_8				0xb78
-#define	RPDP_ANTB_C				0xb7c
-#define	RPDP_ANTB_10				0xb80
-#define	RPDP_ANTB_14				0xb84
-#define	RPDP_ANTB_18				0xb88
-#define	RPDP_ANTB_1C				0xb8c
-#define	RPDP_ANTB_20				0xb90
-#define	RPDP_ANTB_24				0xb94
+#define	RPDP_ANTB					0xb70
+#define	RPDP_ANTB_4					0xb74
+#define	RPDP_ANTB_8					0xb78
+#define	RPDP_ANTB_C					0xb7c
+#define	RPDP_ANTB_10					0xb80
+#define	RPDP_ANTB_14					0xb84
+#define	RPDP_ANTB_18					0xb88
+#define	RPDP_ANTB_1C					0xb8c
+#define	RPDP_ANTB_20					0xb90
+#define	RPDP_ANTB_24					0xb94
 
 #define	RCONFIG_PMPD_ANTB			0xb98
 
-#define	RBNDB					0xba0
+#define	RBNDB						0xba0
 
-#define	RAPK					0xbd8
-#define	rPm_Rx0_AntA				0xbdc
-#define	rPm_Rx1_AntA				0xbe0
-#define	rPm_Rx2_AntA				0xbe4
-#define	rPm_Rx3_AntA				0xbe8
-#define	rPm_Rx0_AntB				0xbec
-#define	rPm_Rx1_AntB				0xbf0
-#define	rPm_Rx2_AntB				0xbf4
-#define	rPm_Rx3_AntB				0xbf8
+#define	RAPK							0xbd8
+#define	RPM_RX0_ANTA				0xbdc
+#define	RPM_RX1_ANTA				0xbe0
+#define	RPM_RX2_ANTA				0xbe4
+#define	RPM_RX3_ANTA				0xbe8
+#define	RPM_RX0_ANTB				0xbec
+#define	RPM_RX1_ANTB				0xbf0
+#define	RPM_RX2_ANTB				0xbf4
+#define	RPM_RX3_ANTB				0xbf8
 
 /*Page C*/
-#define	ROFDM0_LSTF				0xc00
+#define	ROFDM0_LSTF					0xc00
 
-#define	ROFDM0_TRXPATHENABLE			0xc04
+#define	ROFDM0_TRXPATHENABLE		0xc04
 #define	ROFDM0_TRMUXPAR				0xc08
-#define	ROFDM0_TRSWISOLATION			0xc0c
+#define	ROFDM0_TRSWISOLATION		0xc0c
 
 #define	ROFDM0_XARXAFE				0xc10
-#define	ROFDM0_XARXIQIMBAL			0xc14
-#define	ROFDM0_XBRXAFE				0xc18
-#define	ROFDM0_XBRXIQIMBAL			0xc1c
-#define	ROFDM0_XCRXAFE				0xc20
-#define	ROFDM0_XCRXIQIMBAL			0xc24
-#define	ROFDM0_XDRXAFE				0xc28
-#define	ROFDM0_XDRXIQIMBAL			0xc2c
+#define	ROFDM0_XARXIQIMBALANCE		0xc14
+#define	ROFDM0_XBRXAFE			0xc18
+#define	ROFDM0_XBRXIQIMBALANCE		0xc1c
+#define	ROFDM0_XCRXAFE			0xc20
+#define	ROFDM0_XCRXIQIMBANLANCE		0xc24
+#define	ROFDM0_XDRXAFE			0xc28
+#define	ROFDM0_XDRXIQIMBALANCE		0xc2c
 
 #define	ROFDM0_RXDETECTOR1			0xc30
 #define	ROFDM0_RXDETECTOR2			0xc34
@@ -1428,8 +1442,8 @@
 
 #define	ROFDM0_RXDSP				0xc40
 #define	ROFDM0_CFOANDDAGC			0xc44
-#define	ROFDM0_CCADROPTHRES			0xc48
-#define	ROFDM0_ECCATHRES			0xc4c
+#define	ROFDM0_CCADROPTHRESHOLD		0xc48
+#define	ROFDM0_ECCATHRESHOLD		0xc4c
 
 #define	ROFDM0_XAAGCCORE1			0xc50
 #define	ROFDM0_XAAGCCORE2			0xc54
@@ -1440,18 +1454,18 @@
 #define	ROFDM0_XDAGCCORE1			0xc68
 #define	ROFDM0_XDAGCCORE2			0xc6c
 
-#define	ROFDM0_AGCPARAMETER1			0xc70
-#define	ROFDM0_AGCPARAMETER2			0xc74
+#define	ROFDM0_AGCPARAMETER1		0xc70
+#define	ROFDM0_AGCPARAMETER2		0xc74
 #define	ROFDM0_AGCRSSITABLE			0xc78
 #define	ROFDM0_HTSTFAGC				0xc7c
 
-#define	ROFDM0_XATXIQIMBAL			0xc80
+#define	ROFDM0_XATXIQIMBALANCE		0xc80
 #define	ROFDM0_XATXAFE				0xc84
-#define	ROFDM0_XBTXIQIMBAL			0xc88
+#define	ROFDM0_XBTXIQIMBALANCE		0xc88
 #define	ROFDM0_XBTXAFE				0xc8c
-#define	ROFDM0_XCTXIQIMBAL			0xc90
-#define	ROFDM0_XCTXAFE				0xc94
-#define	ROFDM0_XDTXIQIMBAL			0xc98
+#define	ROFDM0_XCTXIQIMBALANCE		0xc90
+#define	ROFDM0_XCTXAFE			0xc94
+#define	ROFDM0_XDTXIQIMBALANCE		0xc98
 #define	ROFDM0_XDTXAFE				0xc9c
 
 #define ROFDM0_RXIQEXTANTA			0xca0
@@ -1462,25 +1476,24 @@
 #define	ROFDM0_TXCOEFF5				0xcb4
 #define	ROFDM0_TXCOEFF6				0xcb8
 
-#define	ROFDM0_RXHPPARAMETER			0xce0
-#define	ROFDM0_TXPSEUDONOISEWGT			0xce4
+#define	ROFDM0_RXHPPARAMETER		0xce0
+#define	ROFDM0_TXPSEUDONOISEWGT		0xce4
 #define	ROFDM0_FRAMESYNC			0xcf0
 #define	ROFDM0_DFSREPORT			0xcf4
 
+#define	ROFDM1_LSTF					0xd00
+#define	ROFDM1_TRXPATHENABLE		0xd04
 
-#define	ROFDM1_LSTF				0xd00
-#define	ROFDM1_TRXPATHENABLE			0xd04
-
-#define	ROFDM1_CF0				0xd08
-#define	ROFDM1_CSI1				0xd10
-#define	ROFDM1_SBD				0xd14
-#define	ROFDM1_CSI2				0xd18
+#define	ROFDM1_CF0					0xd08
+#define	ROFDM1_CSI1					0xd10
+#define	ROFDM1_SBD					0xd14
+#define	ROFDM1_CSI2					0xd18
 #define	ROFDM1_CFOTRACKING			0xd2c
 #define	ROFDM1_TRXMESAURE1			0xd34
 #define	ROFDM1_INTFDET				0xd3c
-#define	ROFDM1_PSEUDONOISESTATEAB		0xd50
-#define	ROFDM1_PSEUDONOISESTATECD		0xd54
-#define	ROFDM1_RXPSEUDONOISEWGT			0xd58
+#define	ROFDM1_PSEUDONOISESTATEAB	0xd50
+#define	ROFDM1_PSEUDONOISESTATECD	0xd54
+#define	ROFDM1_RXPSEUDONOISEWGT		0xd58
 
 #define	ROFDM_PHYCOUNTER1			0xda0
 #define	ROFDM_PHYCOUNTER2			0xda4
@@ -1492,84 +1505,84 @@
 #define	ROFDM_LONGCFOCD				0xdb8
 #define	ROFDM_TAILCF0AB				0xdbc
 #define	ROFDM_TAILCF0CD				0xdc0
-#define	ROFDM_PWMEASURE1			0xdc4
-#define	ROFDM_PWMEASURE2			0xdc8
+#define	ROFDM_PWMEASURE1		0xdc4
+#define	ROFDM_PWMEASURE2		0xdc8
 #define	ROFDM_BWREPORT				0xdcc
 #define	ROFDM_AGCREPORT				0xdd0
-#define	ROFDM_RXSNR				0xdd4
+#define	ROFDM_RXSNR					0xdd4
 #define	ROFDM_RXEVMCSI				0xdd8
 #define	ROFDM_SIGREPORT				0xddc
 
 #define	RTXAGC_A_RATE18_06			0xe00
 #define	RTXAGC_A_RATE54_24			0xe04
 #define	RTXAGC_A_CCK1_MCS32			0xe08
-#define	RTXAGC_A_MCS03_MCS00			0xe10
-#define	RTXAGC_A_MCS07_MCS04			0xe14
-#define	RTXAGC_A_MCS11_MCS08			0xe18
-#define	RTXAGC_A_MCS15_MCS12			0xe1c
+#define	RTXAGC_A_MCS03_MCS00		0xe10
+#define	RTXAGC_A_MCS07_MCS04		0xe14
+#define	RTXAGC_A_MCS11_MCS08		0xe18
+#define	RTXAGC_A_MCS15_MCS12		0xe1c
 
 #define	RTXAGC_B_RATE18_06			0x830
 #define	RTXAGC_B_RATE54_24			0x834
-#define	RTXAGC_B_CCK1_55_MCS32			0x838
-#define	RTXAGC_B_MCS03_MCS00			0x83c
-#define	RTXAGC_B_MCS07_MCS04			0x848
-#define	RTXAGC_B_MCS11_MCS08			0x84c
-#define	RTXAGC_B_MCS15_MCS12			0x868
-#define	RTXAGC_B_CCK11_A_CCK2_11		0x86c
+#define	RTXAGC_B_CCK1_55_MCS32		0x838
+#define	RTXAGC_B_MCS03_MCS00		0x83c
+#define	RTXAGC_B_MCS07_MCS04		0x848
+#define	RTXAGC_B_MCS11_MCS08		0x84c
+#define	RTXAGC_B_MCS15_MCS12		0x868
+#define	RTXAGC_B_CCK11_A_CCK2_11	0x86c
 
-#define	RFPGA0_IQK				0xe28
+#define	RFPGA0_IQK					0xe28
 #define	RTX_IQK_TONE_A				0xe30
 #define	RRX_IQK_TONE_A				0xe34
-#define	RTX_IQK_PI_A				0xe38
-#define	RRX_IQK_PI_A				0xe3c
+#define	RTX_IQK_PI_A					0xe38
+#define	RRX_IQK_PI_A					0xe3c
 
-#define	RTX_IQK					0xe40
-#define	RRX_IQK					0xe44
-#define	RIQK_AGC_PTS				0xe48
-#define	RIQK_AGC_RSP				0xe4c
+#define	RTX_IQK							0xe40
+#define	RRX_IQK						0xe44
+#define	RIQK_AGC_PTS					0xe48
+#define	RIQK_AGC_RSP					0xe4c
 #define	RTX_IQK_TONE_B				0xe50
 #define	RRX_IQK_TONE_B				0xe54
-#define	RTX_IQK_PI_B				0xe58
-#define	RRX_IQK_PI_B				0xe5c
+#define	RTX_IQK_PI_B					0xe58
+#define	RRX_IQK_PI_B					0xe5c
 #define	RIQK_AGC_CONT				0xe60
 
-#define	RBLUE_TOOTH				0xe6c
-#define	RRX_WAIT_CCA				0xe70
-#define	RTX_CCK_RFON				0xe74
+#define	RBLUE_TOOTH					0xe6c
+#define	RRX_WAIT_CCA					0xe70
+#define	RTX_CCK_RFON					0xe74
 #define	RTX_CCK_BBON				0xe78
 #define	RTX_OFDM_RFON				0xe7c
 #define	RTX_OFDM_BBON				0xe80
-#define	RTX_TO_RX				0xe84
-#define	RTX_TO_TX				0xe88
-#define	RRX_CCK					0xe8c
+#define	RTX_TO_RX					0xe84
+#define	RTX_TO_TX					0xe88
+#define	RRX_CCK						0xe8c
 
-#define	RTX_POWER_BEFORE_IQK_A			0xe94
+#define	RTX_POWER_BEFORE_IQK_A		0xe94
 #define	RTX_POWER_AFTER_IQK_A			0xe9c
 
-#define	RRX_POWER_BEFORE_IQK_A			0xea0
+#define	RRX_POWER_BEFORE_IQK_A		0xea0
 #define	RRX_POWER_BEFORE_IQK_A_2		0xea4
 #define	RRX_POWER_AFTER_IQK_A			0xea8
-#define	RRX_POWER_AFTER_IQK_A_2			0xeac
+#define	RRX_POWER_AFTER_IQK_A_2		0xeac
 
-#define	RTX_POWER_BEFORE_IQK_B			0xeb4
+#define	RTX_POWER_BEFORE_IQK_B		0xeb4
 #define	RTX_POWER_AFTER_IQK_B			0xebc
 
-#define	RRX_POWER_BEFORE_IQK_B			0xec0
+#define	RRX_POWER_BEFORE_IQK_B		0xec0
 #define	RRX_POWER_BEFORE_IQK_B_2		0xec4
 #define	RRX_POWER_AFTER_IQK_B			0xec8
-#define	RRX_POWER_AFTER_IQK_B_2			0xecc
+#define	RRX_POWER_AFTER_IQK_B_2		0xecc
 
-#define	RRX_OFDM				0xed0
+#define	RRX_OFDM					0xed0
 #define	RRX_WAIT_RIFS				0xed4
-#define	RRX_TO_RX				0xed8
-#define	RSTANDBY				0xedc
-#define	RSLEEP					0xee0
+#define	RRX_TO_RX					0xed8
+#define	RSTANDBY						0xedc
+#define	RSLEEP						0xee0
 #define	RPMPD_ANAEN				0xeec
 
 #define	RZEBRA1_HSSIENABLE			0x0
 #define	RZEBRA1_TRXENABLE1			0x1
 #define	RZEBRA1_TRXENABLE2			0x2
-#define	RZEBRA1_AGC				0x4
+#define	RZEBRA1_AGC					0x4
 #define	RZEBRA1_CHARGEPUMP			0x5
 #define	RZEBRA1_CHANNEL				0x7
 
@@ -1578,666 +1591,681 @@
 #define	RZEBRA1_RXLPF				0xb
 #define	RZEBRA1_RXHPFCORNER			0xc
 
-#define	RGLOBALCTRL				0
+#define	RGLOBALCTRL					0
 #define	RRTL8256_TXLPF				19
 #define	RRTL8256_RXLPF				11
 #define	RRTL8258_TXLPF				0x11
 #define	RRTL8258_RXLPF				0x13
 #define	RRTL8258_RSSILPF			0xa
 
-#define	RF_AC					0x00
+#define	RF_AC						0x00
 
-#define	RF_IQADJ_G1				0x01
-#define	RF_IQADJ_G2				0x02
-#define	RF_POW_TRSW				0x05
+#define	RF_IQADJ_G1					0x01
+#define	RF_IQADJ_G2					0x02
+#define	RF_POW_TRSW					0x05
 
-#define	RF_GAIN_RX				0x06
-#define	RF_GAIN_TX				0x07
+#define	RF_GAIN_RX					0x06
+#define	RF_GAIN_TX					0x07
 
-#define	RF_TXM_IDAC				0x08
-#define	RF_BS_IQGEN				0x0F
+#define	RF_TXM_IDAC					0x08
+#define	RF_BS_IQGEN					0x0F
 
-#define	RF_MODE1				0x10
-#define	RF_MODE2				0x11
+#define	RF_MODE1					0x10
+#define	RF_MODE2					0x11
 
 #define	RF_RX_AGC_HP				0x12
-#define	RF_TX_AGC				0x13
-#define	RF_BIAS					0x14
-#define	RF_IPA					0x15
+#define	RF_TX_AGC					0x13
+#define	RF_BIAS						0x14
+#define	RF_IPA						0x15
 #define	RF_POW_ABILITY				0x17
-#define	RF_MODE_AG				0x18
-#define	RRFCHANNEL				0x18
-#define	RF_CHNLBW				0x18
-#define	RF_TOP					0x19
+#define	RF_MODE_AG					0x18
+#define	RRFCHANNEL					0x18
+#define	RF_CHNLBW					0x18
+#define	RF_TOP						0x19
 
-#define	RF_RX_G1				0x1A
-#define	RF_RX_G2				0x1B
+#define	RF_RX_G1					0x1A
+#define	RF_RX_G2					0x1B
 
-#define	RF_RX_BB2				0x1C
-#define	RF_RX_BB1				0x1D
+#define	RF_RX_BB2					0x1C
+#define	RF_RX_BB1					0x1D
 
-#define	RF_RCK1					0x1E
-#define	RF_RCK2					0x1F
+#define	RF_RCK1						0x1E
+#define	RF_RCK2						0x1F
 
-#define	RF_TX_G1				0x20
-#define	RF_TX_G2				0x21
-#define	RF_TX_G3				0x22
+#define	RF_TX_G1					0x20
+#define	RF_TX_G2					0x21
+#define	RF_TX_G3					0x22
 
-#define	RF_TX_BB1				0x23
-#define	RF_T_METER				0x42
+#define	RF_TX_BB1					0x23
+#define	RF_T_METER					0x42
 
-#define	RF_SYN_G1				0x25
-#define	RF_SYN_G2				0x26
-#define	RF_SYN_G3				0x27
-#define	RF_SYN_G4				0x28
-#define	RF_SYN_G5				0x29
-#define	RF_SYN_G6				0x2A
-#define	RF_SYN_G7				0x2B
-#define	RF_SYN_G8				0x2C
+#define	RF_SYN_G1					0x25
+#define	RF_SYN_G2					0x26
+#define	RF_SYN_G3					0x27
+#define	RF_SYN_G4					0x28
+#define	RF_SYN_G5					0x29
+#define	RF_SYN_G6					0x2A
+#define	RF_SYN_G7					0x2B
+#define	RF_SYN_G8					0x2C
 
-#define	RF_RCK_OS				0x30
-#define	RF_TXPA_G1				0x31
-#define	RF_TXPA_G2				0x32
-#define	RF_TXPA_G3				0x33
+#define	RF_RCK_OS					0x30
+#define	RF_TXPA_G1					0x31
+#define	RF_TXPA_G2					0x32
+#define	RF_TXPA_G3					0x33
 
-#define	RF_TX_BIAS_A				0x35
-#define	RF_TX_BIAS_D				0x36
-#define	RF_LOBF_9				0x38
-#define	RF_RXRF_A3				0x3C
-#define	RF_TRSW					0x3F
+#define	RF_TX_BIAS_A					0x35
+#define	RF_TX_BIAS_D					0x36
+#define	RF_LOBF_9					0x38
+#define	RF_RXRF_A3					0x3C
+#define	RF_TRSW						0x3F
 
-#define	RF_TXRF_A2				0x41
-#define	RF_TXPA_G4				0x46
-#define	RF_TXPA_A4				0x4B
+#define	RF_TXRF_A2					0x41
+#define	RF_TXPA_G4					0x46
+#define	RF_TXPA_A4					0x4B
 
-#define	RF_WE_LUT				0xEF
+#define	RF_WE_LUT					0xEF
 
-#define	BBBRESETB				0x100
+#define	BBBRESETB					0x100
 #define	BGLOBALRESETB				0x200
 #define	BOFDMTXSTART				0x4
-#define	BCCKTXSTART				0x8
-#define	BCRC32DEBUG				0x100
+#define	BCCKTXSTART					0x8
+#define	BCRC32DEBUG					0x100
 #define	BPMACLOOPBACK				0x10
-#define	BTXLSIG					0xffffff
-#define	BOFDMTXRATE				0xf
+#define	BTXLSIG						0xffffff
+#define	BOFDMTXRATE					0xf
 #define	BOFDMTXRESERVED				0x10
 #define	BOFDMTXLENGTH				0x1ffe0
 #define	BOFDMTXPARITY				0x20000
-#define	BTXHTSIG1				0xffffff
+#define	BTXHTSIG1					0xffffff
 #define	BTXHTMCSRATE				0x7f
-#define	BTXHTBW					0x80
-#define	BTXHTLENGTH				0xffff00
-#define	BTXHTSIG2				0xffffff
+#define	BTXHTBW						0x80
+#define	BTXHTLENGTH					0xffff00
+#define	BTXHTSIG2					0xffffff
 #define	BTXHTSMOOTHING				0x1
 #define	BTXHTSOUNDING				0x2
 #define	BTXHTRESERVED				0x4
 #define	BTXHTAGGREATION				0x8
-#define	BTXHTSTBC				0x30
+#define	BTXHTSTBC					0x30
 #define	BTXHTADVANCECODING			0x40
 #define	BTXHTSHORTGI				0x80
 #define	BTXHTNUMBERHT_LTF			0x300
-#define	BTXHTCRC8				0x3fc00
+#define	BTXHTCRC8					0x3fc00
 #define	BCOUNTERRESET				0x10000
 #define	BNUMOFOFDMTX				0xffff
-#define	BNUMOFCCKTX				0xffff0000
+#define	BNUMOFCCKTX					0xffff0000
 #define	BTXIDLEINTERVAL				0xffff
 #define	BOFDMSERVICE				0xffff0000
 #define	BTXMACHEADER				0xffffffff
-#define	BTXDATAINIT				0xff
-#define	BTXHTMODE				0x100
-#define	BTXDATATYPE				0x30000
+#define	BTXDATAINIT					0xff
+#define	BTXHTMODE					0x100
+#define	BTXDATATYPE					0x30000
 #define	BTXRANDOMSEED				0xffffffff
 #define	BCCKTXPREAMBLE				0x1
-#define	BCCKTXSFD				0xffff0000
-#define	BCCKTXSIG				0xff
+#define	BCCKTXSFD					0xffff0000
+#define	BCCKTXSIG					0xff
 #define	BCCKTXSERVICE				0xff00
 #define	BCCKLENGTHEXT				0x8000
 #define	BCCKTXLENGHT				0xffff0000
-#define	BCCKTXCRC16				0xffff
+#define	BCCKTXCRC16					0xffff
 #define	BCCKTXSTATUS				0x1
 #define	BOFDMTXSTATUS				0x2
 #define IS_BB_REG_OFFSET_92S(_offset)	\
 	((_offset >= 0x800) && (_offset <= 0xfff))
 
-#define	BRFMOD					0x1
-#define	BJAPANMODE				0x2
-#define	BCCKTXSC				0x30
-#define	BCCKEN					0x1000000
-#define	BOFDMEN					0x2000000
+#define	BRFMOD						0x1
+#define	BJAPANMODE					0x2
+#define	BCCKTXSC					0x30
+#define	BCCKEN						0x1000000
+#define	BOFDMEN						0x2000000
 
-#define	BOFDMRXADCPHASE				0x10000
-#define	BOFDMTXDACPHASE				0x40000
-#define	BXATXAGC				0x3f
+#define	BOFDMRXADCPHASE			0x10000
+#define	BOFDMTXDACPHASE			0x40000
+#define	BXATXAGC			0x3f
 
-#define	BXBTXAGC				0xf00
-#define	BXCTXAGC				0xf000
-#define	BXDTXAGC				0xf0000
+#define	BXBTXAGC			0xf00
+#define	BXCTXAGC			0xf000
+#define	BXDTXAGC			0xf0000
 
-#define	BPASTART				0xf0000000
-#define	BTRSTART				0x00f00000
-#define	BRFSTART				0x0000f000
-#define	BBBSTART				0x000000f0
-#define	BBBCCKSTART				0x0000000f
-#define	BPAEND					0xf
-#define	BTREND					0x0f000000
-#define	BRFEND					0x000f0000
-#define	BCCAMASK				0x000000f0
-#define	BR2RCCAMASK				0x00000f00
-#define	BHSSI_R2TDELAY				0xf8000000
-#define	BHSSI_T2RDELAY				0xf80000
-#define	BCONTXHSSI				0x400
-#define	BIGFROMCCK				0x200
-#define	BAGCADDRESS				0x3f
-#define	BRXHPTX					0x7000
-#define	BRXHP2RX				0x38000
-#define	BRXHPCCKINI				0xc0000
-#define	BAGCTXCODE				0xc00000
-#define	BAGCRXCODE				0x300000
+#define	BPASTART			0xf0000000
+#define	BTRSTART			0x00f00000
+#define	BRFSTART			0x0000f000
+#define	BBBSTART			0x000000f0
+#define	BBBCCKSTART			0x0000000f
+#define	BPAEND				0xf
+#define	BTREND				0x0f000000
+#define	BRFEND				0x000f0000
+#define	BCCAMASK			0x000000f0
+#define	BR2RCCAMASK			0x00000f00
+#define	BHSSI_R2TDELAY			0xf8000000
+#define	BHSSI_T2RDELAY			0xf80000
+#define	BCONTXHSSI			0x400
+#define	BIGFROMCCK			0x200
+#define	BAGCADDRESS			0x3f
+#define	BRXHPTX				0x7000
+#define	BRXHP2RX			0x38000
+#define	BRXHPCCKINI			0xc0000
+#define	BAGCTXCODE			0xc00000
+#define	BAGCRXCODE			0x300000
 
-#define	B3WIREDATALENGTH			0x800
-#define	B3WIREADDREAALENGTH			0x400
+#define	B3WIREDATALENGTH		0x800
+#define	B3WIREADDREAALENGTH		0x400
 
-#define	B3WIRERFPOWERDOWN			0x1
-#define	B5GPAPEPOLARITY				0x40000000
-#define	B2GPAPEPOLARITY				0x80000000
-#define	BRFSW_TXDEFAULTANT			0x3
-#define	BRFSW_TXOPTIONANT			0x30
-#define	BRFSW_RXDEFAULTANT			0x300
-#define	BRFSW_RXOPTIONANT			0x3000
-#define	BRFSI_3WIREDATA				0x1
-#define	BRFSI_3WIRECLOCK			0x2
-#define	BRFSI_3WIRELOAD				0x4
-#define	BRFSI_3WIRERW				0x8
-#define	BRFSI_3WIRE				0xf
+#define	B3WIRERFPOWERDOWN		0x1
+#define	B5GPAPEPOLARITY			0x40000000
+#define	B2GPAPEPOLARITY			0x80000000
+#define	BRFSW_TXDEFAULTANT		0x3
+#define	BRFSW_TXOPTIONANT		0x30
+#define	BRFSW_RXDEFAULTANT		0x300
+#define	BRFSW_RXOPTIONANT		0x3000
+#define	BRFSI_3WIREDATA			0x1
+#define	BRFSI_3WIRECLOCK		0x2
+#define	BRFSI_3WIRELOAD			0x4
+#define	BRFSI_3WIRERW			0x8
+#define	BRFSI_3WIRE			0xf
 
-#define	BRFSI_RFENV				0x10
+#define	BRFSI_RFENV			0x10
 
-#define	BRFSI_TRSW				0x20
-#define	BRFSI_TRSWB				0x40
-#define	BRFSI_ANTSW				0x100
-#define	BRFSI_ANTSWB				0x200
-#define	BRFSI_PAPE				0x400
-#define	BRFSI_PAPE5G				0x800
-#define	BBANDSELECT				0x1
-#define	BHTSIG2_GI				0x80
-#define	BHTSIG2_SMOOTHING			0x01
-#define	BHTSIG2_SOUNDING			0x02
-#define	BHTSIG2_AGGREATON			0x08
-#define	BHTSIG2_STBC				0x30
-#define	BHTSIG2_ADVCODING			0x40
-#define	BHTSIG2_NUMOFHTLTF			0x300
-#define	BHTSIG2_CRC8				0x3fc
-#define	BHTSIG1_MCS				0x7f
-#define	BHTSIG1_BANDWIDTH			0x80
-#define	BHTSIG1_HTLENGTH			0xffff
-#define	BLSIG_RATE				0xf
-#define	BLSIG_RESERVED				0x10
-#define	BLSIG_LENGTH				0x1fffe
-#define	BLSIG_PARITY				0x20
-#define	BCCKRXPHASE				0x4
+#define	BRFSI_TRSW			0x20
+#define	BRFSI_TRSWB			0x40
+#define	BRFSI_ANTSW			0x100
+#define	BRFSI_ANTSWB			0x200
+#define	BRFSI_PAPE			0x400
+#define	BRFSI_PAPE5G			0x800
+#define	BBANDSELECT			0x1
+#define	BHTSIG2_GI			0x80
+#define	BHTSIG2_SMOOTHING		0x01
+#define	BHTSIG2_SOUNDING		0x02
+#define	BHTSIG2_AGGREATON		0x08
+#define	BHTSIG2_STBC			0x30
+#define	BHTSIG2_ADVCODING		0x40
+#define	BHTSIG2_NUMOFHTLTF		0x300
+#define	BHTSIG2_CRC8			0x3fc
+#define	BHTSIG1_MCS			0x7f
+#define	BHTSIG1_BANDWIDTH		0x80
+#define	BHTSIG1_HTLENGTH		0xffff
+#define	BLSIG_RATE			0xf
+#define	BLSIG_RESERVED			0x10
+#define	BLSIG_LENGTH			0x1fffe
+#define	BLSIG_PARITY			0x20
+#define	BCCKRXPHASE			0x4
 
-#define	BLSSIREADADDRESS			0x7f800000
-#define	BLSSIREADEDGE				0x80000000
+#define	BLSSIREADADDRESS		0x7f800000
+#define	BLSSIREADEDGE			0x80000000
 
-#define	BLSSIREADBACKDATA			0xfffff
+#define	BLSSIREADBACKDATA		0xfffff
 
-#define	BLSSIREADOKFLAG				0x1000
-#define	BCCKSAMPLERATE				0x8
-#define	BREGULATOR0STANDBY			0x1
-#define	BREGULATORPLLSTANDBY			0x2
-#define	BREGULATOR1STANDBY			0x4
-#define	BPLLPOWERUP				0x8
-#define	BDPLLPOWERUP				0x10
-#define	BDA10POWERUP				0x20
-#define	BAD7POWERUP				0x200
-#define	BDA6POWERUP				0x2000
-#define	BXTALPOWERUP				0x4000
-#define	B40MDCLKPOWERUP				0x8000
-#define	BDA6DEBUGMODE				0x20000
-#define	BDA6SWING				0x380000
+#define	BLSSIREADOKFLAG			0x1000
+#define	BCCKSAMPLERATE			0x8
+#define	BREGULATOR0STANDBY		0x1
+#define	BREGULATORPLLSTANDBY		0x2
+#define	BREGULATOR1STANDBY		0x4
+#define	BPLLPOWERUP			0x8
+#define	BDPLLPOWERUP			0x10
+#define	BDA10POWERUP			0x20
+#define	BAD7POWERUP			0x200
+#define	BDA6POWERUP			0x2000
+#define	BXTALPOWERUP			0x4000
+#define	B40MDCLKPOWERUP			0x8000
+#define	BDA6DEBUGMODE			0x20000
+#define	BDA6SWING			0x380000
 
-#define	BADCLKPHASE				0x4000000
-#define	B80MCLKDELAY				0x18000000
-#define	BAFEWATCHDOGENABLE			0x20000000
+#define	BADCLKPHASE			0x4000000
+#define	B80MCLKDELAY			0x18000000
+#define	BAFEWATCHDOGENABLE		0x20000000
 
-#define	BXTALCAP01				0xc0000000
-#define	BXTALCAP23				0x3
-#define	BXTALCAP92X				0x0f000000
-#define BXTALCAP				0x0f000000
+#define	BXTALCAP01			0xc0000000
+#define	BXTALCAP23			0x3
+#define	BXTALCAP92X					0x0f000000
+#define BXTALCAP			0x0f000000
 
-#define	BINTDIFCLKENABLE			0x400
-#define	BEXTSIGCLKENABLE			0x800
-#define	BBANDGAP_MBIAS_POWERUP			0x10000
-#define	BAD11SH_GAIN				0xc0000
-#define	BAD11NPUT_RANGE				0x700000
-#define	BAD110P_CURRENT				0x3800000
-#define	BLPATH_LOOPBACK				0x4000000
-#define	BQPATH_LOOPBACK				0x8000000
-#define	BAFE_LOOPBACK				0x10000000
-#define	BDA10_SWING				0x7e0
-#define	BDA10_REVERSE				0x800
-#define	BDA_CLK_SOURCE				0x1000
-#define	BDA7INPUT_RANGE				0x6000
-#define	BDA7_GAIN				0x38000
-#define	BDA7OUTPUT_CM_MODE			0x40000
-#define	BDA7INPUT_CM_MODE			0x380000
-#define	BDA7CURRENT				0xc00000
-#define	BREGULATOR_ADJUST			0x7000000
-#define	BAD11POWERUP_ATTX			0x1
-#define	BDA10PS_ATTX				0x10
-#define	BAD11POWERUP_ATRX			0x100
-#define	BDA10PS_ATRX				0x1000
-#define	BCCKRX_AGC_FORMAT			0x200
-#define	BPSDFFT_SAMPLE_POINT			0xc000
-#define	BPSD_AVERAGE_NUM			0x3000
-#define	BIQPATH_CONTROL				0xc00
-#define	BPSD_FREQ				0x3ff
-#define	BPSD_ANTENNA_PATH			0x30
-#define	BPSD_IQ_SWITCH				0x40
-#define	BPSD_RX_TRIGGER				0x400000
-#define	BPSD_TX_TRIGGERCW			0x80000000
-#define	BPSD_SINE_TONE_SCALE			0x7f000000
-#define	BPSD_REPORT				0xffff
+#define	BINTDIFCLKENABLE		0x400
+#define	BEXTSIGCLKENABLE		0x800
+#define	BBANDGAP_MBIAS_POWERUP      0x10000
+#define	BAD11SH_GAIN			0xc0000
+#define	BAD11NPUT_RANGE			0x700000
+#define	BAD110P_CURRENT			0x3800000
+#define	BLPATH_LOOPBACK			0x4000000
+#define	BQPATH_LOOPBACK			0x8000000
+#define	BAFE_LOOPBACK			0x10000000
+#define	BDA10_SWING			0x7e0
+#define	BDA10_REVERSE			0x800
+#define	BDA_CLK_SOURCE              0x1000
+#define	BDA7INPUT_RANGE			0x6000
+#define	BDA7_GAIN			0x38000
+#define	BDA7OUTPUT_CM_MODE          0x40000
+#define	BDA7INPUT_CM_MODE           0x380000
+#define	BDA7CURRENT			0xc00000
+#define	BREGULATOR_ADJUST		0x7000000
+#define	BAD11POWERUP_ATTX		0x1
+#define	BDA10PS_ATTX			0x10
+#define	BAD11POWERUP_ATRX		0x100
+#define	BDA10PS_ATRX			0x1000
+#define	BCCKRX_AGC_FORMAT           0x200
+#define	BPSDFFT_SAMPLE_POINT		0xc000
+#define	BPSD_AVERAGE_NUM            0x3000
+#define	BIQPATH_CONTROL			0xc00
+#define	BPSD_FREQ			0x3ff
+#define	BPSD_ANTENNA_PATH           0x30
+#define	BPSD_IQ_SWITCH              0x40
+#define	BPSD_RX_TRIGGER             0x400000
+#define	BPSD_TX_TRIGGER             0x80000000
+#define	BPSD_SINE_TONE_SCALE        0x7f000000
+#define	BPSD_REPORT			0xffff
 
-#define	BOFDM_TXSC				0x30000000
-#define	BCCK_TXON				0x1
-#define	BOFDM_TXON				0x2
-#define	BDEBUG_PAGE				0xfff
-#define	BDEBUG_ITEM				0xff
-#define	BANTL					0x10
-#define	BANT_NONHT				0x100
-#define	BANT_HT1				0x1000
-#define	BANT_HT2				0x10000
-#define	BANT_HT1S1				0x100000
-#define	BANT_NONHTS1				0x1000000
+#define	BOFDM_TXSC			0x30000000
+#define	BCCK_TXON			0x1
+#define	BOFDM_TXON			0x2
+#define	BDEBUG_PAGE			0xfff
+#define	BDEBUG_ITEM			0xff
+#define	BANTL				0x10
+#define	BANT_NONHT		    0x100
+#define	BANT_HT1			0x1000
+#define	BANT_HT2			0x10000
+#define	BANT_HT1S1			0x100000
+#define	BANT_NONHTS1			0x1000000
 
-#define	BCCK_BBMODE				0x3
-#define	BCCK_TXPOWERSAVING			0x80
-#define	BCCK_RXPOWERSAVING			0x40
+#define	BCCK_BBMODE			0x3
+#define	BCCK_TXPOWERSAVING		0x80
+#define	BCCK_RXPOWERSAVING		0x40
 
-#define	BCCK_SIDEBAND				0x10
+#define	BCCK_SIDEBAND			0x10
 
-#define	BCCK_SCRAMBLE				0x8
-#define	BCCK_ANTDIVERSITY			0x8000
-#define	BCCK_CARRIER_RECOVERY			0x4000
-#define	BCCK_TXRATE				0x3000
-#define	BCCK_DCCANCEL				0x0800
-#define	BCCK_ISICANCEL				0x0400
-#define	BCCK_MATCH_FILTER			0x0200
-#define	BCCK_EQUALIZER				0x0100
-#define	BCCK_PREAMBLE_DETECT			0x800000
-#define	BCCK_FAST_FALSECCA			0x400000
-#define	BCCK_CH_ESTSTART			0x300000
-#define	BCCK_CCA_COUNT				0x080000
-#define	BCCK_CS_LIM				0x070000
-#define	BCCK_BIST_MODE				0x80000000
-#define	BCCK_CCAMASK				0x40000000
-#define	BCCK_TX_DAC_PHASE			0x4
-#define	BCCK_RX_ADC_PHASE			0x20000000
-#define	BCCKR_CP_MODE				0x0100
-#define	BCCK_TXDC_OFFSET			0xf0
-#define	BCCK_RXDC_OFFSET			0xf
-#define	BCCK_CCA_MODE				0xc000
-#define	BCCK_FALSECS_LIM			0x3f00
-#define	BCCK_CS_RATIO				0xc00000
-#define	BCCK_CORGBIT_SEL			0x300000
-#define	BCCK_PD_LIM				0x0f0000
-#define	BCCK_NEWCCA				0x80000000
-#define	BCCK_RXHP_OF_IG				0x8000
-#define	BCCK_RXIG				0x7f00
-#define	BCCK_LNA_POLARITY			0x800000
-#define	BCCK_RX1ST_BAIN				0x7f0000
-#define	BCCK_RF_EXTEND				0x20000000
-#define	BCCK_RXAGC_SATLEVEL			0x1f000000
-#define	BCCK_RXAGC_SATCOUNT			0xe0
-#define	BCCKRXRFSETTLE				0x1f
-#define	BCCK_FIXED_RXAGC			0x8000
-#define	BCCK_ANTENNA_POLARITY			0x2000
-#define	BCCK_TXFILTER_TYPE			0x0c00
-#define	BCCK_RXAGC_REPORTTYPE			0x0300
-#define	BCCK_RXDAGC_EN				0x80000000
-#define	BCCK_RXDAGC_PERIOD			0x20000000
-#define	BCCK_RXDAGC_SATLEVEL			0x1f000000
-#define	BCCK_TIMING_RECOVERY			0x800000
-#define	BCCK_TXC0				0x3f0000
-#define	BCCK_TXC1				0x3f000000
-#define	BCCK_TXC2				0x3f
-#define	BCCK_TXC3				0x3f00
-#define	BCCK_TXC4				0x3f0000
-#define	BCCK_TXC5				0x3f000000
-#define	BCCK_TXC6				0x3f
-#define	BCCK_TXC7				0x3f00
-#define	BCCK_DEBUGPORT				0xff0000
-#define	BCCK_DAC_DEBUG				0x0f000000
-#define	BCCK_FALSEALARM_ENABLE			0x8000
-#define	BCCK_FALSEALARM_READ			0x4000
-#define	BCCK_TRSSI				0x7f
-#define	BCCK_RXAGC_REPORT			0xfe
-#define	BCCK_RXREPORT_ANTSEL			0x80000000
-#define	BCCK_RXREPORT_MFOFF			0x40000000
-#define	BCCK_RXREPORT_SQLOSS			0x20000000
-#define	BCCK_RXREPORT_PKTLOSS			0x10000000
-#define	BCCK_RXREPORT_LOCKEDBIT			0x08000000
-#define	BCCK_RXREPORT_RATEERROR			0x04000000
-#define	BCCK_RXREPORT_RXRATE			0x03000000
-#define	BCCK_RXFA_COUNTER_LOWER			0xff
-#define	BCCK_RXFA_COUNTER_UPPER			0xff000000
-#define	BCCK_RXHPAGC_START			0xe000
-#define	BCCK_RXHPAGC_FINAL			0x1c00
-#define	BCCK_RXFALSEALARM_ENABLE		0x8000
-#define	BCCK_FACOUNTER_FREEZE			0x4000
-#define	BCCK_TXPATH_SEL				0x10000000
-#define	BCCK_DEFAULT_RXPATH			0xc000000
-#define	BCCK_OPTION_RXPATH			0x3000000
+#define	BCCK_SCRAMBLE			0x8
+#define	BCCK_ANTDIVERSITY		0x8000
+#define	BCCK_CARRIER_RECOVERY		0x4000
+#define	BCCK_TXRATE			0x3000
+#define	BCCK_DCCANCEL			0x0800
+#define	BCCK_ISICANCEL			0x0400
+#define	BCCK_MATCH_FILTER           0x0200
+#define	BCCK_EQUALIZER			0x0100
+#define	BCCK_PREAMBLE_DETECT		0x800000
+#define	BCCK_FAST_FALSECCA          0x400000
+#define	BCCK_CH_ESTSTART            0x300000
+#define	BCCK_CCA_COUNT              0x080000
+#define	BCCK_CS_LIM			0x070000
+#define	BCCK_BIST_MODE              0x80000000
+#define	BCCK_CCAMASK			0x40000000
+#define	BCCK_TX_DAC_PHASE		0x4
+#define	BCCK_RX_ADC_PHASE		0x20000000
+#define	BCCKR_CP_MODE			0x0100
+#define	BCCK_TXDC_OFFSET		0xf0
+#define	BCCK_RXDC_OFFSET		0xf
+#define	BCCK_CCA_MODE			0xc000
+#define	BCCK_FALSECS_LIM		0x3f00
+#define	BCCK_CS_RATIO			0xc00000
+#define	BCCK_CORGBIT_SEL		0x300000
+#define	BCCK_PD_LIM			0x0f0000
+#define	BCCK_NEWCCA			0x80000000
+#define	BCCK_RXHP_OF_IG             0x8000
+#define	BCCK_RXIG			0x7f00
+#define	BCCK_LNA_POLARITY           0x800000
+#define	BCCK_RX1ST_BAIN             0x7f0000
+#define	BCCK_RF_EXTEND              0x20000000
+#define	BCCK_RXAGC_SATLEVEL		0x1f000000
+#define	BCCK_RXAGC_SATCOUNT		0xe0
+#define	BCCKRXRFSETTLE			0x1f
+#define	BCCK_FIXED_RXAGC		0x8000
+#define	BCCK_ANTENNA_POLARITY		0x2000
+#define	BCCK_TXFILTER_TYPE          0x0c00
+#define	BCCK_RXAGC_REPORTTYPE		0x0300
+#define	BCCK_RXDAGC_EN              0x80000000
+#define	BCCK_RXDAGC_PERIOD		0x20000000
+#define	BCCK_RXDAGC_SATLEVEL		0x1f000000
+#define	BCCK_TIMING_RECOVERY		0x800000
+#define	BCCK_TXC0			0x3f0000
+#define	BCCK_TXC1			0x3f000000
+#define	BCCK_TXC2			0x3f
+#define	BCCK_TXC3			0x3f00
+#define	BCCK_TXC4			0x3f0000
+#define	BCCK_TXC5			0x3f000000
+#define	BCCK_TXC6			0x3f
+#define	BCCK_TXC7			0x3f00
+#define	BCCK_DEBUGPORT			0xff0000
+#define	BCCK_DAC_DEBUG              0x0f000000
+#define	BCCK_FALSEALARM_ENABLE      0x8000
+#define	BCCK_FALSEALARM_READ        0x4000
+#define	BCCK_TRSSI			0x7f
+#define	BCCK_RXAGC_REPORT           0xfe
+#define	BCCK_RXREPORT_ANTSEL		0x80000000
+#define	BCCK_RXREPORT_MFOFF		0x40000000
+#define	BCCK_RXREPORT_SQLOSS		0x20000000
+#define	BCCK_RXREPORT_PKTLOSS		0x10000000
+#define	BCCK_RXREPORT_LOCKEDBIT		0x08000000
+#define	BCCK_RXREPORT_RATEERROR		0x04000000
+#define	BCCK_RXREPORT_RXRATE		0x03000000
+#define	BCCK_RXFA_COUNTER_LOWER     0xff
+#define	BCCK_RXFA_COUNTER_UPPER     0xff000000
+#define	BCCK_RXHPAGC_START          0xe000
+#define	BCCK_RXHPAGC_FINAL          0x1c00
+#define	BCCK_RXFALSEALARM_ENABLE    0x8000
+#define	BCCK_FACOUNTER_FREEZE       0x4000
+#define	BCCK_TXPATH_SEL             0x10000000
+#define	BCCK_DEFAULT_RXPATH         0xc000000
+#define	BCCK_OPTION_RXPATH          0x3000000
 
-#define	BNUM_OFSTF				0x3
-#define	BSHIFT_L				0xc0
-#define	BGI_TH					0xc
-#define	BRXPATH_A				0x1
-#define	BRXPATH_B				0x2
-#define	BRXPATH_C				0x4
-#define	BRXPATH_D				0x8
-#define	BTXPATH_A				0x1
-#define	BTXPATH_B				0x2
-#define	BTXPATH_C				0x4
-#define	BTXPATH_D				0x8
-#define	BTRSSI_FREQ				0x200
-#define	BADC_BACKOFF				0x3000
-#define	BDFIR_BACKOFF				0xc000
-#define	BTRSSI_LATCH_PHASE			0x10000
-#define	BRX_LDC_OFFSET				0xff
-#define	BRX_QDC_OFFSET				0xff00
-#define	BRX_DFIR_MODE				0x1800000
-#define	BRX_DCNF_TYPE				0xe000000
-#define	BRXIQIMB_A				0x3ff
-#define	BRXIQIMB_B				0xfc00
-#define	BRXIQIMB_C				0x3f0000
-#define	BRXIQIMB_D				0xffc00000
-#define	BDC_DC_NOTCH				0x60000
-#define	BRXNB_NOTCH				0x1f000000
-#define	BPD_TH					0xf
-#define	BPD_TH_OPT2				0xc000
-#define	BPWED_TH				0x700
-#define	BIFMF_WIN_L				0x800
-#define	BPD_OPTION				0x1000
-#define	BMF_WIN_L				0xe000
-#define	BBW_SEARCH_L				0x30000
-#define	BWIN_ENH_L				0xc0000
-#define	BBW_TH					0x700000
-#define	BED_TH2					0x3800000
-#define	BBW_OPTION				0x4000000
-#define	BRADIO_TH				0x18000000
-#define	BWINDOW_L				0xe0000000
-#define	BSBD_OPTION				0x1
-#define	BFRAME_TH				0x1c
-#define	BFS_OPTION				0x60
-#define	BDC_SLOPE_CHECK				0x80
-#define	BFGUARD_COUNTER_DC_L			0xe00
-#define	BFRAME_WEIGHT_SHORT			0x7000
-#define	BSUB_TUNE				0xe00000
-#define	BFRAME_DC_LENGTH			0xe000000
-#define	BSBD_START_OFFSET			0x30000000
-#define	BFRAME_TH_2				0x7
-#define	BFRAME_GI2_TH				0x38
-#define	BGI2_SYNC_EN				0x40
-#define	BSARCH_SHORT_EARLY			0x300
-#define	BSARCH_SHORT_LATE			0xc00
-#define	BSARCH_GI2_LATE				0x70000
-#define	BCFOANTSUM				0x1
-#define	BCFOACC					0x2
-#define	BCFOSTARTOFFSET				0xc
-#define	BCFOLOOPBACK				0x70
-#define	BCFOSUMWEIGHT				0x80
-#define	BDAGCENABLE				0x10000
-#define	BTXIQIMB_A				0x3ff
-#define	BTXIQIMB_B				0xfc00
-#define	BTXIQIMB_C				0x3f0000
-#define	BTXIQIMB_D				0xffc00000
-#define	BTXIDCOFFSET				0xff
-#define	BTXIQDCOFFSET				0xff00
-#define	BTXDFIRMODE				0x10000
-#define	BTXPESUDO_NOISEON			0x4000000
-#define	BTXPESUDO_NOISE_A			0xff
-#define	BTXPESUDO_NOISE_B			0xff00
-#define	BTXPESUDO_NOISE_C			0xff0000
-#define	BTXPESUDO_NOISE_D			0xff000000
-#define	BCCA_DROPOPTION				0x20000
-#define	BCCA_DROPTHRES				0xfff00000
-#define	BEDCCA_H				0xf
-#define	BEDCCA_L				0xf0
-#define	BLAMBDA_ED				0x300
-#define	BRX_INITIALGAIN				0x7f
-#define	BRX_ANTDIV_EN				0x80
-#define	BRX_AGC_ADDRESS_FOR_LNA			0x7f00
-#define	BRX_HIGHPOWER_FLOW			0x8000
-#define	BRX_AGC_FREEZE_THRES			0xc0000
-#define	BRX_FREEZESTEP_AGC1			0x300000
-#define	BRX_FREEZESTEP_AGC2			0xc00000
-#define	BRX_FREEZESTEP_AGC3			0x3000000
-#define	BRX_FREEZESTEP_AGC0			0xc000000
-#define	BRXRSSI_CMP_EN				0x10000000
-#define	BRXQUICK_AGCEN				0x20000000
-#define	BRXAGC_FREEZE_THRES_MODE		0x40000000
-#define	BRX_OVERFLOW_CHECKTYPE			0x80000000
-#define	BRX_AGCSHIFT				0x7f
-#define	BTRSW_TRI_ONLY				0x80
-#define	BPOWER_THRES				0x300
-#define	BRXAGC_EN				0x1
-#define	BRXAGC_TOGETHER_EN			0x2
-#define	BRXAGC_MIN				0x4
-#define	BRXHP_INI				0x7
-#define	BRXHP_TRLNA				0x70
-#define	BRXHP_RSSI				0x700
-#define	BRXHP_BBP1				0x7000
-#define	BRXHP_BBP2				0x70000
-#define	BRXHP_BBP3				0x700000
-#define	BRSSI_H					0x7f0000
-#define	BRSSI_GEN				0x7f000000
-#define	BRXSETTLE_TRSW				0x7
-#define	BRXSETTLE_LNA				0x38
-#define	BRXSETTLE_RSSI				0x1c0
-#define	BRXSETTLE_BBP				0xe00
-#define	BRXSETTLE_RXHP				0x7000
-#define	BRXSETTLE_ANTSW_RSSI			0x38000
-#define	BRXSETTLE_ANTSW				0xc0000
-#define	BRXPROCESS_TIME_DAGC			0x300000
-#define	BRXSETTLE_HSSI				0x400000
-#define	BRXPROCESS_TIME_BBPPW			0x800000
-#define	BRXANTENNA_POWER_SHIFT			0x3000000
-#define	BRSSI_TABLE_SELECT			0xc000000
-#define	BRXHP_FINAL				0x7000000
-#define	BRXHPSETTLE_BBP				0x7
-#define	BRXHTSETTLE_HSSI			0x8
-#define	BRXHTSETTLE_RXHP			0x70
-#define	BRXHTSETTLE_BBPPW			0x80
-#define	BRXHTSETTLE_IDLE			0x300
-#define	BRXHTSETTLE_RESERVED			0x1c00
-#define	BRXHT_RXHP_EN				0x8000
-#define	BRXAGC_FREEZE_THRES			0x30000
-#define	BRXAGC_TOGETHEREN			0x40000
-#define	BRXHTAGC_MIN				0x80000
-#define	BRXHTAGC_EN				0x100000
-#define	BRXHTDAGC_EN				0x200000
-#define	BRXHT_RXHP_BBP				0x1c00000
-#define	BRXHT_RXHP_FINAL			0xe0000000
-#define	BRXPW_RADIO_TH				0x3
-#define	BRXPW_RADIO_EN				0x4
-#define	BRXMF_HOLD				0x3800
-#define	BRXPD_DELAY_TH1				0x38
-#define	BRXPD_DELAY_TH2				0x1c0
-#define	BRXPD_DC_COUNT_MAX			0x600
-#define	BRXPD_DELAY_TH				0x8000
-#define	BRXPROCESS_DELAY			0xf0000
-#define	BRXSEARCHRANGE_GI2_EARLY		0x700000
-#define	BRXFRAME_FUARD_COUNTER_L		0x3800000
-#define	BRXSGI_GUARD_L				0xc000000
-#define	BRXSGI_SEARCH_L				0x30000000
-#define	BRXSGI_TH				0xc0000000
-#define	BDFSCNT0				0xff
-#define	BDFSCNT1				0xff00
-#define	BDFSFLAG				0xf0000
-#define	BMF_WEIGHT_SUM				0x300000
-#define	BMINIDX_TH				0x7f000000
-#define	BDAFORMAT				0x40000
-#define	BTXCH_EMU_ENABLE			0x01000000
-#define	BTRSW_ISOLATION_A			0x7f
-#define	BTRSW_ISOLATION_B			0x7f00
-#define	BTRSW_ISOLATION_C			0x7f0000
-#define	BTRSW_ISOLATION_D			0x7f000000
-#define	BEXT_LNA_GAIN				0x7c00
+#define	BNUM_OFSTF			0x3
+#define	BSHIFT_L			0xc0
+#define	BGI_TH				0xc
+#define	BRXPATH_A			0x1
+#define	BRXPATH_B			0x2
+#define	BRXPATH_C			0x4
+#define	BRXPATH_D			0x8
+#define	BTXPATH_A			0x1
+#define	BTXPATH_B			0x2
+#define	BTXPATH_C			0x4
+#define	BTXPATH_D			0x8
+#define	BTRSSI_FREQ			0x200
+#define	BADC_BACKOFF			0x3000
+#define	BDFIR_BACKOFF			0xc000
+#define	BTRSSI_LATCH_PHASE		0x10000
+#define	BRX_LDC_OFFSET			0xff
+#define	BRX_QDC_OFFSET			0xff00
+#define	BRX_DFIR_MODE			0x1800000
+#define	BRX_DCNF_TYPE			0xe000000
+#define	BRXIQIMB_A			0x3ff
+#define	BRXIQIMB_B			0xfc00
+#define	BRXIQIMB_C			0x3f0000
+#define	BRXIQIMB_D			0xffc00000
+#define	BDC_DC_NOTCH			0x60000
+#define	BRXNB_NOTCH			0x1f000000
+#define	BPD_TH				0xf
+#define	BPD_TH_OPT2			0xc000
+#define	BPWED_TH			0x700
+#define	BIFMF_WIN_L			0x800
+#define	BPD_OPTION			0x1000
+#define	BMF_WIN_L			0xe000
+#define	BBW_SEARCH_L			0x30000
+#define	BWIN_ENH_L			0xc0000
+#define	BBW_TH				0x700000
+#define	BED_TH2				0x3800000
+#define	BBW_OPTION			0x4000000
+#define	BRADIO_TH			0x18000000
+#define	BWINDOW_L			0xe0000000
+#define	BSBD_OPTION			0x1
+#define	BFRAME_TH			0x1c
+#define	BFS_OPTION			0x60
+#define	BDC_SLOPE_CHECK			0x80
+#define	BFGUARD_COUNTER_DC_L		0xe00
+#define	BFRAME_WEIGHT_SHORT		0x7000
+#define	BSUB_TUNE			0xe00000
+#define	BFRAME_DC_LENGTH		0xe000000
+#define	BSBD_START_OFFSET		0x30000000
+#define	BFRAME_TH_2			0x7
+#define	BFRAME_GI2_TH			0x38
+#define	BGI2_SYNC_EN			0x40
+#define	BSARCH_SHORT_EARLY		0x300
+#define	BSARCH_SHORT_LATE		0xc00
+#define	BSARCH_GI2_LATE			0x70000
+#define	BCFOANTSUM			0x1
+#define	BCFOACC				0x2
+#define	BCFOSTARTOFFSET			0xc
+#define	BCFOLOOPBACK			0x70
+#define	BCFOSUMWEIGHT			0x80
+#define	BDAGCENABLE			0x10000
+#define	BTXIQIMB_A			0x3ff
+#define	BTXIQIMB_b			0xfc00
+#define	BTXIQIMB_C			0x3f0000
+#define	BTXIQIMB_D			0xffc00000
+#define	BTXIDCOFFSET			0xff
+#define	BTXIQDCOFFSET			0xff00
+#define	BTXDFIRMODE			0x10000
+#define	BTXPESUDO_NOISEON		0x4000000
+#define	BTXPESUDO_NOISE_A		0xff
+#define	BTXPESUDO_NOISE_B		0xff00
+#define	BTXPESUDO_NOISE_C		0xff0000
+#define	BTXPESUDO_NOISE_D		0xff000000
+#define	BCCA_DROPOPTION			0x20000
+#define	BCCA_DROPTHRES			0xfff00000
+#define	BEDCCA_H			0xf
+#define	BEDCCA_L			0xf0
+#define	BLAMBDA_ED			0x300
+#define	BRX_INITIALGAIN			0x7f
+#define	BRX_ANTDIV_EN			0x80
+#define	BRX_AGC_ADDRESS_FOR_LNA     0x7f00
+#define	BRX_HIGHPOWER_FLOW		0x8000
+#define	BRX_AGC_FREEZE_THRES        0xc0000
+#define	BRX_FREEZESTEP_AGC1		0x300000
+#define	BRX_FREEZESTEP_AGC2		0xc00000
+#define	BRX_FREEZESTEP_AGC3		0x3000000
+#define	BRX_FREEZESTEP_AGC0		0xc000000
+#define	BRXRSSI_CMP_EN			0x10000000
+#define	BRXQUICK_AGCEN			0x20000000
+#define	BRXAGC_FREEZE_THRES_MODE    0x40000000
+#define	BRX_OVERFLOW_CHECKTYPE		0x80000000
+#define	BRX_AGCSHIFT			0x7f
+#define	BTRSW_TRI_ONLY			0x80
+#define	BPOWER_THRES			0x300
+#define	BRXAGC_EN			0x1
+#define	BRXAGC_TOGETHER_EN		0x2
+#define	BRXAGC_MIN			0x4
+#define	BRXHP_INI			0x7
+#define	BRXHP_TRLNA			0x70
+#define	BRXHP_RSSI			0x700
+#define	BRXHP_BBP1			0x7000
+#define	BRXHP_BBP2			0x70000
+#define	BRXHP_BBP3			0x700000
+#define	BRSSI_H				0x7f0000
+#define	BRSSI_GEN			0x7f000000
+#define	BRXSETTLE_TRSW			0x7
+#define	BRXSETTLE_LNA			0x38
+#define	BRXSETTLE_RSSI			0x1c0
+#define	BRXSETTLE_BBP			0xe00
+#define	BRXSETTLE_RXHP			0x7000
+#define	BRXSETTLE_ANTSW_RSSI		0x38000
+#define	BRXSETTLE_ANTSW			0xc0000
+#define	BRXPROCESS_TIME_DAGC		0x300000
+#define	BRXSETTLE_HSSI			0x400000
+#define	BRXPROCESS_TIME_BBPPW		0x800000
+#define	BRXANTENNA_POWER_SHIFT		0x3000000
+#define	BRSSI_TABLE_SELECT		0xc000000
+#define	BRXHP_FINAL			0x7000000
+#define	BRXHPSETTLE_BBP			0x7
+#define	BRXHTSETTLE_HSSI		0x8
+#define	BRXHTSETTLE_RXHP		0x70
+#define	BRXHTSETTLE_BBPPW		0x80
+#define	BRXHTSETTLE_IDLE		0x300
+#define	BRXHTSETTLE_RESERVED		0x1c00
+#define	BRXHT_RXHP_EN			0x8000
+#define	BRXAGC_FREEZE_THRES		0x30000
+#define	BRXAGC_TOGETHEREN		0x40000
+#define	BRXHTAGC_MIN			0x80000
+#define	BRXHTAGC_EN			0x100000
+#define	BRXHTDAGC_EN			0x200000
+#define	BRXHT_RXHP_BBP			0x1c00000
+#define	BRXHT_RXHP_FINAL		0xe0000000
+#define	BRXPW_RADIO_TH			0x3
+#define	BRXPW_RADIO_EN			0x4
+#define	BRXMF_HOLD			0x3800
+#define	BRXPD_DELAY_TH1			0x38
+#define	BRXPD_DELAY_TH2			0x1c0
+#define	BRXPD_DC_COUNT_MAX		0x600
+#define	BRXPD_DELAY_TH			0x8000
+#define	BRXPROCESS_DELAY		0xf0000
+#define	BRXSEARCHRANGE_GI2_EARLY	0x700000
+#define	BRXFRAME_FUARD_COUNTER_L	0x3800000
+#define	BRXSGI_GUARD_L			0xc000000
+#define	BRXSGI_SEARCH_L			0x30000000
+#define	BRXSGI_TH			0xc0000000
+#define	BDFSCNT0			0xff
+#define	BDFSCNT1			0xff00
+#define	BDFSFLAG			0xf0000
+#define	BMF_WEIGHT_SUM			0x300000
+#define	BMINIDX_TH			0x7f000000
+#define	BDAFORMAT			0x40000
+#define	BTXCH_EMU_ENABLE		0x01000000
+#define	BTRSW_ISOLATION_A		0x7f
+#define	BTRSW_ISOLATION_B		0x7f00
+#define	BTRSW_ISOLATION_C		0x7f0000
+#define	BTRSW_ISOLATION_D		0x7f000000
+#define	BEXT_LNA_GAIN			0x7c00
 
-#define	BSTBC_EN				0x4
-#define	BANTENNA_MAPPING			0x10
-#define	BNSS					0x20
-#define	BCFO_ANTSUM_ID				0x200
-#define	BPHY_COUNTER_RESET			0x8000000
-#define	BCFO_REPORT_GET				0x4000000
-#define	BOFDM_CONTINUE_TX			0x10000000
-#define	BOFDM_SINGLE_CARRIER			0x20000000
-#define	BOFDM_SINGLE_TONE			0x40000000
-#define	BHT_DETECT				0x100
-#define	BCFOEN					0x10000
-#define	BCFOVALUE				0xfff00000
-#define	BSIGTONE_RE				0x3f
-#define	BSIGTONE_IM				0x7f00
-#define	BCOUNTER_CCA				0xffff
-#define	BCOUNTER_PARITYFAIL			0xffff0000
-#define	BCOUNTER_RATEILLEGAL			0xffff
-#define	BCOUNTER_CRC8FAIL			0xffff0000
-#define	BCOUNTER_MCSNOSUPPORT			0xffff
-#define	BCOUNTER_FASTSYNC			0xffff
-#define	BSHORTCFO				0xfff
-#define	BSHORTCFOT_LENGTH			12
-#define	BSHORTCFOF_LENGTH			11
-#define	BLONGCFO				0x7ff
-#define	BLONGCFOT_LENGTH			11
-#define	BLONGCFOF_LENGTH			11
-#define	BTAILCFO				0x1fff
-#define	BTAILCFOT_LENGTH			13
-#define	BTAILCFOF_LENGTH			12
-#define	BNOISE_EN_PWDB				0xffff
-#define	BCC_POWER_DB				0xffff0000
-#define	BMOISE_PWDB				0xffff
-#define	BPOWERMEAST_LENGTH			10
-#define	BPOWERMEASF_LENGTH			3
-#define	BRX_HT_BW				0x1
-#define	BRXSC					0x6
-#define	BRX_HT					0x8
-#define	BNB_INTF_DET_ON				0x1
-#define	BINTF_WIN_LEN_CFG			0x30
-#define	BNB_INTF_TH_CFG				0x1c0
-#define	BRFGAIN					0x3f
-#define	BTABLESEL				0x40
-#define	BTRSW					0x80
-#define	BRXSNR_A				0xff
-#define	BRXSNR_B				0xff00
-#define	BRXSNR_C				0xff0000
-#define	BRXSNR_D				0xff000000
-#define	BSNR_EVMT_LENGTH			8
-#define	BSNR_EVMF_LENGTH			1
-#define	BCSI1ST					0xff
-#define	BCSI2ND					0xff00
-#define	BRXEVM1ST				0xff0000
-#define	BRXEVM2ND				0xff000000
-#define	BSIGEVM					0xff
-#define	BPWDB					0xff00
-#define	BSGIEN					0x10000
+#define	BSTBC_EN			0x4
+#define	BANTENNA_MAPPING		0x10
+#define	BNSS				0x20
+#define	BCFO_ANTSUM_ID              0x200
+#define	BPHY_COUNTER_RESET		0x8000000
+#define	BCFO_REPORT_GET			0x4000000
+#define	BOFDM_CONTINUE_TX		0x10000000
+#define	BOFDM_SINGLE_CARRIER		0x20000000
+#define	BOFDM_SINGLE_TONE		0x40000000
+#define	BHT_DETECT			0x100
+#define	BCFOEN				0x10000
+#define	BCFOVALUE			0xfff00000
+#define	BSIGTONE_RE			0x3f
+#define	BSIGTONE_IM			0x7f00
+#define	BCOUNTER_CCA			0xffff
+#define	BCOUNTER_PARITYFAIL		0xffff0000
+#define	BCOUNTER_RATEILLEGAL		0xffff
+#define	BCOUNTER_CRC8FAIL		0xffff0000
+#define	BCOUNTER_MCSNOSUPPORT		0xffff
+#define	BCOUNTER_FASTSYNC		0xffff
+#define	BSHORTCFO			0xfff
+#define	BSHORTCFOT_LENGTH		12
+#define	BSHORTCFOF_LENGTH		11
+#define	BLONGCFO			0x7ff
+#define	BLONGCFOT_LENGTH		11
+#define	BLONGCFOF_LENGTH		11
+#define	BTAILCFO			0x1fff
+#define	BTAILCFOT_LENGTH		13
+#define	BTAILCFOF_LENGTH		12
+#define	BNOISE_EN_PWDB			0xffff
+#define	BCC_POWER_DB			0xffff0000
+#define	BMOISE_PWDB			0xffff
+#define	BPOWERMEAST_LENGTH		10
+#define	BPOWERMEASF_LENGTH		3
+#define	BRX_HT_BW			0x1
+#define	BRXSC				0x6
+#define	BRX_HT				0x8
+#define	BNB_INTF_DET_ON			0x1
+#define	BINTF_WIN_LEN_CFG		0x30
+#define	BNB_INTF_TH_CFG			0x1c0
+#define	BRFGAIN				0x3f
+#define	BTABLESEL			0x40
+#define	BTRSW				0x80
+#define	BRXSNR_A			0xff
+#define	BRXSNR_B			0xff00
+#define	BRXSNR_C			0xff0000
+#define	BRXSNR_D			0xff000000
+#define	BSNR_EVMT_LENGTH		8
+#define	BSNR_EVMF_LENGTH		1
+#define	BCSI1ST				0xff
+#define	BCSI2ND				0xff00
+#define	BRXEVM1ST			0xff0000
+#define	BRXEVM2ND			0xff000000
+#define	BSIGEVM				0xff
+#define	BPWDB				0xff00
+#define	BSGIEN				0x10000
 
-#define	BSFACTOR_QMA1				0xf
-#define	BSFACTOR_QMA2				0xf0
-#define	BSFACTOR_QMA3				0xf00
-#define	BSFACTOR_QMA4				0xf000
-#define	BSFACTOR_QMA5				0xf0000
-#define	BSFACTOR_QMA6				0xf0000
-#define	BSFACTOR_QMA7				0xf00000
-#define	BSFACTOR_QMA8				0xf000000
-#define	BSFACTOR_QMA9				0xf0000000
-#define	BCSI_SCHEME				0x100000
+#define	BSFACTOR_QMA1			0xf
+#define	BSFACTOR_QMA2			0xf0
+#define	BSFACTOR_QMA3			0xf00
+#define	BSFACTOR_QMA4			0xf000
+#define	BSFACTOR_QMA5			0xf0000
+#define	BSFACTOR_QMA6			0xf0000
+#define	BSFACTOR_QMA7			0xf00000
+#define	BSFACTOR_QMA8			0xf000000
+#define	BSFACTOR_QMA9			0xf0000000
+#define	BCSI_SCHEME			0x100000
 
-#define	BNOISE_LVL_TOP_SET			0x3
-#define	BCHSMOOTH				0x4
-#define	BCHSMOOTH_CFG1				0x38
-#define	BCHSMOOTH_CFG2				0x1c0
-#define	BCHSMOOTH_CFG3				0xe00
-#define	BCHSMOOTH_CFG4				0x7000
-#define	BMRCMODE				0x800000
-#define	BTHEVMCFG				0x7000000
+#define	BNOISE_LVL_TOP_SET          0x3
+#define	BCHSMOOTH			0x4
+#define	BCHSMOOTH_CFG1			0x38
+#define	BCHSMOOTH_CFG2			0x1c0
+#define	BCHSMOOTH_CFG3			0xe00
+#define	BCHSMOOTH_CFG4			0x7000
+#define	BMRCMODE			0x800000
+#define	BTHEVMCFG			0x7000000
 
-#define	BLOOP_FIT_TYPE				0x1
-#define	BUPD_CFO				0x40
-#define	BUPD_CFO_OFFDATA			0x80
-#define	BADV_UPD_CFO				0x100
-#define	BADV_TIME_CTRL				0x800
-#define	BUPD_CLKO				0x1000
-#define	BFC					0x6000
-#define	BTRACKING_MODE				0x8000
-#define	BPHCMP_ENABLE				0x10000
-#define	BUPD_CLKO_LTF				0x20000
-#define	BCOM_CH_CFO				0x40000
-#define	BCSI_ESTI_MODE				0x80000
-#define	BADV_UPD_EQZ				0x100000
-#define	BUCHCFG					0x7000000
-#define	BUPDEQZ					0x8000000
+#define	BLOOP_FIT_TYPE			0x1
+#define	BUPD_CFO			0x40
+#define	BUPD_CFO_OFFDATA		0x80
+#define	BADV_UPD_CFO			0x100
+#define	BADV_TIME_CTRL			0x800
+#define	BUPD_CLKO			0x1000
+#define	BFC				0x6000
+#define	BTRACKING_MODE			0x8000
+#define	BPHCMP_ENABLE			0x10000
+#define	BUPD_CLKO_LTF			0x20000
+#define	BCOM_CH_CFO			0x40000
+#define	BCSI_ESTI_MODE			0x80000
+#define	BADV_UPD_EQZ			0x100000
+#define	BUCHCFG				0x7000000
+#define	BUPDEQZ				0x8000000
 
-#define	BRX_PESUDO_NOISE_ON			0x20000000
-#define	BRX_PESUDO_NOISE_A			0xff
-#define	BRX_PESUDO_NOISE_B			0xff00
-#define	BRX_PESUDO_NOISE_C			0xff0000
-#define	BRX_PESUDO_NOISE_D			0xff000000
-#define	BRX_PESUDO_NOISESTATE_A			0xffff
-#define	BRX_PESUDO_NOISESTATE_B			0xffff0000
-#define	BRX_PESUDO_NOISESTATE_C			0xffff
-#define	BRX_PESUDO_NOISESTATE_D			0xffff0000
+#define	BRX_PESUDO_NOISE_ON         0x20000000
+#define	BRX_PESUDO_NOISE_A		0xff
+#define	BRX_PESUDO_NOISE_B		0xff00
+#define	BRX_PESUDO_NOISE_C		0xff0000
+#define	BRX_PESUDO_NOISE_D		0xff000000
+#define	BRX_PESUDO_NOISESTATE_A     0xffff
+#define	BRX_PESUDO_NOISESTATE_B     0xffff0000
+#define	BRX_PESUDO_NOISESTATE_C     0xffff
+#define	BRX_PESUDO_NOISESTATE_D     0xffff0000
 
-#define	BZEBRA1_HSSIENABLE			0x8
-#define	BZEBRA1_TRXCONTROL			0xc00
-#define	BZEBRA1_TRXGAINSETTING			0x07f
-#define	BZEBRA1_RXCOUNTER			0xc00
-#define	BZEBRA1_TXCHANGEPUMP			0x38
-#define	BZEBRA1_RXCHANGEPUMP			0x7
-#define	BZEBRA1_CHANNEL_NUM			0xf80
-#define	BZEBRA1_TXLPFBW				0x400
-#define	BZEBRA1_RXLPFBW				0x600
+#define	BZEBRA1_HSSIENABLE		0x8
+#define	BZEBRA1_TRXCONTROL		0xc00
+#define	BZEBRA1_TRXGAINSETTING		0x07f
+#define	BZEBRA1_RXCOUNTER		0xc00
+#define	BZEBRA1_TXCHANGEPUMP		0x38
+#define	BZEBRA1_RXCHANGEPUMP		0x7
+#define	BZEBRA1_CHANNEL_NUM		0xf80
+#define	BZEBRA1_TXLPFBW			0x400
+#define	BZEBRA1_RXLPFBW			0x600
 
-#define	BRTL8256REG_MODE_CTRL1			0x100
-#define	BRTL8256REG_MODE_CTRL0			0x40
-#define	BRTL8256REG_TXLPFBW			0x18
-#define	BRTL8256REG_RXLPFBW			0x600
+#define	BRTL8256REG_MODE_CTRL1      0x100
+#define	BRTL8256REG_MODE_CTRL0      0x40
+#define	BRTL8256REG_TXLPFBW         0x18
+#define	BRTL8256REG_RXLPFBW         0x600
 
-#define	BRTL8258_TXLPFBW			0xc
-#define	BRTL8258_RXLPFBW			0xc00
-#define	BRTL8258_RSSILPFBW			0xc0
+#define	BRTL8258_TXLPFBW		0xc
+#define	BRTL8258_RXLPFBW		0xc00
+#define	BRTL8258_RSSILPFBW		0xc0
 
-#define	BBYTE0					0x1
-#define	BBYTE1					0x2
-#define	BBYTE2					0x4
-#define	BBYTE3					0x8
-#define	BWORD0					0x3
-#define	BWORD1					0xc
-#define	BWORD					0xf
+#define	BBYTE0				0x1
+#define	BBYTE1				0x2
+#define	BBYTE2				0x4
+#define	BBYTE3				0x8
+#define	BWORD0				0x3
+#define	BWORD1				0xc
+#define	BWORD				0xf
 
-#define	BENABLE					0x1
-#define	BDISABLE				0x0
+#define	MASKBYTE0			0xff
+#define	MASKBYTE1			0xff00
+#define	MASKBYTE2			0xff0000
+#define	MASKBYTE3			0xff000000
+#define	MASKHWORD			0xffff0000
+#define	MASKLWORD			0x0000ffff
+#define	MASKDWORD					0xffffffff
+#define	MASK12BITS					0xfff
+#define	MASKH4BITS					0xf0000000
+#define MASKOFDM_D					0xffc00000
+#define	MASKCCK						0x3f3f3f3f
 
-#define	LEFT_ANTENNA				0x0
-#define	RIGHT_ANTENNA				0x1
+#define	MASK4BITS			0x0f
+#define	MASK20BITS			0xfffff
+#define RFREG_OFFSET_MASK			0xfffff
 
-#define	TCHECK_TXSTATUS				500
-#define	TUPDATE_RXCOUNTER			100
+#define	BENABLE				0x1
+#define	BDISABLE			0x0
 
-#define	REG_UN_USED_REGISTER			0x01bf
+#define	LEFT_ANTENNA			0x0
+#define	RIGHT_ANTENNA			0x1
+
+#define	TCHECK_TXSTATUS			500
+#define	TUPDATE_RXCOUNTER		100
+
+#define	REG_UN_used_register		0x01bf
 
 /* WOL bit information */
 #define	HAL92C_WOL_PTK_UPDATE_EVENT		BIT(0)
 #define	HAL92C_WOL_GTK_UPDATE_EVENT		BIT(1)
 #define	HAL92C_WOL_DISASSOC_EVENT		BIT(2)
 #define	HAL92C_WOL_DEAUTH_EVENT			BIT(3)
-#define	HAL92C_WOL_FW_DISCONNECT_EVENT		BIT(4)
+#define	HAL92C_WOL_FW_DISCONNECT_EVENT	BIT(4)
 
 #define		WOL_REASON_PTK_UPDATE		BIT(0)
 #define		WOL_REASON_GTK_UPDATE		BIT(1)
-#define		WOL_REASON_DISASSOC		BIT(2)
-#define		WOL_REASON_DEAUTH		BIT(3)
+#define		WOL_REASON_DISASSOC			BIT(2)
+#define		WOL_REASON_DEAUTH			BIT(3)
 #define		WOL_REASON_FW_DISCONNECT	BIT(4)
-
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/rf.c b/drivers/net/wireless/rtlwifi/rtl8188ee/rf.c
index 4faafdb..40893ce 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/rf.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -34,6 +30,8 @@
 #include "rf.h"
 #include "dm.h"
 
+static bool _rtl88e_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
+
 void rtl88e_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -60,7 +58,7 @@
 }
 
 void rtl88e_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
-				       u8 *plevel)
+				       u8 *ppowerlevel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -82,32 +80,36 @@
 
 		if (turbo_scanoff) {
 			for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
-				tx_agc[idx1] = plevel[idx1] |
-					       (plevel[idx1] << 8) |
-					       (plevel[idx1] << 16) |
-					       (plevel[idx1] << 24);
+				tx_agc[idx1] = ppowerlevel[idx1] |
+				    (ppowerlevel[idx1] << 8) |
+				    (ppowerlevel[idx1] << 16) |
+				    (ppowerlevel[idx1] << 24);
 			}
 		}
 	} else {
 		for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
-			tx_agc[idx1] = plevel[idx1] | (plevel[idx1] << 8) |
-				       (plevel[idx1] << 16) |
-				       (plevel[idx1] << 24);
+			tx_agc[idx1] = ppowerlevel[idx1] |
+			    (ppowerlevel[idx1] << 8) |
+			    (ppowerlevel[idx1] << 16) |
+			    (ppowerlevel[idx1] << 24);
 		}
 
 		if (rtlefuse->eeprom_regulatory == 0) {
-			tmpval = (rtlphy->mcs_offset[0][6]) +
-				 (rtlphy->mcs_offset[0][7] << 8);
+			tmpval =
+			    (rtlphy->mcs_txpwrlevel_origoffset[0][6]) +
+			    (rtlphy->mcs_txpwrlevel_origoffset[0][7] <<
+			     8);
 			tx_agc[RF90_PATH_A] += tmpval;
 
-			tmpval = (rtlphy->mcs_offset[0][14]) +
-				 (rtlphy->mcs_offset[0][15] << 24);
+			tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) +
+			    (rtlphy->mcs_txpwrlevel_origoffset[0][15] <<
+			     24);
 			tx_agc[RF90_PATH_B] += tmpval;
 		}
 	}
 
 	for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
-		ptr = (u8 *)(&(tx_agc[idx1]));
+		ptr = (u8 *)(&tx_agc[idx1]);
 		for (idx2 = 0; idx2 < 4; idx2++) {
 			if (*ptr > RF6052_MAX_TX_PWR)
 				*ptr = RF6052_MAX_TX_PWR;
@@ -127,10 +129,12 @@
 
 	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 		"CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
-		RTXAGC_A_CCK1_MCS32);
+		 RTXAGC_A_CCK1_MCS32);
 
 	tmpval = tx_agc[RF90_PATH_A] >> 8;
 
+	/*tmpval = tmpval & 0xff00ffff;*/
+
 	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
 
 	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
@@ -153,148 +157,180 @@
 }
 
 static void rtl88e_phy_get_power_base(struct ieee80211_hw *hw,
-				      u8 *pwrlvlofdm, u8 *pwrlvlbw20,
-				      u8 *pwrlvlbw40, u8 channel,
+				      u8 *ppowerlevel_ofdm,
+				      u8 *ppowerlevel_bw20,
+				      u8 *ppowerlevel_bw40, u8 channel,
 				      u32 *ofdmbase, u32 *mcsbase)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	u32 base0, base1;
+	u32 powerbase0, powerbase1;
 	u8 i, powerlevel[2];
 
 	for (i = 0; i < 2; i++) {
-		base0 = pwrlvlofdm[i];
+		powerbase0 = ppowerlevel_ofdm[i];
 
-		base0 = (base0 << 24) | (base0 << 16) |
-			     (base0 << 8) | base0;
-		*(ofdmbase + i) = base0;
+		powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) |
+		    (powerbase0 << 8) | powerbase0;
+		*(ofdmbase + i) = powerbase0;
 		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
-			"[OFDM power base index rf(%c) = 0x%x]\n",
-			((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
+			" [OFDM power base index rf(%c) = 0x%x]\n",
+			 ((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
 	}
 
 	for (i = 0; i < 2; i++) {
 		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20)
-			powerlevel[i] = pwrlvlbw20[i];
+			powerlevel[i] = ppowerlevel_bw20[i];
 		else
-			powerlevel[i] = pwrlvlbw40[i];
-		base1 = powerlevel[i];
-		base1 = (base1 << 24) |
-		    (base1 << 16) | (base1 << 8) | base1;
+			powerlevel[i] = ppowerlevel_bw40[i];
 
-		*(mcsbase + i) = base1;
+		powerbase1 = powerlevel[i];
+		powerbase1 = (powerbase1 << 24) |
+		    (powerbase1 << 16) | (powerbase1 << 8) | powerbase1;
+
+		*(mcsbase + i) = powerbase1;
 
 		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
-			"[MCS power base index rf(%c) = 0x%x]\n",
-			((i == 0) ? 'A' : 'B'), *(mcsbase + i));
+			" [MCS power base index rf(%c) = 0x%x]\n",
+			 ((i == 0) ? 'A' : 'B'), *(mcsbase + i));
 	}
 }
 
-static void get_txpwr_by_reg(struct ieee80211_hw *hw, u8 chan, u8 index,
-			     u32 *base0, u32 *base1, u32 *outval)
+static void _rtl88e_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
+						       u8 channel, u8 index,
+						       u32 *powerbase0,
+						       u32 *powerbase1,
+						       u32 *p_outwriteval)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
-	u8 i, chg = 0, pwr_lim[4], pwr_diff = 0, cust_pwr_dif;
-	u32 writeval, cust_lim, rf, tmp;
-	u8 ch = chan - 1;
-	u8 j;
+	u8 i, chnlgroup = 0, pwr_diff_limit[4], pwr_diff = 0, customer_pwr_diff;
+	u32 writeval, customer_limit, rf;
 
 	for (rf = 0; rf < 2; rf++) {
-		j = index + (rf ? 8 : 0);
-		tmp = ((index < 2) ? base0[rf] : base1[rf]);
 		switch (rtlefuse->eeprom_regulatory) {
 		case 0:
-			chg = 0;
+			chnlgroup = 0;
 
-			writeval = rtlphy->mcs_offset[chg][j] + tmp;
+			writeval =
+			    rtlphy->mcs_txpwrlevel_origoffset
+				[chnlgroup][index + (rf ? 8 : 0)]
+			    + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 
 			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
-				"RTK better performance, "
-				"writeval(%c) = 0x%x\n",
+				"RTK better performance, writeval(%c) = 0x%x\n",
 				((rf == 0) ? 'A' : 'B'), writeval);
 			break;
 		case 1:
 			if (rtlphy->pwrgroup_cnt == 1) {
-				chg = 0;
+				chnlgroup = 0;
 			} else {
-				chg = chan / 3;
-				if (chan == 14)
-					chg = 5;
+				if (channel < 3)
+					chnlgroup = 0;
+				else if (channel < 6)
+					chnlgroup = 1;
+				else if (channel < 9)
+					chnlgroup = 2;
+				else if (channel < 12)
+					chnlgroup = 3;
+				else if (channel < 14)
+					chnlgroup = 4;
+				else if (channel == 14)
+					chnlgroup = 5;
 			}
-			writeval = rtlphy->mcs_offset[chg][j] + tmp;
+
+			writeval =
+			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
+			    [index + (rf ? 8 : 0)] + ((index < 2) ?
+						      powerbase0[rf] :
+						      powerbase1[rf]);
 
 			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 				"Realtek regulatory, 20MHz, writeval(%c) = 0x%x\n",
 				 ((rf == 0) ? 'A' : 'B'), writeval);
+
 			break;
 		case 2:
-			writeval = ((index < 2) ? base0[rf] : base1[rf]);
+			writeval =
+			    ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 
 			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 				"Better regulatory, writeval(%c) = 0x%x\n",
-				 ((rf == 0) ? 'A' : 'B'), writeval);
+				((rf == 0) ? 'A' : 'B'), writeval);
 			break;
 		case 3:
-			chg = 0;
+			chnlgroup = 0;
 
 			if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
 				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 					"customer's limit, 40MHz rf(%c) = 0x%x\n",
-					 ((rf == 0) ? 'A' : 'B'),
-					 rtlefuse->pwrgroup_ht40[rf][ch]);
+					((rf == 0) ? 'A' : 'B'),
+					rtlefuse->pwrgroup_ht40[rf][channel -
+								    1]);
 			} else {
 				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 					"customer's limit, 20MHz rf(%c) = 0x%x\n",
-					 ((rf == 0) ? 'A' : 'B'),
-					 rtlefuse->pwrgroup_ht20[rf][ch]);
+					((rf == 0) ? 'A' : 'B'),
+					rtlefuse->pwrgroup_ht20[rf][channel -
+								    1]);
 			}
 
 			if (index < 2)
-				pwr_diff = rtlefuse->txpwr_legacyhtdiff[rf][ch];
+				pwr_diff =
+				   rtlefuse->txpwr_legacyhtdiff[rf][channel-1];
 			else if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20)
-				pwr_diff = rtlefuse->txpwr_ht20diff[rf][ch];
+				pwr_diff =
+					rtlefuse->txpwr_ht20diff[rf][channel-1];
 
 			if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40)
-				cust_pwr_dif = rtlefuse->pwrgroup_ht40[rf][ch];
+				customer_pwr_diff =
+					rtlefuse->pwrgroup_ht40[rf][channel-1];
 			else
-				cust_pwr_dif = rtlefuse->pwrgroup_ht20[rf][ch];
+				customer_pwr_diff =
+					rtlefuse->pwrgroup_ht20[rf][channel-1];
 
-			if (pwr_diff > cust_pwr_dif)
+			if (pwr_diff > customer_pwr_diff)
 				pwr_diff = 0;
 			else
-				pwr_diff = cust_pwr_dif - pwr_diff;
+				pwr_diff = customer_pwr_diff - pwr_diff;
 
 			for (i = 0; i < 4; i++) {
-				pwr_lim[i] = (u8)((rtlphy->mcs_offset[chg][j] &
-					     (0x7f << (i * 8))) >> (i * 8));
+				pwr_diff_limit[i] =
+				    (u8)((rtlphy->mcs_txpwrlevel_origoffset
+					  [chnlgroup][index +
+					  (rf ? 8 : 0)] & (0x7f <<
+					  (i * 8))) >> (i * 8));
 
-				if (pwr_lim[i] > pwr_diff)
-					pwr_lim[i] = pwr_diff;
+				if (pwr_diff_limit[i] > pwr_diff)
+					pwr_diff_limit[i] = pwr_diff;
 			}
 
-			cust_lim = (pwr_lim[3] << 24) | (pwr_lim[2] << 16) |
-				   (pwr_lim[1] << 8) | (pwr_lim[0]);
+			customer_limit = (pwr_diff_limit[3] << 24) |
+			    (pwr_diff_limit[2] << 16) |
+			    (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]);
 
 			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 				"Customer's limit rf(%c) = 0x%x\n",
-				((rf == 0) ? 'A' : 'B'), cust_lim);
+				 ((rf == 0) ? 'A' : 'B'), customer_limit);
 
-			writeval = cust_lim + tmp;
+			writeval = customer_limit +
+			    ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 
 			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
-				"Customer, writeval rf(%c) = 0x%x\n",
-				((rf == 0) ? 'A' : 'B'), writeval);
+				"Customer, writeval rf(%c)= 0x%x\n",
+				 ((rf == 0) ? 'A' : 'B'), writeval);
 			break;
 		default:
-			chg = 0;
-			writeval = rtlphy->mcs_offset[chg][j] + tmp;
+			chnlgroup = 0;
+			writeval =
+			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
+			    [index + (rf ? 8 : 0)]
+			    + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 
 			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
-				"RTK better performance, writeval "
-				"rf(%c) = 0x%x\n",
-				((rf == 0) ? 'A' : 'B'), writeval);
+				"RTK better performance, writeval rf(%c) = 0x%x\n",
+				 ((rf == 0) ? 'A' : 'B'), writeval);
 			break;
 		}
 
@@ -302,12 +338,13 @@
 			writeval = writeval - 0x06060606;
 		else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
 			 TXHIGHPWRLEVEL_BT2)
-			writeval -= 0x0c0c0c0c;
-		*(outval + rf) = writeval;
+			writeval = writeval - 0x0c0c0c0c;
+		*(p_outwriteval + rf) = writeval;
 	}
 }
 
-static void write_ofdm_pwr(struct ieee80211_hw *hw, u8 index, u32 *pvalue)
+static void _rtl88e_write_ofdm_power_reg(struct ieee80211_hw *hw,
+					 u8 index, u32 *value)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u16 regoffset_a[6] = {
@@ -325,16 +362,16 @@
 	u16 regoffset;
 
 	for (rf = 0; rf < 2; rf++) {
-		writeval = pvalue[rf];
+		writeval = value[rf];
 		for (i = 0; i < 4; i++) {
-			pwr_val[i] = (u8) ((writeval & (0x7f <<
-				     (i * 8))) >> (i * 8));
+			pwr_val[i] = (u8)((writeval & (0x7f <<
+					   (i * 8))) >> (i * 8));
 
 			if (pwr_val[i] > RF6052_MAX_TX_PWR)
 				pwr_val[i] = RF6052_MAX_TX_PWR;
 		}
 		writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
-			   (pwr_val[1] << 8) | pwr_val[0];
+		    (pwr_val[1] << 8) | pwr_val[0];
 
 		if (rf == 0)
 			regoffset = regoffset_a[index];
@@ -348,24 +385,27 @@
 }
 
 void rtl88e_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
-					u8 *pwrlvlofdm,
-					u8 *pwrlvlbw20,
-					u8 *pwrlvlbw40, u8 chan)
+					u8 *ppowerlevel_ofdm,
+					u8 *ppowerlevel_bw20,
+					u8 *ppowerlevel_bw40, u8 channel)
 {
-	u32 writeval[2], base0[2], base1[2];
+	u32 writeval[2], powerbase0[2], powerbase1[2];
 	u8 index;
 	u8 direction;
 	u32 pwrtrac_value;
 
-	rtl88e_phy_get_power_base(hw, pwrlvlofdm, pwrlvlbw20,
-				  pwrlvlbw40, chan, &base0[0],
-				  &base1[0]);
+	rtl88e_phy_get_power_base(hw, ppowerlevel_ofdm,
+				  ppowerlevel_bw20, ppowerlevel_bw40,
+				  channel, &powerbase0[0], &powerbase1[0]);
 
 	rtl88e_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
 
 	for (index = 0; index < 6; index++) {
-		get_txpwr_by_reg(hw, chan, index, &base0[0], &base1[0],
-				 &writeval[0]);
+		_rtl88e_get_txpower_writeval_by_regulatory(hw,
+							   channel, index,
+							   &powerbase0[0],
+							   &powerbase1[0],
+							   &writeval[0]);
 		if (direction == 1) {
 			writeval[0] += pwrtrac_value;
 			writeval[1] += pwrtrac_value;
@@ -373,15 +413,28 @@
 			writeval[0] -= pwrtrac_value;
 			writeval[1] -= pwrtrac_value;
 		}
-		write_ofdm_pwr(hw, index, &writeval[0]);
+		_rtl88e_write_ofdm_power_reg(hw, index, &writeval[0]);
 	}
 }
 
-static bool rf6052_conf_para(struct ieee80211_hw *hw)
+bool rtl88e_phy_rf6052_config(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	u32 u4val = 0;
+
+	if (rtlphy->rf_type == RF_1T1R)
+		rtlphy->num_total_rfpath = 1;
+	else
+		rtlphy->num_total_rfpath = 2;
+
+	return _rtl88e_phy_rf6052_config_parafile(hw);
+}
+
+static bool _rtl88e_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u32 u4_regvalue = 0;
 	u8 rfpath;
 	bool rtstatus = true;
 	struct bb_reg_def *pphyreg;
@@ -392,12 +445,12 @@
 		switch (rfpath) {
 		case RF90_PATH_A:
 		case RF90_PATH_C:
-			u4val = rtl_get_bbreg(hw, pphyreg->rfintfs,
+			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
 						    BRFSI_RFENV);
 			break;
 		case RF90_PATH_B:
 		case RF90_PATH_D:
-			u4val = rtl_get_bbreg(hw, pphyreg->rfintfs,
+			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
 						    BRFSI_RFENV << 16);
 			break;
 		}
@@ -418,11 +471,11 @@
 		switch (rfpath) {
 		case RF90_PATH_A:
 			rtstatus = rtl88e_phy_config_rf_with_headerfile(hw,
-					(enum radio_path)rfpath);
+						(enum radio_path)rfpath);
 			break;
 		case RF90_PATH_B:
 			rtstatus = rtl88e_phy_config_rf_with_headerfile(hw,
-					(enum radio_path)rfpath);
+						(enum radio_path)rfpath);
 			break;
 		case RF90_PATH_C:
 			break;
@@ -433,12 +486,13 @@
 		switch (rfpath) {
 		case RF90_PATH_A:
 		case RF90_PATH_C:
-			rtl_set_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV, u4val);
+			rtl_set_bbreg(hw, pphyreg->rfintfs,
+				      BRFSI_RFENV, u4_regvalue);
 			break;
 		case RF90_PATH_B:
 		case RF90_PATH_D:
-			rtl_set_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV << 16,
-				      u4val);
+			rtl_set_bbreg(hw, pphyreg->rfintfs,
+				      BRFSI_RFENV << 16, u4_regvalue);
 			break;
 		}
 
@@ -447,21 +501,9 @@
 				 "Radio[%d] Fail!!", rfpath);
 			return false;
 		}
+
 	}
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
 	return rtstatus;
 }
-
-bool rtl88e_phy_rf6052_config(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-
-	if (rtlphy->rf_type == RF_1T1R)
-		rtlphy->num_total_rfpath = 1;
-	else
-		rtlphy->num_total_rfpath = 2;
-
-	return rf6052_conf_para(hw);
-}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/rf.h b/drivers/net/wireless/rtlwifi/rtl8188ee/rf.h
index a39a2a3..5c1472d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/rf.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/rf.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -40,7 +36,8 @@
 void rtl88e_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
 					u8 *ppowerlevel_ofdm,
 					u8 *ppowerlevel_bw20,
-					u8 *ppowerlevel_bw40, u8 channel);
+					u8 *ppowerlevel_bw40,
+					u8 channel);
 bool rtl88e_phy_rf6052_config(struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
index 631b690..1134412 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,7 +26,6 @@
 #include "../wifi.h"
 #include "../core.h"
 #include "../pci.h"
-#include "../base.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
@@ -122,7 +117,7 @@
 				  0);
 
 	rtlpci->irq_mask[0] =
-				(u32) (IMR_PSTIMEOUT	|
+				(u32)(IMR_PSTIMEOUT	|
 				IMR_HSISR_IND_ON_INT	|
 				IMR_C2HCMD		|
 				IMR_HIGHDOK		|
@@ -143,6 +138,8 @@
 	rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
 	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
 	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+	if (rtlpriv->cfg->mod_params->disable_watchdog)
+		pr_info("watchdog disabled\n");
 	if (!rtlpriv->psc.inactiveps)
 		pr_info("rtl8188ee: Power Save off (module option)\n");
 	if (!rtlpriv->psc.fwctrl_lps)
@@ -162,7 +159,7 @@
 		rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
 
 	/* for firmware buf */
-	rtlpriv->rtlhal.pfirmware = vmalloc(0x8000);
+	rtlpriv->rtlhal.pfirmware = vzalloc(0x8000);
 	if (!rtlpriv->rtlhal.pfirmware) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 "Can't alloc buffer for fw.\n");
@@ -199,7 +196,7 @@
 	init_timer(&rtlpriv->works.fast_antenna_training_timer);
 	setup_timer(&rtlpriv->works.fast_antenna_training_timer,
 		    rtl88e_dm_fast_antenna_training_callback,
-		    (unsigned long)hw);
+			(unsigned long)hw);
 	return err;
 }
 
@@ -218,6 +215,12 @@
 	del_timer_sync(&rtlpriv->works.fast_antenna_training_timer);
 }
 
+/* get bt coexist status */
+bool rtl88e_get_btc_status(void)
+{
+	return false;
+}
+
 static struct rtl_hal_ops rtl8188ee_hal_ops = {
 	.init_sw_vars = rtl88e_init_sw_vars,
 	.deinit_sw_vars = rtl88e_deinit_sw_vars,
@@ -246,11 +249,12 @@
 	.set_bw_mode = rtl88e_phy_set_bw_mode,
 	.switch_channel = rtl88e_phy_sw_chnl,
 	.dm_watchdog = rtl88e_dm_watchdog,
-	.scan_operation_backup = rtl_phy_scan_operation_backup,
+	.scan_operation_backup = rtl88e_phy_scan_operation_backup,
 	.set_rf_power_state = rtl88e_phy_set_rf_power_state,
 	.led_control = rtl88ee_led_control,
 	.set_desc = rtl88ee_set_desc,
 	.get_desc = rtl88ee_get_desc,
+	.is_tx_desc_closed = rtl88ee_is_tx_desc_closed,
 	.tx_polling = rtl88ee_tx_polling,
 	.enable_hw_sec = rtl88ee_enable_hw_security_config,
 	.set_key = rtl88ee_set_key,
@@ -259,14 +263,17 @@
 	.set_bbreg = rtl88e_phy_set_bb_reg,
 	.get_rfreg = rtl88e_phy_query_rf_reg,
 	.set_rfreg = rtl88e_phy_set_rf_reg,
+	.get_btc_status = rtl88e_get_btc_status,
+	.rx_command_packet = rtl88ee_rx_command_packet,
+
 };
 
 static struct rtl_mod_params rtl88ee_mod_params = {
 	.sw_crypto = false,
-	.inactiveps = true,
+	.inactiveps = false,
 	.swctrl_lps = false,
-	.fwctrl_lps = true,
-	.msi_support = false,
+	.fwctrl_lps = false,
+	.msi_support = true,
 	.debug = DBG_EMERG,
 };
 
@@ -274,6 +281,7 @@
 	.bar_id = 2,
 	.write_readback = true,
 	.name = "rtl88e_pci",
+	.fw_name = "rtlwifi/rtl8188efw.bin",
 	.ops = &rtl8188ee_hal_ops,
 	.mod_params = &rtl88ee_mod_params,
 
@@ -285,6 +293,9 @@
 	.maps[MAC_RCR_ACRC32] = ACRC32,
 	.maps[MAC_RCR_ACF] = ACF,
 	.maps[MAC_RCR_AAP] = AAP,
+	.maps[MAC_HIMR] = REG_HIMR,
+	.maps[MAC_HIMRE] = REG_HIMRE,
+	.maps[MAC_HSISR] = REG_HSISR,
 
 	.maps[EFUSE_ACCESS] = REG_EFUSE_ACCESS,
 
@@ -345,6 +356,7 @@
 	.maps[RTL_IMR_VIDOK] = IMR_VIDOK,
 	.maps[RTL_IMR_VODOK] = IMR_VODOK,
 	.maps[RTL_IMR_ROK] = IMR_ROK,
+	.maps[RTL_IMR_HSISR_IND] = IMR_HSISR_IND_ON_INT,
 	.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNDMAINT0 | IMR_TBDOK | IMR_TBDER),
 
 	.maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
@@ -364,7 +376,7 @@
 	.maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
 };
 
-static const struct pci_device_id rtl88ee_pci_ids[] = {
+static struct pci_device_id rtl88ee_pci_ids[] = {
 	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8179, rtl88ee_hal_cfg)},
 	{},
 };
@@ -384,12 +396,15 @@
 module_param_named(swlps, rtl88ee_mod_params.swctrl_lps, bool, 0444);
 module_param_named(fwlps, rtl88ee_mod_params.fwctrl_lps, bool, 0444);
 module_param_named(msi, rtl88ee_mod_params.msi_support, bool, 0444);
+module_param_named(disable_watchdog, rtl88ee_mod_params.disable_watchdog,
+		   bool, 0444);
 MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
 MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
 MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
 MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
-MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 0)\n");
+MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 1)\n");
 MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n");
 
 static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/sw.h b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.h
index 85e02b3..22398c3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/sw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -32,5 +28,7 @@
 
 int rtl88e_init_sw_vars(struct ieee80211_hw *hw);
 void rtl88e_deinit_sw_vars(struct ieee80211_hw *hw);
+bool rtl88e_get_btc_status(void);
+
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/table.c b/drivers/net/wireless/rtlwifi/rtl8188ee/table.c
index fad373f..68bcb7f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/table.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/table.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,7 +26,6 @@
  *****************************************************************************/
 
 #include "table.h"
-
 u32 RTL8188EEPHY_REG_1TARRAY[] = {
 		0x800, 0x80040000,
 		0x804, 0x00000003,
@@ -640,4 +635,5 @@
 		0xC78, 0x407D0001,
 		0xC78, 0x407E0001,
 		0xC78, 0x407F0001,
+
 };
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/table.h b/drivers/net/wireless/rtlwifi/rtl8188ee/table.h
index c1218e8..403c4dd 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/table.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/table.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -35,13 +31,13 @@
 #include <linux/types.h>
 #define  RTL8188EEPHY_REG_1TARRAYLEN	382
 extern u32 RTL8188EEPHY_REG_1TARRAY[];
-#define RTL8188EEPHY_REG_ARRAY_PGLEN	264
+#define RTL8188EEPHY_REG_ARRAY_PGLEN 264
 extern u32 RTL8188EEPHY_REG_ARRAY_PG[];
-#define	RTL8188EE_RADIOA_1TARRAYLEN	190
+#define	RTL8188EE_RADIOA_1TARRAYLEN 190
 extern u32 RTL8188EE_RADIOA_1TARRAY[];
-#define RTL8188EEMAC_1T_ARRAYLEN	180
+#define RTL8188EEMAC_1T_ARRAYLEN  180
 extern u32 RTL8188EEMAC_1T_ARRAY[];
-#define RTL8188EEAGCTAB_1TARRAYLEN	256
+#define RTL8188EEAGCTAB_1TARRAYLEN 256
 extern u32 RTL8188EEAGCTAB_1TARRAY[];
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
index 5b4c225..df549c9 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -37,6 +33,7 @@
 #include "trx.h"
 #include "led.h"
 #include "dm.h"
+#include "phy.h"
 
 static u8 _rtl88ee_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
 {
@@ -50,6 +47,164 @@
 	return skb->priority;
 }
 
+/* mac80211's rate_idx is like this:
+ *
+ * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
+ *
+ * B/G rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
+ *
+ * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
+ * A rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
+ */
+static int _rtl88ee_rate_mapping(struct ieee80211_hw *hw,
+				 bool isht, u8 desc_rate)
+{
+	int rate_idx;
+
+	if (!isht) {
+		if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
+			switch (desc_rate) {
+			case DESC92C_RATE1M:
+				rate_idx = 0;
+				break;
+			case DESC92C_RATE2M:
+				rate_idx = 1;
+				break;
+			case DESC92C_RATE5_5M:
+				rate_idx = 2;
+				break;
+			case DESC92C_RATE11M:
+				rate_idx = 3;
+				break;
+			case DESC92C_RATE6M:
+				rate_idx = 4;
+				break;
+			case DESC92C_RATE9M:
+				rate_idx = 5;
+				break;
+			case DESC92C_RATE12M:
+				rate_idx = 6;
+				break;
+			case DESC92C_RATE18M:
+				rate_idx = 7;
+				break;
+			case DESC92C_RATE24M:
+				rate_idx = 8;
+				break;
+			case DESC92C_RATE36M:
+				rate_idx = 9;
+				break;
+			case DESC92C_RATE48M:
+				rate_idx = 10;
+				break;
+			case DESC92C_RATE54M:
+				rate_idx = 11;
+				break;
+			default:
+				rate_idx = 0;
+				break;
+			}
+		} else {
+			switch (desc_rate) {
+			case DESC92C_RATE6M:
+				rate_idx = 0;
+				break;
+			case DESC92C_RATE9M:
+				rate_idx = 1;
+				break;
+			case DESC92C_RATE12M:
+				rate_idx = 2;
+				break;
+			case DESC92C_RATE18M:
+				rate_idx = 3;
+				break;
+			case DESC92C_RATE24M:
+				rate_idx = 4;
+				break;
+			case DESC92C_RATE36M:
+				rate_idx = 5;
+				break;
+			case DESC92C_RATE48M:
+				rate_idx = 6;
+				break;
+			case DESC92C_RATE54M:
+				rate_idx = 7;
+				break;
+			default:
+				rate_idx = 0;
+				break;
+			}
+		}
+	} else {
+		switch (desc_rate) {
+		case DESC92C_RATEMCS0:
+			rate_idx = 0;
+			break;
+		case DESC92C_RATEMCS1:
+			rate_idx = 1;
+			break;
+		case DESC92C_RATEMCS2:
+			rate_idx = 2;
+			break;
+		case DESC92C_RATEMCS3:
+			rate_idx = 3;
+			break;
+		case DESC92C_RATEMCS4:
+			rate_idx = 4;
+			break;
+		case DESC92C_RATEMCS5:
+			rate_idx = 5;
+			break;
+		case DESC92C_RATEMCS6:
+			rate_idx = 6;
+			break;
+		case DESC92C_RATEMCS7:
+			rate_idx = 7;
+			break;
+		case DESC92C_RATEMCS8:
+			rate_idx = 8;
+			break;
+		case DESC92C_RATEMCS9:
+			rate_idx = 9;
+			break;
+		case DESC92C_RATEMCS10:
+			rate_idx = 10;
+			break;
+		case DESC92C_RATEMCS11:
+			rate_idx = 11;
+			break;
+		case DESC92C_RATEMCS12:
+			rate_idx = 12;
+			break;
+		case DESC92C_RATEMCS13:
+			rate_idx = 13;
+			break;
+		case DESC92C_RATEMCS14:
+			rate_idx = 14;
+			break;
+		case DESC92C_RATEMCS15:
+			rate_idx = 15;
+			break;
+		default:
+			rate_idx = 0;
+			break;
+		}
+	}
+	return rate_idx;
+}
+
 static void _rtl88ee_query_rxphystatus(struct ieee80211_hw *hw,
 			struct rtl_stats *pstatus, u8 *pdesc,
 			struct rx_fwinfo_88e *p_drvinfo,
@@ -59,7 +214,8 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
 	struct phy_sts_cck_8192s_t *cck_buf;
-	struct phy_status_rpt *phystrpt = (struct phy_status_rpt *)p_drvinfo;
+	struct phy_status_rpt *phystrpt =
+		(struct phy_status_rpt *)p_drvinfo;
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
 	char rx_pwr_all = 0, rx_pwr[4];
 	u8 rf_rx_num = 0, evm, pwdb_all;
@@ -72,11 +228,11 @@
 	pstatus->packet_matchbssid = bpacket_match_bssid;
 	pstatus->packet_toself = bpacket_toself;
 	pstatus->packet_beacon = packet_beacon;
-	pstatus->rx_mimo_sig_qual[0] = -1;
-	pstatus->rx_mimo_sig_qual[1] = -1;
+	pstatus->rx_mimo_signalquality[0] = -1;
+	pstatus->rx_mimo_signalquality[1] = -1;
 
 	if (is_cck) {
-		u8 cck_hipwr;
+		u8 cck_highpwr;
 		u8 cck_agc_rpt;
 		/* CCK Driver info Structure is not the same as OFDM packet. */
 		cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo;
@@ -87,53 +243,58 @@
 		 * hardware (for rate adaptive)
 		 */
 		if (ppsc->rfpwr_state == ERFON)
-			cck_hipwr = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2,
+			cck_highpwr =
+				(u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2,
 						  BIT(9));
 		else
-			cck_hipwr = false;
+			cck_highpwr = false;
 
 		lan_idx = ((cck_agc_rpt & 0xE0) >> 5);
 		vga_idx = (cck_agc_rpt & 0x1f);
 		switch (lan_idx) {
 		case 7:
 			if (vga_idx <= 27)
-				rx_pwr_all = -100 + 2 * (27 - vga_idx);
+				/*VGA_idx = 27~2*/
+				rx_pwr_all = -100 + 2*(27-vga_idx);
 			else
 				rx_pwr_all = -100;
 			break;
 		case 6:
-			rx_pwr_all = -48 + 2 * (2 - vga_idx); /*VGA_idx = 2~0*/
+			/*VGA_idx = 2~0*/
+			rx_pwr_all = -48 + 2*(2-vga_idx);
 			break;
 		case 5:
-			rx_pwr_all = -42 + 2 * (7 - vga_idx); /*VGA_idx = 7~5*/
+			/*VGA_idx = 7~5*/
+			rx_pwr_all = -42 + 2*(7-vga_idx);
 			break;
 		case 4:
-			rx_pwr_all = -36 + 2 * (7 - vga_idx); /*VGA_idx = 7~4*/
+			/*VGA_idx = 7~4*/
+			rx_pwr_all = -36 + 2*(7-vga_idx);
 			break;
 		case 3:
-			rx_pwr_all = -24 + 2 * (7 - vga_idx); /*VGA_idx = 7~0*/
+			/*VGA_idx = 7~0*/
+			rx_pwr_all = -24 + 2*(7-vga_idx);
 			break;
 		case 2:
-			if (cck_hipwr)
-				rx_pwr_all = -12 + 2 * (5 - vga_idx);
+			if (cck_highpwr)
+				/*VGA_idx = 5~0*/
+				rx_pwr_all = -12 + 2*(5-vga_idx);
 			else
-				rx_pwr_all = -6 + 2 * (5 - vga_idx);
+				rx_pwr_all = -6 + 2*(5-vga_idx);
 			break;
 		case 1:
-			rx_pwr_all = 8 - 2 * vga_idx;
+			rx_pwr_all = 8-2*vga_idx;
 			break;
 		case 0:
-			rx_pwr_all = 14 - 2 * vga_idx;
+			rx_pwr_all = 14-2*vga_idx;
 			break;
 		default:
 			break;
 		}
 		rx_pwr_all += 6;
 		pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
-		/* CCK gain is smaller than OFDM/MCS gain,
-		 * so we add gain diff by experiences,
-		 * the val is 6
-		 */
+		/* CCK gain is smaller than OFDM/MCS gain,  */
+		/* so we add gain diff by experiences, the val is 6 */
 		pwdb_all += 6;
 		if (pwdb_all > 100)
 			pwdb_all = 100;
@@ -148,10 +309,10 @@
 			pwdb_all -= 8;
 		else if (pwdb_all > 4 && pwdb_all <= 14)
 			pwdb_all -= 4;
-		if (cck_hipwr == false) {
+		if (!cck_highpwr) {
 			if (pwdb_all >= 80)
-				pwdb_all = ((pwdb_all - 80)<<1) +
-					   ((pwdb_all - 80)>>1) + 80;
+				pwdb_all = ((pwdb_all-80)<<1) +
+					   ((pwdb_all-80)>>1) + 80;
 			else if ((pwdb_all <= 78) && (pwdb_all >= 20))
 				pwdb_all += 3;
 			if (pwdb_all > 100)
@@ -165,9 +326,9 @@
 		if (bpacket_match_bssid) {
 			u8 sq;
 
-			if (pstatus->rx_pwdb_all > 40) {
+			if (pstatus->rx_pwdb_all > 40)
 				sq = 100;
-			} else {
+			else {
 				sq = cck_buf->sq_rpt;
 				if (sq > 64)
 					sq = 0;
@@ -178,8 +339,8 @@
 			}
 
 			pstatus->signalquality = sq;
-			pstatus->rx_mimo_sig_qual[0] = sq;
-			pstatus->rx_mimo_sig_qual[1] = -1;
+			pstatus->rx_mimo_signalquality[0] = sq;
+			pstatus->rx_mimo_signalquality[1] = -1;
 		}
 	} else {
 		rtlpriv->dm.rfpath_rxenable[0] =
@@ -191,18 +352,20 @@
 			if (rtlpriv->dm.rfpath_rxenable[i])
 				rf_rx_num++;
 
-			rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f) * 2)-110;
+			rx_pwr[i] = ((p_drvinfo->gain_trsw[i] &
+				      0x3f) * 2) - 110;
 
 			/* Translate DBM to percentage. */
 			rssi = rtl_query_rxpwrpercentage(rx_pwr[i]);
 			total_rssi += rssi;
 
 			/* Get Rx snr value in DB */
-			rtlpriv->stats.rx_snr_db[i] = p_drvinfo->rxsnr[i] / 2;
+			rtlpriv->stats.rx_snr_db[i] =
+				(long)(p_drvinfo->rxsnr[i] / 2);
 
 			/* Record Signal Strength for next packet */
 			if (bpacket_match_bssid)
-				pstatus->rx_mimo_signalstrength[i] = (u8) rssi;
+				pstatus->rx_mimo_signalstrength[i] = (u8)rssi;
 		}
 
 		/* (2)PWDB, Average PWDB cacluated by
@@ -227,11 +390,13 @@
 
 			if (bpacket_match_bssid) {
 				/* Fill value in RFD, Get the first
-				 * spatial stream only
+				 * spatial stream onlyi
 				 */
 				if (i == 0)
-					pstatus->signalquality = evm & 0xff;
-				pstatus->rx_mimo_sig_qual[i] = evm & 0xff;
+					pstatus->signalquality =
+						(u8)(evm & 0xff);
+				pstatus->rx_mimo_signalquality[i] =
+					(u8)(evm & 0xff);
 			}
 		}
 	}
@@ -241,10 +406,10 @@
 	 */
 	if (is_cck)
 		pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
-					  pwdb_all));
+			pwdb_all));
 	else if (rf_rx_num != 0)
 		pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
-					  total_rssi /= rf_rx_num));
+			total_rssi /= rf_rx_num));
 	/*HW antenna diversity*/
 	rtldm->fat_table.antsel_rx_keep_0 = phystrpt->ant_sel;
 	rtldm->fat_table.antsel_rx_keep_1 = phystrpt->ant_sel_b;
@@ -256,34 +421,39 @@
 {
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
-	u8 ant_mux;
-	struct fast_ant_training *pfat = &(rtldm->fat_table);
+	u8 antsel_tr_mux;
+	struct fast_ant_training *pfat_table = &rtldm->fat_table;
 
 	if (rtlefuse->antenna_div_type == CG_TRX_SMART_ANTDIV) {
-		if (pfat->fat_state == FAT_TRAINING_STATE) {
+		if (pfat_table->fat_state == FAT_TRAINING_STATE) {
 			if (pstatus->packet_toself) {
-				ant_mux = (pfat->antsel_rx_keep_2 << 2) |
-						(pfat->antsel_rx_keep_1 << 1) |
-						 pfat->antsel_rx_keep_0;
-				pfat->ant_sum[ant_mux] += pstatus->rx_pwdb_all;
-				pfat->ant_cnt[ant_mux]++;
+				antsel_tr_mux =
+					(pfat_table->antsel_rx_keep_2 << 2) |
+					(pfat_table->antsel_rx_keep_1 << 1) |
+					pfat_table->antsel_rx_keep_0;
+				pfat_table->ant_sum[antsel_tr_mux] +=
+					pstatus->rx_pwdb_all;
+				pfat_table->ant_cnt[antsel_tr_mux]++;
 			}
 		}
 	} else if ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) ||
-		   (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)) {
+	(rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)) {
 		if (pstatus->packet_toself || pstatus->packet_matchbssid) {
-			ant_mux = (pfat->antsel_rx_keep_2 << 2) |
-				  (pfat->antsel_rx_keep_1 << 1) |
-				   pfat->antsel_rx_keep_0;
-			rtl88e_dm_ant_sel_statistics(hw, ant_mux, 0,
+			antsel_tr_mux = (pfat_table->antsel_rx_keep_2 << 2) |
+					(pfat_table->antsel_rx_keep_1 << 1) |
+					pfat_table->antsel_rx_keep_0;
+			rtl88e_dm_ant_sel_statistics(hw, antsel_tr_mux, 0,
 						     pstatus->rx_pwdb_all);
 		}
+
 	}
 }
 
 static void _rtl88ee_translate_rx_signal_stuff(struct ieee80211_hw *hw,
-		struct sk_buff *skb, struct rtl_stats *pstatus,
-		u8 *pdesc, struct rx_fwinfo_88e *p_drvinfo)
+					       struct sk_buff *skb,
+					       struct rtl_stats *pstatus,
+					       u8 *pdesc,
+					       struct rx_fwinfo_88e *p_drvinfo)
 {
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
@@ -292,42 +462,42 @@
 	u8 *praddr;
 	u8 *psaddr;
 	__le16 fc;
-	u16 type, ufc;
-	bool match_bssid, packet_toself, packet_beacon = false, addr;
+	bool packet_matchbssid, packet_toself, packet_beacon;
 
 	tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
 
 	hdr = (struct ieee80211_hdr *)tmp_buf;
 	fc = hdr->frame_control;
-	ufc = le16_to_cpu(fc);
-	type = WLAN_FC_GET_TYPE(fc);
 	praddr = hdr->addr1;
 	psaddr = ieee80211_get_SA(hdr);
 	memcpy(pstatus->psaddr, psaddr, ETH_ALEN);
 
-	addr = ether_addr_equal(mac->bssid,
-				(ufc & IEEE80211_FCTL_TODS) ? hdr->addr1 :
-				(ufc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 :
-				hdr->addr3);
-	match_bssid = ((IEEE80211_FTYPE_CTL != type) && (!pstatus->hwerror) &&
-		       (!pstatus->crc) && (!pstatus->icv)) && addr;
+	packet_matchbssid = ((!ieee80211_is_ctl(fc)) &&
+	     (ether_addr_equal(mac->bssid, ieee80211_has_tods(fc) ?
+			       hdr->addr1 : ieee80211_has_fromds(fc) ?
+			       hdr->addr2 : hdr->addr3)) &&
+			       (!pstatus->hwerror) &&
+			       (!pstatus->crc) && (!pstatus->icv));
 
-	addr = ether_addr_equal(praddr, rtlefuse->dev_addr);
-	packet_toself = match_bssid && addr;
+	packet_toself = packet_matchbssid &&
+	    (ether_addr_equal(praddr, rtlefuse->dev_addr));
 
-	if (ieee80211_is_beacon(fc))
+	if (ieee80211_is_beacon(hdr->frame_control))
 		packet_beacon = true;
+	else
+		packet_beacon = false;
 
 	_rtl88ee_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo,
-				   match_bssid, packet_toself, packet_beacon);
+				   packet_matchbssid, packet_toself,
+				   packet_beacon);
 	_rtl88ee_smart_antenna(hw, pstatus);
 	rtl_process_phyinfo(hw, tmp_buf, pstatus);
 }
 
-static void insert_em(struct rtl_tcb_desc *ptcb_desc, u8 *virtualaddress)
+static void _rtl88ee_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
+				      u8 *virtualaddress)
 {
 	u32 dwtmp = 0;
-
 	memset(virtualaddress, 0, 8);
 
 	SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num);
@@ -335,7 +505,7 @@
 		dwtmp = ptcb_desc->empkt_len[0];
 	} else {
 		dwtmp = ptcb_desc->empkt_len[0];
-		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+		dwtmp += ((dwtmp%4) ? (4-dwtmp%4) : 0)+4;
 		dwtmp += ptcb_desc->empkt_len[1];
 	}
 	SET_EARLYMODE_LEN0(virtualaddress, dwtmp);
@@ -344,7 +514,7 @@
 		dwtmp = ptcb_desc->empkt_len[2];
 	} else {
 		dwtmp = ptcb_desc->empkt_len[2];
-		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+		dwtmp += ((dwtmp%4) ? (4-dwtmp%4) : 0)+4;
 		dwtmp += ptcb_desc->empkt_len[3];
 	}
 	SET_EARLYMODE_LEN1(virtualaddress, dwtmp);
@@ -352,7 +522,7 @@
 		dwtmp = ptcb_desc->empkt_len[4];
 	} else {
 		dwtmp = ptcb_desc->empkt_len[4];
-		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+		dwtmp += ((dwtmp%4) ? (4-dwtmp%4) : 0)+4;
 		dwtmp += ptcb_desc->empkt_len[5];
 	}
 	SET_EARLYMODE_LEN2_1(virtualaddress, dwtmp & 0xF);
@@ -361,7 +531,7 @@
 		dwtmp = ptcb_desc->empkt_len[6];
 	} else {
 		dwtmp = ptcb_desc->empkt_len[6];
-		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+		dwtmp += ((dwtmp%4) ? (4-dwtmp%4) : 0)+4;
 		dwtmp += ptcb_desc->empkt_len[7];
 	}
 	SET_EARLYMODE_LEN3(virtualaddress, dwtmp);
@@ -369,7 +539,7 @@
 		dwtmp = ptcb_desc->empkt_len[8];
 	} else {
 		dwtmp = ptcb_desc->empkt_len[8];
-		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+		dwtmp += ((dwtmp%4) ? (4-dwtmp%4) : 0)+4;
 		dwtmp += ptcb_desc->empkt_len[9];
 	}
 	SET_EARLYMODE_LEN4(virtualaddress, dwtmp);
@@ -387,21 +557,21 @@
 	u32 phystatus = GET_RX_DESC_PHYST(pdesc);
 	status->packet_report_type = (u8)GET_RX_STATUS_DESC_RPT_SEL(pdesc);
 	if (status->packet_report_type == TX_REPORT2)
-		status->length = (u16) GET_RX_RPT2_DESC_PKT_LEN(pdesc);
+		status->length = (u16)GET_RX_RPT2_DESC_PKT_LEN(pdesc);
 	else
-		status->length = (u16) GET_RX_DESC_PKT_LEN(pdesc);
-	status->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
-				       RX_DRV_INFO_SIZE_UNIT;
-	status->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03);
-	status->icv = (u16) GET_RX_DESC_ICV(pdesc);
-	status->crc = (u16) GET_RX_DESC_CRC32(pdesc);
+		status->length = (u16)GET_RX_DESC_PKT_LEN(pdesc);
+	status->rx_drvinfo_size = (u8)GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
+	    RX_DRV_INFO_SIZE_UNIT;
+	status->rx_bufshift = (u8)(GET_RX_DESC_SHIFT(pdesc) & 0x03);
+	status->icv = (u16)GET_RX_DESC_ICV(pdesc);
+	status->crc = (u16)GET_RX_DESC_CRC32(pdesc);
 	status->hwerror = (status->crc | status->icv);
 	status->decrypted = !GET_RX_DESC_SWDEC(pdesc);
-	status->rate = (u8) GET_RX_DESC_RXMCS(pdesc);
-	status->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
+	status->rate = (u8)GET_RX_DESC_RXMCS(pdesc);
+	status->shortpreamble = (u16)GET_RX_DESC_SPLCP(pdesc);
 	status->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
-	status->isfirst_ampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1) &&
-					(GET_RX_DESC_FAGGR(pdesc) == 1));
+	status->isfirst_ampdu = (bool)((GET_RX_DESC_PAGGR(pdesc) == 1) &&
+				(GET_RX_DESC_FAGGR(pdesc) == 1));
 	if (status->packet_report_type == NORMAL_RX)
 		status->timestamp_low = GET_RX_DESC_TSFL(pdesc);
 	status->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
@@ -420,11 +590,14 @@
 		status->wake_match = 0;
 	if (status->wake_match)
 		RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD,
-			 "Get Wakeup Packet!! WakeMatch =%d\n",
-			 status->wake_match);
+		"GGGGGGGGGGGGGet Wakeup Packet!! WakeMatch=%d\n",
+		status->wake_match);
 	rx_status->freq = hw->conf.chandef.chan->center_freq;
 	rx_status->band = hw->conf.chandef.chan->band;
 
+	hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size
+			+ status->rx_bufshift);
+
 	if (status->crc)
 		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
 
@@ -445,18 +618,11 @@
 	 * to decrypt it
 	 */
 	if (status->decrypted) {
-		hdr = (struct ieee80211_hdr *)(skb->data +
-		       status->rx_drvinfo_size + status->rx_bufshift);
-
-		if (!hdr) {
-			/* During testing, hdr was NULL */
-			return false;
-		}
-		if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
+		if ((!_ieee80211_is_robust_mgmt_frame(hdr)) &&
 		    (ieee80211_has_protected(hdr->frame_control)))
-			rx_status->flag &= ~RX_FLAG_DECRYPTED;
-		else
 			rx_status->flag |= RX_FLAG_DECRYPTED;
+		else
+			rx_status->flag &= ~RX_FLAG_DECRYPTED;
 	}
 
 	/* rate_idx: index of data rate into band's
@@ -464,19 +630,18 @@
 	 * are use (RX_FLAG_HT)
 	 * Notice: this is diff with windows define
 	 */
-	rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht,
-						   status->rate, false);
+	rx_status->rate_idx = _rtl88ee_rate_mapping(hw,
+				status->is_ht, status->rate);
 
 	rx_status->mactime = status->timestamp_low;
 	if (phystatus == true) {
 		p_drvinfo = (struct rx_fwinfo_88e *)(skb->data +
 						     status->rx_bufshift);
 
-		_rtl88ee_translate_rx_signal_stuff(hw, skb, status, pdesc,
+		_rtl88ee_translate_rx_signal_stuff(hw,
+						   skb, status, pdesc,
 						   p_drvinfo);
 	}
-
-	/*rx_status->qual = status->signal; */
 	rx_status->signal = status->recvsignalpower + 10;
 	if (status->packet_report_type == TX_REPORT2) {
 		status->macid_valid_entry[0] =
@@ -489,15 +654,17 @@
 
 void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw,
 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-			  u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
-			  struct ieee80211_sta *sta, struct sk_buff *skb,
+			  u8 *txbd, struct ieee80211_tx_info *info,
+			  struct ieee80211_sta *sta,
+			  struct sk_buff *skb,
 			  u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
+
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-	u8 *pdesc = pdesc_tx;
+	u8 *pdesc = (u8 *)pdesc_tx;
 	u16 seq_number;
 	__le16 fc = hdr->frame_control;
 	unsigned int buf_len = 0;
@@ -547,8 +714,9 @@
 			if (ptcb_desc->empkt_num) {
 				RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
 					 "Insert 8 byte.pTcb->EMPktNum:%d\n",
-					 ptcb_desc->empkt_num);
-				insert_em(ptcb_desc, (u8 *)(skb->data));
+					  ptcb_desc->empkt_num);
+				_rtl88ee_insert_emcontent(ptcb_desc,
+							  (u8 *)(skb->data));
 			}
 		} else {
 			SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
@@ -560,6 +728,7 @@
 			short_gi = (ptcb_desc->use_shortgi) ? 1 : 0;
 		else
 			short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0;
+
 		SET_TX_DESC_DATA_SHORTGI(pdesc, short_gi);
 
 		if (info->flags & IEEE80211_TX_CTL_AMPDU) {
@@ -568,7 +737,7 @@
 		}
 		SET_TX_DESC_SEQ(pdesc, seq_number);
 		SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable &&
-					      !ptcb_desc->cts_enable) ? 1 : 0));
+						!ptcb_desc->cts_enable) ? 1 : 0));
 		SET_TX_DESC_HW_RTS_ENABLE(pdesc, 0);
 		SET_TX_DESC_CTS2SELF(pdesc, ((ptcb_desc->cts_enable) ? 1 : 0));
 		SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0));
@@ -581,17 +750,17 @@
 			(ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
 			(ptcb_desc->rts_use_shortgi ? 1 : 0)));
 
-		if (ptcb_desc->btx_enable_sw_calc_duration)
+		if (ptcb_desc->tx_enable_sw_calc_duration)
 			SET_TX_DESC_NAV_USE_HDR(pdesc, 1);
 
 		if (bw_40) {
-			if (ptcb_desc->packet_bw) {
+			if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40) {
 				SET_TX_DESC_DATA_BW(pdesc, 1);
 				SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3);
 			} else {
 				SET_TX_DESC_DATA_BW(pdesc, 0);
 				SET_TX_DESC_TX_SUB_CARRIER(pdesc,
-						   mac->cur_40_prime_sc);
+							   mac->cur_40_prime_sc);
 			}
 		} else {
 			SET_TX_DESC_DATA_BW(pdesc, 0);
@@ -599,13 +768,14 @@
 		}
 
 		SET_TX_DESC_LINIP(pdesc, 0);
-		SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb_len);
+		SET_TX_DESC_PKT_SIZE(pdesc, (u16)skb_len);
 		if (sta) {
 			u8 ampdu_density = sta->ht_cap.ampdu_density;
 			SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density);
 		}
 		if (info->control.hw_key) {
 			struct ieee80211_key_conf *keyconf;
+
 			keyconf = info->control.hw_key;
 			switch (keyconf->cipher) {
 			case WLAN_CIPHER_SUITE_WEP40:
@@ -619,6 +789,7 @@
 			default:
 				SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
 				break;
+
 			}
 		}
 
@@ -629,6 +800,7 @@
 				       1 : 0);
 		SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0);
 
+		/*SET_TX_DESC_PWR_STATUS(pdesc, pwr_status);*/
 		/* Set TxRate and RTSRate in TxDesc  */
 		/* This prevent Tx initial rate of new-coming packets */
 		/* from being overwritten by retried  packet rate.*/
@@ -639,7 +811,7 @@
 		if (ieee80211_is_data_qos(fc)) {
 			if (mac->rdg_en) {
 				RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
-					 "Enable RDG function.\n");
+					"Enable RDG function.\n");
 				SET_TX_DESC_RDG_ENABLE(pdesc, 1);
 				SET_TX_DESC_HTC(pdesc, 1);
 			}
@@ -648,7 +820,7 @@
 
 	SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
 	SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
-	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) buf_len);
+	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)buf_len);
 	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
 	if (rtlpriv->dm.useramask) {
 		SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index);
@@ -664,8 +836,9 @@
 		SET_TX_DESC_HWSEQ_EN(pdesc, 1);
 	SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1));
 	if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
-	    is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
+	    is_broadcast_ether_addr(ieee80211_get_DA(hdr))) {
 		SET_TX_DESC_BMC(pdesc, 1);
+	}
 
 	rtl88e_dm_set_tx_ant_by_tx_info(hw, pdesc, ptcb_desc->mac_id);
 	RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n");
@@ -733,8 +906,8 @@
 		      pdesc, TX_DESC_SIZE);
 }
 
-void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
-		      u8 desc_name, u8 *val)
+void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc,
+		      bool istx, u8 desc_name, u8 *val)
 {
 	if (istx == true) {
 		switch (desc_name) {
@@ -745,7 +918,7 @@
 			SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *)val);
 			break;
 		default:
-			RT_ASSERT(false, "ERR txdesc :%d not processed\n",
+			RT_ASSERT(false, "ERR txdesc :%d not process\n",
 				  desc_name);
 			break;
 		}
@@ -764,7 +937,7 @@
 			SET_RX_DESC_EOR(pdesc, 1);
 			break;
 		default:
-			RT_ASSERT(false, "ERR rxdesc :%d not processed\n",
+			RT_ASSERT(false, "ERR rxdesc :%d not process\n",
 				  desc_name);
 			break;
 		}
@@ -784,7 +957,7 @@
 			ret = GET_TX_DESC_TX_BUFFER_ADDRESS(pdesc);
 			break;
 		default:
-			RT_ASSERT(false, "ERR txdesc :%d not processed\n",
+			RT_ASSERT(false, "ERR txdesc :%d not process\n",
 				  desc_name);
 			break;
 		}
@@ -796,8 +969,11 @@
 		case HW_DESC_RXPKT_LEN:
 			ret = GET_RX_DESC_PKT_LEN(pdesc);
 			break;
+		case HW_DESC_RXBUFF_ADDR:
+			ret = GET_RX_DESC_BUFF_ADDR(pdesc);
+			break;
 		default:
-			RT_ASSERT(false, "ERR rxdesc :%d not processed\n",
+			RT_ASSERT(false, "ERR rxdesc :%d not process\n",
 				  desc_name);
 			break;
 		}
@@ -805,6 +981,22 @@
 	return ret;
 }
 
+bool rtl88ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index)
+{
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+	u8 *entry = (u8 *)(&ring->desc[ring->idx]);
+	u8 own = (u8)rtl88ee_get_desc(entry, true, HW_DESC_OWN);
+
+	/*beacon packet will only use the first
+	 *descriptor defautly,and the own may not
+	 *be cleared by the hardware
+	 */
+	if (own)
+		return false;
+	return true;
+}
+
 void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -815,3 +1007,10 @@
 			       BIT(0) << (hw_queue));
 	}
 }
+
+u32 rtl88ee_rx_command_packet(struct ieee80211_hw *hw,
+			      struct rtl_stats status,
+			      struct sk_buff *skb)
+{
+	return 0;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h
index 8c26094..eab5ae0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,59 +26,59 @@
 #ifndef __RTL92CE_TRX_H__
 #define __RTL92CE_TRX_H__
 
-#define TX_DESC_SIZE				64
+#define TX_DESC_SIZE					64
 #define TX_DESC_AGGR_SUBFRAME_SIZE		32
 
-#define RX_DESC_SIZE				32
+#define RX_DESC_SIZE					32
 #define RX_DRV_INFO_SIZE_UNIT			8
 
 #define	TX_DESC_NEXT_DESC_OFFSET		40
 #define USB_HWDESC_HEADER_LEN			32
-#define CRCLENGTH				4
+#define CRCLENGTH						4
 
 #define SET_TX_DESC_PKT_SIZE(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val)
-#define SET_TX_DESC_OFFSET(__pdesc, __val)		\
+#define SET_TX_DESC_OFFSET(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val)
-#define SET_TX_DESC_BMC(__pdesc, __val)			\
+#define SET_TX_DESC_BMC(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val)
-#define SET_TX_DESC_HTC(__pdesc, __val)			\
+#define SET_TX_DESC_HTC(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val)
 #define SET_TX_DESC_LAST_SEG(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val)
 #define SET_TX_DESC_FIRST_SEG(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val)
-#define SET_TX_DESC_LINIP(__pdesc, __val)		\
+#define SET_TX_DESC_LINIP(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val)
-#define SET_TX_DESC_NO_ACM(__pdesc, __val)		\
+#define SET_TX_DESC_NO_ACM(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val)
-#define SET_TX_DESC_GF(__pdesc, __val)			\
+#define SET_TX_DESC_GF(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
-#define SET_TX_DESC_OWN(__pdesc, __val)			\
+#define SET_TX_DESC_OWN(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
 
-#define GET_TX_DESC_PKT_SIZE(__pdesc)			\
+#define GET_TX_DESC_PKT_SIZE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 0, 16)
-#define GET_TX_DESC_OFFSET(__pdesc)			\
+#define GET_TX_DESC_OFFSET(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc, 16, 8)
-#define GET_TX_DESC_BMC(__pdesc)			\
+#define GET_TX_DESC_BMC(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc, 24, 1)
-#define GET_TX_DESC_HTC(__pdesc)			\
+#define GET_TX_DESC_HTC(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc, 25, 1)
-#define GET_TX_DESC_LAST_SEG(__pdesc)			\
+#define GET_TX_DESC_LAST_SEG(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 26, 1)
-#define GET_TX_DESC_FIRST_SEG(__pdesc)			\
+#define GET_TX_DESC_FIRST_SEG(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 27, 1)
-#define GET_TX_DESC_LINIP(__pdesc)			\
+#define GET_TX_DESC_LINIP(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc, 28, 1)
-#define GET_TX_DESC_NO_ACM(__pdesc)			\
+#define GET_TX_DESC_NO_ACM(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc, 29, 1)
-#define GET_TX_DESC_GF(__pdesc)				\
+#define GET_TX_DESC_GF(__pdesc)						\
 	LE_BITS_TO_4BYTE(__pdesc, 30, 1)
-#define GET_TX_DESC_OWN(__pdesc)			\
+#define GET_TX_DESC_OWN(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc, 31, 1)
 
-#define SET_TX_DESC_MACID(__pdesc, __val)		\
+#define SET_TX_DESC_MACID(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 6, __val)
 #define SET_TX_DESC_QUEUE_SEL(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val)
@@ -90,11 +86,11 @@
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val)
 #define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val)	\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val)
-#define SET_TX_DESC_PIFS(__pdesc, __val)		\
+#define SET_TX_DESC_PIFS(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val)
 #define SET_TX_DESC_RATE_ID(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 4, __val)
-#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val)	\
+#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 20, 1, __val)
 #define SET_TX_DESC_EN_DESC_ID(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val)
@@ -102,10 +98,10 @@
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val)
 #define SET_TX_DESC_PKT_OFFSET(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 26, 5, __val)
-#define SET_TX_DESC_PADDING_LEN(__pdesc, __val)		\
+#define SET_TX_DESC_PADDING_LEN(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 8, __val)
 
-#define GET_TX_DESC_MACID(__pdesc)				\
+#define GET_TX_DESC_MACID(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc+4, 0, 5)
 #define GET_TX_DESC_AGG_ENABLE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 5, 1)
@@ -119,7 +115,7 @@
 	LE_BITS_TO_4BYTE(__pdesc+4, 13, 1)
 #define GET_TX_DESC_LSIG_TXOP_EN(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
-#define GET_TX_DESC_PIFS(__pdesc)				\
+#define GET_TX_DESC_PIFS(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
 #define GET_TX_DESC_RATE_ID(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
@@ -205,7 +201,6 @@
 #define SET_TX_DESC_HWSEQ_EN(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc+12, 31, 1, __val)
 
-
 #define GET_TX_DESC_NEXT_HEAP_PAGE(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+12, 0, 8)
 #define GET_TX_DESC_TAIL_PAGE(__pdesc)				\
@@ -213,7 +208,6 @@
 #define GET_TX_DESC_SEQ(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc+12, 16, 12)
 
-
 #define SET_TX_DESC_RTS_RATE(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 5, __val)
 #define SET_TX_DESC_AP_DCFE(__pdesc, __val)		\
@@ -386,7 +380,6 @@
 #define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+28, 0, 16)
 
-
 #define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val)	\
 	SET_BITS_TO_LE_4BYTE(__pdesc+32, 0, 32, __val)
 #define SET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc, __val) \
@@ -549,8 +542,10 @@
 	 rxmcs == DESC92C_RATE5_5M ||\
 	 rxmcs == DESC92C_RATE11M)
 
+#define IS_LITTLE_ENDIAN	1
+
 struct phy_rx_agc_info_t {
-	#ifdef __LITTLE_ENDIAN
+	#if IS_LITTLE_ENDIAN
 		u8	gain:7, trsw:1;
 	#else
 		u8	trsw:1, gain:7;
@@ -562,7 +557,7 @@
 	u8	cck_sig_qual_ofdm_pwdb_all;
 	u8	cck_agc_rpt_ofdm_cfosho_a;
 	u8	cck_rpt_b_ofdm_cfosho_b;
-	u8	rsvd_1;
+	u8	rsvd_1;/* ch_corr_msb; */
 	u8	noise_power_db_msb;
 	u8	path_cfotail[2];
 	u8	pcts_mask[2];
@@ -574,7 +569,7 @@
 	u8	stream_target_csi[2];
 	u8	sig_evm;
 	u8	rsvd_3;
-#ifdef __LITTLE_ENDIAN
+#if IS_LITTLE_ENDIAN
 	u8	antsel_rx_keep_2:1;	/*ex_intf_flg:1;*/
 	u8	sgi_en:1;
 	u8	rxsc:2;
@@ -777,19 +772,25 @@
 
 void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw,
 			  struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-			  u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
-			  struct ieee80211_sta *sta, struct sk_buff *skb,
+			  u8 *txbd, struct ieee80211_tx_info *info,
+			  struct ieee80211_sta *sta,
+			  struct sk_buff *skb,
 			  u8 hw_queue, struct rtl_tcb_desc *ptcb_desc);
 bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
 			   struct rtl_stats *status,
 			   struct ieee80211_rx_status *rx_status,
 			   u8 *pdesc, struct sk_buff *skb);
-void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
-		      u8 desc_name, u8 *val);
+void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc,
+		      bool istx, u8 desc_name, u8 *val);
 u32 rtl88ee_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+bool rtl88ee_is_tx_desc_closed(struct ieee80211_hw *hw,
+			       u8 hw_queue, u16 index);
 void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
 void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
-			     bool b_firstseg, bool b_lastseg,
+			     bool firstseg, bool lastseg,
 			     struct sk_buff *skb);
+u32 rtl88ee_rx_command_packet(struct ieee80211_hw *hw,
+			      struct rtl_stats status,
+			      struct sk_buff *skb);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
index eb78fd8..f6cb5ae 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -1771,7 +1771,7 @@
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u8 tmp1byte = 0;
 
-	if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version) &&
+	if (IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version) &&
 	    rtlpcipriv->bt_coexist.bt_coexistence)
 		tmp1byte |= BIT(5);
 	if (rtlpcipriv->bt_coexist.bt_cur_state) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
index 04a4162..a00861b 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,6 +26,7 @@
 #include "../wifi.h"
 #include "../pci.h"
 #include "../base.h"
+#include "../core.h"
 #include "../rtl8192ce/reg.h"
 #include "../rtl8192ce/def.h"
 #include "fw_common.h"
@@ -71,66 +68,31 @@
 	}
 }
 
-static void rtl_block_fw_writeN(struct ieee80211_hw *hw, const u8 *buffer,
-				u32 size)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 blockSize = REALTEK_USB_VENQT_MAX_BUF_SIZE - 20;
-	u8 *bufferPtr = (u8 *) buffer;
-	u32 i, offset, blockCount, remainSize;
-
-	blockCount = size / blockSize;
-	remainSize = size % blockSize;
-
-	for (i = 0; i < blockCount; i++) {
-		offset = i * blockSize;
-		rtlpriv->io.writeN_sync(rtlpriv,
-					(FW_8192C_START_ADDRESS + offset),
-					(void *)(bufferPtr + offset),
-					blockSize);
-	}
-
-	if (remainSize) {
-		offset = blockCount * blockSize;
-		rtlpriv->io.writeN_sync(rtlpriv,
-					(FW_8192C_START_ADDRESS + offset),
-					(void *)(bufferPtr + offset),
-					remainSize);
-	}
-}
-
 static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
 				   const u8 *buffer, u32 size)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 blockSize = sizeof(u32);
-	u8 *bufferPtr = (u8 *) buffer;
-	u32 *pu4BytePtr = (u32 *) buffer;
-	u32 i, offset, blockCount, remainSize;
-	u32 data;
+	u32 blocksize = sizeof(u32);
+	u8 *bufferptr = (u8 *)buffer;
+	u32 *pu4byteptr = (u32 *)buffer;
+	u32 i, offset, blockcount, remainsize;
 
-	if (rtlpriv->io.writeN_sync) {
-		rtl_block_fw_writeN(hw, buffer, size);
-		return;
-	}
-	blockCount = size / blockSize;
-	remainSize = size % blockSize;
-	if (remainSize) {
-		/* the last word is < 4 bytes - pad it with zeros */
-		for (i = 0; i < 4 - remainSize; i++)
-			*(bufferPtr + size + i) = 0;
-		blockCount++;
-	}
+	blockcount = size / blocksize;
+	remainsize = size % blocksize;
 
-	for (i = 0; i < blockCount; i++) {
-		offset = i * blockSize;
-		/* for big-endian platforms, the firmware data need to be byte
-		 * swapped as it was read as a byte string and will be written
-		 * as 32-bit dwords and byte swapped when written
-		 */
-		data = le32_to_cpu(*(__le32 *)(pu4BytePtr + i));
+	for (i = 0; i < blockcount; i++) {
+		offset = i * blocksize;
 		rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
-				data);
+				*(pu4byteptr + i));
+	}
+
+	if (remainsize) {
+		offset = blockcount * blocksize;
+		bufferptr += offset;
+		for (i = 0; i < remainsize; i++) {
+			rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
+						 offset + i), *(bufferptr + i));
+		}
 	}
 }
 
@@ -168,19 +130,20 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	u8 *bufferPtr = buffer;
+	bool is_version_b;
+	u8 *bufferptr = (u8 *)buffer;
 
-	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes\n", size);
-
-	if (IS_CHIP_VER_B(version)) {
-		u32 pageNums, remainSize;
+	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
+	is_version_b = IS_NORMAL_CHIP(version);
+	if (is_version_b) {
+		u32 pageNums, remainsize;
 		u32 page, offset;
 
-		if (IS_HARDWARE_TYPE_8192CE(rtlhal))
-			_rtl92c_fill_dummy(bufferPtr, &size);
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE)
+			_rtl92c_fill_dummy(bufferptr, &size);
 
 		pageNums = size / FW_8192C_PAGE_SIZE;
-		remainSize = size % FW_8192C_PAGE_SIZE;
+		remainsize = size % FW_8192C_PAGE_SIZE;
 
 		if (pageNums > 4) {
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -189,15 +152,15 @@
 
 		for (page = 0; page < pageNums; page++) {
 			offset = page * FW_8192C_PAGE_SIZE;
-			_rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
+			_rtl92c_fw_page_write(hw, page, (bufferptr + offset),
 					      FW_8192C_PAGE_SIZE);
 		}
 
-		if (remainSize) {
+		if (remainsize) {
 			offset = pageNums * FW_8192C_PAGE_SIZE;
 			page = pageNums;
-			_rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
-					      remainSize);
+			_rtl92c_fw_page_write(hw, page, (bufferptr + offset),
+					      remainsize);
 		}
 	} else {
 		_rtl92c_fw_block_write(hw, buffer, size);
@@ -207,6 +170,7 @@
 static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	int err = -EIO;
 	u32 counter = 0;
 	u32 value32;
 
@@ -217,12 +181,13 @@
 
 	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "chksum report faill ! REG_MCUFWDL:0x%08x\n", value32);
-		return -EIO;
+			 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
+			  value32);
+		goto exit;
 	}
 
 	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-		 "Checksum report OK ! REG_MCUFWDL:0x%08x\n", value32);
+		 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
 
 	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 	value32 |= MCUFWDL_RDY;
@@ -235,9 +200,10 @@
 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 		if (value32 & WINTINI_RDY) {
 			RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-				 "Polling FW ready success!! REG_MCUFWDL:0x%08x\n",
-				 value32);
-			return 0;
+				 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
+					value32);
+			err = 0;
+			goto exit;
 		}
 
 		mdelay(FW_8192C_POLLING_DELAY);
@@ -245,8 +211,10 @@
 	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
 
 	RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-		 "Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", value32);
-	return -EIO;
+		 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
+
+exit:
+	return err;
 }
 
 int rtl92c_download_fw(struct ieee80211_hw *hw)
@@ -256,21 +224,21 @@
 	struct rtl92c_firmware_header *pfwheader;
 	u8 *pfwdata;
 	u32 fwsize;
+	int err;
 	enum version_8192c version = rtlhal->version;
 
-	if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
+	if (!rtlhal->pfirmware)
 		return 1;
 
 	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
-	pfwdata = rtlhal->pfirmware;
+	pfwdata = (u8 *)rtlhal->pfirmware;
 	fwsize = rtlhal->fwsize;
 
 	if (IS_FW_HEADER_EXIST(pfwheader)) {
 		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 			 "Firmware Version(%d), Signature(%#x),Size(%d)\n",
-			 le16_to_cpu(pfwheader->version),
-			 le16_to_cpu(pfwheader->signature),
-			 (uint)sizeof(struct rtl92c_firmware_header));
+			  pfwheader->version, pfwheader->signature,
+			  (int)sizeof(struct rtl92c_firmware_header));
 
 		pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
 		fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
@@ -280,7 +248,8 @@
 	_rtl92c_write_fw(hw, version, pfwdata, fwsize);
 	_rtl92c_enable_fw_download(hw, false);
 
-	if (_rtl92c_fw_free_to_go(hw)) {
+	err = _rtl92c_fw_free_to_go(hw);
+	if (err) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 "Firmware is not ready to run!\n");
 	} else {
@@ -307,7 +276,7 @@
 }
 
 static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
-			      u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
+			      u8 element_id, u32 cmd_len, u8 *cmdbuffer)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -315,7 +284,8 @@
 	u16 box_reg = 0, box_extreg = 0;
 	u8 u1b_tmp;
 	bool isfw_read = false;
-	bool bwrite_success = false;
+	u8 buf_index = 0;
+	bool bwrite_sucess = false;
 	u8 wait_h2c_limmit = 100;
 	u8 wait_writeh2c_limmit = 100;
 	u8 boxcontent[4], boxextcontent[2];
@@ -329,16 +299,15 @@
 		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 		if (rtlhal->h2c_setinprogress) {
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
-				 "H2C set in progress! Wait to set..element_id(%d)\n",
+				 "H2C set in progress! Wait to set..element_id(%d).\n",
 				 element_id);
-
 			while (rtlhal->h2c_setinprogress) {
 				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
 						       flag);
 				h2c_waitcounter++;
 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 					 "Wait 100 us (%d times)...\n",
-					 h2c_waitcounter);
+					  h2c_waitcounter);
 				udelay(100);
 
 				if (h2c_waitcounter > 1000)
@@ -354,7 +323,7 @@
 		}
 	}
 
-	while (!bwrite_success) {
+	while (!bwrite_sucess) {
 		wait_writeh2c_limmit--;
 		if (wait_writeh2c_limmit == 0) {
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -381,14 +350,13 @@
 			box_extreg = REG_HMEBOX_EXT_3;
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
 			break;
 		}
 
 		isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
 		while (!isfw_read) {
-
 			wait_h2c_limmit--;
 			if (wait_h2c_limmit == 0) {
 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
@@ -408,7 +376,7 @@
 
 		if (!isfw_read) {
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
-				 "Write H2C register BOX[%d] fail!!!!! Fw do not read\n",
+				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
 				 boxnum);
 			break;
 		}
@@ -418,13 +386,13 @@
 		boxcontent[0] = element_id;
 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 			 "Write element_id box_reg(%4x) = %2x\n",
-			 box_reg, element_id);
+			  box_reg, element_id);
 
 		switch (cmd_len) {
 		case 1:
 			boxcontent[0] &= ~(BIT(7));
-			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer, 1);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index, 1);
 
 			for (idx = 0; idx < 4; idx++) {
 				rtl_write_byte(rtlpriv, box_reg + idx,
@@ -433,8 +401,8 @@
 			break;
 		case 2:
 			boxcontent[0] &= ~(BIT(7));
-			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer, 2);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index, 2);
 
 			for (idx = 0; idx < 4; idx++) {
 				rtl_write_byte(rtlpriv, box_reg + idx,
@@ -443,8 +411,8 @@
 			break;
 		case 3:
 			boxcontent[0] &= ~(BIT(7));
-			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer, 3);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index, 3);
 
 			for (idx = 0; idx < 4; idx++) {
 				rtl_write_byte(rtlpriv, box_reg + idx,
@@ -453,10 +421,10 @@
 			break;
 		case 4:
 			boxcontent[0] |= (BIT(7));
-			memcpy((u8 *) (boxextcontent),
-			       p_cmdbuffer, 2);
-			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer + 2, 2);
+			memcpy((u8 *)(boxextcontent),
+			       cmdbuffer + buf_index, 2);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index + 2, 2);
 
 			for (idx = 0; idx < 2; idx++) {
 				rtl_write_byte(rtlpriv, box_extreg + idx,
@@ -470,10 +438,10 @@
 			break;
 		case 5:
 			boxcontent[0] |= (BIT(7));
-			memcpy((u8 *) (boxextcontent),
-			       p_cmdbuffer, 2);
-			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer + 2, 3);
+			memcpy((u8 *)(boxextcontent),
+			       cmdbuffer + buf_index, 2);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index + 2, 3);
 
 			for (idx = 0; idx < 2; idx++) {
 				rtl_write_byte(rtlpriv, box_extreg + idx,
@@ -486,12 +454,12 @@
 			}
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
 			break;
 		}
 
-		bwrite_success = true;
+		bwrite_sucess = true;
 
 		rtlhal->last_hmeboxnum = boxnum + 1;
 		if (rtlhal->last_hmeboxnum == 4)
@@ -499,7 +467,7 @@
 
 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 			 "pHalData->last_hmeboxnum  = %d\n",
-			 rtlhal->last_hmeboxnum);
+			  rtlhal->last_hmeboxnum);
 	}
 
 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
@@ -510,12 +478,19 @@
 }
 
 void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
-			 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
+			 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
 {
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u32 tmp_cmdbuf[2];
 
+	if (!rtlhal->fw_ready) {
+		RT_ASSERT(false,
+			  "return H2C cmd because of Fw download fail!!!\n");
+		return;
+	}
+
 	memset(tmp_cmdbuf, 0, 8);
-	memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
+	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
 	_rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
 
 	return;
@@ -534,7 +509,7 @@
 	while (u1b_tmp & BIT(2)) {
 		delay--;
 		if (delay == 0) {
-			RT_ASSERT(false, "8051 reset fail\n");
+			RT_ASSERT(false, "8051 reset fail.\n");
 			break;
 		}
 		udelay(50);
@@ -546,56 +521,24 @@
 void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u8 u1_h2c_set_pwrmode[3] = {0};
+	u8 u1_h2c_set_pwrmode[3] = { 0 };
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 
 	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
 
 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
-					 (rtlpriv->mac80211.p2p) ?
-					 ppsc->smart_ps : 1);
+		(rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
 	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
 					      ppsc->reg_max_lps_awakeintvl);
 
 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
-		      "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode",
+		      "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
 		      u1_h2c_set_pwrmode, 3);
 	rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
-
 }
 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
 
-static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
-				struct sk_buff *skb)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-	struct rtl8192_tx_ring *ring;
-	struct rtl_tx_desc *pdesc;
-	unsigned long flags;
-	struct sk_buff *pskb = NULL;
-
-	ring = &rtlpci->tx_ring[BEACON_QUEUE];
-
-	pskb = __skb_dequeue(&ring->queue);
-	kfree_skb(pskb);
-
-	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
-
-	pdesc = &ring->desc[0];
-
-	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
-
-	__skb_queue_tail(&ring->queue, skb);
-
-	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-
-	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
-
-	return true;
-}
-
 #define BEACON_PG		0 /*->1*/
 #define PSPOLL_PG		2
 #define NULL_PG			3
@@ -713,7 +656,7 @@
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
+void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -721,13 +664,13 @@
 
 	u32 totalpacketlen;
 	bool rtstatus;
-	u8 u1RsvdPageLoc[3] = {0};
-	bool dlok = false;
+	u8 u1rsvdpageloc[3] = { 0 };
+	bool b_dlok = false;
 
 	u8 *beacon;
-	u8 *pspoll;
+	u8 *p_pspoll;
 	u8 *nullfunc;
-	u8 *probersp;
+	u8 *p_probersp;
 	/*---------------------------------------------------------
 				(1) beacon
 	---------------------------------------------------------*/
@@ -738,12 +681,12 @@
 	/*-------------------------------------------------------
 				(2) ps-poll
 	--------------------------------------------------------*/
-	pspoll = &reserved_page_packet[PSPOLL_PG * 128];
-	SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
-	SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
-	SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
+	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
+	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
+	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
+	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
 
-	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
+	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
 
 	/*--------------------------------------------------------
 				(3) null data
@@ -753,57 +696,54 @@
 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
 
-	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
+	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
 
 	/*---------------------------------------------------------
 				(4) probe response
 	----------------------------------------------------------*/
-	probersp = &reserved_page_packet[PROBERSP_PG * 128];
-	SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
-	SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
-	SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
+	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
+	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
+	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
 
-	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
+	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
 
 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
 
 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
-		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
+		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
 		      &reserved_page_packet[0], totalpacketlen);
 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
-		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
-		      u1RsvdPageLoc, 3);
+		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+		      u1rsvdpageloc, 3);
 
 
 	skb = dev_alloc_skb(totalpacketlen);
-	if (!skb)
-		return;
-	kmemleak_not_leak(skb);
-
-	memcpy((u8 *) skb_put(skb, totalpacketlen),
+	memcpy((u8 *)skb_put(skb, totalpacketlen),
 	       &reserved_page_packet, totalpacketlen);
 
-	rtstatus = _rtl92c_cmd_send_packet(hw, skb);
+	rtstatus = rtl_cmd_send_packet(hw, skb);
 
 	if (rtstatus)
-		dlok = true;
+		b_dlok = true;
 
-	if (dlok) {
+	if (b_dlok) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
-			 "Set RSVD page location to Fw\n");
+			 "Set RSVD page location to Fw.\n");
 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
-			      "H2C_RSVDPAGE", u1RsvdPageLoc, 3);
+				"H2C_RSVDPAGE:\n",
+				u1rsvdpageloc, 3);
 		rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
-				    sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
+				    sizeof(u1rsvdpageloc), u1rsvdpageloc);
 	} else
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-			 "Set RSVD page location to Fw FAIL!!!!!!\n");
+			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
 }
 EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
 
 void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
 {
-	u8 u1_joinbssrpt_parm[1] = {0};
+	u8 u1_joinbssrpt_parm[1] = { 0 };
 
 	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
 
@@ -813,11 +753,51 @@
 
 static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
 {
-	u8 u1_ctwindow_period[1] = {ctwindow};
+	u8 u1_ctwindow_period[1] = { ctwindow};
 
 	rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
 }
 
+/* refactored routine */
+static void set_noa_data(struct rtl_priv *rtlpriv,
+			 struct rtl_p2p_ps_info *p2pinfo,
+			 struct p2p_ps_offload_t *p2p_ps_offload)
+{
+	int i;
+	u32	start_time, tsf_low;
+
+	/* hw only support 2 set of NoA */
+	for (i = 0 ; i < p2pinfo->noa_num ; i++) {
+		/* To control the reg setting for which NOA*/
+		rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
+		if (i == 0)
+			p2p_ps_offload->noa0_en = 1;
+		else
+			p2p_ps_offload->noa1_en = 1;
+
+		/* config P2P NoA Descriptor Register */
+		rtl_write_dword(rtlpriv, 0x5E0,
+				p2pinfo->noa_duration[i]);
+		rtl_write_dword(rtlpriv, 0x5E4,
+				p2pinfo->noa_interval[i]);
+
+		/*Get Current TSF value */
+		tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+		start_time = p2pinfo->noa_start_time[i];
+		if (p2pinfo->noa_count_type[i] != 1) {
+			while (start_time <= (tsf_low+(50*1024))) {
+				start_time += p2pinfo->noa_interval[i];
+				if (p2pinfo->noa_count_type[i] != 255)
+					p2pinfo->noa_count_type[i]--;
+			}
+		}
+		rtl_write_dword(rtlpriv, 0x5E8, start_time);
+		rtl_write_dword(rtlpriv, 0x5EC,
+				p2pinfo->noa_count_type[i]);
+	}
+}
+
 void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -825,83 +805,58 @@
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
 	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
-	u8	i;
 	u16	ctwindow;
-	u32	start_time, tsf_low;
 
 	switch (p2p_ps_state) {
 	case P2P_PS_DISABLE:
-		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
-		memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
-		break;
+			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+				 "P2P_PS_DISABLE\n");
+			memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
+			break;
 	case P2P_PS_ENABLE:
-		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
-		/* update CTWindow value. */
-		if (p2pinfo->ctwindow > 0) {
-			p2p_ps_offload->ctwindow_en = 1;
-			ctwindow = p2pinfo->ctwindow;
-			rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow);
-		}
-		/* hw only support 2 set of NoA */
-		for (i = 0; i < p2pinfo->noa_num; i++) {
-			/* To control the register setting for which NOA*/
-			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
-			if (i == 0)
-				p2p_ps_offload->noa0_en = 1;
-			else
-				p2p_ps_offload->noa1_en = 1;
+			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+				 "P2P_PS_ENABLE\n");
+			/* update CTWindow value. */
+			if (p2pinfo->ctwindow > 0) {
+				p2p_ps_offload->ctwindow_en = 1;
+				ctwindow = p2pinfo->ctwindow;
+				rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow);
+			}
+			/* call refactored routine */
+			set_noa_data(rtlpriv, p2pinfo, p2p_ps_offload);
 
-			/* config P2P NoA Descriptor Register */
-			rtl_write_dword(rtlpriv, 0x5E0,
-					p2pinfo->noa_duration[i]);
-			rtl_write_dword(rtlpriv, 0x5E4,
-					p2pinfo->noa_interval[i]);
+			if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
+				/* rst p2p circuit */
+				rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST,
+					       BIT(4));
 
-			/*Get Current TSF value */
-			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+				p2p_ps_offload->offload_en = 1;
 
-			start_time = p2pinfo->noa_start_time[i];
-			if (p2pinfo->noa_count_type[i] != 1) {
-				while (start_time <= (tsf_low+(50*1024))) {
-					start_time += p2pinfo->noa_interval[i];
-					if (p2pinfo->noa_count_type[i] != 255)
-						p2pinfo->noa_count_type[i]--;
+				if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
+					p2p_ps_offload->role = 1;
+					p2p_ps_offload->allstasleep = 0;
+				} else {
+					p2p_ps_offload->role = 0;
 				}
+
+				p2p_ps_offload->discovery = 0;
 			}
-			rtl_write_dword(rtlpriv, 0x5E8, start_time);
-			rtl_write_dword(rtlpriv, 0x5EC,
-					p2pinfo->noa_count_type[i]);
-		}
-
-		if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
-			/* rst p2p circuit */
-			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
-
-			p2p_ps_offload->offload_en = 1;
-
-			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
-				p2p_ps_offload->role = 1;
-				p2p_ps_offload->allstasleep = 0;
-			} else {
-				p2p_ps_offload->role = 0;
-			}
-
-			p2p_ps_offload->discovery = 0;
-		}
-		break;
+			break;
 	case P2P_PS_SCAN:
-		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
-		p2p_ps_offload->discovery = 1;
-		break;
+			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
+			p2p_ps_offload->discovery = 1;
+			break;
 	case P2P_PS_SCAN_DONE:
-		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
-		p2p_ps_offload->discovery = 0;
-		p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
-		break;
+			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+				 "P2P_PS_SCAN_DONE\n");
+			p2p_ps_offload->discovery = 0;
+			p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
+			break;
 	default:
-		break;
+			break;
 	}
 
 	rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
+
 }
 EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
index 15b2055..a815bd6 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
@@ -36,11 +36,38 @@
 #define FW_8192C_PAGE_SIZE			4096
 #define FW_8192C_POLLING_DELAY			5
 #define FW_8192C_POLLING_TIMEOUT_COUNT		100
+#define NORMAL_CHIP				BIT(4)
 
 #define IS_FW_HEADER_EXIST(_pfwhdr)	\
 	((le16_to_cpu(_pfwhdr->signature)&0xFFF0) == 0x92C0 ||\
 	(le16_to_cpu(_pfwhdr->signature)&0xFFF0) == 0x88C0)
 
+#define CUT_VERSION_MASK		(BIT(6)|BIT(7))
+#define CHIP_VENDOR_UMC			BIT(5)
+#define CHIP_VENDOR_UMC_B_CUT		BIT(6) /* Chip version for ECO */
+#define IS_CHIP_VER_B(version)  ((version & CHIP_VER_B) ? true : false)
+#define RF_TYPE_MASK			(BIT(0)|BIT(1))
+#define GET_CVID_RF_TYPE(version)	\
+	((version) & RF_TYPE_MASK)
+#define GET_CVID_CUT_VERSION(version) \
+	((version) & CUT_VERSION_MASK)
+#define IS_NORMAL_CHIP(version)	\
+	((version & NORMAL_CHIP) ? true : false)
+#define IS_2T2R(version) \
+	(((GET_CVID_RF_TYPE(version)) == \
+	CHIP_92C_BITMASK) ? true : false)
+#define IS_92C_SERIAL(version) \
+	((IS_2T2R(version)) ? true : false)
+#define IS_CHIP_VENDOR_UMC(version)	\
+	((version & CHIP_VENDOR_UMC) ? true : false)
+#define IS_VENDOR_UMC_A_CUT(version) \
+	((IS_CHIP_VENDOR_UMC(version)) ? \
+	((GET_CVID_CUT_VERSION(version)) ? false : true) : false)
+#define IS_81XXC_VENDOR_UMC_B_CUT(version)	\
+	((IS_CHIP_VENDOR_UMC(version)) ? \
+	((GET_CVID_CUT_VERSION(version) == \
+		CHIP_VENDOR_UMC_B_CUT) ? true : false) : false)
+
 struct rtl92c_firmware_header {
 	__le16 signature;
 	u8 category;
@@ -60,19 +87,6 @@
 	__le32 rsvd5;
 };
 
-enum rtl8192c_h2c_cmd {
-	H2C_AP_OFFLOAD = 0,
-	H2C_SETPWRMODE = 1,
-	H2C_JOINBSSRPT = 2,
-	H2C_RSVDPAGE = 3,
-	H2C_RSSI_REPORT = 5,
-	H2C_RA_MASK = 6,
-	H2C_MACID_PS_MODE = 7,
-	H2C_P2P_PS_OFFLOAD = 8,
-	H2C_P2P_PS_CTW_CMD = 32,
-	MAX_H2CCMD
-};
-
 #define pagenum_128(_len)	(u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0))
 
 #define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val)			\
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
index 9e32ac8..77e61b1 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
@@ -27,12 +27,13 @@
  *
  *****************************************************************************/
 
-#include <linux/export.h>
 #include "../wifi.h"
 #include "../rtl8192ce/reg.h"
 #include "../rtl8192ce/def.h"
 #include "dm_common.h"
+#include "fw_common.h"
 #include "phy_common.h"
+#include <linux/export.h>
 
 u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
 {
@@ -50,7 +51,6 @@
 		 bitmask, regaddr, originalvalue);
 
 	return returnvalue;
-
 }
 EXPORT_SYMBOL(rtl92c_phy_query_bb_reg);
 
@@ -75,7 +75,6 @@
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
 		 "regaddr(%#x), bitmask(%#x), data(%#x)\n",
 		 regaddr, bitmask, data);
-
 }
 EXPORT_SYMBOL(rtl92c_phy_set_bb_reg);
 
@@ -84,7 +83,6 @@
 {
 	RT_ASSERT(false, "deprecated!\n");
 	return 0;
-
 }
 EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_read);
 
@@ -129,10 +127,10 @@
 		      tmplong | BLSSIREADEDGE);
 	mdelay(1);
 	if (rfpath == RF90_PATH_A)
-		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
+		rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
 						 BIT(8));
 	else if (rfpath == RF90_PATH_B)
-		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
+		rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
 						 BIT(8));
 	if (rfpi_enable)
 		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,
@@ -141,7 +139,8 @@
 		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
 					 BLSSIREADBACKDATA);
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n",
-		 rfpath, pphyreg->rf_rb, retvalue);
+					       rfpath, pphyreg->rf_rb,
+					       retvalue);
 	return retvalue;
 }
 EXPORT_SYMBOL(_rtl92c_phy_rf_serial_read);
@@ -165,7 +164,8 @@
 	data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
 	rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n",
-		 rfpath, pphyreg->rf3wire_offset, data_and_addr);
+					       rfpath, pphyreg->rf3wire_offset,
+					       data_and_addr);
 }
 EXPORT_SYMBOL(_rtl92c_phy_rf_serial_write);
 
@@ -174,7 +174,7 @@
 	u32 i;
 
 	for (i = 0; i <= 31; i++) {
-		if ((bitmask >> i) & 0x1)
+		if (((bitmask >> i) & 0x1) == 1)
 			break;
 	}
 	return i;
@@ -210,11 +210,10 @@
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	bool rtstatus;
 
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "==>\n");
 	rtstatus = rtlpriv->cfg->ops->config_bb_with_headerfile(hw,
 						 BASEBAND_CONFIG_PHY_REG);
 	if (!rtstatus) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!\n");
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!");
 		return false;
 	}
 	if (rtlphy->rf_type == RF_1T2R) {
@@ -227,7 +226,7 @@
 						   BASEBAND_CONFIG_PHY_REG);
 	}
 	if (!rtstatus) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!\n");
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!");
 		return false;
 	}
 	rtstatus = rtlpriv->cfg->ops->config_bb_with_headerfile(hw,
@@ -236,12 +235,12 @@
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
 		return false;
 	}
-	rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw,
-						RFPGA0_XA_HSSIPARAMETER2,
-						0x200));
+	rtlphy->cck_high_power =
+		(bool)(rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, 0x200));
 
 	return true;
 }
+
 EXPORT_SYMBOL(_rtl92c_phy_bb8192c_config_parafile);
 
 void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
@@ -250,51 +249,153 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	int index;
 
-	if (regaddr == RTXAGC_A_RATE18_06)
-		index = 0;
-	else if (regaddr == RTXAGC_A_RATE54_24)
-		index = 1;
-	else if (regaddr == RTXAGC_A_CCK1_MCS32)
-		index = 6;
-	else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00)
-		index = 7;
-	else if (regaddr == RTXAGC_A_MCS03_MCS00)
-		index = 2;
-	else if (regaddr == RTXAGC_A_MCS07_MCS04)
-		index = 3;
-	else if (regaddr == RTXAGC_A_MCS11_MCS08)
-		index = 4;
-	else if (regaddr == RTXAGC_A_MCS15_MCS12)
-		index = 5;
-	else if (regaddr == RTXAGC_B_RATE18_06)
-		index = 8;
-	else if (regaddr == RTXAGC_B_RATE54_24)
-		index = 9;
-	else if (regaddr == RTXAGC_B_CCK1_55_MCS32)
-		index = 14;
-	else if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff)
-		index = 15;
-	else if (regaddr == RTXAGC_B_MCS03_MCS00)
-		index = 10;
-	else if (regaddr == RTXAGC_B_MCS07_MCS04)
-		index = 11;
-	else if (regaddr == RTXAGC_B_MCS11_MCS08)
-		index = 12;
-	else if (regaddr == RTXAGC_B_MCS15_MCS12)
-		index = 13;
-	else
-		return;
+	if (regaddr == RTXAGC_A_RATE18_06) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][0]);
+	}
+	if (regaddr == RTXAGC_A_RATE54_24) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][1]);
+	}
+	if (regaddr == RTXAGC_A_CCK1_MCS32) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][6]);
+	}
+	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][7] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][7]);
+	}
+	if (regaddr == RTXAGC_A_MCS03_MCS00) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][2]);
+	}
+	if (regaddr == RTXAGC_A_MCS07_MCS04) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][3]);
+	}
+	if (regaddr == RTXAGC_A_MCS11_MCS08) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][4]);
+	}
+	if (regaddr == RTXAGC_A_MCS15_MCS12) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][5]);
+	}
+	if (regaddr == RTXAGC_B_RATE18_06) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][8] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][8]);
+	}
+	if (regaddr == RTXAGC_B_RATE54_24) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][9] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][9]);
+	}
+	if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][14] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][14]);
+	}
+	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][15] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][15]);
+	}
+	if (regaddr == RTXAGC_B_MCS03_MCS00) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][10] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][10]);
+	}
+	if (regaddr == RTXAGC_B_MCS07_MCS04) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][11] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][11]);
+	}
+	if (regaddr == RTXAGC_B_MCS11_MCS08) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][12] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][12]);
+	}
+	if (regaddr == RTXAGC_B_MCS15_MCS12) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][13] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][13]);
 
-	rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index] = data;
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-		 "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n",
-		 rtlphy->pwrgroup_cnt, index,
-		 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index]);
-
-	if (index == 13)
 		rtlphy->pwrgroup_cnt++;
+	}
 }
 EXPORT_SYMBOL(_rtl92c_store_pwrIndex_diffrate_offset);
 
@@ -304,29 +405,29 @@
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 
 	rtlphy->default_initialgain[0] =
-	    (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
 	rtlphy->default_initialgain[1] =
-	    (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
 	rtlphy->default_initialgain[2] =
-	    (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
 	rtlphy->default_initialgain[3] =
-	    (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 		 "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x\n",
-		 rtlphy->default_initialgain[0],
-		 rtlphy->default_initialgain[1],
-		 rtlphy->default_initialgain[2],
-		 rtlphy->default_initialgain[3]);
+		  rtlphy->default_initialgain[0],
+		  rtlphy->default_initialgain[1],
+		  rtlphy->default_initialgain[2],
+		  rtlphy->default_initialgain[3]);
 
-	rtlphy->framesync = (u8) rtl_get_bbreg(hw,
+	rtlphy->framesync = (u8)rtl_get_bbreg(hw,
 					       ROFDM0_RXDETECTOR3, MASKBYTE0);
 	rtlphy->framesync_c34 = rtl_get_bbreg(hw,
 					      ROFDM0_RXDETECTOR2, MASKDWORD);
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 		 "Default framesync (0x%x) = 0x%x\n",
-		 ROFDM0_RXDETECTOR3, rtlphy->framesync);
+		  ROFDM0_RXDETECTOR3, rtlphy->framesync);
 }
 
 void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
@@ -426,19 +527,17 @@
 	long txpwr_dbm;
 
 	txpwr_level = rtlphy->cur_cck_txpwridx;
-	txpwr_dbm = _rtl92c_phy_txpwr_idx_to_dbm(hw,
-						 WIRELESS_MODE_B, txpwr_level);
+	txpwr_dbm = _rtl92c_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B,
+						 txpwr_level);
 	txpwr_level = rtlphy->cur_ofdm24g_txpwridx +
 	    rtlefuse->legacy_ht_txpowerdiff;
-	if (_rtl92c_phy_txpwr_idx_to_dbm(hw,
-					 WIRELESS_MODE_G,
+	if (_rtl92c_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
 					 txpwr_level) > txpwr_dbm)
 		txpwr_dbm =
 		    _rtl92c_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
 						 txpwr_level);
 	txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
-	if (_rtl92c_phy_txpwr_idx_to_dbm(hw,
-					 WIRELESS_MODE_N_24G,
+	if (_rtl92c_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
 					 txpwr_level) > txpwr_dbm)
 		txpwr_dbm =
 		    _rtl92c_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
@@ -480,21 +579,19 @@
 
 	rtlphy->cur_cck_txpwridx = cckpowerlevel[0];
 	rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0];
-
 }
 
 void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	u8 cckpowerlevel[2], ofdmpowerlevel[2];
 
 	if (!rtlefuse->txpwr_fromeprom)
 		return;
 	_rtl92c_get_txpower_index(hw, channel,
 				  &cckpowerlevel[0], &ofdmpowerlevel[0]);
-	_rtl92c_ccxpower_index_check(hw,
-				     channel, &cckpowerlevel[0],
+	_rtl92c_ccxpower_index_check(hw, channel, &cckpowerlevel[0],
 				     &ofdmpowerlevel[0]);
 	rtlpriv->cfg->ops->phy_rf6052_set_cck_txpower(hw, &cckpowerlevel[0]);
 	rtlpriv->cfg->ops->phy_rf6052_set_ofdm_txpower(hw, &ofdmpowerlevel[0],
@@ -509,11 +606,9 @@
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	u8 idx;
 	u8 rf_path;
-	u8 ccktxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw,
-						      WIRELESS_MODE_B,
+	u8 ccktxpwridx = _rtl92c_phy_dbm_to_txpwr_idx(hw, WIRELESS_MODE_B,
 						      power_indbm);
-	u8 ofdmtxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw,
-						       WIRELESS_MODE_N_24G,
+	u8 ofdmtxpwridx = _rtl92c_phy_dbm_to_txpwr_idx(hw, WIRELESS_MODE_N_24G,
 						       power_indbm);
 	if (ofdmtxpwridx - rtlefuse->legacy_ht_txpowerdiff > 0)
 		ofdmtxpwridx -= rtlefuse->legacy_ht_txpowerdiff;
@@ -521,7 +616,7 @@
 		ofdmtxpwridx = 0;
 	RT_TRACE(rtlpriv, COMP_TXAGC, DBG_TRACE,
 		 "%lx dBm, ccktxpwridx = %d, ofdmtxpwridx = %d\n",
-		 power_indbm, ccktxpwridx, ofdmtxpwridx);
+		  power_indbm, ccktxpwridx, ofdmtxpwridx);
 	for (idx = 0; idx < 14; idx++) {
 		for (rf_path = 0; rf_path < 2; rf_path++) {
 			rtlefuse->txpwrlevel_cck[rf_path][idx] = ccktxpwridx;
@@ -536,7 +631,7 @@
 }
 EXPORT_SYMBOL(rtl92c_phy_update_txpower_dbm);
 
-u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
+u8 _rtl92c_phy_dbm_to_txpwr_idx(struct ieee80211_hw *hw,
 				enum wireless_mode wirelessmode,
 				long power_indbm)
 {
@@ -557,7 +652,7 @@
 	}
 
 	if ((power_indbm - offset) > 0)
-		txpwridx = (u8) ((power_indbm - offset) * 2);
+		txpwridx = (u8)((power_indbm - offset) * 2);
 	else
 		txpwridx = 0;
 
@@ -566,7 +661,7 @@
 
 	return txpwridx;
 }
-EXPORT_SYMBOL(_rtl92c_phy_dbm_to_txpwr_Idx);
+EXPORT_SYMBOL(_rtl92c_phy_dbm_to_txpwr_idx);
 
 long _rtl92c_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
 				  enum wireless_mode wirelessmode,
@@ -607,7 +702,7 @@
 		rtlpriv->cfg->ops->phy_set_bw_mode_callback(hw);
 	} else {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-			 "FALSE driver sleep or unload\n");
+			 "false driver sleep or unload\n");
 		rtlphy->set_bwmode_inprogress = false;
 		rtlphy->current_chan_bw = tmp_bw;
 	}
@@ -640,7 +735,7 @@
 		}
 		break;
 	} while (true);
-	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n");
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "\n");
 }
 EXPORT_SYMBOL(rtl92c_phy_sw_chnl_callback);
 
@@ -655,14 +750,14 @@
 	if (rtlphy->set_bwmode_inprogress)
 		return 0;
 	RT_ASSERT((rtlphy->current_channel <= 14),
-		  "WIRELESS_MODE_G but channel>14\n");
+		  "WIRELESS_MODE_G but channel>14");
 	rtlphy->sw_chnl_inprogress = true;
 	rtlphy->sw_chnl_stage = 0;
 	rtlphy->sw_chnl_step = 0;
 	if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
 		rtl92c_phy_sw_chnl_callback(hw);
 		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
-			 "sw_chnl_inprogress false schedule workitem\n");
+			 "sw_chnl_inprogress false schdule workitem\n");
 		rtlphy->sw_chnl_inprogress = false;
 	} else {
 		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
@@ -673,22 +768,22 @@
 }
 EXPORT_SYMBOL(rtl92c_phy_sw_chnl);
 
-static void _rtl92c_phy_sw_rf_setting(struct ieee80211_hw *hw, u8 channel)
+static void _rtl92c_phy_sw_rf_seting(struct ieee80211_hw *hw, u8 channel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-
-	if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) {
-		if (channel == 6 && rtlphy->current_chan_bw ==
-		    HT_CHANNEL_WIDTH_20)
+	if (IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version)) {
+		if (channel == 6 &&
+		    rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {
+			rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1,
+				      MASKDWORD, 0x00255);
+		} else {
+			u32 backuprf0x1A =
+			  (u32)rtl_get_rfreg(hw, RF90_PATH_A, RF_RX_G1,
+					     RFREG_OFFSET_MASK);
 			rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD,
-				      0x00255);
-		else{
-			u32 backupRF0x1A = (u32)rtl_get_rfreg(hw, RF90_PATH_A,
-					    RF_RX_G1, RFREG_OFFSET_MASK);
-			rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD,
-				      backupRF0x1A);
+				      backuprf0x1A);
 		}
 	}
 }
@@ -701,7 +796,7 @@
 	struct swchnlcmd *pcmd;
 
 	if (cmdtable == NULL) {
-		RT_ASSERT(false, "cmdtable cannot be NULL\n");
+		RT_ASSERT(false, "cmdtable cannot be NULL.\n");
 		return false;
 	}
 
@@ -747,7 +842,7 @@
 	rfdependcmdcnt = 0;
 
 	RT_ASSERT((channel >= 1 && channel <= 14),
-		  "invalid channel for Zebra: %d\n", channel);
+		  "illegal channel for Zebra: %d\n", channel);
 
 	_rtl92c_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
 					 MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
@@ -768,6 +863,10 @@
 		case 2:
 			currentcmd = &postcommoncmd[*step];
 			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "Invalid 'stage' = %d, Check it!\n", *stage);
+			return true;
 		}
 
 		if (currentcmd->cmdid == CMDID_END) {
@@ -794,7 +893,7 @@
 			break;
 		case CMDID_WRITEPORT_UCHAR:
 			rtl_write_byte(rtlpriv, currentcmd->para1,
-				       (u8) currentcmd->para2);
+				       (u8)currentcmd->para2);
 			break;
 		case CMDID_RF_WRITEREG:
 			for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
@@ -806,12 +905,12 @@
 					      currentcmd->para1,
 					      RFREG_OFFSET_MASK,
 					      rtlphy->rfreg_chnlval[rfpath]);
-			_rtl92c_phy_sw_rf_setting(hw, channel);
 			}
+			_rtl92c_phy_sw_rf_seting(hw, channel);
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
 			break;
 		}
 
@@ -900,7 +999,7 @@
 }
 
 static void _rtl92c_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw,
-					       bool iqk_ok, long result[][8],
+					       bool b_iqk_ok, long result[][8],
 					       u8 final_candidate, bool btxonly)
 {
 	u32 oldval_0, x, tx0_a, reg;
@@ -908,7 +1007,7 @@
 
 	if (final_candidate == 0xFF) {
 		return;
-	} else if (iqk_ok) {
+	} else if (b_iqk_ok) {
 		oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
 					  MASKDWORD) >> 22) & 0x3FF;
 		x = result[final_candidate][0];
@@ -940,7 +1039,7 @@
 }
 
 static void _rtl92c_phy_path_b_fill_iqk_matrix(struct ieee80211_hw *hw,
-					       bool iqk_ok, long result[][8],
+					       bool b_iqk_ok, long result[][8],
 					       u8 final_candidate, bool btxonly)
 {
 	u32 oldval_1, x, tx1_a, reg;
@@ -948,7 +1047,7 @@
 
 	if (final_candidate == 0xFF) {
 		return;
-	} else if (iqk_ok) {
+	} else if (b_iqk_ok) {
 		oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE,
 					  MASKDWORD) >> 22) & 0x3FF;
 		x = result[final_candidate][4];
@@ -1017,7 +1116,7 @@
 	u32 i;
 
 	for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
-		rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]);
+		rtl_write_byte(rtlpriv, macreg[i], (u8)macbackup[i]);
 	rtl_write_dword(rtlpriv, macreg[i], macbackup[i]);
 }
 
@@ -1043,14 +1142,14 @@
 						u32 *macreg, u32 *macbackup)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 i;
+	u32 i = 0;
 
-	rtl_write_byte(rtlpriv, macreg[0], 0x3F);
+	rtl_write_byte(rtlpriv, macreg[i], 0x3F);
 
 	for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++)
 		rtl_write_byte(rtlpriv, macreg[i],
-			       (u8) (macbackup[i] & (~BIT(3))));
-	rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5))));
+			       (u8)(macbackup[i] & (~BIT(3))));
+	rtl_write_byte(rtlpriv, macreg[i], (u8)(macbackup[i] & (~BIT(5))));
 }
 
 static void _rtl92c_phy_path_a_standby(struct ieee80211_hw *hw)
@@ -1126,7 +1225,6 @@
 	} else {
 		return false;
 	}
-
 }
 
 static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
@@ -1142,51 +1240,37 @@
 		0xe88, 0xe8c, 0xed0, 0xed4,
 		0xed8, 0xedc, 0xee0, 0xeec
 	};
-
 	u32 iqk_mac_reg[IQK_MAC_REG_NUM] = {
 		0x522, 0x550, 0x551, 0x040
 	};
-
-	u32 iqk_bb_reg_92C[9] = {
-		0xc04, 0xc08, 0x874, 0xb68,
-		0xb6c, 0x870, 0x860, 0x864,
-		0x800
-	};
-
 	const u32 retrycount = 2;
+	u32 bbvalue;
 
 	if (t == 0) {
-		/* dummy read */
-		rtl_get_bbreg(hw, 0x800, MASKDWORD);
+		bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD);
 
 		_rtl92c_phy_save_adda_registers(hw, adda_reg,
 						rtlphy->adda_backup, 16);
 		_rtl92c_phy_save_mac_registers(hw, iqk_mac_reg,
 					       rtlphy->iqk_mac_backup);
-		_rtl92c_phy_save_adda_registers(hw, iqk_bb_reg_92C,
-						rtlphy->iqk_bb_backup, 9);
 	}
 	_rtl92c_phy_path_adda_on(hw, adda_reg, true, is2t);
 	if (t == 0) {
-		rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw,
-						   RFPGA0_XA_HSSIPARAMETER1,
-						   BIT(8));
+		rtlphy->rfpi_enable =
+		   (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
+				     BIT(8));
 	}
 
 	if (!rtlphy->rfpi_enable)
 		_rtl92c_phy_pi_mode_switch(hw, true);
-
-	rtl_set_bbreg(hw, 0x800, BIT(24), 0x0);
-
+	if (t == 0) {
+		rtlphy->reg_c04 = rtl_get_bbreg(hw, 0xc04, MASKDWORD);
+		rtlphy->reg_c08 = rtl_get_bbreg(hw, 0xc08, MASKDWORD);
+		rtlphy->reg_874 = rtl_get_bbreg(hw, 0x874, MASKDWORD);
+	}
 	rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600);
 	rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4);
 	rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000);
-
-	rtl_set_bbreg(hw, 0x870, BIT(10), 0x1);
-	rtl_set_bbreg(hw, 0x870, BIT(26), 0x1);
-	rtl_set_bbreg(hw, 0x860, BIT(10), 0x0);
-	rtl_set_bbreg(hw, 0x864, BIT(10), 0x0);
-
 	if (is2t) {
 		rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
 		rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000);
@@ -1228,8 +1312,8 @@
 			pathb_ok = _rtl92c_phy_path_b_iqk(hw);
 			if (pathb_ok == 0x03) {
 				result[t][4] = (rtl_get_bbreg(hw,
-						      0xeb4,
-						      MASKDWORD) &
+							      0xeb4,
+							      MASKDWORD) &
 						0x3FF0000) >> 16;
 				result[t][5] =
 				    (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
@@ -1243,17 +1327,21 @@
 				break;
 			} else if (i == (retrycount - 1) && pathb_ok == 0x01) {
 				result[t][4] = (rtl_get_bbreg(hw,
-						      0xeb4,
-						      MASKDWORD) &
+							      0xeb4,
+							      MASKDWORD) &
 						0x3FF0000) >> 16;
 			}
 			result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
 					0x3FF0000) >> 16;
 		}
 	}
-
+	rtl_set_bbreg(hw, 0xc04, MASKDWORD, rtlphy->reg_c04);
+	rtl_set_bbreg(hw, 0x874, MASKDWORD, rtlphy->reg_874);
+	rtl_set_bbreg(hw, 0xc08, MASKDWORD, rtlphy->reg_c08);
 	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
-
+	rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3);
+	if (is2t)
+		rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3);
 	if (t != 0) {
 		if (!rtlphy->rfpi_enable)
 			_rtl92c_phy_pi_mode_switch(hw, false);
@@ -1261,379 +1349,12 @@
 						  rtlphy->adda_backup, 16);
 		_rtl92c_phy_reload_mac_registers(hw, iqk_mac_reg,
 						 rtlphy->iqk_mac_backup);
-		_rtl92c_phy_reload_adda_registers(hw, iqk_bb_reg_92C,
-						  rtlphy->iqk_bb_backup, 9);
-
-		rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3);
-		if (is2t)
-			rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3);
-
-		rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00);
-		rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00);
 	}
 }
 
 static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw,
 				     char delta, bool is2t)
 {
-#if 0 /* This routine is deliberately dummied out for later fixes */
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
-
-	u32 reg_d[PATH_NUM];
-	u32 tmpreg, index, offset, path, i, pathbound = PATH_NUM, apkbound;
-
-	u32 bb_backup[APK_BB_REG_NUM];
-	u32 bb_reg[APK_BB_REG_NUM] = {
-		0x904, 0xc04, 0x800, 0xc08, 0x874
-	};
-	u32 bb_ap_mode[APK_BB_REG_NUM] = {
-		0x00000020, 0x00a05430, 0x02040000,
-		0x000800e4, 0x00204000
-	};
-	u32 bb_normal_ap_mode[APK_BB_REG_NUM] = {
-		0x00000020, 0x00a05430, 0x02040000,
-		0x000800e4, 0x22204000
-	};
-
-	u32 afe_backup[APK_AFE_REG_NUM];
-	u32 afe_reg[APK_AFE_REG_NUM] = {
-		0x85c, 0xe6c, 0xe70, 0xe74, 0xe78,
-		0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c,
-		0xed0, 0xed4, 0xed8, 0xedc, 0xee0,
-		0xeec
-	};
-
-	u32 mac_backup[IQK_MAC_REG_NUM];
-	u32 mac_reg[IQK_MAC_REG_NUM] = {
-		0x522, 0x550, 0x551, 0x040
-	};
-
-	u32 apk_rf_init_value[PATH_NUM][APK_BB_REG_NUM] = {
-		{0x0852c, 0x1852c, 0x5852c, 0x1852c, 0x5852c},
-		{0x2852e, 0x0852e, 0x3852e, 0x0852e, 0x0852e}
-	};
-
-	u32 apk_normal_rf_init_value[PATH_NUM][APK_BB_REG_NUM] = {
-		{0x0852c, 0x0a52c, 0x3a52c, 0x5a52c, 0x5a52c},
-		{0x0852c, 0x0a52c, 0x5a52c, 0x5a52c, 0x5a52c}
-	};
-
-	u32 apk_rf_value_0[PATH_NUM][APK_BB_REG_NUM] = {
-		{0x52019, 0x52014, 0x52013, 0x5200f, 0x5208d},
-		{0x5201a, 0x52019, 0x52016, 0x52033, 0x52050}
-	};
-
-	u32 apk_normal_rf_value_0[PATH_NUM][APK_BB_REG_NUM] = {
-		{0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a},
-		{0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}
-	};
-
-	u32 afe_on_off[PATH_NUM] = {
-		0x04db25a4, 0x0b1b25a4
-	};
-
-	const u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c };
-
-	u32 apk_normal_offset[PATH_NUM] = { 0xb28, 0xb98 };
-
-	u32 apk_value[PATH_NUM] = { 0x92fc0000, 0x12fc0000 };
-
-	u32 apk_normal_value[PATH_NUM] = { 0x92680000, 0x12680000 };
-
-	const char apk_delta_mapping[APK_BB_REG_NUM][13] = {
-		{-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6},
-		{-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6},
-		{-6, -4, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6},
-		{-1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6},
-		{-11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0}
-	};
-
-	const u32 apk_normal_setting_value_1[13] = {
-		0x01017018, 0xf7ed8f84, 0x1b1a1816, 0x2522201e, 0x322e2b28,
-		0x433f3a36, 0x5b544e49, 0x7b726a62, 0xa69a8f84, 0xdfcfc0b3,
-		0x12680000, 0x00880000, 0x00880000
-	};
-
-	const u32 apk_normal_setting_value_2[16] = {
-		0x01c7021d, 0x01670183, 0x01000123, 0x00bf00e2, 0x008d00a3,
-		0x0068007b, 0x004d0059, 0x003a0042, 0x002b0031, 0x001f0025,
-		0x0017001b, 0x00110014, 0x000c000f, 0x0009000b, 0x00070008,
-		0x00050006
-	};
-
-	u32 apk_result[PATH_NUM][APK_BB_REG_NUM];
-
-	long bb_offset, delta_v, delta_offset;
-
-	if (!is2t)
-		pathbound = 1;
-
-	return;
-
-	for (index = 0; index < PATH_NUM; index++) {
-		apk_offset[index] = apk_normal_offset[index];
-		apk_value[index] = apk_normal_value[index];
-		afe_on_off[index] = 0x6fdb25a4;
-	}
-
-	for (index = 0; index < APK_BB_REG_NUM; index++) {
-		for (path = 0; path < pathbound; path++) {
-			apk_rf_init_value[path][index] =
-			    apk_normal_rf_init_value[path][index];
-			apk_rf_value_0[path][index] =
-			    apk_normal_rf_value_0[path][index];
-		}
-		bb_ap_mode[index] = bb_normal_ap_mode[index];
-
-		apkbound = 6;
-	}
-
-	for (index = 0; index < APK_BB_REG_NUM; index++) {
-		if (index == 0)
-			continue;
-		bb_backup[index] = rtl_get_bbreg(hw, bb_reg[index], MASKDWORD);
-	}
-
-	_rtl92c_phy_save_mac_registers(hw, mac_reg, mac_backup);
-
-	_rtl92c_phy_save_adda_registers(hw, afe_reg, afe_backup, 16);
-
-	for (path = 0; path < pathbound; path++) {
-		if (path == RF90_PATH_A) {
-			offset = 0xb00;
-			for (index = 0; index < 11; index++) {
-				rtl_set_bbreg(hw, offset, MASKDWORD,
-					      apk_normal_setting_value_1
-					      [index]);
-
-				offset += 0x04;
-			}
-
-			rtl_set_bbreg(hw, 0xb98, MASKDWORD, 0x12680000);
-
-			offset = 0xb68;
-			for (; index < 13; index++) {
-				rtl_set_bbreg(hw, offset, MASKDWORD,
-					      apk_normal_setting_value_1
-					      [index]);
-
-				offset += 0x04;
-			}
-
-			rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x40000000);
-
-			offset = 0xb00;
-			for (index = 0; index < 16; index++) {
-				rtl_set_bbreg(hw, offset, MASKDWORD,
-					      apk_normal_setting_value_2
-					      [index]);
-
-				offset += 0x04;
-			}
-			rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000);
-		} else if (path == RF90_PATH_B) {
-			offset = 0xb70;
-			for (index = 0; index < 10; index++) {
-				rtl_set_bbreg(hw, offset, MASKDWORD,
-					      apk_normal_setting_value_1
-					      [index]);
-
-				offset += 0x04;
-			}
-			rtl_set_bbreg(hw, 0xb28, MASKDWORD, 0x12680000);
-			rtl_set_bbreg(hw, 0xb98, MASKDWORD, 0x12680000);
-
-			offset = 0xb68;
-			index = 11;
-			for (; index < 13; index++) {
-				rtl_set_bbreg(hw, offset, MASKDWORD,
-					      apk_normal_setting_value_1
-					      [index]);
-
-				offset += 0x04;
-			}
-
-			rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x40000000);
-
-			offset = 0xb60;
-			for (index = 0; index < 16; index++) {
-				rtl_set_bbreg(hw, offset, MASKDWORD,
-					      apk_normal_setting_value_2
-					      [index]);
-
-				offset += 0x04;
-			}
-			rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000);
-		}
-
-		reg_d[path] = rtl_get_rfreg(hw, (enum radio_path)path,
-					    0xd, MASKDWORD);
-
-		for (index = 0; index < APK_AFE_REG_NUM; index++)
-			rtl_set_bbreg(hw, afe_reg[index], MASKDWORD,
-				      afe_on_off[path]);
-
-		if (path == RF90_PATH_A) {
-			for (index = 0; index < APK_BB_REG_NUM; index++) {
-				if (index == 0)
-					continue;
-				rtl_set_bbreg(hw, bb_reg[index], MASKDWORD,
-					      bb_ap_mode[index]);
-			}
-		}
-
-		_rtl92c_phy_mac_setting_calibration(hw, mac_reg, mac_backup);
-
-		if (path == 0) {
-			rtl_set_rfreg(hw, RF90_PATH_B, 0x0, MASKDWORD, 0x10000);
-		} else {
-			rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASKDWORD,
-				      0x10000);
-			rtl_set_rfreg(hw, RF90_PATH_A, 0x10, MASKDWORD,
-				      0x1000f);
-			rtl_set_rfreg(hw, RF90_PATH_A, 0x11, MASKDWORD,
-				      0x20103);
-		}
-
-		delta_offset = ((delta + 14) / 2);
-		if (delta_offset < 0)
-			delta_offset = 0;
-		else if (delta_offset > 12)
-			delta_offset = 12;
-
-		for (index = 0; index < APK_BB_REG_NUM; index++) {
-			if (index != 1)
-				continue;
-
-			tmpreg = apk_rf_init_value[path][index];
-
-			if (!rtlefuse->apk_thermalmeterignore) {
-				bb_offset = (tmpreg & 0xF0000) >> 16;
-
-				if (!(tmpreg & BIT(15)))
-					bb_offset = -bb_offset;
-
-				delta_v =
-				    apk_delta_mapping[index][delta_offset];
-
-				bb_offset += delta_v;
-
-				if (bb_offset < 0) {
-					tmpreg = tmpreg & (~BIT(15));
-					bb_offset = -bb_offset;
-				} else {
-					tmpreg = tmpreg | BIT(15);
-				}
-
-				tmpreg =
-				    (tmpreg & 0xFFF0FFFF) | (bb_offset << 16);
-			}
-
-			rtl_set_rfreg(hw, (enum radio_path)path, 0xc,
-				      MASKDWORD, 0x8992e);
-			rtl_set_rfreg(hw, (enum radio_path)path, 0x0,
-				      MASKDWORD, apk_rf_value_0[path][index]);
-			rtl_set_rfreg(hw, (enum radio_path)path, 0xd,
-				      MASKDWORD, tmpreg);
-
-			i = 0;
-			do {
-				rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80000000);
-				rtl_set_bbreg(hw, apk_offset[path],
-					      MASKDWORD, apk_value[0]);
-				RTPRINT(rtlpriv, FINIT, INIT_IQK,
-					("PHY_APCalibrate() offset 0x%x "
-					 "value 0x%x\n",
-					 apk_offset[path],
-					 rtl_get_bbreg(hw, apk_offset[path],
-						       MASKDWORD)));
-
-				mdelay(3);
-
-				rtl_set_bbreg(hw, apk_offset[path],
-					      MASKDWORD, apk_value[1]);
-				RTPRINT(rtlpriv, FINIT, INIT_IQK,
-					("PHY_APCalibrate() offset 0x%x "
-					 "value 0x%x\n",
-					 apk_offset[path],
-					 rtl_get_bbreg(hw, apk_offset[path],
-						       MASKDWORD)));
-
-				mdelay(20);
-
-				rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000);
-
-				if (path == RF90_PATH_A)
-					tmpreg = rtl_get_bbreg(hw, 0xbd8,
-							       0x03E00000);
-				else
-					tmpreg = rtl_get_bbreg(hw, 0xbd8,
-							       0xF8000000);
-
-				RTPRINT(rtlpriv, FINIT, INIT_IQK,
-					("PHY_APCalibrate() offset "
-					 "0xbd8[25:21] %x\n", tmpreg));
-
-				i++;
-
-			} while (tmpreg > apkbound && i < 4);
-
-			apk_result[path][index] = tmpreg;
-		}
-	}
-
-	_rtl92c_phy_reload_mac_registers(hw, mac_reg, mac_backup);
-
-	for (index = 0; index < APK_BB_REG_NUM; index++) {
-		if (index == 0)
-			continue;
-		rtl_set_bbreg(hw, bb_reg[index], MASKDWORD, bb_backup[index]);
-	}
-
-	_rtl92c_phy_reload_adda_registers(hw, afe_reg, afe_backup, 16);
-
-	for (path = 0; path < pathbound; path++) {
-		rtl_set_rfreg(hw, (enum radio_path)path, 0xd,
-			      MASKDWORD, reg_d[path]);
-
-		if (path == RF90_PATH_B) {
-			rtl_set_rfreg(hw, RF90_PATH_A, 0x10, MASKDWORD,
-				      0x1000f);
-			rtl_set_rfreg(hw, RF90_PATH_A, 0x11, MASKDWORD,
-				      0x20101);
-		}
-
-		if (apk_result[path][1] > 6)
-			apk_result[path][1] = 6;
-	}
-
-	for (path = 0; path < pathbound; path++) {
-		rtl_set_rfreg(hw, (enum radio_path)path, 0x3, MASKDWORD,
-			      ((apk_result[path][1] << 15) |
-			       (apk_result[path][1] << 10) |
-			       (apk_result[path][1] << 5) |
-			       apk_result[path][1]));
-
-		if (path == RF90_PATH_A)
-			rtl_set_rfreg(hw, (enum radio_path)path, 0x4, MASKDWORD,
-				      ((apk_result[path][1] << 15) |
-				       (apk_result[path][1] << 10) |
-				       (0x00 << 5) | 0x05));
-		else
-			rtl_set_rfreg(hw, (enum radio_path)path, 0x4, MASKDWORD,
-				      ((apk_result[path][1] << 15) |
-				       (apk_result[path][1] << 10) |
-				       (0x02 << 5) | 0x05));
-
-		rtl_set_rfreg(hw, (enum radio_path)path, 0xe, MASKDWORD,
-			      ((0x08 << 15) | (0x08 << 10) | (0x08 << 5) |
-			       0x08));
-
-	}
-	rtlphy->b_apk_done = true;
-#endif
 }
 
 static void _rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw,
@@ -1657,15 +1378,13 @@
 			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x2);
 		else
 			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1);
-
 	}
-
 }
 
 #undef IQK_ADDA_REG_NUM
 #undef IQK_DELAY_TIME
 
-void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
+void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -1673,10 +1392,10 @@
 
 	long result[4][8];
 	u8 i, final_candidate;
-	bool patha_ok, pathb_ok;
-	long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_ec4, reg_tmp = 0;
+	bool b_patha_ok, b_pathb_ok;
+	long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4,
+	    reg_ecc, reg_tmp = 0;
 	bool is12simular, is13simular, is23simular;
-	bool start_conttx = false, singletone = false;
 	u32 iqk_bb_reg[10] = {
 		ROFDM0_XARXIQIMBALANCE,
 		ROFDM0_XBRXIQIMBALANCE,
@@ -1690,14 +1409,12 @@
 		ROFDM0_RXIQEXTANTA
 	};
 
-	if (recovery) {
+	if (b_recovery) {
 		_rtl92c_phy_reload_adda_registers(hw,
 						  iqk_bb_reg,
 						  rtlphy->iqk_bb_backup, 10);
 		return;
 	}
-	if (start_conttx || singletone)
-		return;
 	for (i = 0; i < 8; i++) {
 		result[0][i] = 0;
 		result[1][i] = 0;
@@ -1705,8 +1422,8 @@
 		result[3][i] = 0;
 	}
 	final_candidate = 0xff;
-	patha_ok = false;
-	pathb_ok = false;
+	b_patha_ok = false;
+	b_pathb_ok = false;
 	is12simular = false;
 	is23simular = false;
 	is13simular = false;
@@ -1752,29 +1469,34 @@
 		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 (final_candidate != 0xff) {
 		rtlphy->reg_e94 = reg_e94 = result[final_candidate][0];
 		rtlphy->reg_e9c = reg_e9c = result[final_candidate][1];
 		reg_ea4 = result[final_candidate][2];
+		reg_eac = result[final_candidate][3];
 		rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4];
 		rtlphy->reg_ebc = reg_ebc = result[final_candidate][5];
 		reg_ec4 = result[final_candidate][6];
-		patha_ok = pathb_ok = true;
+		reg_ecc = result[final_candidate][7];
+		b_patha_ok = true;
+		b_pathb_ok = true;
 	} else {
 		rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100;
 		rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0;
 	}
 	if (reg_e94 != 0) /*&&(reg_ea4 != 0) */
-		_rtl92c_phy_path_a_fill_iqk_matrix(hw, patha_ok, result,
+		_rtl92c_phy_path_a_fill_iqk_matrix(hw, b_patha_ok, result,
 						   final_candidate,
 						   (reg_ea4 == 0));
 	if (IS_92C_SERIAL(rtlhal->version)) {
 		if (reg_eb4 != 0) /*&&(reg_ec4 != 0) */
-			_rtl92c_phy_path_b_fill_iqk_matrix(hw, pathb_ok,
+			_rtl92c_phy_path_b_fill_iqk_matrix(hw, b_pathb_ok,
 							   result,
 							   final_candidate,
 							   (reg_ec4 == 0));
@@ -1788,10 +1510,7 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	bool start_conttx = false, singletone = false;
 
-	if (start_conttx || singletone)
-		return;
 	if (IS_92C_SERIAL(rtlhal->version))
 		rtlpriv->cfg->ops->phy_lc_calibrate(hw, true);
 	else
@@ -1833,22 +1552,22 @@
 
 	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
 		 "-->IO Cmd(%#x), set_io_inprogress(%d)\n",
-		 iotype, rtlphy->set_io_inprogress);
+		  iotype, rtlphy->set_io_inprogress);
 	do {
 		switch (iotype) {
 		case IO_CMD_RESUME_DM_BY_SCAN:
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
-				 "[IO CMD] Resume DM after scan\n");
+				 "[IO CMD] Resume DM after scan.\n");
 			postprocessing = true;
 			break;
-		case IO_CMD_PAUSE_DM_BY_SCAN:
+		case IO_CMD_PAUSE_BAND0_DM_BY_SCAN:
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
-				 "[IO CMD] Pause DM before scan\n");
+				 "[IO CMD] Pause DM before scan.\n");
 			postprocessing = true;
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
 			break;
 		}
 	} while (false);
@@ -1859,7 +1578,7 @@
 		return false;
 	}
 	rtl92c_phy_set_io(hw);
-	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "<--IO Type(%#x)\n", iotype);
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "IO Type(%#x)\n", iotype);
 	return true;
 }
 EXPORT_SYMBOL(rtl92c_phy_set_io_cmd);
@@ -1868,30 +1587,30 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct dig_t dm_digtable = rtlpriv->dm_digtable;
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
 	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
 		 "--->Cmd(%#x), set_io_inprogress(%d)\n",
-		 rtlphy->current_io_type, rtlphy->set_io_inprogress);
+		  rtlphy->current_io_type, rtlphy->set_io_inprogress);
 	switch (rtlphy->current_io_type) {
 	case IO_CMD_RESUME_DM_BY_SCAN:
-		dm_digtable.cur_igvalue = rtlphy->initgain_backup.xaagccore1;
+		dm_digtable->cur_igvalue = rtlphy->initgain_backup.xaagccore1;
 		rtl92c_dm_write_dig(hw);
 		rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel);
 		break;
-	case IO_CMD_PAUSE_DM_BY_SCAN:
-		rtlphy->initgain_backup.xaagccore1 = dm_digtable.cur_igvalue;
-		dm_digtable.cur_igvalue = 0x37;
+	case IO_CMD_PAUSE_BAND0_DM_BY_SCAN:
+		rtlphy->initgain_backup.xaagccore1 = dm_digtable->cur_igvalue;
+		dm_digtable->cur_igvalue = 0x17;
 		rtl92c_dm_write_dig(hw);
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not processed\n");
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
 		break;
 	}
 	rtlphy->set_io_inprogress = false;
-	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "<---(%#x)\n",
-		 rtlphy->current_io_type);
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+		 "(%#x)\n", rtlphy->current_io_type);
 }
 EXPORT_SYMBOL(rtl92c_phy_set_io);
 
@@ -1931,7 +1650,7 @@
 		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
 		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
-			 "Switch RF timeout !!!\n");
+			 "Switch RF timeout !!!.\n");
 		return;
 	}
 	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h
index e79dabe..64bc49f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h
@@ -226,7 +226,7 @@
 long _rtl92c_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
 				  enum wireless_mode wirelessmode,
 				  u8 txpwridx);
-u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
+u8 _rtl92c_phy_dbm_to_txpwr_idx(struct ieee80211_hw *hw,
 				enum wireless_mode wirelessmode,
 				long power_indbm);
 void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
index fa24de4..831df10 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
@@ -146,21 +146,6 @@
 	VERSION_UNKNOWN = 0x88,
 };
 
-#define CUT_VERSION_MASK		(BIT(6)|BIT(7))
-#define CHIP_VENDOR_UMC			BIT(5)
-#define CHIP_VENDOR_UMC_B_CUT		BIT(6) /* Chip version for ECO */
-#define IS_VENDOR_UMC_A_CUT(version)	((IS_CHIP_VENDOR_UMC(version)) ? \
-	((GET_CVID_CUT_VERSION(version)) ? false : true) : false)
-#define IS_CHIP_VER_B(version)  ((version & CHIP_VER_B) ? true : false)
-#define IS_92C_SERIAL(version)  ((version & CHIP_92C_BITMASK) ? true : false)
-#define IS_CHIP_VENDOR_UMC(version)		\
-	((version & CHIP_VENDOR_UMC) ? true : false)
-#define GET_CVID_CUT_VERSION(version)	((version) & CUT_VERSION_MASK)
-#define IS_81xxC_VENDOR_UMC_B_CUT(version)		\
-	((IS_CHIP_VENDOR_UMC(version)) ? \
-	((GET_CVID_CUT_VERSION(version) == CHIP_VENDOR_UMC_B_CUT) ?	\
-	true : false) : false)
-
 enum rtl819x_loopback_e {
 	RTL819X_NO_LOOPBACK = 0,
 	RTL819X_MAC_LOOPBACK = 1,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
index d4a3d03..9c5311c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
@@ -86,70 +86,6 @@
 #define TX_POWER_NEAR_FIELD_THRESH_LVL2		74
 #define TX_POWER_NEAR_FIELD_THRESH_LVL1		67
 
-struct swat_t {
-	u8 failure_cnt;
-	u8 try_flag;
-	u8 stop_trying;
-	long pre_rssi;
-	long trying_threshold;
-	u8 cur_antenna;
-	u8 pre_antenna;
-};
-
-enum tag_dynamic_init_gain_operation_type_definition {
-	DIG_TYPE_THRESH_HIGH = 0,
-	DIG_TYPE_THRESH_LOW = 1,
-	DIG_TYPE_BACKOFF = 2,
-	DIG_TYPE_RX_GAIN_MIN = 3,
-	DIG_TYPE_RX_GAIN_MAX = 4,
-	DIG_TYPE_ENABLE = 5,
-	DIG_TYPE_DISABLE = 6,
-	DIG_OP_TYPE_MAX
-};
-
-enum tag_cck_packet_detection_threshold_type_definition {
-	CCK_PD_STAGE_LowRssi = 0,
-	CCK_PD_STAGE_HighRssi = 1,
-	CCK_FA_STAGE_Low = 2,
-	CCK_FA_STAGE_High = 3,
-	CCK_PD_STAGE_MAX = 4,
-};
-
-enum dm_1r_cca_e {
-	CCA_1R = 0,
-	CCA_2R = 1,
-	CCA_MAX = 2,
-};
-
-enum dm_rf_e {
-	RF_SAVE = 0,
-	RF_NORMAL = 1,
-	RF_MAX = 2,
-};
-
-enum dm_sw_ant_switch_e {
-	ANS_ANTENNA_B = 1,
-	ANS_ANTENNA_A = 2,
-	ANS_ANTENNA_MAX = 3,
-};
-
-enum dm_dig_ext_port_alg_e {
-	DIG_EXT_PORT_STAGE_0 = 0,
-	DIG_EXT_PORT_STAGE_1 = 1,
-	DIG_EXT_PORT_STAGE_2 = 2,
-	DIG_EXT_PORT_STAGE_3 = 3,
-	DIG_EXT_PORT_STAGE_MAX = 4,
-};
-
-enum dm_dig_connect_e {
-	DIG_STA_DISCONNECT = 0,
-	DIG_STA_CONNECT = 1,
-	DIG_STA_BEFORE_CONNECT = 2,
-	DIG_MULTISTA_DISCONNECT = 3,
-	DIG_MULTISTA_CONNECT = 4,
-	DIG_CONNECT_MAX
-};
-
 void rtl92c_dm_init(struct ieee80211_hw *hw);
 void rtl92c_dm_watchdog(struct ieee80211_hw *hw);
 void rtl92c_dm_write_dig(struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index df98a5e..8ec0f03 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -37,7 +37,9 @@
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
+#include "../rtl8192c/dm_common.h"
 #include "../rtl8192c/fw_common.h"
+#include "../rtl8192c/phy_common.h"
 #include "dm.h"
 #include "led.h"
 #include "hw.h"
@@ -53,7 +55,7 @@
 	rtlpci->reg_bcn_ctrl_val |= set_bits;
 	rtlpci->reg_bcn_ctrl_val &= ~clear_bits;
 
-	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val);
+	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8)rtlpci->reg_bcn_ctrl_val);
 }
 
 static void _rtl92ce_stop_tx_beacon(struct ieee80211_hw *hw)
@@ -985,7 +987,7 @@
 	    !IS_92C_SERIAL(rtlhal->version)) {
 		rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD, 0x30255);
 		rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G2, MASKDWORD, 0x50a00);
-	} else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) {
+	} else if (IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version)) {
 		rtl_set_rfreg(hw, RF90_PATH_A, 0x0C, MASKDWORD, 0x894AE);
 		rtl_set_rfreg(hw, RF90_PATH_A, 0x0A, MASKDWORD, 0x1AF31);
 		rtl_set_rfreg(hw, RF90_PATH_A, RF_IPA, MASKDWORD, 0x8F425);
@@ -1330,7 +1332,7 @@
 	rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790);
 	rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080);
 	rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80);
-	if (!IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
+	if (!IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version))
 		rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23);
 	if (rtlpcipriv->bt_coexist.bt_coexistence) {
 		u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL);
@@ -1494,7 +1496,7 @@
 
 	for (rf_path = 0; rf_path < 2; rf_path++) {
 		for (i = 0; i < 14; i++) {
-			index = _rtl92c_get_chnl_group((u8) i);
+			index = rtl92c_get_chnl_group((u8)i);
 
 			rtlefuse->txpwrlevel_cck[rf_path][i] =
 			    rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][index];
@@ -1543,7 +1545,7 @@
 
 	for (rf_path = 0; rf_path < 2; rf_path++) {
 		for (i = 0; i < 14; i++) {
-			index = _rtl92c_get_chnl_group((u8) i);
+			index = rtl92c_get_chnl_group((u8)i);
 
 			if (rf_path == RF90_PATH_A) {
 				rtlefuse->pwrgroup_ht20[rf_path][i] =
@@ -1573,7 +1575,7 @@
 	}
 
 	for (i = 0; i < 14; i++) {
-		index = _rtl92c_get_chnl_group((u8) i);
+		index = rtl92c_get_chnl_group((u8)i);
 
 		if (!autoload_fail)
 			tempval = hwinfo[EEPROM_TXPOWERHT20DIFF + index];
@@ -1590,7 +1592,7 @@
 		if (rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] & BIT(3))
 			rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] |= 0xF0;
 
-		index = _rtl92c_get_chnl_group((u8) i);
+		index = rtl92c_get_chnl_group((u8)i);
 
 		if (!autoload_fail)
 			tempval = hwinfo[EEPROM_TXPOWER_OFDMDIFF + index];
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
index 5533070..98a0868 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
@@ -30,7 +30,7 @@
 #ifndef __RTL92CE_HW_H__
 #define __RTL92CE_HW_H__
 
-static inline u8 _rtl92c_get_chnl_group(u8 chnl)
+static inline u8 rtl92c_get_chnl_group(u8 chnl)
 {
 	u8 group;
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
index 98b2230..bc5ca98 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
@@ -35,8 +35,11 @@
 #include "def.h"
 #include "hw.h"
 #include "phy.h"
+#include "../rtl8192c/phy_common.h"
 #include "rf.h"
 #include "dm.h"
+#include "../rtl8192c/dm_common.h"
+#include "../rtl8192c/fw_common.h"
 #include "table.h"
 
 static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
index 94486cc..e5e1353 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
@@ -78,113 +78,6 @@
 
 #define RTL92C_MAX_PATH_NUM		2
 
-enum swchnlcmd_id {
-	CMDID_END,
-	CMDID_SET_TXPOWEROWER_LEVEL,
-	CMDID_BBREGWRITE10,
-	CMDID_WRITEPORT_ULONG,
-	CMDID_WRITEPORT_USHORT,
-	CMDID_WRITEPORT_UCHAR,
-	CMDID_RF_WRITEREG,
-};
-
-struct swchnlcmd {
-	enum swchnlcmd_id cmdid;
-	u32 para1;
-	u32 para2;
-	u32 msdelay;
-};
-
-enum hw90_block_e {
-	HW90_BLOCK_MAC = 0,
-	HW90_BLOCK_PHY0 = 1,
-	HW90_BLOCK_PHY1 = 2,
-	HW90_BLOCK_RF = 3,
-	HW90_BLOCK_MAXIMUM = 4,
-};
-
-enum baseband_config_type {
-	BASEBAND_CONFIG_PHY_REG = 0,
-	BASEBAND_CONFIG_AGC_TAB = 1,
-};
-
-enum ra_offset_area {
-	RA_OFFSET_LEGACY_OFDM1,
-	RA_OFFSET_LEGACY_OFDM2,
-	RA_OFFSET_HT_OFDM1,
-	RA_OFFSET_HT_OFDM2,
-	RA_OFFSET_HT_OFDM3,
-	RA_OFFSET_HT_OFDM4,
-	RA_OFFSET_HT_CCK,
-};
-
-enum antenna_path {
-	ANTENNA_NONE,
-	ANTENNA_D,
-	ANTENNA_C,
-	ANTENNA_CD,
-	ANTENNA_B,
-	ANTENNA_BD,
-	ANTENNA_BC,
-	ANTENNA_BCD,
-	ANTENNA_A,
-	ANTENNA_AD,
-	ANTENNA_AC,
-	ANTENNA_ACD,
-	ANTENNA_AB,
-	ANTENNA_ABD,
-	ANTENNA_ABC,
-	ANTENNA_ABCD
-};
-
-struct r_antenna_select_ofdm {
-	u32 r_tx_antenna:4;
-	u32 r_ant_l:4;
-	u32 r_ant_non_ht:4;
-	u32 r_ant_ht1:4;
-	u32 r_ant_ht2:4;
-	u32 r_ant_ht_s1:4;
-	u32 r_ant_non_ht_s1:4;
-	u32 ofdm_txsc:2;
-	u32 reserved:2;
-};
-
-struct r_antenna_select_cck {
-	u8 r_cckrx_enable_2:2;
-	u8 r_cckrx_enable:2;
-	u8 r_ccktx_enable:4;
-};
-
-struct efuse_contents {
-	u8 mac_addr[ETH_ALEN];
-	u8 cck_tx_power_idx[6];
-	u8 ht40_1s_tx_power_idx[6];
-	u8 ht40_2s_tx_power_idx_diff[3];
-	u8 ht20_tx_power_idx_diff[3];
-	u8 ofdm_tx_power_idx_diff[3];
-	u8 ht40_max_power_offset[3];
-	u8 ht20_max_power_offset[3];
-	u8 channel_plan;
-	u8 thermal_meter;
-	u8 rf_option[5];
-	u8 version;
-	u8 oem_id;
-	u8 regulatory;
-};
-
-struct tx_power_struct {
-	u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 legacy_ht_txpowerdiff;
-	u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 pwrgroup_cnt;
-	u32 mcs_original_offset[4][16];
-};
-
 bool rtl92c_phy_bb_config(struct ieee80211_hw *hw);
 u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask);
 void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
index 4bbdfb2..d86b5b5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -35,6 +35,9 @@
 #include "def.h"
 #include "phy.h"
 #include "dm.h"
+#include "../rtl8192c/dm_common.h"
+#include "../rtl8192c/fw_common.h"
+#include "../rtl8192c/phy_common.h"
 #include "hw.h"
 #include "rf.h"
 #include "sw.h"
@@ -165,7 +168,7 @@
 	if (IS_VENDOR_UMC_A_CUT(rtlhal->version) &&
 	    !IS_92C_SERIAL(rtlhal->version))
 		rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU.bin";
-	else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
+	else if (IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version))
 		rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cfwU_B.bin";
 
 	rtlpriv->max_fw_size = 0x4000;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index 8f04817..2fb9c7a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -125,7 +125,7 @@
 	u32 rssi, total_rssi = 0;
 	bool is_cck_rate;
 
-	is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc);
+	is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc->rxmcs);
 	pstats->packet_matchbssid = packet_match_bssid;
 	pstats->packet_toself = packet_toself;
 	pstats->is_cck = is_cck_rate;
@@ -361,7 +361,7 @@
 	stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
 	stats->is_ht = (bool)GET_RX_DESC_RXHT(pdesc);
 
-	stats->is_cck = RX_HAL_IS_CCK_RATE(pdesc);
+	stats->is_cck = RX_HAL_IS_CCK_RATE(pdesc->rxmcs);
 
 	rx_status->freq = hw->conf.chandef.chan->center_freq;
 	rx_status->band = hw->conf.chandef.chan->band;
@@ -389,10 +389,6 @@
 	 * to decrypt it
 	 */
 	if (stats->decrypted) {
-		if (!hdr) {
-			/* In testing, hdr was NULL here */
-			return false;
-		}
 		if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
 		    (ieee80211_has_protected(hdr->frame_control)))
 			rx_status->flag &= ~RX_FLAG_DECRYPTED;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h
index f916555..c940a87 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h
@@ -38,9 +38,6 @@
 #define CHIP_VENDOR_UMC			BIT(5)
 #define CHIP_VENDOR_UMC_B_CUT		BIT(6)
 
-#define IS_NORMAL_CHIP(version)		\
-	(((version) & NORMAL_CHIP) ? true : false)
-
 #define IS_8723_SERIES(version)		\
 	(((version) & CHIP_8723) ? true : false)
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index 270cbff..04aa0b5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -36,8 +36,11 @@
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
+#include "../rtl8192c/phy_common.h"
 #include "mac.h"
 #include "dm.h"
+#include "../rtl8192c/dm_common.h"
+#include "../rtl8192c/fw_common.h"
 #include "hw.h"
 #include "../rtl8192ce/hw.h"
 #include "trx.h"
@@ -180,7 +183,7 @@
 				eprom_chnl_txpwr_ht40_2sdf[rf_path][i]);
 	for (rf_path = 0; rf_path < 2; rf_path++) {
 		for (i = 0; i < 14; i++) {
-			index = _rtl92c_get_chnl_group((u8) i);
+			index = rtl92c_get_chnl_group((u8)i);
 			rtlefuse->txpwrlevel_cck[rf_path][i] =
 			    rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][index];
 			rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
@@ -222,7 +225,7 @@
 	}
 	for (rf_path = 0; rf_path < 2; rf_path++) {
 		for (i = 0; i < 14; i++) {
-			index = _rtl92c_get_chnl_group((u8) i);
+			index = rtl92c_get_chnl_group((u8)i);
 			if (rf_path == RF90_PATH_A) {
 				rtlefuse->pwrgroup_ht20[rf_path][i] =
 				    (rtlefuse->eeprom_pwrlimit_ht20[index]
@@ -249,7 +252,7 @@
 		}
 	}
 	for (i = 0; i < 14; i++) {
-		index = _rtl92c_get_chnl_group((u8) i);
+		index = rtl92c_get_chnl_group((u8)i);
 		if (!autoload_fail)
 			tempval = hwinfo[EEPROM_TXPOWERHT20DIFF + index];
 		else
@@ -261,7 +264,7 @@
 			rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] |= 0xF0;
 		if (rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] & BIT(3))
 			rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] |= 0xF0;
-		index = _rtl92c_get_chnl_group((u8) i);
+		index = rtl92c_get_chnl_group((u8)i);
 		if (!autoload_fail)
 			tempval = hwinfo[EEPROM_TXPOWER_OFDMDIFF + index];
 		else
@@ -1169,13 +1172,13 @@
 	/* 1. Disable GPIO[7:0] */
 	rtl_write_word(rtlpriv, REG_GPIO_PIN_CTRL+2, 0x0000);
 	value32 = rtl_read_dword(rtlpriv, REG_GPIO_PIN_CTRL) & 0xFFFF00FF;
-	value8 = (u8) (value32&0x000000FF);
+	value8 = (u8)(value32&0x000000FF);
 	value32 |= ((value8<<8) | 0x00FF0000);
 	rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, value32);
 	/* 2. Disable GPIO[10:8] */
 	rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG+3, 0x00);
 	value16 = rtl_read_word(rtlpriv, REG_GPIO_MUXCFG+2) & 0xFF0F;
-	value8 = (u8) (value16&0x000F);
+	value8 = (u8)(value16&0x000F);
 	value16 |= ((value8<<4) | 0x0780);
 	rtl_write_word(rtlpriv, REG_GPIO_PIN_CTRL+2, value16);
 	/* 3. Disable LED0 & 1 */
@@ -1245,7 +1248,7 @@
 
 	rtlusb->reg_bcn_ctrl_val |= set_bits;
 	rtlusb->reg_bcn_ctrl_val &= ~clear_bits;
-	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlusb->reg_bcn_ctrl_val);
+	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8)rtlusb->reg_bcn_ctrl_val);
 }
 
 static void _rtl92cu_stop_tx_beacon(struct ieee80211_hw *hw)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
index e26312f..c2d8ec6 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
@@ -40,6 +40,7 @@
 #include "dm.h"
 #include "mac.h"
 #include "trx.h"
+#include "../rtl8192c/fw_common.h"
 
 #include <linux/module.h>
 
@@ -786,7 +787,7 @@
 	bool is_cck_rate;
 	u8 *pdesc = (u8 *)p_desc;
 
-	is_cck_rate = RX_HAL_IS_CCK_RATE(p_desc);
+	is_cck_rate = RX_HAL_IS_CCK_RATE(p_desc->rxmcs);
 	pstats->packet_matchbssid = packet_match_bssid;
 	pstats->packet_toself = packet_toself;
 	pstats->packet_beacon = packet_beacon;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
index 9831ff1..12f6d47 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
@@ -34,8 +34,11 @@
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
+#include "../rtl8192c/phy_common.h"
 #include "rf.h"
 #include "dm.h"
+#include "../rtl8192c/dm_common.h"
+#include "../rtl8192c/fw_common.h"
 #include "table.h"
 
 u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index b68507b..18933c0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -42,6 +42,7 @@
 #include "trx.h"
 #include "led.h"
 #include "hw.h"
+#include "../rtl8192c/fw_common.h"
 #include <linux/module.h>
 
 MODULE_AUTHOR("Georgia		<georgia@realtek.com>");
@@ -75,7 +76,7 @@
 	if (IS_VENDOR_UMC_A_CUT(rtlpriv->rtlhal.version) &&
 	    !IS_92C_SERIAL(rtlpriv->rtlhal.version)) {
 		rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_A.bin";
-	} else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlpriv->rtlhal.version)) {
+	} else if (IS_81XXC_VENDOR_UMC_B_CUT(rtlpriv->rtlhal.version)) {
 		rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_B.bin";
 	} else {
 		rtlpriv->cfg->fw_name = "rtlwifi/rtl8192cufw_TMSC.bin";
@@ -121,7 +122,6 @@
 	.fill_tx_desc = rtl92cu_tx_fill_desc,
 	.fill_fake_txdesc = rtl92cu_fill_fake_txdesc,
 	.fill_tx_cmddesc = rtl92cu_tx_fill_cmddesc,
-	.cmd_send_packet = rtl92cu_cmd_send_packet,
 	.query_rx_desc = rtl92cu_rx_query_desc,
 	.set_channel_access = rtl92cu_update_channel_access_setting,
 	.radio_onoff_checking = rtl92cu_gpio_radio_on_off_checking,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index 035e0dc..f383d5f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -38,6 +38,7 @@
 #include "dm.h"
 #include "mac.h"
 #include "trx.h"
+#include "../rtl8192c/fw_common.h"
 
 static int _ConfigVerTOutEP(struct ieee80211_hw *hw)
 {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h
index 1ffacdd..a55a803 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h
@@ -132,18 +132,6 @@
 	u32 rsvd5;
 };
 
-enum rtl8192d_h2c_cmd {
-	H2C_AP_OFFLOAD = 0,
-	H2C_SETPWRMODE = 1,
-	H2C_JOINBSSRPT = 2,
-	H2C_RSVDPAGE = 3,
-	H2C_RSSI_REPORT = 5,
-	H2C_RA_MASK = 6,
-	H2C_MAC_MODE_SEL = 9,
-	H2C_PWRM = 15,
-	MAX_H2CCMD
-};
-
 int rtl92d_download_fw(struct ieee80211_hw *hw);
 void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
 			 u32 cmd_len, u8 *p_cmdbuffer);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
index 592125a..1961b8e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
@@ -677,7 +677,7 @@
 
 	rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index] = data;
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-		 "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%ulx\n",
+		 "MCSTxPowerLevelOriginalOffset[%d][%d] = 0x%x\n",
 		 rtlphy->pwrgroup_cnt, index,
 		 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][index]);
 	if (index == 13)
@@ -2531,7 +2531,7 @@
 	if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G) {/* Path-A for 5G */
 		u4tmp = curveindex_5g[channel-1];
 		RTPRINT(rtlpriv, FINIT, INIT_IQK,
-			"ver 1 set RF-A, 5G,	0x28 = 0x%ulx !!\n", u4tmp);
+			"ver 1 set RF-A, 5G,	0x28 = 0x%x !!\n", u4tmp);
 		if (rtlpriv->rtlhal.macphymode == DUALMAC_DUALPHY &&
 			rtlpriv->rtlhal.interfaceindex == 1) {
 			bneed_powerdown_radio =
@@ -2550,7 +2550,7 @@
 	} else if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) {
 		u4tmp = curveindex_2g[channel-1];
 		RTPRINT(rtlpriv, FINIT, INIT_IQK,
-			"ver 3 set RF-B, 2G, 0x28 = 0x%ulx !!\n", u4tmp);
+			"ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n", u4tmp);
 		if (rtlpriv->rtlhal.macphymode == DUALMAC_DUALPHY &&
 			rtlpriv->rtlhal.interfaceindex == 0) {
 			bneed_powerdown_radio =
@@ -2562,7 +2562,7 @@
 		}
 		rtl_set_rfreg(hw, erfpath, RF_SYN_G4, 0x3f800, u4tmp);
 		RTPRINT(rtlpriv, FINIT, INIT_IQK,
-			"ver 3 set RF-B, 2G, 0x28 = 0x%ulx !!\n",
+			"ver 3 set RF-B, 2G, 0x28 = 0x%x !!\n",
 			rtl_get_rfreg(hw,  erfpath, RF_SYN_G4, 0x3f800));
 		if (bneed_powerdown_radio)
 			_rtl92d_phy_restore_rf_env(hw, erfpath, &u4regvalue);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
index 99c2ab5..8efbcc7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
@@ -127,7 +127,7 @@
 	u32 rssi, total_rssi = 0;
 	bool is_cck_rate;
 
-	is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc);
+	is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc->rxmcs);
 	pstats->packet_matchbssid = packet_match_bssid;
 	pstats->packet_toself = packet_toself;
 	pstats->packet_beacon = packet_beacon;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/Makefile b/drivers/net/wireless/rtlwifi/rtl8192ee/Makefile
new file mode 100644
index 0000000..aeea8a9
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/Makefile
@@ -0,0 +1,19 @@
+obj-m := rtl8192ee.o
+
+
+rtl8192ee-objs :=		\
+		dm.o		\
+		fw.o		\
+		hw.o		\
+		led.o		\
+		phy.o		\
+		pwrseq.o	\
+		rf.o		\
+		sw.o		\
+		table.o		\
+		trx.o		\
+
+
+obj-$(CPTCFG_RTL8821AE) += rtl8192ee.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/def.h b/drivers/net/wireless/rtlwifi/rtl8192ee/def.h
new file mode 100644
index 0000000..60f5728
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/def.h
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92E_DEF_H__
+#define __RTL92E_DEF_H__
+
+#define RX_DESC_NUM_92E					512
+
+#define HAL_PRIME_CHNL_OFFSET_DONT_CARE			0
+#define HAL_PRIME_CHNL_OFFSET_LOWER			1
+#define HAL_PRIME_CHNL_OFFSET_UPPER			2
+
+#define RX_MPDU_QUEUE					0
+
+#define IS_HT_RATE(_rate)	\
+	(_rate >= DESC92C_RATEMCS0)
+#define IS_CCK_RATE(_rate)	\
+	(_rate >= DESC92C_RATE1M && _rate <= DESC92C_RATE11M)
+#define IS_OFDM_RATE(_rate)	\
+	(_rate >= DESC92C_RATE6M && _rate <= DESC92C_RATE54M)
+
+enum version_8192e {
+	VERSION_TEST_CHIP_2T2R_8192E = 0x0024,
+	VERSION_NORMAL_CHIP_2T2R_8192E = 0x102C,
+	VERSION_UNKNOWN = 0xFF,
+};
+
+enum rx_packet_type {
+	NORMAL_RX,
+	TX_REPORT1,
+	TX_REPORT2,
+	HIS_REPORT,
+	C2H_PACKET,
+};
+
+enum rtl_desc_qsel {
+	QSLT_BK = 0x2,
+	QSLT_BE = 0x0,
+	QSLT_VI = 0x5,
+	QSLT_VO = 0x7,
+	QSLT_BEACON = 0x10,
+	QSLT_HIGH = 0x11,
+	QSLT_MGNT = 0x12,
+	QSLT_CMD = 0x13,
+};
+
+enum rtl_desc92c_rate {
+	DESC92C_RATE1M = 0x00,
+	DESC92C_RATE2M = 0x01,
+	DESC92C_RATE5_5M = 0x02,
+	DESC92C_RATE11M = 0x03,
+
+	DESC92C_RATE6M = 0x04,
+	DESC92C_RATE9M = 0x05,
+	DESC92C_RATE12M = 0x06,
+	DESC92C_RATE18M = 0x07,
+	DESC92C_RATE24M = 0x08,
+	DESC92C_RATE36M = 0x09,
+	DESC92C_RATE48M = 0x0a,
+	DESC92C_RATE54M = 0x0b,
+
+	DESC92C_RATEMCS0 = 0x0c,
+	DESC92C_RATEMCS1 = 0x0d,
+	DESC92C_RATEMCS2 = 0x0e,
+	DESC92C_RATEMCS3 = 0x0f,
+	DESC92C_RATEMCS4 = 0x10,
+	DESC92C_RATEMCS5 = 0x11,
+	DESC92C_RATEMCS6 = 0x12,
+	DESC92C_RATEMCS7 = 0x13,
+	DESC92C_RATEMCS8 = 0x14,
+	DESC92C_RATEMCS9 = 0x15,
+	DESC92C_RATEMCS10 = 0x16,
+	DESC92C_RATEMCS11 = 0x17,
+	DESC92C_RATEMCS12 = 0x18,
+	DESC92C_RATEMCS13 = 0x19,
+	DESC92C_RATEMCS14 = 0x1a,
+	DESC92C_RATEMCS15 = 0x1b,
+};
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c
new file mode 100644
index 0000000..77deedf
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c
@@ -0,0 +1,1263 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../base.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "trx.h"
+
+static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = {
+	0x7f8001fe,		/* 0, +6.0dB */
+	0x788001e2,		/* 1, +5.5dB */
+	0x71c001c7,		/* 2, +5.0dB */
+	0x6b8001ae,		/* 3, +4.5dB */
+	0x65400195,		/* 4, +4.0dB */
+	0x5fc0017f,		/* 5, +3.5dB */
+	0x5a400169,		/* 6, +3.0dB */
+	0x55400155,		/* 7, +2.5dB */
+	0x50800142,		/* 8, +2.0dB */
+	0x4c000130,		/* 9, +1.5dB */
+	0x47c0011f,		/* 10, +1.0dB */
+	0x43c0010f,		/* 11, +0.5dB */
+	0x40000100,		/* 12, +0dB */
+	0x3c8000f2,		/* 13, -0.5dB */
+	0x390000e4,		/* 14, -1.0dB */
+	0x35c000d7,		/* 15, -1.5dB */
+	0x32c000cb,		/* 16, -2.0dB */
+	0x300000c0,		/* 17, -2.5dB */
+	0x2d4000b5,		/* 18, -3.0dB */
+	0x2ac000ab,		/* 19, -3.5dB */
+	0x288000a2,		/* 20, -4.0dB */
+	0x26000098,		/* 21, -4.5dB */
+	0x24000090,		/* 22, -5.0dB */
+	0x22000088,		/* 23, -5.5dB */
+	0x20000080,		/* 24, -6.0dB */
+	0x1e400079,		/* 25, -6.5dB */
+	0x1c800072,		/* 26, -7.0dB */
+	0x1b00006c,		/* 27. -7.5dB */
+	0x19800066,		/* 28, -8.0dB */
+	0x18000060,		/* 29, -8.5dB */
+	0x16c0005b,		/* 30, -9.0dB */
+	0x15800056,		/* 31, -9.5dB */
+	0x14400051,		/* 32, -10.0dB */
+	0x1300004c,		/* 33, -10.5dB */
+	0x12000048,		/* 34, -11.0dB */
+	0x11000044,		/* 35, -11.5dB */
+	0x10000040,		/* 36, -12.0dB */
+	0x0f00003c,		/* 37, -12.5dB */
+	0x0e400039,		/* 38, -13.0dB */
+	0x0d800036,		/* 39, -13.5dB */
+	0x0cc00033,		/* 40, -14.0dB */
+	0x0c000030,		/* 41, -14.5dB */
+	0x0b40002d,		/* 42, -15.0dB */
+};
+
+static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = {
+	{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0dB */
+	{0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 1, -0.5dB */
+	{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 2, -1.0dB */
+	{0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 3, -1.5dB */
+	{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 4, -2.0dB */
+	{0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 5, -2.5dB */
+	{0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 6, -3.0dB */
+	{0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 7, -3.5dB */
+	{0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 8, -4.0dB */
+	{0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 9, -4.5dB */
+	{0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 10, -5.0dB */
+	{0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 11, -5.5dB */
+	{0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 12, -6.0dB */
+	{0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 13, -6.5dB */
+	{0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 14, -7.0dB */
+	{0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 15, -7.5dB */
+	{0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */
+	{0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 17, -8.5dB */
+	{0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 18, -9.0dB */
+	{0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 19, -9.5dB */
+	{0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 20, -10.0dB */
+	{0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 21, -10.5dB */
+	{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 22, -11.0dB */
+	{0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 23, -11.5dB */
+	{0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 24, -12.0dB */
+	{0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 25, -12.5dB */
+	{0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 26, -13.0dB */
+	{0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 27, -13.5dB */
+	{0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 28, -14.0dB */
+	{0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 29, -14.5dB */
+	{0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 30, -15.0dB */
+	{0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 31, -15.5dB */
+	{0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}  /* 32, -16.0dB */
+};
+
+static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = {
+	{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0dB */
+	{0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 1, -0.5dB */
+	{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 2, -1.0dB */
+	{0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 3, -1.5dB */
+	{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 4, -2.0dB */
+	{0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 5, -2.5dB */
+	{0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 6, -3.0dB */
+	{0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 7, -3.5dB */
+	{0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 8, -4.0dB */
+	{0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 9, -4.5dB */
+	{0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 10, -5.0dB */
+	{0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 11, -5.5dB */
+	{0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 12, -6.0dB */
+	{0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 13, -6.5dB */
+	{0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 14, -7.0dB */
+	{0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 15, -7.5dB */
+	{0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */
+	{0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 17, -8.5dB */
+	{0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 18, -9.0dB */
+	{0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 19, -9.5dB */
+	{0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 20, -10.0dB */
+	{0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 21, -10.5dB */
+	{0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 22, -11.0dB */
+	{0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 23, -11.5dB */
+	{0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 24, -12.0dB */
+	{0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 25, -12.5dB */
+	{0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 26, -13.0dB */
+	{0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 27, -13.5dB */
+	{0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 28, -14.0dB */
+	{0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 29, -14.5dB */
+	{0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 30, -15.0dB */
+	{0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 31, -15.5dB */
+	{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}  /* 32, -16.0dB */
+};
+
+static void rtl92ee_dm_diginit(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+
+	dm_dig->cur_igvalue = rtl_get_bbreg(hw, DM_REG_IGI_A_11N,
+					    DM_BIT_IGI_11N);
+	dm_dig->rssi_lowthresh = DM_DIG_THRESH_LOW;
+	dm_dig->rssi_highthresh = DM_DIG_THRESH_HIGH;
+	dm_dig->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
+	dm_dig->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
+	dm_dig->rx_gain_max = DM_DIG_MAX;
+	dm_dig->rx_gain_min = DM_DIG_MIN;
+	dm_dig->back_val = DM_DIG_BACKOFF_DEFAULT;
+	dm_dig->back_range_max = DM_DIG_BACKOFF_MAX;
+	dm_dig->back_range_min = DM_DIG_BACKOFF_MIN;
+	dm_dig->pre_cck_cca_thres = 0xff;
+	dm_dig->cur_cck_cca_thres = 0x83;
+	dm_dig->forbidden_igi = DM_DIG_MIN;
+	dm_dig->large_fa_hit = 0;
+	dm_dig->recover_cnt = 0;
+	dm_dig->dig_dynamic_min = DM_DIG_MIN;
+	dm_dig->dig_dynamic_min_1 = DM_DIG_MIN;
+	dm_dig->media_connect_0 = false;
+	dm_dig->media_connect_1 = false;
+	rtlpriv->dm.dm_initialgain_enable = true;
+	dm_dig->bt30_cur_igi = 0x32;
+}
+
+static void rtl92ee_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
+{
+	u32 ret_value;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct false_alarm_statistics *falsealm_cnt = &rtlpriv->falsealm_cnt;
+
+	rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 1);
+	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 1);
+
+	ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE1_11N, MASKDWORD);
+	falsealm_cnt->cnt_fast_fsync_fail = (ret_value & 0xffff);
+	falsealm_cnt->cnt_sb_search_fail = ((ret_value & 0xffff0000) >> 16);
+
+	ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE2_11N, MASKDWORD);
+	falsealm_cnt->cnt_ofdm_cca = (ret_value & 0xffff);
+	falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16);
+
+	ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE3_11N, MASKDWORD);
+	falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff);
+	falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16);
+
+	ret_value = rtl_get_bbreg(hw, DM_REG_OFDM_FA_TYPE4_11N, MASKDWORD);
+	falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
+
+	falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
+				      falsealm_cnt->cnt_rate_illegal +
+				      falsealm_cnt->cnt_crc8_fail +
+				      falsealm_cnt->cnt_mcs_fail +
+				      falsealm_cnt->cnt_fast_fsync_fail +
+				      falsealm_cnt->cnt_sb_search_fail;
+
+	ret_value = rtl_get_bbreg(hw, DM_REG_SC_CNT_11N, MASKDWORD);
+	falsealm_cnt->cnt_bw_lsc = (ret_value & 0xffff);
+	falsealm_cnt->cnt_bw_usc = ((ret_value & 0xffff0000) >> 16);
+
+	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(12), 1);
+	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(14), 1);
+
+	ret_value = rtl_get_bbreg(hw, DM_REG_CCK_FA_LSB_11N, MASKBYTE0);
+	falsealm_cnt->cnt_cck_fail = ret_value;
+
+	ret_value = rtl_get_bbreg(hw, DM_REG_CCK_FA_MSB_11N, MASKBYTE3);
+	falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8;
+
+	ret_value = rtl_get_bbreg(hw, DM_REG_CCK_CCA_CNT_11N, MASKDWORD);
+	falsealm_cnt->cnt_cck_cca = ((ret_value & 0xff) << 8) |
+				    ((ret_value & 0xFF00) >> 8);
+
+	falsealm_cnt->cnt_all = falsealm_cnt->cnt_fast_fsync_fail +
+				falsealm_cnt->cnt_sb_search_fail +
+				falsealm_cnt->cnt_parity_fail +
+				falsealm_cnt->cnt_rate_illegal +
+				falsealm_cnt->cnt_crc8_fail +
+				falsealm_cnt->cnt_mcs_fail +
+				falsealm_cnt->cnt_cck_fail;
+
+	falsealm_cnt->cnt_cca_all = falsealm_cnt->cnt_ofdm_cca +
+				    falsealm_cnt->cnt_cck_cca;
+
+	/*reset false alarm counter registers*/
+	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTC_11N, BIT(31), 1);
+	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTC_11N, BIT(31), 0);
+	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(27), 1);
+	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(27), 0);
+	/*update ofdm counter*/
+	rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 0);
+	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 0);
+	/*reset CCK CCA counter*/
+	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 0);
+	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 2);
+	/*reset CCK FA counter*/
+	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 0);
+	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 2);
+
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+		 "cnt_parity_fail = %d, cnt_rate_illegal = %d, cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
+		  falsealm_cnt->cnt_parity_fail,
+		  falsealm_cnt->cnt_rate_illegal,
+		  falsealm_cnt->cnt_crc8_fail, falsealm_cnt->cnt_mcs_fail);
+
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+		 "cnt_ofdm_fail = %x, cnt_cck_fail = %x, cnt_all = %x\n",
+		  falsealm_cnt->cnt_ofdm_fail,
+		  falsealm_cnt->cnt_cck_fail, falsealm_cnt->cnt_all);
+}
+
+static void rtl92ee_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+	u8 cur_cck_cca_thresh;
+
+	if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
+		if (dm_dig->rssi_val_min > 25) {
+			cur_cck_cca_thresh = 0xcd;
+		} else if ((dm_dig->rssi_val_min <= 25) &&
+			   (dm_dig->rssi_val_min > 10)) {
+			cur_cck_cca_thresh = 0x83;
+		} else {
+			if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
+				cur_cck_cca_thresh = 0x83;
+			else
+				cur_cck_cca_thresh = 0x40;
+		}
+	} else {
+		if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
+			cur_cck_cca_thresh = 0x83;
+		else
+			cur_cck_cca_thresh = 0x40;
+	}
+	rtl92ee_dm_write_cck_cca_thres(hw, cur_cck_cca_thresh);
+}
+
+static void rtl92ee_dm_dig(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+	u8 dig_dynamic_min , dig_maxofmin;
+	bool bfirstconnect , bfirstdisconnect;
+	u8 dm_dig_max, dm_dig_min;
+	u8 current_igi = dm_dig->cur_igvalue;
+	u8 offset;
+
+	/* AP,BT */
+	if (mac->act_scanning)
+		return;
+
+	dig_dynamic_min = dm_dig->dig_dynamic_min;
+	bfirstconnect = (mac->link_state >= MAC80211_LINKED) &&
+			!dm_dig->media_connect_0;
+	bfirstdisconnect = (mac->link_state < MAC80211_LINKED) &&
+			   dm_dig->media_connect_0;
+
+	dm_dig_max = 0x5a;
+	dm_dig_min = DM_DIG_MIN;
+	dig_maxofmin = DM_DIG_MAX_AP;
+
+	if (mac->link_state >= MAC80211_LINKED) {
+		if ((dm_dig->rssi_val_min + 10) > dm_dig_max)
+			dm_dig->rx_gain_max = dm_dig_max;
+		else if ((dm_dig->rssi_val_min + 10) < dm_dig_min)
+			dm_dig->rx_gain_max = dm_dig_min;
+		else
+			dm_dig->rx_gain_max = dm_dig->rssi_val_min + 10;
+
+		if (rtlpriv->dm.one_entry_only) {
+			offset = 0;
+			if (dm_dig->rssi_val_min - offset < dm_dig_min)
+				dig_dynamic_min = dm_dig_min;
+			else if (dm_dig->rssi_val_min - offset >
+				 dig_maxofmin)
+				dig_dynamic_min = dig_maxofmin;
+			else
+				dig_dynamic_min = dm_dig->rssi_val_min - offset;
+		} else {
+			dig_dynamic_min = dm_dig_min;
+		}
+
+	} else {
+		dm_dig->rx_gain_max = dm_dig_max;
+		dig_dynamic_min = dm_dig_min;
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n");
+	}
+
+	if (rtlpriv->falsealm_cnt.cnt_all > 10000) {
+		if (dm_dig->large_fa_hit != 3)
+			dm_dig->large_fa_hit++;
+		if (dm_dig->forbidden_igi < current_igi) {
+			dm_dig->forbidden_igi = current_igi;
+			dm_dig->large_fa_hit = 1;
+		}
+
+		if (dm_dig->large_fa_hit >= 3) {
+			if (dm_dig->forbidden_igi + 1 > dm_dig->rx_gain_max)
+				dm_dig->rx_gain_min =
+						dm_dig->rx_gain_max;
+			else
+				dm_dig->rx_gain_min =
+						dm_dig->forbidden_igi + 1;
+			dm_dig->recover_cnt = 3600;
+		}
+	} else {
+		if (dm_dig->recover_cnt != 0) {
+			dm_dig->recover_cnt--;
+		} else {
+			if (dm_dig->large_fa_hit < 3) {
+				if ((dm_dig->forbidden_igi - 1) <
+				    dig_dynamic_min) {
+					dm_dig->forbidden_igi = dig_dynamic_min;
+					dm_dig->rx_gain_min =
+								dig_dynamic_min;
+				} else {
+					dm_dig->forbidden_igi--;
+					dm_dig->rx_gain_min =
+						dm_dig->forbidden_igi + 1;
+				}
+			} else {
+				dm_dig->large_fa_hit = 0;
+			}
+		}
+	}
+
+	if (rtlpriv->dm.dbginfo.num_qry_beacon_pkt < 5)
+		dm_dig->rx_gain_min = dm_dig_min;
+
+	if (dm_dig->rx_gain_min > dm_dig->rx_gain_max)
+		dm_dig->rx_gain_min = dm_dig->rx_gain_max;
+
+	if (mac->link_state >= MAC80211_LINKED) {
+		if (bfirstconnect) {
+			if (dm_dig->rssi_val_min <= dig_maxofmin)
+				current_igi = dm_dig->rssi_val_min;
+			else
+				current_igi = dig_maxofmin;
+
+			dm_dig->large_fa_hit = 0;
+		} else {
+			if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH2)
+				current_igi += 4;
+			else if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH1)
+				current_igi += 2;
+			else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0)
+				current_igi -= 2;
+
+			if (rtlpriv->dm.dbginfo.num_qry_beacon_pkt < 5 &&
+			    rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH1)
+				current_igi = dm_dig->rx_gain_min;
+		}
+	} else {
+		if (bfirstdisconnect) {
+			current_igi = dm_dig->rx_gain_min;
+		} else {
+			if (rtlpriv->falsealm_cnt.cnt_all > 10000)
+				current_igi += 4;
+			else if (rtlpriv->falsealm_cnt.cnt_all > 8000)
+				current_igi += 2;
+			else if (rtlpriv->falsealm_cnt.cnt_all < 500)
+				current_igi -= 2;
+		}
+	}
+
+	if (current_igi > dm_dig->rx_gain_max)
+		current_igi = dm_dig->rx_gain_max;
+	if (current_igi < dm_dig->rx_gain_min)
+		current_igi = dm_dig->rx_gain_min;
+
+	rtl92ee_dm_write_dig(hw , current_igi);
+	dm_dig->media_connect_0 = ((mac->link_state >= MAC80211_LINKED) ?
+				   true : false);
+	dm_dig->dig_dynamic_min = dig_dynamic_min;
+}
+
+void rtl92ee_dm_write_cck_cca_thres(struct ieee80211_hw *hw, u8 cur_thres)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+
+	if (dm_dig->cur_cck_cca_thres != cur_thres)
+		rtl_write_byte(rtlpriv, DM_REG_CCK_CCA_11N, cur_thres);
+
+	dm_dig->pre_cck_cca_thres = dm_dig->cur_cck_cca_thres;
+	dm_dig->cur_cck_cca_thres = cur_thres;
+}
+
+void rtl92ee_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+
+	if (dm_dig->stop_dig)
+		return;
+
+	if (dm_dig->cur_igvalue != current_igi) {
+		rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, current_igi);
+		if (rtlpriv->phy.rf_type != RF_1T1R)
+			rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, current_igi);
+	}
+	dm_dig->pre_igvalue = dm_dig->cur_igvalue;
+	dm_dig->cur_igvalue = current_igi;
+}
+
+static void rtl92ee_rssi_dump_to_register(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtl_write_byte(rtlpriv, RA_RSSIDUMP,
+		       rtlpriv->stats.rx_rssi_percentage[0]);
+	rtl_write_byte(rtlpriv, RB_RSSIDUMP,
+		       rtlpriv->stats.rx_rssi_percentage[1]);
+	/*It seems the following values are not initialized.
+	  *According to Windows code,
+	  *these value will only be valid with JAGUAR chips
+	  */
+	/* Rx EVM */
+	rtl_write_byte(rtlpriv, RS1_RXEVMDUMP, rtlpriv->stats.rx_evm_dbm[0]);
+	rtl_write_byte(rtlpriv, RS2_RXEVMDUMP, rtlpriv->stats.rx_evm_dbm[1]);
+	/* Rx SNR */
+	rtl_write_byte(rtlpriv, RA_RXSNRDUMP,
+		       (u8)(rtlpriv->stats.rx_snr_db[0]));
+	rtl_write_byte(rtlpriv, RB_RXSNRDUMP,
+		       (u8)(rtlpriv->stats.rx_snr_db[1]));
+	/* Rx Cfo_Short */
+	rtl_write_word(rtlpriv, RA_CFOSHORTDUMP,
+		       rtlpriv->stats.rx_cfo_short[0]);
+	rtl_write_word(rtlpriv, RB_CFOSHORTDUMP,
+		       rtlpriv->stats.rx_cfo_short[1]);
+	/* Rx Cfo_Tail */
+	rtl_write_word(rtlpriv, RA_CFOLONGDUMP, rtlpriv->stats.rx_cfo_tail[0]);
+	rtl_write_word(rtlpriv, RB_CFOLONGDUMP, rtlpriv->stats.rx_cfo_tail[1]);
+}
+
+static void rtl92ee_dm_find_minimum_rssi(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *rtl_dm_dig = &rtlpriv->dm_digtable;
+	struct rtl_mac *mac = rtl_mac(rtlpriv);
+
+	/* Determine the minimum RSSI  */
+	if ((mac->link_state < MAC80211_LINKED) &&
+	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
+		rtl_dm_dig->min_undec_pwdb_for_dm = 0;
+		RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+			 "Not connected to any\n");
+	}
+	if (mac->link_state >= MAC80211_LINKED) {
+		if (mac->opmode == NL80211_IFTYPE_AP ||
+		    mac->opmode == NL80211_IFTYPE_ADHOC) {
+			rtl_dm_dig->min_undec_pwdb_for_dm =
+				rtlpriv->dm.entry_min_undec_sm_pwdb;
+			RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+				 "AP Client PWDB = 0x%lx\n",
+				 rtlpriv->dm.entry_min_undec_sm_pwdb);
+		} else {
+			rtl_dm_dig->min_undec_pwdb_for_dm =
+			    rtlpriv->dm.undec_sm_pwdb;
+			RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+				 "STA Default Port PWDB = 0x%x\n",
+				 rtl_dm_dig->min_undec_pwdb_for_dm);
+		}
+	} else {
+		rtl_dm_dig->min_undec_pwdb_for_dm =
+			rtlpriv->dm.entry_min_undec_sm_pwdb;
+		RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+			 "AP Ext Port or disconnet PWDB = 0x%x\n",
+			 rtl_dm_dig->min_undec_pwdb_for_dm);
+	}
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+		 "MinUndecoratedPWDBForDM =%d\n",
+		 rtl_dm_dig->min_undec_pwdb_for_dm);
+}
+
+static void rtl92ee_dm_check_rssi_monitor(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+	struct rtl_mac *mac = rtl_mac(rtlpriv);
+	struct rtl_dm *dm = rtl_dm(rtlpriv);
+	struct rtl_sta_info *drv_priv;
+	u8 h2c[4] = { 0 };
+	long max = 0, min = 0xff;
+	u8 i = 0;
+
+	if (mac->opmode == NL80211_IFTYPE_AP ||
+	    mac->opmode == NL80211_IFTYPE_ADHOC ||
+	    mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+		/* AP & ADHOC & MESH */
+		spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+		list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
+			struct rssi_sta *stat = &drv_priv->rssi_stat;
+
+			if (stat->undec_sm_pwdb < min)
+				min = stat->undec_sm_pwdb;
+			if (stat->undec_sm_pwdb > max)
+				max = stat->undec_sm_pwdb;
+
+			h2c[3] = 0;
+			h2c[2] = (u8)(dm->undec_sm_pwdb & 0xFF);
+			h2c[1] = 0x20;
+			h2c[0] = ++i;
+			rtl92ee_fill_h2c_cmd(hw, H2C_92E_RSSI_REPORT, 4, h2c);
+		}
+		spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+
+		/* If associated entry is found */
+		if (max != 0) {
+			dm->entry_max_undec_sm_pwdb = max;
+			RTPRINT(rtlpriv, FDM, DM_PWDB,
+				"EntryMaxPWDB = 0x%lx(%ld)\n", max, max);
+		} else {
+			dm->entry_max_undec_sm_pwdb = 0;
+		}
+		/* If associated entry is found */
+		if (min != 0xff) {
+			dm->entry_min_undec_sm_pwdb = min;
+			RTPRINT(rtlpriv, FDM, DM_PWDB,
+				"EntryMinPWDB = 0x%lx(%ld)\n", min, min);
+		} else {
+			dm->entry_min_undec_sm_pwdb = 0;
+		}
+	}
+
+	/* Indicate Rx signal strength to FW. */
+	if (dm->useramask) {
+		h2c[3] = 0;
+		h2c[2] = (u8)(dm->undec_sm_pwdb & 0xFF);
+		h2c[1] = 0x20;
+		h2c[0] = 0;
+		rtl92ee_fill_h2c_cmd(hw, H2C_92E_RSSI_REPORT, 4, h2c);
+	} else {
+		rtl_write_byte(rtlpriv, 0x4fe, dm->undec_sm_pwdb);
+	}
+	rtl92ee_rssi_dump_to_register(hw);
+	rtl92ee_dm_find_minimum_rssi(hw);
+	dm_dig->rssi_val_min = rtlpriv->dm_digtable.min_undec_pwdb_for_dm;
+}
+
+static void rtl92ee_dm_init_primary_cca_check(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	struct dynamic_primary_cca *primarycca = &rtlpriv->primarycca;
+
+	rtlhal->rts_en = 0;
+	primarycca->dup_rts_flag = 0;
+	primarycca->intf_flag = 0;
+	primarycca->intf_type = 0;
+	primarycca->monitor_flag = 0;
+	primarycca->ch_offset = 0;
+	primarycca->mf_state = 0;
+}
+
+static bool rtl92ee_dm_is_edca_turbo_disable(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (rtlpriv->mac80211.mode == WIRELESS_MODE_B)
+		return true;
+
+	return false;
+}
+
+void rtl92ee_dm_init_edca_turbo(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtlpriv->dm.current_turbo_edca = false;
+	rtlpriv->dm.is_cur_rdlstate = false;
+	rtlpriv->dm.is_any_nonbepkts = false;
+}
+
+static void rtl92ee_dm_check_edca_turbo(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	static u64 last_txok_cnt;
+	static u64 last_rxok_cnt;
+	u64 cur_txok_cnt = 0;
+	u64 cur_rxok_cnt = 0;
+	u32 edca_be_ul = 0x5ea42b;
+	u32 edca_be_dl = 0x5ea42b; /*not sure*/
+	u32 edca_be = 0x5ea42b;
+	bool is_cur_rdlstate;
+	bool b_edca_turbo_on = false;
+
+	if (rtlpriv->dm.dbginfo.num_non_be_pkt > 0x100)
+		rtlpriv->dm.is_any_nonbepkts = true;
+	rtlpriv->dm.dbginfo.num_non_be_pkt = 0;
+
+	cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
+	cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
+
+	/*b_bias_on_rx = false;*/
+	b_edca_turbo_on = ((!rtlpriv->dm.is_any_nonbepkts) &&
+			   (!rtlpriv->dm.disable_framebursting)) ?
+			  true : false;
+
+	if (rtl92ee_dm_is_edca_turbo_disable(hw))
+		goto check_exit;
+
+	if (b_edca_turbo_on) {
+		is_cur_rdlstate = (cur_rxok_cnt > cur_txok_cnt * 4) ?
+				    true : false;
+
+		edca_be = is_cur_rdlstate ? edca_be_dl : edca_be_ul;
+		rtl_write_dword(rtlpriv , REG_EDCA_BE_PARAM , edca_be);
+		rtlpriv->dm.is_cur_rdlstate = is_cur_rdlstate;
+		rtlpriv->dm.current_turbo_edca = true;
+	} else {
+		if (rtlpriv->dm.current_turbo_edca) {
+			u8 tmp = AC0_BE;
+
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+						      (u8 *)(&tmp));
+		}
+		rtlpriv->dm.current_turbo_edca = false;
+	}
+
+check_exit:
+	rtlpriv->dm.is_any_nonbepkts = false;
+	last_txok_cnt = rtlpriv->stats.txbytesunicast;
+	last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
+}
+
+static void rtl92ee_dm_dynamic_edcca(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 reg_c50 , reg_c58;
+	bool fw_current_in_ps_mode = false;
+
+	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+				      (u8 *)(&fw_current_in_ps_mode));
+	if (fw_current_in_ps_mode)
+		return;
+
+	reg_c50 = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
+	reg_c58 = rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
+
+	if (reg_c50 > 0x28 && reg_c58 > 0x28) {
+		if (!rtlpriv->rtlhal.pre_edcca_enable) {
+			rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD, 0x03);
+			rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD + 2, 0x00);
+			rtlpriv->rtlhal.pre_edcca_enable = true;
+		}
+	} else if (reg_c50 < 0x25 && reg_c58 < 0x25) {
+		if (rtlpriv->rtlhal.pre_edcca_enable) {
+			rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD, 0x7f);
+			rtl_write_byte(rtlpriv, ROFDM0_ECCATHRESHOLD + 2, 0x7f);
+			rtlpriv->rtlhal.pre_edcca_enable = false;
+		}
+	}
+}
+
+static void rtl92ee_dm_adaptivity(struct ieee80211_hw *hw)
+{
+	rtl92ee_dm_dynamic_edcca(hw);
+}
+
+static void rtl92ee_dm_write_dynamic_cca(struct ieee80211_hw *hw,
+					 u8 cur_mf_state)
+{
+	struct dynamic_primary_cca *primarycca = &rtl_priv(hw)->primarycca;
+
+	if (primarycca->mf_state != cur_mf_state)
+		rtl_set_bbreg(hw, DM_REG_L1SBD_PD_CH_11N, BIT(8) | BIT(7),
+			      cur_mf_state);
+
+	primarycca->mf_state = cur_mf_state;
+}
+
+static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct false_alarm_statistics *falsealm_cnt = &rtlpriv->falsealm_cnt;
+	struct dynamic_primary_cca *primarycca = &rtlpriv->primarycca;
+	bool is40mhz = false;
+	u64 ofdm_cca, ofdm_fa, bw_usc_cnt, bw_lsc_cnt;
+	u8 sec_ch_offset;
+	u8 cur_mf_state;
+	static u8 count_down = MONITOR_TIME;
+
+	ofdm_cca = falsealm_cnt->cnt_ofdm_cca;
+	ofdm_fa = falsealm_cnt->cnt_ofdm_fail;
+	bw_usc_cnt = falsealm_cnt->cnt_bw_usc;
+	bw_lsc_cnt = falsealm_cnt->cnt_bw_lsc;
+	is40mhz = rtlpriv->mac80211.bw_40;
+	sec_ch_offset = rtlpriv->mac80211.cur_40_prime_sc;
+	/* NIC: 2: sec is below,  1: sec is above */
+
+	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) {
+		cur_mf_state = MF_USC_LSC;
+		rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
+		return;
+	}
+
+	if (rtlpriv->mac80211.link_state < MAC80211_LINKED)
+		return;
+
+	if (is40mhz)
+		return;
+
+	if (primarycca->pricca_flag == 0) {
+		/* Primary channel is above
+		 * NOTE: duplicate CTS can remove this condition
+		 */
+		if (sec_ch_offset == 2) {
+			if ((ofdm_cca > OFDMCCA_TH) &&
+			    (bw_lsc_cnt > (bw_usc_cnt + BW_IND_BIAS)) &&
+			    (ofdm_fa > (ofdm_cca >> 1))) {
+				primarycca->intf_type = 1;
+				primarycca->intf_flag = 1;
+				cur_mf_state = MF_USC;
+				rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
+				primarycca->pricca_flag = 1;
+			} else if ((ofdm_cca > OFDMCCA_TH) &&
+				   (bw_lsc_cnt > (bw_usc_cnt + BW_IND_BIAS)) &&
+				   (ofdm_fa < (ofdm_cca >> 1))) {
+				primarycca->intf_type = 2;
+				primarycca->intf_flag = 1;
+				cur_mf_state = MF_USC;
+				rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
+				primarycca->pricca_flag = 1;
+				primarycca->dup_rts_flag = 1;
+				rtlpriv->rtlhal.rts_en = 1;
+			} else {
+				primarycca->intf_type = 0;
+				primarycca->intf_flag = 0;
+				cur_mf_state = MF_USC_LSC;
+				rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
+				rtlpriv->rtlhal.rts_en = 0;
+				primarycca->dup_rts_flag = 0;
+			}
+		} else if (sec_ch_offset == 1) {
+			if ((ofdm_cca > OFDMCCA_TH) &&
+			    (bw_usc_cnt > (bw_lsc_cnt + BW_IND_BIAS)) &&
+			    (ofdm_fa > (ofdm_cca >> 1))) {
+				primarycca->intf_type = 1;
+				primarycca->intf_flag = 1;
+				cur_mf_state = MF_LSC;
+				rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
+				primarycca->pricca_flag = 1;
+			} else if ((ofdm_cca > OFDMCCA_TH) &&
+				   (bw_usc_cnt > (bw_lsc_cnt + BW_IND_BIAS)) &&
+				   (ofdm_fa < (ofdm_cca >> 1))) {
+				primarycca->intf_type = 2;
+				primarycca->intf_flag = 1;
+				cur_mf_state = MF_LSC;
+				rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
+				primarycca->pricca_flag = 1;
+				primarycca->dup_rts_flag = 1;
+				rtlpriv->rtlhal.rts_en = 1;
+			} else {
+				primarycca->intf_type = 0;
+				primarycca->intf_flag = 0;
+				cur_mf_state = MF_USC_LSC;
+				rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
+				rtlpriv->rtlhal.rts_en = 0;
+				primarycca->dup_rts_flag = 0;
+			}
+		}
+	} else {/* PrimaryCCA->PriCCA_flag==1 */
+		count_down--;
+		if (count_down == 0) {
+			count_down = MONITOR_TIME;
+			primarycca->pricca_flag = 0;
+			cur_mf_state = MF_USC_LSC;
+			/* default */
+			rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
+			rtlpriv->rtlhal.rts_en = 0;
+			primarycca->dup_rts_flag = 0;
+			primarycca->intf_type = 0;
+			primarycca->intf_flag = 0;
+		}
+	}
+}
+
+static void rtl92ee_dm_dynamic_atc_switch(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+	u8 crystal_cap;
+	u32 packet_count;
+	int cfo_khz_a , cfo_khz_b , cfo_ave = 0, adjust_xtal = 0;
+	int cfo_ave_diff;
+
+	if (rtlpriv->mac80211.link_state < MAC80211_LINKED) {
+		if (rtldm->atc_status == ATC_STATUS_OFF) {
+			rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11),
+				      ATC_STATUS_ON);
+			rtldm->atc_status = ATC_STATUS_ON;
+		}
+		/* Disable CFO tracking for BT */
+		if (rtlpriv->cfg->ops->get_btc_status()) {
+			if (!rtlpriv->btcoexist.btc_ops->
+			    btc_is_bt_disabled(rtlpriv)) {
+				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
+					 "odm_DynamicATCSwitch(): Disable CFO tracking for BT!!\n");
+				return;
+			}
+		}
+		/* Reset Crystal Cap */
+		if (rtldm->crystal_cap != rtlpriv->efuse.crystalcap) {
+			rtldm->crystal_cap = rtlpriv->efuse.crystalcap;
+			crystal_cap = rtldm->crystal_cap & 0x3f;
+			rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000,
+				      (crystal_cap | (crystal_cap << 6)));
+		}
+	} else {
+		cfo_khz_a = (int)(rtldm->cfo_tail[0] * 3125) / 1280;
+		cfo_khz_b = (int)(rtldm->cfo_tail[1] * 3125) / 1280;
+		packet_count = rtldm->packet_count;
+
+		if (packet_count == rtldm->packet_count_pre)
+			return;
+
+		rtldm->packet_count_pre = packet_count;
+
+		if (rtlpriv->phy.rf_type == RF_1T1R)
+			cfo_ave = cfo_khz_a;
+		else
+			cfo_ave = (int)(cfo_khz_a + cfo_khz_b) >> 1;
+
+		cfo_ave_diff = (rtldm->cfo_ave_pre >= cfo_ave) ?
+			       (rtldm->cfo_ave_pre - cfo_ave) :
+			       (cfo_ave - rtldm->cfo_ave_pre);
+
+		if (cfo_ave_diff > 20 && rtldm->large_cfo_hit == 0) {
+			rtldm->large_cfo_hit = 1;
+			return;
+		}
+		rtldm->large_cfo_hit = 0;
+
+		rtldm->cfo_ave_pre = cfo_ave;
+
+		if (cfo_ave >= -rtldm->cfo_threshold &&
+		    cfo_ave <= rtldm->cfo_threshold && rtldm->is_freeze == 0) {
+			if (rtldm->cfo_threshold == CFO_THRESHOLD_XTAL) {
+				rtldm->cfo_threshold = CFO_THRESHOLD_XTAL + 10;
+				rtldm->is_freeze = 1;
+			} else {
+				rtldm->cfo_threshold = CFO_THRESHOLD_XTAL;
+			}
+		}
+
+		if (cfo_ave > rtldm->cfo_threshold && rtldm->crystal_cap < 0x3f)
+			adjust_xtal = ((cfo_ave - CFO_THRESHOLD_XTAL) >> 2) + 1;
+		else if ((cfo_ave < -rtlpriv->dm.cfo_threshold) &&
+			 rtlpriv->dm.crystal_cap > 0)
+			adjust_xtal = ((cfo_ave + CFO_THRESHOLD_XTAL) >> 2) - 1;
+
+		if (adjust_xtal != 0) {
+			rtldm->is_freeze = 0;
+			rtldm->crystal_cap += adjust_xtal;
+
+			if (rtldm->crystal_cap > 0x3f)
+				rtldm->crystal_cap = 0x3f;
+			else if (rtldm->crystal_cap < 0)
+				rtldm->crystal_cap = 0;
+
+			crystal_cap = rtldm->crystal_cap & 0x3f;
+			rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000,
+				      (crystal_cap | (crystal_cap << 6)));
+		}
+
+		if (cfo_ave < CFO_THRESHOLD_ATC &&
+		    cfo_ave > -CFO_THRESHOLD_ATC) {
+			if (rtldm->atc_status == ATC_STATUS_ON) {
+				rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11),
+					      ATC_STATUS_OFF);
+				rtldm->atc_status = ATC_STATUS_OFF;
+			}
+		} else {
+			if (rtldm->atc_status == ATC_STATUS_OFF) {
+				rtl_set_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11),
+					      ATC_STATUS_ON);
+				rtldm->atc_status = ATC_STATUS_ON;
+			}
+		}
+	}
+}
+
+static void rtl92ee_dm_init_txpower_tracking(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_dm *dm = rtl_dm(rtlpriv);
+	u8 path;
+
+	dm->txpower_tracking = true;
+	dm->default_ofdm_index = 30;
+	dm->default_cck_index = 20;
+
+	dm->swing_idx_cck_base = dm->default_cck_index;
+	dm->cck_index = dm->default_cck_index;
+
+	for (path = RF90_PATH_A; path < MAX_RF_PATH; path++) {
+		dm->swing_idx_ofdm_base[path] = dm->default_ofdm_index;
+		dm->ofdm_index[path] = dm->default_ofdm_index;
+		dm->delta_power_index[path] = 0;
+		dm->delta_power_index_last[path] = 0;
+		dm->power_index_offset[path] = 0;
+	}
+}
+
+void rtl92ee_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rate_adaptive *p_ra = &rtlpriv->ra;
+
+	p_ra->ratr_state = DM_RATR_STA_INIT;
+	p_ra->pre_ratr_state = DM_RATR_STA_INIT;
+
+	if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
+		rtlpriv->dm.useramask = true;
+	else
+		rtlpriv->dm.useramask = false;
+
+	p_ra->ldpc_thres = 35;
+	p_ra->use_ldpc = false;
+	p_ra->high_rssi_thresh_for_ra = 50;
+	p_ra->low_rssi_thresh_for_ra40m = 20;
+}
+
+static bool _rtl92ee_dm_ra_state_check(struct ieee80211_hw *hw,
+				       s32 rssi, u8 *ratr_state)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rate_adaptive *p_ra = &rtlpriv->ra;
+	const u8 go_up_gap = 5;
+	u32 high_rssithresh_for_ra = p_ra->high_rssi_thresh_for_ra;
+	u32 low_rssithresh_for_ra = p_ra->low_rssi_thresh_for_ra40m;
+	u8 state;
+
+	/* Threshold Adjustment:
+	 * when RSSI state trends to go up one or two levels,
+	 * make sure RSSI is high enough.
+	 * Here GoUpGap is added to solve
+	 * the boundary's level alternation issue.
+	 */
+	switch (*ratr_state) {
+	case DM_RATR_STA_INIT:
+	case DM_RATR_STA_HIGH:
+		break;
+	case DM_RATR_STA_MIDDLE:
+		high_rssithresh_for_ra += go_up_gap;
+		break;
+	case DM_RATR_STA_LOW:
+		high_rssithresh_for_ra += go_up_gap;
+		low_rssithresh_for_ra += go_up_gap;
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+			 "wrong rssi level setting %d !", *ratr_state);
+		break;
+	}
+
+	/* Decide RATRState by RSSI. */
+	if (rssi > high_rssithresh_for_ra)
+		state = DM_RATR_STA_HIGH;
+	else if (rssi > low_rssithresh_for_ra)
+		state = DM_RATR_STA_MIDDLE;
+	else
+		state = DM_RATR_STA_LOW;
+
+	if (*ratr_state != state) {
+		*ratr_state = state;
+		return true;
+	}
+
+	return false;
+}
+
+static void rtl92ee_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rate_adaptive *p_ra = &rtlpriv->ra;
+	struct ieee80211_sta *sta = NULL;
+
+	if (is_hal_stop(rtlhal)) {
+		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+			 "driver is going to unload\n");
+		return;
+	}
+
+	if (!rtlpriv->dm.useramask) {
+		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+			 "driver does not control rate adaptive mask\n");
+		return;
+	}
+
+	if (mac->link_state == MAC80211_LINKED &&
+	    mac->opmode == NL80211_IFTYPE_STATION) {
+		if (rtlpriv->dm.undec_sm_pwdb < p_ra->ldpc_thres) {
+			p_ra->use_ldpc = true;
+			p_ra->lower_rts_rate = true;
+		} else if (rtlpriv->dm.undec_sm_pwdb >
+			   (p_ra->ldpc_thres - 5)) {
+			p_ra->use_ldpc = false;
+			p_ra->lower_rts_rate = false;
+		}
+		if (_rtl92ee_dm_ra_state_check(hw, rtlpriv->dm.undec_sm_pwdb,
+					       &p_ra->ratr_state)) {
+			rcu_read_lock();
+			sta = rtl_find_sta(hw, mac->bssid);
+			if (sta)
+				rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
+							      p_ra->ratr_state);
+			rcu_read_unlock();
+
+			p_ra->pre_ratr_state = p_ra->ratr_state;
+		}
+	}
+}
+
+static void rtl92ee_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtlpriv->dm.crystal_cap = rtlpriv->efuse.crystalcap;
+
+	rtlpriv->dm.atc_status = rtl_get_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11));
+	rtlpriv->dm.cfo_threshold = CFO_THRESHOLD_XTAL;
+}
+
+void rtl92ee_dm_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
+
+	rtl92ee_dm_diginit(hw);
+	rtl92ee_dm_init_rate_adaptive_mask(hw);
+	rtl92ee_dm_init_primary_cca_check(hw);
+	rtl92ee_dm_init_edca_turbo(hw);
+	rtl92ee_dm_init_txpower_tracking(hw);
+	rtl92ee_dm_init_dynamic_atc_switch(hw);
+}
+
+static void rtl92ee_dm_common_info_self_update(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_sta_info *drv_priv;
+	u8 cnt = 0;
+
+	rtlpriv->dm.one_entry_only = false;
+
+	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION &&
+	    rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
+		rtlpriv->dm.one_entry_only = true;
+		return;
+	}
+
+	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP ||
+	    rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC ||
+	    rtlpriv->mac80211.opmode == NL80211_IFTYPE_MESH_POINT) {
+		spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+		list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
+			cnt++;
+		}
+		spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+
+		if (cnt == 1)
+			rtlpriv->dm.one_entry_only = true;
+	}
+}
+
+void rtl92ee_dm_dynamic_arfb_select(struct ieee80211_hw *hw,
+				    u8 rate, bool collision_state)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (rate >= DESC92C_RATEMCS8  && rate <= DESC92C_RATEMCS12) {
+		if (collision_state == 1) {
+			if (rate == DESC92C_RATEMCS12) {
+				rtl_write_dword(rtlpriv, REG_DARFRC, 0x0);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x07060501);
+			} else if (rate == DESC92C_RATEMCS11) {
+				rtl_write_dword(rtlpriv, REG_DARFRC, 0x0);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x07070605);
+			} else if (rate == DESC92C_RATEMCS10) {
+				rtl_write_dword(rtlpriv, REG_DARFRC, 0x0);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x08080706);
+			} else if (rate == DESC92C_RATEMCS9) {
+				rtl_write_dword(rtlpriv, REG_DARFRC, 0x0);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x08080707);
+			} else {
+				rtl_write_dword(rtlpriv, REG_DARFRC, 0x0);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x09090808);
+			}
+		} else {   /* collision_state == 0 */
+			if (rate == DESC92C_RATEMCS12) {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x05010000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x09080706);
+			} else if (rate == DESC92C_RATEMCS11) {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x06050000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x09080807);
+			} else if (rate == DESC92C_RATEMCS10) {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x07060000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x0a090908);
+			} else if (rate == DESC92C_RATEMCS9) {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x07070000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x0a090808);
+			} else {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x08080000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x0b0a0909);
+			}
+		}
+	} else {  /* MCS13~MCS15,  1SS, G-mode */
+		if (collision_state == 1) {
+			if (rate == DESC92C_RATEMCS15) {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x00000000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x05040302);
+			} else if (rate == DESC92C_RATEMCS14) {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x00000000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x06050302);
+			} else if (rate == DESC92C_RATEMCS13) {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x00000000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x07060502);
+			} else {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x00000000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x06050402);
+			}
+		} else{   /* collision_state == 0 */
+			if (rate == DESC92C_RATEMCS15) {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x03020000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x07060504);
+			} else if (rate == DESC92C_RATEMCS14) {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x03020000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x08070605);
+			} else if (rate == DESC92C_RATEMCS13) {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x05020000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x09080706);
+			} else {
+				rtl_write_dword(rtlpriv, REG_DARFRC,
+						0x04020000);
+				rtl_write_dword(rtlpriv, REG_DARFRC + 4,
+						0x08070605);
+			}
+		}
+	}
+}
+
+void rtl92ee_dm_watchdog(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	bool fw_current_inpsmode = false;
+	bool fw_ps_awake = true;
+
+	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+				      (u8 *)(&fw_current_inpsmode));
+	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
+				      (u8 *)(&fw_ps_awake));
+	if (ppsc->p2p_ps_info.p2p_ps_mode)
+		fw_ps_awake = false;
+
+	if ((ppsc->rfpwr_state == ERFON) &&
+	    ((!fw_current_inpsmode) && fw_ps_awake) &&
+	    (!ppsc->rfchange_inprogress)) {
+		rtl92ee_dm_common_info_self_update(hw);
+		rtl92ee_dm_false_alarm_counter_statistics(hw);
+		rtl92ee_dm_check_rssi_monitor(hw);
+		rtl92ee_dm_dig(hw);
+		rtl92ee_dm_adaptivity(hw);
+		rtl92ee_dm_cck_packet_detection_thresh(hw);
+		rtl92ee_dm_refresh_rate_adaptive_mask(hw);
+		rtl92ee_dm_check_edca_turbo(hw);
+		rtl92ee_dm_dynamic_atc_switch(hw);
+		rtl92ee_dm_dynamic_primary_cca_ckeck(hw);
+	}
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h
new file mode 100644
index 0000000..881db7d
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h
@@ -0,0 +1,267 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef	__RTL92E_DM_H__
+#define __RTL92E_DM_H__
+
+#define	OFDMCCA_TH				500
+#define	BW_IND_BIAS				500
+#define	MF_USC					2
+#define	MF_LSC					1
+#define	MF_USC_LSC				0
+#define	MONITOR_TIME				30
+
+#define	MAIN_ANT				0
+#define	AUX_ANT					1
+#define	MAIN_ANT_CG_TRX				1
+#define	AUX_ANT_CG_TRX				0
+#define	MAIN_ANT_CGCS_RX			0
+#define	AUX_ANT_CGCS_RX				1
+
+/*RF REG LIST*/
+#define	DM_REG_RF_MODE_11N			0x00
+#define	DM_REG_RF_0B_11N			0x0B
+#define	DM_REG_CHNBW_11N			0x18
+#define	DM_REG_T_METER_11N			0x24
+#define	DM_REG_RF_25_11N			0x25
+#define	DM_REG_RF_26_11N			0x26
+#define	DM_REG_RF_27_11N			0x27
+#define	DM_REG_RF_2B_11N			0x2B
+#define	DM_REG_RF_2C_11N			0x2C
+#define	DM_REG_RXRF_A3_11N			0x3C
+#define	DM_REG_T_METER_92D_11N			0x42
+#define	DM_REG_T_METER_92E_11N			0x42
+
+/*BB REG LIST*/
+/*PAGE 8 */
+#define	DM_REG_BB_CTRL_11N			0x800
+#define	DM_REG_RF_PIN_11N			0x804
+#define	DM_REG_PSD_CTRL_11N			0x808
+#define	DM_REG_TX_ANT_CTRL_11N			0x80C
+#define	DM_REG_BB_PWR_SAV5_11N			0x818
+#define	DM_REG_CCK_RPT_FORMAT_11N		0x824
+#define	DM_REG_RX_DEFUALT_A_11N			0x858
+#define	DM_REG_RX_DEFUALT_B_11N			0x85A
+#define	DM_REG_BB_PWR_SAV3_11N			0x85C
+#define	DM_REG_ANTSEL_CTRL_11N			0x860
+#define	DM_REG_RX_ANT_CTRL_11N			0x864
+#define	DM_REG_PIN_CTRL_11N			0x870
+#define	DM_REG_BB_PWR_SAV1_11N			0x874
+#define	DM_REG_ANTSEL_PATH_11N			0x878
+#define	DM_REG_BB_3WIRE_11N			0x88C
+#define	DM_REG_SC_CNT_11N			0x8C4
+#define	DM_REG_PSD_DATA_11N			0x8B4
+/*PAGE 9*/
+#define	DM_REG_ANT_MAPPING1_11N			0x914
+#define	DM_REG_ANT_MAPPING2_11N			0x918
+/*PAGE A*/
+#define	DM_REG_CCK_ANTDIV_PARA1_11N		0xA00
+#define	DM_REG_CCK_CCA_11N			0xA0A
+#define	DM_REG_CCK_ANTDIV_PARA2_11N		0xA0C
+#define	DM_REG_CCK_ANTDIV_PARA3_11N		0xA10
+#define	DM_REG_CCK_ANTDIV_PARA4_11N		0xA14
+#define	DM_REG_CCK_FILTER_PARA1_11N		0xA22
+#define	DM_REG_CCK_FILTER_PARA2_11N		0xA23
+#define	DM_REG_CCK_FILTER_PARA3_11N		0xA24
+#define	DM_REG_CCK_FILTER_PARA4_11N		0xA25
+#define	DM_REG_CCK_FILTER_PARA5_11N		0xA26
+#define	DM_REG_CCK_FILTER_PARA6_11N		0xA27
+#define	DM_REG_CCK_FILTER_PARA7_11N		0xA28
+#define	DM_REG_CCK_FILTER_PARA8_11N		0xA29
+#define	DM_REG_CCK_FA_RST_11N			0xA2C
+#define	DM_REG_CCK_FA_MSB_11N			0xA58
+#define	DM_REG_CCK_FA_LSB_11N			0xA5C
+#define	DM_REG_CCK_CCA_CNT_11N			0xA60
+#define	DM_REG_BB_PWR_SAV4_11N			0xA74
+/*PAGE B */
+#define	DM_REG_LNA_SWITCH_11N			0xB2C
+#define	DM_REG_PATH_SWITCH_11N			0xB30
+#define	DM_REG_RSSI_CTRL_11N			0xB38
+#define	DM_REG_CONFIG_ANTA_11N			0xB68
+#define	DM_REG_RSSI_BT_11N			0xB9C
+/*PAGE C */
+#define	DM_REG_OFDM_FA_HOLDC_11N		0xC00
+#define	DM_REG_RX_PATH_11N			0xC04
+#define	DM_REG_TRMUX_11N			0xC08
+#define	DM_REG_OFDM_FA_RSTC_11N			0xC0C
+#define	DM_REG_RXIQI_MATRIX_11N			0xC14
+#define	DM_REG_TXIQK_MATRIX_LSB1_11N		0xC4C
+#define	DM_REG_IGI_A_11N			0xC50
+#define	DM_REG_ANTDIV_PARA2_11N			0xC54
+#define	DM_REG_IGI_B_11N			0xC58
+#define	DM_REG_ANTDIV_PARA3_11N			0xC5C
+#define DM_REG_L1SBD_PD_CH_11N			0XC6C
+#define	DM_REG_BB_PWR_SAV2_11N			0xC70
+#define	DM_REG_RX_OFF_11N			0xC7C
+#define	DM_REG_TXIQK_MATRIXA_11N		0xC80
+#define	DM_REG_TXIQK_MATRIXB_11N		0xC88
+#define	DM_REG_TXIQK_MATRIXA_LSB2_11N		0xC94
+#define	DM_REG_TXIQK_MATRIXB_LSB2_11N		0xC9C
+#define	DM_REG_RXIQK_MATRIX_LSB_11N		0xCA0
+#define	DM_REG_ANTDIV_PARA1_11N			0xCA4
+#define	DM_REG_OFDM_FA_TYPE1_11N		0xCF0
+/*PAGE D */
+#define	DM_REG_OFDM_FA_RSTD_11N			0xD00
+#define	DM_REG_OFDM_FA_TYPE2_11N		0xDA0
+#define	DM_REG_OFDM_FA_TYPE3_11N		0xDA4
+#define	DM_REG_OFDM_FA_TYPE4_11N		0xDA8
+/*PAGE E */
+#define	DM_REG_TXAGC_A_6_18_11N			0xE00
+#define	DM_REG_TXAGC_A_24_54_11N		0xE04
+#define	DM_REG_TXAGC_A_1_MCS32_11N		0xE08
+#define	DM_REG_TXAGC_A_MCS0_3_11N		0xE10
+#define	DM_REG_TXAGC_A_MCS4_7_11N		0xE14
+#define	DM_REG_TXAGC_A_MCS8_11_11N		0xE18
+#define	DM_REG_TXAGC_A_MCS12_15_11N		0xE1C
+#define	DM_REG_FPGA0_IQK_11N			0xE28
+#define	DM_REG_TXIQK_TONE_A_11N			0xE30
+#define	DM_REG_RXIQK_TONE_A_11N			0xE34
+#define	DM_REG_TXIQK_PI_A_11N			0xE38
+#define	DM_REG_RXIQK_PI_A_11N			0xE3C
+#define	DM_REG_TXIQK_11N			0xE40
+#define	DM_REG_RXIQK_11N			0xE44
+#define	DM_REG_IQK_AGC_PTS_11N			0xE48
+#define	DM_REG_IQK_AGC_RSP_11N			0xE4C
+#define	DM_REG_BLUETOOTH_11N			0xE6C
+#define	DM_REG_RX_WAIT_CCA_11N			0xE70
+#define	DM_REG_TX_CCK_RFON_11N			0xE74
+#define	DM_REG_TX_CCK_BBON_11N			0xE78
+#define	DM_REG_OFDM_RFON_11N			0xE7C
+#define	DM_REG_OFDM_BBON_11N			0xE80
+#define		DM_REG_TX2RX_11N		0xE84
+#define	DM_REG_TX2TX_11N			0xE88
+#define	DM_REG_RX_CCK_11N			0xE8C
+#define	DM_REG_RX_OFDM_11N			0xED0
+#define	DM_REG_RX_WAIT_RIFS_11N			0xED4
+#define	DM_REG_RX2RX_11N			0xED8
+#define	DM_REG_STANDBY_11N			0xEDC
+#define	DM_REG_SLEEP_11N			0xEE0
+#define	DM_REG_PMPD_ANAEN_11N			0xEEC
+
+/*MAC REG LIST*/
+#define	DM_REG_BB_RST_11N			0x02
+#define	DM_REG_ANTSEL_PIN_11N			0x4C
+#define	DM_REG_EARLY_MODE_11N			0x4D0
+#define	DM_REG_RSSI_MONITOR_11N			0x4FE
+#define	DM_REG_EDCA_VO_11N			0x500
+#define	DM_REG_EDCA_VI_11N			0x504
+#define	DM_REG_EDCA_BE_11N			0x508
+#define	DM_REG_EDCA_BK_11N			0x50C
+#define	DM_REG_TXPAUSE_11N			0x522
+#define	DM_REG_RESP_TX_11N			0x6D8
+#define	DM_REG_ANT_TRAIN_PARA1_11N		0x7b0
+#define	DM_REG_ANT_TRAIN_PARA2_11N		0x7b4
+
+/*DIG Related*/
+#define	DM_BIT_IGI_11N				0x0000007F
+
+#define HAL_DM_DIG_DISABLE			BIT(0)
+#define HAL_DM_HIPWR_DISABLE			BIT(1)
+
+#define OFDM_TABLE_LENGTH			43
+#define CCK_TABLE_LENGTH			33
+
+#define OFDM_TABLE_SIZE				43
+#define CCK_TABLE_SIZE				33
+
+#define BW_AUTO_SWITCH_HIGH_LOW			25
+#define BW_AUTO_SWITCH_LOW_HIGH			30
+
+#define DM_DIG_THRESH_HIGH			40
+#define DM_DIG_THRESH_LOW			35
+
+#define DM_FALSEALARM_THRESH_LOW		400
+#define DM_FALSEALARM_THRESH_HIGH		1000
+
+#define DM_DIG_MAX				0x3e
+#define DM_DIG_MIN				0x1e
+
+#define DM_DIG_MAX_AP				0x32
+#define DM_DIG_MIN_AP				0x20
+
+#define DM_DIG_FA_UPPER				0x3e
+#define DM_DIG_FA_LOWER				0x1e
+#define DM_DIG_FA_TH0				0x200
+#define DM_DIG_FA_TH1				0x300
+#define DM_DIG_FA_TH2				0x400
+
+#define DM_DIG_BACKOFF_MAX			12
+#define DM_DIG_BACKOFF_MIN			-4
+#define DM_DIG_BACKOFF_DEFAULT			10
+
+#define RXPATHSELECTION_SS_TH_LOW		30
+#define RXPATHSELECTION_DIFF_TH			18
+
+#define DM_RATR_STA_INIT			0
+#define DM_RATR_STA_HIGH			1
+#define DM_RATR_STA_MIDDLE			2
+#define DM_RATR_STA_LOW				3
+
+#define CTS2SELF_THVAL				30
+#define REGC38_TH				20
+
+#define WAIOTTHVAL				25
+
+#define TXHIGHPWRLEVEL_NORMAL			0
+#define TXHIGHPWRLEVEL_LEVEL1			1
+#define TXHIGHPWRLEVEL_LEVEL2			2
+#define TXHIGHPWRLEVEL_BT1			3
+#define TXHIGHPWRLEVEL_BT2			4
+
+#define DM_TYPE_BYFW				0
+#define DM_TYPE_BYDRIVER			1
+
+#define TX_POWER_NEAR_FIELD_THRESH_LVL2		74
+#define TX_POWER_NEAR_FIELD_THRESH_LVL1		67
+#define TXPWRTRACK_MAX_IDX			6
+
+/* Dynamic ATC switch */
+#define ATC_STATUS_OFF				0x0	/* enable */
+#define	ATC_STATUS_ON				0x1	/* disable */
+#define	CFO_THRESHOLD_XTAL			10	/* kHz */
+#define	CFO_THRESHOLD_ATC			80	/* kHz */
+
+/* RSSI Dump Message */
+#define RA_RSSIDUMP				0xcb0
+#define RB_RSSIDUMP				0xcb1
+#define RS1_RXEVMDUMP				0xcb2
+#define RS2_RXEVMDUMP				0xcb3
+#define RA_RXSNRDUMP				0xcb4
+#define RB_RXSNRDUMP				0xcb5
+#define RA_CFOSHORTDUMP				0xcb6
+#define RB_CFOSHORTDUMP				0xcb8
+#define RA_CFOLONGDUMP				0xcba
+#define RB_CFOLONGDUMP				0xcbc
+
+void rtl92ee_dm_init(struct ieee80211_hw *hw);
+void rtl92ee_dm_watchdog(struct ieee80211_hw *hw);
+void rtl92ee_dm_write_cck_cca_thres(struct ieee80211_hw *hw,
+				    u8 cur_thres);
+void rtl92ee_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi);
+void rtl92ee_dm_init_edca_turbo(struct ieee80211_hw *hw);
+void rtl92ee_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
+void rtl92ee_dm_dynamic_arfb_select(struct ieee80211_hw *hw,
+				    u8 rate, bool collision_state);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
new file mode 100644
index 0000000..45c128b
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
@@ -0,0 +1,906 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "../core.h"
+#include "reg.h"
+#include "def.h"
+#include "fw.h"
+#include "dm.h"
+
+static void _rtl92ee_enable_fw_download(struct ieee80211_hw *hw, bool enable)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 tmp;
+
+	if (enable) {
+		rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x05);
+
+		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
+		rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
+	} else {
+		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
+	}
+}
+
+static void _rtl92ee_fw_block_write(struct ieee80211_hw *hw,
+				    const u8 *buffer, u32 size)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 blocksize = sizeof(u32);
+	u8 *bufferptr = (u8 *)buffer;
+	u32 *pu4byteptr = (u32 *)buffer;
+	u32 i, offset, blockcount, remainsize;
+
+	blockcount = size / blocksize;
+	remainsize = size % blocksize;
+
+	for (i = 0; i < blockcount; i++) {
+		offset = i * blocksize;
+		rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
+				*(pu4byteptr + i));
+	}
+
+	if (remainsize) {
+		offset = blockcount * blocksize;
+		bufferptr += offset;
+		for (i = 0; i < remainsize; i++) {
+			rtl_write_byte(rtlpriv,
+				       (FW_8192C_START_ADDRESS + offset + i),
+				       *(bufferptr + i));
+		}
+	}
+}
+
+static void _rtl92ee_fw_page_write(struct ieee80211_hw *hw, u32 page,
+				   const u8 *buffer, u32 size)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 value8;
+	u8 u8page = (u8)(page & 0x07);
+
+	value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
+	rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
+
+	_rtl92ee_fw_block_write(hw, buffer, size);
+}
+
+static void _rtl92ee_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
+{
+	u32 fwlen = *pfwlen;
+	u8 remain = (u8)(fwlen % 4);
+
+	remain = (remain == 0) ? 0 : (4 - remain);
+
+	while (remain > 0) {
+		pfwbuf[fwlen] = 0;
+		fwlen++;
+		remain--;
+	}
+
+	*pfwlen = fwlen;
+}
+
+static void _rtl92ee_write_fw(struct ieee80211_hw *hw,
+			      enum version_8192e version,
+			      u8 *buffer, u32 size)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 *bufferptr = (u8 *)buffer;
+	u32 pagenums, remainsize;
+	u32 page, offset;
+
+	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "FW size is %d bytes,\n", size);
+
+	_rtl92ee_fill_dummy(bufferptr, &size);
+
+	pagenums = size / FW_8192C_PAGE_SIZE;
+	remainsize = size % FW_8192C_PAGE_SIZE;
+
+	if (pagenums > 8) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Page numbers should not greater then 8\n");
+	}
+
+	for (page = 0; page < pagenums; page++) {
+		offset = page * FW_8192C_PAGE_SIZE;
+		_rtl92ee_fw_page_write(hw, page, (bufferptr + offset),
+				       FW_8192C_PAGE_SIZE);
+		udelay(2);
+	}
+
+	if (remainsize) {
+		offset = pagenums * FW_8192C_PAGE_SIZE;
+		page = pagenums;
+		_rtl92ee_fw_page_write(hw, page, (bufferptr + offset),
+				       remainsize);
+	}
+}
+
+static int _rtl92ee_fw_free_to_go(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	int err = -EIO;
+	u32 counter = 0;
+	u32 value32;
+
+	do {
+		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+	} while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
+		 (!(value32 & FWDL_CHKSUM_RPT)));
+
+	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
+			  value32);
+		goto exit;
+	}
+
+	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+		 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
+
+	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+	value32 |= MCUFWDL_RDY;
+	value32 &= ~WINTINI_RDY;
+	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
+
+	rtl92ee_firmware_selfreset(hw);
+	counter = 0;
+
+	do {
+		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+		if (value32 & WINTINI_RDY) {
+			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD ,
+				 "Polling FW ready success!! REG_MCUFWDL:0x%08x. count = %d\n",
+				 value32, counter);
+			err = 0;
+			goto exit;
+		}
+
+		udelay(FW_8192C_POLLING_DELAY*10);
+
+	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
+
+	RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+		 "Polling FW ready fail!! REG_MCUFWDL:0x%08x. count = %d\n",
+		 value32, counter);
+
+exit:
+	return err;
+}
+
+int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl92c_firmware_header *pfwheader;
+	u8 *pfwdata;
+	u32 fwsize;
+	int err;
+	enum version_8192e version = rtlhal->version;
+
+	if (!rtlhal->pfirmware)
+		return 1;
+
+	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
+	rtlhal->fw_version = pfwheader->version;
+	rtlhal->fw_subversion = pfwheader->subversion;
+	pfwdata = (u8 *)rtlhal->pfirmware;
+	fwsize = rtlhal->fwsize;
+	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+		 "normal Firmware SIZE %d\n" , fwsize);
+
+	if (IS_FW_HEADER_EXIST(pfwheader)) {
+		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+			 "Firmware Version(%d), Signature(%#x),Size(%d)\n",
+			  pfwheader->version, pfwheader->signature,
+			  (int)sizeof(struct rtl92c_firmware_header));
+
+		pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
+		fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
+	} else {
+		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+			 "Firmware no Header, Signature(%#x)\n",
+			  pfwheader->signature);
+	}
+
+	if (rtlhal->mac_func_enable) {
+		if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
+			rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
+			rtl92ee_firmware_selfreset(hw);
+		}
+	}
+	_rtl92ee_enable_fw_download(hw, true);
+	_rtl92ee_write_fw(hw, version, pfwdata, fwsize);
+	_rtl92ee_enable_fw_download(hw, false);
+
+	err = _rtl92ee_fw_free_to_go(hw);
+	if (err) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Firmware is not ready to run!\n");
+	} else {
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD ,
+			 "Firmware is ready to run!\n");
+	}
+
+	return 0;
+}
+
+static bool _rtl92ee_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 val_hmetfr;
+	bool result = false;
+
+	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
+	if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
+		result = true;
+	return result;
+}
+
+static void _rtl92ee_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id,
+				      u32 cmd_len, u8 *cmdbuffer)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	u8 boxnum;
+	u16 box_reg = 0, box_extreg = 0;
+	u8 u1b_tmp;
+	bool isfw_read = false;
+	u8 buf_index = 0;
+	bool bwrite_sucess = false;
+	u8 wait_h2c_limmit = 100;
+	u8 boxcontent[4], boxextcontent[4];
+	u32 h2c_waitcounter = 0;
+	unsigned long flag;
+	u8 idx;
+
+	if (ppsc->dot11_psmode != EACTIVE ||
+	    ppsc->inactive_pwrstate == ERFOFF) {
+		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
+			 "FillH2CCommand8192E(): Return because RF is off!!!\n");
+		return;
+	}
+
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD , "come in\n");
+
+	/* 1. Prevent race condition in setting H2C cmd.
+	 * (copy from MgntActSet_RF_State().)
+	 */
+	while (true) {
+		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+		if (rtlhal->h2c_setinprogress) {
+			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
+				 "H2C set in progress! Wait to set..element_id(%d).\n",
+				  element_id);
+
+			while (rtlhal->h2c_setinprogress) {
+				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
+						       flag);
+				h2c_waitcounter++;
+				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
+					 "Wait 100 us (%d times)...\n",
+					  h2c_waitcounter);
+				udelay(100);
+
+				if (h2c_waitcounter > 1000)
+					return;
+				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
+						  flag);
+			}
+			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+		} else {
+			rtlhal->h2c_setinprogress = true;
+			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+			break;
+		}
+	}
+
+	while (!bwrite_sucess) {
+		/* 2. Find the last BOX number which has been writen. */
+		boxnum = rtlhal->last_hmeboxnum;
+		switch (boxnum) {
+		case 0:
+			box_reg = REG_HMEBOX_0;
+			box_extreg = REG_HMEBOX_EXT_0;
+			break;
+		case 1:
+			box_reg = REG_HMEBOX_1;
+			box_extreg = REG_HMEBOX_EXT_1;
+			break;
+		case 2:
+			box_reg = REG_HMEBOX_2;
+			box_extreg = REG_HMEBOX_EXT_2;
+			break;
+		case 3:
+			box_reg = REG_HMEBOX_3;
+			box_extreg = REG_HMEBOX_EXT_3;
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
+			break;
+		}
+
+		/* 3. Check if the box content is empty. */
+		isfw_read = false;
+		u1b_tmp = rtl_read_byte(rtlpriv, REG_CR);
+
+		if (u1b_tmp != 0xea) {
+			isfw_read = true;
+		} else {
+			if (rtl_read_byte(rtlpriv, REG_TXDMA_STATUS) == 0xea ||
+			    rtl_read_byte(rtlpriv, REG_TXPKT_EMPTY) == 0xea)
+				rtl_write_byte(rtlpriv, REG_SYS_CFG1 + 3, 0xff);
+		}
+
+		if (isfw_read) {
+			wait_h2c_limmit = 100;
+			isfw_read = _rtl92ee_check_fw_read_last_h2c(hw, boxnum);
+			while (!isfw_read) {
+				wait_h2c_limmit--;
+				if (wait_h2c_limmit == 0) {
+					RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
+						 "Waiting too long for FW read clear HMEBox(%d)!!!\n",
+						 boxnum);
+					break;
+				}
+				udelay(10);
+				isfw_read =
+				  _rtl92ee_check_fw_read_last_h2c(hw, boxnum);
+				u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
+				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
+					 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
+					 boxnum, u1b_tmp);
+			}
+		}
+
+		/* If Fw has not read the last
+		 * H2C cmd, break and give up this H2C.
+		 */
+		if (!isfw_read) {
+			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
+				 "Write H2C reg BOX[%d] fail,Fw don't read.\n",
+				 boxnum);
+			break;
+		}
+		/* 4. Fill the H2C cmd into box */
+		memset(boxcontent, 0, sizeof(boxcontent));
+		memset(boxextcontent, 0, sizeof(boxextcontent));
+		boxcontent[0] = element_id;
+		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
+			 "Write element_id box_reg(%4x) = %2x\n",
+			  box_reg, element_id);
+
+		switch (cmd_len) {
+		case 1:
+		case 2:
+		case 3:
+			/*boxcontent[0] &= ~(BIT(7));*/
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index, cmd_len);
+
+			for (idx = 0; idx < 4; idx++) {
+				rtl_write_byte(rtlpriv, box_reg + idx,
+					       boxcontent[idx]);
+			}
+			break;
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+			/*boxcontent[0] |= (BIT(7));*/
+			memcpy((u8 *)(boxextcontent),
+			       cmdbuffer + buf_index+3, cmd_len-3);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index, 3);
+
+			for (idx = 0; idx < 4; idx++) {
+				rtl_write_byte(rtlpriv, box_extreg + idx,
+					       boxextcontent[idx]);
+			}
+
+			for (idx = 0; idx < 4; idx++) {
+				rtl_write_byte(rtlpriv, box_reg + idx,
+					       boxcontent[idx]);
+			}
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
+			break;
+		}
+
+		bwrite_sucess = true;
+
+		rtlhal->last_hmeboxnum = boxnum + 1;
+		if (rtlhal->last_hmeboxnum == 4)
+			rtlhal->last_hmeboxnum = 0;
+
+		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
+			 "pHalData->last_hmeboxnum  = %d\n",
+			  rtlhal->last_hmeboxnum);
+	}
+
+	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+	rtlhal->h2c_setinprogress = false;
+	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD , "go out\n");
+}
+
+void rtl92ee_fill_h2c_cmd(struct ieee80211_hw *hw,
+			  u8 element_id, u32 cmd_len, u8 *cmdbuffer)
+{
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u32 tmp_cmdbuf[2];
+
+	if (!rtlhal->fw_ready) {
+		RT_ASSERT(false,
+			  "return H2C cmd because of Fw download fail!!!\n");
+		return;
+	}
+
+	memset(tmp_cmdbuf, 0, 8);
+	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
+	_rtl92ee_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
+}
+
+void rtl92ee_firmware_selfreset(struct ieee80211_hw *hw)
+{
+	u8 u1b_tmp;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
+
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
+
+	udelay(50);
+
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));
+
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD ,
+		 "  _8051Reset92E(): 8051 reset success .\n");
+}
+
+void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 u1_h2c_set_pwrmode[H2C_92E_PWEMODE_LENGTH] = { 0 };
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	u8 rlbm , power_state = 0;
+
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD , "FW LPS mode = %d\n", mode);
+
+	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
+	rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/
+	SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
+	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
+					 (rtlpriv->mac80211.p2p) ?
+					 ppsc->smart_ps : 1);
+	SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
+					       ppsc->reg_max_lps_awakeintvl);
+	SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
+	if (mode == FW_PS_ACTIVE_MODE)
+		power_state |= FW_PWR_STATE_ACTIVE;
+	else
+		power_state |= FW_PWR_STATE_RF_OFF;
+	SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
+
+	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+		      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
+		      u1_h2c_set_pwrmode, H2C_92E_PWEMODE_LENGTH);
+	rtl92ee_fill_h2c_cmd(hw, H2C_92E_SETPWRMODE, H2C_92E_PWEMODE_LENGTH,
+			     u1_h2c_set_pwrmode);
+}
+
+void rtl92ee_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus)
+{
+	u8 parm[3] = { 0 , 0 , 0 };
+	/* parm[0]: bit0=0-->Disconnect, bit0=1-->Connect
+	 *          bit1=0-->update Media Status to MACID
+	 *          bit1=1-->update Media Status from MACID to MACID_End
+	 * parm[1]: MACID, if this is INFRA_STA, MacID = 0
+	 * parm[2]: MACID_End
+	 */
+
+	SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, mstatus);
+	SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0);
+
+	rtl92ee_fill_h2c_cmd(hw, H2C_92E_MSRRPT, 3, parm);
+}
+
+#define BEACON_PG		0 /* ->1 */
+#define PSPOLL_PG		2
+#define NULL_PG			3
+#define PROBERSP_PG		4 /* ->5 */
+
+#define TOTAL_RESERVED_PKT_LEN	768
+
+static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
+	/* page 0 beacon */
+	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
+	0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65,
+	0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B,
+	0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06,
+	0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32,
+	0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C,
+	0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C,
+	0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50,
+	0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04,
+	0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00,
+
+	/* page 1 beacon */
+	0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+	/* page 2  ps-poll */
+	0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B,
+	0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+	/* page 3  null */
+	0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B,
+	0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
+	0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+	/* page 4  probe_resp */
+	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
+	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
+	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
+	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
+	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
+	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
+	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
+	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
+	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
+	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
+	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+	/* page 5  probe_resp */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct sk_buff *skb = NULL;
+
+	u32 totalpacketlen;
+	bool rtstatus;
+	u8 u1rsvdpageloc[5] = { 0 };
+	bool b_dlok = false;
+
+	u8 *beacon;
+	u8 *p_pspoll;
+	u8 *nullfunc;
+	u8 *p_probersp;
+	/*---------------------------------------------------------
+	 *			(1) beacon
+	 *---------------------------------------------------------
+	 */
+	beacon = &reserved_page_packet[BEACON_PG * 128];
+	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
+
+	/*-------------------------------------------------------
+	 *			(2) ps-poll
+	 *--------------------------------------------------------
+	 */
+	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
+	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
+	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
+	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
+
+	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
+
+	/*--------------------------------------------------------
+	 *			(3) null data
+	 *---------------------------------------------------------
+	 */
+	nullfunc = &reserved_page_packet[NULL_PG * 128];
+	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
+	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
+
+	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
+
+	/*---------------------------------------------------------
+	 *			(4) probe response
+	 *----------------------------------------------------------
+	 */
+	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
+	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
+	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
+
+	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
+
+	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
+
+	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
+		      "rtl92ee_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+		      &reserved_page_packet[0], totalpacketlen);
+	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
+		      "rtl92ee_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+		      u1rsvdpageloc, 3);
+
+	skb = dev_alloc_skb(totalpacketlen);
+	memcpy((u8 *)skb_put(skb, totalpacketlen),
+	       &reserved_page_packet, totalpacketlen);
+
+	rtstatus = rtl_cmd_send_packet(hw, skb);
+
+	if (rtstatus)
+		b_dlok = true;
+
+	if (b_dlok) {
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD ,
+			 "Set RSVD page location to Fw.\n");
+		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
+			      "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
+		rtl92ee_fill_h2c_cmd(hw, H2C_92E_RSVDPAGE,
+				     sizeof(u1rsvdpageloc), u1rsvdpageloc);
+	} else {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
+	}
+}
+
+/*Shoud check FW support p2p or not.*/
+static void rtl92ee_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
+{
+	u8 u1_ctwindow_period[1] = {ctwindow};
+
+	rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
+}
+
+void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_p2p_ps_info *p2pinfo = &rtlps->p2p_ps_info;
+	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
+	u8 i;
+	u16 ctwindow;
+	u32 start_time, tsf_low;
+
+	switch (p2p_ps_state) {
+	case P2P_PS_DISABLE:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_DISABLE\n");
+		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
+		break;
+	case P2P_PS_ENABLE:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_ENABLE\n");
+		/* update CTWindow value. */
+		if (p2pinfo->ctwindow > 0) {
+			p2p_ps_offload->ctwindow_en = 1;
+			ctwindow = p2pinfo->ctwindow;
+			rtl92ee_set_p2p_ctw_period_cmd(hw, ctwindow);
+		}
+		/* hw only support 2 set of NoA */
+		for (i = 0 ; i < p2pinfo->noa_num ; i++) {
+			/* To control the register setting for which NOA*/
+			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
+			if (i == 0)
+				p2p_ps_offload->noa0_en = 1;
+			else
+				p2p_ps_offload->noa1_en = 1;
+			/* config P2P NoA Descriptor Register */
+			rtl_write_dword(rtlpriv, 0x5E0,
+					p2pinfo->noa_duration[i]);
+			rtl_write_dword(rtlpriv, 0x5E4,
+					p2pinfo->noa_interval[i]);
+
+			/*Get Current TSF value */
+			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+			start_time = p2pinfo->noa_start_time[i];
+			if (p2pinfo->noa_count_type[i] != 1) {
+				while (start_time <= (tsf_low + (50 * 1024))) {
+					start_time += p2pinfo->noa_interval[i];
+					if (p2pinfo->noa_count_type[i] != 255)
+						p2pinfo->noa_count_type[i]--;
+				}
+			}
+			rtl_write_dword(rtlpriv, 0x5E8, start_time);
+			rtl_write_dword(rtlpriv, 0x5EC,
+					p2pinfo->noa_count_type[i]);
+		}
+		if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
+			/* rst p2p circuit */
+			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
+			p2p_ps_offload->offload_en = 1;
+
+			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
+				p2p_ps_offload->role = 1;
+				p2p_ps_offload->allstasleep = 0;
+			} else {
+				p2p_ps_offload->role = 0;
+			}
+			p2p_ps_offload->discovery = 0;
+		}
+		break;
+	case P2P_PS_SCAN:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_SCAN\n");
+		p2p_ps_offload->discovery = 1;
+		break;
+	case P2P_PS_SCAN_DONE:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_SCAN_DONE\n");
+		p2p_ps_offload->discovery = 0;
+		p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
+		break;
+	default:
+		break;
+	}
+	rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_OFFLOAD, 1,
+			     (u8 *)p2p_ps_offload);
+}
+
+static void _rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw,
+					   u8 *cmd_buf, u8 cmd_len)
+{
+	u8 rate = cmd_buf[0] & 0x3F;
+	bool collision_state = cmd_buf[3] & BIT(0);
+
+	rtl92ee_dm_dynamic_arfb_select(hw, rate, collision_state);
+}
+
+static void _rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id,
+					 u8 c2h_cmd_len, u8 *tmp_buf)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	switch (c2h_cmd_id) {
+	case C2H_8192E_DBG:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+			 "[C2H], C2H_8723BE_DBG!!\n");
+		break;
+	case C2H_8192E_TXBF:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+			 "[C2H], C2H_8192E_TXBF!!\n");
+		break;
+	case C2H_8192E_TX_REPORT:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE ,
+			 "[C2H], C2H_8723BE_TX_REPORT!\n");
+		break;
+	case C2H_8192E_BT_INFO:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+			 "[C2H], C2H_8723BE_BT_INFO!!\n");
+		rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf,
+							      c2h_cmd_len);
+		break;
+	case C2H_8192E_BT_MP:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+			 "[C2H], C2H_8723BE_BT_MP!!\n");
+		break;
+	case C2H_8192E_RA_RPT:
+		_rtl92ee_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len);
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+			 "[C2H], Unkown packet!! CmdId(%#X)!\n", c2h_cmd_id);
+		break;
+	}
+}
+
+void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0;
+	u8 *tmp_buf = NULL;
+
+	c2h_cmd_id = buffer[0];
+	c2h_cmd_seq = buffer[1];
+	c2h_cmd_len = len - 2;
+	tmp_buf = buffer + 2;
+
+	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+		 "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n",
+		 c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len);
+
+	RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE,
+		      "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
+
+	_rtl92ee_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.h b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.h
new file mode 100644
index 0000000..3e2a48e
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.h
@@ -0,0 +1,208 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92E__FW__H__
+#define __RTL92E__FW__H__
+
+#define FW_8192C_SIZE				0x8000
+#define FW_8192C_START_ADDRESS			0x1000
+#define FW_8192C_END_ADDRESS			0x5FFF
+#define FW_8192C_PAGE_SIZE			4096
+#define FW_8192C_POLLING_DELAY			5
+#define FW_8192C_POLLING_TIMEOUT_COUNT		3000
+
+#define IS_FW_HEADER_EXIST(_pfwhdr)	\
+	((_pfwhdr->signature&0xFFF0) == 0x92E0)
+#define USE_OLD_WOWLAN_DEBUG_FW 0
+
+#define H2C_92E_RSVDPAGE_LOC_LEN		5
+#define H2C_92E_PWEMODE_LENGTH			5
+#define H2C_92E_JOINBSSRPT_LENGTH		1
+#define H2C_92E_AP_OFFLOAD_LENGTH		3
+#define H2C_92E_WOWLAN_LENGTH			3
+#define H2C_92E_KEEP_ALIVE_CTRL_LENGTH		3
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+#define H2C_92E_REMOTE_WAKE_CTRL_LEN		1
+#else
+#define H2C_92E_REMOTE_WAKE_CTRL_LEN		3
+#endif
+#define H2C_92E_AOAC_GLOBAL_INFO_LEN		2
+#define H2C_92E_AOAC_RSVDPAGE_LOC_LEN		7
+
+/* Fw PS state for RPWM.
+*BIT[2:0] = HW state
+*BIT[3] = Protocol PS state,  1: register active state, 0: register sleep state
+*BIT[4] = sub-state
+*/
+#define	FW_PS_RF_ON		BIT(2)
+#define	FW_PS_REGISTER_ACTIVE	BIT(3)
+
+#define	FW_PS_ACK		BIT(6)
+#define	FW_PS_TOGGLE		BIT(7)
+
+ /* 92E RPWM value*/
+ /* BIT[0] = 1: 32k, 0: 40M*/
+#define	FW_PS_CLOCK_OFF		BIT(0)		/* 32k */
+#define	FW_PS_CLOCK_ON		0		/* 40M */
+
+#define	FW_PS_STATE_MASK		(0x0F)
+#define	FW_PS_STATE_HW_MASK		(0x07)
+#define	FW_PS_STATE_INT_MASK		(0x3F)
+
+#define	FW_PS_STATE(x)			(FW_PS_STATE_MASK & (x))
+
+#define	FW_PS_STATE_ALL_ON_92E		(FW_PS_CLOCK_ON)
+#define	FW_PS_STATE_RF_ON_92E		(FW_PS_CLOCK_ON)
+#define	FW_PS_STATE_RF_OFF_92E		(FW_PS_CLOCK_ON)
+#define	FW_PS_STATE_RF_OFF_LOW_PWR	(FW_PS_CLOCK_OFF)
+
+/* For 92E H2C PwrMode Cmd ID 5.*/
+#define	FW_PWR_STATE_ACTIVE	((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
+#define	FW_PWR_STATE_RF_OFF	0
+
+#define	FW_PS_IS_ACK(x)		((x) & FW_PS_ACK)
+
+#define	IS_IN_LOW_POWER_STATE_92E(__state)		\
+	(FW_PS_STATE(__state) == FW_PS_CLOCK_OFF)
+
+#define	FW_PWR_STATE_ACTIVE	((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
+#define	FW_PWR_STATE_RF_OFF	0
+
+struct rtl92c_firmware_header {
+	u16 signature;
+	u8 category;
+	u8 function;
+	u16 version;
+	u8 subversion;
+	u8 rsvd1;
+	u8 month;
+	u8 date;
+	u8 hour;
+	u8 minute;
+	u16 ramcodesize;
+	u16 rsvd2;
+	u32 svnindex;
+	u32 rsvd3;
+	u32 rsvd4;
+	u32 rsvd5;
+};
+
+enum rtl8192e_h2c_cmd {
+	H2C_92E_RSVDPAGE = 0,
+	H2C_92E_MSRRPT = 1,
+	H2C_92E_SCAN = 2,
+	H2C_92E_KEEP_ALIVE_CTRL = 3,
+	H2C_92E_DISCONNECT_DECISION = 4,
+#if (USE_OLD_WOWLAN_DEBUG_FW == 1)
+	H2C_92E_WO_WLAN = 5,
+#endif
+	H2C_92E_INIT_OFFLOAD = 6,
+#if (USE_OLD_WOWLAN_DEBUG_FW == 1)
+	H2C_92E_REMOTE_WAKE_CTRL = 7,
+#endif
+	H2C_92E_AP_OFFLOAD = 8,
+	H2C_92E_BCN_RSVDPAGE = 9,
+	H2C_92E_PROBERSP_RSVDPAGE = 10,
+
+	H2C_92E_SETPWRMODE = 0x20,
+	H2C_92E_PS_TUNING_PARA = 0x21,
+	H2C_92E_PS_TUNING_PARA2 = 0x22,
+	H2C_92E_PS_LPS_PARA = 0x23,
+	H2C_92E_P2P_PS_OFFLOAD = 024,
+
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+	H2C_92E_WO_WLAN = 0x80,
+	H2C_92E_REMOTE_WAKE_CTRL = 0x81,
+	H2C_92E_AOAC_GLOBAL_INFO = 0x82,
+	H2C_92E_AOAC_RSVDPAGE = 0x83,
+#endif
+	H2C_92E_RA_MASK = 0x40,
+	H2C_92E_RSSI_REPORT = 0x42,
+	H2C_92E_SELECTIVE_SUSPEND_ROF_CMD,
+	H2C_92E_P2P_PS_MODE,
+	H2C_92E_PSD_RESULT,
+	/*Not defined CTW CMD for P2P yet*/
+	H2C_92E_P2P_PS_CTW_CMD,
+	MAX_92E_H2CCMD
+};
+
+enum rtl8192e_c2h_evt {
+	C2H_8192E_DBG = 0,
+	C2H_8192E_LB = 1,
+	C2H_8192E_TXBF = 2,
+	C2H_8192E_TX_REPORT = 3,
+	C2H_8192E_BT_INFO = 9,
+	C2H_8192E_BT_MP = 11,
+	C2H_8192E_RA_RPT = 12,
+	MAX_8192E_C2HEVENT
+};
+
+#define pagenum_128(_len)	\
+	(u32)(((_len) >> 7) + ((_len) & 0x7F ? 1 : 0))
+
+#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val)			\
+	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_RLBM(__cmd, __val)			\
+	SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 4, __val)
+#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__cmd, __val)		\
+	SET_BITS_TO_LE_1BYTE((__cmd)+1, 4, 4, __val)
+#define SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(__cmd, __val)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(__cmd, __val)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__cmd, __val)		\
+	SET_BITS_TO_LE_1BYTE((__cmd)+4, 0, 8, __val)
+#define GET_92E_H2CCMD_PWRMODE_PARM_MODE(__cmd)			\
+	LE_BITS_TO_1BYTE(__cmd, 0, 8)
+
+#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val)		\
+	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val)		\
+	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val)		\
+	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val)		\
+	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+
+/* _MEDIA_STATUS_RPT_PARM_CMD1 */
+#define SET_H2CCMD_MSRRPT_PARM_OPMODE(__cmd, __val)		\
+	SET_BITS_TO_LE_1BYTE(__cmd, 0, 1, __val)
+#define SET_H2CCMD_MSRRPT_PARM_MACID_IND(__cmd, __val)		\
+	SET_BITS_TO_LE_1BYTE(__cmd, 1, 1, __val)
+#define SET_H2CCMD_MSRRPT_PARM_MACID(__cmd, __val)		\
+	SET_BITS_TO_LE_1BYTE(__cmd+1, 0, 8, __val)
+#define SET_H2CCMD_MSRRPT_PARM_MACID_END(__cmd, __val)		\
+	SET_BITS_TO_LE_1BYTE(__cmd+2, 0, 8, __val)
+
+int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw);
+void rtl92ee_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
+			  u32 cmd_len, u8 *cmdbuffer);
+void rtl92ee_firmware_selfreset(struct ieee80211_hw *hw);
+void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
+void rtl92ee_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus);
+void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
+void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
+void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
new file mode 100644
index 0000000..dfdc9b2
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
@@ -0,0 +1,2569 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../efuse.h"
+#include "../base.h"
+#include "../regd.h"
+#include "../cam.h"
+#include "../ps.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "led.h"
+#include "hw.h"
+#include "../pwrseqcmd.h"
+#include "pwrseq.h"
+
+#define LLT_CONFIG	5
+
+static void _rtl92ee_set_bcn_ctrl_reg(struct ieee80211_hw *hw,
+				      u8 set_bits, u8 clear_bits)
+{
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtlpci->reg_bcn_ctrl_val |= set_bits;
+	rtlpci->reg_bcn_ctrl_val &= ~clear_bits;
+
+	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8)rtlpci->reg_bcn_ctrl_val);
+}
+
+static void _rtl92ee_stop_tx_beacon(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 tmp;
+
+	tmp = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp & (~BIT(6)));
+	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64);
+	tmp = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+	tmp &= ~(BIT(0));
+	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp);
+}
+
+static void _rtl92ee_resume_tx_beacon(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 tmp;
+
+	tmp = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp | BIT(6));
+	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+	tmp = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+	tmp |= BIT(0);
+	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp);
+}
+
+static void _rtl92ee_enable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+	_rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(1));
+}
+
+static void _rtl92ee_return_beacon_queue_skb(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
+	unsigned long flags;
+
+	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+	while (skb_queue_len(&ring->queue)) {
+		struct rtl_tx_buffer_desc *entry =
+						&ring->buffer_desc[ring->idx];
+		struct sk_buff *skb = __skb_dequeue(&ring->queue);
+
+		pci_unmap_single(rtlpci->pdev,
+				 rtlpriv->cfg->ops->get_desc(
+				 (u8 *)entry, true, HW_DESC_TXBUFF_ADDR),
+				 skb->len, PCI_DMA_TODEVICE);
+		kfree_skb(skb);
+		ring->idx = (ring->idx + 1) % ring->entries;
+	}
+	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+}
+
+static void _rtl92ee_disable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+	_rtl92ee_set_bcn_ctrl_reg(hw, BIT(1), 0);
+}
+
+static void _rtl92ee_set_fw_clock_on(struct ieee80211_hw *hw,
+				     u8 rpwm_val, bool b_need_turn_off_ckk)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	bool b_support_remote_wake_up;
+	u32 count = 0, isr_regaddr, content;
+	bool b_schedule_timer = b_need_turn_off_ckk;
+
+	rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+				      (u8 *)(&b_support_remote_wake_up));
+
+	if (!rtlhal->fw_ready)
+		return;
+	if (!rtlpriv->psc.fw_current_inpsmode)
+		return;
+
+	while (1) {
+		spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+		if (rtlhal->fw_clk_change_in_progress) {
+			while (rtlhal->fw_clk_change_in_progress) {
+				spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+				count++;
+				udelay(100);
+				if (count > 1000)
+					return;
+				spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+			}
+			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+		} else {
+			rtlhal->fw_clk_change_in_progress = false;
+			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+			break;
+		}
+	}
+
+	if (IS_IN_LOW_POWER_STATE_92E(rtlhal->fw_ps_state)) {
+		rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM,
+					      (u8 *)(&rpwm_val));
+		if (FW_PS_IS_ACK(rpwm_val)) {
+			isr_regaddr = REG_HISR;
+			content = rtl_read_dword(rtlpriv, isr_regaddr);
+			while (!(content & IMR_CPWM) && (count < 500)) {
+				udelay(50);
+				count++;
+				content = rtl_read_dword(rtlpriv, isr_regaddr);
+			}
+
+			if (content & IMR_CPWM) {
+				rtl_write_word(rtlpriv, isr_regaddr, 0x0100);
+				rtlhal->fw_ps_state = FW_PS_STATE_RF_ON_92E;
+				RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+					 "Receive CPWM INT!!! PSState = %X\n",
+					 rtlhal->fw_ps_state);
+			}
+		}
+
+		spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+		rtlhal->fw_clk_change_in_progress = false;
+		spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+		if (b_schedule_timer) {
+			mod_timer(&rtlpriv->works.fw_clockoff_timer,
+				  jiffies + MSECS(10));
+		}
+	} else  {
+		spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+		rtlhal->fw_clk_change_in_progress = false;
+		spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+	}
+}
+
+static void _rtl92ee_set_fw_clock_off(struct ieee80211_hw *hw, u8 rpwm_val)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl8192_tx_ring *ring;
+	enum rf_pwrstate rtstate;
+	bool b_schedule_timer = false;
+	u8 queue;
+
+	if (!rtlhal->fw_ready)
+		return;
+	if (!rtlpriv->psc.fw_current_inpsmode)
+		return;
+	if (!rtlhal->allow_sw_to_change_hwclc)
+		return;
+
+	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE, (u8 *)(&rtstate));
+	if (rtstate == ERFOFF || rtlpriv->psc.inactive_pwrstate == ERFOFF)
+		return;
+
+	for (queue = 0; queue < RTL_PCI_MAX_TX_QUEUE_COUNT; queue++) {
+		ring = &rtlpci->tx_ring[queue];
+		if (skb_queue_len(&ring->queue)) {
+			b_schedule_timer = true;
+			break;
+		}
+	}
+
+	if (b_schedule_timer) {
+		mod_timer(&rtlpriv->works.fw_clockoff_timer,
+			  jiffies + MSECS(10));
+		return;
+	}
+
+	if (FW_PS_STATE(rtlhal->fw_ps_state) != FW_PS_STATE_RF_OFF_LOW_PWR) {
+		spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+		if (!rtlhal->fw_clk_change_in_progress) {
+			rtlhal->fw_clk_change_in_progress = true;
+			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+			rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val);
+			rtl_write_word(rtlpriv, REG_HISR, 0x0100);
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+						      (u8 *)(&rpwm_val));
+			spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+			rtlhal->fw_clk_change_in_progress = false;
+			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+		} else {
+			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+			mod_timer(&rtlpriv->works.fw_clockoff_timer,
+				  jiffies + MSECS(10));
+		}
+	}
+}
+
+static void _rtl92ee_set_fw_ps_rf_on(struct ieee80211_hw *hw)
+{
+	u8 rpwm_val = 0;
+
+	rpwm_val |= (FW_PS_STATE_RF_OFF_92E | FW_PS_ACK);
+	_rtl92ee_set_fw_clock_on(hw, rpwm_val, true);
+}
+
+static void _rtl92ee_set_fw_ps_rf_off_low_power(struct ieee80211_hw *hw)
+{
+	u8 rpwm_val = 0;
+
+	rpwm_val |= FW_PS_STATE_RF_OFF_LOW_PWR;
+	_rtl92ee_set_fw_clock_off(hw, rpwm_val);
+}
+
+void rtl92ee_fw_clk_off_timer_callback(unsigned long data)
+{
+	struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+
+	_rtl92ee_set_fw_ps_rf_off_low_power(hw);
+}
+
+static void _rtl92ee_fwlps_leave(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	bool fw_current_inps = false;
+	u8 rpwm_val = 0, fw_pwrmode = FW_PS_ACTIVE_MODE;
+
+	if (ppsc->low_power_enable) {
+		rpwm_val = (FW_PS_STATE_ALL_ON_92E | FW_PS_ACK);/* RF on */
+		_rtl92ee_set_fw_clock_on(hw, rpwm_val, false);
+		rtlhal->allow_sw_to_change_hwclc = false;
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+					      (u8 *)(&fw_pwrmode));
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+					      (u8 *)(&fw_current_inps));
+	} else {
+		rpwm_val = FW_PS_STATE_ALL_ON_92E;	/* RF on */
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+					      (u8 *)(&rpwm_val));
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+					      (u8 *)(&fw_pwrmode));
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+					      (u8 *)(&fw_current_inps));
+	}
+}
+
+static void _rtl92ee_fwlps_enter(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	bool fw_current_inps = true;
+	u8 rpwm_val;
+
+	if (ppsc->low_power_enable) {
+		rpwm_val = FW_PS_STATE_RF_OFF_LOW_PWR;	/* RF off */
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+					      (u8 *)(&fw_current_inps));
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+					      (u8 *)(&ppsc->fwctrl_psmode));
+		rtlhal->allow_sw_to_change_hwclc = true;
+		_rtl92ee_set_fw_clock_off(hw, rpwm_val);
+	} else {
+		rpwm_val = FW_PS_STATE_RF_OFF_92E;	/* RF off */
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+					      (u8 *)(&fw_current_inps));
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+					      (u8 *)(&ppsc->fwctrl_psmode));
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+					      (u8 *)(&rpwm_val));
+	}
+}
+
+void rtl92ee_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	switch (variable) {
+	case HW_VAR_RCR:
+		*((u32 *)(val)) = rtlpci->receive_config;
+		break;
+	case HW_VAR_RF_STATE:
+		*((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
+		break;
+	case HW_VAR_FWLPS_RF_ON:{
+			enum rf_pwrstate rfstate;
+			u32 val_rcr;
+
+			rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE,
+						      (u8 *)(&rfstate));
+			if (rfstate == ERFOFF) {
+				*((bool *)(val)) = true;
+			} else {
+				val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+				val_rcr &= 0x00070000;
+				if (val_rcr)
+					*((bool *)(val)) = false;
+				else
+					*((bool *)(val)) = true;
+			}
+		}
+		break;
+	case HW_VAR_FW_PSMODE_STATUS:
+		*((bool *)(val)) = ppsc->fw_current_inpsmode;
+		break;
+	case HW_VAR_CORRECT_TSF:{
+		u64 tsf;
+		u32 *ptsf_low = (u32 *)&tsf;
+		u32 *ptsf_high = ((u32 *)&tsf) + 1;
+
+		*ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4));
+		*ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+		*((u64 *)(val)) = tsf;
+		}
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "switch case not process %x\n", variable);
+		break;
+	}
+}
+
+static void _rtl92ee_download_rsvd_page(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 tmp_regcr, tmp_reg422;
+	u8 bcnvalid_reg, txbc_reg;
+	u8 count = 0, dlbcn_count = 0;
+	bool b_recover = false;
+
+	/*Set REG_CR bit 8. DMA beacon by SW.*/
+	tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
+	rtl_write_byte(rtlpriv, REG_CR + 1, tmp_regcr | BIT(0));
+
+	/* Disable Hw protection for a time which revserd for Hw sending beacon.
+	 * Fix download reserved page packet fail
+	 * that access collision with the protection time.
+	 * 2010.05.11. Added by tynli.
+	 */
+	_rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(3));
+	_rtl92ee_set_bcn_ctrl_reg(hw, BIT(4), 0);
+
+	/* Set FWHW_TXQ_CTRL 0x422[6]=0 to
+	 * tell Hw the packet is not a real beacon frame.
+	 */
+	tmp_reg422 = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp_reg422 & (~BIT(6)));
+
+	if (tmp_reg422 & BIT(6))
+		b_recover = true;
+
+	do {
+		/* Clear beacon valid check bit */
+		bcnvalid_reg = rtl_read_byte(rtlpriv, REG_DWBCN0_CTRL + 2);
+		rtl_write_byte(rtlpriv, REG_DWBCN0_CTRL + 2,
+			       bcnvalid_reg | BIT(0));
+
+		/* Return Beacon TCB */
+		_rtl92ee_return_beacon_queue_skb(hw);
+
+		/* download rsvd page */
+		rtl92ee_set_fw_rsvdpagepkt(hw, false);
+
+		txbc_reg = rtl_read_byte(rtlpriv, REG_MGQ_TXBD_NUM + 3);
+		count = 0;
+		while ((txbc_reg & BIT(4)) && count < 20) {
+			count++;
+			udelay(10);
+			txbc_reg = rtl_read_byte(rtlpriv, REG_MGQ_TXBD_NUM + 3);
+		}
+		rtl_write_byte(rtlpriv, REG_MGQ_TXBD_NUM + 3,
+			       txbc_reg | BIT(4));
+
+		/* check rsvd page download OK. */
+		bcnvalid_reg = rtl_read_byte(rtlpriv, REG_DWBCN0_CTRL + 2);
+		count = 0;
+		while (!(bcnvalid_reg & BIT(0)) && count < 20) {
+			count++;
+			udelay(50);
+			bcnvalid_reg = rtl_read_byte(rtlpriv,
+						     REG_DWBCN0_CTRL + 2);
+		}
+
+		if (bcnvalid_reg & BIT(0))
+			rtl_write_byte(rtlpriv, REG_DWBCN0_CTRL + 2, BIT(0));
+
+		dlbcn_count++;
+	} while (!(bcnvalid_reg & BIT(0)) && dlbcn_count < 5);
+
+	if (!(bcnvalid_reg & BIT(0)))
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Download RSVD page failed!\n");
+
+	/* Enable Bcn */
+	_rtl92ee_set_bcn_ctrl_reg(hw, BIT(3), 0);
+	_rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(4));
+
+	if (b_recover)
+		rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp_reg422);
+
+	tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
+	rtl_write_byte(rtlpriv, REG_CR + 1, tmp_regcr & (~BIT(0)));
+}
+
+void rtl92ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_efuse *efuse = rtl_efuse(rtl_priv(hw));
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	u8 idx;
+
+	switch (variable) {
+	case HW_VAR_ETHER_ADDR:
+		for (idx = 0; idx < ETH_ALEN; idx++)
+			rtl_write_byte(rtlpriv, (REG_MACID + idx), val[idx]);
+		break;
+	case HW_VAR_BASIC_RATE:{
+		u16 b_rate_cfg = ((u16 *)val)[0];
+
+		b_rate_cfg = b_rate_cfg & 0x15f;
+		b_rate_cfg |= 0x01;
+		b_rate_cfg = (b_rate_cfg | 0xd) & (~BIT(1));
+		rtl_write_byte(rtlpriv, REG_RRSR, b_rate_cfg & 0xff);
+		rtl_write_byte(rtlpriv, REG_RRSR + 1, (b_rate_cfg >> 8) & 0xff);
+		break; }
+	case HW_VAR_BSSID:
+		for (idx = 0; idx < ETH_ALEN; idx++)
+			rtl_write_byte(rtlpriv, (REG_BSSID + idx), val[idx]);
+		break;
+	case HW_VAR_SIFS:
+		rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]);
+		rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]);
+
+		rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]);
+		rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]);
+
+		if (!mac->ht_enable)
+			rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, 0x0e0e);
+		else
+			rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
+				       *((u16 *)val));
+		break;
+	case HW_VAR_SLOT_TIME:{
+		u8 e_aci;
+
+		RT_TRACE(rtlpriv, COMP_MLME, DBG_TRACE,
+			 "HW_VAR_SLOT_TIME %x\n", val[0]);
+
+		rtl_write_byte(rtlpriv, REG_SLOT, val[0]);
+
+		for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+						      (u8 *)(&e_aci));
+		}
+		break; }
+	case HW_VAR_ACK_PREAMBLE:{
+		u8 reg_tmp;
+		u8 short_preamble = (bool)(*(u8 *)val);
+
+		reg_tmp = (rtlpriv->mac80211.cur_40_prime_sc) << 5;
+		if (short_preamble)
+			reg_tmp |= 0x80;
+		rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_tmp);
+		rtlpriv->mac80211.short_preamble = short_preamble;
+		}
+		break;
+	case HW_VAR_WPA_CONFIG:
+		rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *)val));
+		break;
+	case HW_VAR_AMPDU_FACTOR:{
+		u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 };
+		u8 fac;
+		u8 *reg = NULL;
+		u8 i = 0;
+
+		reg = regtoset_normal;
+
+		fac = *((u8 *)val);
+		if (fac <= 3) {
+			fac = (1 << (fac + 2));
+			if (fac > 0xf)
+				fac = 0xf;
+			for (i = 0; i < 4; i++) {
+				if ((reg[i] & 0xf0) > (fac << 4))
+					reg[i] = (reg[i] & 0x0f) |
+						(fac << 4);
+				if ((reg[i] & 0x0f) > fac)
+					reg[i] = (reg[i] & 0xf0) | fac;
+				rtl_write_byte(rtlpriv,
+					       (REG_AGGLEN_LMT + i),
+					       reg[i]);
+			}
+			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+				 "Set HW_VAR_AMPDU_FACTOR:%#x\n", fac);
+		}
+		}
+		break;
+	case HW_VAR_AC_PARAM:{
+		u8 e_aci = *((u8 *)val);
+
+		if (rtlpci->acm_method != EACMWAY2_SW)
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
+						      (u8 *)(&e_aci));
+		}
+		break;
+	case HW_VAR_ACM_CTRL:{
+		u8 e_aci = *((u8 *)val);
+		union aci_aifsn *aifs = (union aci_aifsn *)(&mac->ac[0].aifs);
+
+		u8 acm = aifs->f.acm;
+		u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL);
+
+		acm_ctrl = acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1);
+
+		if (acm) {
+			switch (e_aci) {
+			case AC0_BE:
+				acm_ctrl |= ACMHW_BEQEN;
+				break;
+			case AC2_VI:
+				acm_ctrl |= ACMHW_VIQEN;
+				break;
+			case AC3_VO:
+				acm_ctrl |= ACMHW_VOQEN;
+				break;
+			default:
+				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+					 "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n",
+					 acm);
+				break;
+			}
+		} else {
+			switch (e_aci) {
+			case AC0_BE:
+				acm_ctrl &= (~ACMHW_BEQEN);
+				break;
+			case AC2_VI:
+				acm_ctrl &= (~ACMHW_VIQEN);
+				break;
+			case AC3_VO:
+				acm_ctrl &= (~ACMHW_BEQEN);
+				break;
+			default:
+				RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+					 "switch case not process\n");
+				break;
+			}
+		}
+
+		RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
+			 "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n",
+			  acm_ctrl);
+		rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl);
+		}
+		break;
+	case HW_VAR_RCR:{
+		rtl_write_dword(rtlpriv, REG_RCR, ((u32 *)(val))[0]);
+		rtlpci->receive_config = ((u32 *)(val))[0];
+		}
+		break;
+	case HW_VAR_RETRY_LIMIT:{
+		u8 retry_limit = ((u8 *)(val))[0];
+
+		rtl_write_word(rtlpriv, REG_RETRY_LIMIT,
+			       retry_limit << RETRY_LIMIT_SHORT_SHIFT |
+			       retry_limit << RETRY_LIMIT_LONG_SHIFT);
+		}
+		break;
+	case HW_VAR_DUAL_TSF_RST:
+		rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1)));
+		break;
+	case HW_VAR_EFUSE_BYTES:
+		efuse->efuse_usedbytes = *((u16 *)val);
+		break;
+	case HW_VAR_EFUSE_USAGE:
+		efuse->efuse_usedpercentage = *((u8 *)val);
+		break;
+	case HW_VAR_IO_CMD:
+		rtl92ee_phy_set_io_cmd(hw, (*(enum io_type *)val));
+		break;
+	case HW_VAR_SET_RPWM:{
+		u8 rpwm_val;
+
+		rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM);
+		udelay(1);
+
+		if (rpwm_val & BIT(7)) {
+			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, (*(u8 *)val));
+		} else {
+			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+				       ((*(u8 *)val) | BIT(7)));
+		}
+		}
+		break;
+	case HW_VAR_H2C_FW_PWRMODE:
+		rtl92ee_set_fw_pwrmode_cmd(hw, (*(u8 *)val));
+		break;
+	case HW_VAR_FW_PSMODE_STATUS:
+		ppsc->fw_current_inpsmode = *((bool *)val);
+		break;
+	case HW_VAR_RESUME_CLK_ON:
+		_rtl92ee_set_fw_ps_rf_on(hw);
+		break;
+	case HW_VAR_FW_LPS_ACTION:{
+		bool b_enter_fwlps = *((bool *)val);
+
+		if (b_enter_fwlps)
+			_rtl92ee_fwlps_enter(hw);
+		else
+			_rtl92ee_fwlps_leave(hw);
+		}
+		break;
+	case HW_VAR_H2C_FW_JOINBSSRPT:{
+		u8 mstatus = (*(u8 *)val);
+
+		if (mstatus == RT_MEDIA_CONNECT) {
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL);
+			_rtl92ee_download_rsvd_page(hw);
+		}
+		rtl92ee_set_fw_media_status_rpt_cmd(hw, mstatus);
+		}
+		break;
+	case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+		rtl92ee_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+		break;
+	case HW_VAR_AID:{
+		u16 u2btmp;
+
+		u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
+		u2btmp &= 0xC000;
+		rtl_write_word(rtlpriv, REG_BCN_PSR_RPT,
+			       (u2btmp | mac->assoc_id));
+		}
+		break;
+	case HW_VAR_CORRECT_TSF:{
+		u8 btype_ibss = ((u8 *)(val))[0];
+
+		if (btype_ibss)
+			_rtl92ee_stop_tx_beacon(hw);
+
+		_rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(3));
+
+		rtl_write_dword(rtlpriv, REG_TSFTR,
+				(u32)(mac->tsf & 0xffffffff));
+		rtl_write_dword(rtlpriv, REG_TSFTR + 4,
+				(u32)((mac->tsf >> 32) & 0xffffffff));
+
+		_rtl92ee_set_bcn_ctrl_reg(hw, BIT(3), 0);
+
+		if (btype_ibss)
+			_rtl92ee_resume_tx_beacon(hw);
+		}
+		break;
+	case HW_VAR_KEEP_ALIVE: {
+		u8 array[2];
+
+		array[0] = 0xff;
+		array[1] = *((u8 *)val);
+		rtl92ee_fill_h2c_cmd(hw, H2C_92E_KEEP_ALIVE_CTRL, 2, array);
+		}
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "switch case not process %x\n", variable);
+		break;
+	}
+}
+
+static bool _rtl92ee_llt_table_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 txpktbuf_bndy;
+	u8 u8tmp, testcnt = 0;
+
+	txpktbuf_bndy = 0xFA;
+
+	rtl_write_dword(rtlpriv, REG_RQPN, 0x80E90808);
+
+	rtl_write_byte(rtlpriv, REG_TRXFF_BNDY, txpktbuf_bndy);
+	rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, 0x3d00 - 1);
+
+	rtl_write_byte(rtlpriv, REG_DWBCN0_CTRL + 1, txpktbuf_bndy);
+	rtl_write_byte(rtlpriv, REG_DWBCN1_CTRL + 1, txpktbuf_bndy);
+
+	rtl_write_byte(rtlpriv, REG_BCNQ_BDNY, txpktbuf_bndy);
+	rtl_write_byte(rtlpriv, REG_BCNQ1_BDNY, txpktbuf_bndy);
+
+	rtl_write_byte(rtlpriv, REG_MGQ_BDNY, txpktbuf_bndy);
+	rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy);
+
+	rtl_write_byte(rtlpriv, REG_PBP, 0x31);
+	rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4);
+
+	u8tmp = rtl_read_byte(rtlpriv, REG_AUTO_LLT + 2);
+	rtl_write_byte(rtlpriv, REG_AUTO_LLT + 2, u8tmp | BIT(0));
+
+	while (u8tmp & BIT(0)) {
+		u8tmp = rtl_read_byte(rtlpriv, REG_AUTO_LLT + 2);
+		udelay(10);
+		testcnt++;
+		if (testcnt > 10)
+			break;
+	}
+
+	return true;
+}
+
+static void _rtl92ee_gen_refresh_led_state(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_led *pled0 = &pcipriv->ledctl.sw_led0;
+
+	if (rtlpriv->rtlhal.up_first_time)
+		return;
+
+	if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS)
+		rtl92ee_sw_led_on(hw, pled0);
+	else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT)
+		rtl92ee_sw_led_on(hw, pled0);
+	else
+		rtl92ee_sw_led_off(hw, pled0);
+}
+
+static bool _rtl92ee_init_mac(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+	u8 bytetmp;
+	u16 wordtmp;
+	u32 dwordtmp;
+
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0);
+
+	dwordtmp = rtl_read_dword(rtlpriv, REG_SYS_CFG1);
+	if (dwordtmp & BIT(24)) {
+		rtl_write_byte(rtlpriv, 0x7c, 0xc3);
+	} else {
+		bytetmp = rtl_read_byte(rtlpriv, 0x16);
+		rtl_write_byte(rtlpriv, 0x16, bytetmp | BIT(4) | BIT(6));
+		rtl_write_byte(rtlpriv, 0x7c, 0x83);
+	}
+	/* 1. 40Mhz crystal source*/
+	bytetmp = rtl_read_byte(rtlpriv, REG_AFE_CTRL2);
+	bytetmp &= 0xfb;
+	rtl_write_byte(rtlpriv, REG_AFE_CTRL2, bytetmp);
+
+	dwordtmp = rtl_read_dword(rtlpriv, REG_AFE_CTRL4);
+	dwordtmp &= 0xfffffc7f;
+	rtl_write_dword(rtlpriv, REG_AFE_CTRL4, dwordtmp);
+
+	/* 2. 92E AFE parameter
+	 * MP chip then check version
+	 */
+	bytetmp = rtl_read_byte(rtlpriv, REG_AFE_CTRL2);
+	bytetmp &= 0xbf;
+	rtl_write_byte(rtlpriv, REG_AFE_CTRL2, bytetmp);
+
+	dwordtmp = rtl_read_dword(rtlpriv, REG_AFE_CTRL4);
+	dwordtmp &= 0xffdfffff;
+	rtl_write_dword(rtlpriv, REG_AFE_CTRL4, dwordtmp);
+
+	/* HW Power on sequence */
+	if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+				      PWR_INTF_PCI_MSK,
+				      RTL8192E_NIC_ENABLE_FLOW)) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "init MAC Fail as rtl_hal_pwrseqcmdparsing\n");
+		return false;
+	}
+
+	/* Release MAC IO register reset */
+	bytetmp = rtl_read_byte(rtlpriv, REG_CR);
+	bytetmp = 0xff;
+	rtl_write_byte(rtlpriv, REG_CR, bytetmp);
+	mdelay(2);
+	bytetmp = 0x7f;
+	rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, bytetmp);
+	mdelay(2);
+
+	/* Add for wakeup online */
+	bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CLKR);
+	rtl_write_byte(rtlpriv, REG_SYS_CLKR, bytetmp | BIT(3));
+	bytetmp = rtl_read_byte(rtlpriv, REG_GPIO_MUXCFG + 1);
+	rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG + 1, bytetmp & (~BIT(4)));
+	/* Release MAC IO register reset */
+	rtl_write_word(rtlpriv, REG_CR, 0x2ff);
+
+	if (!rtlhal->mac_func_enable) {
+		if (_rtl92ee_llt_table_init(hw) == false) {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "LLT table init fail\n");
+			return false;
+		}
+	}
+
+	rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff);
+	rtl_write_dword(rtlpriv, REG_HISRE, 0xffffffff);
+
+	wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL);
+	wordtmp &= 0xf;
+	wordtmp |= 0xF5B1;
+	rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp);
+	/* Reported Tx status from HW for rate adaptive.*/
+	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F);
+
+	/* Set RCR register */
+	rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+	rtl_write_word(rtlpriv, REG_RXFLTMAP2, 0xffff);
+
+	/* Set TCR register */
+	rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config);
+
+	/* Set TX/RX descriptor physical address(from OS API). */
+	rtl_write_dword(rtlpriv, REG_BCNQ_DESA,
+			((u64)rtlpci->tx_ring[BEACON_QUEUE].buffer_desc_dma) &
+			DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_MGQ_DESA,
+			(u64)rtlpci->tx_ring[MGNT_QUEUE].buffer_desc_dma &
+			DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_VOQ_DESA,
+			(u64)rtlpci->tx_ring[VO_QUEUE].buffer_desc_dma &
+			DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_VIQ_DESA,
+			(u64)rtlpci->tx_ring[VI_QUEUE].buffer_desc_dma &
+			DMA_BIT_MASK(32));
+
+	rtl_write_dword(rtlpriv, REG_BEQ_DESA,
+			(u64)rtlpci->tx_ring[BE_QUEUE].buffer_desc_dma &
+			DMA_BIT_MASK(32));
+
+	dwordtmp = rtl_read_dword(rtlpriv, REG_BEQ_DESA);
+
+	rtl_write_dword(rtlpriv, REG_BKQ_DESA,
+			(u64)rtlpci->tx_ring[BK_QUEUE].buffer_desc_dma &
+			DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_HQ0_DESA,
+			(u64)rtlpci->tx_ring[HIGH_QUEUE].buffer_desc_dma &
+			DMA_BIT_MASK(32));
+
+	rtl_write_dword(rtlpriv, REG_RX_DESA,
+			(u64)rtlpci->rx_ring[RX_MPDU_QUEUE].dma &
+			DMA_BIT_MASK(32));
+
+	/* if we want to support 64 bit DMA, we should set it here,
+	 * but now we do not support 64 bit DMA
+	 */
+
+	rtl_write_dword(rtlpriv, REG_TSFTIMER_HCI, 0x3fffffff);
+
+	bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 3);
+	rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, bytetmp | 0xF7);
+
+	rtl_write_dword(rtlpriv, REG_INT_MIG, 0);
+
+	rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0);
+
+	rtl_write_word(rtlpriv, REG_MGQ_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_VOQ_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_VIQ_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_BEQ_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_VOQ_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_BKQ_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_HI0Q_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_HI1Q_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_HI2Q_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_HI3Q_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_HI4Q_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_HI5Q_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_HI6Q_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	rtl_write_word(rtlpriv, REG_HI7Q_TXBD_NUM,
+		       TX_DESC_NUM_92E | ((RTL8192EE_SEG_NUM << 12) & 0x3000));
+	/*Rx*/
+#if (DMA_IS_64BIT == 1)
+	rtl_write_word(rtlpriv, REG_RX_RXBD_NUM,
+		       RX_DESC_NUM_92E |
+		       ((RTL8192EE_SEG_NUM << 13) & 0x6000) | 0x8000);
+#else
+	rtl_write_word(rtlpriv, REG_RX_RXBD_NUM,
+		       RX_DESC_NUM_92E |
+		       ((RTL8192EE_SEG_NUM << 13) & 0x6000) | 0x0000);
+#endif
+
+	rtl_write_dword(rtlpriv, REG_TSFTIMER_HCI, 0XFFFFFFFF);
+
+	_rtl92ee_gen_refresh_led_state(hw);
+	return true;
+}
+
+static void _rtl92ee_hw_configure(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u32 reg_rrsr;
+
+	reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
+	/* Init value for RRSR. */
+	rtl_write_dword(rtlpriv, REG_RRSR, reg_rrsr);
+
+	/* ARFB table 9 for 11ac 5G 2SS */
+	rtl_write_dword(rtlpriv, REG_ARFR0, 0x00000010);
+	rtl_write_dword(rtlpriv, REG_ARFR0 + 4, 0x3e0ff000);
+
+	/* ARFB table 10 for 11ac 5G 1SS */
+	rtl_write_dword(rtlpriv, REG_ARFR1, 0x00000010);
+	rtl_write_dword(rtlpriv, REG_ARFR1 + 4, 0x000ff000);
+
+	/* Set SLOT time */
+	rtl_write_byte(rtlpriv, REG_SLOT, 0x09);
+
+	/* CF-End setting. */
+	rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F80);
+
+	/* Set retry limit */
+	rtl_write_word(rtlpriv, REG_RETRY_LIMIT, 0x0707);
+
+	/* BAR settings */
+	rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0x0201ffff);
+
+	/* Set Data / Response auto rate fallack retry count */
+	rtl_write_dword(rtlpriv, REG_DARFRC, 0x01000000);
+	rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x07060504);
+	rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000);
+	rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504);
+
+	/* Beacon related, for rate adaptive */
+	rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2);
+	rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xff);
+
+	rtlpci->reg_bcn_ctrl_val = 0x1d;
+	rtl_write_byte(rtlpriv, REG_BCN_CTRL, rtlpci->reg_bcn_ctrl_val);
+
+	/* Marked out by Bruce, 2010-09-09.
+	 * This register is configured for the 2nd Beacon (multiple BSSID).
+	 * We shall disable this register if we only support 1 BSSID.
+	 * vivi guess 92d also need this, also 92d now doesnot set this reg
+	 */
+	rtl_write_byte(rtlpriv, REG_BCN_CTRL_1, 0);
+
+	/* TBTT prohibit hold time. Suggested by designer TimChen. */
+	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); /* 8 ms */
+
+	rtl_write_byte(rtlpriv, REG_PIFS, 0);
+	rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16);
+
+	rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0040);
+	rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x08ff);
+
+	/* For Rx TP. Suggested by SD1 Richard. Added by tynli. 2010.04.12.*/
+	rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666);
+
+	/* ACKTO for IOT issue. */
+	rtl_write_byte(rtlpriv, REG_ACKTO, 0x40);
+
+	/* Set Spec SIFS (used in NAV) */
+	rtl_write_word(rtlpriv, REG_SPEC_SIFS, 0x100a);
+	rtl_write_word(rtlpriv, REG_MAC_SPEC_SIFS, 0x100a);
+
+	/* Set SIFS for CCK */
+	rtl_write_word(rtlpriv, REG_SIFS_CTX, 0x100a);
+
+	/* Set SIFS for OFDM */
+	rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x100a);
+
+	/* Note Data sheet don't define */
+	rtl_write_word(rtlpriv, 0x4C7, 0x80);
+
+	rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x20);
+
+	rtl_write_word(rtlpriv, REG_MAX_AGGR_NUM, 0x1717);
+
+	/* Set Multicast Address. 2009.01.07. by tynli. */
+	rtl_write_dword(rtlpriv, REG_MAR, 0xffffffff);
+	rtl_write_dword(rtlpriv, REG_MAR + 4, 0xffffffff);
+}
+
+static void _rtl92ee_enable_aspm_back_door(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	u32 tmp32 = 0, count = 0;
+	u8 tmp8 = 0;
+
+	rtl_write_word(rtlpriv, REG_BACKDOOR_DBI_DATA, 0x78);
+	rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2, 0x2);
+	tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2);
+	count = 0;
+	while (tmp8 && count < 20) {
+		udelay(10);
+		tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2);
+		count++;
+	}
+
+	if (0 == tmp8) {
+		tmp32 = rtl_read_dword(rtlpriv, REG_BACKDOOR_DBI_RDATA);
+		if ((tmp32 & 0xff00) != 0x2000) {
+			tmp32 &= 0xffff00ff;
+			rtl_write_dword(rtlpriv, REG_BACKDOOR_DBI_WDATA,
+					tmp32 | BIT(13));
+			rtl_write_word(rtlpriv, REG_BACKDOOR_DBI_DATA, 0xf078);
+			rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2, 0x1);
+
+			tmp8 = rtl_read_byte(rtlpriv,
+					     REG_BACKDOOR_DBI_DATA + 2);
+			count = 0;
+			while (tmp8 && count < 20) {
+				udelay(10);
+				tmp8 = rtl_read_byte(rtlpriv,
+						     REG_BACKDOOR_DBI_DATA + 2);
+				count++;
+			}
+		}
+	}
+
+	rtl_write_word(rtlpriv, REG_BACKDOOR_DBI_DATA, 0x70c);
+	rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2, 0x2);
+	tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2);
+	count = 0;
+	while (tmp8 && count < 20) {
+		udelay(10);
+		tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2);
+		count++;
+	}
+	if (0 == tmp8) {
+		tmp32 = rtl_read_dword(rtlpriv, REG_BACKDOOR_DBI_RDATA);
+		rtl_write_dword(rtlpriv, REG_BACKDOOR_DBI_WDATA,
+				tmp32 | BIT(31));
+		rtl_write_word(rtlpriv, REG_BACKDOOR_DBI_DATA, 0xf70c);
+		rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2, 0x1);
+	}
+
+	tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2);
+	count = 0;
+	while (tmp8 && count < 20) {
+		udelay(10);
+		tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2);
+		count++;
+	}
+
+	rtl_write_word(rtlpriv, REG_BACKDOOR_DBI_DATA, 0x718);
+	rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2, 0x2);
+	tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2);
+	count = 0;
+	while (tmp8 && count < 20) {
+		udelay(10);
+		tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2);
+		count++;
+	}
+	if (ppsc->support_backdoor || (0 == tmp8)) {
+		tmp32 = rtl_read_dword(rtlpriv, REG_BACKDOOR_DBI_RDATA);
+		rtl_write_dword(rtlpriv, REG_BACKDOOR_DBI_WDATA,
+				tmp32 | BIT(11) | BIT(12));
+		rtl_write_word(rtlpriv, REG_BACKDOOR_DBI_DATA, 0xf718);
+		rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2, 0x1);
+	}
+	tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2);
+	count = 0;
+	while (tmp8 && count < 20) {
+		udelay(10);
+		tmp8 = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 2);
+		count++;
+	}
+}
+
+void rtl92ee_enable_hw_security_config(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 sec_reg_value;
+	u8 tmp;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		 "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n",
+		  rtlpriv->sec.pairwise_enc_algorithm,
+		  rtlpriv->sec.group_enc_algorithm);
+
+	if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
+		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+			 "not open hw encryption\n");
+		return;
+	}
+
+	sec_reg_value = SCR_TXENCENABLE | SCR_RXDECENABLE;
+
+	if (rtlpriv->sec.use_defaultkey) {
+		sec_reg_value |= SCR_TXUSEDK;
+		sec_reg_value |= SCR_RXUSEDK;
+	}
+
+	sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK);
+
+	tmp = rtl_read_byte(rtlpriv, REG_CR + 1);
+	rtl_write_byte(rtlpriv, REG_CR + 1, tmp | BIT(1));
+
+	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+		 "The SECR-value %x\n", sec_reg_value);
+
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
+}
+
+int rtl92ee_hw_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	bool rtstatus = true;
+	int err = 0;
+	u8 tmp_u1b, u1byte;
+	u32 tmp_u4b;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, " Rtl8192EE hw init\n");
+	rtlpriv->rtlhal.being_init_adapter = true;
+	rtlpriv->intf_ops->disable_aspm(hw);
+
+	tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CLKR+1);
+	u1byte = rtl_read_byte(rtlpriv, REG_CR);
+	if ((tmp_u1b & BIT(3)) && (u1byte != 0 && u1byte != 0xEA)) {
+		rtlhal->mac_func_enable = true;
+	} else {
+		rtlhal->mac_func_enable = false;
+		rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_92E;
+	}
+
+	rtstatus = _rtl92ee_init_mac(hw);
+
+	rtl_write_byte(rtlpriv, 0x577, 0x03);
+
+	/*for Crystal 40 Mhz setting */
+	rtl_write_byte(rtlpriv, REG_AFE_CTRL4, 0x2A);
+	rtl_write_byte(rtlpriv, REG_AFE_CTRL4 + 1, 0x00);
+	rtl_write_byte(rtlpriv, REG_AFE_CTRL2, 0x83);
+
+	/*Forced the antenna b to wifi */
+	if (rtlpriv->btcoexist.btc_info.btcoexist == 1) {
+		rtl_write_byte(rtlpriv, 0x64, 0);
+		rtl_write_byte(rtlpriv, 0x65, 1);
+	}
+	if (!rtstatus) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
+		err = 1;
+		return err;
+	}
+	rtlhal->rx_tag = 0;
+	rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, 0x8000);
+	err = rtl92ee_download_fw(hw, false);
+	if (err) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "Failed to download FW. Init HW without FW now..\n");
+		err = 1;
+		rtlhal->fw_ready = false;
+		return err;
+	}
+	rtlhal->fw_ready = true;
+	/*fw related variable initialize */
+	ppsc->fw_current_inpsmode = false;
+	rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_92E;
+	rtlhal->fw_clk_change_in_progress = false;
+	rtlhal->allow_sw_to_change_hwclc = false;
+	rtlhal->last_hmeboxnum = 0;
+
+	rtl92ee_phy_mac_config(hw);
+
+	rtl92ee_phy_bb_config(hw);
+
+	rtl92ee_phy_rf_config(hw);
+
+	rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, RF90_PATH_A,
+						 RF_CHNLBW, RFREG_OFFSET_MASK);
+	rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, RF90_PATH_B,
+						 RF_CHNLBW, RFREG_OFFSET_MASK);
+	rtlphy->backup_rf_0x1a = (u32)rtl_get_rfreg(hw, RF90_PATH_A, RF_RX_G1,
+						    RFREG_OFFSET_MASK);
+	rtlphy->rfreg_chnlval[0] = (rtlphy->rfreg_chnlval[0] & 0xfffff3ff) |
+				   BIT(10) | BIT(11);
+
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+		      rtlphy->rfreg_chnlval[0]);
+	rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, RFREG_OFFSET_MASK,
+		      rtlphy->rfreg_chnlval[0]);
+
+	/*---- Set CCK and OFDM Block "ON"----*/
+	rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1);
+	rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1);
+
+	/* Must set this,
+	 * otherwise the rx sensitivity will be very pool. Maddest
+	 */
+	rtl_set_rfreg(hw, RF90_PATH_A, 0xB1, RFREG_OFFSET_MASK, 0x54418);
+
+	/*Set Hardware(MAC default setting.)*/
+	_rtl92ee_hw_configure(hw);
+
+	rtlhal->mac_func_enable = true;
+
+	rtl_cam_reset_all_entry(hw);
+	rtl92ee_enable_hw_security_config(hw);
+
+	ppsc->rfpwr_state = ERFON;
+
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
+	_rtl92ee_enable_aspm_back_door(hw);
+	rtlpriv->intf_ops->enable_aspm(hw);
+
+	rtl92ee_bt_hw_init(hw);
+
+	rtlpriv->rtlhal.being_init_adapter = false;
+
+	if (ppsc->rfpwr_state == ERFON) {
+		if (rtlphy->iqk_initialized) {
+			rtl92ee_phy_iq_calibrate(hw, true);
+		} else {
+			rtl92ee_phy_iq_calibrate(hw, false);
+			rtlphy->iqk_initialized = true;
+		}
+	}
+
+	rtlphy->rfpath_rx_enable[0] = true;
+	if (rtlphy->rf_type == RF_2T2R)
+		rtlphy->rfpath_rx_enable[1] = true;
+
+	efuse_one_byte_read(hw, 0x1FA, &tmp_u1b);
+	if (!(tmp_u1b & BIT(0))) {
+		rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05);
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "PA BIAS path A\n");
+	}
+
+	if ((!(tmp_u1b & BIT(1))) && (rtlphy->rf_type == RF_2T2R)) {
+		rtl_set_rfreg(hw, RF90_PATH_B, 0x15, 0x0F, 0x05);
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "PA BIAS path B\n");
+	}
+
+	rtl_write_byte(rtlpriv, REG_NAV_UPPER, ((30000 + 127) / 128));
+
+	/*Fixed LDPC rx hang issue. */
+	tmp_u4b = rtl_read_dword(rtlpriv, REG_SYS_SWR_CTRL1);
+	rtl_write_byte(rtlpriv, REG_SYS_SWR_CTRL2, 0x75);
+	tmp_u4b =  (tmp_u4b & 0xfff00fff) | (0x7E << 12);
+	rtl_write_dword(rtlpriv, REG_SYS_SWR_CTRL1, tmp_u4b);
+
+	rtl92ee_dm_init(hw);
+
+	rtl_write_dword(rtlpriv, 0x4fc, 0);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "end of Rtl8192EE hw init %x\n", err);
+	return 0;
+}
+
+static enum version_8192e _rtl92ee_read_chip_version(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	enum version_8192e version = VERSION_UNKNOWN;
+	u32 value32;
+
+	rtlphy->rf_type = RF_2T2R;
+
+	value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG1);
+	if (value32 & TRP_VAUX_EN)
+		version = (enum version_8192e)VERSION_TEST_CHIP_2T2R_8192E;
+	else
+		version = (enum version_8192e)VERSION_NORMAL_CHIP_2T2R_8192E;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "Chip RF Type: %s\n", (rtlphy->rf_type == RF_2T2R) ?
+		  "RF_2T2R" : "RF_1T1R");
+
+	return version;
+}
+
+static int _rtl92ee_set_media_status(struct ieee80211_hw *hw,
+				     enum nl80211_iftype type)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 bt_msr = rtl_read_byte(rtlpriv, MSR) & 0xfc;
+	enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
+	u8 mode = MSR_NOLINK;
+
+	switch (type) {
+	case NL80211_IFTYPE_UNSPECIFIED:
+		mode = MSR_NOLINK;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "Set Network type to NO LINK!\n");
+		break;
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MESH_POINT:
+		mode = MSR_ADHOC;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "Set Network type to Ad Hoc!\n");
+		break;
+	case NL80211_IFTYPE_STATION:
+		mode = MSR_INFRA;
+		ledaction = LED_CTL_LINK;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "Set Network type to STA!\n");
+		break;
+	case NL80211_IFTYPE_AP:
+		mode = MSR_AP;
+		ledaction = LED_CTL_LINK;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "Set Network type to AP!\n");
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Network type %d not support!\n", type);
+		return 1;
+	}
+
+	/* MSR_INFRA == Link in infrastructure network;
+	 * MSR_ADHOC == Link in ad hoc network;
+	 * Therefore, check link state is necessary.
+	 *
+	 * MSR_AP == AP mode; link state is not cared here.
+	 */
+	if (mode != MSR_AP && rtlpriv->mac80211.link_state < MAC80211_LINKED) {
+		mode = MSR_NOLINK;
+		ledaction = LED_CTL_NO_LINK;
+	}
+
+	if (mode == MSR_NOLINK || mode == MSR_INFRA) {
+		_rtl92ee_stop_tx_beacon(hw);
+		_rtl92ee_enable_bcn_sub_func(hw);
+	} else if (mode == MSR_ADHOC || mode == MSR_AP) {
+		_rtl92ee_resume_tx_beacon(hw);
+		_rtl92ee_disable_bcn_sub_func(hw);
+	} else {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n",
+			 mode);
+	}
+
+	rtl_write_byte(rtlpriv, (MSR), bt_msr | mode);
+	rtlpriv->cfg->ops->led_control(hw, ledaction);
+	if (mode == MSR_AP)
+		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
+	else
+		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
+	return 0;
+}
+
+void rtl92ee_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u32 reg_rcr = rtlpci->receive_config;
+
+	if (rtlpriv->psc.rfpwr_state != ERFON)
+		return;
+
+	if (check_bssid) {
+		reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
+					      (u8 *)(&reg_rcr));
+		_rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(4));
+	} else {
+		reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN));
+		_rtl92ee_set_bcn_ctrl_reg(hw, BIT(4), 0);
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
+					      (u8 *)(&reg_rcr));
+	}
+}
+
+int rtl92ee_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (_rtl92ee_set_media_status(hw, type))
+		return -EOPNOTSUPP;
+
+	if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+		if (type != NL80211_IFTYPE_AP &&
+		    type != NL80211_IFTYPE_MESH_POINT)
+			rtl92ee_set_check_bssid(hw, true);
+	} else {
+		rtl92ee_set_check_bssid(hw, false);
+	}
+
+	return 0;
+}
+
+/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */
+void rtl92ee_set_qos(struct ieee80211_hw *hw, int aci)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtl92ee_dm_init_edca_turbo(hw);
+	switch (aci) {
+	case AC1_BK:
+		rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
+		break;
+	case AC0_BE:
+		/* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); */
+		break;
+	case AC2_VI:
+		rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322);
+		break;
+	case AC3_VO:
+		rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222);
+		break;
+	default:
+		RT_ASSERT(false, "invalid aci: %d !\n", aci);
+		break;
+	}
+}
+
+static void rtl92ee_clear_interrupt(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 tmp;
+
+	tmp = rtl_read_dword(rtlpriv, REG_HISR);
+	rtl_write_dword(rtlpriv, REG_HISR, tmp);
+
+	tmp = rtl_read_dword(rtlpriv, REG_HISRE);
+	rtl_write_dword(rtlpriv, REG_HISRE, tmp);
+
+	tmp = rtl_read_dword(rtlpriv, REG_HSISR);
+	rtl_write_dword(rtlpriv, REG_HSISR, tmp);
+}
+
+void rtl92ee_enable_interrupt(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	rtl92ee_clear_interrupt(hw);/*clear it here first*/
+
+	rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
+	rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
+	rtlpci->irq_enabled = true;
+}
+
+void rtl92ee_disable_interrupt(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	rtl_write_dword(rtlpriv, REG_HIMR, IMR_DISABLED);
+	rtl_write_dword(rtlpriv, REG_HIMRE, IMR_DISABLED);
+	rtlpci->irq_enabled = false;
+	/*synchronize_irq(rtlpci->pdev->irq);*/
+}
+
+static void _rtl92ee_poweroff_adapter(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 u1b_tmp;
+
+	rtlhal->mac_func_enable = false;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "POWER OFF adapter\n");
+
+	/* Run LPS WL RFOFF flow */
+	rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+				 PWR_INTF_PCI_MSK, RTL8192E_NIC_LPS_ENTER_FLOW);
+	/* turn off RF */
+	rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00);
+
+	/* ==== Reset digital sequence   ======  */
+	if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && rtlhal->fw_ready)
+		rtl92ee_firmware_selfreset(hw);
+
+	/* Reset MCU  */
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
+
+	/* reset MCU ready status */
+	rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
+
+	/* HW card disable configuration. */
+	rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+				 PWR_INTF_PCI_MSK, RTL8192E_NIC_DISABLE_FLOW);
+
+	/* Reset MCU IO Wrapper */
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));
+
+	/* lock ISO/CLK/Power control register */
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0E);
+}
+
+void rtl92ee_card_disable(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	enum nl80211_iftype opmode;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "RTL8192ee card disable\n");
+
+	RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+	mac->link_state = MAC80211_NOLINK;
+	opmode = NL80211_IFTYPE_UNSPECIFIED;
+
+	_rtl92ee_set_media_status(hw, opmode);
+
+	if (rtlpriv->rtlhal.driver_is_goingto_unload ||
+	    ppsc->rfoff_reason > RF_CHANGE_BY_PS)
+		rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
+
+	_rtl92ee_poweroff_adapter(hw);
+
+	/* after power off we should do iqk again */
+	rtlpriv->phy.iqk_initialized = false;
+}
+
+void rtl92ee_interrupt_recognized(struct ieee80211_hw *hw,
+				  u32 *p_inta, u32 *p_intb)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	*p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0];
+	rtl_write_dword(rtlpriv, ISR, *p_inta);
+
+	*p_intb = rtl_read_dword(rtlpriv, REG_HISRE) & rtlpci->irq_mask[1];
+	rtl_write_dword(rtlpriv, REG_HISRE, *p_intb);
+}
+
+void rtl92ee_set_beacon_related_registers(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u16 bcn_interval, atim_window;
+
+	bcn_interval = mac->beacon_interval;
+	atim_window = 2;	/*FIX MERGE */
+	rtl92ee_disable_interrupt(hw);
+	rtl_write_word(rtlpriv, REG_ATIMWND, atim_window);
+	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+	rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f);
+	rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18);
+	rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18);
+	rtl_write_byte(rtlpriv, 0x606, 0x30);
+	rtlpci->reg_bcn_ctrl_val |= BIT(3);
+	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8)rtlpci->reg_bcn_ctrl_val);
+}
+
+void rtl92ee_set_beacon_interval(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	u16 bcn_interval = mac->beacon_interval;
+
+	RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
+		 "beacon_interval:%d\n", bcn_interval);
+	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+}
+
+void rtl92ee_update_interrupt_mask(struct ieee80211_hw *hw,
+				   u32 add_msr, u32 rm_msr)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
+		 "add_msr:%x, rm_msr:%x\n", add_msr, rm_msr);
+
+	if (add_msr)
+		rtlpci->irq_mask[0] |= add_msr;
+	if (rm_msr)
+		rtlpci->irq_mask[0] &= (~rm_msr);
+	rtl92ee_disable_interrupt(hw);
+	rtl92ee_enable_interrupt(hw);
+}
+
+static u8 _rtl92ee_get_chnl_group(u8 chnl)
+{
+	u8 group = 0;
+
+	if (chnl <= 14) {
+		if (1 <= chnl && chnl <= 2)
+			group = 0;
+		else if (3 <= chnl && chnl <= 5)
+			group = 1;
+		else if (6 <= chnl && chnl <= 8)
+			group = 2;
+		else if (9 <= chnl && chnl <= 11)
+			group = 3;
+		else if (12 <= chnl && chnl <= 14)
+			group = 4;
+	} else {
+		if (36 <= chnl && chnl <= 42)
+			group = 0;
+		else if (44 <= chnl && chnl <= 48)
+			group = 1;
+		else if (50 <= chnl && chnl <= 58)
+			group = 2;
+		else if (60 <= chnl && chnl <= 64)
+			group = 3;
+		else if (100 <= chnl && chnl <= 106)
+			group = 4;
+		else if (108 <= chnl && chnl <= 114)
+			group = 5;
+		else if (116 <= chnl && chnl <= 122)
+			group = 6;
+		else if (124 <= chnl && chnl <= 130)
+			group = 7;
+		else if (132 <= chnl && chnl <= 138)
+			group = 8;
+		else if (140 <= chnl && chnl <= 144)
+			group = 9;
+		else if (149 <= chnl && chnl <= 155)
+			group = 10;
+		else if (157 <= chnl && chnl <= 161)
+			group = 11;
+		else if (165 <= chnl && chnl <= 171)
+			group = 12;
+		else if (173 <= chnl && chnl <= 177)
+			group = 13;
+	}
+	return group;
+}
+
+static void _rtl8192ee_read_power_value_fromprom(struct ieee80211_hw *hw,
+						 struct txpower_info_2g *pwr2g,
+						 struct txpower_info_5g *pwr5g,
+						 bool autoload_fail, u8 *hwinfo)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 rf, addr = EEPROM_TX_PWR_INX, group, i = 0;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "hal_ReadPowerValueFromPROM92E(): PROMContent[0x%x]=0x%x\n",
+		 (addr + 1), hwinfo[addr + 1]);
+	if (0xFF == hwinfo[addr+1])  /*YJ,add,120316*/
+		autoload_fail = true;
+
+	if (autoload_fail) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "auto load fail : Use Default value!\n");
+		for (rf = 0 ; rf < MAX_RF_PATH ; rf++) {
+			/* 2.4G default value */
+			for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) {
+				pwr2g->index_cck_base[rf][group] = 0x2D;
+				pwr2g->index_bw40_base[rf][group] = 0x2D;
+			}
+			for (i = 0; i < MAX_TX_COUNT; i++) {
+				if (i == 0) {
+					pwr2g->bw20_diff[rf][0] = 0x02;
+					pwr2g->ofdm_diff[rf][0] = 0x04;
+				} else {
+					pwr2g->bw20_diff[rf][i] = 0xFE;
+					pwr2g->bw40_diff[rf][i] = 0xFE;
+					pwr2g->cck_diff[rf][i] = 0xFE;
+					pwr2g->ofdm_diff[rf][i] = 0xFE;
+				}
+			}
+
+			/*5G default value*/
+			for (group = 0 ; group < MAX_CHNL_GROUP_5G; group++)
+				pwr5g->index_bw40_base[rf][group] = 0x2A;
+
+			for (i = 0; i < MAX_TX_COUNT; i++) {
+				if (i == 0) {
+					pwr5g->ofdm_diff[rf][0] = 0x04;
+					pwr5g->bw20_diff[rf][0] = 0x00;
+					pwr5g->bw80_diff[rf][0] = 0xFE;
+					pwr5g->bw160_diff[rf][0] = 0xFE;
+				} else {
+					pwr5g->ofdm_diff[rf][0] = 0xFE;
+					pwr5g->bw20_diff[rf][0] = 0xFE;
+					pwr5g->bw40_diff[rf][0] = 0xFE;
+					pwr5g->bw80_diff[rf][0] = 0xFE;
+					pwr5g->bw160_diff[rf][0] = 0xFE;
+				}
+			}
+		}
+		return;
+	}
+
+	rtl_priv(hw)->efuse.txpwr_fromeprom = true;
+
+	for (rf = 0 ; rf < MAX_RF_PATH ; rf++) {
+		/*2.4G default value*/
+		for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) {
+			pwr2g->index_cck_base[rf][group] = hwinfo[addr++];
+			if (pwr2g->index_cck_base[rf][group] == 0xFF)
+				pwr2g->index_cck_base[rf][group] = 0x2D;
+		}
+		for (group = 0 ; group < MAX_CHNL_GROUP_24G - 1; group++) {
+			pwr2g->index_bw40_base[rf][group] = hwinfo[addr++];
+			if (pwr2g->index_bw40_base[rf][group] == 0xFF)
+				pwr2g->index_bw40_base[rf][group] = 0x2D;
+		}
+		for (i = 0; i < MAX_TX_COUNT; i++) {
+			if (i == 0) {
+				pwr2g->bw40_diff[rf][i] = 0;
+				if (hwinfo[addr] == 0xFF) {
+					pwr2g->bw20_diff[rf][i] = 0x02;
+				} else {
+					pwr2g->bw20_diff[rf][i] = (hwinfo[addr]
+								   & 0xf0) >> 4;
+					if (pwr2g->bw20_diff[rf][i] & BIT(3))
+						pwr2g->bw20_diff[rf][i] |= 0xF0;
+				}
+
+				if (hwinfo[addr] == 0xFF) {
+					pwr2g->ofdm_diff[rf][i] = 0x04;
+				} else {
+					pwr2g->ofdm_diff[rf][i] = (hwinfo[addr]
+								   & 0x0f);
+					if (pwr2g->ofdm_diff[rf][i] & BIT(3))
+						pwr2g->ofdm_diff[rf][i] |= 0xF0;
+				}
+				pwr2g->cck_diff[rf][i] = 0;
+				addr++;
+			} else {
+				if (hwinfo[addr] == 0xFF) {
+					pwr2g->bw40_diff[rf][i] = 0xFE;
+				} else {
+					pwr2g->bw40_diff[rf][i] = (hwinfo[addr]
+								   & 0xf0) >> 4;
+					if (pwr2g->bw40_diff[rf][i] & BIT(3))
+						pwr2g->bw40_diff[rf][i] |= 0xF0;
+				}
+
+				if (hwinfo[addr] == 0xFF) {
+					pwr2g->bw20_diff[rf][i] = 0xFE;
+				} else {
+					pwr2g->bw20_diff[rf][i] = (hwinfo[addr]
+								   & 0x0f);
+					if (pwr2g->bw20_diff[rf][i] & BIT(3))
+						pwr2g->bw20_diff[rf][i] |= 0xF0;
+				}
+				addr++;
+
+				if (hwinfo[addr] == 0xFF) {
+					pwr2g->ofdm_diff[rf][i] = 0xFE;
+				} else {
+					pwr2g->ofdm_diff[rf][i] = (hwinfo[addr]
+								   & 0xf0) >> 4;
+					if (pwr2g->ofdm_diff[rf][i] & BIT(3))
+						pwr2g->ofdm_diff[rf][i] |= 0xF0;
+				}
+
+				if (hwinfo[addr] == 0xFF) {
+					pwr2g->cck_diff[rf][i] = 0xFE;
+				} else {
+					pwr2g->cck_diff[rf][i] = (hwinfo[addr]
+								  & 0x0f);
+					if (pwr2g->cck_diff[rf][i] & BIT(3))
+						pwr2g->cck_diff[rf][i] |= 0xF0;
+				}
+				addr++;
+			}
+		}
+
+		/*5G default value*/
+		for (group = 0 ; group < MAX_CHNL_GROUP_5G; group++) {
+			pwr5g->index_bw40_base[rf][group] = hwinfo[addr++];
+			if (pwr5g->index_bw40_base[rf][group] == 0xFF)
+				pwr5g->index_bw40_base[rf][group] = 0xFE;
+		}
+
+		for (i = 0; i < MAX_TX_COUNT; i++) {
+			if (i == 0) {
+				pwr5g->bw40_diff[rf][i] = 0;
+
+				if (hwinfo[addr] == 0xFF) {
+					pwr5g->bw20_diff[rf][i] = 0;
+				} else {
+					pwr5g->bw20_diff[rf][0] = (hwinfo[addr]
+								   & 0xf0) >> 4;
+					if (pwr5g->bw20_diff[rf][i] & BIT(3))
+						pwr5g->bw20_diff[rf][i] |= 0xF0;
+				}
+
+				if (hwinfo[addr] == 0xFF) {
+					pwr5g->ofdm_diff[rf][i] = 0x04;
+				} else {
+					pwr5g->ofdm_diff[rf][0] = (hwinfo[addr]
+								   & 0x0f);
+					if (pwr5g->ofdm_diff[rf][i] & BIT(3))
+						pwr5g->ofdm_diff[rf][i] |= 0xF0;
+				}
+				addr++;
+			} else {
+				if (hwinfo[addr] == 0xFF) {
+					pwr5g->bw40_diff[rf][i] = 0xFE;
+				} else {
+					pwr5g->bw40_diff[rf][i] = (hwinfo[addr]
+								  & 0xf0) >> 4;
+					if (pwr5g->bw40_diff[rf][i] & BIT(3))
+						pwr5g->bw40_diff[rf][i] |= 0xF0;
+				}
+
+				if (hwinfo[addr] == 0xFF) {
+					pwr5g->bw20_diff[rf][i] = 0xFE;
+				} else {
+					pwr5g->bw20_diff[rf][i] = (hwinfo[addr]
+								   & 0x0f);
+					if (pwr5g->bw20_diff[rf][i] & BIT(3))
+						pwr5g->bw20_diff[rf][i] |= 0xF0;
+				}
+				addr++;
+			}
+		}
+
+		if (hwinfo[addr] == 0xFF) {
+			pwr5g->ofdm_diff[rf][1] = 0xFE;
+			pwr5g->ofdm_diff[rf][2] = 0xFE;
+		} else {
+			pwr5g->ofdm_diff[rf][1] = (hwinfo[addr] & 0xf0) >> 4;
+			pwr5g->ofdm_diff[rf][2] = (hwinfo[addr] & 0x0f);
+		}
+		addr++;
+
+		if (hwinfo[addr] == 0xFF)
+			pwr5g->ofdm_diff[rf][3] = 0xFE;
+		else
+			pwr5g->ofdm_diff[rf][3] = (hwinfo[addr] & 0x0f);
+		addr++;
+
+		for (i = 1; i < MAX_TX_COUNT; i++) {
+			if (pwr5g->ofdm_diff[rf][i] == 0xFF)
+				pwr5g->ofdm_diff[rf][i] = 0xFE;
+			else if (pwr5g->ofdm_diff[rf][i] & BIT(3))
+				pwr5g->ofdm_diff[rf][i] |= 0xF0;
+		}
+
+		for (i = 0; i < MAX_TX_COUNT; i++) {
+			if (hwinfo[addr] == 0xFF) {
+				pwr5g->bw80_diff[rf][i] = 0xFE;
+			} else {
+				pwr5g->bw80_diff[rf][i] = (hwinfo[addr] & 0xf0)
+							  >> 4;
+				if (pwr5g->bw80_diff[rf][i] & BIT(3))
+					pwr5g->bw80_diff[rf][i] |= 0xF0;
+			}
+
+			if (hwinfo[addr] == 0xFF) {
+				pwr5g->bw160_diff[rf][i] = 0xFE;
+			} else {
+				pwr5g->bw160_diff[rf][i] =
+				  (hwinfo[addr] & 0x0f);
+				if (pwr5g->bw160_diff[rf][i] & BIT(3))
+					pwr5g->bw160_diff[rf][i] |= 0xF0;
+			}
+			addr++;
+		}
+	}
+}
+
+static void _rtl92ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
+						 bool autoload_fail, u8 *hwinfo)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_efuse *efu = rtl_efuse(rtl_priv(hw));
+	struct txpower_info_2g pwr2g;
+	struct txpower_info_5g pwr5g;
+	u8 channel5g[CHANNEL_MAX_NUMBER_5G] = {
+		36, 38, 40, 42, 44, 46, 48, 50, 52, 54,
+		56, 58, 60, 62, 64, 100, 102, 104, 106,
+		108, 110, 112, 114, 116, 118, 120, 122,
+		124, 126, 128, 130, 132, 134, 136, 138,
+		140, 142, 144, 149, 151, 153, 155, 157,
+		159, 161, 163, 165, 167, 168, 169, 171,
+		173, 175, 177
+	};
+	u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {
+		42, 58, 106, 122, 138, 155, 171
+	};
+	u8 rf, idx;
+	u8 i;
+
+	_rtl8192ee_read_power_value_fromprom(hw, &pwr2g, &pwr5g,
+					     autoload_fail, hwinfo);
+
+	for (rf = 0; rf < MAX_RF_PATH; rf++) {
+		for (i = 0; i < 14; i++) {
+			idx = _rtl92ee_get_chnl_group(i + 1);
+
+			if (i == CHANNEL_MAX_NUMBER_2G - 1) {
+				efu->txpwrlevel_cck[rf][i] =
+						pwr2g.index_cck_base[rf][5];
+				efu->txpwrlevel_ht40_1s[rf][i] =
+						pwr2g.index_bw40_base[rf][idx];
+			} else {
+				efu->txpwrlevel_cck[rf][i] =
+						pwr2g.index_cck_base[rf][idx];
+				efu->txpwrlevel_ht40_1s[rf][i] =
+						pwr2g.index_bw40_base[rf][idx];
+			}
+		}
+		for (i = 0; i < CHANNEL_MAX_NUMBER_5G; i++) {
+			idx = _rtl92ee_get_chnl_group(channel5g[i]);
+			efu->txpwr_5g_bw40base[rf][i] =
+					pwr5g.index_bw40_base[rf][idx];
+		}
+		for (i = 0; i < CHANNEL_MAX_NUMBER_5G_80M; i++) {
+			u8 upper, lower;
+
+			idx = _rtl92ee_get_chnl_group(channel5g_80m[i]);
+			upper = pwr5g.index_bw40_base[rf][idx];
+			lower = pwr5g.index_bw40_base[rf][idx + 1];
+
+			efu->txpwr_5g_bw80base[rf][i] = (upper + lower) / 2;
+		}
+		for (i = 0; i < MAX_TX_COUNT; i++) {
+			efu->txpwr_cckdiff[rf][i] = pwr2g.cck_diff[rf][i];
+			efu->txpwr_legacyhtdiff[rf][i] = pwr2g.ofdm_diff[rf][i];
+			efu->txpwr_ht20diff[rf][i] = pwr2g.bw20_diff[rf][i];
+			efu->txpwr_ht40diff[rf][i] = pwr2g.bw40_diff[rf][i];
+
+			efu->txpwr_5g_ofdmdiff[rf][i] = pwr5g.ofdm_diff[rf][i];
+			efu->txpwr_5g_bw20diff[rf][i] = pwr5g.bw20_diff[rf][i];
+			efu->txpwr_5g_bw40diff[rf][i] = pwr5g.bw40_diff[rf][i];
+			efu->txpwr_5g_bw80diff[rf][i] = pwr5g.bw80_diff[rf][i];
+		}
+	}
+
+	if (!autoload_fail)
+		efu->eeprom_thermalmeter = hwinfo[EEPROM_THERMAL_METER_92E];
+	else
+		efu->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER;
+
+	if (efu->eeprom_thermalmeter == 0xff || autoload_fail) {
+		efu->apk_thermalmeterignore = true;
+		efu->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER;
+	}
+
+	efu->thermalmeter[0] = efu->eeprom_thermalmeter;
+	RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
+		"thermalmeter = 0x%x\n", efu->eeprom_thermalmeter);
+
+	if (!autoload_fail) {
+		efu->eeprom_regulatory = hwinfo[EEPROM_RF_BOARD_OPTION_92E]
+					 & 0x07;
+		if (hwinfo[EEPROM_RF_BOARD_OPTION_92E] == 0xFF)
+			efu->eeprom_regulatory = 0;
+	} else {
+		efu->eeprom_regulatory = 0;
+	}
+	RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
+		"eeprom_regulatory = 0x%x\n", efu->eeprom_regulatory);
+}
+
+static void _rtl92ee_read_adapter_info(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u16 i, usvalue;
+	u8 hwinfo[HWSET_MAX_SIZE];
+	u16 eeprom_id;
+
+	if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
+		rtl_efuse_shadow_map_update(hw);
+
+		memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+		       HWSET_MAX_SIZE);
+	} else if (rtlefuse->epromtype == EEPROM_93C46) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "RTL819X Not boot from eeprom, check it !!");
+		return;
+	} else {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "boot from neither eeprom nor efuse, check it !!");
+		return;
+	}
+
+	RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP\n",
+		      hwinfo, HWSET_MAX_SIZE);
+
+	eeprom_id = *((u16 *)&hwinfo[0]);
+	if (eeprom_id != RTL8192E_EEPROM_ID) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "EEPROM ID(%#x) is invalid!!\n", eeprom_id);
+		rtlefuse->autoload_failflag = true;
+	} else {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+		rtlefuse->autoload_failflag = false;
+	}
+
+	if (rtlefuse->autoload_failflag)
+		return;
+	/*VID DID SVID SDID*/
+	rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID];
+	rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID];
+	rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID];
+	rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID];
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "EEPROMId = 0x%4x\n", eeprom_id);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);
+	/*customer ID*/
+	rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+	if (rtlefuse->eeprom_oemid == 0xFF)
+		rtlefuse->eeprom_oemid = 0;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
+	/*EEPROM version*/
+	rtlefuse->eeprom_version = *(u8 *)&hwinfo[EEPROM_VERSION];
+	/*mac address*/
+	for (i = 0; i < 6; i += 2) {
+		usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
+		*((u16 *)(&rtlefuse->dev_addr[i])) = usvalue;
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		 "dev_addr: %pM\n", rtlefuse->dev_addr);
+	/*channel plan */
+	rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+	/* set channel paln to world wide 13 */
+	rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+	/*tx power*/
+	_rtl92ee_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag,
+					     hwinfo);
+
+	rtl92ee_read_bt_coexist_info_from_hwpg(hw, rtlefuse->autoload_failflag,
+					       hwinfo);
+
+	/*board type*/
+	rtlefuse->board_type = (((*(u8 *)&hwinfo[EEPROM_RF_BOARD_OPTION_92E])
+				& 0xE0) >> 5);
+	if ((*(u8 *)&hwinfo[EEPROM_RF_BOARD_OPTION_92E]) == 0xFF)
+		rtlefuse->board_type = 0;
+
+	rtlhal->board_type = rtlefuse->board_type;
+	/*parse xtal*/
+	rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_92E];
+	if (hwinfo[EEPROM_XTAL_92E] == 0xFF)
+		rtlefuse->crystalcap = 0x20;
+
+	/*antenna diversity*/
+	rtlefuse->antenna_div_type = NO_ANTDIV;
+	rtlefuse->antenna_div_cfg = 0;
+
+	if (rtlhal->oem_id == RT_CID_DEFAULT) {
+		switch (rtlefuse->eeprom_oemid) {
+		case EEPROM_CID_DEFAULT:
+			if (rtlefuse->eeprom_did == 0x818B) {
+				if ((rtlefuse->eeprom_svid == 0x10EC) &&
+				    (rtlefuse->eeprom_smid == 0x001B))
+					rtlhal->oem_id = RT_CID_819X_LENOVO;
+			} else {
+				rtlhal->oem_id = RT_CID_DEFAULT;
+			}
+			break;
+		default:
+			rtlhal->oem_id = RT_CID_DEFAULT;
+			break;
+		}
+	}
+}
+
+static void _rtl92ee_hal_customized_behavior(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+	pcipriv->ledctl.led_opendrain = true;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		 "RT Customized ID: 0x%02X\n", rtlhal->oem_id);
+}
+
+void rtl92ee_read_eeprom_info(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 tmp_u1b;
+
+	rtlhal->version = _rtl92ee_read_chip_version(hw);
+	if (get_rf_type(rtlphy) == RF_1T1R) {
+		rtlpriv->dm.rfpath_rxenable[0] = true;
+	} else {
+		rtlpriv->dm.rfpath_rxenable[0] = true;
+		rtlpriv->dm.rfpath_rxenable[1] = true;
+	}
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n",
+		 rtlhal->version);
+	tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR);
+	if (tmp_u1b & BIT(4)) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n");
+		rtlefuse->epromtype = EEPROM_93C46;
+	} else {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n");
+		rtlefuse->epromtype = EEPROM_BOOT_EFUSE;
+	}
+	if (tmp_u1b & BIT(5)) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+		rtlefuse->autoload_failflag = false;
+		_rtl92ee_read_adapter_info(hw);
+	} else {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n");
+	}
+	_rtl92ee_hal_customized_behavior(hw);
+
+	rtlphy->rfpath_rx_enable[0] = true;
+	if (rtlphy->rf_type == RF_2T2R)
+		rtlphy->rfpath_rx_enable[1] = true;
+}
+
+static u8 _rtl92ee_mrate_idx_to_arfr_id(struct ieee80211_hw *hw, u8 rate_index)
+{
+	u8 ret = 0;
+
+	switch (rate_index) {
+	case RATR_INX_WIRELESS_NGB:
+		ret = 0;
+		break;
+	case RATR_INX_WIRELESS_N:
+	case RATR_INX_WIRELESS_NG:
+		ret = 4;
+		break;
+	case RATR_INX_WIRELESS_NB:
+		ret = 2;
+		break;
+	case RATR_INX_WIRELESS_GB:
+		ret = 6;
+		break;
+	case RATR_INX_WIRELESS_G:
+		ret = 7;
+		break;
+	case RATR_INX_WIRELESS_B:
+		ret = 8;
+		break;
+	default:
+		ret = 0;
+		break;
+	}
+	return ret;
+}
+
+static void rtl92ee_update_hal_rate_mask(struct ieee80211_hw *hw,
+					 struct ieee80211_sta *sta,
+					 u8 rssi_level)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_sta_info *sta_entry = NULL;
+	u32 ratr_bitmap;
+	u8 ratr_index;
+	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+			     ? 1 : 0;
+	u8 b_curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+				1 : 0;
+	u8 b_curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+				1 : 0;
+	enum wireless_mode wirelessmode = 0;
+	bool b_shortgi = false;
+	u8 rate_mask[7] = {0};
+	u8 macid = 0;
+	/*u8 mimo_ps = IEEE80211_SMPS_OFF;*/
+	sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+	wirelessmode = sta_entry->wireless_mode;
+	if (mac->opmode == NL80211_IFTYPE_STATION ||
+	    mac->opmode == NL80211_IFTYPE_MESH_POINT)
+		curtxbw_40mhz = mac->bw_40;
+	else if (mac->opmode == NL80211_IFTYPE_AP ||
+		 mac->opmode == NL80211_IFTYPE_ADHOC)
+		macid = sta->aid + 1;
+
+	ratr_bitmap = sta->supp_rates[0];
+	if (mac->opmode == NL80211_IFTYPE_ADHOC)
+		ratr_bitmap = 0xfff;
+
+	ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+			sta->ht_cap.mcs.rx_mask[0] << 12);
+
+	switch (wirelessmode) {
+	case WIRELESS_MODE_B:
+		ratr_index = RATR_INX_WIRELESS_B;
+		if (ratr_bitmap & 0x0000000c)
+			ratr_bitmap &= 0x0000000d;
+		else
+			ratr_bitmap &= 0x0000000f;
+		break;
+	case WIRELESS_MODE_G:
+		ratr_index = RATR_INX_WIRELESS_GB;
+
+		if (rssi_level == 1)
+			ratr_bitmap &= 0x00000f00;
+		else if (rssi_level == 2)
+			ratr_bitmap &= 0x00000ff0;
+		else
+			ratr_bitmap &= 0x00000ff5;
+		break;
+	case WIRELESS_MODE_N_24G:
+		if (curtxbw_40mhz)
+			ratr_index = RATR_INX_WIRELESS_NGB;
+		else
+			ratr_index = RATR_INX_WIRELESS_NB;
+
+		if (rtlphy->rf_type == RF_1T1R) {
+			if (curtxbw_40mhz) {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x000f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x000ff000;
+				else
+					ratr_bitmap &= 0x000ff015;
+			} else {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x000f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x000ff000;
+				else
+					ratr_bitmap &= 0x000ff005;
+			}
+		} else {
+			if (curtxbw_40mhz) {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x0f8f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x0ffff000;
+				else
+					ratr_bitmap &= 0x0ffff015;
+			} else {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x0f8f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x0ffff000;
+				else
+					ratr_bitmap &= 0x0ffff005;
+			}
+		}
+
+		if ((curtxbw_40mhz && b_curshortgi_40mhz) ||
+		    (!curtxbw_40mhz && b_curshortgi_20mhz)) {
+			if (macid == 0)
+				b_shortgi = true;
+			else if (macid == 1)
+				b_shortgi = false;
+		}
+		break;
+	default:
+		ratr_index = RATR_INX_WIRELESS_NGB;
+
+		if (rtlphy->rf_type == RF_1T1R)
+			ratr_bitmap &= 0x000ff0ff;
+		else
+			ratr_bitmap &= 0x0f8ff0ff;
+		break;
+	}
+	ratr_index = _rtl92ee_mrate_idx_to_arfr_id(hw, ratr_index);
+	sta_entry->ratr_index = ratr_index;
+
+	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+		 "ratr_bitmap :%x\n", ratr_bitmap);
+	*(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
+				       (ratr_index << 28);
+	rate_mask[0] = macid;
+	rate_mask[1] = ratr_index | (b_shortgi ? 0x80 : 0x00);
+	rate_mask[2] = curtxbw_40mhz;
+	rate_mask[3] = (u8)(ratr_bitmap & 0x000000ff);
+	rate_mask[4] = (u8)((ratr_bitmap & 0x0000ff00) >> 8);
+	rate_mask[5] = (u8)((ratr_bitmap & 0x00ff0000) >> 16);
+	rate_mask[6] = (u8)((ratr_bitmap & 0xff000000) >> 24);
+	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+		 "Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x:%x:%x\n",
+		  ratr_index, ratr_bitmap, rate_mask[0], rate_mask[1],
+		  rate_mask[2], rate_mask[3], rate_mask[4],
+		  rate_mask[5], rate_mask[6]);
+	rtl92ee_fill_h2c_cmd(hw, H2C_92E_RA_MASK, 7, rate_mask);
+	_rtl92ee_set_bcn_ctrl_reg(hw, BIT(3), 0);
+}
+
+void rtl92ee_update_hal_rate_tbl(struct ieee80211_hw *hw,
+				 struct ieee80211_sta *sta, u8 rssi_level)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (rtlpriv->dm.useramask)
+		rtl92ee_update_hal_rate_mask(hw, sta, rssi_level);
+}
+
+void rtl92ee_update_channel_access_setting(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	u16 sifs_timer;
+
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
+				      (u8 *)&mac->slot_time);
+	if (!mac->ht_enable)
+		sifs_timer = 0x0a0a;
+	else
+		sifs_timer = 0x0e0e;
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
+}
+
+bool rtl92ee_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
+{
+	*valid = 1;
+	return true;
+}
+
+void rtl92ee_set_key(struct ieee80211_hw *hw, u32 key_index,
+		     u8 *p_macaddr, bool is_group, u8 enc_algo,
+		     bool is_wepkey, bool clear_all)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	u8 *macaddr = p_macaddr;
+	u32 entry_id = 0;
+	bool is_pairwise = false;
+
+	static u8 cam_const_addr[4][6] = {
+		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+		{0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+		{0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+		{0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+	};
+	static u8 cam_const_broad[] = {
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+	};
+
+	if (clear_all) {
+		u8 idx = 0;
+		u8 cam_offset = 0;
+		u8 clear_number = 5;
+
+		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n");
+
+		for (idx = 0; idx < clear_number; idx++) {
+			rtl_cam_mark_invalid(hw, cam_offset + idx);
+			rtl_cam_empty_entry(hw, cam_offset + idx);
+
+			if (idx < 5) {
+				memset(rtlpriv->sec.key_buf[idx], 0,
+				       MAX_KEY_LEN);
+				rtlpriv->sec.key_len[idx] = 0;
+			}
+		}
+
+	} else {
+		switch (enc_algo) {
+		case WEP40_ENCRYPTION:
+			enc_algo = CAM_WEP40;
+			break;
+		case WEP104_ENCRYPTION:
+			enc_algo = CAM_WEP104;
+			break;
+		case TKIP_ENCRYPTION:
+			enc_algo = CAM_TKIP;
+			break;
+		case AESCCMP_ENCRYPTION:
+			enc_algo = CAM_AES;
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "switch case not process\n");
+			enc_algo = CAM_TKIP;
+			break;
+		}
+
+		if (is_wepkey || rtlpriv->sec.use_defaultkey) {
+			macaddr = cam_const_addr[key_index];
+			entry_id = key_index;
+		} else {
+			if (is_group) {
+				macaddr = cam_const_broad;
+				entry_id = key_index;
+			} else {
+				if (mac->opmode == NL80211_IFTYPE_AP ||
+				    mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+					entry_id = rtl_cam_get_free_entry(hw,
+								     p_macaddr);
+					if (entry_id >=  TOTAL_CAM_ENTRY) {
+						RT_TRACE(rtlpriv, COMP_SEC,
+							 DBG_EMERG,
+							 "Can not find free hw security cam entry\n");
+						return;
+					}
+				} else {
+					entry_id = CAM_PAIRWISE_KEY_POSITION;
+				}
+
+				key_index = PAIRWISE_KEYIDX;
+				is_pairwise = true;
+			}
+		}
+
+		if (rtlpriv->sec.key_len[key_index] == 0) {
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+				 "delete one entry, entry_id is %d\n",
+				 entry_id);
+			if (mac->opmode == NL80211_IFTYPE_AP ||
+			    mac->opmode == NL80211_IFTYPE_MESH_POINT)
+				rtl_cam_del_entry(hw, p_macaddr);
+			rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
+		} else {
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+				 "add one entry\n");
+			if (is_pairwise) {
+				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+					 "set Pairwiase key\n");
+
+				rtl_cam_add_one_entry(hw, macaddr, key_index,
+					       entry_id, enc_algo,
+					       CAM_CONFIG_NO_USEDK,
+					       rtlpriv->sec.key_buf[key_index]);
+			} else {
+				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+					 "set group key\n");
+
+				if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+					rtl_cam_add_one_entry(hw,
+						rtlefuse->dev_addr,
+						PAIRWISE_KEYIDX,
+						CAM_PAIRWISE_KEY_POSITION,
+						enc_algo, CAM_CONFIG_NO_USEDK,
+						rtlpriv->sec.key_buf[entry_id]);
+				}
+
+				rtl_cam_add_one_entry(hw, macaddr, key_index,
+						entry_id, enc_algo,
+						CAM_CONFIG_NO_USEDK,
+						rtlpriv->sec.key_buf[entry_id]);
+			}
+		}
+	}
+}
+
+void rtl92ee_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+					    bool auto_load_fail, u8 *hwinfo)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 value;
+
+	if (!auto_load_fail) {
+		value = hwinfo[EEPROM_RF_BOARD_OPTION_92E];
+		if (((value & 0xe0) >> 5) == 0x1)
+			rtlpriv->btcoexist.btc_info.btcoexist = 1;
+		else
+			rtlpriv->btcoexist.btc_info.btcoexist = 0;
+
+		rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8192E;
+		rtlpriv->btcoexist.btc_info.ant_num = ANT_TOTAL_X2;
+	} else {
+		rtlpriv->btcoexist.btc_info.btcoexist = 1;
+		rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8192E;
+		rtlpriv->btcoexist.btc_info.ant_num = ANT_TOTAL_X1;
+	}
+}
+
+void rtl92ee_bt_reg_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	/* 0:Low, 1:High, 2:From Efuse. */
+	rtlpriv->btcoexist.reg_bt_iso = 2;
+	/* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */
+	rtlpriv->btcoexist.reg_bt_sco = 3;
+	/* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
+	rtlpriv->btcoexist.reg_bt_sco = 0;
+}
+
+void rtl92ee_bt_hw_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (rtlpriv->cfg->ops->get_btc_status())
+		rtlpriv->btcoexist.btc_ops->btc_init_hw_config(rtlpriv);
+}
+
+void rtl92ee_suspend(struct ieee80211_hw *hw)
+{
+}
+
+void rtl92ee_resume(struct ieee80211_hw *hw)
+{
+}
+
+/* Turn on AAP (RCR:bit 0) for promicuous mode. */
+void rtl92ee_allow_all_destaddr(struct ieee80211_hw *hw,
+				bool allow_all_da, bool write_into_reg)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	if (allow_all_da)	/* Set BIT0 */
+		rtlpci->receive_config |= RCR_AAP;
+	else			/* Clear BIT0 */
+		rtlpci->receive_config &= ~RCR_AAP;
+
+	if (write_into_reg)
+		rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+	RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD,
+		 "receive_config=0x%08X, write_into_reg=%d\n",
+		  rtlpci->receive_config, write_into_reg);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.h b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.h
new file mode 100644
index 0000000..05413f1
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92E_HW_H__
+#define __RTL92E_HW_H__
+
+void rtl92ee_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl92ee_read_eeprom_info(struct ieee80211_hw *hw);
+void rtl92ee_interrupt_recognized(struct ieee80211_hw *hw,
+				  u32 *p_inta, u32 *p_intb);
+int rtl92ee_hw_init(struct ieee80211_hw *hw);
+void rtl92ee_card_disable(struct ieee80211_hw *hw);
+void rtl92ee_enable_interrupt(struct ieee80211_hw *hw);
+void rtl92ee_disable_interrupt(struct ieee80211_hw *hw);
+int rtl92ee_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type);
+void rtl92ee_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
+void rtl92ee_set_qos(struct ieee80211_hw *hw, int aci);
+void rtl92ee_set_beacon_related_registers(struct ieee80211_hw *hw);
+void rtl92ee_set_beacon_interval(struct ieee80211_hw *hw);
+void rtl92ee_update_interrupt_mask(struct ieee80211_hw *hw,
+				   u32 add_msr, u32 rm_msr);
+void rtl92ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl92ee_update_hal_rate_tbl(struct ieee80211_hw *hw,
+				 struct ieee80211_sta *sta, u8 rssi_level);
+void rtl92ee_update_channel_access_setting(struct ieee80211_hw *hw);
+bool rtl92ee_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
+void rtl92ee_enable_hw_security_config(struct ieee80211_hw *hw);
+void rtl92ee_set_key(struct ieee80211_hw *hw, u32 key_index,
+		     u8 *p_macaddr, bool is_group, u8 enc_algo,
+		     bool is_wepkey, bool clear_all);
+void rtl92ee_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+					    bool autoload_fail, u8 *hwinfo);
+void rtl92ee_bt_reg_init(struct ieee80211_hw *hw);
+void rtl92ee_bt_hw_init(struct ieee80211_hw *hw);
+void rtl92ee_suspend(struct ieee80211_hw *hw);
+void rtl92ee_resume(struct ieee80211_hw *hw);
+void rtl92ee_allow_all_destaddr(struct ieee80211_hw *hw, bool allow_all_da,
+				bool write_into_reg);
+void rtl92ee_fw_clk_off_timer_callback(unsigned long data);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/led.c b/drivers/net/wireless/rtlwifi/rtl8192ee/led.c
new file mode 100644
index 0000000..8388e37
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/led.c
@@ -0,0 +1,145 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "reg.h"
+#include "led.h"
+
+static void _rtl92ee_init_led(struct ieee80211_hw *hw,
+			      struct rtl_led *pled, enum rtl_led_pin ledpin)
+{
+	pled->hw = hw;
+	pled->ledpin = ledpin;
+	pled->ledon = false;
+}
+
+void rtl92ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+	u32 ledcfg;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
+
+	switch (pled->ledpin) {
+	case LED_PIN_GPIO0:
+		break;
+	case LED_PIN_LED0:
+		ledcfg = rtl_read_dword(rtlpriv , REG_GPIO_PIN_CTRL);
+		ledcfg &= ~BIT(13);
+		ledcfg |= BIT(21);
+		ledcfg &= ~BIT(29);
+
+		rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, ledcfg);
+
+		break;
+	case LED_PIN_LED1:
+
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
+		break;
+	}
+	pled->ledon = true;
+}
+
+void rtl92ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 ledcfg;
+
+	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
+
+	switch (pled->ledpin) {
+	case LED_PIN_GPIO0:
+		break;
+	case LED_PIN_LED0:
+
+		ledcfg = rtl_read_dword(rtlpriv , REG_GPIO_PIN_CTRL);
+		ledcfg |= ~BIT(21);
+		ledcfg &= ~BIT(29);
+		rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, ledcfg);
+
+		break;
+	case LED_PIN_LED1:
+
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
+		break;
+	}
+	pled->ledon = false;
+}
+
+void rtl92ee_init_sw_leds(struct ieee80211_hw *hw)
+{
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+
+	_rtl92ee_init_led(hw, &pcipriv->ledctl.sw_led0, LED_PIN_LED0);
+	_rtl92ee_init_led(hw, &pcipriv->ledctl.sw_led1, LED_PIN_LED1);
+}
+
+static void _rtl92ee_sw_led_control(struct ieee80211_hw *hw,
+				    enum led_ctl_mode ledaction)
+{
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	struct rtl_led *pLed0 = &pcipriv->ledctl.sw_led0;
+
+	switch (ledaction) {
+	case LED_CTL_POWER_ON:
+	case LED_CTL_LINK:
+	case LED_CTL_NO_LINK:
+		rtl92ee_sw_led_on(hw, pLed0);
+		break;
+	case LED_CTL_POWER_OFF:
+		rtl92ee_sw_led_off(hw, pLed0);
+		break;
+	default:
+		break;
+	}
+}
+
+void rtl92ee_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+	if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) &&
+	    (ledaction == LED_CTL_TX ||
+	     ledaction == LED_CTL_RX ||
+	     ledaction == LED_CTL_SITE_SURVEY ||
+	     ledaction == LED_CTL_LINK ||
+	     ledaction == LED_CTL_NO_LINK ||
+	     ledaction == LED_CTL_START_TO_LINK ||
+	     ledaction == LED_CTL_POWER_ON)) {
+		return;
+	}
+	RT_TRACE(rtlpriv, COMP_LED, DBG_TRACE, "ledaction %d,\n", ledaction);
+	_rtl92ee_sw_led_control(hw, ledaction);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/led.h b/drivers/net/wireless/rtlwifi/rtl8192ee/led.h
new file mode 100644
index 0000000..8ef640a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/led.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92E_LED_H__
+#define __RTL92E_LED_H__
+
+void rtl92ee_init_sw_leds(struct ieee80211_hw *hw);
+void rtl92ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl92ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl92ee_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c
new file mode 100644
index 0000000..a863a44
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c
@@ -0,0 +1,3219 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../ps.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+#include "table.h"
+
+static u32 _rtl92ee_phy_rf_serial_read(struct ieee80211_hw *hw,
+				       enum radio_path rfpath, u32 offset);
+static void _rtl92ee_phy_rf_serial_write(struct ieee80211_hw *hw,
+					 enum radio_path rfpath, u32 offset,
+					 u32 data);
+static u32 _rtl92ee_phy_calculate_bit_shift(u32 bitmask);
+static bool _rtl92ee_phy_bb8192ee_config_parafile(struct ieee80211_hw *hw);
+static bool _rtl92ee_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
+static bool phy_config_bb_with_hdr_file(struct ieee80211_hw *hw,
+					u8 configtype);
+static bool phy_config_bb_with_pghdrfile(struct ieee80211_hw *hw,
+					 u8 configtype);
+static void phy_init_bb_rf_register_def(struct ieee80211_hw *hw);
+static bool _rtl92ee_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+					      u32 cmdtableidx, u32 cmdtablesz,
+					      enum swchnlcmd_id cmdid,
+					      u32 para1, u32 para2,
+					      u32 msdelay);
+static bool _rtl92ee_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+					      u8 channel, u8 *stage,
+					      u8 *step, u32 *delay);
+static long _rtl92ee_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+					  enum wireless_mode wirelessmode,
+					  u8 txpwridx);
+static void rtl92ee_phy_set_rf_on(struct ieee80211_hw *hw);
+static void rtl92ee_phy_set_io(struct ieee80211_hw *hw);
+
+u32 rtl92ee_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 returnvalue, originalvalue, bitshift;
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask);
+	originalvalue = rtl_read_dword(rtlpriv, regaddr);
+	bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask);
+	returnvalue = (originalvalue & bitmask) >> bitshift;
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "BBR MASK=0x%x Addr[0x%x]=0x%x\n",
+		  bitmask, regaddr, originalvalue);
+
+	return returnvalue;
+}
+
+void rtl92ee_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
+			    u32 bitmask, u32 data)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 originalvalue, bitshift;
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), bitmask(%#x), data(%#x)\n",
+		  regaddr, bitmask, data);
+
+	if (bitmask != MASKDWORD) {
+		originalvalue = rtl_read_dword(rtlpriv, regaddr);
+		bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask);
+		data = ((originalvalue & (~bitmask)) | (data << bitshift));
+	}
+
+	rtl_write_dword(rtlpriv, regaddr, data);
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), bitmask(%#x), data(%#x)\n",
+		  regaddr, bitmask, data);
+}
+
+u32 rtl92ee_phy_query_rf_reg(struct ieee80211_hw *hw,
+			     enum radio_path rfpath, u32 regaddr, u32 bitmask)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 original_value, readback_value, bitshift;
+	unsigned long flags;
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
+		  regaddr, rfpath, bitmask);
+
+	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+	original_value = _rtl92ee_phy_rf_serial_read(hw , rfpath, regaddr);
+	bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask);
+	readback_value = (original_value & bitmask) >> bitshift;
+
+	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x),rfpath(%#x),bitmask(%#x),original_value(%#x)\n",
+		  regaddr, rfpath, bitmask, original_value);
+
+	return readback_value;
+}
+
+void rtl92ee_phy_set_rf_reg(struct ieee80211_hw *hw,
+			    enum radio_path rfpath,
+			    u32 addr, u32 bitmask, u32 data)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 original_value, bitshift;
+	unsigned long flags;
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+		  addr, bitmask, data, rfpath);
+
+	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+	if (bitmask != RFREG_OFFSET_MASK) {
+		original_value = _rtl92ee_phy_rf_serial_read(hw, rfpath, addr);
+		bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask);
+		data = (original_value & (~bitmask)) | (data << bitshift);
+	}
+
+	_rtl92ee_phy_rf_serial_write(hw, rfpath, addr, data);
+
+	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+		  addr, bitmask, data, rfpath);
+}
+
+static u32 _rtl92ee_phy_rf_serial_read(struct ieee80211_hw *hw,
+				       enum radio_path rfpath, u32 offset)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+	u32 newoffset;
+	u32 tmplong, tmplong2;
+	u8 rfpi_enable = 0;
+	u32 retvalue;
+
+	offset &= 0xff;
+	newoffset = offset;
+	if (RT_CANNOT_IO(hw)) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
+		return 0xFFFFFFFF;
+	}
+	tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
+	if (rfpath == RF90_PATH_A)
+		tmplong2 = tmplong;
+	else
+		tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
+	tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
+		   (newoffset << 23) | BLSSIREADEDGE;
+	rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+		      tmplong & (~BLSSIREADEDGE));
+	mdelay(1);
+	rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
+	mdelay(2);
+	if (rfpath == RF90_PATH_A)
+		rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
+						BIT(8));
+	else if (rfpath == RF90_PATH_B)
+		rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
+						BIT(8));
+	if (rfpi_enable)
+		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,
+					 BLSSIREADBACKDATA);
+	else
+		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
+					 BLSSIREADBACKDATA);
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "RFR-%d Addr[0x%x]=0x%x\n",
+		  rfpath, pphyreg->rf_rb, retvalue);
+	return retvalue;
+}
+
+static void _rtl92ee_phy_rf_serial_write(struct ieee80211_hw *hw,
+					 enum radio_path rfpath, u32 offset,
+					 u32 data)
+{
+	u32 data_and_addr;
+	u32 newoffset;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+
+	if (RT_CANNOT_IO(hw)) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
+		return;
+	}
+	offset &= 0xff;
+	newoffset = offset;
+	data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
+	rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "RFW-%d Addr[0x%x]=0x%x\n", rfpath,
+		 pphyreg->rf3wire_offset, data_and_addr);
+}
+
+static u32 _rtl92ee_phy_calculate_bit_shift(u32 bitmask)
+{
+	u32 i;
+
+	for (i = 0; i <= 31; i++) {
+		if (((bitmask >> i) & 0x1) == 1)
+			break;
+	}
+	return i;
+}
+
+bool rtl92ee_phy_mac_config(struct ieee80211_hw *hw)
+{
+	return _rtl92ee_phy_config_mac_with_headerfile(hw);
+}
+
+bool rtl92ee_phy_bb_config(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	bool rtstatus = true;
+	u16 regval;
+	u32 tmp;
+	u8 crystal_cap;
+
+	phy_init_bb_rf_register_def(hw);
+	regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+	rtl_write_word(rtlpriv, REG_SYS_FUNC_EN,
+		       regval | BIT(13) | BIT(0) | BIT(1));
+
+	rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN,
+		       FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE |
+		       FEN_BB_GLB_RSTN | FEN_BBRSTB);
+
+	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
+
+	tmp = rtl_read_dword(rtlpriv, 0x4c);
+	rtl_write_dword(rtlpriv, 0x4c, tmp | BIT(23));
+
+	rtstatus = _rtl92ee_phy_bb8192ee_config_parafile(hw);
+
+	crystal_cap = rtlpriv->efuse.eeprom_crystalcap & 0x3F;
+	rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000,
+		      (crystal_cap | (crystal_cap << 6)));
+	return rtstatus;
+}
+
+bool rtl92ee_phy_rf_config(struct ieee80211_hw *hw)
+{
+	return rtl92ee_phy_rf6052_config(hw);
+}
+
+static bool _check_condition(struct ieee80211_hw *hw,
+			     const u32  condition)
+{
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	u32 _board = rtlefuse->board_type; /*need efuse define*/
+	u32 _interface = rtlhal->interface;
+	u32 _platform = 0x08;/*SupportPlatform */
+	u32 cond = condition;
+
+	if (condition == 0xCDCDCDCD)
+		return true;
+
+	cond = condition & 0xFF;
+	if ((_board != cond) && (cond != 0xFF))
+		return false;
+
+	cond = condition & 0xFF00;
+	cond = cond >> 8;
+	if ((_interface & cond) == 0 && cond != 0x07)
+		return false;
+
+	cond = condition & 0xFF0000;
+	cond = cond >> 16;
+	if ((_platform & cond) == 0 && cond != 0x0F)
+		return false;
+
+	return true;
+}
+
+static void _rtl92ee_config_rf_reg(struct ieee80211_hw *hw, u32 addr, u32 data,
+				   enum radio_path rfpath, u32 regaddr)
+{
+	if (addr == 0xfe || addr == 0xffe) {
+		mdelay(50);
+	} else {
+		rtl_set_rfreg(hw, rfpath, regaddr, RFREG_OFFSET_MASK, data);
+		udelay(1);
+
+		if (addr == 0xb6) {
+			u32 getvalue;
+			u8 count = 0;
+
+			getvalue = rtl_get_rfreg(hw, rfpath, addr, MASKDWORD);
+			udelay(1);
+
+			while ((getvalue >> 8) != (data >> 8)) {
+				count++;
+				rtl_set_rfreg(hw, rfpath, regaddr,
+					      RFREG_OFFSET_MASK, data);
+				udelay(1);
+				getvalue = rtl_get_rfreg(hw, rfpath, addr,
+							 MASKDWORD);
+				if (count > 5)
+					break;
+			}
+		}
+
+		if (addr == 0xb2) {
+			u32 getvalue;
+			u8 count = 0;
+
+			getvalue = rtl_get_rfreg(hw, rfpath, addr, MASKDWORD);
+			udelay(1);
+
+			while (getvalue != data) {
+				count++;
+				rtl_set_rfreg(hw, rfpath, regaddr,
+					      RFREG_OFFSET_MASK, data);
+				udelay(1);
+				rtl_set_rfreg(hw, rfpath, 0x18,
+					      RFREG_OFFSET_MASK, 0x0fc07);
+				udelay(1);
+				getvalue = rtl_get_rfreg(hw, rfpath, addr,
+							 MASKDWORD);
+				if (count > 5)
+					break;
+			}
+		}
+	}
+}
+
+static void _rtl92ee_config_rf_radio_a(struct ieee80211_hw *hw,
+				       u32 addr, u32 data)
+{
+	u32 content = 0x1000; /*RF Content: radio_a_txt*/
+	u32 maskforphyset = (u32)(content & 0xE000);
+
+	_rtl92ee_config_rf_reg(hw, addr, data, RF90_PATH_A,
+			       addr | maskforphyset);
+}
+
+static void _rtl92ee_config_rf_radio_b(struct ieee80211_hw *hw,
+				       u32 addr, u32 data)
+{
+	u32 content = 0x1001; /*RF Content: radio_b_txt*/
+	u32 maskforphyset = (u32)(content & 0xE000);
+
+	_rtl92ee_config_rf_reg(hw, addr, data, RF90_PATH_B,
+			       addr | maskforphyset);
+}
+
+static void _rtl92ee_config_bb_reg(struct ieee80211_hw *hw,
+				   u32 addr, u32 data)
+{
+	if (addr == 0xfe)
+		mdelay(50);
+	else if (addr == 0xfd)
+		mdelay(5);
+	else if (addr == 0xfc)
+		mdelay(1);
+	else if (addr == 0xfb)
+		udelay(50);
+	else if (addr == 0xfa)
+		udelay(5);
+	else if (addr == 0xf9)
+		udelay(1);
+	else
+		rtl_set_bbreg(hw, addr, MASKDWORD , data);
+
+	udelay(1);
+}
+
+static void _rtl92ee_phy_init_tx_power_by_rate(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	u8 band = BAND_ON_2_4G, rf = 0, txnum = 0, sec = 0;
+
+	for (; band <= BAND_ON_5G; ++band)
+		for (; rf < TX_PWR_BY_RATE_NUM_RF; ++rf)
+			for (; txnum < TX_PWR_BY_RATE_NUM_RF; ++txnum)
+				for (; sec < TX_PWR_BY_RATE_NUM_SECTION; ++sec)
+					rtlphy->tx_power_by_rate_offset
+					     [band][rf][txnum][sec] = 0;
+}
+
+static void _rtl92ee_phy_set_txpower_by_rate_base(struct ieee80211_hw *hw,
+						  u8 band, u8 path,
+						  u8 rate_section, u8 txnum,
+						  u8 value)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	if (path > RF90_PATH_D) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Invalid Rf Path %d\n", path);
+		return;
+	}
+
+	if (band == BAND_ON_2_4G) {
+		switch (rate_section) {
+		case CCK:
+			rtlphy->txpwr_by_rate_base_24g[path][txnum][0] = value;
+			break;
+		case OFDM:
+			rtlphy->txpwr_by_rate_base_24g[path][txnum][1] = value;
+			break;
+		case HT_MCS0_MCS7:
+			rtlphy->txpwr_by_rate_base_24g[path][txnum][2] = value;
+			break;
+		case HT_MCS8_MCS15:
+			rtlphy->txpwr_by_rate_base_24g[path][txnum][3] = value;
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "Invalid RateSection %d in 2.4G,Rf %d,%dTx\n",
+				  rate_section, path, txnum);
+			break;
+		};
+	} else {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Invalid Band %d\n", band);
+	}
+}
+
+static u8 _rtl92ee_phy_get_txpower_by_rate_base(struct ieee80211_hw *hw,
+						u8 band, u8 path, u8 txnum,
+						u8 rate_section)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 value = 0;
+
+	if (path > RF90_PATH_D) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Invalid Rf Path %d\n", path);
+		return 0;
+	}
+
+	if (band == BAND_ON_2_4G) {
+		switch (rate_section) {
+		case CCK:
+			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][0];
+			break;
+		case OFDM:
+			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][1];
+			break;
+		case HT_MCS0_MCS7:
+			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][2];
+			break;
+		case HT_MCS8_MCS15:
+			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][3];
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "Invalid RateSection %d in 2.4G,Rf %d,%dTx\n",
+				  rate_section, path, txnum);
+			break;
+		};
+	} else {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Invalid Band %d()\n", band);
+	}
+	return value;
+}
+
+static void _rtl92ee_phy_store_txpower_by_rate_base(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u16 raw = 0;
+	u8 base = 0, path = 0;
+
+	for (path = RF90_PATH_A; path <= RF90_PATH_B; ++path) {
+		if (path == RF90_PATH_A) {
+			raw = (u16)(rtlphy->tx_power_by_rate_offset
+				    [BAND_ON_2_4G][path][RF_1TX][3] >> 24) &
+				    0xFF;
+			base = (raw >> 4) * 10 + (raw & 0xF);
+			_rtl92ee_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G,
+							      path, CCK, RF_1TX,
+							      base);
+		} else if (path == RF90_PATH_B) {
+			raw = (u16)(rtlphy->tx_power_by_rate_offset
+				    [BAND_ON_2_4G][path][RF_1TX][3] >> 0) &
+				    0xFF;
+			base = (raw >> 4) * 10 + (raw & 0xF);
+			_rtl92ee_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G,
+							      path, CCK, RF_1TX,
+							      base);
+		}
+		raw = (u16)(rtlphy->tx_power_by_rate_offset
+			    [BAND_ON_2_4G][path][RF_1TX][1] >> 24) & 0xFF;
+		base = (raw >> 4) * 10 + (raw & 0xF);
+		_rtl92ee_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path,
+						      OFDM, RF_1TX, base);
+
+		raw = (u16)(rtlphy->tx_power_by_rate_offset
+			    [BAND_ON_2_4G][path][RF_1TX][5] >> 24) & 0xFF;
+		base = (raw >> 4) * 10 + (raw & 0xF);
+		_rtl92ee_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path,
+						      HT_MCS0_MCS7, RF_1TX,
+						      base);
+
+		raw = (u16)(rtlphy->tx_power_by_rate_offset
+			    [BAND_ON_2_4G][path][RF_2TX][7] >> 24) & 0xFF;
+		base = (raw >> 4) * 10 + (raw & 0xF);
+		_rtl92ee_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path,
+						      HT_MCS8_MCS15, RF_2TX,
+						      base);
+	}
+}
+
+static void _phy_convert_txpower_dbm_to_relative_value(u32 *data, u8 start,
+						       u8 end, u8 base)
+{
+	char i = 0;
+	u8 tmp = 0;
+	u32 temp_data = 0;
+
+	for (i = 3; i >= 0; --i) {
+		if (i >= start && i <= end) {
+			/* Get the exact value */
+			tmp = (u8)(*data >> (i * 8)) & 0xF;
+			tmp += ((u8)((*data >> (i * 8 + 4)) & 0xF)) * 10;
+
+			/* Change the value to a relative value */
+			tmp = (tmp > base) ? tmp - base : base - tmp;
+		} else {
+			tmp = (u8)(*data >> (i * 8)) & 0xFF;
+		}
+		temp_data <<= 8;
+		temp_data |= tmp;
+	}
+	*data = temp_data;
+}
+
+static void phy_convert_txpwr_dbm_to_rel_val(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 base = 0, rf = 0, band = BAND_ON_2_4G;
+
+	for (rf = RF90_PATH_A; rf <= RF90_PATH_B; ++rf) {
+		if (rf == RF90_PATH_A) {
+			base = _rtl92ee_phy_get_txpower_by_rate_base(hw, band,
+								     rf, RF_1TX,
+								     CCK);
+			_phy_convert_txpower_dbm_to_relative_value(
+				&rtlphy->tx_power_by_rate_offset
+				[band][rf][RF_1TX][2],
+				1, 1, base);
+			_phy_convert_txpower_dbm_to_relative_value(
+				&rtlphy->tx_power_by_rate_offset
+				[band][rf][RF_1TX][3],
+				1, 3, base);
+		} else if (rf == RF90_PATH_B) {
+			base = _rtl92ee_phy_get_txpower_by_rate_base(hw, band,
+								     rf, RF_1TX,
+								     CCK);
+			_phy_convert_txpower_dbm_to_relative_value(
+				&rtlphy->tx_power_by_rate_offset
+				[band][rf][RF_1TX][3],
+				0, 0, base);
+			_phy_convert_txpower_dbm_to_relative_value(
+				&rtlphy->tx_power_by_rate_offset
+				[band][rf][RF_1TX][2],
+				1, 3, base);
+		}
+		base = _rtl92ee_phy_get_txpower_by_rate_base(hw, band, rf,
+							     RF_1TX, OFDM);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[band][rf][RF_1TX][0],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[band][rf][RF_1TX][1],
+			0, 3, base);
+
+		base = _rtl92ee_phy_get_txpower_by_rate_base(hw, band, rf,
+							     RF_1TX,
+							     HT_MCS0_MCS7);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[band][rf][RF_1TX][4],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[band][rf][RF_1TX][5],
+			0, 3, base);
+
+		base = _rtl92ee_phy_get_txpower_by_rate_base(hw, band, rf,
+							     RF_2TX,
+							     HT_MCS8_MCS15);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[band][rf][RF_2TX][6],
+			0, 3, base);
+
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[band][rf][RF_2TX][7],
+			0, 3, base);
+	}
+
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+		 "<==phy_convert_txpwr_dbm_to_rel_val()\n");
+}
+
+static void _rtl92ee_phy_txpower_by_rate_configuration(struct ieee80211_hw *hw)
+{
+	_rtl92ee_phy_store_txpower_by_rate_base(hw);
+	phy_convert_txpwr_dbm_to_rel_val(hw);
+}
+
+static bool _rtl92ee_phy_bb8192ee_config_parafile(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	bool rtstatus;
+
+	rtstatus = phy_config_bb_with_hdr_file(hw, BASEBAND_CONFIG_PHY_REG);
+	if (!rtstatus) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!");
+		return false;
+	}
+
+	_rtl92ee_phy_init_tx_power_by_rate(hw);
+	if (!rtlefuse->autoload_failflag) {
+		rtlphy->pwrgroup_cnt = 0;
+		rtstatus =
+		  phy_config_bb_with_pghdrfile(hw, BASEBAND_CONFIG_PHY_REG);
+	}
+	_rtl92ee_phy_txpower_by_rate_configuration(hw);
+	if (!rtstatus) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!");
+		return false;
+	}
+	rtstatus = phy_config_bb_with_hdr_file(hw, BASEBAND_CONFIG_AGC_TAB);
+	if (!rtstatus) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
+		return false;
+	}
+	rtlphy->cck_high_power = (bool)(rtl_get_bbreg(hw,
+						      RFPGA0_XA_HSSIPARAMETER2,
+						      0x200));
+
+	return true;
+}
+
+static bool _rtl92ee_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 i;
+	u32 arraylength;
+	u32 *ptrarray;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl8192EMACPHY_Array\n");
+	arraylength = RTL8192EE_MAC_ARRAY_LEN;
+	ptrarray = RTL8192EE_MAC_ARRAY;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "Img:RTL8192EE_MAC_ARRAY LEN %d\n" , arraylength);
+	for (i = 0; i < arraylength; i = i + 2)
+		rtl_write_byte(rtlpriv, ptrarray[i], (u8)ptrarray[i + 1]);
+	return true;
+}
+
+#define READ_NEXT_PAIR(v1, v2, i) \
+	do { \
+		i += 2; \
+		v1 = array[i]; \
+		v2 = array[i+1]; \
+	} while (0)
+
+static bool phy_config_bb_with_hdr_file(struct ieee80211_hw *hw,
+					u8 configtype)
+{
+	int i;
+	u32 *array;
+	u16 len;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 v1 = 0, v2 = 0;
+
+	if (configtype == BASEBAND_CONFIG_PHY_REG) {
+		len = RTL8192EE_PHY_REG_ARRAY_LEN;
+		array = RTL8192EE_PHY_REG_ARRAY;
+
+		for (i = 0; i < len; i = i + 2) {
+			v1 = array[i];
+			v2 = array[i+1];
+			if (v1 < 0xcdcdcdcd) {
+				_rtl92ee_config_bb_reg(hw, v1, v2);
+			} else {/*This line is the start line of branch.*/
+				/* to protect READ_NEXT_PAIR not overrun */
+				if (i >= len - 2)
+					break;
+
+				if (!_check_condition(hw , array[i])) {
+					/*Discard the following pairs*/
+					READ_NEXT_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD && i < len - 2) {
+						READ_NEXT_PAIR(v1, v2, i);
+					}
+					i -= 2; /* prevent from for-loop += 2*/
+				} else {
+					/* Configure matched pairs and
+					 * skip to end of if-else.
+					 */
+					READ_NEXT_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD && i < len - 2) {
+						_rtl92ee_config_bb_reg(hw, v1,
+								       v2);
+						READ_NEXT_PAIR(v1, v2, i);
+					}
+
+					while (v2 != 0xDEAD && i < len - 2)
+						READ_NEXT_PAIR(v1, v2, i);
+				}
+			}
+		}
+	} else if (configtype == BASEBAND_CONFIG_AGC_TAB) {
+		len = RTL8192EE_AGC_TAB_ARRAY_LEN;
+		array = RTL8192EE_AGC_TAB_ARRAY;
+
+		for (i = 0; i < len; i = i + 2) {
+			v1 = array[i];
+			v2 = array[i+1];
+			if (v1 < 0xCDCDCDCD) {
+				rtl_set_bbreg(hw, array[i], MASKDWORD,
+					      array[i + 1]);
+				udelay(1);
+				continue;
+		    } else{/*This line is the start line of branch.*/
+			  /* to protect READ_NEXT_PAIR not overrun */
+				if (i >= len - 2)
+					break;
+
+				if (!_check_condition(hw , array[i])) {
+					/*Discard the following pairs*/
+					READ_NEXT_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD &&
+					       i < len - 2) {
+						READ_NEXT_PAIR(v1, v2, i);
+					}
+					i -= 2; /* prevent from for-loop += 2*/
+				} else {
+					/* Configure matched pairs and
+					 * skip to end of if-else.
+					 */
+					READ_NEXT_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD &&
+					       i < len - 2) {
+						rtl_set_bbreg(hw,
+							      array[i],
+							      MASKDWORD,
+							      array[i + 1]);
+						udelay(1);
+						READ_NEXT_PAIR(v1 , v2 , i);
+					}
+
+					while (v2 != 0xDEAD &&
+					       i < len - 2) {
+						READ_NEXT_PAIR(v1 , v2 , i);
+					}
+				}
+			}
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+				 "The agctab_array_table[0] is %x Rtl818EEPHY_REGArray[1] is %x\n",
+				 array[i],
+				 array[i + 1]);
+		}
+	}
+	return true;
+}
+
+static u8 _rtl92ee_get_rate_section_index(u32 regaddr)
+{
+	u8 index = 0;
+
+	switch (regaddr) {
+	case RTXAGC_A_RATE18_06:
+	case RTXAGC_B_RATE18_06:
+		index = 0;
+		break;
+	case RTXAGC_A_RATE54_24:
+	case RTXAGC_B_RATE54_24:
+		index = 1;
+		break;
+	case RTXAGC_A_CCK1_MCS32:
+	case RTXAGC_B_CCK1_55_MCS32:
+		index = 2;
+		break;
+	case RTXAGC_B_CCK11_A_CCK2_11:
+		index = 3;
+		break;
+	case RTXAGC_A_MCS03_MCS00:
+	case RTXAGC_B_MCS03_MCS00:
+		index = 4;
+		break;
+	case RTXAGC_A_MCS07_MCS04:
+	case RTXAGC_B_MCS07_MCS04:
+		index = 5;
+		break;
+	case RTXAGC_A_MCS11_MCS08:
+	case RTXAGC_B_MCS11_MCS08:
+		index = 6;
+		break;
+	case RTXAGC_A_MCS15_MCS12:
+	case RTXAGC_B_MCS15_MCS12:
+		index = 7;
+		break;
+	default:
+		regaddr &= 0xFFF;
+		if (regaddr >= 0xC20 && regaddr <= 0xC4C)
+			index = (u8)((regaddr - 0xC20) / 4);
+		else if (regaddr >= 0xE20 && regaddr <= 0xE4C)
+			index = (u8)((regaddr - 0xE20) / 4);
+		break;
+	};
+	return index;
+}
+
+static void _rtl92ee_store_tx_power_by_rate(struct ieee80211_hw *hw,
+					    enum band_type band,
+					    enum radio_path rfpath,
+					    u32 txnum, u32 regaddr,
+					    u32 bitmask, u32 data)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 section = _rtl92ee_get_rate_section_index(regaddr);
+
+	if (band != BAND_ON_2_4G && band != BAND_ON_5G) {
+		RT_TRACE(rtlpriv, FPHY, PHY_TXPWR, "Invalid Band %d\n", band);
+		return;
+	}
+
+	if (rfpath > MAX_RF_PATH - 1) {
+		RT_TRACE(rtlpriv, FPHY, PHY_TXPWR,
+			 "Invalid RfPath %d\n", rfpath);
+		return;
+	}
+	if (txnum > MAX_RF_PATH - 1) {
+		RT_TRACE(rtlpriv, FPHY, PHY_TXPWR, "Invalid TxNum %d\n", txnum);
+		return;
+	}
+
+	rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][section] = data;
+}
+
+static bool phy_config_bb_with_pghdrfile(struct ieee80211_hw *hw,
+					 u8 configtype)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	int i;
+	u32 *phy_regarray_table_pg;
+	u16 phy_regarray_pg_len;
+	u32 v1 = 0, v2 = 0, v3 = 0, v4 = 0, v5 = 0, v6 = 0;
+
+	phy_regarray_pg_len = RTL8192EE_PHY_REG_ARRAY_PG_LEN;
+	phy_regarray_table_pg = RTL8192EE_PHY_REG_ARRAY_PG;
+
+	if (configtype == BASEBAND_CONFIG_PHY_REG) {
+		for (i = 0; i < phy_regarray_pg_len; i = i + 6) {
+			v1 = phy_regarray_table_pg[i];
+			v2 = phy_regarray_table_pg[i+1];
+			v3 = phy_regarray_table_pg[i+2];
+			v4 = phy_regarray_table_pg[i+3];
+			v5 = phy_regarray_table_pg[i+4];
+			v6 = phy_regarray_table_pg[i+5];
+
+			if (v1 < 0xcdcdcdcd) {
+				_rtl92ee_store_tx_power_by_rate(hw, v1, v2, v3,
+								v4, v5, v6);
+				continue;
+			}
+		}
+	} else {
+		RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+			 "configtype != BaseBand_Config_PHY_REG\n");
+	}
+	return true;
+}
+
+#define READ_NEXT_RF_PAIR(v1, v2, i) \
+	do { \
+		i += 2; \
+		v1 = array[i]; \
+		v2 = array[i+1]; \
+	} while (0)
+
+bool rtl92ee_phy_config_rf_with_headerfile(struct ieee80211_hw  *hw,
+					   enum radio_path rfpath)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	int i;
+	u32 *array;
+	u16 len;
+	u32 v1 = 0, v2 = 0;
+
+	switch (rfpath) {
+	case RF90_PATH_A:
+		len = RTL8192EE_RADIOA_ARRAY_LEN;
+		array = RTL8192EE_RADIOA_ARRAY;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Radio_A:RTL8192EE_RADIOA_ARRAY %d\n" , len);
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath);
+		for (i = 0; i < len; i = i + 2) {
+			v1 = array[i];
+			v2 = array[i+1];
+			if (v1 < 0xcdcdcdcd) {
+				_rtl92ee_config_rf_radio_a(hw, v1, v2);
+				continue;
+			} else {/*This line is the start line of branch.*/
+				/* to protect READ_NEXT_PAIR not overrun */
+				if (i >= len - 2)
+					break;
+
+				if (!_check_condition(hw , array[i])) {
+					/*Discard the following pairs*/
+					READ_NEXT_RF_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD && i < len - 2) {
+						READ_NEXT_RF_PAIR(v1, v2, i);
+					}
+					i -= 2; /* prevent from for-loop += 2*/
+				} else {
+					/* Configure matched pairs and
+					 * skip to end of if-else.
+					 */
+					READ_NEXT_RF_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD && i < len - 2) {
+						_rtl92ee_config_rf_radio_a(hw,
+									   v1,
+									   v2);
+						READ_NEXT_RF_PAIR(v1, v2, i);
+					}
+
+					while (v2 != 0xDEAD && i < len - 2)
+						READ_NEXT_RF_PAIR(v1, v2, i);
+				}
+			}
+		}
+		break;
+
+	case RF90_PATH_B:
+		len = RTL8192EE_RADIOB_ARRAY_LEN;
+		array = RTL8192EE_RADIOB_ARRAY;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Radio_A:RTL8192EE_RADIOB_ARRAY %d\n" , len);
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath);
+		for (i = 0; i < len; i = i + 2) {
+			v1 = array[i];
+			v2 = array[i+1];
+			if (v1 < 0xcdcdcdcd) {
+				_rtl92ee_config_rf_radio_b(hw, v1, v2);
+				continue;
+			} else {/*This line is the start line of branch.*/
+				/* to protect READ_NEXT_PAIR not overrun */
+				if (i >= len - 2)
+					break;
+
+				if (!_check_condition(hw , array[i])) {
+					/*Discard the following pairs*/
+					READ_NEXT_RF_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD && i < len - 2) {
+						READ_NEXT_RF_PAIR(v1, v2, i);
+					}
+					i -= 2; /* prevent from for-loop += 2*/
+				} else {
+					/* Configure matched pairs and
+					 * skip to end of if-else.
+					 */
+					READ_NEXT_RF_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD && i < len - 2) {
+						_rtl92ee_config_rf_radio_b(hw,
+									   v1,
+									   v2);
+						READ_NEXT_RF_PAIR(v1, v2, i);
+					}
+
+					while (v2 != 0xDEAD && i < len - 2)
+						READ_NEXT_RF_PAIR(v1, v2, i);
+				}
+			}
+		}
+		break;
+	case RF90_PATH_C:
+	case RF90_PATH_D:
+		break;
+	}
+	return true;
+}
+
+void rtl92ee_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	rtlphy->default_initialgain[0] =
+		(u8)rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
+	rtlphy->default_initialgain[1] =
+		(u8)rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
+	rtlphy->default_initialgain[2] =
+		(u8)rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
+	rtlphy->default_initialgain[3] =
+		(u8)rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+		 "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x\n",
+		  rtlphy->default_initialgain[0],
+		  rtlphy->default_initialgain[1],
+		  rtlphy->default_initialgain[2],
+		  rtlphy->default_initialgain[3]);
+
+	rtlphy->framesync = (u8)rtl_get_bbreg(hw,
+					      ROFDM0_RXDETECTOR3, MASKBYTE0);
+	rtlphy->framesync_c34 = rtl_get_bbreg(hw,
+					      ROFDM0_RXDETECTOR2, MASKDWORD);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+		 "Default framesync (0x%x) = 0x%x\n",
+		  ROFDM0_RXDETECTOR3, rtlphy->framesync);
+}
+
+static void phy_init_bb_rf_register_def(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+	rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE;
+	rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE;
+	rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset =
+							RFPGA0_XA_LSSIPARAMETER;
+	rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset =
+							RFPGA0_XB_LSSIPARAMETER;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
+	rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK;
+	rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK;
+	rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;
+}
+
+void rtl92ee_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 txpwr_level;
+	long txpwr_dbm;
+
+	txpwr_level = rtlphy->cur_cck_txpwridx;
+	txpwr_dbm = _rtl92ee_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B,
+						  txpwr_level);
+	txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
+	if (_rtl92ee_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) >
+	    txpwr_dbm)
+		txpwr_dbm = _rtl92ee_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
+							  txpwr_level);
+	txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
+	if (_rtl92ee_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
+					  txpwr_level) > txpwr_dbm)
+		txpwr_dbm = _rtl92ee_phy_txpwr_idx_to_dbm(hw,
+							  WIRELESS_MODE_N_24G,
+							  txpwr_level);
+	*powerlevel = txpwr_dbm;
+}
+
+static u8 _rtl92ee_phy_get_ratesection_intxpower_byrate(enum radio_path path,
+							u8 rate)
+{
+	u8 rate_section = 0;
+
+	switch (rate) {
+	case DESC92C_RATE1M:
+		rate_section = 2;
+		break;
+	case DESC92C_RATE2M:
+	case DESC92C_RATE5_5M:
+		if (path == RF90_PATH_A)
+			rate_section = 3;
+		else if (path == RF90_PATH_B)
+			rate_section = 2;
+		break;
+	case DESC92C_RATE11M:
+		rate_section = 3;
+		break;
+	case DESC92C_RATE6M:
+	case DESC92C_RATE9M:
+	case DESC92C_RATE12M:
+	case DESC92C_RATE18M:
+		rate_section = 0;
+		break;
+	case DESC92C_RATE24M:
+	case DESC92C_RATE36M:
+	case DESC92C_RATE48M:
+	case DESC92C_RATE54M:
+		rate_section = 1;
+		break;
+	case DESC92C_RATEMCS0:
+	case DESC92C_RATEMCS1:
+	case DESC92C_RATEMCS2:
+	case DESC92C_RATEMCS3:
+		rate_section = 4;
+		break;
+	case DESC92C_RATEMCS4:
+	case DESC92C_RATEMCS5:
+	case DESC92C_RATEMCS6:
+	case DESC92C_RATEMCS7:
+		rate_section = 5;
+		break;
+	case DESC92C_RATEMCS8:
+	case DESC92C_RATEMCS9:
+	case DESC92C_RATEMCS10:
+	case DESC92C_RATEMCS11:
+		rate_section = 6;
+		break;
+	case DESC92C_RATEMCS12:
+	case DESC92C_RATEMCS13:
+	case DESC92C_RATEMCS14:
+	case DESC92C_RATEMCS15:
+		rate_section = 7;
+		break;
+	default:
+		RT_ASSERT(true, "Rate_Section is Illegal\n");
+		break;
+	}
+	return rate_section;
+}
+
+static u8 _rtl92ee_get_txpower_by_rate(struct ieee80211_hw *hw,
+				       enum band_type band,
+				       enum radio_path rf, u8 rate)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 shift = 0, sec, tx_num;
+	char diff = 0;
+
+	sec = _rtl92ee_phy_get_ratesection_intxpower_byrate(rf, rate);
+	tx_num = RF_TX_NUM_NONIMPLEMENT;
+
+	if (tx_num == RF_TX_NUM_NONIMPLEMENT) {
+		if ((rate >= DESC92C_RATEMCS8 && rate <= DESC92C_RATEMCS15))
+			tx_num = RF_2TX;
+		else
+			tx_num = RF_1TX;
+	}
+
+	switch (rate) {
+	case DESC92C_RATE1M:
+	case DESC92C_RATE6M:
+	case DESC92C_RATE24M:
+	case DESC92C_RATEMCS0:
+	case DESC92C_RATEMCS4:
+	case DESC92C_RATEMCS8:
+	case DESC92C_RATEMCS12:
+		shift = 0;
+		break;
+	case DESC92C_RATE2M:
+	case DESC92C_RATE9M:
+	case DESC92C_RATE36M:
+	case DESC92C_RATEMCS1:
+	case DESC92C_RATEMCS5:
+	case DESC92C_RATEMCS9:
+	case DESC92C_RATEMCS13:
+		shift = 8;
+		break;
+	case DESC92C_RATE5_5M:
+	case DESC92C_RATE12M:
+	case DESC92C_RATE48M:
+	case DESC92C_RATEMCS2:
+	case DESC92C_RATEMCS6:
+	case DESC92C_RATEMCS10:
+	case DESC92C_RATEMCS14:
+		shift = 16;
+		break;
+	case DESC92C_RATE11M:
+	case DESC92C_RATE18M:
+	case DESC92C_RATE54M:
+	case DESC92C_RATEMCS3:
+	case DESC92C_RATEMCS7:
+	case DESC92C_RATEMCS11:
+	case DESC92C_RATEMCS15:
+		shift = 24;
+		break;
+	default:
+		RT_ASSERT(true, "Rate_Section is Illegal\n");
+		break;
+	}
+
+	diff = (u8)(rtlphy->tx_power_by_rate_offset[band][rf][tx_num][sec] >>
+		    shift) & 0xff;
+
+	return	diff;
+}
+
+static u8 _rtl92ee_get_txpower_index(struct ieee80211_hw *hw,
+				     enum radio_path rfpath, u8 rate,
+				     u8 bw, u8 channel)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
+	u8 index = (channel - 1);
+	u8 tx_power = 0;
+	u8 diff = 0;
+
+	if (channel < 1 || channel > 14) {
+		index = 0;
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_DMESG,
+			 "Illegal channel!!\n");
+	}
+
+	if (IS_CCK_RATE(rate))
+		tx_power = rtlefuse->txpwrlevel_cck[rfpath][index];
+	else if (DESC92C_RATE6M <= rate)
+		tx_power = rtlefuse->txpwrlevel_ht40_1s[rfpath][index];
+
+	/* OFDM-1T*/
+	if (DESC92C_RATE6M <= rate && rate <= DESC92C_RATE54M &&
+	    !IS_CCK_RATE(rate))
+		tx_power += rtlefuse->txpwr_legacyhtdiff[rfpath][TX_1S];
+
+	/* BW20-1S, BW20-2S */
+	if (bw == HT_CHANNEL_WIDTH_20) {
+		if (DESC92C_RATEMCS0 <= rate && rate <= DESC92C_RATEMCS15)
+			tx_power += rtlefuse->txpwr_ht20diff[rfpath][TX_1S];
+		if (DESC92C_RATEMCS8 <= rate && rate <= DESC92C_RATEMCS15)
+			tx_power += rtlefuse->txpwr_ht20diff[rfpath][TX_2S];
+	} else if (bw == HT_CHANNEL_WIDTH_20_40) {/* BW40-1S, BW40-2S */
+		if (DESC92C_RATEMCS0 <= rate && rate <= DESC92C_RATEMCS15)
+			tx_power += rtlefuse->txpwr_ht40diff[rfpath][TX_1S];
+		if (DESC92C_RATEMCS8 <= rate && rate <= DESC92C_RATEMCS15)
+			tx_power += rtlefuse->txpwr_ht40diff[rfpath][TX_2S];
+	}
+
+	if (rtlefuse->eeprom_regulatory != 2)
+		diff = _rtl92ee_get_txpower_by_rate(hw, BAND_ON_2_4G,
+						    rfpath, rate);
+
+	tx_power += diff;
+
+	if (tx_power > MAX_POWER_INDEX)
+		tx_power = MAX_POWER_INDEX;
+
+	return tx_power;
+}
+
+static void _rtl92ee_set_txpower_index(struct ieee80211_hw *hw, u8 pwr_idx,
+				       enum radio_path rfpath, u8 rate)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (rfpath == RF90_PATH_A) {
+		switch (rate) {
+		case DESC92C_RATE1M:
+			rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE2M:
+			rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE5_5M:
+			rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE11M:
+			rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE3,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE6M:
+			rtl_set_bbreg(hw, RTXAGC_A_RATE18_06, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE9M:
+			rtl_set_bbreg(hw, RTXAGC_A_RATE18_06, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE12M:
+			rtl_set_bbreg(hw, RTXAGC_A_RATE18_06, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE18M:
+			rtl_set_bbreg(hw, RTXAGC_A_RATE18_06, MASKBYTE3,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE24M:
+			rtl_set_bbreg(hw, RTXAGC_A_RATE54_24, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE36M:
+			rtl_set_bbreg(hw, RTXAGC_A_RATE54_24, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE48M:
+			rtl_set_bbreg(hw, RTXAGC_A_RATE54_24, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE54M:
+			rtl_set_bbreg(hw, RTXAGC_A_RATE54_24, MASKBYTE3,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS0:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS1:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS2:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS3:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00, MASKBYTE3,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS4:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS5:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS6:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS7:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04, MASKBYTE3,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS8:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS9:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS10:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS11:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08, MASKBYTE3,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS12:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS13:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS14:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS15:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12, MASKBYTE3,
+				      pwr_idx);
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+				 "Invalid Rate!!\n");
+			break;
+		}
+	} else if (rfpath == RF90_PATH_B) {
+		switch (rate) {
+		case DESC92C_RATE1M:
+			rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE2M:
+			rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE5_5M:
+			rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, MASKBYTE3,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE11M:
+			rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE6M:
+			rtl_set_bbreg(hw, RTXAGC_B_RATE18_06, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE9M:
+			rtl_set_bbreg(hw, RTXAGC_B_RATE18_06, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE12M:
+			rtl_set_bbreg(hw, RTXAGC_B_RATE18_06, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE18M:
+			rtl_set_bbreg(hw, RTXAGC_B_RATE18_06, MASKBYTE3,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE24M:
+			rtl_set_bbreg(hw, RTXAGC_B_RATE54_24, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE36M:
+			rtl_set_bbreg(hw, RTXAGC_B_RATE54_24, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE48M:
+			rtl_set_bbreg(hw, RTXAGC_B_RATE54_24, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATE54M:
+			rtl_set_bbreg(hw, RTXAGC_B_RATE54_24, MASKBYTE3,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS0:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS1:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS2:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS3:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00, MASKBYTE3,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS4:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS5:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS6:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS7:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04, MASKBYTE3,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS8:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS9:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS10:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS11:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08, MASKBYTE3,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS12:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12, MASKBYTE0,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS13:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12, MASKBYTE1,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS14:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12, MASKBYTE2,
+				      pwr_idx);
+			break;
+		case DESC92C_RATEMCS15:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12, MASKBYTE3,
+				      pwr_idx);
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+				 "Invalid Rate!!\n");
+			break;
+		}
+	} else {
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Invalid RFPath!!\n");
+	}
+}
+
+static void phy_set_txpower_index_by_rate_array(struct ieee80211_hw *hw,
+						enum radio_path rfpath, u8 bw,
+						u8 channel, u8 *rates, u8 size)
+{
+	u8 i;
+	u8 power_index;
+
+	for (i = 0; i < size; i++) {
+		power_index = _rtl92ee_get_txpower_index(hw, rfpath, rates[i],
+							 bw, channel);
+		_rtl92ee_set_txpower_index(hw, power_index, rfpath, rates[i]);
+	}
+}
+
+static void phy_set_txpower_index_by_rate_section(struct ieee80211_hw *hw,
+						  enum radio_path rfpath,
+						  u8 channel,
+						  enum rate_section section)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	if (section == CCK) {
+		u8 cck_rates[] = {DESC92C_RATE1M, DESC92C_RATE2M,
+				  DESC92C_RATE5_5M, DESC92C_RATE11M};
+		if (rtlhal->current_bandtype == BAND_ON_2_4G)
+			phy_set_txpower_index_by_rate_array(hw, rfpath,
+							rtlphy->current_chan_bw,
+							channel, cck_rates, 4);
+	} else if (section == OFDM) {
+		u8 ofdm_rates[] = {DESC92C_RATE6M, DESC92C_RATE9M,
+				   DESC92C_RATE12M, DESC92C_RATE18M,
+				   DESC92C_RATE24M, DESC92C_RATE36M,
+				   DESC92C_RATE48M, DESC92C_RATE54M};
+		phy_set_txpower_index_by_rate_array(hw, rfpath,
+						    rtlphy->current_chan_bw,
+						    channel, ofdm_rates, 8);
+	} else if (section == HT_MCS0_MCS7) {
+		u8 ht_rates1t[]  = {DESC92C_RATEMCS0, DESC92C_RATEMCS1,
+				    DESC92C_RATEMCS2, DESC92C_RATEMCS3,
+				    DESC92C_RATEMCS4, DESC92C_RATEMCS5,
+				    DESC92C_RATEMCS6, DESC92C_RATEMCS7};
+		phy_set_txpower_index_by_rate_array(hw, rfpath,
+						    rtlphy->current_chan_bw,
+						    channel, ht_rates1t, 8);
+	} else if (section == HT_MCS8_MCS15) {
+		u8 ht_rates2t[]  = {DESC92C_RATEMCS8, DESC92C_RATEMCS9,
+				    DESC92C_RATEMCS10, DESC92C_RATEMCS11,
+				    DESC92C_RATEMCS12, DESC92C_RATEMCS13,
+				    DESC92C_RATEMCS14, DESC92C_RATEMCS15};
+		phy_set_txpower_index_by_rate_array(hw, rfpath,
+						    rtlphy->current_chan_bw,
+						    channel, ht_rates2t, 8);
+	} else
+		RT_TRACE(rtlpriv, FPHY, PHY_TXPWR,
+			 "Invalid RateSection %d\n", section);
+}
+
+void rtl92ee_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
+{
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtl_priv(hw)->phy;
+	enum radio_path rfpath;
+
+	if (!rtlefuse->txpwr_fromeprom)
+		return;
+	for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
+	     rfpath++) {
+		phy_set_txpower_index_by_rate_section(hw, rfpath,
+						      channel, CCK);
+		phy_set_txpower_index_by_rate_section(hw, rfpath,
+						      channel, OFDM);
+		phy_set_txpower_index_by_rate_section(hw, rfpath,
+						      channel,
+						      HT_MCS0_MCS7);
+
+		if (rtlphy->num_total_rfpath >= 2)
+			phy_set_txpower_index_by_rate_section(hw,
+							      rfpath, channel,
+							      HT_MCS8_MCS15);
+	}
+}
+
+static long _rtl92ee_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+					  enum wireless_mode wirelessmode,
+					  u8 txpwridx)
+{
+	long offset;
+	long pwrout_dbm;
+
+	switch (wirelessmode) {
+	case WIRELESS_MODE_B:
+		offset = -7;
+		break;
+	case WIRELESS_MODE_G:
+	case WIRELESS_MODE_N_24G:
+		offset = -8;
+		break;
+	default:
+		offset = -8;
+		break;
+	}
+	pwrout_dbm = txpwridx / 2 + offset;
+	return pwrout_dbm;
+}
+
+void rtl92ee_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	enum io_type iotype;
+
+	if (!is_hal_stop(rtlhal)) {
+		switch (operation) {
+		case SCAN_OPT_BACKUP_BAND0:
+			iotype = IO_CMD_PAUSE_BAND0_DM_BY_SCAN;
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD,
+						      (u8 *)&iotype);
+
+			break;
+		case SCAN_OPT_RESTORE:
+			iotype = IO_CMD_RESUME_DM_BY_SCAN;
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD,
+						      (u8 *)&iotype);
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "Unknown Scan Backup operation.\n");
+			break;
+		}
+	}
+}
+
+void rtl92ee_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	u8 reg_bw_opmode;
+	u8 reg_prsr_rsc;
+
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+		 "Switch to %s bandwidth\n",
+		  rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+		  "20MHz" : "40MHz");
+
+	if (is_hal_stop(rtlhal)) {
+		rtlphy->set_bwmode_inprogress = false;
+		return;
+	}
+
+	reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE);
+	reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2);
+
+	switch (rtlphy->current_chan_bw) {
+	case HT_CHANNEL_WIDTH_20:
+		reg_bw_opmode |= BW_OPMODE_20MHZ;
+		rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+		break;
+	case HT_CHANNEL_WIDTH_20_40:
+		reg_bw_opmode &= ~BW_OPMODE_20MHZ;
+		rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+		reg_prsr_rsc = (reg_prsr_rsc & 0x90) |
+			       (mac->cur_40_prime_sc << 5);
+		rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+		break;
+	}
+
+	switch (rtlphy->current_chan_bw) {
+	case HT_CHANNEL_WIDTH_20:
+		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
+		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
+		rtl_set_bbreg(hw, ROFDM0_TXPSEUDONOISEWGT,
+			      (BIT(31) | BIT(30)), 0);
+		break;
+	case HT_CHANNEL_WIDTH_20_40:
+		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
+		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+		rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
+			      (mac->cur_40_prime_sc >> 1));
+		rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00,
+			      mac->cur_40_prime_sc);
+
+		rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
+			      (mac->cur_40_prime_sc ==
+			       HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+		break;
+	}
+	rtl92ee_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+	rtlphy->set_bwmode_inprogress = false;
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, "\n");
+}
+
+void rtl92ee_phy_set_bw_mode(struct ieee80211_hw *hw,
+			     enum nl80211_channel_type ch_type)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 tmp_bw = rtlphy->current_chan_bw;
+
+	if (rtlphy->set_bwmode_inprogress)
+		return;
+	rtlphy->set_bwmode_inprogress = true;
+	if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+		rtl92ee_phy_set_bw_mode_callback(hw);
+	} else {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "false driver sleep or unload\n");
+		rtlphy->set_bwmode_inprogress = false;
+		rtlphy->current_chan_bw = tmp_bw;
+	}
+}
+
+void rtl92ee_phy_sw_chnl_callback(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u32 delay;
+
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+		 "switch to channel%d\n", rtlphy->current_channel);
+	if (is_hal_stop(rtlhal))
+		return;
+	do {
+		if (!rtlphy->sw_chnl_inprogress)
+			break;
+		if (!_rtl92ee_phy_sw_chnl_step_by_step
+		    (hw, rtlphy->current_channel, &rtlphy->sw_chnl_stage,
+		     &rtlphy->sw_chnl_step, &delay)) {
+			if (delay > 0)
+				mdelay(delay);
+			else
+				continue;
+		} else {
+			rtlphy->sw_chnl_inprogress = false;
+		}
+		break;
+	} while (true);
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "\n");
+}
+
+u8 rtl92ee_phy_sw_chnl(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+	if (rtlphy->sw_chnl_inprogress)
+		return 0;
+	if (rtlphy->set_bwmode_inprogress)
+		return 0;
+	RT_ASSERT((rtlphy->current_channel <= 14),
+		  "WIRELESS_MODE_G but channel>14");
+	rtlphy->sw_chnl_inprogress = true;
+	rtlphy->sw_chnl_stage = 0;
+	rtlphy->sw_chnl_step = 0;
+	if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+		rtl92ee_phy_sw_chnl_callback(hw);
+		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+			 "sw_chnl_inprogress false schdule workitem current channel %d\n",
+			 rtlphy->current_channel);
+		rtlphy->sw_chnl_inprogress = false;
+	} else {
+		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+			 "sw_chnl_inprogress false driver sleep or unload\n");
+		rtlphy->sw_chnl_inprogress = false;
+	}
+	return 1;
+}
+
+static bool _rtl92ee_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+					      u8 channel, u8 *stage, u8 *step,
+					      u32 *delay)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
+	u32 precommoncmdcnt;
+	struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
+	u32 postcommoncmdcnt;
+	struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT];
+	u32 rfdependcmdcnt;
+	struct swchnlcmd *currentcmd = NULL;
+	u8 rfpath;
+	u8 num_total_rfpath = rtlphy->num_total_rfpath;
+
+	precommoncmdcnt = 0;
+	_rtl92ee_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+					  MAX_PRECMD_CNT,
+					  CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0);
+	_rtl92ee_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+					  MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+
+	postcommoncmdcnt = 0;
+
+	_rtl92ee_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
+					  MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
+
+	rfdependcmdcnt = 0;
+
+	RT_ASSERT((channel >= 1 && channel <= 14),
+		  "illegal channel for Zebra: %d\n", channel);
+
+	_rtl92ee_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+					  MAX_RFDEPENDCMD_CNT,
+					  CMDID_RF_WRITEREG,
+					  RF_CHNLBW, channel, 10);
+
+	_rtl92ee_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+					  MAX_RFDEPENDCMD_CNT, CMDID_END,
+					  0, 0, 0);
+
+	do {
+		switch (*stage) {
+		case 0:
+			currentcmd = &precommoncmd[*step];
+			break;
+		case 1:
+			currentcmd = &rfdependcmd[*step];
+			break;
+		case 2:
+			currentcmd = &postcommoncmd[*step];
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "Invalid 'stage' = %d, Check it!\n" , *stage);
+			return true;
+		}
+
+		if (currentcmd->cmdid == CMDID_END) {
+			if ((*stage) == 2)
+				return true;
+			(*stage)++;
+			(*step) = 0;
+			continue;
+		}
+
+		switch (currentcmd->cmdid) {
+		case CMDID_SET_TXPOWEROWER_LEVEL:
+			rtl92ee_phy_set_txpower_level(hw, channel);
+			break;
+		case CMDID_WRITEPORT_ULONG:
+			rtl_write_dword(rtlpriv, currentcmd->para1,
+					currentcmd->para2);
+			break;
+		case CMDID_WRITEPORT_USHORT:
+			rtl_write_word(rtlpriv, currentcmd->para1,
+				       (u16)currentcmd->para2);
+			break;
+		case CMDID_WRITEPORT_UCHAR:
+			rtl_write_byte(rtlpriv, currentcmd->para1,
+				       (u8)currentcmd->para2);
+			break;
+		case CMDID_RF_WRITEREG:
+			for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
+				rtlphy->rfreg_chnlval[rfpath] =
+					((rtlphy->rfreg_chnlval[rfpath] &
+					  0xfffff00) | currentcmd->para2);
+
+				rtl_set_rfreg(hw, (enum radio_path)rfpath,
+					      currentcmd->para1,
+					      0x3ff,
+					      rtlphy->rfreg_chnlval[rfpath]);
+			}
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
+			break;
+		}
+
+		break;
+	} while (true);
+
+	(*delay) = currentcmd->msdelay;
+	(*step)++;
+	return false;
+}
+
+static bool _rtl92ee_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+					      u32 cmdtableidx, u32 cmdtablesz,
+					      enum swchnlcmd_id cmdid,
+					      u32 para1, u32 para2, u32 msdelay)
+{
+	struct swchnlcmd *pcmd;
+
+	if (cmdtable == NULL) {
+		RT_ASSERT(false, "cmdtable cannot be NULL.\n");
+		return false;
+	}
+
+	if (cmdtableidx >= cmdtablesz)
+		return false;
+
+	pcmd = cmdtable + cmdtableidx;
+	pcmd->cmdid = cmdid;
+	pcmd->para1 = para1;
+	pcmd->para2 = para2;
+	pcmd->msdelay = msdelay;
+	return true;
+}
+
+static u8 _rtl92ee_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
+{
+	u32 reg_eac, reg_e94, reg_e9c;
+	u8 result = 0x00;
+	/* path-A IQK setting */
+	/* PA/PAD controlled by 0x0 */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0xdf, RFREG_OFFSET_MASK, 0x180);
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x18008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RTX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+
+	rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x82140303);
+	rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x68160000);
+
+	/*LO calibration setting*/
+	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x00462911);
+
+	/*One shot, path A LOK & IQK*/
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+	mdelay(IQK_DELAY_TIME);
+
+	reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
+	reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
+	reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
+
+	if (!(reg_eac & BIT(28)) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+	    (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
+		result |= 0x01;
+	else
+		return result;
+
+	return result;
+}
+
+static u8 _rtl92ee_phy_path_b_iqk(struct ieee80211_hw *hw)
+{
+	u32 reg_eac, reg_eb4, reg_ebc;
+	u8 result = 0x00;
+
+	/* PA/PAD controlled by 0x0 */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	rtl_set_rfreg(hw, RF90_PATH_B, 0xdf, RFREG_OFFSET_MASK, 0x180);
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000);
+	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+
+	rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RTX_IQK_TONE_B, MASKDWORD, 0x18008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+
+	rtl_set_bbreg(hw, RTX_IQK_PI_B, MASKDWORD, 0x821403e2);
+	rtl_set_bbreg(hw, RRX_IQK_PI_B, MASKDWORD, 0x68160000);
+
+	/* LO calibration setting */
+	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x00462911);
+
+	/*One shot, path B LOK & IQK*/
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xfa000000);
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+	mdelay(IQK_DELAY_TIME);
+
+	reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
+	reg_eb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD);
+	reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD);
+
+	if (!(reg_eac & BIT(31)) &&
+	    (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) &&
+	    (((reg_ebc & 0x03FF0000) >> 16) != 0x42))
+		result |= 0x01;
+	else
+		return result;
+
+	return result;
+}
+
+static u8 _rtl92ee_phy_path_a_rx_iqk(struct ieee80211_hw *hw, bool config_pathb)
+{
+	u32 reg_eac, reg_e94, reg_e9c, reg_ea4 , u32temp;
+	u8 result = 0x00;
+
+	/*Get TXIMR Setting*/
+	/*Modify RX IQK mode table*/
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf117b);
+
+	/*PA/PAD control by 0x56, and set = 0x0*/
+	rtl_set_rfreg(hw, RF90_PATH_A, 0xdf, RFREG_OFFSET_MASK, 0x980);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0x56, RFREG_OFFSET_MASK, 0x51000);
+
+	/*enter IQK mode*/
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	/*IQK Setting*/
+	rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, 0x01007c00);
+	rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+
+	/*path a IQK setting*/
+	rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x18008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RTX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+
+	rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x82160c1f);
+	rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x68160c1f);
+
+	/*LO calibration Setting*/
+	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a911);
+
+	/*one shot,path A LOK & iqk*/
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xfa000000);
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+	mdelay(IQK_DELAY_TIME);
+
+	/* Check failed */
+	reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+	reg_e94 = rtl_get_bbreg(hw, RTX_POWER_BEFORE_IQK_A, MASKDWORD);
+	reg_e9c = rtl_get_bbreg(hw, RTX_POWER_AFTER_IQK_A, MASKDWORD);
+
+	if (!(reg_eac & BIT(28)) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+	    (((reg_e9c & 0x03FF0000) >> 16) != 0x42)) {
+		result |= 0x01;
+	} else {
+		/*	PA/PAD controlled by 0x0 */
+		rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+		rtl_set_rfreg(hw, RF90_PATH_A, 0xdf, RFREG_OFFSET_MASK, 0x180);
+		return result;
+	}
+
+	u32temp = 0x80007C00 | (reg_e94 & 0x3FF0000)  |
+		  ((reg_e9c & 0x3FF0000) >> 16);
+	rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, u32temp);
+	/*RX IQK*/
+	/*Modify RX IQK mode table*/
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
+
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7ffa);
+
+	/*PA/PAD control by 0x56, and set = 0x0*/
+	rtl_set_rfreg(hw, RF90_PATH_A, 0xdf, RFREG_OFFSET_MASK, 0x980);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0x56, RFREG_OFFSET_MASK, 0x51000);
+
+	/*enter IQK mode*/
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	/*IQK Setting*/
+	rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+
+	/*path a IQK setting*/
+	rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x18008c1c);
+	rtl_set_bbreg(hw, RTX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+
+	rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x82160c1f);
+	rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x28160c1f);
+
+	/*LO calibration Setting*/
+	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a891);
+	/*one shot,path A LOK & iqk*/
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xfa000000);
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+	mdelay(IQK_DELAY_TIME);
+	/*Check failed*/
+	reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+	reg_ea4 = rtl_get_bbreg(hw, RRX_POWER_BEFORE_IQK_A_2, MASKDWORD);
+
+	/*PA/PAD controlled by 0x0*/
+	/*leave IQK mode*/
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0xdf, RFREG_OFFSET_MASK, 0x180);
+	/*if Tx is OK, check whether Rx is OK*/
+	if (!(reg_eac & BIT(27)) &&
+	    (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) &&
+	    (((reg_eac & 0x03FF0000) >> 16) != 0x36))
+		result |= 0x02;
+
+	return result;
+}
+
+static u8 _rtl92ee_phy_path_b_rx_iqk(struct ieee80211_hw *hw, bool config_pathb)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 reg_eac, reg_eb4, reg_ebc, reg_ecc, reg_ec4, u32temp;
+	u8 result = 0x00;
+
+	/*Get TXIMR Setting*/
+	/*Modify RX IQK mode table*/
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+
+	rtl_set_rfreg(hw, RF90_PATH_B, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
+	rtl_set_rfreg(hw, RF90_PATH_B, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+	rtl_set_rfreg(hw, RF90_PATH_B, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f);
+	rtl_set_rfreg(hw, RF90_PATH_B, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf117b);
+
+	/*PA/PAD all off*/
+	rtl_set_rfreg(hw, RF90_PATH_B, 0xdf, RFREG_OFFSET_MASK, 0x980);
+	rtl_set_rfreg(hw, RF90_PATH_B, 0x56, RFREG_OFFSET_MASK, 0x51000);
+
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	/*IQK Setting*/
+	rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, 0x01007c00);
+	rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+
+	/*path a IQK setting*/
+	rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RTX_IQK_TONE_B, MASKDWORD, 0x18008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+
+	rtl_set_bbreg(hw, RTX_IQK_PI_B, MASKDWORD, 0x82160c1f);
+	rtl_set_bbreg(hw, RRX_IQK_PI_B, MASKDWORD, 0x68160c1f);
+
+	/*LO calibration Setting*/
+	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a911);
+
+	/*one shot,path A LOK & iqk*/
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xfa000000);
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+	mdelay(IQK_DELAY_TIME);
+
+	/* Check failed */
+	reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+	reg_eb4 = rtl_get_bbreg(hw, RTX_POWER_BEFORE_IQK_B, MASKDWORD);
+	reg_ebc = rtl_get_bbreg(hw, RTX_POWER_AFTER_IQK_B, MASKDWORD);
+
+	if (!(reg_eac & BIT(31)) &&
+	    (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) &&
+	    (((reg_ebc & 0x03FF0000) >> 16) != 0x42)) {
+		result |= 0x01;
+	} else {
+		/*	PA/PAD controlled by 0x0 */
+		rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+		rtl_set_rfreg(hw, RF90_PATH_B, 0xdf, RFREG_OFFSET_MASK, 0x180);
+		return result;
+	}
+
+	u32temp = 0x80007C00 | (reg_eb4 & 0x3FF0000) |
+		  ((reg_ebc & 0x3FF0000) >> 16);
+	rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, u32temp);
+	/*RX IQK*/
+	/*Modify RX IQK mode table*/
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	rtl_set_rfreg(hw, RF90_PATH_B, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
+
+	rtl_set_rfreg(hw, RF90_PATH_B, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+	rtl_set_rfreg(hw, RF90_PATH_B, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f);
+	rtl_set_rfreg(hw, RF90_PATH_B, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7ffa);
+
+	/*PA/PAD all off*/
+	rtl_set_rfreg(hw, RF90_PATH_B, 0xdf, RFREG_OFFSET_MASK, 0x980);
+	rtl_set_rfreg(hw, RF90_PATH_B, 0x56, RFREG_OFFSET_MASK, 0x51000);
+
+	/*enter IQK mode*/
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	/*IQK Setting*/
+	rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+
+	/*path b IQK setting*/
+	rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RTX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_B, MASKDWORD, 0x18008c1c);
+
+	rtl_set_bbreg(hw, RTX_IQK_PI_B, MASKDWORD, 0x82160c1f);
+	rtl_set_bbreg(hw, RRX_IQK_PI_B, MASKDWORD, 0x28160c1f);
+
+	/*LO calibration Setting*/
+	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a891);
+	/*one shot,path A LOK & iqk*/
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xfa000000);
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+	mdelay(IQK_DELAY_TIME);
+	/*Check failed*/
+	reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+	reg_ec4 = rtl_get_bbreg(hw, RRX_POWER_BEFORE_IQK_B_2, MASKDWORD);
+	reg_ecc = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_B_2, MASKDWORD);
+	/*PA/PAD controlled by 0x0*/
+	/*leave IQK mode*/
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	rtl_set_rfreg(hw, RF90_PATH_B, 0xdf, RFREG_OFFSET_MASK, 0x180);
+	/*if Tx is OK, check whether Rx is OK*/
+	if (!(reg_eac & BIT(30)) &&
+	    (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) &&
+	    (((reg_ecc & 0x03FF0000) >> 16) != 0x36))
+		result |= 0x02;
+	else
+		RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD, "Path B Rx IQK fail!!\n");
+
+	return result;
+}
+
+static void _rtl92ee_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw,
+						bool b_iqk_ok, long result[][8],
+						u8 final_candidate,
+						bool btxonly)
+{
+	u32 oldval_0, x, tx0_a, reg;
+	long y, tx0_c;
+
+	if (final_candidate == 0xFF) {
+		return;
+	} else if (b_iqk_ok) {
+		oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+					  MASKDWORD) >> 22) & 0x3FF;
+		x = result[final_candidate][0];
+		if ((x & 0x00000200) != 0)
+			x = x | 0xFFFFFC00;
+		tx0_a = (x * oldval_0) >> 8;
+		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a);
+		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(31),
+			      ((x * oldval_0 >> 7) & 0x1));
+		y = result[final_candidate][1];
+		if ((y & 0x00000200) != 0)
+			y = y | 0xFFFFFC00;
+		tx0_c = (y * oldval_0) >> 8;
+		rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000,
+			      ((tx0_c & 0x3C0) >> 6));
+		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000,
+			      (tx0_c & 0x3F));
+		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29),
+			      ((y * oldval_0 >> 7) & 0x1));
+
+		if (btxonly)
+			return;
+
+		reg = result[final_candidate][2];
+		rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg);
+
+		reg = result[final_candidate][3] & 0x3F;
+		rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg);
+
+		reg = (result[final_candidate][3] >> 6) & 0xF;
+		rtl_set_bbreg(hw, ROFDM0_RXIQEXTANTA, 0xF0000000, reg);
+	}
+}
+
+static void _rtl92ee_phy_path_b_fill_iqk_matrix(struct ieee80211_hw *hw,
+						bool b_iqk_ok, long result[][8],
+						u8 final_candidate,
+						bool btxonly)
+{
+	u32 oldval_1, x, tx1_a, reg;
+	long y, tx1_c;
+
+	if (final_candidate == 0xFF) {
+		return;
+	} else if (b_iqk_ok) {
+		oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+					  MASKDWORD) >> 22) & 0x3FF;
+		x = result[final_candidate][4];
+		if ((x & 0x00000200) != 0)
+			x = x | 0xFFFFFC00;
+		tx1_a = (x * oldval_1) >> 8;
+		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx1_a);
+		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(27),
+			      ((x * oldval_1 >> 7) & 0x1));
+		y = result[final_candidate][5];
+		if ((y & 0x00000200) != 0)
+			y = y | 0xFFFFFC00;
+		tx1_c = (y * oldval_1) >> 8;
+		rtl_set_bbreg(hw, ROFDM0_XDTXAFE, 0xF0000000,
+			      ((tx1_c & 0x3C0) >> 6));
+		rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, 0x003F0000,
+			      (tx1_c & 0x3F));
+		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(25),
+			      ((y * oldval_1 >> 7) & 0x1));
+
+		if (btxonly)
+			return;
+
+		reg = result[final_candidate][6];
+		rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, 0x3FF, reg);
+
+		reg = result[final_candidate][7] & 0x3F;
+		rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, 0xFC00, reg);
+
+		reg = (result[final_candidate][7] >> 6) & 0xF;
+		rtl_set_bbreg(hw, ROFDM0_AGCRSSITABLE, 0xF0000000, reg);
+	}
+}
+
+static void _rtl92ee_phy_save_adda_registers(struct ieee80211_hw *hw,
+					     u32 *addareg, u32 *addabackup,
+					     u32 registernum)
+{
+	u32 i;
+
+	for (i = 0; i < registernum; i++)
+		addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD);
+}
+
+static void _rtl92ee_phy_save_mac_registers(struct ieee80211_hw *hw,
+					    u32 *macreg, u32 *macbackup)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 i;
+
+	for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+		macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]);
+
+	macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]);
+}
+
+static void _rtl92ee_phy_reload_adda_registers(struct ieee80211_hw *hw,
+					       u32 *addareg, u32 *addabackup,
+					       u32 regiesternum)
+{
+	u32 i;
+
+	for (i = 0; i < regiesternum; i++)
+		rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]);
+}
+
+static void _rtl92ee_phy_reload_mac_registers(struct ieee80211_hw *hw,
+					      u32 *macreg, u32 *macbackup)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 i;
+
+	for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+		rtl_write_byte(rtlpriv, macreg[i], (u8)macbackup[i]);
+	rtl_write_dword(rtlpriv, macreg[i], macbackup[i]);
+}
+
+static void _rtl92ee_phy_path_adda_on(struct ieee80211_hw *hw, u32 *addareg,
+				      bool is_patha_on, bool is2t)
+{
+	u32 pathon;
+	u32 i;
+
+	pathon = is_patha_on ? 0x0fc01616 : 0x0fc01616;
+	if (!is2t) {
+		pathon = 0x0fc01616;
+		rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0fc01616);
+	} else {
+		rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathon);
+	}
+
+	for (i = 1; i < IQK_ADDA_REG_NUM; i++)
+		rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathon);
+}
+
+static void _rtl92ee_phy_mac_setting_calibration(struct ieee80211_hw *hw,
+						 u32 *macreg, u32 *macbackup)
+{
+	rtl_set_bbreg(hw, 0x520, 0x00ff0000, 0xff);
+}
+
+static void _rtl92ee_phy_path_a_standby(struct ieee80211_hw *hw)
+{
+	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK, 0x10000);
+	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+}
+
+static bool _rtl92ee_phy_simularity_compare(struct ieee80211_hw *hw,
+					    long result[][8], u8 c1, u8 c2)
+{
+	u32 i, j, diff, simularity_bitmap, bound;
+
+	u8 final_candidate[2] = { 0xFF, 0xFF };
+	bool bresult = true/*, is2t = true*/;
+	s32 tmp1, tmp2;
+
+	bound = 8;
+
+	simularity_bitmap = 0;
+
+	for (i = 0; i < bound; i++) {
+		if ((i == 1) || (i == 3) || (i == 5) || (i == 7)) {
+			if ((result[c1][i] & 0x00000200) != 0)
+				tmp1 = result[c1][i] | 0xFFFFFC00;
+			else
+				tmp1 = result[c1][i];
+
+			if ((result[c2][i] & 0x00000200) != 0)
+				tmp2 = result[c2][i] | 0xFFFFFC00;
+			else
+				tmp2 = result[c2][i];
+		} else {
+			tmp1 = result[c1][i];
+			tmp2 = result[c2][i];
+		}
+
+		diff = (tmp1 > tmp2) ? (tmp1 - tmp2) : (tmp2 - tmp1);
+
+		if (diff > MAX_TOLERANCE) {
+			if ((i == 2 || i == 6) && !simularity_bitmap) {
+				if (result[c1][i] + result[c1][i + 1] == 0)
+					final_candidate[(i / 4)] = c2;
+				else if (result[c2][i] + result[c2][i + 1] == 0)
+					final_candidate[(i / 4)] = c1;
+				else
+					simularity_bitmap |= (1 << i);
+			} else {
+				simularity_bitmap |= (1 << i);
+			}
+		}
+	}
+
+	if (simularity_bitmap == 0) {
+		for (i = 0; i < (bound / 4); i++) {
+			if (final_candidate[i] != 0xFF) {
+				for (j = i * 4; j < (i + 1) * 4 - 2; j++)
+					result[3][j] =
+						result[final_candidate[i]][j];
+				bresult = false;
+			}
+		}
+		return bresult;
+	}
+	if (!(simularity_bitmap & 0x03)) {/*path A TX OK*/
+		for (i = 0; i < 2; i++)
+			result[3][i] = result[c1][i];
+	}
+	if (!(simularity_bitmap & 0x0c)) {/*path A RX OK*/
+		for (i = 2; i < 4; i++)
+			result[3][i] = result[c1][i];
+	}
+	if (!(simularity_bitmap & 0x30)) {/*path B TX OK*/
+		for (i = 4; i < 6; i++)
+			result[3][i] = result[c1][i];
+	}
+	if (!(simularity_bitmap & 0xc0)) {/*path B RX OK*/
+		for (i = 6; i < 8; i++)
+			result[3][i] = result[c1][i];
+	}
+	return false;
+}
+
+static void _rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw,
+				      long result[][8], u8 t, bool is2t)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u32 i;
+	u8 patha_ok, pathb_ok;
+	u8 tmp_0xc50 = (u8)rtl_get_bbreg(hw, 0xc50, MASKBYTE0);
+	u8 tmp_0xc58 = (u8)rtl_get_bbreg(hw, 0xc58, MASKBYTE0);
+	u32 adda_reg[IQK_ADDA_REG_NUM] = {
+		0x85c, 0xe6c, 0xe70, 0xe74,
+		0xe78, 0xe7c, 0xe80, 0xe84,
+		0xe88, 0xe8c, 0xed0, 0xed4,
+		0xed8, 0xedc, 0xee0, 0xeec
+	};
+	u32 iqk_mac_reg[IQK_MAC_REG_NUM] = {
+		0x522, 0x550, 0x551, 0x040
+	};
+	u32 iqk_bb_reg[IQK_BB_REG_NUM] = {
+		ROFDM0_TRXPATHENABLE, ROFDM0_TRMUXPAR,
+		RFPGA0_XCD_RFINTERFACESW, 0xb68, 0xb6c,
+		0x870, 0x860,
+		0x864, 0x800
+	};
+	const u32 retrycount = 2;
+
+	if (t == 0) {
+		_rtl92ee_phy_save_adda_registers(hw, adda_reg,
+						 rtlphy->adda_backup,
+						 IQK_ADDA_REG_NUM);
+		_rtl92ee_phy_save_mac_registers(hw, iqk_mac_reg,
+						rtlphy->iqk_mac_backup);
+		_rtl92ee_phy_save_adda_registers(hw, iqk_bb_reg,
+						 rtlphy->iqk_bb_backup,
+						 IQK_BB_REG_NUM);
+	}
+
+	_rtl92ee_phy_path_adda_on(hw, adda_reg, true, is2t);
+
+	/*BB setting*/
+	rtl_set_bbreg(hw, RFPGA0_RFMOD, BIT(24), 0x00);
+	rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKDWORD, 0x03a05600);
+	rtl_set_bbreg(hw, ROFDM0_TRMUXPAR, MASKDWORD, 0x000800e4);
+	rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, MASKDWORD, 0x22208200);
+
+	rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(10), 0x01);
+	rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(26), 0x01);
+	rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BIT(10), 0x01);
+	rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BIT(10), 0x01);
+
+	_rtl92ee_phy_mac_setting_calibration(hw, iqk_mac_reg,
+					     rtlphy->iqk_mac_backup);
+	/* Page B init*/
+	/* IQ calibration setting*/
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+	rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, 0x01007c00);
+	rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+
+	for (i = 0 ; i < retrycount ; i++) {
+		patha_ok = _rtl92ee_phy_path_a_iqk(hw, is2t);
+
+		if (patha_ok == 0x01) {
+			RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
+				 "Path A Tx IQK Success!!\n");
+			result[t][0] = (rtl_get_bbreg(hw,
+						      RTX_POWER_BEFORE_IQK_A,
+						      MASKDWORD) & 0x3FF0000)
+						      >> 16;
+			result[t][1] = (rtl_get_bbreg(hw, RTX_POWER_AFTER_IQK_A,
+						      MASKDWORD) & 0x3FF0000)
+						      >> 16;
+			break;
+		}
+		RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
+			 "Path A Tx IQK Fail!!, ret = 0x%x\n",
+			 patha_ok);
+	}
+
+	for (i = 0 ; i < retrycount ; i++) {
+		patha_ok = _rtl92ee_phy_path_a_rx_iqk(hw, is2t);
+
+		if (patha_ok == 0x03) {
+			RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
+				 "Path A Rx IQK Success!!\n");
+			result[t][2] = (rtl_get_bbreg(hw,
+						      RRX_POWER_BEFORE_IQK_A_2,
+						      MASKDWORD) & 0x3FF0000)
+						      >> 16;
+			result[t][3] = (rtl_get_bbreg(hw,
+						      RRX_POWER_AFTER_IQK_A_2,
+						      MASKDWORD) & 0x3FF0000)
+						      >> 16;
+			break;
+		}
+		RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
+			 "Path A Rx IQK Fail!!, ret = 0x%x\n",
+			  patha_ok);
+	}
+
+	if (0x00 == patha_ok)
+		RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
+			 "Path A IQK failed!!, ret = 0\n");
+	if (is2t) {
+		_rtl92ee_phy_path_a_standby(hw);
+		/* Turn Path B ADDA on */
+		_rtl92ee_phy_path_adda_on(hw, adda_reg, false, is2t);
+
+		/* IQ calibration setting */
+		rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+		rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, 0x01007c00);
+		rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+
+		for (i = 0 ; i < retrycount ; i++) {
+			pathb_ok = _rtl92ee_phy_path_b_iqk(hw);
+			if (pathb_ok == 0x01) {
+				RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
+					 "Path B Tx IQK Success!!\n");
+				result[t][4] = (rtl_get_bbreg(hw,
+							RTX_POWER_BEFORE_IQK_B,
+							MASKDWORD) & 0x3FF0000)
+							>> 16;
+				result[t][5] = (rtl_get_bbreg(hw,
+							RTX_POWER_AFTER_IQK_B,
+							MASKDWORD) & 0x3FF0000)
+							>> 16;
+				break;
+			}
+			RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
+				 "Path B Tx IQK Fail!!, ret = 0x%x\n",
+				 pathb_ok);
+		}
+
+		for (i = 0 ; i < retrycount ; i++) {
+			pathb_ok = _rtl92ee_phy_path_b_rx_iqk(hw, is2t);
+			if (pathb_ok == 0x03) {
+				RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
+					 "Path B Rx IQK Success!!\n");
+				result[t][6] = (rtl_get_bbreg(hw,
+						       RRX_POWER_BEFORE_IQK_B_2,
+						       MASKDWORD) & 0x3FF0000)
+						       >> 16;
+				result[t][7] = (rtl_get_bbreg(hw,
+						       RRX_POWER_AFTER_IQK_B_2,
+						       MASKDWORD) & 0x3FF0000)
+						       >> 16;
+				break;
+			}
+			RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
+				 "Path B Rx IQK Fail!!, ret = 0x%x\n",
+				 pathb_ok);
+		}
+
+		if (0x00 == pathb_ok)
+			RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
+				 "Path B IQK failed!!, ret = 0\n");
+	}
+	/* Back to BB mode, load original value */
+	RT_TRACE(rtlpriv, COMP_RF, DBG_LOUD,
+		 "IQK:Back to BB mode, load original value!\n");
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0);
+
+	if (t != 0) {
+		/* Reload ADDA power saving parameters */
+		_rtl92ee_phy_reload_adda_registers(hw, adda_reg,
+						   rtlphy->adda_backup,
+						   IQK_ADDA_REG_NUM);
+
+		/* Reload MAC parameters */
+		_rtl92ee_phy_reload_mac_registers(hw, iqk_mac_reg,
+						  rtlphy->iqk_mac_backup);
+
+		_rtl92ee_phy_reload_adda_registers(hw, iqk_bb_reg,
+						   rtlphy->iqk_bb_backup,
+						   IQK_BB_REG_NUM);
+
+		/* Restore RX initial gain */
+		rtl_set_bbreg(hw, 0xc50, MASKBYTE0, 0x50);
+		rtl_set_bbreg(hw, 0xc50, MASKBYTE0, tmp_0xc50);
+		if (is2t) {
+			rtl_set_bbreg(hw, 0xc50, MASKBYTE0, 0x50);
+			rtl_set_bbreg(hw, 0xc58, MASKBYTE0, tmp_0xc58);
+		}
+
+		/* load 0xe30 IQC default value */
+		rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x01008c00);
+		rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x01008c00);
+	}
+}
+
+static void _rtl92ee_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
+{
+	u8 tmpreg;
+	u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	tmpreg = rtl_read_byte(rtlpriv, 0xd03);
+
+	if ((tmpreg & 0x70) != 0)
+		rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F);
+	else
+		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+
+	if ((tmpreg & 0x70) != 0) {
+		rf_a_mode = rtl_get_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS);
+
+		if (is2t)
+			rf_b_mode = rtl_get_rfreg(hw, RF90_PATH_B, 0x00,
+						  MASK12BITS);
+
+		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS,
+			      (rf_a_mode & 0x8FFFF) | 0x10000);
+
+		if (is2t)
+			rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS,
+				      (rf_b_mode & 0x8FFFF) | 0x10000);
+	}
+	lc_cal = rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS);
+
+	rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, lc_cal | 0x08000);
+
+	mdelay(100);
+
+	if ((tmpreg & 0x70) != 0) {
+		rtl_write_byte(rtlpriv, 0xd03, tmpreg);
+		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, rf_a_mode);
+
+		if (is2t)
+			rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS,
+				      rf_b_mode);
+	} else {
+		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+	}
+}
+
+static void _rtl92ee_phy_set_rfpath_switch(struct ieee80211_hw *hw,
+					   bool bmain, bool is2t)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+	RT_TRACE(rtlpriv, COMP_INIT , DBG_LOUD , "\n");
+
+	if (is_hal_stop(rtlhal)) {
+		u8 u1btmp;
+
+		u1btmp = rtl_read_byte(rtlpriv, REG_LEDCFG0);
+		rtl_write_byte(rtlpriv, REG_LEDCFG0, u1btmp | BIT(7));
+		rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(13), 0x01);
+	}
+	if (is2t) {
+		if (bmain)
+			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+				      BIT(5) | BIT(6), 0x1);
+		else
+			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+				      BIT(5) | BIT(6), 0x2);
+	} else {
+		rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(8) | BIT(9), 0);
+		rtl_set_bbreg(hw, 0x914, MASKLWORD, 0x0201);
+
+		/* We use the RF definition of MAIN and AUX,
+		 * left antenna and right antenna repectively.
+		 * Default output at AUX.
+		 */
+		if (bmain) {
+			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE,
+				      BIT(14) | BIT(13) | BIT(12), 0);
+			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+				      BIT(5) | BIT(4) | BIT(3), 0);
+			if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+				rtl_set_bbreg(hw, RCONFIG_RAM64x16, BIT(31), 0);
+		} else {
+			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE,
+				      BIT(14) | BIT(13) | BIT(12), 1);
+			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+				      BIT(5) | BIT(4) | BIT(3), 1);
+			if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+				rtl_set_bbreg(hw, RCONFIG_RAM64x16, BIT(31), 1);
+		}
+	}
+}
+
+#undef IQK_ADDA_REG_NUM
+#undef IQK_DELAY_TIME
+
+static u8 rtl92ee_get_rightchnlplace_for_iqk(u8 chnl)
+{
+	u8 channel_all[59] = {
+		1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+		36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58,
+		60, 62, 64, 100, 102, 104, 106, 108, 110, 112,
+		114, 116, 118, 120, 122, 124, 126, 128,	130,
+		132, 134, 136, 138, 140, 149, 151, 153, 155,
+		157, 159, 161, 163, 165
+	};
+	u8 place = chnl;
+
+	if (chnl > 14) {
+		for (place = 14; place < sizeof(channel_all); place++) {
+			if (channel_all[place] == chnl)
+				return place - 13;
+		}
+	}
+
+	return 0;
+}
+
+void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	long result[4][8];
+	u8 i, final_candidate;
+	bool b_patha_ok, b_pathb_ok;
+	long reg_e94, reg_e9c, reg_ea4, reg_eac;
+	long reg_eb4, reg_ebc, reg_ec4, reg_ecc;
+	bool is12simular, is13simular, is23simular;
+	u8 idx;
+	u32 iqk_bb_reg[IQK_BB_REG_NUM] = {
+		ROFDM0_XARXIQIMBALANCE,
+		ROFDM0_XBRXIQIMBALANCE,
+		ROFDM0_ECCATHRESHOLD,
+		ROFDM0_AGCRSSITABLE,
+		ROFDM0_XATXIQIMBALANCE,
+		ROFDM0_XBTXIQIMBALANCE,
+		ROFDM0_XCTXAFE,
+		ROFDM0_XDTXAFE,
+		ROFDM0_RXIQEXTANTA
+	};
+
+	if (b_recovery) {
+		_rtl92ee_phy_reload_adda_registers(hw, iqk_bb_reg,
+						   rtlphy->iqk_bb_backup, 9);
+		return;
+	}
+
+	for (i = 0; i < 8; i++) {
+		result[0][i] = 0;
+		result[1][i] = 0;
+		result[2][i] = 0;
+
+		if ((i == 0) || (i == 2) || (i == 4)  || (i == 6))
+			result[3][i] = 0x100;
+		else
+			result[3][i] = 0;
+	}
+	final_candidate = 0xff;
+	b_patha_ok = false;
+	b_pathb_ok = false;
+	is12simular = false;
+	is23simular = false;
+	is13simular = false;
+	for (i = 0; i < 3; i++) {
+		_rtl92ee_phy_iq_calibrate(hw, result, i, true);
+		if (i == 1) {
+			is12simular = _rtl92ee_phy_simularity_compare(hw,
+								      result,
+								      0, 1);
+			if (is12simular) {
+				final_candidate = 0;
+				break;
+			}
+		}
+
+		if (i == 2) {
+			is13simular = _rtl92ee_phy_simularity_compare(hw,
+								      result,
+								      0, 2);
+			if (is13simular) {
+				final_candidate = 0;
+				break;
+			}
+			is23simular = _rtl92ee_phy_simularity_compare(hw,
+								      result,
+								      1, 2);
+			if (is23simular)
+				final_candidate = 1;
+			else
+				final_candidate = 3;
+		}
+	}
+
+	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 (final_candidate != 0xff) {
+		reg_e94 = result[final_candidate][0];
+		rtlphy->reg_e94 = reg_e94;
+		reg_e9c = result[final_candidate][1];
+		rtlphy->reg_e9c = reg_e9c;
+		reg_ea4 = result[final_candidate][2];
+		reg_eac = result[final_candidate][3];
+		reg_eb4 = result[final_candidate][4];
+		rtlphy->reg_eb4 = reg_eb4;
+		reg_ebc = result[final_candidate][5];
+		rtlphy->reg_ebc = reg_ebc;
+		reg_ec4 = result[final_candidate][6];
+		reg_ecc = result[final_candidate][7];
+		b_patha_ok = true;
+		b_pathb_ok = true;
+	} else {
+		rtlphy->reg_e94 = 0x100;
+		rtlphy->reg_eb4 = 0x100;
+		rtlphy->reg_e9c = 0x0;
+		rtlphy->reg_ebc = 0x0;
+	}
+
+	if (reg_e94 != 0)
+		_rtl92ee_phy_path_a_fill_iqk_matrix(hw, b_patha_ok, result,
+						    final_candidate,
+						    (reg_ea4 == 0));
+
+	_rtl92ee_phy_path_b_fill_iqk_matrix(hw, b_pathb_ok, result,
+					    final_candidate,
+					    (reg_ec4 == 0));
+
+	idx = rtl92ee_get_rightchnlplace_for_iqk(rtlphy->current_channel);
+
+	/* To Fix BSOD when final_candidate is 0xff */
+	if (final_candidate < 4) {
+		for (i = 0; i < IQK_MATRIX_REG_NUM; i++)
+			rtlphy->iqk_matrix[idx].value[0][i] =
+				result[final_candidate][i];
+
+		rtlphy->iqk_matrix[idx].iqk_done = true;
+	}
+	_rtl92ee_phy_save_adda_registers(hw, iqk_bb_reg,
+					 rtlphy->iqk_bb_backup, 9);
+}
+
+void rtl92ee_phy_lc_calibrate(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = &rtlpriv->rtlhal;
+	u32 timeout = 2000, timecount = 0;
+
+	while (rtlpriv->mac80211.act_scanning && timecount < timeout) {
+		udelay(50);
+		timecount += 50;
+	}
+
+	rtlphy->lck_inprogress = true;
+	RTPRINT(rtlpriv, FINIT, INIT_IQK,
+		"LCK:Start!!! currentband %x delay %d ms\n",
+		 rtlhal->current_bandtype, timecount);
+
+	_rtl92ee_phy_lc_calibrate(hw, false);
+
+	rtlphy->lck_inprogress = false;
+}
+
+void rtl92ee_phy_ap_calibrate(struct ieee80211_hw *hw, char delta)
+{
+}
+
+void rtl92ee_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
+{
+	_rtl92ee_phy_set_rfpath_switch(hw, bmain, false);
+}
+
+bool rtl92ee_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	bool postprocessing = false;
+
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+		 "-->IO Cmd(%#x), set_io_inprogress(%d)\n",
+		  iotype, rtlphy->set_io_inprogress);
+	do {
+		switch (iotype) {
+		case IO_CMD_RESUME_DM_BY_SCAN:
+			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+				 "[IO CMD] Resume DM after scan.\n");
+			postprocessing = true;
+			break;
+		case IO_CMD_PAUSE_BAND0_DM_BY_SCAN:
+			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+				 "[IO CMD] Pause DM before scan.\n");
+			postprocessing = true;
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
+			break;
+		}
+	} while (false);
+	if (postprocessing && !rtlphy->set_io_inprogress) {
+		rtlphy->set_io_inprogress = true;
+		rtlphy->current_io_type = iotype;
+	} else {
+		return false;
+	}
+	rtl92ee_phy_set_io(hw);
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "IO Type(%#x)\n", iotype);
+	return true;
+}
+
+static void rtl92ee_phy_set_io(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+		 "--->Cmd(%#x), set_io_inprogress(%d)\n",
+		  rtlphy->current_io_type, rtlphy->set_io_inprogress);
+	switch (rtlphy->current_io_type) {
+	case IO_CMD_RESUME_DM_BY_SCAN:
+		rtl92ee_dm_write_dig(hw, rtlphy->initgain_backup.xaagccore1);
+		rtl92ee_dm_write_cck_cca_thres(hw, rtlphy->initgain_backup.cca);
+		RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE , "no set txpower\n");
+		rtl92ee_phy_set_txpower_level(hw, rtlphy->current_channel);
+		break;
+	case IO_CMD_PAUSE_BAND0_DM_BY_SCAN:
+		/* 8192eebt */
+		rtlphy->initgain_backup.xaagccore1 = dm_dig->cur_igvalue;
+		rtl92ee_dm_write_dig(hw, 0x17);
+		rtlphy->initgain_backup.cca = dm_dig->cur_cck_cca_thres;
+		rtl92ee_dm_write_cck_cca_thres(hw, 0x40);
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
+		break;
+	}
+	rtlphy->set_io_inprogress = false;
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+		 "(%#x)\n", rtlphy->current_io_type);
+}
+
+static void rtl92ee_phy_set_rf_on(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+	/*rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00);*/
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+}
+
+static void _rtl92ee_phy_set_rf_sleep(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
+
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22);
+}
+
+static bool _rtl92ee_phy_set_rf_power_state(struct ieee80211_hw *hw,
+					    enum rf_pwrstate rfpwr_state)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	bool bresult = true;
+	u8 i, queue_id;
+	struct rtl8192_tx_ring *ring = NULL;
+
+	switch (rfpwr_state) {
+	case ERFON:
+		if ((ppsc->rfpwr_state == ERFOFF) &&
+		    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+			bool rtstatus;
+			u32 initializecount = 0;
+
+			do {
+				initializecount++;
+				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+					 "IPS Set eRf nic enable\n");
+				rtstatus = rtl_ps_enable_nic(hw);
+			} while (!rtstatus && (initializecount < 10));
+			RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+		} else {
+			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+				 "Set ERFON sleeping:%d ms\n",
+				  jiffies_to_msecs(jiffies -
+						   ppsc->last_sleep_jiffies));
+			ppsc->last_awake_jiffies = jiffies;
+			rtl92ee_phy_set_rf_on(hw);
+		}
+		if (mac->link_state == MAC80211_LINKED)
+			rtlpriv->cfg->ops->led_control(hw, LED_CTL_LINK);
+		else
+			rtlpriv->cfg->ops->led_control(hw, LED_CTL_NO_LINK);
+		break;
+	case ERFOFF:
+		for (queue_id = 0, i = 0;
+		     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+			ring = &pcipriv->dev.tx_ring[queue_id];
+			if (queue_id == BEACON_QUEUE ||
+			    skb_queue_len(&ring->queue) == 0) {
+				queue_id++;
+				continue;
+			} else {
+				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+					 "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n",
+					 (i + 1), queue_id,
+					 skb_queue_len(&ring->queue));
+
+				udelay(10);
+				i++;
+			}
+			if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+					 "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
+					  MAX_DOZE_WAITING_TIMES_9x,
+					  queue_id,
+					  skb_queue_len(&ring->queue));
+				break;
+			}
+		}
+
+		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
+			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+				 "IPS Set eRf nic disable\n");
+			rtl_ps_disable_nic(hw);
+			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+		} else {
+			if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) {
+				rtlpriv->cfg->ops->led_control(hw,
+							LED_CTL_NO_LINK);
+			} else {
+				rtlpriv->cfg->ops->led_control(hw,
+							LED_CTL_POWER_OFF);
+			}
+		}
+		break;
+	case ERFSLEEP:
+		if (ppsc->rfpwr_state == ERFOFF)
+			break;
+		for (queue_id = 0, i = 0;
+		     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+			ring = &pcipriv->dev.tx_ring[queue_id];
+			if (skb_queue_len(&ring->queue) == 0) {
+				queue_id++;
+				continue;
+			} else {
+				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+					 "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n",
+					 (i + 1), queue_id,
+					 skb_queue_len(&ring->queue));
+				udelay(10);
+				i++;
+			}
+			if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+					 "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
+					  MAX_DOZE_WAITING_TIMES_9x,
+					  queue_id,
+					  skb_queue_len(&ring->queue));
+				break;
+			}
+		}
+		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+			 "Set ERFSLEEP awaked:%d ms\n",
+			  jiffies_to_msecs(jiffies -
+					   ppsc->last_awake_jiffies));
+		ppsc->last_sleep_jiffies = jiffies;
+		_rtl92ee_phy_set_rf_sleep(hw);
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
+		bresult = false;
+		break;
+	}
+	if (bresult)
+		ppsc->rfpwr_state = rfpwr_state;
+	return bresult;
+}
+
+bool rtl92ee_phy_set_rf_power_state(struct ieee80211_hw *hw,
+				    enum rf_pwrstate rfpwr_state)
+{
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+	bool bresult = false;
+
+	if (rfpwr_state == ppsc->rfpwr_state)
+		return bresult;
+	bresult = _rtl92ee_phy_set_rf_power_state(hw, rfpwr_state);
+	return bresult;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/phy.h b/drivers/net/wireless/rtlwifi/rtl8192ee/phy.h
new file mode 100644
index 0000000..c6e97c8
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/phy.h
@@ -0,0 +1,153 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92E_PHY_H__
+#define __RTL92E_PHY_H__
+
+/* MAX_TX_COUNT must always set to 4, otherwise read efuse table sequence
+ * will be wrong.
+ */
+#define MAX_TX_COUNT				4
+#define TX_1S					0
+#define TX_2S					1
+#define TX_3S					2
+#define TX_4S					3
+
+#define MAX_POWER_INDEX				0x3f
+
+#define MAX_PRECMD_CNT				16
+#define MAX_RFDEPENDCMD_CNT			16
+#define MAX_POSTCMD_CNT				16
+
+#define MAX_DOZE_WAITING_TIMES_9x		64
+
+#define RT_CANNOT_IO(hw)			false
+#define HIGHPOWER_RADIOA_ARRAYLEN		22
+
+#define IQK_ADDA_REG_NUM			16
+#define IQK_MAC_REG_NUM				4
+#define IQK_BB_REG_NUM				9
+#define MAX_TOLERANCE				5
+#define	IQK_DELAY_TIME				10
+#define	index_mapping_NUM			15
+
+#define	APK_BB_REG_NUM				5
+#define	APK_AFE_REG_NUM				16
+#define	APK_CURVE_REG_NUM			4
+#define	PATH_NUM				2
+
+#define LOOP_LIMIT				5
+#define MAX_STALL_TIME				50
+#define ANTENNADIVERSITYVALUE			0x80
+#define MAX_TXPWR_IDX_NMODE_92S			63
+#define RESET_CNT_LIMIT				3
+
+#define RF6052_MAX_PATH				2
+
+#define CT_OFFSET_MAC_ADDR			0X16
+
+#define CT_OFFSET_CCK_TX_PWR_IDX		0x5A
+#define CT_OFFSET_HT401S_TX_PWR_IDX		0x60
+#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF	0x66
+#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF		0x69
+#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF		0x6C
+
+#define CT_OFFSET_HT40_MAX_PWR_OFFSET		0x6F
+#define CT_OFFSET_HT20_MAX_PWR_OFFSET		0x72
+
+#define CT_OFFSET_CHANNEL_PLAH			0x75
+#define CT_OFFSET_THERMAL_METER			0x78
+#define CT_OFFSET_RF_OPTION			0x79
+#define CT_OFFSET_VERSION			0x7E
+#define CT_OFFSET_CUSTOMER_ID			0x7F
+
+#define RTL92C_MAX_PATH_NUM			2
+
+enum swchnlcmd_id {
+	CMDID_END,
+	CMDID_SET_TXPOWEROWER_LEVEL,
+	CMDID_BBREGWRITE10,
+	CMDID_WRITEPORT_ULONG,
+	CMDID_WRITEPORT_USHORT,
+	CMDID_WRITEPORT_UCHAR,
+	CMDID_RF_WRITEREG,
+};
+
+struct swchnlcmd {
+	enum swchnlcmd_id cmdid;
+	u32 para1;
+	u32 para2;
+	u32 msdelay;
+};
+
+enum baseband_config_type {
+	BASEBAND_CONFIG_PHY_REG = 0,
+	BASEBAND_CONFIG_AGC_TAB = 1,
+};
+
+enum ant_div_type {
+	NO_ANTDIV = 0xFF,
+	CG_TRX_HW_ANTDIV = 0x01,
+	CGCS_RX_HW_ANTDIV = 0x02,
+	FIXED_HW_ANTDIV = 0x03,
+	CG_TRX_SMART_ANTDIV = 0x04,
+	CGCS_RX_SW_ANTDIV = 0x05,
+};
+
+u32 rtl92ee_phy_query_bb_reg(struct ieee80211_hw *hw,
+			     u32 regaddr, u32 bitmask);
+void rtl92ee_phy_set_bb_reg(struct ieee80211_hw *hw,
+			    u32 regaddr, u32 bitmask, u32 data);
+u32 rtl92ee_phy_query_rf_reg(struct ieee80211_hw *hw,
+			     enum radio_path rfpath, u32 regaddr,
+			     u32 bitmask);
+void rtl92ee_phy_set_rf_reg(struct ieee80211_hw *hw,
+			    enum radio_path rfpath, u32 regaddr,
+			    u32 bitmask, u32 data);
+bool rtl92ee_phy_mac_config(struct ieee80211_hw *hw);
+bool rtl92ee_phy_bb_config(struct ieee80211_hw *hw);
+bool rtl92ee_phy_rf_config(struct ieee80211_hw *hw);
+void rtl92ee_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+void rtl92ee_phy_get_txpower_level(struct ieee80211_hw *hw,
+				   long *powerlevel);
+void rtl92ee_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
+void rtl92ee_phy_scan_operation_backup(struct ieee80211_hw *hw,
+				       u8 operation);
+void rtl92ee_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+void rtl92ee_phy_set_bw_mode(struct ieee80211_hw *hw,
+			     enum nl80211_channel_type ch_type);
+void rtl92ee_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+u8 rtl92ee_phy_sw_chnl(struct ieee80211_hw *hw);
+void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
+void rtl92ee_phy_ap_calibrate(struct ieee80211_hw *hw, char delta);
+void rtl92ee_phy_lc_calibrate(struct ieee80211_hw *hw);
+void rtl92ee_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
+bool rtl92ee_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+					   enum radio_path rfpath);
+bool rtl92ee_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
+bool rtl92ee_phy_set_rf_power_state(struct ieee80211_hw *hw,
+				    enum rf_pwrstate rfpwr_state);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8192ee/pwrseq.c
new file mode 100644
index 0000000..1a701d0
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/pwrseq.c
@@ -0,0 +1,112 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "pwrseq.h"
+
+/* drivers should parse below arrays and do the corresponding actions */
+
+/*3 Power on  Array*/
+struct wlan_pwr_cfg rtl8192E_power_on_flow
+		[RTL8192E_TRANS_CARDEMU_TO_ACT_STEPS +
+		 RTL8192E_TRANS_END_STEPS] = {
+	RTL8192E_TRANS_CARDEMU_TO_ACT
+	RTL8192E_TRANS_END
+};
+
+/*3Radio off GPIO Array */
+struct wlan_pwr_cfg rtl8192E_radio_off_flow
+		[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS
+		+ RTL8192E_TRANS_END_STEPS] = {
+	RTL8192E_TRANS_ACT_TO_CARDEMU
+	RTL8192E_TRANS_END
+};
+
+/*3Card Disable Array*/
+struct wlan_pwr_cfg rtl8192E_card_disable_flow
+		[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8192E_TRANS_END_STEPS] = {
+	RTL8192E_TRANS_ACT_TO_CARDEMU
+	RTL8192E_TRANS_CARDEMU_TO_CARDDIS
+	RTL8192E_TRANS_END
+};
+
+/*3 Card Enable Array*/
+struct wlan_pwr_cfg rtl8192E_card_enable_flow
+		[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8192E_TRANS_END_STEPS] = {
+	RTL8192E_TRANS_CARDDIS_TO_CARDEMU
+	RTL8192E_TRANS_CARDEMU_TO_ACT
+	RTL8192E_TRANS_END
+};
+
+/*3Suspend Array*/
+struct wlan_pwr_cfg rtl8192E_suspend_flow
+		[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8192E_TRANS_CARDEMU_TO_SUS_STEPS +
+		 RTL8192E_TRANS_END_STEPS] = {
+	RTL8192E_TRANS_ACT_TO_CARDEMU
+	RTL8192E_TRANS_CARDEMU_TO_SUS
+	RTL8192E_TRANS_END
+};
+
+/*3 Resume Array*/
+struct wlan_pwr_cfg rtl8192E_resume_flow
+		[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8192E_TRANS_CARDEMU_TO_SUS_STEPS +
+		 RTL8192E_TRANS_END_STEPS] = {
+	RTL8192E_TRANS_SUS_TO_CARDEMU
+	RTL8192E_TRANS_CARDEMU_TO_ACT
+	RTL8192E_TRANS_END
+};
+
+/*3HWPDN Array*/
+struct wlan_pwr_cfg rtl8192E_hwpdn_flow
+		[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8192E_TRANS_END_STEPS] = {
+	RTL8192E_TRANS_ACT_TO_CARDEMU
+	RTL8192E_TRANS_CARDEMU_TO_PDN
+	RTL8192E_TRANS_END
+};
+
+/*3 Enter LPS */
+struct wlan_pwr_cfg rtl8192E_enter_lps_flow
+		[RTL8192E_TRANS_ACT_TO_LPS_STEPS +
+		 RTL8192E_TRANS_END_STEPS] = {
+	/*FW behavior*/
+	RTL8192E_TRANS_ACT_TO_LPS
+	RTL8192E_TRANS_END
+};
+
+/*3 Leave LPS */
+struct wlan_pwr_cfg rtl8192E_leave_lps_flow
+		[RTL8192E_TRANS_LPS_TO_ACT_STEPS +
+		 RTL8192E_TRANS_END_STEPS] = {
+	/*FW behavior*/
+	RTL8192E_TRANS_LPS_TO_ACT
+	RTL8192E_TRANS_END
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8192ee/pwrseq.h
new file mode 100644
index 0000000..781eeaa
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/pwrseq.h
@@ -0,0 +1,340 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92E_PWRSEQ_H__
+#define __RTL92E_PWRSEQ_H__
+
+#include "../pwrseqcmd.h"
+/**
+ *	Check document WM-20110607-Paul-RTL8192E_Power_Architecture-R02.vsd
+ *	There are 6 HW Power States:
+ *	0: POFF--Power Off
+ *	1: PDN--Power Down
+ *	2: CARDEMU--Card Emulation
+ *	3: ACT--Active Mode
+ *	4: LPS--Low Power State
+ *	5: SUS--Suspend
+ *
+ *	The transision from different states are defined below
+ *	TRANS_CARDEMU_TO_ACT
+ *	TRANS_ACT_TO_CARDEMU
+ *	TRANS_CARDEMU_TO_SUS
+ *	TRANS_SUS_TO_CARDEMU
+ *	TRANS_CARDEMU_TO_PDN
+ *	TRANS_ACT_TO_LPS
+ *	TRANS_LPS_TO_ACT
+ *
+ *	TRANS_END
+ *	PWR SEQ Version: rtl8192E_PwrSeq_V09.h
+ */
+
+#define	RTL8192E_TRANS_CARDEMU_TO_ACT_STEPS	18
+#define	RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS	18
+#define	RTL8192E_TRANS_CARDEMU_TO_SUS_STEPS	18
+#define	RTL8192E_TRANS_SUS_TO_CARDEMU_STEPS	18
+#define	RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS	18
+#define	RTL8192E_TRANS_PDN_TO_CARDEMU_STEPS	18
+#define	RTL8192E_TRANS_ACT_TO_LPS_STEPS		23
+#define	RTL8192E_TRANS_LPS_TO_ACT_STEPS		23
+#define	RTL8192E_TRANS_END_STEPS		1
+
+#define RTL8192E_TRANS_CARDEMU_TO_ACT					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+	/* disable HWPDN 0x04[15]=0*/					\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(7), 0},			\
+	/* disable SW LPS 0x04[10]=0*/					\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(2), 0},			\
+	/* disable WL suspend*/						\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, (BIT(4)|BIT(3)), 0},		\
+	/* wait till 0x04[17] = 1    power ready*/			\
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, BIT(1), BIT(1)},		\
+	/* release WLON reset  0x04[16]=1*/				\
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	/* polling until return 0*/					\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	/**/								\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, BIT(0), 0},
+
+#define RTL8192E_TRANS_ACT_TO_CARDEMU					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+	/*0x1F[7:0] = 0 turn off RF*/					\
+	{0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0},			\
+	/*0x4C[23]=0x4E[7]=0, switch DPDT_SEL_P output from register 0x65[2] */\
+	{0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(7), 0},			\
+	/*0x04[9] = 1 turn off MAC by HW state machine*/		\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(1), BIT(1)},		\
+	/*wait till 0x04[9] = 0 polling until return 0 to disable*/	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, BIT(1), 0},
+
+#define RTL8192E_TRANS_CARDEMU_TO_SUS					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+	/*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/		\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(4) | BIT(3), (BIT(4) | BIT(3))},\
+	/*0x04[12:11] = 2b'01 enable WL suspend*/			\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
+	 PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC,	\
+	 PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},				\
+	/*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/		\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3) | BIT(4)},\
+	/*Set SDIO suspend local register*/				\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_SDIO , PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	 /*wait power state to suspend*/				\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_SDIO , PWR_CMD_POLLING, BIT(1), 0},
+
+#define RTL8192E_TRANS_SUS_TO_CARDEMU					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+	/*Set SDIO suspend local register*/				\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_SDIO , PWR_CMD_WRITE, BIT(0), 0},			\
+	/*wait power state to suspend*/					\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_SDIO , PWR_CMD_POLLING, BIT(1), BIT(1)},		\
+	/*0x04[12:11] = 2b'01enable WL suspend*/			\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(3) | BIT(4), 0},
+
+#define RTL8192E_TRANS_CARDEMU_TO_CARDDIS				\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+	/*0x07=0x20 , SOP option to disable BG/MB*/			\
+	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0x20},			\
+	/*Unlock small LDO Register*/					\
+	{0x00CC, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(2), BIT(2)},		\
+	/*Disable small LDO*/						\
+	{0x0011, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(0), 0},			\
+	/*0x04[12:11] = 2b'01 enable WL suspend*/			\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
+	 PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC,		\
+	 PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},				\
+	/*0x04[10] = 1, enable SW LPS*/					\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(2), BIT(2)},		\
+	/*Set SDIO suspend local register*/				\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_SDIO , PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	/*wait power state to suspend*/					\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_SDIO , PWR_CMD_POLLING, BIT(1), 0},
+
+#define RTL8192E_TRANS_CARDDIS_TO_CARDEMU				\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+	/*Set SDIO suspend local register*/				\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_SDIO , PWR_CMD_WRITE, BIT(0), 0},			\
+	/*wait power state to suspend*/					\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_SDIO , PWR_CMD_POLLING, BIT(1), BIT(1)},		\
+	/*Enable small LDO*/						\
+	{0x0011, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	/*Lock small LDO Register*/					\
+	{0x00CC, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(2), 0},			\
+	/*0x04[12:11] = 2b'01enable WL suspend*/			\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(3) | BIT(4), 0},
+
+#define RTL8192E_TRANS_CARDEMU_TO_PDN					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+	/* 0x04[16] = 0*/						\
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(0), 0},			\
+	/* 0x04[15] = 1*/						\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(7), BIT(7)},
+
+#define RTL8192E_TRANS_PDN_TO_CARDEMU					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+	/* 0x04[15] = 0*/						\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(7), 0},
+
+#define RTL8192E_TRANS_ACT_TO_LPS					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+	/*PCIe DMA stop*/						\
+	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0xFF},			\
+	/*Tx Pause*/							\
+	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0xFF},			\
+	/*Should be zero if no packet is transmitting*/			\
+	{0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, 0xFF, 0},			\
+	/*Should be zero if no packet is transmitting*/			\
+	{0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, 0xFF, 0},			\
+	/*Should be zero if no packet is transmitting*/			\
+	{0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, 0xFF, 0},			\
+	/*Should be zero if no packet is transmitting*/			\
+	{0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, 0xFF, 0},			\
+	/*CCK and OFDM are disabled,and clock are gated*/		\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(0), 0},			\
+	/*Delay 1us*/							\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},		\
+	/*Whole BB is reset*/						\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(1), 0},			\
+	/*Reset MAC TRX*/						\
+	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0x03},			\
+	/*check if removed later*/					\
+	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(1), 0},			\
+	/*When driver enter Sus/ Disable, enable LOP for BT*/		\
+	{0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0x00},			\
+	/*Respond TxOK to scheduler*/					\
+	{0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(5), BIT(5)},
+
+#define RTL8192E_TRANS_LPS_TO_ACT					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+	/*SDIO RPWM, For Repeatly In and out, Taggle bit should be changed*/\
+	{0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
+	 PWR_BASEADDR_SDIO , PWR_CMD_WRITE, 0xFF, 0x84},		\
+	/*USB RPWM*/							\
+	{0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0x84},			\
+	/*PCIe RPWM*/							\
+	{0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0x84},			\
+	/*Delay*/							\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS},		\
+	/*0x08[4] = 0 switch TSF to 40M*/				\
+	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(4), 0},			\
+	/*Polling 0x109[7]=0  TSF in 40M*/				\
+	{0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_POLLING, BIT(7), 0},		\
+	/*0x101[1] = 1*/						\
+	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(1), BIT(1)},		\
+	/*0x100[7:0] = 0xFF  enable WMAC TRX*/				\
+	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0xFF},			\
+	/* 0x02[1:0] = 2b'11 enable BB macro*/				\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(1) | BIT(0), BIT(1) | BIT(0)},\
+	/*0x522 = 0*/							\
+	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0},			\
+	/*Clear ISR*/							\
+	{0x013D, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC , PWR_CMD_WRITE, 0xFF, 0xFF},
+
+#define RTL8192E_TRANS_END						\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+	{0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 0, PWR_CMD_END, 0, 0},
+
+extern struct wlan_pwr_cfg rtl8192E_power_on_flow
+					[RTL8192E_TRANS_CARDEMU_TO_ACT_STEPS +
+					 RTL8192E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8192E_radio_off_flow
+					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS +
+					 RTL8192E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8192E_card_disable_flow
+					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS +
+					 RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS +
+					 RTL8192E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8192E_card_enable_flow
+					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS +
+					 RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS +
+					 RTL8192E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8192E_suspend_flow
+					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS +
+					 RTL8192E_TRANS_CARDEMU_TO_SUS_STEPS +
+					 RTL8192E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8192E_resume_flow
+					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS +
+					 RTL8192E_TRANS_CARDEMU_TO_SUS_STEPS +
+					 RTL8192E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8192E_hwpdn_flow
+					[RTL8192E_TRANS_ACT_TO_CARDEMU_STEPS +
+					 RTL8192E_TRANS_CARDEMU_TO_PDN_STEPS +
+					 RTL8192E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8192E_enter_lps_flow
+					[RTL8192E_TRANS_ACT_TO_LPS_STEPS +
+					 RTL8192E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8192E_leave_lps_flow
+					[RTL8192E_TRANS_LPS_TO_ACT_STEPS +
+					 RTL8192E_TRANS_END_STEPS];
+
+/* RTL8192EE Power Configuration CMDs for PCIe interface */
+#define RTL8192E_NIC_PWR_ON_FLOW	rtl8192E_power_on_flow
+#define RTL8192E_NIC_RF_OFF_FLOW	rtl8192E_radio_off_flow
+#define RTL8192E_NIC_DISABLE_FLOW	rtl8192E_card_disable_flow
+#define RTL8192E_NIC_ENABLE_FLOW	rtl8192E_card_enable_flow
+#define RTL8192E_NIC_SUSPEND_FLOW	rtl8192E_suspend_flow
+#define RTL8192E_NIC_RESUME_FLOW	rtl8192E_resume_flow
+#define RTL8192E_NIC_PDN_FLOW		rtl8192E_hwpdn_flow
+#define RTL8192E_NIC_LPS_ENTER_FLOW	rtl8192E_enter_lps_flow
+#define RTL8192E_NIC_LPS_LEAVE_FLOW	rtl8192E_leave_lps_flow
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h
new file mode 100644
index 0000000..3f2a959
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h
@@ -0,0 +1,2231 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92E_REG_H__
+#define __RTL92E_REG_H__
+
+#define TXPKT_BUF_SELECT			0x69
+#define RXPKT_BUF_SELECT			0xA5
+#define DISABLE_TRXPKT_BUF_ACCESS		0x0
+
+#define REG_SYS_ISO_CTRL			0x0000
+#define REG_SYS_FUNC_EN				0x0002
+#define REG_APS_FSMCO				0x0004
+#define REG_SYS_CLKR				0x0008
+#define REG_9346CR				0x000A
+#define REG_EE_VPD				0x000C
+#define REG_SYS_SWR_CTRL1			0x0010
+#define REG_SPS0_CTRL				0x0011
+#define REG_SYS_SWR_CTRL2			0x0014
+#define REG_SYS_SWR_CTRL3			0x0018
+#define REG_RSV_CTRL				0x001C
+#define REG_RF_CTRL				0x001F
+#define REG_LPLDO_CTRL				0x0023
+#define REG_AFE_CTRL1				0x0024
+#define REG_AFE_XTAL_CTRL			0x0024
+#define REG_AFE_CTRL2				0x0028
+#define REG_MAC_PHY_CTRL			0x002c
+#define REG_AFE_CTRL3				0x002c
+#define REG_EFUSE_CTRL				0x0030
+#define REG_EFUSE_TEST				0x0034
+#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 REG_LEDCFG3				0x004F
+#define REG_FSIMR				0x0050
+#define REG_FSISR				0x0054
+#define REG_HSIMR				0x0058
+#define REG_HSISR				0x005c
+#define REG_SDIO_CTRL				0x0070
+#define REG_OPT_CTRL				0x0074
+#define REG_GPIO_OUTPUT				0x006c
+#define REG_AFE_CTRL4				0x0078
+#define REG_MCUFWDL				0x0080
+
+#define REG_HIMR				0x00B0
+#define REG_HISR				0x00B4
+#define REG_HIMRE				0x00B8
+#define REG_HISRE				0x00BC
+
+#define REG_EFUSE_ACCESS			0x00CF
+#define REG_HPON_FSM				0x00EC
+#define REG_SYS_CFG1				0x00F0
+#define REG_SYS_CFG2				0x00FC
+
+#define REG_CR					0x0100
+#define REG_PBP					0x0104
+#define REG_PKT_BUFF_ACCESS_CTRL		0x0106
+#define REG_TRXDMA_CTRL				0x010C
+#define REG_TRXFF_BNDY				0x0114
+#define REG_TRXFF_STATUS			0x0118
+#define REG_RXFF_PTR				0x011C
+
+#define REG_CPWM				0x012F
+#define REG_FWIMR				0x0130
+#define REG_FWISR				0x0134
+#define REG_PKTBUF_DBG_CTRL			0x0140
+#define REG_RXPKTBUF_CTRL			0x0142
+#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_RSVD3				0x0168
+#define REG_C2HEVT_MSG_NORMAL			0x01A0
+#define REG_C2HEVT_CLEAR			0x01AF
+#define REG_MCUTST_1				0x01c0
+#define REG_MCUTST_WOWLAN			0x01C7
+#define REG_FMETHR				0x01C8
+#define REG_HMETFR				0x01CC
+#define REG_HMEBOX_0				0x01D0
+#define REG_HMEBOX_1				0x01D4
+#define REG_HMEBOX_2				0x01D8
+#define REG_HMEBOX_3				0x01DC
+
+#define REG_LLT_INIT				0x01E0
+
+#define REG_HMEBOX_EXT_0			0x01F0
+#define REG_HMEBOX_EXT_1			0x01F4
+#define REG_HMEBOX_EXT_2			0x01F8
+#define REG_HMEBOX_EXT_3			0x01FC
+
+/*-----------------------------------------------------
+ *
+ *	0x0200h ~ 0x027Fh	TXDMA Configuration
+ *
+ *-----------------------------------------------------
+ */
+#define REG_RQPN				0x0200
+#define REG_FIFOPAGE				0x0204
+#define REG_DWBCN0_CTRL				0x0208
+#define REG_TXDMA_OFFSET_CHK			0x020C
+#define REG_TXDMA_STATUS			0x0210
+#define REG_RQPN_NPQ				0x0214
+#define REG_AUTO_LLT				0x0224
+#define REG_DWBCN1_CTRL				0x0228
+
+/*-----------------------------------------------------
+ *
+ *	0x0280h ~ 0x02FFh	RXDMA Configuration
+ *
+ *-----------------------------------------------------
+ */
+#define REG_RXDMA_AGG_PG_TH			0x0280
+#define REG_FW_UPD_RDPTR			0x0284
+#define REG_RXDMA_CONTROL			0x0286
+#define REG_RXPKT_NUM				0x0287
+#define REG_RXDMA_STATUS			0x0288
+#define REG_RXDMA_PRO				0x0290
+#define REG_EARLY_MODE_CONTROL			0x02BC
+#define REG_RSVD5				0x02F0
+#define REG_RSVD6				0x02F4
+
+/*-----------------------------------------------------
+ *
+ *	0x0300h ~ 0x03FFh	PCIe
+ *
+ *-----------------------------------------------------
+ */
+#define	REG_PCIE_CTRL_REG			0x0300
+#define	REG_INT_MIG				0x0304
+#define	REG_BCNQ_DESA				0x0308
+#define	REG_MGQ_DESA				0x0310
+#define	REG_VOQ_DESA				0x0318
+#define	REG_VIQ_DESA				0x0320
+#define	REG_BEQ_DESA				0x0328
+#define	REG_BKQ_DESA				0x0330
+#define	REG_RX_DESA				0x0338
+#define	REG_HQ0_DESA				0x0340
+#define	REG_HQ1_DESA				0x0348
+#define	REG_HQ2_DESA				0x0350
+#define	REG_HQ3_DESA				0x0358
+#define	REG_HQ4_DESA				0x0360
+#define	REG_HQ5_DESA				0x0368
+#define	REG_HQ6_DESA				0x0370
+#define	REG_HQ7_DESA				0x0378
+#define	REG_MGQ_TXBD_NUM			0x0380
+#define	REG_RX_RXBD_NUM				0x0382
+#define	REG_VOQ_TXBD_NUM			0x0384
+#define	REG_VIQ_TXBD_NUM			0x0386
+#define	REG_BEQ_TXBD_NUM			0x0388
+#define	REG_BKQ_TXBD_NUM			0x038A
+#define	REG_HI0Q_TXBD_NUM			0x038C
+#define	REG_HI1Q_TXBD_NUM			0x038E
+#define	REG_HI2Q_TXBD_NUM			0x0390
+#define	REG_HI3Q_TXBD_NUM			0x0392
+#define	REG_HI4Q_TXBD_NUM			0x0394
+#define	REG_HI5Q_TXBD_NUM			0x0396
+#define	REG_HI6Q_TXBD_NUM			0x0398
+#define	REG_HI7Q_TXBD_NUM			0x039A
+#define	REG_TSFTIMER_HCI			0x039C
+/*Read Write Point*/
+#define	REG_VOQ_TXBD_IDX			0x03A0
+#define	REG_VIQ_TXBD_IDX			0x03A4
+#define	REG_BEQ_TXBD_IDX			0x03A8
+#define	REG_BKQ_TXBD_IDX			0x03AC
+#define	REG_MGQ_TXBD_IDX			0x03B0
+#define	REG_RXQ_TXBD_IDX			0x03B4
+
+#define	REG_HI0Q_TXBD_IDX			0x03B8
+#define	REG_HI1Q_TXBD_IDX			0x03BC
+#define	REG_HI2Q_TXBD_IDX			0x03C0
+#define	REG_HI3Q_TXBD_IDX			0x03C4
+
+#define	REG_HI4Q_TXBD_IDX			0x03C8
+#define	REG_HI5Q_TXBD_IDX			0x03CC
+#define	REG_HI6Q_TXBD_IDX			0x03D0
+#define	REG_HI7Q_TXBD_IDX			0x03D4
+#define	REG_PCIE_HCPWM				0x03D8
+#define	REG_PCIE_CTRL2				0x03DB
+#define	REG_PCIE_HRPWM				0x03DC
+#define	REG_H2C_MSG_DRV2FW_INFO			0x03E0
+#define	REG_PCIE_C2H_MSG_REQUEST		0x03E4
+#define	REG_BACKDOOR_DBI_WDATA			0x03E8
+#define	REG_BACKDOOR_DBI_RDATA			0x03EC
+#define	REG_BACKDOOR_DBI_DATA			0x03F0
+#define	REG_MDIO				0x03F4
+#define	REG_MDIO_DATA				0x03F8
+
+#define	REG_HDAQ_DESA_NODEF			0x0000
+#define	REG_CMDQ_DESA_NODEF			0x0000
+/* spec version 11
+ *-----------------------------------------------------
+ *
+ *	0x0400h ~ 0x047Fh	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_TXPKT_EMPTY				0x041A
+
+#define REG_FWHW_TXQ_CTRL			0x0420
+#define REG_HWSEQ_CTRL				0x0423
+#define REG_BCNQ_BDNY				0x0424
+#define REG_MGQ_BDNY				0x0425
+#define REG_LIFECTRL_CTRL			0x0426
+#define REG_MULTI_BCNQ_OFFSET			0x0427
+#define REG_SPEC_SIFS				0x0428
+#define REG_RETRY_LIMIT				0x042A
+#define REG_TXBF_CTRL				0x042C
+#define REG_DARFRC				0x0430
+#define REG_RARFRC				0x0438
+#define REG_RRSR				0x0440
+#define REG_ARFR0				0x0444
+#define REG_ARFR1				0x044C
+#define REG_AMPDU_MAX_TIME			0x0456
+#define REG_BCNQ1_BDNY				0x0457
+#define REG_AGGLEN_LMT				0x0458
+#define REG_AMPDU_MIN_SPACE			0x045C
+#define REG_TXPKTBUF_WMAC_LBK_BF_HD		0x045D
+#define REG_NDPA_OPT_CTRL			0x045F
+#define REG_FAST_EDCA_CTRL			0x0460
+#define REG_RD_RESP_PKT_TH			0x0463
+#define REG_POWER_STAGE1			0x04B4
+#define REG_POWER_STAGE2			0x04B8
+#define REG_AMPDU_BURST_MODE			0x04BC
+#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_MACID_PKT_DROP0			0x04D0
+
+/*-----------------------------------------------------
+ *
+ *	0x0500h ~ 0x05FFh	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 REG_BCNTCFG				0x0510
+#define REG_PIFS				0x0512
+#define REG_RDG_PIFS				0x0513
+#define REG_SIFS_CTX				0x0514
+#define REG_SIFS_TRX				0x0516
+#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_BCN_CTRL				0x0550
+#define REG_BCN_CTRL_1				0x0551
+#define REG_MBID_NUM				0x0552
+#define REG_DUAL_TSF_RST			0x0553
+#define REG_BCN_INTERVAL			0x0554
+#define REG_DRVERLYINT				0x0558
+#define REG_BCNDMATIM				0x0559
+#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_CTWND				0x0572
+#define REG_PSTIMER				0x0580
+#define REG_TIMER0				0x0584
+#define REG_TIMER1				0x0588
+#define REG_BCN_PREDL_ITV			0x058F
+#define REG_ACMHWCTRL				0x05C0
+
+/*-----------------------------------------------------
+ *
+ *	0x0600h ~ 0x07FFh	WMAC Configuration
+ *
+ *-----------------------------------------------------
+ */
+#define REG_MAC_CR				0x0600
+#define REG_BWOPMODE				0x0603
+#define REG_TCR					0x0604
+#define REG_RCR					0x0608
+#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
+#define REG_RESP_SIFS_CCK			0x063C
+#define REG_RESP_SIFS_OFDM			0x063E
+#define REG_ACKTO				0x0640
+#define REG_CTS2TO				0x0641
+#define REG_EIFS				0x0642
+
+#define	REG_NAV_UPPER				0x0652
+
+/* Security*/
+#define REG_CAMCMD				0x0670
+#define REG_CAMWRITE				0x0674
+#define REG_CAMREAD				0x0678
+#define REG_CAMDBG				0x067C
+#define REG_SECCFG				0x0680
+
+/* Power*/
+#define REG_WOW_CTRL				0x0690
+#define REG_PS_RX_INFO				0x0692
+#define REG_UAPSD_TID				0x0693
+#define REG_WKFMCAM_NUM				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_BT_COEX_TABLE			0x06C0
+#define REG_BFMER0_INFO				0x06E4
+#define REG_BFMER1_INFO				0x06EC
+#define REG_CSI_RPT_PARAM_BW20			0x06F4
+#define REG_CSI_RPT_PARAM_BW40			0x06F8
+#define REG_CSI_RPT_PARAM_BW80			0x06FC
+/* Hardware Port 2*/
+#define REG_MACID1				0x0700
+#define REG_BSSID1				0x0708
+#define REG_BFMEE_SEL				0x0714
+#define REG_SND_PTCL_CTRL			0x0718
+
+#define	CR9346					REG_9346CR
+#define	MSR					(REG_CR + 2)
+#define	ISR					REG_HISR
+#define	TSFR					REG_TSFTR
+
+#define	MACIDR0					REG_MACID
+#define	MACIDR4					(REG_MACID + 4)
+
+#define PBP					REG_PBP
+
+#define	IDR0					MACIDR0
+#define	IDR4					MACIDR4
+
+#define	UNUSED_REGISTER				0x1BF
+#define	DCAM					UNUSED_REGISTER
+#define	PSR					UNUSED_REGISTER
+#define BBADDR					UNUSED_REGISTER
+#define	PHYDATAR				UNUSED_REGISTER
+
+#define	INVALID_BBRF_VALUE			0x12345678
+
+#define	MAX_MSS_DENSITY_2T			0x13
+#define	MAX_MSS_DENSITY_1T			0x0A
+
+#define	CMDEEPROM_EN				BIT(5)
+#define	CMDEEPROM_SEL				BIT(4)
+#define	CMD9346CR_9356SEL			BIT(4)
+#define	AUTOLOAD_EEPROM				(CMDEEPROM_EN | CMDEEPROM_SEL)
+#define	AUTOLOAD_EFUSE				CMDEEPROM_EN
+
+#define	GPIOSEL_GPIO				0
+#define	GPIOSEL_ENBT				BIT(5)
+
+#define	GPIO_IN					REG_GPIO_PIN_CTRL
+#define	GPIO_OUT				(REG_GPIO_PIN_CTRL + 1)
+#define	GPIO_IO_SEL				(REG_GPIO_PIN_CTRL + 2)
+#define	GPIO_MOD				(REG_GPIO_PIN_CTRL + 3)
+
+#define	MSR_NOLINK				0x00
+#define	MSR_ADHOC				0x01
+#define	MSR_INFRA				0x02
+#define	MSR_AP					0x03
+
+#define	RRSR_RSC_OFFSET				21
+#define	RRSR_SHORT_OFFSET			23
+#define	RRSR_RSC_BW_40M				0x600000
+#define	RRSR_RSC_UPSUBCHNL			0x400000
+#define	RRSR_RSC_LOWSUBCHNL			0x200000
+#define	RRSR_SHORT				0x800000
+#define	RRSR_1M					BIT(0)
+#define	RRSR_2M					BIT(1)
+#define	RRSR_5_5M				BIT(2)
+#define	RRSR_11M				BIT(3)
+#define	RRSR_6M					BIT(4)
+#define	RRSR_9M					BIT(5)
+#define	RRSR_12M				BIT(6)
+#define	RRSR_18M				BIT(7)
+#define	RRSR_24M				BIT(8)
+#define	RRSR_36M				BIT(9)
+#define	RRSR_48M				BIT(10)
+#define	RRSR_54M				BIT(11)
+#define	RRSR_MCS0				BIT(12)
+#define	RRSR_MCS1				BIT(13)
+#define	RRSR_MCS2				BIT(14)
+#define	RRSR_MCS3				BIT(15)
+#define	RRSR_MCS4				BIT(16)
+#define	RRSR_MCS5				BIT(17)
+#define	RRSR_MCS6				BIT(18)
+#define	RRSR_MCS7				BIT(19)
+#define	BRSR_ACKSHORTPMB			BIT(23)
+
+#define	RATR_1M					0x00000001
+#define	RATR_2M					0x00000002
+#define	RATR_55M				0x00000004
+#define	RATR_11M				0x00000008
+#define	RATR_6M					0x00000010
+#define	RATR_9M					0x00000020
+#define	RATR_12M				0x00000040
+#define	RATR_18M				0x00000080
+#define	RATR_24M				0x00000100
+#define	RATR_36M				0x00000200
+#define	RATR_48M				0x00000400
+#define	RATR_54M				0x00000800
+#define	RATR_MCS0				0x00001000
+#define	RATR_MCS1				0x00002000
+#define	RATR_MCS2				0x00004000
+#define	RATR_MCS3				0x00008000
+#define	RATR_MCS4				0x00010000
+#define	RATR_MCS5				0x00020000
+#define	RATR_MCS6				0x00040000
+#define	RATR_MCS7				0x00080000
+#define	RATR_MCS8				0x00100000
+#define	RATR_MCS9				0x00200000
+#define	RATR_MCS10				0x00400000
+#define	RATR_MCS11				0x00800000
+#define	RATR_MCS12				0x01000000
+#define	RATR_MCS13				0x02000000
+#define	RATR_MCS14				0x04000000
+#define	RATR_MCS15				0x08000000
+
+#define RATE_1M					BIT(0)
+#define RATE_2M					BIT(1)
+#define RATE_5_5M				BIT(2)
+#define RATE_11M				BIT(3)
+#define RATE_6M					BIT(4)
+#define RATE_9M					BIT(5)
+#define RATE_12M				BIT(6)
+#define RATE_18M				BIT(7)
+#define RATE_24M				BIT(8)
+#define RATE_36M				BIT(9)
+#define RATE_48M				BIT(10)
+#define RATE_54M				BIT(11)
+#define RATE_MCS0				BIT(12)
+#define RATE_MCS1				BIT(13)
+#define RATE_MCS2				BIT(14)
+#define RATE_MCS3				BIT(15)
+#define RATE_MCS4				BIT(16)
+#define RATE_MCS5				BIT(17)
+#define RATE_MCS6				BIT(18)
+#define RATE_MCS7				BIT(19)
+#define RATE_MCS8				BIT(20)
+#define RATE_MCS9				BIT(21)
+#define RATE_MCS10				BIT(22)
+#define RATE_MCS11				BIT(23)
+#define RATE_MCS12				BIT(24)
+#define RATE_MCS13				BIT(25)
+#define RATE_MCS14				BIT(26)
+#define RATE_MCS15				BIT(27)
+
+#define	RATE_ALL_CCK		(RATR_1M | RATR_2M | RATR_55M | RATR_11M)
+#define	RATE_ALL_OFDM_AG	(RATR_6M | RATR_9M | RATR_12M | RATR_18M |\
+				 RATR_24M | RATR_36M | RATR_48M | RATR_54M)
+#define	RATE_ALL_OFDM_1SS	(RATR_MCS0 | RATR_MCS1 | RATR_MCS2 |\
+				 RATR_MCS3 | RATR_MCS4 | RATR_MCS5 |\
+				 RATR_MCS6 | RATR_MCS7)
+#define	RATE_ALL_OFDM_2SS	(RATR_MCS8 | RATR_MCS9 | RATR_MCS10 |\
+				 RATR_MCS11 | RATR_MCS12 | RATR_MCS13 |\
+				 RATR_MCS14 | RATR_MCS15)
+
+#define	BW_OPMODE_20MHZ				BIT(2)
+#define	BW_OPMODE_5G				BIT(1)
+#define	CAM_VALID				BIT(15)
+#define	CAM_NOTVALID				0x0000
+#define	CAM_USEDK				BIT(5)
+
+#define	CAM_NONE				0x0
+#define	CAM_WEP40				0x01
+#define	CAM_TKIP				0x02
+#define	CAM_AES					0x04
+#define	CAM_WEP104				0x05
+
+#define	TOTAL_CAM_ENTRY				32
+#define	HALF_CAM_ENTRY				16
+
+#define	CAM_WRITE				BIT(16)
+#define	CAM_READ				0x00000000
+#define	CAM_POLLINIG				BIT(31)
+
+#define	SCR_USEDK				0x01
+#define	SCR_TXSEC_ENABLE			0x02
+#define	SCR_RXSEC_ENABLE			0x04
+
+/*********************************************
+*       8192EE IMR/ISR bits
+**********************************************/
+#define	IMR_DISABLED				0x0
+/* IMR DW0(0x0060-0063) Bit 0-31 */
+#define	IMR_TIMER2				BIT(31)
+#define	IMR_TIMER1				BIT(30)
+#define	IMR_PSTIMEOUT				BIT(29)
+#define	IMR_GTINT4				BIT(28)
+#define	IMR_GTINT3				BIT(27)
+#define	IMR_TBDER				BIT(26)
+#define	IMR_TBDOK				BIT(25)
+#define	IMR_TSF_BIT32_TOGGLE			BIT(24)
+#define	IMR_BCNDMAINT0				BIT(20)
+#define	IMR_BCNDOK0				BIT(16)
+#define	IMR_BCNDMAINT_E				BIT(14)
+#define	IMR_ATIMEND				BIT(12)
+#define	IMR_HISR1_IND_INT			BIT(11)
+#define	IMR_C2HCMD				BIT(10)
+#define	IMR_CPWM2				BIT(9)
+#define	IMR_CPWM				BIT(8)
+#define	IMR_HIGHDOK				BIT(7)
+#define	IMR_MGNTDOK				BIT(6)
+#define	IMR_BKDOK				BIT(5)
+#define	IMR_BEDOK				BIT(4)
+#define	IMR_VIDOK				BIT(3)
+#define	IMR_VODOK				BIT(2)
+#define	IMR_RDU					BIT(1)
+#define	IMR_ROK					BIT(0)
+
+/* IMR DW1(0x00B4-00B7) Bit 0-31 */
+#define	IMR_MCUERR				BIT(28)
+#define	IMR_BCNDMAINT7				BIT(27)
+#define	IMR_BCNDMAINT6				BIT(26)
+#define	IMR_BCNDMAINT5				BIT(25)
+#define	IMR_BCNDMAINT4				BIT(24)
+#define	IMR_BCNDMAINT3				BIT(23)
+#define	IMR_BCNDMAINT2				BIT(22)
+#define	IMR_BCNDMAINT1				BIT(21)
+#define	IMR_BCNDOK7				BIT(20)
+#define	IMR_BCNDOK6				BIT(19)
+#define	IMR_BCNDOK5				BIT(18)
+#define	IMR_BCNDOK4				BIT(17)
+#define	IMR_BCNDOK3				BIT(16)
+#define	IMR_BCNDOK2				BIT(15)
+#define	IMR_BCNDOK1				BIT(14)
+#define	IMR_ATIMEND_E				BIT(13)
+#define	IMR_TXERR				BIT(11)
+#define	IMR_RXERR				BIT(10)
+#define	IMR_TXFOVW				BIT(9)
+#define	IMR_RXFOVW				BIT(8)
+
+#define	HWSET_MAX_SIZE				512
+#define EFUSE_MAX_SECTION			64
+#define EFUSE_REAL_CONTENT_LEN			256
+#define EFUSE_OOB_PROTECT_BYTES			18
+
+#define	EEPROM_DEFAULT_TSSI			0x0
+#define EEPROM_DEFAULT_TXPOWERDIFF		0x0
+#define EEPROM_DEFAULT_CRYSTALCAP		0x5
+#define EEPROM_DEFAULT_BOARDTYPE		0x02
+#define EEPROM_DEFAULT_TXPOWER			0x1010
+#define	EEPROM_DEFAULT_HT2T_TXPWR		0x10
+
+#define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3
+#define	EEPROM_DEFAULT_THERMALMETER		0x1A
+#define	EEPROM_DEFAULT_ANTTXPOWERDIFF		0x0
+#define	EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP	0x5
+#define	EEPROM_DEFAULT_TXPOWERLEVEL		0x22
+#define	EEPROM_DEFAULT_HT40_2SDIFF		0x0
+#define EEPROM_DEFAULT_HT20_DIFF		2
+#define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3
+#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET	0
+#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET	0
+
+#define RF_OPTION1				0x79
+#define RF_OPTION2				0x7A
+#define RF_OPTION3				0x7B
+#define RF_OPTION4				0x7C
+
+#define EEPROM_DEFAULT_PID			0x1234
+#define EEPROM_DEFAULT_VID			0x5678
+#define EEPROM_DEFAULT_CUSTOMERID		0xAB
+#define EEPROM_DEFAULT_SUBCUSTOMERID		0xCD
+#define EEPROM_DEFAULT_VERSION			0
+
+#define	EEPROM_CHANNEL_PLAN_FCC			0x0
+#define	EEPROM_CHANNEL_PLAN_IC			0x1
+#define	EEPROM_CHANNEL_PLAN_ETSI		0x2
+#define	EEPROM_CHANNEL_PLAN_SPAIN		0x3
+#define	EEPROM_CHANNEL_PLAN_FRANCE		0x4
+#define	EEPROM_CHANNEL_PLAN_MKK			0x5
+#define	EEPROM_CHANNEL_PLAN_MKK1		0x6
+#define	EEPROM_CHANNEL_PLAN_ISRAEL		0x7
+#define	EEPROM_CHANNEL_PLAN_TELEC		0x8
+#define	EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN	0x9
+#define	EEPROM_CHANNEL_PLAN_WORLD_WIDE_13	0xA
+#define	EEPROM_CHANNEL_PLAN_NCC			0xB
+#define	EEPROM_CHANNEL_PLAN_BY_HW_MASK		0x80
+
+#define EEPROM_CID_DEFAULT			0x0
+#define EEPROM_CID_TOSHIBA			0x4
+#define	EEPROM_CID_CCX				0x10
+#define	EEPROM_CID_QMI				0x0D
+#define EEPROM_CID_WHQL				0xFE
+
+#define	RTL8192E_EEPROM_ID			0x8129
+
+#define EEPROM_HPON				0x02
+#define EEPROM_CLK				0x06
+#define EEPROM_TESTR				0x08
+
+#define EEPROM_TXPOWERCCK			0x10
+#define	EEPROM_TXPOWERHT40_1S			0x16
+#define EEPROM_TXPOWERHT20DIFF			0x1B
+#define EEPROM_TXPOWER_OFDMDIFF			0x1B
+
+#define	EEPROM_TX_PWR_INX			0x10
+
+#define	EEPROM_CHANNELPLAN			0xB8
+#define	EEPROM_XTAL_92E				0xB9
+#define	EEPROM_THERMAL_METER_92E		0xBA
+#define	EEPROM_IQK_LCK_92E			0xBB
+
+#define	EEPROM_RF_BOARD_OPTION_92E		0xC1
+#define	EEPROM_RF_FEATURE_OPTION_92E		0xC2
+#define	EEPROM_RF_BT_SETTING_92E		0xC3
+#define	EEPROM_VERSION				0xC4
+#define	EEPROM_CUSTOMER_ID			0xC5
+#define	EEPROM_RF_ANTENNA_OPT_92E		0xC9
+
+#define	EEPROM_MAC_ADDR				0xD0
+#define EEPROM_VID				0xD6
+#define EEPROM_DID				0xD8
+#define EEPROM_SVID				0xDA
+#define EEPROM_SMID				0xDC
+
+#define	STOPBECON				BIT(6)
+#define	STOPHIGHT				BIT(5)
+#define	STOPMGT					BIT(4)
+#define	STOPVO					BIT(3)
+#define	STOPVI					BIT(2)
+#define	STOPBE					BIT(1)
+#define	STOPBK					BIT(0)
+
+#define	RCR_APPFCS				BIT(31)
+#define	RCR_APP_MIC				BIT(30)
+#define	RCR_APP_ICV				BIT(29)
+#define	RCR_APP_PHYST_RXFF			BIT(28)
+#define	RCR_APP_BA_SSN				BIT(27)
+#define	RCR_ENMBID				BIT(24)
+#define	RCR_LSIGEN				BIT(23)
+#define	RCR_MFBEN				BIT(22)
+#define	RCR_HTC_LOC_CTRL			BIT(14)
+#define	RCR_AMF					BIT(13)
+#define	RCR_ACF					BIT(12)
+#define	RCR_ADF					BIT(11)
+#define	RCR_AICV				BIT(9)
+#define	RCR_ACRC32				BIT(8)
+#define	RCR_CBSSID_BCN				BIT(7)
+#define	RCR_CBSSID_DATA				BIT(6)
+#define	RCR_CBSSID				RCR_CBSSID_DATA
+#define	RCR_APWRMGT				BIT(5)
+#define	RCR_ADD3				BIT(4)
+#define	RCR_AB					BIT(3)
+#define	RCR_AM					BIT(2)
+#define	RCR_APM					BIT(1)
+#define	RCR_AAP					BIT(0)
+#define	RCR_MXDMA_OFFSET			8
+#define	RCR_FIFO_OFFSET				13
+
+#define RSV_CTRL				0x001C
+#define RD_CTRL					0x0524
+
+#define REG_USB_INFO				0xFE17
+#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_USB_VID				0xFE60
+#define REG_USB_PID				0xFE62
+#define REG_USB_OPTIONAL			0xFE64
+#define REG_USB_CHIRP_K				0xFE65
+#define REG_USB_PHY				0xFE66
+#define REG_USB_MAC_ADDR			0xFE70
+#define REG_USB_HRPWM				0xFE58
+#define REG_USB_HCPWM				0xFE57
+
+#define SW18_FPWM				BIT(3)
+
+#define ISO_MD2PP				BIT(0)
+#define ISO_UA2USB				BIT(1)
+#define ISO_UD2CORE				BIT(2)
+#define ISO_PA2PCIE				BIT(3)
+#define ISO_PD2CORE				BIT(4)
+#define ISO_IP2MAC				BIT(5)
+#define ISO_DIOP				BIT(6)
+#define ISO_DIOE				BIT(7)
+#define ISO_EB2CORE				BIT(8)
+#define ISO_DIOR				BIT(9)
+
+#define PWC_EV25V				BIT(14)
+#define PWC_EV12V				BIT(15)
+
+#define FEN_BBRSTB				BIT(0)
+#define FEN_BB_GLB_RSTN				BIT(1)
+#define FEN_USBA				BIT(2)
+#define FEN_UPLL				BIT(3)
+#define FEN_USBD				BIT(4)
+#define FEN_DIO_PCIE				BIT(5)
+#define FEN_PCIEA				BIT(6)
+#define FEN_PPLL				BIT(7)
+#define FEN_PCIED				BIT(8)
+#define FEN_DIOE				BIT(9)
+#define FEN_CPUEN				BIT(10)
+#define FEN_DCORE				BIT(11)
+#define FEN_ELDR				BIT(12)
+#define FEN_DIO_RF				BIT(13)
+#define FEN_HWPDN				BIT(14)
+#define FEN_MREGEN				BIT(15)
+
+#define PFM_LDALL				BIT(0)
+#define PFM_ALDN				BIT(1)
+#define PFM_LDKP				BIT(2)
+#define PFM_WOWL				BIT(3)
+#define ENPDN					BIT(4)
+#define PDN_PL					BIT(5)
+#define APFM_ONMAC				BIT(8)
+#define APFM_OFF				BIT(9)
+#define APFM_RSM				BIT(10)
+#define AFSM_HSUS				BIT(11)
+#define AFSM_PCIE				BIT(12)
+#define APDM_MAC				BIT(13)
+#define APDM_HOST				BIT(14)
+#define APDM_HPDN				BIT(15)
+#define RDY_MACON				BIT(16)
+#define SUS_HOST				BIT(17)
+#define ROP_ALD					BIT(20)
+#define ROP_PWR					BIT(21)
+#define ROP_SPS					BIT(22)
+#define SOP_MRST				BIT(25)
+#define SOP_FUSE				BIT(26)
+#define SOP_ABG					BIT(27)
+#define SOP_AMB					BIT(28)
+#define SOP_RCK					BIT(29)
+#define SOP_A8M					BIT(30)
+#define XOP_BTCK				BIT(31)
+
+#define ANAD16V_EN				BIT(0)
+#define ANA8M					BIT(1)
+#define MACSLP					BIT(4)
+#define LOADER_CLK_EN				BIT(5)
+#define _80M_SSC_DIS				BIT(7)
+#define _80M_SSC_EN_HO				BIT(8)
+#define PHY_SSC_RSTB				BIT(9)
+#define SEC_CLK_EN				BIT(10)
+#define MAC_CLK_EN				BIT(11)
+#define SYS_CLK_EN				BIT(12)
+#define RING_CLK_EN				BIT(13)
+
+#define	BOOT_FROM_EEPROM			BIT(4)
+#define	EEPROM_EN				BIT(5)
+
+#define AFE_BGEN				BIT(0)
+#define AFE_MBEN				BIT(1)
+#define MAC_ID_EN				BIT(7)
+
+#define WLOCK_ALL				BIT(0)
+#define WLOCK_00				BIT(1)
+#define WLOCK_04				BIT(2)
+#define WLOCK_08				BIT(3)
+#define WLOCK_40				BIT(4)
+#define R_DIS_PRST_0				BIT(5)
+#define R_DIS_PRST_1				BIT(6)
+#define LOCK_ALL_EN				BIT(7)
+
+#define RF_EN					BIT(0)
+#define RF_RSTB					BIT(1)
+#define RF_SDMRSTB				BIT(2)
+
+#define LDA15_EN				BIT(0)
+#define LDA15_STBY				BIT(1)
+#define LDA15_OBUF				BIT(2)
+#define LDA15_REG_VOS				BIT(3)
+#define _LDA15_VOADJ(x)				(((x) & 0x7) << 4)
+
+#define LDV12_EN				BIT(0)
+#define LDV12_SDBY				BIT(1)
+#define LPLDO_HSM				BIT(2)
+#define LPLDO_LSM_DIS				BIT(3)
+#define _LDV12_VADJ(x)				(((x) & 0xF) << 4)
+
+#define XTAL_EN					BIT(0)
+#define XTAL_BSEL				BIT(1)
+#define _XTAL_BOSC(x)				(((x) & 0x3) << 2)
+#define _XTAL_CADJ(x)				(((x) & 0xF) << 4)
+#define XTAL_GATE_USB				BIT(8)
+#define _XTAL_USB_DRV(x)			(((x) & 0x3) << 9)
+#define XTAL_GATE_AFE				BIT(11)
+#define _XTAL_AFE_DRV(x)			(((x) & 0x3) << 12)
+#define XTAL_RF_GATE				BIT(14)
+#define _XTAL_RF_DRV(x)				(((x) & 0x3) << 15)
+#define XTAL_GATE_DIG				BIT(17)
+#define _XTAL_DIG_DRV(x)			(((x) & 0x3) << 18)
+#define XTAL_BT_GATE				BIT(20)
+#define _XTAL_BT_DRV(x)				(((x) & 0x3) << 21)
+#define _XTAL_GPIO(x)				(((x) & 0x7) << 23)
+
+#define CKDLY_AFE				BIT(26)
+#define CKDLY_USB				BIT(27)
+#define CKDLY_DIG				BIT(28)
+#define CKDLY_BT				BIT(29)
+
+#define APLL_EN					BIT(0)
+#define APLL_320_EN				BIT(1)
+#define APLL_FREF_SEL				BIT(2)
+#define APLL_EDGE_SEL				BIT(3)
+#define APLL_WDOGB				BIT(4)
+#define APLL_LPFEN				BIT(5)
+
+#define APLL_REF_CLK_13MHZ			0x1
+#define APLL_REF_CLK_19_2MHZ			0x2
+#define APLL_REF_CLK_20MHZ			0x3
+#define APLL_REF_CLK_25MHZ			0x4
+#define APLL_REF_CLK_26MHZ			0x5
+#define APLL_REF_CLK_38_4MHZ			0x6
+#define APLL_REF_CLK_40MHZ			0x7
+
+#define APLL_320EN				BIT(14)
+#define APLL_80EN				BIT(15)
+#define APLL_1MEN				BIT(24)
+
+#define ALD_EN					BIT(18)
+#define EF_PD					BIT(19)
+#define EF_FLAG					BIT(31)
+
+#define EF_TRPT					BIT(7)
+#define LDOE25_EN				BIT(31)
+
+#define RSM_EN					BIT(0)
+#define TIMER_EN				BIT(4)
+
+#define TRSW0EN					BIT(2)
+#define TRSW1EN					BIT(3)
+#define EROM_EN					BIT(4)
+#define ENBT					BIT(5)
+#define ENUART					BIT(8)
+#define UART_910				BIT(9)
+#define ENPMAC					BIT(10)
+#define SIC_SWRST				BIT(11)
+#define ENSIC					BIT(12)
+#define SIC_23					BIT(13)
+#define ENHDP					BIT(14)
+#define SIC_LBK					BIT(15)
+
+#define LED0PL					BIT(4)
+#define LED1PL					BIT(12)
+#define LED0DIS					BIT(7)
+
+#define MCUFWDL_EN				BIT(0)
+#define MCUFWDL_RDY				BIT(1)
+#define FWDL_CHKSUM_RPT				BIT(2)
+#define MACINI_RDY				BIT(3)
+#define BBINI_RDY				BIT(4)
+#define RFINI_RDY				BIT(5)
+#define WINTINI_RDY				BIT(6)
+#define CPRST					BIT(23)
+
+#define XCLK_VLD				BIT(0)
+#define ACLK_VLD				BIT(1)
+#define UCLK_VLD				BIT(2)
+#define PCLK_VLD				BIT(3)
+#define PCIRSTB					BIT(4)
+#define V15_VLD					BIT(5)
+#define TRP_B15V_EN				BIT(7)
+#define SIC_IDLE				BIT(8)
+#define BD_MAC2					BIT(9)
+#define BD_MAC1					BIT(10)
+#define IC_MACPHY_MODE				BIT(11)
+#define VENDOR_ID				BIT(19)
+#define PAD_HWPD_IDN				BIT(22)
+#define TRP_VAUX_EN				BIT(23)
+#define TRP_BT_EN				BIT(24)
+#define BD_PKG_SEL				BIT(25)
+#define BD_HCI_SEL				BIT(26)
+#define TYPE_ID					BIT(27)
+
+#define CHIP_VER_RTL_MASK			0xF000
+#define CHIP_VER_RTL_SHIFT			12
+
+#define REG_LBMODE				(REG_CR + 3)
+
+#define HCI_TXDMA_EN				BIT(0)
+#define HCI_RXDMA_EN				BIT(1)
+#define TXDMA_EN				BIT(2)
+#define RXDMA_EN				BIT(3)
+#define PROTOCOL_EN				BIT(4)
+#define SCHEDULE_EN				BIT(5)
+#define MACTXEN					BIT(6)
+#define MACRXEN					BIT(7)
+#define ENSWBCN					BIT(8)
+#define ENSEC					BIT(9)
+
+#define _NETTYPE(x)				(((x) & 0x3) << 16)
+#define MASK_NETTYPE				0x30000
+#define NT_NO_LINK				0x0
+#define NT_LINK_AD_HOC				0x1
+#define NT_LINK_AP				0x2
+#define NT_AS_AP				0x3
+
+#define _LBMODE(x)				(((x) & 0xF) << 24)
+#define MASK_LBMODE				0xF000000
+#define LOOPBACK_NORMAL				0x0
+#define LOOPBACK_IMMEDIATELY			0xB
+#define LOOPBACK_MAC_DELAY			0x3
+#define LOOPBACK_PHY				0x1
+#define LOOPBACK_DMA				0x7
+
+#define GET_RX_PAGE_SIZE(value)			((value) & 0xF)
+#define GET_TX_PAGE_SIZE(value)			(((value) & 0xF0) >> 4)
+#define _PSRX_MASK				0xF
+#define _PSTX_MASK				0xF0
+#define _PSRX(x)				(x)
+#define _PSTX(x)				((x) << 4)
+
+#define PBP_64					0x0
+#define PBP_128					0x1
+#define PBP_256					0x2
+#define PBP_512					0x3
+#define PBP_1024				0x4
+
+#define RXDMA_ARBBW_EN				BIT(0)
+#define RXSHFT_EN				BIT(1)
+#define RXDMA_AGG_EN				BIT(2)
+#define QS_VO_QUEUE				BIT(8)
+#define QS_VI_QUEUE				BIT(9)
+#define QS_BE_QUEUE				BIT(10)
+#define QS_BK_QUEUE				BIT(11)
+#define QS_MANAGER_QUEUE			BIT(12)
+#define QS_HIGH_QUEUE				BIT(13)
+
+#define HQSEL_VOQ				BIT(0)
+#define HQSEL_VIQ				BIT(1)
+#define HQSEL_BEQ				BIT(2)
+#define HQSEL_BKQ				BIT(3)
+#define HQSEL_MGTQ				BIT(4)
+#define HQSEL_HIQ				BIT(5)
+
+#define _TXDMA_HIQ_MAP(x)			(((x)&0x3) << 14)
+#define _TXDMA_MGQ_MAP(x)			(((x)&0x3) << 12)
+#define _TXDMA_BKQ_MAP(x)			(((x)&0x3) << 10)
+#define _TXDMA_BEQ_MAP(x)			(((x)&0x3) << 8)
+#define _TXDMA_VIQ_MAP(x)			(((x)&0x3) << 6)
+#define _TXDMA_VOQ_MAP(x)			(((x)&0x3) << 4)
+
+#define QUEUE_LOW				1
+#define QUEUE_NORMAL				2
+#define QUEUE_HIGH				3
+
+#define _LLT_NO_ACTIVE				0x0
+#define _LLT_WRITE_ACCESS			0x1
+#define _LLT_READ_ACCESS			0x2
+
+#define _LLT_INIT_DATA(x)			((x) & 0xFF)
+#define _LLT_INIT_ADDR(x)			(((x) & 0xFF) << 8)
+#define _LLT_OP(x)					(((x) & 0x3) << 30)
+#define _LLT_OP_VALUE(x)			(((x) >> 30) & 0x3)
+
+#define BB_WRITE_READ_MASK			(BIT(31) | BIT(30))
+#define BB_WRITE_EN				BIT(30)
+#define BB_READ_EN				BIT(31)
+
+#define _HPQ(x)					((x) & 0xFF)
+#define _LPQ(x)					(((x) & 0xFF) << 8)
+#define _PUBQ(x)				(((x) & 0xFF) << 16)
+#define _NPQ(x)					((x) & 0xFF)
+
+#define HPQ_PUBLIC_DIS				BIT(24)
+#define LPQ_PUBLIC_DIS				BIT(25)
+#define LD_RQPN					BIT(31)
+
+#define BCN_VALID				BIT(16)
+#define BCN_HEAD(x)				(((x) & 0xFF) << 8)
+#define	BCN_HEAD_MASK				0xFF00
+
+#define BLK_DESC_NUM_SHIFT			4
+#define BLK_DESC_NUM_MASK			0xF
+
+#define DROP_DATA_EN				BIT(9)
+
+#define EN_AMPDU_RTY_NEW			BIT(7)
+
+#define _INIRTSMCS_SEL(x)			((x) & 0x3F)
+
+#define _SPEC_SIFS_CCK(x)			((x) & 0xFF)
+#define _SPEC_SIFS_OFDM(x)			(((x) & 0xFF) << 8)
+
+#define RATE_REG_BITMAP_ALL			0xFFFFF
+
+#define _RRSC_BITMAP(x)				((x) & 0xFFFFF)
+
+#define _RRSR_RSC(x)				(((x) & 0x3) << 21)
+#define RRSR_RSC_RESERVED			0x0
+#define RRSR_RSC_UPPER_SUBCHANNEL		0x1
+#define RRSR_RSC_LOWER_SUBCHANNEL		0x2
+#define RRSR_RSC_DUPLICATE_MODE			0x3
+
+#define USE_SHORT_G1				BIT(20)
+
+#define _AGGLMT_MCS0(x)				((x) & 0xF)
+#define _AGGLMT_MCS1(x)				(((x) & 0xF) << 4)
+#define _AGGLMT_MCS2(x)				(((x) & 0xF) << 8)
+#define _AGGLMT_MCS3(x)				(((x) & 0xF) << 12)
+#define _AGGLMT_MCS4(x)				(((x) & 0xF) << 16)
+#define _AGGLMT_MCS5(x)				(((x) & 0xF) << 20)
+#define _AGGLMT_MCS6(x)				(((x) & 0xF) << 24)
+#define _AGGLMT_MCS7(x)				(((x) & 0xF) << 28)
+
+#define	RETRY_LIMIT_SHORT_SHIFT			8
+#define	RETRY_LIMIT_LONG_SHIFT			0
+
+#define _DARF_RC1(x)				((x) & 0x1F)
+#define _DARF_RC2(x)				(((x) & 0x1F) << 8)
+#define _DARF_RC3(x)				(((x) & 0x1F) << 16)
+#define _DARF_RC4(x)				(((x) & 0x1F) << 24)
+#define _DARF_RC5(x)				((x) & 0x1F)
+#define _DARF_RC6(x)				(((x) & 0x1F) << 8)
+#define _DARF_RC7(x)				(((x) & 0x1F) << 16)
+#define _DARF_RC8(x)				(((x) & 0x1F) << 24)
+
+#define _RARF_RC1(x)				((x) & 0x1F)
+#define _RARF_RC2(x)				(((x) & 0x1F) << 8)
+#define _RARF_RC3(x)				(((x) & 0x1F) << 16)
+#define _RARF_RC4(x)				(((x) & 0x1F) << 24)
+#define _RARF_RC5(x)				((x) & 0x1F)
+#define _RARF_RC6(x)				(((x) & 0x1F) << 8)
+#define _RARF_RC7(x)				(((x) & 0x1F) << 16)
+#define _RARF_RC8(x)				(((x) & 0x1F) << 24)
+
+#define AC_PARAM_TXOP_LIMIT_OFFSET		16
+#define AC_PARAM_ECW_MAX_OFFSET			12
+#define AC_PARAM_ECW_MIN_OFFSET			8
+#define AC_PARAM_AIFS_OFFSET			0
+
+#define _AIFS(x)				(x)
+#define _ECW_MAX_MIN(x)				((x) << 8)
+#define _TXOP_LIMIT(x)				((x) << 16)
+
+#define _BCNIFS(x)				((x) & 0xFF)
+#define _BCNECW(x)				((((x) & 0xF)) << 8)
+
+#define _LRL(x)					((x) & 0x3F)
+#define _SRL(x)					(((x) & 0x3F) << 8)
+
+#define _SIFS_CCK_CTX(x)			((x) & 0xFF)
+#define _SIFS_CCK_TRX(x)			(((x) & 0xFF) << 8)
+
+#define _SIFS_OFDM_CTX(x)			((x) & 0xFF)
+#define _SIFS_OFDM_TRX(x)			(((x) & 0xFF) << 8)
+
+#define _TBTT_PROHIBIT_HOLD(x)			(((x) & 0xFF) << 8)
+
+#define DIS_EDCA_CNT_DWN			BIT(11)
+
+#define EN_MBSSID				BIT(1)
+#define EN_TXBCN_RPT				BIT(2)
+#define	EN_BCN_FUNCTION				BIT(3)
+
+#define TSFTR_RST				BIT(0)
+#define TSFTR1_RST				BIT(1)
+
+#define STOP_BCNQ				BIT(6)
+
+#define	DIS_TSF_UDT0_NORMAL_CHIP		BIT(4)
+#define	DIS_TSF_UDT0_TEST_CHIP			BIT(5)
+
+#define	ACMHW_HWEN				BIT(0)
+#define	ACMHW_BEQEN				BIT(1)
+#define	ACMHW_VIQEN				BIT(2)
+#define	ACMHW_VOQEN				BIT(3)
+#define	ACMHW_BEQSTATUS				BIT(4)
+#define	ACMHW_VIQSTATUS				BIT(5)
+#define	ACMHW_VOQSTATUS				BIT(6)
+
+#define APSDOFF					BIT(6)
+#define APSDOFF_STATUS				BIT(7)
+
+#define BW_20MHZ				BIT(2)
+
+#define RATE_BITMAP_ALL				0xFFFFF
+
+#define RATE_RRSR_CCK_ONLY_1M			0xFFFF1
+
+#define TSFRST					BIT(0)
+#define DIS_GCLK				BIT(1)
+#define PAD_SEL					BIT(2)
+#define PWR_ST					BIT(6)
+#define PWRBIT_OW_EN				BIT(7)
+#define ACRC					BIT(8)
+#define CFENDFORM				BIT(9)
+#define ICV					BIT(10)
+
+#define AAP					BIT(0)
+#define APM					BIT(1)
+#define AM					BIT(2)
+#define AB					BIT(3)
+#define ADD3					BIT(4)
+#define APWRMGT					BIT(5)
+#define CBSSID					BIT(6)
+#define CBSSID_DATA				BIT(6)
+#define CBSSID_BCN				BIT(7)
+#define ACRC32					BIT(8)
+#define AICV					BIT(9)
+#define ADF					BIT(11)
+#define ACF					BIT(12)
+#define AMF					BIT(13)
+#define HTC_LOC_CTRL				BIT(14)
+#define UC_DATA_EN				BIT(16)
+#define BM_DATA_EN				BIT(17)
+#define MFBEN					BIT(22)
+#define LSIGEN					BIT(23)
+#define ENMBID					BIT(24)
+#define APP_BASSN				BIT(27)
+#define APP_PHYSTS				BIT(28)
+#define APP_ICV					BIT(29)
+#define APP_MIC					BIT(30)
+#define APP_FCS					BIT(31)
+
+#define _MIN_SPACE(x)				((x) & 0x7)
+#define _SHORT_GI_PADDING(x)			(((x) & 0x1F) << 3)
+
+#define RXERR_TYPE_OFDM_PPDU			0
+#define RXERR_TYPE_OFDM_FALSE_ALARM		1
+#define	RXERR_TYPE_OFDM_MPDU_OK			2
+#define RXERR_TYPE_OFDM_MPDU_FAIL		3
+#define RXERR_TYPE_CCK_PPDU			4
+#define RXERR_TYPE_CCK_FALSE_ALARM		5
+#define RXERR_TYPE_CCK_MPDU_OK			6
+#define RXERR_TYPE_CCK_MPDU_FAIL		7
+#define RXERR_TYPE_HT_PPDU			8
+#define RXERR_TYPE_HT_FALSE_ALARM		9
+#define RXERR_TYPE_HT_MPDU_TOTAL		10
+#define RXERR_TYPE_HT_MPDU_OK			11
+#define RXERR_TYPE_HT_MPDU_FAIL			12
+#define RXERR_TYPE_RX_FULL_DROP			15
+
+#define RXERR_COUNTER_MASK			0xFFFFF
+#define RXERR_RPT_RST				BIT(27)
+#define _RXERR_RPT_SEL(type)			((type) << 28)
+
+#define	SCR_TXUSEDK				BIT(0)
+#define	SCR_RXUSEDK				BIT(1)
+#define	SCR_TXENCENABLE				BIT(2)
+#define	SCR_RXDECENABLE				BIT(3)
+#define	SCR_SKBYA2				BIT(4)
+#define	SCR_NOSKMC				BIT(5)
+#define SCR_TXBCUSEDK				BIT(6)
+#define SCR_RXBCUSEDK				BIT(7)
+
+#define USB_IS_HIGH_SPEED			0
+#define USB_IS_FULL_SPEED			1
+#define USB_SPEED_MASK				BIT(5)
+
+#define USB_NORMAL_SIE_EP_MASK			0xF
+#define USB_NORMAL_SIE_EP_SHIFT			4
+
+#define USB_TEST_EP_MASK			0x30
+#define USB_TEST_EP_SHIFT			4
+
+#define USB_AGG_EN				BIT(3)
+
+#define MAC_ADDR_LEN				6
+#define LAST_ENTRY_OF_TX_PKT_BUFFER		175
+
+#define POLLING_LLT_THRESHOLD			20
+#define POLLING_READY_TIMEOUT_COUNT		3000
+
+#define	MAX_MSS_DENSITY_2T			0x13
+#define	MAX_MSS_DENSITY_1T			0x0A
+
+#define EPROM_CMD_OPERATING_MODE_MASK		((1 << 7) | (1 << 6))
+#define EPROM_CMD_CONFIG			0x3
+#define EPROM_CMD_LOAD				1
+
+#define	HWSET_MAX_SIZE_92S			HWSET_MAX_SIZE
+
+#define	HAL_8192C_HW_GPIO_WPS_BIT		BIT(2)
+
+#define	RPMAC_RESET				0x100
+#define	RPMAC_TXSTART				0x104
+#define	RPMAC_TXLEGACYSIG			0x108
+#define	RPMAC_TXHTSIG1				0x10c
+#define	RPMAC_TXHTSIG2				0x110
+#define	RPMAC_PHYDEBUG				0x114
+#define	RPMAC_TXPACKETNUM			0x118
+#define	RPMAC_TXIDLE				0x11c
+#define	RPMAC_TXMACHEADER0			0x120
+#define	RPMAC_TXMACHEADER1			0x124
+#define	RPMAC_TXMACHEADER2			0x128
+#define	RPMAC_TXMACHEADER3			0x12c
+#define	RPMAC_TXMACHEADER4			0x130
+#define	RPMAC_TXMACHEADER5			0x134
+#define	RPMAC_TXDADATYPE			0x138
+#define	RPMAC_TXRANDOMSEED			0x13c
+#define	RPMAC_CCKPLCPPREAMBLE			0x140
+#define	RPMAC_CCKPLCPHEADER			0x144
+#define	RPMAC_CCKCRC16				0x148
+#define	RPMAC_OFDMRXCRC32OK			0x170
+#define	RPMAC_OFDMRXCRC32ER			0x174
+#define	RPMAC_OFDMRXPARITYER			0x178
+#define	RPMAC_OFDMRXCRC8ER			0x17c
+#define	RPMAC_CCKCRXRC16ER			0x180
+#define	RPMAC_CCKCRXRC32ER			0x184
+#define	RPMAC_CCKCRXRC32OK			0x188
+#define	RPMAC_TXSTATUS				0x18c
+
+#define	RFPGA0_RFMOD				0x800
+
+#define	RFPGA0_TXINFO				0x804
+#define	RFPGA0_PSDFUNCTION			0x808
+
+#define	RFPGA0_TXGAINSTAGE			0x80c
+
+#define	RFPGA0_RFTIMING1			0x810
+#define	RFPGA0_RFTIMING2			0x814
+
+#define	RFPGA0_XA_HSSIPARAMETER1		0x820
+#define	RFPGA0_XA_HSSIPARAMETER2		0x824
+#define	RFPGA0_XB_HSSIPARAMETER1		0x828
+#define	RFPGA0_XB_HSSIPARAMETER2		0x82c
+
+#define	RFPGA0_XA_LSSIPARAMETER			0x840
+#define	RFPGA0_XB_LSSIPARAMETER			0x844
+
+#define	RFPGA0_RFWAKEUPPARAMETER		0x850
+#define	RFPGA0_RFSLEEPUPPARAMETER		0x854
+
+#define	RFPGA0_XAB_SWITCHCONTROL		0x858
+#define	RFPGA0_XCD_SWITCHCONTROL		0x85c
+
+#define	RFPGA0_XA_RFINTERFACEOE			0x860
+#define	RFPGA0_XB_RFINTERFACEOE			0x864
+
+#define	RFPGA0_XAB_RFINTERFACESW		0x870
+#define	RFPGA0_XCD_RFINTERFACESW		0x874
+
+#define	RFPGA0_XAB_RFPARAMETER			0x878
+#define	RFPGA0_XCD_RFPARAMETER			0x87c
+
+#define	RFPGA0_ANALOGPARAMETER1			0x880
+#define	RFPGA0_ANALOGPARAMETER2			0x884
+#define	RFPGA0_ANALOGPARAMETER3			0x888
+#define	RFPGA0_ANALOGPARAMETER4			0x88c
+
+#define	RFPGA0_XA_LSSIREADBACK			0x8a0
+#define	RFPGA0_XB_LSSIREADBACK			0x8a4
+#define	RFPGA0_XC_LSSIREADBACK			0x8a8
+#define	RFPGA0_XD_LSSIREADBACK			0x8ac
+
+#define	RFPGA0_PSDREPORT			0x8b4
+#define	TRANSCEIVEA_HSPI_READBACK		0x8b8
+#define	TRANSCEIVEB_HSPI_READBACK		0x8bc
+#define	REG_SC_CNT				0x8c4
+#define	RFPGA0_XAB_RFINTERFACERB		0x8e0
+#define	RFPGA0_XCD_RFINTERFACERB		0x8e4
+
+#define	RFPGA1_RFMOD				0x900
+
+#define	RFPGA1_TXBLOCK				0x904
+#define	RFPGA1_DEBUGSELECT			0x908
+#define	RFPGA1_TXINFO				0x90c
+
+#define	RCCK0_SYSTEM				0xa00
+
+#define	RCCK0_AFESETTING			0xa04
+#define	RCCK0_CCA				0xa08
+
+#define	RCCK0_RXAGC1				0xa0c
+#define	RCCK0_RXAGC2				0xa10
+
+#define	RCCK0_RXHP				0xa14
+
+#define	RCCK0_DSPPARAMETER1			0xa18
+#define	RCCK0_DSPPARAMETER2			0xa1c
+
+#define	RCCK0_TXFILTER1				0xa20
+#define	RCCK0_TXFILTER2				0xa24
+#define	RCCK0_DEBUGPORT				0xa28
+#define	RCCK0_FALSEALARMREPORT			0xa2c
+#define	RCCK0_TRSSIREPORT			0xa50
+#define	RCCK0_RXREPORT				0xa54
+#define	RCCK0_FACOUNTERLOWER			0xa5c
+#define	RCCK0_FACOUNTERUPPER			0xa58
+#define	RCCK0_CCA_CNT				0xa60
+
+/* PageB(0xB00) */
+#define	RPDP_ANTA				0xb00
+#define	RPDP_ANTA_4				0xb04
+#define	RPDP_ANTA_8				0xb08
+#define	RPDP_ANTA_C				0xb0c
+#define	RPDP_ANTA_10				0xb10
+#define	RPDP_ANTA_14				0xb14
+#define	RPDP_ANTA_18				0xb18
+#define	RPDP_ANTA_1C				0xb1c
+#define	RPDP_ANTA_20				0xb20
+#define	RPDP_ANTA_24				0xb24
+
+#define	RCONFIG_PMPD_ANTA			0xb28
+#define	RCONFIG_RAM64x16			0xb2c
+
+#define	RBNDA					0xb30
+#define	RHSSIPAR				0xb34
+
+#define	RCONFIG_ANTA				0xb68
+#define	RCONFIG_ANTB				0xb6c
+
+#define	RPDP_ANTB				0xb70
+#define	RPDP_ANTB_4				0xb74
+#define	RPDP_ANTB_8				0xb78
+#define	RPDP_ANTB_C				0xb7c
+#define	RPDP_ANTB_10				0xb80
+#define	RPDP_ANTB_14				0xb84
+#define	RPDP_ANTB_18				0xb88
+#define	RPDP_ANTB_1C				0xb8c
+#define	RPDP_ANTB_20				0xb90
+#define	RPDP_ANTB_24				0xb94
+
+#define	RCONFIG_PMPD_ANTB			0xb98
+
+#define	RBNDB					0xba0
+
+#define	RAPK					0xbd8
+#define	RPM_RX0_ANTA				0xbdc
+#define	RPM_RX1_ANTA				0xbe0
+#define	RPM_RX2_ANTA				0xbe4
+#define	RPM_RX3_ANTA				0xbe8
+#define	RPM_RX0_ANTB				0xbec
+#define	RPM_RX1_ANTB				0xbf0
+#define	RPM_RX2_ANTB				0xbf4
+#define	RPM_RX3_ANTB				0xbf8
+
+/*Page C*/
+#define	ROFDM0_LSTF				0xc00
+
+#define	ROFDM0_TRXPATHENABLE			0xc04
+#define	ROFDM0_TRMUXPAR				0xc08
+#define	ROFDM0_TRSWISOLATION			0xc0c
+
+#define	ROFDM0_XARXAFE				0xc10
+#define	ROFDM0_XARXIQIMBALANCE			0xc14
+#define	ROFDM0_XBRXAFE				0xc18
+#define	ROFDM0_XBRXIQIMBALANCE			0xc1c
+#define	ROFDM0_XCRXAFE				0xc20
+#define	ROFDM0_XCRXIQIMBANLANCE			0xc24
+#define	ROFDM0_XDRXAFE				0xc28
+#define	ROFDM0_XDRXIQIMBALANCE			0xc2c
+
+#define	ROFDM0_RXDETECTOR1			0xc30
+#define	ROFDM0_RXDETECTOR2			0xc34
+#define	ROFDM0_RXDETECTOR3			0xc38
+#define	ROFDM0_RXDETECTOR4			0xc3c
+
+#define	ROFDM0_RXDSP				0xc40
+#define	ROFDM0_CFOANDDAGC			0xc44
+#define	ROFDM0_CCADROPTHRESHOLD			0xc48
+#define	ROFDM0_ECCATHRESHOLD			0xc4c
+
+#define	ROFDM0_XAAGCCORE1			0xc50
+#define	ROFDM0_XAAGCCORE2			0xc54
+#define	ROFDM0_XBAGCCORE1			0xc58
+#define	ROFDM0_XBAGCCORE2			0xc5c
+#define	ROFDM0_XCAGCCORE1			0xc60
+#define	ROFDM0_XCAGCCORE2			0xc64
+#define	ROFDM0_XDAGCCORE1			0xc68
+#define	ROFDM0_XDAGCCORE2			0xc6c
+
+#define	ROFDM0_AGCPARAMETER1			0xc70
+#define	ROFDM0_AGCPARAMETER2			0xc74
+#define	ROFDM0_AGCRSSITABLE			0xc78
+#define	ROFDM0_HTSTFAGC				0xc7c
+
+#define	ROFDM0_XATXIQIMBALANCE			0xc80
+#define	ROFDM0_XATXAFE				0xc84
+#define	ROFDM0_XBTXIQIMBALANCE			0xc88
+#define	ROFDM0_XBTXAFE				0xc8c
+#define	ROFDM0_XCTXIQIMBALANCE			0xc90
+#define	ROFDM0_XCTXAFE				0xc94
+#define	ROFDM0_XDTXIQIMBALANCE			0xc98
+#define	ROFDM0_XDTXAFE				0xc9c
+
+#define ROFDM0_RXIQEXTANTA			0xca0
+#define	ROFDM0_TXCOEFF1				0xca4
+#define	ROFDM0_TXCOEFF2				0xca8
+#define	ROFDM0_TXCOEFF3				0xcac
+#define	ROFDM0_TXCOEFF4				0xcb0
+#define	ROFDM0_TXCOEFF5				0xcb4
+#define	ROFDM0_TXCOEFF6				0xcb8
+
+#define	ROFDM0_RXHPPARAMETER			0xce0
+#define	ROFDM0_TXPSEUDONOISEWGT			0xce4
+#define	ROFDM0_FRAMESYNC			0xcf0
+#define	ROFDM0_DFSREPORT			0xcf4
+
+#define	ROFDM1_LSTF				0xd00
+#define	ROFDM1_TRXPATHENABLE			0xd04
+
+#define	ROFDM1_CF0				0xd08
+#define	ROFDM1_CSI1				0xd10
+#define	ROFDM1_SBD				0xd14
+#define	ROFDM1_CSI2				0xd18
+#define	ROFDM1_CFOTRACKING			0xd2c
+#define	ROFDM1_TRXMESAURE1			0xd34
+#define	ROFDM1_INTFDET				0xd3c
+#define	ROFDM1_PSEUDONOISESTATEAB		0xd50
+#define	ROFDM1_PSEUDONOISESTATECD		0xd54
+#define	ROFDM1_RXPSEUDONOISEWGT			0xd58
+
+#define	ROFDM_PHYCOUNTER1			0xda0
+#define	ROFDM_PHYCOUNTER2			0xda4
+#define	ROFDM_PHYCOUNTER3			0xda8
+
+#define	ROFDM_SHORTCFOAB			0xdac
+#define	ROFDM_SHORTCFOCD			0xdb0
+#define	ROFDM_LONGCFOAB				0xdb4
+#define	ROFDM_LONGCFOCD				0xdb8
+#define	ROFDM_TAILCF0AB				0xdbc
+#define	ROFDM_TAILCF0CD				0xdc0
+#define	ROFDM_PWMEASURE1			0xdc4
+#define	ROFDM_PWMEASURE2			0xdc8
+#define	ROFDM_BWREPORT				0xdcc
+#define	ROFDM_AGCREPORT				0xdd0
+#define	ROFDM_RXSNR				0xdd4
+#define	ROFDM_RXEVMCSI				0xdd8
+#define	ROFDM_SIGREPORT				0xddc
+
+#define	RTXAGC_A_RATE18_06			0xe00
+#define	RTXAGC_A_RATE54_24			0xe04
+#define	RTXAGC_A_CCK1_MCS32			0xe08
+#define	RTXAGC_A_MCS03_MCS00			0xe10
+#define	RTXAGC_A_MCS07_MCS04			0xe14
+#define	RTXAGC_A_MCS11_MCS08			0xe18
+#define	RTXAGC_A_MCS15_MCS12			0xe1c
+
+#define	RTXAGC_B_RATE18_06			0x830
+#define	RTXAGC_B_RATE54_24			0x834
+#define	RTXAGC_B_CCK1_55_MCS32			0x838
+#define	RTXAGC_B_MCS03_MCS00			0x83c
+#define	RTXAGC_B_MCS07_MCS04			0x848
+#define	RTXAGC_B_MCS11_MCS08			0x84c
+#define	RTXAGC_B_MCS15_MCS12			0x868
+#define	RTXAGC_B_CCK11_A_CCK2_11		0x86c
+
+#define	RFPGA0_IQK				0xe28
+#define	RTX_IQK_TONE_A				0xe30
+#define	RRX_IQK_TONE_A				0xe34
+#define	RTX_IQK_PI_A				0xe38
+#define	RRX_IQK_PI_A				0xe3c
+
+#define	RTX_IQK					0xe40
+#define	RRX_IQK					0xe44
+#define	RIQK_AGC_PTS				0xe48
+#define	RIQK_AGC_RSP				0xe4c
+#define	RTX_IQK_TONE_B				0xe50
+#define	RRX_IQK_TONE_B				0xe54
+#define	RTX_IQK_PI_B				0xe58
+#define	RRX_IQK_PI_B				0xe5c
+#define	RIQK_AGC_CONT				0xe60
+
+#define	RBLUE_TOOTH				0xe6c
+#define	RRX_WAIT_CCA				0xe70
+#define	RTX_CCK_RFON				0xe74
+#define	RTX_CCK_BBON				0xe78
+#define	RTX_OFDM_RFON				0xe7c
+#define	RTX_OFDM_BBON				0xe80
+#define	RTX_TO_RX				0xe84
+#define	RTX_TO_TX				0xe88
+#define	RRX_CCK					0xe8c
+
+#define	RTX_POWER_BEFORE_IQK_A			0xe94
+#define	RTX_POWER_AFTER_IQK_A			0xe9c
+
+#define	RRX_POWER_BEFORE_IQK_A			0xea0
+#define	RRX_POWER_BEFORE_IQK_A_2		0xea4
+#define	RRX_POWER_AFTER_IQK_A			0xea8
+#define	RRX_POWER_AFTER_IQK_A_2			0xeac
+
+#define	RTX_POWER_BEFORE_IQK_B			0xeb4
+#define	RTX_POWER_AFTER_IQK_B			0xebc
+
+#define	RRX_POWER_BEFORE_IQK_B			0xec0
+#define	RRX_POWER_BEFORE_IQK_B_2		0xec4
+#define	RRX_POWER_AFTER_IQK_B			0xec8
+#define	RRX_POWER_AFTER_IQK_B_2			0xecc
+
+#define	RRX_OFDM				0xed0
+#define	RRX_WAIT_RIFS				0xed4
+#define	RRX_TO_RX				0xed8
+#define	RSTANDBY				0xedc
+#define	RSLEEP					0xee0
+#define	RPMPD_ANAEN				0xeec
+
+#define	RZEBRA1_HSSIENABLE			0x0
+#define	RZEBRA1_TRXENABLE1			0x1
+#define	RZEBRA1_TRXENABLE2			0x2
+#define	RZEBRA1_AGC				0x4
+#define	RZEBRA1_CHARGEPUMP			0x5
+#define	RZEBRA1_CHANNEL				0x7
+
+#define	RZEBRA1_TXGAIN				0x8
+#define	RZEBRA1_TXLPF				0x9
+#define	RZEBRA1_RXLPF				0xb
+#define	RZEBRA1_RXHPFCORNER			0xc
+
+#define	RGLOBALCTRL				0
+#define	RRTL8256_TXLPF				19
+#define	RRTL8256_RXLPF				11
+#define	RRTL8258_TXLPF				0x11
+#define	RRTL8258_RXLPF				0x13
+#define	RRTL8258_RSSILPF			0xa
+
+#define	RF_AC					0x00
+
+#define	RF_IQADJ_G1				0x01
+#define	RF_IQADJ_G2				0x02
+#define	RF_POW_TRSW				0x05
+
+#define	RF_GAIN_RX				0x06
+#define	RF_GAIN_TX				0x07
+
+#define	RF_TXM_IDAC				0x08
+#define	RF_BS_IQGEN				0x0F
+
+#define	RF_MODE1				0x10
+#define	RF_MODE2				0x11
+
+#define	RF_RX_AGC_HP				0x12
+#define	RF_TX_AGC				0x13
+#define	RF_BIAS					0x14
+#define	RF_IPA					0x15
+#define	RF_POW_ABILITY				0x17
+#define	RF_MODE_AG				0x18
+#define	RRFCHANNEL				0x18
+#define	RF_CHNLBW				0x18
+#define	RF_TOP					0x19
+
+#define	RF_RX_G1				0x1A
+#define	RF_RX_G2				0x1B
+
+#define	RF_RX_BB2				0x1C
+#define	RF_RX_BB1				0x1D
+
+#define	RF_RCK1					0x1E
+#define	RF_RCK2					0x1F
+
+#define	RF_TX_G1				0x20
+#define	RF_TX_G2				0x21
+#define	RF_TX_G3				0x22
+
+#define	RF_TX_BB1				0x23
+#define	RF_T_METER				0x42
+
+#define	RF_SYN_G1				0x25
+#define	RF_SYN_G2				0x26
+#define	RF_SYN_G3				0x27
+#define	RF_SYN_G4				0x28
+#define	RF_SYN_G5				0x29
+#define	RF_SYN_G6				0x2A
+#define	RF_SYN_G7				0x2B
+#define	RF_SYN_G8				0x2C
+
+#define	RF_RCK_OS				0x30
+#define	RF_TXPA_G1				0x31
+#define	RF_TXPA_G2				0x32
+#define	RF_TXPA_G3				0x33
+
+#define	RF_TX_BIAS_A				0x35
+#define	RF_TX_BIAS_D				0x36
+#define	RF_LOBF_9				0x38
+#define	RF_RXRF_A3				0x3C
+#define	RF_TRSW					0x3F
+
+#define	RF_TXRF_A2				0x41
+#define	RF_TXPA_G4				0x46
+#define	RF_TXPA_A4				0x4B
+
+#define	RF_WE_LUT				0xEF
+
+#define	BBBRESETB				0x100
+#define	BGLOBALRESETB				0x200
+#define	BOFDMTXSTART				0x4
+#define	BCCKTXSTART				0x8
+#define	BCRC32DEBUG				0x100
+#define	BPMACLOOPBACK				0x10
+#define	BTXLSIG					0xffffff
+#define	BOFDMTXRATE				0xf
+#define	BOFDMTXRESERVED				0x10
+#define	BOFDMTXLENGTH				0x1ffe0
+#define	BOFDMTXPARITY				0x20000
+#define	BTXHTSIG1				0xffffff
+#define	BTXHTMCSRATE				0x7f
+#define	BTXHTBW					0x80
+#define	BTXHTLENGTH				0xffff00
+#define	BTXHTSIG2				0xffffff
+#define	BTXHTSMOOTHING				0x1
+#define	BTXHTSOUNDING				0x2
+#define	BTXHTRESERVED				0x4
+#define	BTXHTAGGREATION				0x8
+#define	BTXHTSTBC				0x30
+#define	BTXHTADVANCECODING			0x40
+#define	BTXHTSHORTGI				0x80
+#define	BTXHTNUMBERHT_LTF			0x300
+#define	BTXHTCRC8				0x3fc00
+#define	BCOUNTERRESET				0x10000
+#define	BNUMOFOFDMTX				0xffff
+#define	BNUMOFCCKTX				0xffff0000
+#define	BTXIDLEINTERVAL				0xffff
+#define	BOFDMSERVICE				0xffff0000
+#define	BTXMACHEADER				0xffffffff
+#define	BTXDATAINIT				0xff
+#define	BTXHTMODE				0x100
+#define	BTXDATATYPE				0x30000
+#define	BTXRANDOMSEED				0xffffffff
+#define	BCCKTXPREAMBLE				0x1
+#define	BCCKTXSFD				0xffff0000
+#define	BCCKTXSIG				0xff
+#define	BCCKTXSERVICE				0xff00
+#define	BCCKLENGTHEXT				0x8000
+#define	BCCKTXLENGHT				0xffff0000
+#define	BCCKTXCRC16				0xffff
+#define	BCCKTXSTATUS				0x1
+#define	BOFDMTXSTATUS				0x2
+#define IS_BB_REG_OFFSET_92S(_offset)	\
+	((_offset >= 0x800) && (_offset <= 0xfff))
+
+#define	BRFMOD					0x1
+#define	BJAPANMODE				0x2
+#define	BCCKTXSC				0x30
+#define	BCCKEN					0x1000000
+#define	BOFDMEN					0x2000000
+
+#define	BOFDMRXADCPHASE				0x10000
+#define	BOFDMTXDACPHASE				0x40000
+#define	BXATXAGC				0x3f
+
+#define	BXBTXAGC				0xf00
+#define	BXCTXAGC				0xf000
+#define	BXDTXAGC				0xf0000
+
+#define	BPASTART				0xf0000000
+#define	BTRSTART				0x00f00000
+#define	BRFSTART				0x0000f000
+#define	BBBSTART				0x000000f0
+#define	BBBCCKSTART				0x0000000f
+#define	BPAEND					0xf
+#define	BTREND					0x0f000000
+#define	BRFEND					0x000f0000
+#define	BCCAMASK				0x000000f0
+#define	BR2RCCAMASK				0x00000f00
+#define	BHSSI_R2TDELAY				0xf8000000
+#define	BHSSI_T2RDELAY				0xf80000
+#define	BCONTXHSSI				0x400
+#define	BIGFROMCCK				0x200
+#define	BAGCADDRESS				0x3f
+#define	BRXHPTX					0x7000
+#define	BRXHP2RX				0x38000
+#define	BRXHPCCKINI				0xc0000
+#define	BAGCTXCODE				0xc00000
+#define	BAGCRXCODE				0x300000
+
+#define	B3WIREDATALENGTH			0x800
+#define	B3WIREADDREAALENGTH			0x400
+
+#define	B3WIRERFPOWERDOWN			0x1
+#define	B5GPAPEPOLARITY				0x40000000
+#define	B2GPAPEPOLARITY				0x80000000
+#define	BRFSW_TXDEFAULTANT			0x3
+#define	BRFSW_TXOPTIONANT			0x30
+#define	BRFSW_RXDEFAULTANT			0x300
+#define	BRFSW_RXOPTIONANT			0x3000
+#define	BRFSI_3WIREDATA				0x1
+#define	BRFSI_3WIRECLOCK			0x2
+#define	BRFSI_3WIRELOAD				0x4
+#define	BRFSI_3WIRERW				0x8
+#define	BRFSI_3WIRE				0xf
+
+#define	BRFSI_RFENV				0x10
+
+#define	BRFSI_TRSW				0x20
+#define	BRFSI_TRSWB				0x40
+#define	BRFSI_ANTSW				0x100
+#define	BRFSI_ANTSWB				0x200
+#define	BRFSI_PAPE				0x400
+#define	BRFSI_PAPE5G				0x800
+#define	BBANDSELECT				0x1
+#define	BHTSIG2_GI				0x80
+#define	BHTSIG2_SMOOTHING			0x01
+#define	BHTSIG2_SOUNDING			0x02
+#define	BHTSIG2_AGGREATON			0x08
+#define	BHTSIG2_STBC				0x30
+#define	BHTSIG2_ADVCODING			0x40
+#define	BHTSIG2_NUMOFHTLTF			0x300
+#define	BHTSIG2_CRC8				0x3fc
+#define	BHTSIG1_MCS				0x7f
+#define	BHTSIG1_BANDWIDTH			0x80
+#define	BHTSIG1_HTLENGTH			0xffff
+#define	BLSIG_RATE				0xf
+#define	BLSIG_RESERVED				0x10
+#define	BLSIG_LENGTH				0x1fffe
+#define	BLSIG_PARITY				0x20
+#define	BCCKRXPHASE				0x4
+
+#define	BLSSIREADADDRESS			0x7f800000
+#define	BLSSIREADEDGE				0x80000000
+
+#define	BLSSIREADBACKDATA			0xfffff
+
+#define	BLSSIREADOKFLAG				0x1000
+#define	BCCKSAMPLERATE				0x8
+#define	BREGULATOR0STANDBY			0x1
+#define	BREGULATORPLLSTANDBY			0x2
+#define	BREGULATOR1STANDBY			0x4
+#define	BPLLPOWERUP				0x8
+#define	BDPLLPOWERUP				0x10
+#define	BDA10POWERUP				0x20
+#define	BAD7POWERUP				0x200
+#define	BDA6POWERUP				0x2000
+#define	BXTALPOWERUP				0x4000
+#define	B40MDCLKPOWERUP				0x8000
+#define	BDA6DEBUGMODE				0x20000
+#define	BDA6SWING				0x380000
+
+#define	BADCLKPHASE				0x4000000
+#define	B80MCLKDELAY				0x18000000
+#define	BAFEWATCHDOGENABLE			0x20000000
+
+#define	BXTALCAP01				0xc0000000
+#define	BXTALCAP23				0x3
+#define	BXTALCAP92X				0x0f000000
+#define BXTALCAP				0x0f000000
+
+#define	BINTDIFCLKENABLE			0x400
+#define	BEXTSIGCLKENABLE			0x800
+#define	BBANDGAP_MBIAS_POWERUP			0x10000
+#define	BAD11SH_GAIN				0xc0000
+#define	BAD11NPUT_RANGE				0x700000
+#define	BAD110P_CURRENT				0x3800000
+#define	BLPATH_LOOPBACK				0x4000000
+#define	BQPATH_LOOPBACK				0x8000000
+#define	BAFE_LOOPBACK				0x10000000
+#define	BDA10_SWING				0x7e0
+#define	BDA10_REVERSE				0x800
+#define	BDA_CLK_SOURCE				0x1000
+#define	BDA7INPUT_RANGE				0x6000
+#define	BDA7_GAIN				0x38000
+#define	BDA7OUTPUT_CM_MODE			0x40000
+#define	BDA7INPUT_CM_MODE			0x380000
+#define	BDA7CURRENT				0xc00000
+#define	BREGULATOR_ADJUST			0x7000000
+#define	BAD11POWERUP_ATTX			0x1
+#define	BDA10PS_ATTX				0x10
+#define	BAD11POWERUP_ATRX			0x100
+#define	BDA10PS_ATRX				0x1000
+#define	BCCKRX_AGC_FORMAT			0x200
+#define	BPSDFFT_SAMPLE_POINT			0xc000
+#define	BPSD_AVERAGE_NUM			0x3000
+#define	BIQPATH_CONTROL				0xc00
+#define	BPSD_FREQ				0x3ff
+#define	BPSD_ANTENNA_PATH			0x30
+#define	BPSD_IQ_SWITCH				0x40
+#define	BPSD_RX_TRIGGER				0x400000
+#define	BPSD_TX_TRIGGER				0x80000000
+#define	BPSD_SINE_TONE_SCALE			0x7f000000
+#define	BPSD_REPORT				0xffff
+
+#define	BOFDM_TXSC				0x30000000
+#define	BCCK_TXON				0x1
+#define	BOFDM_TXON				0x2
+#define	BDEBUG_PAGE				0xfff
+#define	BDEBUG_ITEM				0xff
+#define	BANTL					0x10
+#define	BANT_NONHT				0x100
+#define	BANT_HT1				0x1000
+#define	BANT_HT2				0x10000
+#define	BANT_HT1S1				0x100000
+#define	BANT_NONHTS1				0x1000000
+
+#define	BCCK_BBMODE				0x3
+#define	BCCK_TXPOWERSAVING			0x80
+#define	BCCK_RXPOWERSAVING			0x40
+
+#define	BCCK_SIDEBAND				0x10
+
+#define	BCCK_SCRAMBLE				0x8
+#define	BCCK_ANTDIVERSITY			0x8000
+#define	BCCK_CARRIER_RECOVERY			0x4000
+#define	BCCK_TXRATE				0x3000
+#define	BCCK_DCCANCEL				0x0800
+#define	BCCK_ISICANCEL				0x0400
+#define	BCCK_MATCH_FILTER			0x0200
+#define	BCCK_EQUALIZER				0x0100
+#define	BCCK_PREAMBLE_DETECT			0x800000
+#define	BCCK_FAST_FALSECCA			0x400000
+#define	BCCK_CH_ESTSTART			0x300000
+#define	BCCK_CCA_COUNT				0x080000
+#define	BCCK_CS_LIM				0x070000
+#define	BCCK_BIST_MODE				0x80000000
+#define	BCCK_CCAMASK				0x40000000
+#define	BCCK_TX_DAC_PHASE			0x4
+#define	BCCK_RX_ADC_PHASE			0x20000000
+#define	BCCKR_CP_MODE				0x0100
+#define	BCCK_TXDC_OFFSET			0xf0
+#define	BCCK_RXDC_OFFSET			0xf
+#define	BCCK_CCA_MODE				0xc000
+#define	BCCK_FALSECS_LIM			0x3f00
+#define	BCCK_CS_RATIO				0xc00000
+#define	BCCK_CORGBIT_SEL			0x300000
+#define	BCCK_PD_LIM				0x0f0000
+#define	BCCK_NEWCCA				0x80000000
+#define	BCCK_RXHP_OF_IG				0x8000
+#define	BCCK_RXIG				0x7f00
+#define	BCCK_LNA_POLARITY			0x800000
+#define	BCCK_RX1ST_BAIN				0x7f0000
+#define	BCCK_RF_EXTEND				0x20000000
+#define	BCCK_RXAGC_SATLEVEL			0x1f000000
+#define	BCCK_RXAGC_SATCOUNT			0xe0
+#define	BCCKRXRFSETTLE				0x1f
+#define	BCCK_FIXED_RXAGC			0x8000
+#define	BCCK_ANTENNA_POLARITY			0x2000
+#define	BCCK_TXFILTER_TYPE			0x0c00
+#define	BCCK_RXAGC_REPORTTYPE			0x0300
+#define	BCCK_RXDAGC_EN				0x80000000
+#define	BCCK_RXDAGC_PERIOD			0x20000000
+#define	BCCK_RXDAGC_SATLEVEL			0x1f000000
+#define	BCCK_TIMING_RECOVERY			0x800000
+#define	BCCK_TXC0				0x3f0000
+#define	BCCK_TXC1				0x3f000000
+#define	BCCK_TXC2				0x3f
+#define	BCCK_TXC3				0x3f00
+#define	BCCK_TXC4				0x3f0000
+#define	BCCK_TXC5				0x3f000000
+#define	BCCK_TXC6				0x3f
+#define	BCCK_TXC7				0x3f00
+#define	BCCK_DEBUGPORT				0xff0000
+#define	BCCK_DAC_DEBUG				0x0f000000
+#define	BCCK_FALSEALARM_ENABLE			0x8000
+#define	BCCK_FALSEALARM_READ			0x4000
+#define	BCCK_TRSSI				0x7f
+#define	BCCK_RXAGC_REPORT			0xfe
+#define	BCCK_RXREPORT_ANTSEL			0x80000000
+#define	BCCK_RXREPORT_MFOFF			0x40000000
+#define	BCCK_RXREPORT_SQLOSS			0x20000000
+#define	BCCK_RXREPORT_PKTLOSS			0x10000000
+#define	BCCK_RXREPORT_LOCKEDBIT			0x08000000
+#define	BCCK_RXREPORT_RATEERROR			0x04000000
+#define	BCCK_RXREPORT_RXRATE			0x03000000
+#define	BCCK_RXFA_COUNTER_LOWER			0xff
+#define	BCCK_RXFA_COUNTER_UPPER			0xff000000
+#define	BCCK_RXHPAGC_START			0xe000
+#define	BCCK_RXHPAGC_FINAL			0x1c00
+#define	BCCK_RXFALSEALARM_ENABLE		0x8000
+#define	BCCK_FACOUNTER_FREEZE			0x4000
+#define	BCCK_TXPATH_SEL				0x10000000
+#define	BCCK_DEFAULT_RXPATH			0xc000000
+#define	BCCK_OPTION_RXPATH			0x3000000
+
+#define	BNUM_OFSTF				0x3
+#define	BSHIFT_L				0xc0
+#define	BGI_TH					0xc
+#define	BRXPATH_A				0x1
+#define	BRXPATH_B				0x2
+#define	BRXPATH_C				0x4
+#define	BRXPATH_D				0x8
+#define	BTXPATH_A				0x1
+#define	BTXPATH_B				0x2
+#define	BTXPATH_C				0x4
+#define	BTXPATH_D				0x8
+#define	BTRSSI_FREQ				0x200
+#define	BADC_BACKOFF				0x3000
+#define	BDFIR_BACKOFF				0xc000
+#define	BTRSSI_LATCH_PHASE			0x10000
+#define	BRX_LDC_OFFSET				0xff
+#define	BRX_QDC_OFFSET				0xff00
+#define	BRX_DFIR_MODE				0x1800000
+#define	BRX_DCNF_TYPE				0xe000000
+#define	BRXIQIMB_A				0x3ff
+#define	BRXIQIMB_B				0xfc00
+#define	BRXIQIMB_C				0x3f0000
+#define	BRXIQIMB_D				0xffc00000
+#define	BDC_DC_NOTCH				0x60000
+#define	BRXNB_NOTCH				0x1f000000
+#define	BPD_TH					0xf
+#define	BPD_TH_OPT2				0xc000
+#define	BPWED_TH				0x700
+#define	BIFMF_WIN_L				0x800
+#define	BPD_OPTION				0x1000
+#define	BMF_WIN_L				0xe000
+#define	BBW_SEARCH_L				0x30000
+#define	BWIN_ENH_L				0xc0000
+#define	BBW_TH					0x700000
+#define	BED_TH2					0x3800000
+#define	BBW_OPTION				0x4000000
+#define	BRADIO_TH				0x18000000
+#define	BWINDOW_L				0xe0000000
+#define	BSBD_OPTION				0x1
+#define	BFRAME_TH				0x1c
+#define	BFS_OPTION				0x60
+#define	BDC_SLOPE_CHECK				0x80
+#define	BFGUARD_COUNTER_DC_L			0xe00
+#define	BFRAME_WEIGHT_SHORT			0x7000
+#define	BSUB_TUNE				0xe00000
+#define	BFRAME_DC_LENGTH			0xe000000
+#define	BSBD_START_OFFSET			0x30000000
+#define	BFRAME_TH_2				0x7
+#define	BFRAME_GI2_TH				0x38
+#define	BGI2_SYNC_EN				0x40
+#define	BSARCH_SHORT_EARLY			0x300
+#define	BSARCH_SHORT_LATE			0xc00
+#define	BSARCH_GI2_LATE				0x70000
+#define	BCFOANTSUM				0x1
+#define	BCFOACC					0x2
+#define	BCFOSTARTOFFSET				0xc
+#define	BCFOLOOPBACK				0x70
+#define	BCFOSUMWEIGHT				0x80
+#define	BDAGCENABLE				0x10000
+#define	BTXIQIMB_A				0x3ff
+#define	BTXIQIMB_b				0xfc00
+#define	BTXIQIMB_C				0x3f0000
+#define	BTXIQIMB_D				0xffc00000
+#define	BTXIDCOFFSET				0xff
+#define	BTXIQDCOFFSET				0xff00
+#define	BTXDFIRMODE				0x10000
+#define	BTXPESUDO_NOISEON			0x4000000
+#define	BTXPESUDO_NOISE_A			0xff
+#define	BTXPESUDO_NOISE_B			0xff00
+#define	BTXPESUDO_NOISE_C			0xff0000
+#define	BTXPESUDO_NOISE_D			0xff000000
+#define	BCCA_DROPOPTION				0x20000
+#define	BCCA_DROPTHRES				0xfff00000
+#define	BEDCCA_H				0xf
+#define	BEDCCA_L				0xf0
+#define	BLAMBDA_ED				0x300
+#define	BRX_INITIALGAIN				0x7f
+#define	BRX_ANTDIV_EN				0x80
+#define	BRX_AGC_ADDRESS_FOR_LNA			0x7f00
+#define	BRX_HIGHPOWER_FLOW			0x8000
+#define	BRX_AGC_FREEZE_THRES			0xc0000
+#define	BRX_FREEZESTEP_AGC1			0x300000
+#define	BRX_FREEZESTEP_AGC2			0xc00000
+#define	BRX_FREEZESTEP_AGC3			0x3000000
+#define	BRX_FREEZESTEP_AGC0			0xc000000
+#define	BRXRSSI_CMP_EN				0x10000000
+#define	BRXQUICK_AGCEN				0x20000000
+#define	BRXAGC_FREEZE_THRES_MODE		0x40000000
+#define	BRX_OVERFLOW_CHECKTYPE			0x80000000
+#define	BRX_AGCSHIFT				0x7f
+#define	BTRSW_TRI_ONLY				0x80
+#define	BPOWER_THRES				0x300
+#define	BRXAGC_EN				0x1
+#define	BRXAGC_TOGETHER_EN			0x2
+#define	BRXAGC_MIN				0x4
+#define	BRXHP_INI				0x7
+#define	BRXHP_TRLNA				0x70
+#define	BRXHP_RSSI				0x700
+#define	BRXHP_BBP1				0x7000
+#define	BRXHP_BBP2				0x70000
+#define	BRXHP_BBP3				0x700000
+#define	BRSSI_H					0x7f0000
+#define	BRSSI_GEN				0x7f000000
+#define	BRXSETTLE_TRSW				0x7
+#define	BRXSETTLE_LNA				0x38
+#define	BRXSETTLE_RSSI				0x1c0
+#define	BRXSETTLE_BBP				0xe00
+#define	BRXSETTLE_RXHP				0x7000
+#define	BRXSETTLE_ANTSW_RSSI			0x38000
+#define	BRXSETTLE_ANTSW				0xc0000
+#define	BRXPROCESS_TIME_DAGC			0x300000
+#define	BRXSETTLE_HSSI				0x400000
+#define	BRXPROCESS_TIME_BBPPW			0x800000
+#define	BRXANTENNA_POWER_SHIFT			0x3000000
+#define	BRSSI_TABLE_SELECT			0xc000000
+#define	BRXHP_FINAL				0x7000000
+#define	BRXHPSETTLE_BBP				0x7
+#define	BRXHTSETTLE_HSSI			0x8
+#define	BRXHTSETTLE_RXHP			0x70
+#define	BRXHTSETTLE_BBPPW			0x80
+#define	BRXHTSETTLE_IDLE			0x300
+#define	BRXHTSETTLE_RESERVED			0x1c00
+#define	BRXHT_RXHP_EN				0x8000
+#define	BRXAGC_FREEZE_THRES			0x30000
+#define	BRXAGC_TOGETHEREN			0x40000
+#define	BRXHTAGC_MIN				0x80000
+#define	BRXHTAGC_EN				0x100000
+#define	BRXHTDAGC_EN				0x200000
+#define	BRXHT_RXHP_BBP				0x1c00000
+#define	BRXHT_RXHP_FINAL			0xe0000000
+#define	BRXPW_RADIO_TH				0x3
+#define	BRXPW_RADIO_EN				0x4
+#define	BRXMF_HOLD				0x3800
+#define	BRXPD_DELAY_TH1				0x38
+#define	BRXPD_DELAY_TH2				0x1c0
+#define	BRXPD_DC_COUNT_MAX			0x600
+#define	BRXPD_DELAY_TH				0x8000
+#define	BRXPROCESS_DELAY			0xf0000
+#define	BRXSEARCHRANGE_GI2_EARLY		0x700000
+#define	BRXFRAME_FUARD_COUNTER_L		0x3800000
+#define	BRXSGI_GUARD_L				0xc000000
+#define	BRXSGI_SEARCH_L				0x30000000
+#define	BRXSGI_TH				0xc0000000
+#define	BDFSCNT0				0xff
+#define	BDFSCNT1				0xff00
+#define	BDFSFLAG				0xf0000
+#define	BMF_WEIGHT_SUM				0x300000
+#define	BMINIDX_TH				0x7f000000
+#define	BDAFORMAT				0x40000
+#define	BTXCH_EMU_ENABLE			0x01000000
+#define	BTRSW_ISOLATION_A			0x7f
+#define	BTRSW_ISOLATION_B			0x7f00
+#define	BTRSW_ISOLATION_C			0x7f0000
+#define	BTRSW_ISOLATION_D			0x7f000000
+#define	BEXT_LNA_GAIN				0x7c00
+
+#define	BSTBC_EN				0x4
+#define	BANTENNA_MAPPING			0x10
+#define	BNSS					0x20
+#define	BCFO_ANTSUM_ID				0x200
+#define	BPHY_COUNTER_RESET			0x8000000
+#define	BCFO_REPORT_GET				0x4000000
+#define	BOFDM_CONTINUE_TX			0x10000000
+#define	BOFDM_SINGLE_CARRIER			0x20000000
+#define	BOFDM_SINGLE_TONE			0x40000000
+#define	BHT_DETECT				0x100
+#define	BCFOEN					0x10000
+#define	BCFOVALUE				0xfff00000
+#define	BSIGTONE_RE				0x3f
+#define	BSIGTONE_IM				0x7f00
+#define	BCOUNTER_CCA				0xffff
+#define	BCOUNTER_PARITYFAIL			0xffff0000
+#define	BCOUNTER_RATEILLEGAL			0xffff
+#define	BCOUNTER_CRC8FAIL			0xffff0000
+#define	BCOUNTER_MCSNOSUPPORT			0xffff
+#define	BCOUNTER_FASTSYNC			0xffff
+#define	BSHORTCFO				0xfff
+#define	BSHORTCFOT_LENGTH			12
+#define	BSHORTCFOF_LENGTH			11
+#define	BLONGCFO				0x7ff
+#define	BLONGCFOT_LENGTH			11
+#define	BLONGCFOF_LENGTH			11
+#define	BTAILCFO				0x1fff
+#define	BTAILCFOT_LENGTH			13
+#define	BTAILCFOF_LENGTH			12
+#define	BNOISE_EN_PWDB				0xffff
+#define	BCC_POWER_DB				0xffff0000
+#define	BMOISE_PWDB				0xffff
+#define	BPOWERMEAST_LENGTH			10
+#define	BPOWERMEASF_LENGTH			3
+#define	BRX_HT_BW				0x1
+#define	BRXSC					0x6
+#define	BRX_HT					0x8
+#define	BNB_INTF_DET_ON				0x1
+#define	BINTF_WIN_LEN_CFG			0x30
+#define	BNB_INTF_TH_CFG				0x1c0
+#define	BRFGAIN					0x3f
+#define	BTABLESEL				0x40
+#define	BTRSW					0x80
+#define	BRXSNR_A				0xff
+#define	BRXSNR_B				0xff00
+#define	BRXSNR_C				0xff0000
+#define	BRXSNR_D				0xff000000
+#define	BSNR_EVMT_LENGTH			8
+#define	BSNR_EVMF_LENGTH			1
+#define	BCSI1ST					0xff
+#define	BCSI2ND					0xff00
+#define	BRXEVM1ST				0xff0000
+#define	BRXEVM2ND				0xff000000
+#define	BSIGEVM					0xff
+#define	BPWDB					0xff00
+#define	BSGIEN					0x10000
+
+#define	BSFACTOR_QMA1				0xf
+#define	BSFACTOR_QMA2				0xf0
+#define	BSFACTOR_QMA3				0xf00
+#define	BSFACTOR_QMA4				0xf000
+#define	BSFACTOR_QMA5				0xf0000
+#define	BSFACTOR_QMA6				0xf0000
+#define	BSFACTOR_QMA7				0xf00000
+#define	BSFACTOR_QMA8				0xf000000
+#define	BSFACTOR_QMA9				0xf0000000
+#define	BCSI_SCHEME				0x100000
+
+#define	BNOISE_LVL_TOP_SET			0x3
+#define	BCHSMOOTH				0x4
+#define	BCHSMOOTH_CFG1				0x38
+#define	BCHSMOOTH_CFG2				0x1c0
+#define	BCHSMOOTH_CFG3				0xe00
+#define	BCHSMOOTH_CFG4				0x7000
+#define	BMRCMODE				0x800000
+#define	BTHEVMCFG				0x7000000
+
+#define	BLOOP_FIT_TYPE				0x1
+#define	BUPD_CFO				0x40
+#define	BUPD_CFO_OFFDATA			0x80
+#define	BADV_UPD_CFO				0x100
+#define	BADV_TIME_CTRL				0x800
+#define	BUPD_CLKO				0x1000
+#define	BFC					0x6000
+#define	BTRACKING_MODE				0x8000
+#define	BPHCMP_ENABLE				0x10000
+#define	BUPD_CLKO_LTF				0x20000
+#define	BCOM_CH_CFO				0x40000
+#define	BCSI_ESTI_MODE				0x80000
+#define	BADV_UPD_EQZ				0x100000
+#define	BUCHCFG					0x7000000
+#define	BUPDEQZ					0x8000000
+
+#define	BRX_PESUDO_NOISE_ON			0x20000000
+#define	BRX_PESUDO_NOISE_A			0xff
+#define	BRX_PESUDO_NOISE_B			0xff00
+#define	BRX_PESUDO_NOISE_C			0xff0000
+#define	BRX_PESUDO_NOISE_D			0xff000000
+#define	BRX_PESUDO_NOISESTATE_A			0xffff
+#define	BRX_PESUDO_NOISESTATE_B			0xffff0000
+#define	BRX_PESUDO_NOISESTATE_C			0xffff
+#define	BRX_PESUDO_NOISESTATE_D			0xffff0000
+
+#define	BZEBRA1_HSSIENABLE			0x8
+#define	BZEBRA1_TRXCONTROL			0xc00
+#define	BZEBRA1_TRXGAINSETTING			0x07f
+#define	BZEBRA1_RXCOUNTER			0xc00
+#define	BZEBRA1_TXCHANGEPUMP			0x38
+#define	BZEBRA1_RXCHANGEPUMP			0x7
+#define	BZEBRA1_CHANNEL_NUM			0xf80
+#define	BZEBRA1_TXLPFBW				0x400
+#define	BZEBRA1_RXLPFBW				0x600
+
+#define	BRTL8256REG_MODE_CTRL1			0x100
+#define	BRTL8256REG_MODE_CTRL0			0x40
+#define	BRTL8256REG_TXLPFBW			0x18
+#define	BRTL8256REG_RXLPFBW			0x600
+
+#define	BRTL8258_TXLPFBW			0xc
+#define	BRTL8258_RXLPFBW			0xc00
+#define	BRTL8258_RSSILPFBW			0xc0
+
+#define	BBYTE0					0x1
+#define	BBYTE1					0x2
+#define	BBYTE2					0x4
+#define	BBYTE3					0x8
+#define	BWORD0					0x3
+#define	BWORD1					0xc
+#define	BWORD					0xf
+
+#define	MASKBYTE0				0xff
+#define	MASKBYTE1				0xff00
+#define	MASKBYTE2				0xff0000
+#define	MASKBYTE3				0xff000000
+#define	MASKHWORD				0xffff0000
+#define	MASKLWORD				0x0000ffff
+#define	MASKDWORD				0xffffffff
+#define	MASK12BITS				0xfff
+#define	MASKH4BITS				0xf0000000
+#define MASKOFDM_D				0xffc00000
+#define	MASKCCK					0x3f3f3f3f
+
+#define	MASK4BITS				0x0f
+#define	MASK20BITS				0xfffff
+#define RFREG_OFFSET_MASK			0xfffff
+
+#define	BENABLE					0x1
+#define	BDISABLE				0x0
+
+#define	LEFT_ANTENNA				0x0
+#define	RIGHT_ANTENNA				0x1
+
+#define	TCHECK_TXSTATUS				500
+#define	TUPDATE_RXCOUNTER			100
+
+#define	REG_UN_used_register			0x01bf
+
+/* WOL bit information */
+#define	HAL92C_WOL_PTK_UPDATE_EVENT		BIT(0)
+#define	HAL92C_WOL_GTK_UPDATE_EVENT		BIT(1)
+#define	HAL92C_WOL_DISASSOC_EVENT		BIT(2)
+#define	HAL92C_WOL_DEAUTH_EVENT			BIT(3)
+#define	HAL92C_WOL_FW_DISCONNECT_EVENT		BIT(4)
+
+#define WOL_REASON_PTK_UPDATE			BIT(0)
+#define WOL_REASON_GTK_UPDATE			BIT(1)
+#define WOL_REASON_DISASSOC			BIT(2)
+#define WOL_REASON_DEAUTH			BIT(3)
+#define WOL_REASON_FW_DISCONNECT		BIT(4)
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/rf.c b/drivers/net/wireless/rtlwifi/rtl8192ee/rf.c
new file mode 100644
index 0000000..c9bc33c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/rf.c
@@ -0,0 +1,152 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+
+static bool _rtl92ee_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
+
+void rtl92ee_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	switch (bandwidth) {
+	case HT_CHANNEL_WIDTH_20:
+		rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+					     0xfffff3ff) | BIT(10) | BIT(11));
+		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+			      rtlphy->rfreg_chnlval[0]);
+		rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, RFREG_OFFSET_MASK,
+			      rtlphy->rfreg_chnlval[0]);
+		break;
+	case HT_CHANNEL_WIDTH_20_40:
+		rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+					     0xfffff3ff) | BIT(10));
+		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+			      rtlphy->rfreg_chnlval[0]);
+		rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, RFREG_OFFSET_MASK,
+			      rtlphy->rfreg_chnlval[0]);
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "unknown bandwidth: %#X\n", bandwidth);
+		break;
+	}
+}
+
+bool rtl92ee_phy_rf6052_config(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	if (rtlphy->rf_type == RF_1T1R)
+		rtlphy->num_total_rfpath = 1;
+	else
+		rtlphy->num_total_rfpath = 2;
+
+	return _rtl92ee_phy_rf6052_config_parafile(hw);
+}
+
+static bool _rtl92ee_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u32 u4_regvalue = 0;
+	u8 rfpath;
+	bool rtstatus = true;
+	struct bb_reg_def *pphyreg;
+
+	for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
+		pphyreg = &rtlphy->phyreg_def[rfpath];
+
+		switch (rfpath) {
+		case RF90_PATH_A:
+		case RF90_PATH_C:
+			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
+						    BRFSI_RFENV);
+			break;
+		case RF90_PATH_B:
+		case RF90_PATH_D:
+			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
+						    BRFSI_RFENV << 16);
+			break;
+		}
+
+		rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1);
+		udelay(1);
+
+		rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
+		udelay(1);
+
+		rtl_set_bbreg(hw, pphyreg->rfhssi_para2,
+			      B3WIREADDREAALENGTH, 0x0);
+		udelay(1);
+
+		rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0);
+		udelay(1);
+
+		switch (rfpath) {
+		case RF90_PATH_A:
+			rtstatus = rtl92ee_phy_config_rf_with_headerfile(hw,
+						       (enum radio_path)rfpath);
+			break;
+		case RF90_PATH_B:
+			rtstatus = rtl92ee_phy_config_rf_with_headerfile(hw,
+						       (enum radio_path)rfpath);
+			break;
+		case RF90_PATH_C:
+			break;
+		case RF90_PATH_D:
+			break;
+		}
+
+		switch (rfpath) {
+		case RF90_PATH_A:
+		case RF90_PATH_C:
+			rtl_set_bbreg(hw, pphyreg->rfintfs,
+				      BRFSI_RFENV, u4_regvalue);
+			break;
+		case RF90_PATH_B:
+		case RF90_PATH_D:
+			rtl_set_bbreg(hw, pphyreg->rfintfs,
+				      BRFSI_RFENV << 16, u4_regvalue);
+			break;
+		}
+
+		if (!rtstatus) {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+				 "Radio[%d] Fail!!", rfpath);
+			return false;
+		}
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
+	return rtstatus;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/rf.h b/drivers/net/wireless/rtlwifi/rtl8192ee/rf.h
new file mode 100644
index 0000000..8bdeed3
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/rf.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92E_RF_H__
+#define __RTL92E_RF_H__
+
+#define RF6052_MAX_TX_PWR		0x3F
+#define RF6052_MAX_REG			0x3F
+
+void rtl92ee_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+				      u8 bandwidth);
+bool rtl92ee_phy_rf6052_config(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c
new file mode 100644
index 0000000..9b5a7d5
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c
@@ -0,0 +1,399 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../core.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "hw.h"
+#include "sw.h"
+#include "fw.h"
+#include "trx.h"
+#include "led.h"
+#include "table.h"
+
+#include "../btcoexist/rtl_btc.h"
+
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+
+static void rtl92ee_init_aspm_vars(struct ieee80211_hw *hw)
+{
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	/*close ASPM for AMD defaultly */
+	rtlpci->const_amdpci_aspm = 0;
+
+	/**
+	 * ASPM PS mode.
+	 * 0 - Disable ASPM,
+	 * 1 - Enable ASPM without Clock Req,
+	 * 2 - Enable ASPM with Clock Req,
+	 * 3 - Alwyas Enable ASPM with Clock Req,
+	 * 4 - Always Enable ASPM without Clock Req.
+	 * set defult to RTL8192CE:3 RTL8192E:2
+	 */
+	rtlpci->const_pci_aspm = 3;
+
+	/*Setting for PCI-E device */
+	rtlpci->const_devicepci_aspm_setting = 0x03;
+
+	/*Setting for PCI-E bridge */
+	rtlpci->const_hostpci_aspm_setting = 0x02;
+
+	/**
+	 * In Hw/Sw Radio Off situation.
+	 * 0 - Default,
+	 * 1 - From ASPM setting without low Mac Pwr,
+	 * 2 - From ASPM setting with low Mac Pwr,
+	 * 3 - Bus D3
+	 * set default to RTL8192CE:0 RTL8192SE:2
+	 */
+	rtlpci->const_hwsw_rfoff_d3 = 0;
+
+	/**
+	 * This setting works for those device with
+	 * backdoor ASPM setting such as EPHY setting.
+	 * 0 - Not support ASPM,
+	 * 1 - Support ASPM,
+	 * 2 - According to chipset.
+	 */
+	rtlpci->const_support_pciaspm = 1;
+}
+
+int rtl92ee_init_sw_vars(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	int err = 0;
+
+	rtl92ee_bt_reg_init(hw);
+	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
+	rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer();
+
+	rtlpriv->dm.dm_initialgain_enable = 1;
+	rtlpriv->dm.dm_flag = 0;
+	rtlpriv->dm.disable_framebursting = 0;
+	rtlpci->transmit_config = CFENDFORM | BIT(15);
+
+	/*just 2.4G band*/
+	rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G;
+	rtlpriv->rtlhal.bandset = BAND_ON_2_4G;
+	rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY;
+
+	rtlpci->receive_config = (RCR_APPFCS			|
+				  RCR_APP_MIC			|
+				  RCR_APP_ICV			|
+				  RCR_APP_PHYST_RXFF		|
+				  RCR_HTC_LOC_CTRL		|
+				  RCR_AMF			|
+				  RCR_ACF			|
+				  RCR_ADF			|
+				  RCR_AICV			|
+				  RCR_ACRC32			|
+				  RCR_AB			|
+				  RCR_AM			|
+				  RCR_APM			|
+				  0);
+
+	rtlpci->irq_mask[0] = (u32)(IMR_PSTIMEOUT		|
+				     IMR_C2HCMD			|
+				     IMR_HIGHDOK		|
+				     IMR_MGNTDOK		|
+				     IMR_BKDOK			|
+				     IMR_BEDOK			|
+				     IMR_VIDOK			|
+				     IMR_VODOK			|
+				     IMR_RDU			|
+				     IMR_ROK			|
+				     0);
+	rtlpci->irq_mask[1] = (u32)(IMR_RXFOVW | 0);
+
+	/* for debug level */
+	rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
+	/* for LPS & IPS */
+	rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
+	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
+	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
+	if (rtlpriv->cfg->mod_params->disable_watchdog)
+		pr_info("watchdog disabled\n");
+	rtlpriv->psc.reg_fwctrl_lps = 3;
+	rtlpriv->psc.reg_max_lps_awakeintvl = 5;
+	/* for ASPM, you can close aspm through
+	 * set const_support_pciaspm = 0
+	 */
+	rtl92ee_init_aspm_vars(hw);
+
+	if (rtlpriv->psc.reg_fwctrl_lps == 1)
+		rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE;
+	else if (rtlpriv->psc.reg_fwctrl_lps == 2)
+		rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE;
+	else if (rtlpriv->psc.reg_fwctrl_lps == 3)
+		rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
+
+	/* for early mode */
+	rtlpriv->rtlhal.earlymode_enable = false;
+
+	/*low power */
+	rtlpriv->psc.low_power_enable = false;
+
+	/* for firmware buf */
+	rtlpriv->rtlhal.pfirmware = vzalloc(0x8000);
+	if (!rtlpriv->rtlhal.pfirmware) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Can't alloc buffer for fw\n");
+		return 1;
+	}
+
+	/* request fw */
+	rtlpriv->cfg->fw_name = "rtlwifi/rtl8192eefw.bin";
+
+	rtlpriv->max_fw_size = 0x8000;
+	pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
+	err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+				      rtlpriv->io.dev, GFP_KERNEL, hw,
+				      rtl_fw_cb);
+	if (err) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Failed to request firmware!\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+void rtl92ee_deinit_sw_vars(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (rtlpriv->rtlhal.pfirmware) {
+		vfree(rtlpriv->rtlhal.pfirmware);
+		rtlpriv->rtlhal.pfirmware = NULL;
+	}
+}
+
+/* get bt coexist status */
+bool rtl92ee_get_btc_status(void)
+{
+	return true;
+}
+
+static struct rtl_hal_ops rtl8192ee_hal_ops = {
+	.init_sw_vars = rtl92ee_init_sw_vars,
+	.deinit_sw_vars = rtl92ee_deinit_sw_vars,
+	.read_eeprom_info = rtl92ee_read_eeprom_info,
+	.interrupt_recognized = rtl92ee_interrupt_recognized,/*need check*/
+	.hw_init = rtl92ee_hw_init,
+	.hw_disable = rtl92ee_card_disable,
+	.hw_suspend = rtl92ee_suspend,
+	.hw_resume = rtl92ee_resume,
+	.enable_interrupt = rtl92ee_enable_interrupt,
+	.disable_interrupt = rtl92ee_disable_interrupt,
+	.set_network_type = rtl92ee_set_network_type,
+	.set_chk_bssid = rtl92ee_set_check_bssid,
+	.set_qos = rtl92ee_set_qos,
+	.set_bcn_reg = rtl92ee_set_beacon_related_registers,
+	.set_bcn_intv = rtl92ee_set_beacon_interval,
+	.update_interrupt_mask = rtl92ee_update_interrupt_mask,
+	.get_hw_reg = rtl92ee_get_hw_reg,
+	.set_hw_reg = rtl92ee_set_hw_reg,
+	.update_rate_tbl = rtl92ee_update_hal_rate_tbl,
+	.pre_fill_tx_bd_desc = rtl92ee_pre_fill_tx_bd_desc,
+	.rx_desc_buff_remained_cnt = rtl92ee_rx_desc_buff_remained_cnt,
+	.rx_check_dma_ok = rtl92ee_rx_check_dma_ok,
+	.fill_tx_desc = rtl92ee_tx_fill_desc,
+	.fill_tx_cmddesc = rtl92ee_tx_fill_cmddesc,
+	.query_rx_desc = rtl92ee_rx_query_desc,
+	.set_channel_access = rtl92ee_update_channel_access_setting,
+	.radio_onoff_checking = rtl92ee_gpio_radio_on_off_checking,
+	.set_bw_mode = rtl92ee_phy_set_bw_mode,
+	.switch_channel = rtl92ee_phy_sw_chnl,
+	.dm_watchdog = rtl92ee_dm_watchdog,
+	.scan_operation_backup = rtl92ee_phy_scan_operation_backup,
+	.set_rf_power_state = rtl92ee_phy_set_rf_power_state,
+	.led_control = rtl92ee_led_control,
+	.set_desc = rtl92ee_set_desc,
+	.get_desc = rtl92ee_get_desc,
+	.is_tx_desc_closed = rtl92ee_is_tx_desc_closed,
+	.tx_polling = rtl92ee_tx_polling,
+	.enable_hw_sec = rtl92ee_enable_hw_security_config,
+	.set_key = rtl92ee_set_key,
+	.init_sw_leds = rtl92ee_init_sw_leds,
+	.get_bbreg = rtl92ee_phy_query_bb_reg,
+	.set_bbreg = rtl92ee_phy_set_bb_reg,
+	.get_rfreg = rtl92ee_phy_query_rf_reg,
+	.set_rfreg = rtl92ee_phy_set_rf_reg,
+	.fill_h2c_cmd = rtl92ee_fill_h2c_cmd,
+	.get_btc_status = rtl92ee_get_btc_status,
+	.rx_command_packet = rtl92ee_rx_command_packet,
+};
+
+static struct rtl_mod_params rtl92ee_mod_params = {
+	.sw_crypto = false,
+	.inactiveps = false,
+	.swctrl_lps = false,
+	.fwctrl_lps = true,
+	.msi_support = true,
+	.debug = DBG_EMERG,
+};
+
+static struct rtl_hal_cfg rtl92ee_hal_cfg = {
+	.bar_id = 2,
+	.write_readback = true,
+	.name = "rtl92ee_pci",
+	.fw_name = "rtlwifi/rtl8192eefw.bin",
+	.ops = &rtl8192ee_hal_ops,
+	.mod_params = &rtl92ee_mod_params,
+
+	.maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
+	.maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN,
+	.maps[SYS_CLK] = REG_SYS_CLKR,
+	.maps[MAC_RCR_AM] = AM,
+	.maps[MAC_RCR_AB] = AB,
+	.maps[MAC_RCR_ACRC32] = ACRC32,
+	.maps[MAC_RCR_ACF] = ACF,
+	.maps[MAC_RCR_AAP] = AAP,
+	.maps[MAC_HIMR] = REG_HIMR,
+	.maps[MAC_HIMRE] = REG_HIMRE,
+
+	.maps[EFUSE_ACCESS] = REG_EFUSE_ACCESS,
+
+	.maps[EFUSE_TEST] = REG_EFUSE_TEST,
+	.maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
+	.maps[EFUSE_CLK] = 0,
+	.maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL,
+	.maps[EFUSE_PWC_EV12V] = PWC_EV12V,
+	.maps[EFUSE_FEN_ELDR] = FEN_ELDR,
+	.maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN,
+	.maps[EFUSE_ANA8M] = ANA8M,
+	.maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE,
+	.maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
+	.maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
+	.maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES,
+
+	.maps[RWCAM] = REG_CAMCMD,
+	.maps[WCAMI] = REG_CAMWRITE,
+	.maps[RCAMO] = REG_CAMREAD,
+	.maps[CAMDBG] = REG_CAMDBG,
+	.maps[SECR] = REG_SECCFG,
+	.maps[SEC_CAM_NONE] = CAM_NONE,
+	.maps[SEC_CAM_WEP40] = CAM_WEP40,
+	.maps[SEC_CAM_TKIP] = CAM_TKIP,
+	.maps[SEC_CAM_AES] = CAM_AES,
+	.maps[SEC_CAM_WEP104] = CAM_WEP104,
+
+	.maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6,
+	.maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5,
+	.maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4,
+	.maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3,
+	.maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2,
+	.maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1,
+	.maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7,
+	.maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6,
+	.maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5,
+	.maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4,
+	.maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3,
+	.maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2,
+	.maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1,
+
+	.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
+	.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
+	.maps[RTL_IMR_BCNINT] = IMR_BCNDMAINT0,
+	.maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
+	.maps[RTL_IMR_RDU] = IMR_RDU,
+	.maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
+	.maps[RTL_IMR_BDOK] = IMR_BCNDOK0,
+	.maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK,
+	.maps[RTL_IMR_TBDER] = IMR_TBDER,
+	.maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK,
+	.maps[RTL_IMR_TBDOK] = IMR_TBDOK,
+	.maps[RTL_IMR_BKDOK] = IMR_BKDOK,
+	.maps[RTL_IMR_BEDOK] = IMR_BEDOK,
+	.maps[RTL_IMR_VIDOK] = IMR_VIDOK,
+	.maps[RTL_IMR_VODOK] = IMR_VODOK,
+	.maps[RTL_IMR_ROK] = IMR_ROK,
+	.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNDMAINT0 | IMR_TBDOK | IMR_TBDER),
+
+	.maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
+	.maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M,
+	.maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M,
+	.maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M,
+	.maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M,
+	.maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M,
+	.maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M,
+	.maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M,
+	.maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M,
+	.maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M,
+	.maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M,
+	.maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M,
+
+	.maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7,
+	.maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
+};
+
+static struct pci_device_id rtl92ee_pci_ids[] = {
+	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x818B, rtl92ee_hal_cfg)},
+	{},
+};
+
+MODULE_DEVICE_TABLE(pci, rtl92ee_pci_ids);
+
+MODULE_AUTHOR("Realtek WlanFAE	<wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger	<Larry.Finger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 8192EE 802.11n PCI wireless");
+MODULE_FIRMWARE("rtlwifi/rtl8192eefw.bin");
+
+module_param_named(swenc, rtl92ee_mod_params.sw_crypto, bool, 0444);
+module_param_named(debug, rtl92ee_mod_params.debug, int, 0444);
+module_param_named(ips, rtl92ee_mod_params.inactiveps, bool, 0444);
+module_param_named(swlps, rtl92ee_mod_params.swctrl_lps, bool, 0444);
+module_param_named(fwlps, rtl92ee_mod_params.fwctrl_lps, bool, 0444);
+module_param_named(msi, rtl92ee_mod_params.msi_support, bool, 0444);
+module_param_named(disable_watchdog, rtl92ee_mod_params.disable_watchdog,
+		   bool, 0444);
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
+MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 1)\n");
+MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n");
+
+static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
+
+static struct pci_driver rtl92ee_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = rtl92ee_pci_ids,
+	.probe = rtl_pci_probe,
+	.remove = rtl_pci_disconnect,
+	.driver.pm = &rtlwifi_pm_ops,
+};
+
+module_pci_driver(rtl92ee_driver);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/sw.h b/drivers/net/wireless/rtlwifi/rtl8192ee/sw.h
new file mode 100644
index 0000000..21433d0
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/sw.h
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92E_SW_H__
+#define __RTL92E_SW_H__
+
+int rtl92ee_init_sw_vars(struct ieee80211_hw *hw);
+void rtl92ee_deinit_sw_vars(struct ieee80211_hw *hw);
+bool rtl92ee_get_btc_status(void);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/table.c b/drivers/net/wireless/rtlwifi/rtl8192ee/table.c
new file mode 100644
index 0000000..abcdd06
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/table.c
@@ -0,0 +1,882 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on  2010/ 5/18,  1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "table.h"
+u32 RTL8192EE_PHY_REG_ARRAY[] = {
+		0x800, 0x80040000,
+		0x804, 0x00000003,
+		0x808, 0x0000FC00,
+		0x80C, 0x0000000A,
+		0x810, 0x10001331,
+		0x814, 0x020C3D10,
+		0x818, 0x02220385,
+		0x81C, 0x00000000,
+		0x820, 0x01000100,
+		0x824, 0x00390204,
+		0x828, 0x01000100,
+		0x82C, 0x00390204,
+		0x830, 0x32323232,
+		0x834, 0x30303030,
+		0x838, 0x30303030,
+		0x83C, 0x30303030,
+		0x840, 0x00010000,
+		0x844, 0x00010000,
+		0x848, 0x28282828,
+		0x84C, 0x28282828,
+		0x850, 0x00000000,
+		0x854, 0x00000000,
+		0x858, 0x009A009A,
+		0x85C, 0x01000014,
+		0x860, 0x66F60000,
+		0x864, 0x061F0000,
+		0x868, 0x30303030,
+		0x86C, 0x30303030,
+		0x870, 0x00000000,
+		0x874, 0x55004200,
+		0x878, 0x08080808,
+		0x87C, 0x00000000,
+		0x880, 0xB0000C1C,
+		0x884, 0x00000001,
+		0x888, 0x00000000,
+		0x88C, 0xCC0000C0,
+		0x890, 0x00000800,
+		0x894, 0xFFFFFFFE,
+		0x898, 0x40302010,
+		0x900, 0x00000000,
+		0x904, 0x00000023,
+		0x908, 0x00000000,
+		0x90C, 0x81121313,
+		0x910, 0x806C0001,
+		0x914, 0x00000001,
+		0x918, 0x00000000,
+		0x91C, 0x00010000,
+		0x924, 0x00000001,
+		0x928, 0x00000000,
+		0x92C, 0x00000000,
+		0x930, 0x00000000,
+		0x934, 0x00000000,
+		0x938, 0x00000000,
+		0x93C, 0x00000000,
+		0x940, 0x00000000,
+		0x944, 0x00000000,
+		0x94C, 0x00000008,
+		0xA00, 0x00D0C7C8,
+		0xA04, 0x81FF000C,
+		0xA08, 0x8C838300,
+		0xA0C, 0x2E68120F,
+		0xA10, 0x95009B78,
+		0xA14, 0x1114D028,
+		0xA18, 0x00881117,
+		0xA1C, 0x89140F00,
+		0xA20, 0x1A1B0000,
+		0xA24, 0x090E1317,
+		0xA28, 0x00000204,
+		0xA2C, 0x00D30000,
+		0xA70, 0x101FBF00,
+		0xA74, 0x00000007,
+		0xA78, 0x00000900,
+		0xA7C, 0x225B0606,
+		0xA80, 0x218075B1,
+		0xB38, 0x00000000,
+		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, 0x69E9AC47,
+		0xC34, 0x469652AF,
+		0xC38, 0x49795994,
+		0xC3C, 0x0A97971C,
+		0xC40, 0x1F7C403F,
+		0xC44, 0x000100B7,
+		0xC48, 0xEC020107,
+		0xC4C, 0x007F037F,
+	0xFF010718, 0xABCD,
+		0xC50, 0x00340220,
+	0xCDCDCDCD, 0xCDCD,
+		0xC50, 0x00340020,
+	0xFF010718, 0xDEAD,
+		0xC54, 0x0080801F,
+	0xFF010718, 0xABCD,
+		0xC58, 0x00000220,
+	0xCDCDCDCD, 0xCDCD,
+		0xC58, 0x00000020,
+	0xFF010718, 0xDEAD,
+		0xC5C, 0x00248492,
+		0xC60, 0x00000000,
+		0xC64, 0x7112848B,
+		0xC68, 0x47C00BFF,
+		0xC6C, 0x00000036,
+		0xC70, 0x00000600,
+		0xC74, 0x02013169,
+		0xC78, 0x0000001F,
+		0xC7C, 0x00B91612,
+	0xFF010718, 0xABCD,
+		0xC80, 0x2D4000B5,
+	0xCDCDCDCD, 0xCDCD,
+		0xC80, 0x40000100,
+	0xFF010718, 0xDEAD,
+		0xC84, 0x21F60000,
+	0xFF010718, 0xABCD,
+		0xC88, 0x2D4000B5,
+	0xCDCDCDCD, 0xCDCD,
+		0xC88, 0x40000100,
+	0xFF010718, 0xDEAD,
+		0xC8C, 0xA0E40000,
+		0xC90, 0x00121820,
+		0xC94, 0x00000000,
+		0xC98, 0x00121820,
+		0xC9C, 0x00007F7F,
+		0xCA0, 0x00000000,
+		0xCA4, 0x000300A0,
+		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, 0x00040000,
+		0xCE8, 0x77644302,
+		0xCEC, 0x2F97D40C,
+		0xD00, 0x00080740,
+		0xD04, 0x00020403,
+		0xD08, 0x0000907F,
+		0xD0C, 0x20010201,
+		0xD10, 0xA0633333,
+		0xD14, 0x3333BC43,
+		0xD18, 0x7A8F5B6B,
+		0xD1C, 0x0000007F,
+		0xD2C, 0xCC979975,
+		0xD30, 0x00000000,
+		0xD34, 0x80608000,
+		0xD38, 0x00000000,
+		0xD3C, 0x00127353,
+		0xD40, 0x00000000,
+		0xD44, 0x00000000,
+		0xD48, 0x00000000,
+		0xD4C, 0x00000000,
+		0xD50, 0x6437140A,
+		0xD54, 0x00000000,
+		0xD58, 0x00000282,
+		0xD5C, 0x30032064,
+		0xD60, 0x4653DE68,
+		0xD64, 0x04518A3C,
+		0xD68, 0x00002101,
+		0xD6C, 0x2A201C16,
+		0xD70, 0x1812362E,
+		0xD74, 0x322C2220,
+		0xD78, 0x000E3C24,
+		0xD80, 0x01081008,
+		0xD84, 0x00000800,
+		0xD88, 0xF0B50000,
+		0xE00, 0x30303030,
+		0xE04, 0x30303030,
+		0xE08, 0x03903030,
+		0xE10, 0x30303030,
+		0xE14, 0x30303030,
+		0xE18, 0x30303030,
+		0xE1C, 0x30303030,
+		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, 0x0FC05656,
+		0xE6C, 0x03C09696,
+		0xE70, 0x03C09696,
+		0xE74, 0x0C005656,
+		0xE78, 0x0C005656,
+		0xE7C, 0x0C005656,
+		0xE80, 0x0C005656,
+		0xE84, 0x03C09696,
+		0xE88, 0x0C005656,
+		0xE8C, 0x03C09696,
+		0xED0, 0x03C09696,
+		0xED4, 0x03C09696,
+		0xED8, 0x03C09696,
+		0xEDC, 0x0000D6D6,
+		0xEE0, 0x0000D6D6,
+		0xEEC, 0x0FC01616,
+		0xEE4, 0xB0000C1C,
+		0xEE8, 0x00000001,
+		0xF14, 0x00000003,
+		0xF4C, 0x00000000,
+		0xF00, 0x00000300,
+};
+
+u32 RTL8192EE_PHY_REG_ARRAY_PG[] = {
+	0, 0, 0, 0x00000e08, 0x0000ff00, 0x00003200,
+	0, 0, 1, 0x00000e08, 0x0000ff00, 0x00003200,
+	0, 0, 0, 0x0000086c, 0xffffff00, 0x32323200,
+	0, 0, 1, 0x0000086c, 0xffffff00, 0x32323200,
+	0, 0, 0, 0x00000e00, 0xffffffff, 0x34343636,
+	0, 0, 1, 0x00000e00, 0xffffffff, 0x34343636,
+	0, 0, 0, 0x00000e04, 0xffffffff, 0x28283032,
+	0, 0, 1, 0x00000e04, 0xffffffff, 0x28283032,
+	0, 0, 0, 0x00000e10, 0xffffffff, 0x34363840,
+	0, 0, 1, 0x00000e10, 0xffffffff, 0x34363840,
+	0, 0, 0, 0x00000e14, 0xffffffff, 0x26283032,
+	0, 0, 1, 0x00000e14, 0xffffffff, 0x26283032,
+	0, 0, 1, 0x00000e18, 0xffffffff, 0x36384040,
+	0, 0, 1, 0x00000e1c, 0xffffffff, 0x24262832,
+	0, 1, 0, 0x00000838, 0xffffff00, 0x32323200,
+	0, 1, 1, 0x00000838, 0xffffff00, 0x32323200,
+	0, 1, 0, 0x0000086c, 0x000000ff, 0x00000032,
+	0, 1, 1, 0x0000086c, 0x000000ff, 0x00000032,
+	0, 1, 0, 0x00000830, 0xffffffff, 0x34343636,
+	0, 1, 1, 0x00000830, 0xffffffff, 0x34343636,
+	0, 1, 0, 0x00000834, 0xffffffff, 0x28283032,
+	0, 1, 1, 0x00000834, 0xffffffff, 0x28283032,
+	0, 1, 0, 0x0000083c, 0xffffffff, 0x34363840,
+	0, 1, 1, 0x0000083c, 0xffffffff, 0x34363840,
+	0, 1, 0, 0x00000848, 0xffffffff, 0x26283032,
+	0, 1, 1, 0x00000848, 0xffffffff, 0x26283032,
+	0, 1, 1, 0x0000084c, 0xffffffff, 0x36384040,
+	0, 1, 1, 0x00000868, 0xffffffff, 0x24262832
+};
+
+u32 RTL8192EE_RADIOA_ARRAY[] = {
+		0x07F, 0x00000082,
+		0x081, 0x0003FC00,
+		0x000, 0x00030000,
+		0x008, 0x00008400,
+		0x018, 0x00000407,
+		0x019, 0x00000012,
+		0x01B, 0x00000064,
+		0x01E, 0x00080009,
+		0x01F, 0x00000880,
+		0x02F, 0x0001A060,
+		0x03F, 0x00000000,
+		0x042, 0x000060C0,
+		0x057, 0x000D0000,
+		0x058, 0x000BE180,
+		0x067, 0x00001552,
+		0x083, 0x00000000,
+		0x0B0, 0x000FF9F1,
+		0x0B1, 0x00055418,
+		0x0B2, 0x0008CC00,
+		0x0B4, 0x00043083,
+		0x0B5, 0x00008166,
+		0x0B6, 0x0000803E,
+		0x0B7, 0x0001C69F,
+		0x0B8, 0x0000407F,
+		0x0B9, 0x00080001,
+		0x0BA, 0x00040001,
+		0x0BB, 0x00000400,
+		0x0BF, 0x000C0000,
+		0x0C2, 0x00002400,
+		0x0C3, 0x00000009,
+		0x0C4, 0x00040C91,
+		0x0C5, 0x00099999,
+		0x0C6, 0x000000A3,
+		0x0C7, 0x00088820,
+		0x0C8, 0x00076C06,
+		0x0C9, 0x00000000,
+		0x0CA, 0x00080000,
+		0x0DF, 0x00000180,
+		0x0EF, 0x000001A0,
+		0x051, 0x00069545,
+		0x052, 0x0007E45E,
+		0x053, 0x00000071,
+		0x056, 0x00051FF3,
+		0x035, 0x000000A8,
+		0x035, 0x000001E2,
+		0x035, 0x000002A8,
+		0x036, 0x00001C24,
+		0x036, 0x00009C24,
+		0x036, 0x00011C24,
+		0x036, 0x00019C24,
+		0x018, 0x00000C07,
+		0x05A, 0x00048000,
+		0x019, 0x000739D0,
+	0xFF010718, 0xABCD,
+		0x034, 0x0000A093,
+		0x034, 0x0000908F,
+		0x034, 0x0000808C,
+		0x034, 0x0000704D,
+		0x034, 0x0000604A,
+		0x034, 0x00005047,
+		0x034, 0x0000400A,
+		0x034, 0x00003007,
+		0x034, 0x00002004,
+		0x034, 0x00001001,
+		0x034, 0x00000000,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0000ADD7,
+		0x034, 0x00009DD4,
+		0x034, 0x00008DD1,
+		0x034, 0x00007DCE,
+		0x034, 0x00006DCB,
+		0x034, 0x00005DC8,
+		0x034, 0x00004DC5,
+		0x034, 0x000034CC,
+		0x034, 0x0000244F,
+		0x034, 0x0000144C,
+		0x034, 0x00000014,
+	0xFF010718, 0xDEAD,
+		0x000, 0x00030159,
+		0x084, 0x00068180,
+		0x086, 0x0000014E,
+		0x087, 0x00048E00,
+		0x08E, 0x00065540,
+		0x08F, 0x00088000,
+		0x0EF, 0x000020A0,
+	0xFF010718, 0xABCD,
+		0x03B, 0x000F07B0,
+	0xCDCDCDCD, 0xCDCD,
+		0x03B, 0x000F02B0,
+	0xFF010718, 0xDEAD,
+		0x03B, 0x000EF7B0,
+		0x03B, 0x000D4FB0,
+		0x03B, 0x000CF060,
+		0x03B, 0x000B0090,
+		0x03B, 0x000A0080,
+		0x03B, 0x00090080,
+		0x03B, 0x0008F780,
+	0xFF010718, 0xABCD,
+		0x03B, 0x000787B0,
+	0xCDCDCDCD, 0xCDCD,
+		0x03B, 0x00078730,
+	0xFF010718, 0xDEAD,
+		0x03B, 0x00060FB0,
+		0x03B, 0x0005FFA0,
+		0x03B, 0x00040620,
+		0x03B, 0x00037090,
+		0x03B, 0x00020080,
+		0x03B, 0x0001F060,
+		0x03B, 0x0000FFB0,
+		0x0EF, 0x000000A0,
+		0x0FE, 0x00000000,
+		0x018, 0x0000FC07,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x01E, 0x00000001,
+		0x01F, 0x00080000,
+		0x000, 0x00033E70,
+};
+
+u32 RTL8192EE_RADIOB_ARRAY[] = {
+		0x07F, 0x00000082,
+		0x081, 0x0003FC00,
+		0x000, 0x00030000,
+		0x008, 0x00008400,
+		0x018, 0x00000407,
+		0x019, 0x00000012,
+		0x01B, 0x00000064,
+		0x01E, 0x00080009,
+		0x01F, 0x00000880,
+		0x02F, 0x0001A060,
+		0x03F, 0x00000000,
+		0x042, 0x000060C0,
+		0x057, 0x000D0000,
+		0x058, 0x000BE180,
+		0x067, 0x00001552,
+		0x07F, 0x00000082,
+		0x081, 0x0003F000,
+		0x083, 0x00000000,
+		0x0DF, 0x00000180,
+		0x0EF, 0x000001A0,
+		0x051, 0x00069545,
+		0x052, 0x0007E42E,
+		0x053, 0x00000071,
+		0x056, 0x00051FF3,
+		0x035, 0x000000A8,
+		0x035, 0x000001E0,
+		0x035, 0x000002A8,
+		0x036, 0x00001CA8,
+		0x036, 0x00009C24,
+		0x036, 0x00011C24,
+		0x036, 0x00019C24,
+		0x018, 0x00000C07,
+		0x05A, 0x00048000,
+		0x019, 0x000739D0,
+	0xFF010718, 0xABCD,
+		0x034, 0x0000A093,
+		0x034, 0x0000908F,
+		0x034, 0x0000808C,
+		0x034, 0x0000704D,
+		0x034, 0x0000604A,
+		0x034, 0x00005047,
+		0x034, 0x0000400A,
+		0x034, 0x00003007,
+		0x034, 0x00002004,
+		0x034, 0x00001001,
+		0x034, 0x00000000,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0000ADD7,
+		0x034, 0x00009DD4,
+		0x034, 0x00008DD1,
+		0x034, 0x00007DCE,
+		0x034, 0x00006DCB,
+		0x034, 0x00005DC8,
+		0x034, 0x00004DC5,
+		0x034, 0x000034CC,
+		0x034, 0x0000244F,
+		0x034, 0x0000144C,
+		0x034, 0x00000014,
+	0xFF010718, 0xDEAD,
+		0x000, 0x00030159,
+		0x084, 0x00068180,
+		0x086, 0x000000CE,
+		0x087, 0x00048A00,
+		0x08E, 0x00065540,
+		0x08F, 0x00088000,
+		0x0EF, 0x000020A0,
+	0xFF010718, 0xABCD,
+		0x03B, 0x000F07B0,
+	0xCDCDCDCD, 0xCDCD,
+		0x03B, 0x000F02B0,
+	0xFF010718, 0xDEAD,
+		0x03B, 0x000EF7B0,
+		0x03B, 0x000D4FB0,
+		0x03B, 0x000CF060,
+		0x03B, 0x000B0090,
+		0x03B, 0x000A0080,
+		0x03B, 0x00090080,
+		0x03B, 0x0008F780,
+	0xFF010718, 0xABCD,
+		0x03B, 0x000787B0,
+	0xCDCDCDCD, 0xCDCD,
+		0x03B, 0x00078730,
+	0xFF010718, 0xDEAD,
+		0x03B, 0x00060FB0,
+		0x03B, 0x0005FFA0,
+		0x03B, 0x00040620,
+		0x03B, 0x00037090,
+		0x03B, 0x00020080,
+		0x03B, 0x0001F060,
+		0x03B, 0x0000FFB0,
+		0x0EF, 0x000000A0,
+		0x000, 0x00010159,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x01E, 0x00000001,
+		0x01F, 0x00080000,
+		0x000, 0x00033E70,
+};
+
+u32 RTL8192EE_MAC_ARRAY[] = {
+		0x011, 0x000000EB,
+		0x012, 0x00000007,
+		0x014, 0x00000075,
+		0x303, 0x000000A7,
+		0x428, 0x0000000A,
+		0x429, 0x00000010,
+		0x430, 0x00000000,
+		0x431, 0x00000000,
+		0x432, 0x00000000,
+		0x433, 0x00000001,
+		0x434, 0x00000004,
+		0x435, 0x00000005,
+		0x436, 0x00000007,
+		0x437, 0x00000008,
+		0x43C, 0x00000004,
+		0x43D, 0x00000005,
+		0x43E, 0x00000007,
+		0x43F, 0x00000008,
+		0x440, 0x0000005D,
+		0x441, 0x00000001,
+		0x442, 0x00000000,
+		0x444, 0x00000010,
+		0x445, 0x00000000,
+		0x446, 0x00000000,
+		0x447, 0x00000000,
+		0x448, 0x00000000,
+		0x449, 0x000000F0,
+		0x44A, 0x0000000F,
+		0x44B, 0x0000003E,
+		0x44C, 0x00000010,
+		0x44D, 0x00000000,
+		0x44E, 0x00000000,
+		0x44F, 0x00000000,
+		0x450, 0x00000000,
+		0x451, 0x000000F0,
+		0x452, 0x0000000F,
+		0x453, 0x00000000,
+		0x456, 0x0000005E,
+		0x460, 0x00000066,
+		0x461, 0x00000066,
+		0x4C8, 0x000000FF,
+		0x4C9, 0x00000008,
+		0x4CC, 0x000000FF,
+		0x4CD, 0x000000FF,
+		0x4CE, 0x00000001,
+		0x500, 0x00000026,
+		0x501, 0x000000A2,
+		0x502, 0x0000002F,
+		0x503, 0x00000000,
+		0x504, 0x00000028,
+		0x505, 0x000000A3,
+		0x506, 0x0000005E,
+		0x507, 0x00000000,
+		0x508, 0x0000002B,
+		0x509, 0x000000A4,
+		0x50A, 0x0000005E,
+		0x50B, 0x00000000,
+		0x50C, 0x0000004F,
+		0x50D, 0x000000A4,
+		0x50E, 0x00000000,
+		0x50F, 0x00000000,
+		0x512, 0x0000001C,
+		0x514, 0x0000000A,
+		0x516, 0x0000000A,
+		0x525, 0x0000004F,
+		0x540, 0x00000012,
+		0x541, 0x00000064,
+		0x550, 0x00000010,
+		0x551, 0x00000010,
+		0x559, 0x00000002,
+		0x55C, 0x00000050,
+		0x55D, 0x000000FF,
+		0x605, 0x00000030,
+		0x608, 0x0000000E,
+		0x609, 0x0000002A,
+		0x620, 0x000000FF,
+		0x621, 0x000000FF,
+		0x622, 0x000000FF,
+		0x623, 0x000000FF,
+		0x624, 0x000000FF,
+		0x625, 0x000000FF,
+		0x626, 0x000000FF,
+		0x627, 0x000000FF,
+		0x638, 0x00000050,
+		0x63C, 0x0000000A,
+		0x63D, 0x0000000A,
+		0x63E, 0x0000000E,
+		0x63F, 0x0000000E,
+		0x640, 0x00000040,
+		0x642, 0x00000040,
+		0x643, 0x00000000,
+		0x652, 0x000000C8,
+		0x66E, 0x00000005,
+		0x700, 0x00000021,
+		0x701, 0x00000043,
+		0x702, 0x00000065,
+		0x703, 0x00000087,
+		0x708, 0x00000021,
+		0x709, 0x00000043,
+		0x70A, 0x00000065,
+		0x70B, 0x00000087,
+};
+
+u32 RTL8192EE_AGC_TAB_ARRAY[] = {
+	0xFF010718, 0xABCD,
+		0xC78, 0xFA000001,
+		0xC78, 0xF9010001,
+		0xC78, 0xF8020001,
+		0xC78, 0xF7030001,
+		0xC78, 0xF6040001,
+		0xC78, 0xF5050001,
+		0xC78, 0xF4060001,
+		0xC78, 0xF3070001,
+		0xC78, 0xF2080001,
+		0xC78, 0xF1090001,
+		0xC78, 0xF00A0001,
+		0xC78, 0xEF0B0001,
+		0xC78, 0xEE0C0001,
+		0xC78, 0xED0D0001,
+		0xC78, 0xEC0E0001,
+		0xC78, 0xEB0F0001,
+		0xC78, 0xEA100001,
+		0xC78, 0xE9110001,
+		0xC78, 0xE8120001,
+		0xC78, 0xE7130001,
+		0xC78, 0xE6140001,
+		0xC78, 0xE5150001,
+		0xC78, 0xE4160001,
+		0xC78, 0xE3170001,
+		0xC78, 0xE2180001,
+		0xC78, 0xE1190001,
+		0xC78, 0x8A1A0001,
+		0xC78, 0x891B0001,
+		0xC78, 0x881C0001,
+		0xC78, 0x871D0001,
+		0xC78, 0x861E0001,
+		0xC78, 0x851F0001,
+		0xC78, 0x84200001,
+		0xC78, 0x83210001,
+		0xC78, 0x82220001,
+		0xC78, 0x6A230001,
+		0xC78, 0x69240001,
+		0xC78, 0x68250001,
+		0xC78, 0x67260001,
+		0xC78, 0x66270001,
+		0xC78, 0x65280001,
+		0xC78, 0x64290001,
+		0xC78, 0x632A0001,
+		0xC78, 0x622B0001,
+		0xC78, 0x612C0001,
+		0xC78, 0x602D0001,
+		0xC78, 0x472E0001,
+		0xC78, 0x462F0001,
+		0xC78, 0x45300001,
+		0xC78, 0x44310001,
+		0xC78, 0x43320001,
+		0xC78, 0x42330001,
+		0xC78, 0x41340001,
+		0xC78, 0x40350001,
+		0xC78, 0x40360001,
+		0xC78, 0x40370001,
+		0xC78, 0x40380001,
+		0xC78, 0x40390001,
+		0xC78, 0x403A0001,
+		0xC78, 0x403B0001,
+		0xC78, 0x403C0001,
+		0xC78, 0x403D0001,
+		0xC78, 0x403E0001,
+		0xC78, 0x403F0001,
+	0xCDCDCDCD, 0xCDCD,
+		0xC78, 0xFB000001,
+		0xC78, 0xFB010001,
+		0xC78, 0xFB020001,
+		0xC78, 0xFB030001,
+		0xC78, 0xFB040001,
+		0xC78, 0xFB050001,
+		0xC78, 0xFA060001,
+		0xC78, 0xF9070001,
+		0xC78, 0xF8080001,
+		0xC78, 0xF7090001,
+		0xC78, 0xF60A0001,
+		0xC78, 0xF50B0001,
+		0xC78, 0xF40C0001,
+		0xC78, 0xF30D0001,
+		0xC78, 0xF20E0001,
+		0xC78, 0xF10F0001,
+		0xC78, 0xF0100001,
+		0xC78, 0xEF110001,
+		0xC78, 0xEE120001,
+		0xC78, 0xED130001,
+		0xC78, 0xEC140001,
+		0xC78, 0xEB150001,
+		0xC78, 0xEA160001,
+		0xC78, 0xE9170001,
+		0xC78, 0xE8180001,
+		0xC78, 0xE7190001,
+		0xC78, 0xC81A0001,
+		0xC78, 0xC71B0001,
+		0xC78, 0xC61C0001,
+		0xC78, 0x071D0001,
+		0xC78, 0x061E0001,
+		0xC78, 0x051F0001,
+		0xC78, 0x04200001,
+		0xC78, 0x03210001,
+		0xC78, 0xAA220001,
+		0xC78, 0xA9230001,
+		0xC78, 0xA8240001,
+		0xC78, 0xA7250001,
+		0xC78, 0xA6260001,
+		0xC78, 0x85270001,
+		0xC78, 0x84280001,
+		0xC78, 0x83290001,
+		0xC78, 0x252A0001,
+		0xC78, 0x242B0001,
+		0xC78, 0x232C0001,
+		0xC78, 0x222D0001,
+		0xC78, 0x672E0001,
+		0xC78, 0x662F0001,
+		0xC78, 0x65300001,
+		0xC78, 0x64310001,
+		0xC78, 0x63320001,
+		0xC78, 0x62330001,
+		0xC78, 0x61340001,
+		0xC78, 0x45350001,
+		0xC78, 0x44360001,
+		0xC78, 0x43370001,
+		0xC78, 0x42380001,
+		0xC78, 0x41390001,
+		0xC78, 0x403A0001,
+		0xC78, 0x403B0001,
+		0xC78, 0x403C0001,
+		0xC78, 0x403D0001,
+		0xC78, 0x403E0001,
+		0xC78, 0x403F0001,
+	0xFF010718, 0xDEAD,
+	0xFF010718, 0xABCD,
+		0xC78, 0xFA400001,
+		0xC78, 0xF9410001,
+		0xC78, 0xF8420001,
+		0xC78, 0xF7430001,
+		0xC78, 0xF6440001,
+		0xC78, 0xF5450001,
+		0xC78, 0xF4460001,
+		0xC78, 0xF3470001,
+		0xC78, 0xF2480001,
+		0xC78, 0xF1490001,
+		0xC78, 0xF04A0001,
+		0xC78, 0xEF4B0001,
+		0xC78, 0xEE4C0001,
+		0xC78, 0xED4D0001,
+		0xC78, 0xEC4E0001,
+		0xC78, 0xEB4F0001,
+		0xC78, 0xEA500001,
+		0xC78, 0xE9510001,
+		0xC78, 0xE8520001,
+		0xC78, 0xE7530001,
+		0xC78, 0xE6540001,
+		0xC78, 0xE5550001,
+		0xC78, 0xE4560001,
+		0xC78, 0xE3570001,
+		0xC78, 0xE2580001,
+		0xC78, 0xE1590001,
+		0xC78, 0x8A5A0001,
+		0xC78, 0x895B0001,
+		0xC78, 0x885C0001,
+		0xC78, 0x875D0001,
+		0xC78, 0x865E0001,
+		0xC78, 0x855F0001,
+		0xC78, 0x84600001,
+		0xC78, 0x83610001,
+		0xC78, 0x82620001,
+		0xC78, 0x6A630001,
+		0xC78, 0x69640001,
+		0xC78, 0x68650001,
+		0xC78, 0x67660001,
+		0xC78, 0x66670001,
+		0xC78, 0x65680001,
+		0xC78, 0x64690001,
+		0xC78, 0x636A0001,
+		0xC78, 0x626B0001,
+		0xC78, 0x616C0001,
+		0xC78, 0x606D0001,
+		0xC78, 0x476E0001,
+		0xC78, 0x466F0001,
+		0xC78, 0x45700001,
+		0xC78, 0x44710001,
+		0xC78, 0x43720001,
+		0xC78, 0x42730001,
+		0xC78, 0x41740001,
+		0xC78, 0x40750001,
+		0xC78, 0x40760001,
+		0xC78, 0x40770001,
+		0xC78, 0x40780001,
+		0xC78, 0x40790001,
+		0xC78, 0x407A0001,
+		0xC78, 0x407B0001,
+		0xC78, 0x407C0001,
+		0xC78, 0x407D0001,
+		0xC78, 0x407E0001,
+		0xC78, 0x407F0001,
+		0xC50, 0x00040222,
+		0xC50, 0x00040220,
+	0xCDCDCDCD, 0xCDCD,
+		0xC78, 0xFB400001,
+		0xC78, 0xFB410001,
+		0xC78, 0xFB420001,
+		0xC78, 0xFB430001,
+		0xC78, 0xFB440001,
+		0xC78, 0xFB450001,
+		0xC78, 0xFA460001,
+		0xC78, 0xF9470001,
+		0xC78, 0xF8480001,
+		0xC78, 0xF7490001,
+		0xC78, 0xF64A0001,
+		0xC78, 0xF54B0001,
+		0xC78, 0xF44C0001,
+		0xC78, 0xF34D0001,
+		0xC78, 0xF24E0001,
+		0xC78, 0xF14F0001,
+		0xC78, 0xF0500001,
+		0xC78, 0xEF510001,
+		0xC78, 0xEE520001,
+		0xC78, 0xED530001,
+		0xC78, 0xEC540001,
+		0xC78, 0xEB550001,
+		0xC78, 0xEA560001,
+		0xC78, 0xE9570001,
+		0xC78, 0xE8580001,
+		0xC78, 0xE7590001,
+		0xC78, 0xE65A0001,
+		0xC78, 0xE55B0001,
+		0xC78, 0xE45C0001,
+		0xC78, 0xE35D0001,
+		0xC78, 0xE25E0001,
+		0xC78, 0xE15F0001,
+		0xC78, 0x8A600001,
+		0xC78, 0x89610001,
+		0xC78, 0x88620001,
+		0xC78, 0x87630001,
+		0xC78, 0x86640001,
+		0xC78, 0x85650001,
+		0xC78, 0x84660001,
+		0xC78, 0x83670001,
+		0xC78, 0x82680001,
+		0xC78, 0x6B690001,
+		0xC78, 0x6A6A0001,
+		0xC78, 0x696B0001,
+		0xC78, 0x686C0001,
+		0xC78, 0x676D0001,
+		0xC78, 0x666E0001,
+		0xC78, 0x656F0001,
+		0xC78, 0x64700001,
+		0xC78, 0x63710001,
+		0xC78, 0x62720001,
+		0xC78, 0x61730001,
+		0xC78, 0x49740001,
+		0xC78, 0x48750001,
+		0xC78, 0x47760001,
+		0xC78, 0x46770001,
+		0xC78, 0x45780001,
+		0xC78, 0x44790001,
+		0xC78, 0x437A0001,
+		0xC78, 0x427B0001,
+		0xC78, 0x417C0001,
+		0xC78, 0x407D0001,
+		0xC78, 0x407E0001,
+		0xC78, 0x407F0001,
+		0xC50, 0x00040022,
+		0xC50, 0x00040020,
+	0xFF010718, 0xDEAD,
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/table.h b/drivers/net/wireless/rtlwifi/rtl8192ee/table.h
new file mode 100644
index 0000000..bff9df8
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/table.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on  2010/ 5/18,  1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92E_TABLE__H_
+#define __RTL92E_TABLE__H_
+
+#include <linux/types.h>
+#define RTL8192EE_PHY_REG_ARRAY_LEN	448
+extern u32 RTL8192EE_PHY_REG_ARRAY[];
+#define RTL8192EE_PHY_REG_ARRAY_PG_LEN	168
+extern u32 RTL8192EE_PHY_REG_ARRAY_PG[];
+#define	RTL8192EE_RADIOA_ARRAY_LEN	238
+extern u32 RTL8192EE_RADIOA_ARRAY[];
+#define	RTL8192EE_RADIOB_ARRAY_LEN	198
+extern u32 RTL8192EE_RADIOB_ARRAY[];
+#define RTL8192EE_MAC_ARRAY_LEN		202
+extern u32 RTL8192EE_MAC_ARRAY[];
+#define RTL8192EE_AGC_TAB_ARRAY_LEN	532
+extern u32 RTL8192EE_AGC_TAB_ARRAY[];
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c
new file mode 100644
index 0000000..2fcbef1
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c
@@ -0,0 +1,1293 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "../stats.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "trx.h"
+#include "led.h"
+#include "dm.h"
+#include "fw.h"
+
+static u8 _rtl92ee_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
+{
+	__le16 fc = rtl_get_fc(skb);
+
+	if (unlikely(ieee80211_is_beacon(fc)))
+		return QSLT_BEACON;
+	if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
+		return QSLT_MGNT;
+
+	return skb->priority;
+}
+
+/* mac80211's rate_idx is like this:
+ *
+ * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
+ *
+ * B/G rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
+ *
+ * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
+ * A rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
+ */
+static int _rtl92ee_rate_mapping(struct ieee80211_hw *hw,
+				 bool isht, u8 desc_rate)
+{
+	int rate_idx;
+
+	if (!isht) {
+		if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
+			switch (desc_rate) {
+			case DESC92C_RATE1M:
+				rate_idx = 0;
+				break;
+			case DESC92C_RATE2M:
+				rate_idx = 1;
+				break;
+			case DESC92C_RATE5_5M:
+				rate_idx = 2;
+				break;
+			case DESC92C_RATE11M:
+				rate_idx = 3;
+				break;
+			case DESC92C_RATE6M:
+				rate_idx = 4;
+				break;
+			case DESC92C_RATE9M:
+				rate_idx = 5;
+				break;
+			case DESC92C_RATE12M:
+				rate_idx = 6;
+				break;
+			case DESC92C_RATE18M:
+				rate_idx = 7;
+				break;
+			case DESC92C_RATE24M:
+				rate_idx = 8;
+				break;
+			case DESC92C_RATE36M:
+				rate_idx = 9;
+				break;
+			case DESC92C_RATE48M:
+				rate_idx = 10;
+				break;
+			case DESC92C_RATE54M:
+				rate_idx = 11;
+				break;
+			default:
+				rate_idx = 0;
+				break;
+			}
+		} else {
+			switch (desc_rate) {
+			case DESC92C_RATE6M:
+				rate_idx = 0;
+				break;
+			case DESC92C_RATE9M:
+				rate_idx = 1;
+				break;
+			case DESC92C_RATE12M:
+				rate_idx = 2;
+				break;
+			case DESC92C_RATE18M:
+				rate_idx = 3;
+				break;
+			case DESC92C_RATE24M:
+				rate_idx = 4;
+				break;
+			case DESC92C_RATE36M:
+				rate_idx = 5;
+				break;
+			case DESC92C_RATE48M:
+				rate_idx = 6;
+				break;
+			case DESC92C_RATE54M:
+				rate_idx = 7;
+				break;
+			default:
+				rate_idx = 0;
+				break;
+			}
+		}
+	} else {
+		switch (desc_rate) {
+		case DESC92C_RATEMCS0:
+			rate_idx = 0;
+			break;
+		case DESC92C_RATEMCS1:
+			rate_idx = 1;
+			break;
+		case DESC92C_RATEMCS2:
+			rate_idx = 2;
+			break;
+		case DESC92C_RATEMCS3:
+			rate_idx = 3;
+			break;
+		case DESC92C_RATEMCS4:
+			rate_idx = 4;
+			break;
+		case DESC92C_RATEMCS5:
+			rate_idx = 5;
+			break;
+		case DESC92C_RATEMCS6:
+			rate_idx = 6;
+			break;
+		case DESC92C_RATEMCS7:
+			rate_idx = 7;
+			break;
+		case DESC92C_RATEMCS8:
+			rate_idx = 8;
+			break;
+		case DESC92C_RATEMCS9:
+			rate_idx = 9;
+			break;
+		case DESC92C_RATEMCS10:
+			rate_idx = 10;
+			break;
+		case DESC92C_RATEMCS11:
+			rate_idx = 11;
+			break;
+		case DESC92C_RATEMCS12:
+			rate_idx = 12;
+			break;
+		case DESC92C_RATEMCS13:
+			rate_idx = 13;
+			break;
+		case DESC92C_RATEMCS14:
+			rate_idx = 14;
+			break;
+		case DESC92C_RATEMCS15:
+			rate_idx = 15;
+			break;
+		default:
+			rate_idx = 0;
+			break;
+		}
+	}
+	return rate_idx;
+}
+
+static void _rtl92ee_query_rxphystatus(struct ieee80211_hw *hw,
+				       struct rtl_stats *pstatus, u8 *pdesc,
+				       struct rx_fwinfo *p_drvinfo,
+				       bool bpacket_match_bssid,
+				       bool bpacket_toself,
+				       bool packet_beacon)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct phy_status_rpt *p_phystrpt = (struct phy_status_rpt *)p_drvinfo;
+	char rx_pwr_all = 0, rx_pwr[4];
+	u8 rf_rx_num = 0, evm, pwdb_all;
+	u8 i, max_spatial_stream;
+	u32 rssi, total_rssi = 0;
+	bool is_cck = pstatus->is_cck;
+	u8 lan_idx, vga_idx;
+
+	/* Record it for next packet processing */
+	pstatus->packet_matchbssid = bpacket_match_bssid;
+	pstatus->packet_toself = bpacket_toself;
+	pstatus->packet_beacon = packet_beacon;
+	pstatus->rx_mimo_signalquality[0] = -1;
+	pstatus->rx_mimo_signalquality[1] = -1;
+
+	if (is_cck) {
+		u8 cck_highpwr;
+		u8 cck_agc_rpt;
+		/* CCK Driver info Structure is not the same as OFDM packet. */
+		cck_agc_rpt = p_phystrpt->cck_agc_rpt_ofdm_cfosho_a;
+
+		/* (1)Hardware does not provide RSSI for CCK
+		 * (2)PWDB, Average PWDB cacluated by
+		 * hardware (for rate adaptive)
+		 */
+		cck_highpwr = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2,
+						 BIT(9));
+
+		lan_idx = ((cck_agc_rpt & 0xE0) >> 5);
+		vga_idx = (cck_agc_rpt & 0x1f);
+		switch (lan_idx) {
+		case 7: /*VGA_idx = 27~2*/
+				if (vga_idx <= 27)
+					rx_pwr_all = -100 + 2 * (27 - vga_idx);
+				else
+					rx_pwr_all = -100;
+				break;
+		case 6: /*VGA_idx = 2~0*/
+				rx_pwr_all = -48 + 2 * (2 - vga_idx);
+				break;
+		case 5: /*VGA_idx = 7~5*/
+				rx_pwr_all = -42 + 2 * (7 - vga_idx);
+				break;
+		case 4: /*VGA_idx = 7~4*/
+				rx_pwr_all = -36 + 2 * (7 - vga_idx);
+				break;
+		case 3: /*VGA_idx = 7~0*/
+				rx_pwr_all = -24 + 2 * (7 - vga_idx);
+				break;
+		case 2: /*VGA_idx = 5~0*/
+				if (cck_highpwr)
+					rx_pwr_all = -12 + 2 * (5 - vga_idx);
+				else
+					rx_pwr_all = -6 + 2 * (5 - vga_idx);
+				break;
+		case 1:
+				rx_pwr_all = 8 - 2 * vga_idx;
+				break;
+		case 0:
+				rx_pwr_all = 14 - 2 * vga_idx;
+				break;
+		default:
+				break;
+		}
+		rx_pwr_all += 16;
+		pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+
+		if (!cck_highpwr) {
+			if (pwdb_all >= 80)
+				pwdb_all = ((pwdb_all - 80) << 1) +
+					   ((pwdb_all - 80) >> 1) + 80;
+			else if ((pwdb_all <= 78) && (pwdb_all >= 20))
+				pwdb_all += 3;
+			if (pwdb_all > 100)
+				pwdb_all = 100;
+		}
+
+		pstatus->rx_pwdb_all = pwdb_all;
+		pstatus->bt_rx_rssi_percentage = pwdb_all;
+		pstatus->recvsignalpower = rx_pwr_all;
+
+		/* (3) Get Signal Quality (EVM) */
+		if (bpacket_match_bssid) {
+			u8 sq, sq_rpt;
+
+			if (pstatus->rx_pwdb_all > 40) {
+				sq = 100;
+			} else {
+				sq_rpt = p_phystrpt->cck_sig_qual_ofdm_pwdb_all;
+				if (sq_rpt > 64)
+					sq = 0;
+				else if (sq_rpt < 20)
+					sq = 100;
+				else
+					sq = ((64 - sq_rpt) * 100) / 44;
+			}
+
+			pstatus->signalquality = sq;
+			pstatus->rx_mimo_signalquality[0] = sq;
+			pstatus->rx_mimo_signalquality[1] = -1;
+		}
+	} else {
+		/* (1)Get RSSI for HT rate */
+		for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) {
+			/* we will judge RF RX path now. */
+			if (rtlpriv->dm.rfpath_rxenable[i])
+				rf_rx_num++;
+
+			rx_pwr[i] = ((p_phystrpt->path_agc[i].gain & 0x3f) * 2)
+				    - 110;
+
+			pstatus->rx_pwr[i] = rx_pwr[i];
+			/* Translate DBM to percentage. */
+			rssi = rtl_query_rxpwrpercentage(rx_pwr[i]);
+			total_rssi += rssi;
+
+			pstatus->rx_mimo_signalstrength[i] = (u8)rssi;
+		}
+
+		/* (2)PWDB, Average PWDB cacluated by
+		 * hardware (for rate adaptive)
+		 */
+		rx_pwr_all = ((p_phystrpt->cck_sig_qual_ofdm_pwdb_all >> 1)
+			      & 0x7f) - 110;
+
+		pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+		pstatus->rx_pwdb_all = pwdb_all;
+		pstatus->bt_rx_rssi_percentage = pwdb_all;
+		pstatus->rxpower = rx_pwr_all;
+		pstatus->recvsignalpower = rx_pwr_all;
+
+		/* (3)EVM of HT rate */
+		if (pstatus->rate >= DESC92C_RATEMCS8 &&
+		    pstatus->rate <= DESC92C_RATEMCS15)
+			max_spatial_stream = 2;
+		else
+			max_spatial_stream = 1;
+
+		for (i = 0; i < max_spatial_stream; i++) {
+			evm = rtl_evm_db_to_percentage(
+						p_phystrpt->stream_rxevm[i]);
+
+			if (bpacket_match_bssid) {
+				/* Fill value in RFD, Get the first
+				 * spatial stream only
+				 */
+				if (i == 0)
+					pstatus->signalquality = (u8)(evm &
+								       0xff);
+				pstatus->rx_mimo_signalquality[i] = (u8)(evm &
+									  0xff);
+			}
+		}
+
+		if (bpacket_match_bssid) {
+			for (i = RF90_PATH_A; i <= RF90_PATH_B; i++)
+				rtl_priv(hw)->dm.cfo_tail[i] =
+					(int)p_phystrpt->path_cfotail[i];
+
+			if (rtl_priv(hw)->dm.packet_count == 0xffffffff)
+				rtl_priv(hw)->dm.packet_count = 0;
+			else
+				rtl_priv(hw)->dm.packet_count++;
+		}
+	}
+
+	/* UI BSS List signal strength(in percentage),
+	 * make it good looking, from 0~100.
+	 */
+	if (is_cck)
+		pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+								     pwdb_all));
+	else if (rf_rx_num != 0)
+		pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+						      total_rssi /= rf_rx_num));
+}
+
+static void _rtl92ee_translate_rx_signal_stuff(struct ieee80211_hw *hw,
+					       struct sk_buff *skb,
+					       struct rtl_stats *pstatus,
+					       u8 *pdesc,
+					       struct rx_fwinfo *p_drvinfo)
+{
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct ieee80211_hdr *hdr;
+	u8 *tmp_buf;
+	u8 *praddr;
+	u8 *psaddr;
+	__le16 fc;
+	bool packet_matchbssid, packet_toself, packet_beacon;
+
+	tmp_buf = skb->data + pstatus->rx_drvinfo_size +
+		  pstatus->rx_bufshift + 24;
+
+	hdr = (struct ieee80211_hdr *)tmp_buf;
+	fc = hdr->frame_control;
+	praddr = hdr->addr1;
+	psaddr = ieee80211_get_SA(hdr);
+	ether_addr_copy(pstatus->psaddr, psaddr);
+
+	packet_matchbssid = (!ieee80211_is_ctl(fc) &&
+			       (ether_addr_equal(mac->bssid,
+						ieee80211_has_tods(fc) ?
+						hdr->addr1 :
+						ieee80211_has_fromds(fc) ?
+						hdr->addr2 : hdr->addr3)) &&
+				(!pstatus->hwerror) && (!pstatus->crc) &&
+				(!pstatus->icv));
+
+	packet_toself = packet_matchbssid &&
+			 (ether_addr_equal(praddr, rtlefuse->dev_addr));
+
+	if (ieee80211_is_beacon(fc))
+		packet_beacon = true;
+	else
+		packet_beacon = false;
+
+	if (packet_beacon && packet_matchbssid)
+		rtl_priv(hw)->dm.dbginfo.num_qry_beacon_pkt++;
+
+	if (packet_matchbssid && ieee80211_is_data_qos(hdr->frame_control) &&
+	    !is_multicast_ether_addr(ieee80211_get_DA(hdr))) {
+		struct ieee80211_qos_hdr *hdr_qos =
+					    (struct ieee80211_qos_hdr *)tmp_buf;
+		u16 tid = le16_to_cpu(hdr_qos->qos_ctrl) & 0xf;
+
+		if (tid != 0 && tid != 3)
+			rtl_priv(hw)->dm.dbginfo.num_non_be_pkt++;
+	}
+
+	_rtl92ee_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo,
+				   packet_matchbssid, packet_toself,
+				   packet_beacon);
+	rtl_process_phyinfo(hw, tmp_buf, pstatus);
+}
+
+static void _rtl92ee_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
+				      u8 *virtualaddress)
+{
+	u32 dwtmp = 0;
+
+	memset(virtualaddress, 0, 8);
+
+	SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num);
+	if (ptcb_desc->empkt_num == 1) {
+		dwtmp = ptcb_desc->empkt_len[0];
+	} else {
+		dwtmp = ptcb_desc->empkt_len[0];
+		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+		dwtmp += ptcb_desc->empkt_len[1];
+	}
+	SET_EARLYMODE_LEN0(virtualaddress, dwtmp);
+
+	if (ptcb_desc->empkt_num <= 3) {
+		dwtmp = ptcb_desc->empkt_len[2];
+	} else {
+		dwtmp = ptcb_desc->empkt_len[2];
+		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+		dwtmp += ptcb_desc->empkt_len[3];
+	}
+	SET_EARLYMODE_LEN1(virtualaddress, dwtmp);
+	if (ptcb_desc->empkt_num <= 5) {
+		dwtmp = ptcb_desc->empkt_len[4];
+	} else {
+		dwtmp = ptcb_desc->empkt_len[4];
+		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+		dwtmp += ptcb_desc->empkt_len[5];
+	}
+	SET_EARLYMODE_LEN2_1(virtualaddress, dwtmp & 0xF);
+	SET_EARLYMODE_LEN2_2(virtualaddress, dwtmp >> 4);
+	if (ptcb_desc->empkt_num <= 7) {
+		dwtmp = ptcb_desc->empkt_len[6];
+	} else {
+		dwtmp = ptcb_desc->empkt_len[6];
+		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+		dwtmp += ptcb_desc->empkt_len[7];
+	}
+	SET_EARLYMODE_LEN3(virtualaddress, dwtmp);
+	if (ptcb_desc->empkt_num <= 9) {
+		dwtmp = ptcb_desc->empkt_len[8];
+	} else {
+		dwtmp = ptcb_desc->empkt_len[8];
+		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+		dwtmp += ptcb_desc->empkt_len[9];
+	}
+	SET_EARLYMODE_LEN4(virtualaddress, dwtmp);
+}
+
+bool rtl92ee_rx_query_desc(struct ieee80211_hw *hw,
+			   struct rtl_stats *status,
+			   struct ieee80211_rx_status *rx_status,
+			   u8 *pdesc, struct sk_buff *skb)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rx_fwinfo *p_drvinfo;
+	struct ieee80211_hdr *hdr;
+	u32 phystatus = GET_RX_DESC_PHYST(pdesc);
+
+	status->length = (u16)GET_RX_DESC_PKT_LEN(pdesc);
+	status->rx_drvinfo_size = (u8)GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
+				  RX_DRV_INFO_SIZE_UNIT;
+	status->rx_bufshift = (u8)(GET_RX_DESC_SHIFT(pdesc) & 0x03);
+	status->icv = (u16)GET_RX_DESC_ICV(pdesc);
+	status->crc = (u16)GET_RX_DESC_CRC32(pdesc);
+	status->hwerror = (status->crc | status->icv);
+	status->decrypted = !GET_RX_DESC_SWDEC(pdesc);
+	status->rate = (u8)GET_RX_DESC_RXMCS(pdesc);
+	status->isampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1);
+		status->timestamp_low = GET_RX_DESC_TSFL(pdesc);
+	status->is_cck = RTL92EE_RX_HAL_IS_CCK_RATE(status->rate);
+
+	status->macid = GET_RX_DESC_MACID(pdesc);
+	if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
+		status->wake_match = BIT(2);
+	else if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
+		status->wake_match = BIT(1);
+	else if (GET_RX_STATUS_DESC_UNICAST_MATCH(pdesc))
+		status->wake_match = BIT(0);
+	else
+		status->wake_match = 0;
+	if (status->wake_match)
+		RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD,
+			 "GGGGGGGGGGGGGet Wakeup Packet!! WakeMatch=%d\n",
+			 status->wake_match);
+	rx_status->freq = hw->conf.chandef.chan->center_freq;
+	rx_status->band = hw->conf.chandef.chan->band;
+
+	hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size +
+				       status->rx_bufshift + 24);
+
+	if (status->crc)
+		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+	if (status->rx_is40Mhzpacket)
+		rx_status->flag |= RX_FLAG_40MHZ;
+
+	if (status->is_ht)
+		rx_status->flag |= RX_FLAG_HT;
+
+	rx_status->flag |= RX_FLAG_MACTIME_START;
+
+	/* hw will set status->decrypted true, if it finds the
+	 * frame is open data frame or mgmt frame.
+	 * So hw will not decryption robust managment frame
+	 * for IEEE80211w but still set status->decrypted
+	 * true, so here we should set it back to undecrypted
+	 * for IEEE80211w frame, and mac80211 sw will help
+	 * to decrypt it
+	 */
+	if (status->decrypted) {
+		if ((!_ieee80211_is_robust_mgmt_frame(hdr)) &&
+		    (ieee80211_has_protected(hdr->frame_control)))
+			rx_status->flag |= RX_FLAG_DECRYPTED;
+		else
+			rx_status->flag &= ~RX_FLAG_DECRYPTED;
+	}
+
+	/* rate_idx: index of data rate into band's
+	 * supported rates or MCS index if HT rates
+	 * are use (RX_FLAG_HT)
+	 * Notice: this is diff with windows define
+	 */
+	rx_status->rate_idx = _rtl92ee_rate_mapping(hw,
+						    status->is_ht,
+						    status->rate);
+
+	rx_status->mactime = status->timestamp_low;
+	if (phystatus) {
+		p_drvinfo = (struct rx_fwinfo *)(skb->data +
+						 status->rx_bufshift + 24);
+
+		_rtl92ee_translate_rx_signal_stuff(hw, skb, status, pdesc,
+						   p_drvinfo);
+	}
+	rx_status->signal = status->recvsignalpower + 10;
+	if (status->packet_report_type == TX_REPORT2) {
+		status->macid_valid_entry[0] =
+			GET_RX_RPT2_DESC_MACID_VALID_1(pdesc);
+		status->macid_valid_entry[1] =
+			GET_RX_RPT2_DESC_MACID_VALID_2(pdesc);
+	}
+	return true;
+}
+
+/*in Windows, this == Rx_92EE_Interrupt*/
+void rtl92ee_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc,
+			     u8 queue_index)
+{
+	u8 first_seg = 0;
+	u8 last_seg = 0;
+	u16 total_len = 0;
+	u16 read_cnt = 0;
+
+	if (header_desc == NULL)
+		return;
+
+	total_len = (u16)GET_RX_BUFFER_DESC_TOTAL_LENGTH(header_desc);
+
+	first_seg = (u8)GET_RX_BUFFER_DESC_FS(header_desc);
+
+	last_seg = (u8)GET_RX_BUFFER_DESC_LS(header_desc);
+
+	while (total_len == 0 && first_seg == 0 && last_seg == 0) {
+		read_cnt++;
+		total_len = (u16)GET_RX_BUFFER_DESC_TOTAL_LENGTH(header_desc);
+		first_seg = (u8)GET_RX_BUFFER_DESC_FS(header_desc);
+		last_seg = (u8)GET_RX_BUFFER_DESC_LS(header_desc);
+
+		if (read_cnt > 20)
+			break;
+	}
+}
+
+u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, u8 queue_index)
+{
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u16 read_point = 0, write_point = 0, remind_cnt = 0;
+	u32 tmp_4byte = 0;
+	static u16 last_read_point;
+	static bool start_rx;
+
+	tmp_4byte = rtl_read_dword(rtlpriv, REG_RXQ_TXBD_IDX);
+	read_point = (u16)((tmp_4byte>>16) & 0x7ff);
+	write_point = (u16)(tmp_4byte & 0x7ff);
+
+	if (write_point != rtlpci->rx_ring[queue_index].next_rx_rp) {
+		RT_TRACE(rtlpriv, COMP_RXDESC, DBG_DMESG,
+			 "!!!write point is 0x%x, reg 0x3B4 value is 0x%x\n",
+			  write_point, tmp_4byte);
+		tmp_4byte = rtl_read_dword(rtlpriv, REG_RXQ_TXBD_IDX);
+		read_point = (u16)((tmp_4byte>>16) & 0x7ff);
+		write_point = (u16)(tmp_4byte & 0x7ff);
+	}
+
+	if (read_point > 0)
+		start_rx = true;
+	if (!start_rx)
+		return 0;
+
+	if ((last_read_point > (RX_DESC_NUM_92E / 2)) &&
+	    (read_point <= (RX_DESC_NUM_92E / 2))) {
+		remind_cnt = RX_DESC_NUM_92E - write_point;
+	} else {
+		remind_cnt = (read_point >= write_point) ?
+			     (read_point - write_point) :
+			     (RX_DESC_NUM_92E - write_point + read_point);
+	}
+
+	if (remind_cnt == 0)
+		return 0;
+
+	rtlpci->rx_ring[queue_index].next_rx_rp = write_point;
+
+	last_read_point = read_point;
+	return remind_cnt;
+}
+
+static u16 get_desc_addr_fr_q_idx(u16 queue_index)
+{
+	u16 desc_address = REG_BEQ_TXBD_IDX;
+
+	switch (queue_index) {
+	case BK_QUEUE:
+		desc_address = REG_BKQ_TXBD_IDX;
+		break;
+	case BE_QUEUE:
+		desc_address = REG_BEQ_TXBD_IDX;
+		break;
+	case VI_QUEUE:
+		desc_address = REG_VIQ_TXBD_IDX;
+		break;
+	case VO_QUEUE:
+		desc_address = REG_VOQ_TXBD_IDX;
+		break;
+	case BEACON_QUEUE:
+		desc_address = REG_BEQ_TXBD_IDX;
+		break;
+	case TXCMD_QUEUE:
+		desc_address = REG_BEQ_TXBD_IDX;
+		break;
+	case MGNT_QUEUE:
+		desc_address = REG_MGQ_TXBD_IDX;
+		break;
+	case HIGH_QUEUE:
+		desc_address = REG_HI0Q_TXBD_IDX;
+		break;
+	case HCCA_QUEUE:
+		desc_address = REG_BEQ_TXBD_IDX;
+		break;
+	default:
+		break;
+	}
+	return desc_address;
+}
+
+void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx)
+{
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u16 point_diff = 0;
+	u16 current_tx_read_point = 0, current_tx_write_point = 0;
+	u32 tmp_4byte;
+
+	tmp_4byte = rtl_read_dword(rtlpriv,
+				   get_desc_addr_fr_q_idx(q_idx));
+	current_tx_read_point = (u16)((tmp_4byte >> 16) & 0x0fff);
+	current_tx_write_point = (u16)((tmp_4byte) & 0x0fff);
+
+	point_diff = ((current_tx_read_point > current_tx_write_point) ?
+		      (current_tx_read_point - current_tx_write_point) :
+		      (TX_DESC_NUM_92E - current_tx_write_point +
+		       current_tx_read_point));
+
+	rtlpci->tx_ring[q_idx].avl_desc = point_diff;
+}
+
+void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw,
+				 u8 *tx_bd_desc, u8 *desc, u8 queue_index,
+				 struct sk_buff *skb, dma_addr_t addr)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u32 pkt_len = skb->len;
+	u16 desc_size = 40; /*tx desc size*/
+	u32 psblen = 0;
+	u16 tx_page_size = 0;
+	u32 total_packet_size = 0;
+	u16 current_bd_desc;
+	u8 i = 0;
+	u16 real_desc_size = 0x28;
+	u16	append_early_mode_size = 0;
+#if (RTL8192EE_SEG_NUM == 0)
+	u8 segmentnum = 2;
+#elif (RTL8192EE_SEG_NUM == 1)
+	u8 segmentnum = 4;
+#elif (RTL8192EE_SEG_NUM == 2)
+	u8 segmentnum = 8;
+#endif
+
+	tx_page_size = 2;
+	current_bd_desc = rtlpci->tx_ring[queue_index].cur_tx_wp;
+
+	total_packet_size = desc_size+pkt_len;
+
+	if (rtlpriv->rtlhal.earlymode_enable)	{
+		if (queue_index < BEACON_QUEUE) {
+			append_early_mode_size = 8;
+			total_packet_size += append_early_mode_size;
+		}
+	}
+
+	if (tx_page_size > 0) {
+		psblen = (pkt_len + real_desc_size + append_early_mode_size) /
+			 (tx_page_size * 128);
+
+		if (psblen * (tx_page_size * 128) < total_packet_size)
+			psblen += 1;
+	}
+
+	/* Reset */
+	SET_TX_BUFF_DESC_LEN_0(tx_bd_desc, 0);
+	SET_TX_BUFF_DESC_PSB(tx_bd_desc, 0);
+	SET_TX_BUFF_DESC_OWN(tx_bd_desc, 0);
+
+	for (i = 1; i < segmentnum; i++) {
+		SET_TXBUFFER_DESC_LEN_WITH_OFFSET(tx_bd_desc, i, 0);
+		SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(tx_bd_desc, i, 0);
+		SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(tx_bd_desc, i, 0);
+#if (DMA_IS_64BIT == 1)
+		SET_TXBUFFER_DESC_ADD_HIGT_WITH_OFFSET(tx_bd_desc, i, 0);
+#endif
+	}
+	SET_TX_BUFF_DESC_LEN_1(tx_bd_desc, 0);
+	SET_TX_BUFF_DESC_AMSDU_1(tx_bd_desc, 0);
+
+	SET_TX_BUFF_DESC_LEN_2(tx_bd_desc, 0);
+	SET_TX_BUFF_DESC_AMSDU_2(tx_bd_desc, 0);
+	SET_TX_BUFF_DESC_LEN_3(tx_bd_desc, 0);
+	SET_TX_BUFF_DESC_AMSDU_3(tx_bd_desc, 0);
+	/* Clear all status */
+	CLEAR_PCI_TX_DESC_CONTENT(desc, TX_DESC_SIZE);
+
+	if (rtlpriv->rtlhal.earlymode_enable) {
+		if (queue_index < BEACON_QUEUE) {
+			/* This if needs braces */
+			SET_TX_BUFF_DESC_LEN_0(tx_bd_desc, desc_size + 8);
+		} else {
+			SET_TX_BUFF_DESC_LEN_0(tx_bd_desc, desc_size);
+		}
+	} else {
+		SET_TX_BUFF_DESC_LEN_0(tx_bd_desc, desc_size);
+	}
+	SET_TX_BUFF_DESC_PSB(tx_bd_desc, psblen);
+	SET_TX_BUFF_DESC_ADDR_LOW_0(tx_bd_desc,
+				    rtlpci->tx_ring[queue_index].dma +
+				    (current_bd_desc * TX_DESC_SIZE));
+
+	SET_TXBUFFER_DESC_LEN_WITH_OFFSET(tx_bd_desc, 1, pkt_len);
+	/* don't using extendsion mode. */
+	SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(tx_bd_desc, 1, 0);
+	SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(tx_bd_desc, 1, addr);
+
+	SET_TX_DESC_PKT_SIZE(desc, (u16)(pkt_len));
+	SET_TX_DESC_TX_BUFFER_SIZE(desc, (u16)(pkt_len));
+}
+
+void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw,
+			  struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+			  u8 *pbd_desc_tx,
+			  struct ieee80211_tx_info *info,
+			  struct ieee80211_sta *sta,
+			  struct sk_buff *skb,
+			  u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	u8 *pdesc = (u8 *)pdesc_tx;
+	u16 seq_number;
+	__le16 fc = hdr->frame_control;
+	unsigned int buf_len = 0;
+	u8 fw_qsel = _rtl92ee_map_hwqueue_to_fwqueue(skb, hw_queue);
+	bool firstseg = ((hdr->seq_ctrl &
+			    cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
+	bool lastseg = ((hdr->frame_control &
+			   cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
+	dma_addr_t mapping;
+	u8 bw_40 = 0;
+	u8 short_gi = 0;
+
+	if (mac->opmode == NL80211_IFTYPE_STATION) {
+		bw_40 = mac->bw_40;
+	} else if (mac->opmode == NL80211_IFTYPE_AP ||
+		   mac->opmode == NL80211_IFTYPE_ADHOC) {
+		if (sta)
+			bw_40 = sta->ht_cap.cap &
+				IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+	}
+	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+	rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
+	/* reserve 8 byte for AMPDU early mode */
+	if (rtlhal->earlymode_enable) {
+		skb_push(skb, EM_HDR_LEN);
+		memset(skb->data, 0, EM_HDR_LEN);
+	}
+	buf_len = skb->len;
+	mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
+				 PCI_DMA_TODEVICE);
+	if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+		RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+			 "DMA mapping error");
+		return;
+	}
+
+	if (pbd_desc_tx != NULL)
+		rtl92ee_pre_fill_tx_bd_desc(hw, pbd_desc_tx, pdesc, hw_queue,
+					    skb, mapping);
+
+	if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
+		firstseg = true;
+		lastseg = true;
+	}
+	if (firstseg) {
+		if (rtlhal->earlymode_enable) {
+			SET_TX_DESC_PKT_OFFSET(pdesc, 1);
+			SET_TX_DESC_OFFSET(pdesc,
+					   USB_HWDESC_HEADER_LEN + EM_HDR_LEN);
+			if (ptcb_desc->empkt_num) {
+				RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+					 "Insert 8 byte.pTcb->EMPktNum:%d\n",
+					  ptcb_desc->empkt_num);
+				_rtl92ee_insert_emcontent(ptcb_desc,
+							  (u8 *)(skb->data));
+			}
+		} else {
+			SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+		}
+
+		SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
+
+		if (ieee80211_is_mgmt(fc)) {
+			ptcb_desc->use_driver_rate = true;
+		} else {
+			if (rtlpriv->ra.is_special_data) {
+				ptcb_desc->use_driver_rate = true;
+				SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE11M);
+			} else {
+				ptcb_desc->use_driver_rate = false;
+			}
+		}
+
+		if (ptcb_desc->hw_rate > DESC92C_RATEMCS0)
+			short_gi = (ptcb_desc->use_shortgi) ? 1 : 0;
+		else
+			short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0;
+
+		if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+			SET_TX_DESC_AGG_ENABLE(pdesc, 1);
+			SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14);
+		}
+		SET_TX_DESC_SEQ(pdesc, seq_number);
+		SET_TX_DESC_RTS_ENABLE(pdesc,
+				       ((ptcb_desc->rts_enable &&
+					 !ptcb_desc->cts_enable) ? 1 : 0));
+		SET_TX_DESC_HW_RTS_ENABLE(pdesc, 0);
+		SET_TX_DESC_CTS2SELF(pdesc,
+				     ((ptcb_desc->cts_enable) ? 1 : 0));
+
+		SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
+		SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc);
+		SET_TX_DESC_RTS_SHORT(pdesc,
+				((ptcb_desc->rts_rate <= DESC92C_RATE54M) ?
+				 (ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
+				 (ptcb_desc->rts_use_shortgi ? 1 : 0)));
+
+		if (ptcb_desc->tx_enable_sw_calc_duration)
+			SET_TX_DESC_NAV_USE_HDR(pdesc, 1);
+
+		if (bw_40) {
+			if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40) {
+				SET_TX_DESC_DATA_BW(pdesc, 1);
+				SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3);
+			} else {
+				SET_TX_DESC_DATA_BW(pdesc, 0);
+				SET_TX_DESC_TX_SUB_CARRIER(pdesc,
+							   mac->cur_40_prime_sc);
+			}
+		} else {
+			SET_TX_DESC_DATA_BW(pdesc, 0);
+			SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0);
+		}
+
+		SET_TX_DESC_LINIP(pdesc, 0);
+		if (sta) {
+			u8 ampdu_density = sta->ht_cap.ampdu_density;
+
+			SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density);
+		}
+		if (info->control.hw_key) {
+			struct ieee80211_key_conf *key = info->control.hw_key;
+
+			switch (key->cipher) {
+			case WLAN_CIPHER_SUITE_WEP40:
+			case WLAN_CIPHER_SUITE_WEP104:
+			case WLAN_CIPHER_SUITE_TKIP:
+				SET_TX_DESC_SEC_TYPE(pdesc, 0x1);
+				break;
+			case WLAN_CIPHER_SUITE_CCMP:
+				SET_TX_DESC_SEC_TYPE(pdesc, 0x3);
+				break;
+			default:
+				SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
+				break;
+			}
+		}
+
+		SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel);
+		SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
+		SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
+		SET_TX_DESC_DISABLE_FB(pdesc,
+				       ptcb_desc->disable_ratefallback ? 1 : 0);
+		SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0);
+
+		/*SET_TX_DESC_PWR_STATUS(pdesc, pwr_status);*/
+		/* Set TxRate and RTSRate in TxDesc  */
+		/* This prevent Tx initial rate of new-coming packets */
+		/* from being overwritten by retried  packet rate.*/
+		if (!ptcb_desc->use_driver_rate) {
+			/*SET_TX_DESC_RTS_RATE(pdesc, 0x08); */
+			/* SET_TX_DESC_TX_RATE(pdesc, 0x0b); */
+		}
+		if (ieee80211_is_data_qos(fc)) {
+			if (mac->rdg_en) {
+				RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+					 "Enable RDG function.\n");
+				SET_TX_DESC_RDG_ENABLE(pdesc, 1);
+				SET_TX_DESC_HTC(pdesc, 1);
+			}
+		}
+	}
+
+	SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
+	SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
+	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+	if (rtlpriv->dm.useramask) {
+		SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index);
+		SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+	} else {
+		SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcb_desc->ratr_index);
+		SET_TX_DESC_MACID(pdesc, ptcb_desc->ratr_index);
+	}
+
+	SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1));
+	if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+	    is_broadcast_ether_addr(ieee80211_get_DA(hdr))) {
+		SET_TX_DESC_BMC(pdesc, 1);
+	}
+	RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n");
+}
+
+void rtl92ee_tx_fill_cmddesc(struct ieee80211_hw *hw,
+			     u8 *pdesc, bool firstseg,
+			     bool lastseg, struct sk_buff *skb)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u8 fw_queue = QSLT_BEACON;
+	dma_addr_t mapping = pci_map_single(rtlpci->pdev,
+					    skb->data, skb->len,
+					    PCI_DMA_TODEVICE);
+	u8 txdesc_len = 40;
+
+	if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+		RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+			 "DMA mapping error");
+		return;
+	}
+	CLEAR_PCI_TX_DESC_CONTENT(pdesc, txdesc_len);
+
+	if (firstseg)
+		SET_TX_DESC_OFFSET(pdesc, txdesc_len);
+
+	SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
+
+	SET_TX_DESC_SEQ(pdesc, 0);
+
+	SET_TX_DESC_LINIP(pdesc, 0);
+
+	SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
+
+	SET_TX_DESC_FIRST_SEG(pdesc, 1);
+	SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
+
+	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+
+	SET_TX_DESC_RATE_ID(pdesc, 7);
+	SET_TX_DESC_MACID(pdesc, 0);
+
+	SET_TX_DESC_OWN(pdesc, 1);
+
+	SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len));
+
+	SET_TX_DESC_FIRST_SEG(pdesc, 1);
+	SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+	SET_TX_DESC_OFFSET(pdesc, 40);
+
+	SET_TX_DESC_USE_RATE(pdesc, 1);
+
+	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+		      "H2C Tx Cmd Content\n", pdesc, txdesc_len);
+}
+
+void rtl92ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+		      u8 desc_name, u8 *val)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u16 cur_tx_rp = 0;
+	u16 cur_tx_wp = 0;
+	static u16 last_txw_point;
+	static bool over_run;
+	u32 tmp = 0;
+	u8 q_idx = *val;
+
+	if (istx) {
+		switch (desc_name) {
+		case HW_DESC_TX_NEXTDESC_ADDR:
+			SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *)val);
+			break;
+		case HW_DESC_OWN:{
+			struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+			struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[q_idx];
+			u16 max_tx_desc = ring->entries;
+
+			if (q_idx == BEACON_QUEUE) {
+				ring->cur_tx_wp = 0;
+				ring->cur_tx_rp = 0;
+				SET_TX_BUFF_DESC_OWN(pdesc, 1);
+				return;
+			}
+
+			ring->cur_tx_wp = ((ring->cur_tx_wp + 1) % max_tx_desc);
+
+			if (over_run) {
+				ring->cur_tx_wp = 0;
+				over_run = false;
+			}
+			if (ring->avl_desc > 1) {
+				ring->avl_desc--;
+
+				rtl_write_word(rtlpriv,
+					       get_desc_addr_fr_q_idx(q_idx),
+					       ring->cur_tx_wp);
+
+				if (q_idx == 1)
+					last_txw_point = cur_tx_wp;
+			}
+
+			if (ring->avl_desc < (max_tx_desc - 15)) {
+				u16 point_diff = 0;
+
+				tmp =
+				  rtl_read_dword(rtlpriv,
+						 get_desc_addr_fr_q_idx(q_idx));
+				cur_tx_rp = (u16)((tmp >> 16) & 0x0fff);
+				cur_tx_wp = (u16)(tmp & 0x0fff);
+
+				ring->cur_tx_wp = cur_tx_wp;
+				ring->cur_tx_rp = cur_tx_rp;
+				point_diff = ((cur_tx_rp > cur_tx_wp) ?
+					      (cur_tx_rp - cur_tx_wp) :
+					      (TX_DESC_NUM_92E - 1 -
+					       cur_tx_wp + cur_tx_rp));
+
+				ring->avl_desc = point_diff;
+			}
+		}
+		break;
+		}
+	} else {
+		switch (desc_name) {
+		case HW_DESC_RX_PREPARE:
+			SET_RX_BUFFER_DESC_LS(pdesc, 0);
+			SET_RX_BUFFER_DESC_FS(pdesc, 0);
+			SET_RX_BUFFER_DESC_TOTAL_LENGTH(pdesc, 0);
+
+			SET_RX_BUFFER_DESC_DATA_LENGTH(pdesc,
+						       MAX_RECEIVE_BUFFER_SIZE +
+						       RX_DESC_SIZE);
+
+			SET_RX_BUFFER_PHYSICAL_LOW(pdesc, *(u32 *)val);
+			break;
+		case HW_DESC_RXERO:
+			SET_RX_DESC_EOR(pdesc, 1);
+			break;
+		default:
+			RT_ASSERT(false,
+				  "ERR rxdesc :%d not process\n", desc_name);
+			break;
+		}
+	}
+}
+
+u32 rtl92ee_get_desc(u8 *pdesc, bool istx, u8 desc_name)
+{
+	u32 ret = 0;
+
+	if (istx) {
+		switch (desc_name) {
+		case HW_DESC_OWN:
+			ret = GET_TX_DESC_OWN(pdesc);
+			break;
+		case HW_DESC_TXBUFF_ADDR:
+			ret = GET_TXBUFFER_DESC_ADDR_LOW(pdesc, 1);
+			break;
+		default:
+			RT_ASSERT(false,
+				  "ERR txdesc :%d not process\n", desc_name);
+			break;
+		}
+	} else {
+		switch (desc_name) {
+		case HW_DESC_OWN:
+			ret = GET_RX_DESC_OWN(pdesc);
+			break;
+		case HW_DESC_RXPKT_LEN:
+			ret = GET_RX_DESC_PKT_LEN(pdesc);
+			break;
+		case HW_DESC_RXBUFF_ADDR:
+			ret = GET_RX_DESC_BUFF_ADDR(pdesc);
+			break;
+		default:
+			RT_ASSERT(false,
+				  "ERR rxdesc :%d not process\n", desc_name);
+			break;
+		}
+	}
+	return ret;
+}
+
+bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index)
+{
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u16 read_point, write_point, available_desc_num;
+	bool ret = false;
+	static u8 stop_report_cnt;
+	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+
+	/*checking Read/Write Point each interrupt wastes CPU */
+	if (stop_report_cnt > 15 || !rtlpriv->link_info.busytraffic) {
+		u16 point_diff = 0;
+		u16 cur_tx_rp, cur_tx_wp;
+		u32 tmpu32 = 0;
+
+		tmpu32 =
+		  rtl_read_dword(rtlpriv,
+				 get_desc_addr_fr_q_idx(hw_queue));
+		cur_tx_rp = (u16)((tmpu32 >> 16) & 0x0fff);
+		cur_tx_wp = (u16)(tmpu32 & 0x0fff);
+
+		ring->cur_tx_wp = cur_tx_wp;
+		ring->cur_tx_rp = cur_tx_rp;
+		point_diff = ((cur_tx_rp > cur_tx_wp) ?
+			      (cur_tx_rp - cur_tx_wp) :
+			      (TX_DESC_NUM_92E - cur_tx_wp + cur_tx_rp));
+
+		ring->avl_desc = point_diff;
+	}
+
+	read_point = ring->cur_tx_rp;
+	write_point = ring->cur_tx_wp;
+	available_desc_num = ring->avl_desc;
+
+	if (write_point > read_point) {
+		if (index < write_point && index >= read_point)
+			ret = false;
+		else
+			ret = true;
+	} else if (write_point < read_point) {
+		if (index > write_point && index < read_point)
+			ret = true;
+		else
+			ret = false;
+	} else {
+		if (index != read_point)
+			ret = true;
+	}
+
+	if (hw_queue == BEACON_QUEUE)
+		ret = true;
+
+	if (rtlpriv->rtlhal.driver_is_goingto_unload ||
+	    rtlpriv->psc.rfoff_reason > RF_CHANGE_BY_PS)
+		ret = true;
+
+	if (hw_queue < BEACON_QUEUE) {
+		if (!ret)
+			stop_report_cnt++;
+		else
+			stop_report_cnt = 0;
+	}
+
+	return ret;
+}
+
+void rtl92ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
+{
+}
+
+u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw,
+			      struct rtl_stats status,
+			      struct sk_buff *skb)
+{
+	u32 result = 0;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	switch (status.packet_report_type) {
+	case NORMAL_RX:
+		result = 0;
+		break;
+	case C2H_PACKET:
+		rtl92ee_c2h_packet_handler(hw, skb->data, (u8)skb->len);
+		result = 1;
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_RECV, DBG_TRACE,
+			 "Unknown packet type %d\n", status.packet_report_type);
+		break;
+	}
+
+	return result;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h
new file mode 100644
index 0000000..6f9be1c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h
@@ -0,0 +1,860 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2014  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92E_TRX_H__
+#define __RTL92E_TRX_H__
+
+#if (DMA_IS_64BIT == 1)
+#if (RTL8192EE_SEG_NUM == 2)
+#define TX_BD_DESC_SIZE					128
+#elif (RTL8192EE_SEG_NUM == 1)
+#define TX_BD_DESC_SIZE					64
+#elif (RTL8192EE_SEG_NUM == 0)
+#define TX_BD_DESC_SIZE					32
+#endif
+#else
+#if (RTL8192EE_SEG_NUM == 2)
+#define TX_BD_DESC_SIZE					64
+#elif (RTL8192EE_SEG_NUM == 1)
+#define TX_BD_DESC_SIZE					32
+#elif (RTL8192EE_SEG_NUM == 0)
+#define TX_BD_DESC_SIZE					16
+#endif
+#endif
+
+#define TX_DESC_SIZE					64
+
+#define RX_DRV_INFO_SIZE_UNIT				8
+
+#define	TX_DESC_NEXT_DESC_OFFSET			40
+#define USB_HWDESC_HEADER_LEN				40
+
+#define RX_DESC_SIZE					24
+#define MAX_RECEIVE_BUFFER_SIZE				8192
+
+#define SET_TX_DESC_PKT_SIZE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val)
+#define SET_TX_DESC_OFFSET(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val)
+#define SET_TX_DESC_BMC(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val)
+#define SET_TX_DESC_HTC(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val)
+#define SET_TX_DESC_LAST_SEG(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val)
+#define SET_TX_DESC_FIRST_SEG(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val)
+#define SET_TX_DESC_LINIP(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val)
+#define SET_TX_DESC_NO_ACM(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val)
+#define SET_TX_DESC_GF(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_TX_DESC_OWN(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_TX_DESC_PKT_SIZE(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 0, 16)
+#define GET_TX_DESC_OFFSET(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 16, 8)
+#define GET_TX_DESC_BMC(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 24, 1)
+#define GET_TX_DESC_HTC(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 25, 1)
+#define GET_TX_DESC_LAST_SEG(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_TX_DESC_FIRST_SEG(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_TX_DESC_LINIP(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_TX_DESC_NO_ACM(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_TX_DESC_GF(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_TX_DESC_OWN(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_TX_DESC_MACID(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 7, __val)
+#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val)
+#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val)
+#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val)
+#define SET_TX_DESC_PIFS(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val)
+#define SET_TX_DESC_RATE_ID(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 5, __val)
+#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val)
+#define SET_TX_DESC_SEC_TYPE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val)
+#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 5, __val)
+#define SET_TX_DESC_MORE_DATA(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 29, 1, __val)
+#define SET_TX_DESC_TXOP_PS_CAP(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 30, 1, __val)
+#define SET_TX_DESC_TXOP_PS_MODE(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 31, 1, __val)
+
+#define GET_TX_DESC_MACID(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 0, 5)
+#define GET_TX_DESC_AGG_ENABLE(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 5, 1)
+#define GET_TX_DESC_AGG_BREAK(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 6, 1)
+#define GET_TX_DESC_RDG_ENABLE(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 7, 1)
+#define GET_TX_DESC_QUEUE_SEL(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 8, 5)
+#define GET_TX_DESC_RDG_NAV_EXT(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+4, 13, 1)
+#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_TX_DESC_PIFS(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_TX_DESC_RATE_ID(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_TX_DESC_NAV_USE_HDR(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+4, 20, 1)
+#define GET_TX_DESC_EN_DESC_ID(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 21, 1)
+#define GET_TX_DESC_SEC_TYPE(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 22, 2)
+#define GET_TX_DESC_PKT_OFFSET(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 24, 5)
+
+#define SET_TX_DESC_PAID(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 9, __val)
+#define SET_TX_DESC_CCA_RTS(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 10, 2, __val)
+#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 12, 1, __val)
+#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 13, 1, __val)
+#define SET_TX_DESC_NULL_0(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 1, __val)
+#define SET_TX_DESC_NULL_1(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 15, 1, __val)
+#define SET_TX_DESC_BK(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val)
+#define SET_TX_DESC_MORE_FRAG(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val)
+#define SET_TX_DESC_RAW(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val)
+#define SET_TX_DESC_SPE_RPT(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val)
+#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val)
+#define SET_TX_DESC_BT_NULL(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 23, 1, __val)
+#define SET_TX_DESC_GID(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 6, __val)
+
+#define SET_TX_DESC_WHEADER_LEN(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 4, __val)
+#define SET_TX_DESC_CHK_EN(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 4, 1, __val)
+#define SET_TX_DESC_EARLY_RATE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 5, 1, __val)
+#define SET_TX_DESC_HWSEQ_SEL(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 6, 2, __val)
+#define SET_TX_DESC_USE_RATE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 1, __val)
+#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 9, 1, __val)
+#define SET_TX_DESC_DISABLE_FB(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 10, 1, __val)
+#define SET_TX_DESC_CTS2SELF(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 11, 1, __val)
+#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 12, 1, __val)
+#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 13, 1, __val)
+#define SET_TX_DESC_HW_PORT_ID(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 14, 1, __val)
+#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 15, 1, __val)
+#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 1, __val)
+#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 17, 5, __val)
+#define SET_TX_DESC_NDPA(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 22, 2, __val)
+#define SET_TX_DESC_AMPDU_MAX_TIME(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 24, 8, __val)
+
+/* Dword 4 */
+#define SET_TX_DESC_TX_RATE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 7, __val)
+#define SET_TX_DESC_TRY_RATE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 7, 1, __val)
+#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 5, __val)
+#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 4, __val)
+#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 17, 1, __val)
+#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 6, __val)
+#define SET_TX_DESC_RTS_RATE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 5, __val)
+#define SET_TX_DESC_PCTS_ENABLE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 29, 1, __val)
+#define SET_TX_DESC_PCTS_MASK_IDX(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 30, 2, __val)
+
+/* Dword 5 */
+#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 4, __val)
+#define SET_TX_DESC_DATA_SHORT(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 4, 1, __val)
+#define SET_TX_DESC_DATA_BW(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 5, 2, __val)
+#define SET_TX_DESC_DATA_LDPC(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val)
+#define SET_TX_DESC_DATA_STBC(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 2, __val)
+#define SET_TX_DESC_VCS_STBC(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 10, 2, __val)
+#define SET_TX_DESC_RTS_SHORT(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 12, 1, __val)
+#define SET_TX_DESC_RTS_SC(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val)
+#define SET_TX_DESC_TX_ANT(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 24, 4, __val)
+#define SET_TX_DESC_TX_POWER_0_PSET(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 28, 3, __val)
+
+/* Dword 6 */
+#define SET_TX_DESC_SW_DEFINE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 12, __val)
+#define SET_TX_DESC_ANTSEL_A(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+24, 16, 3, __val)
+#define SET_TX_DESC_ANTSEL_B(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+24, 19, 3, __val)
+#define SET_TX_DESC_ANTSEL_C(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+24, 22, 3, __val)
+#define SET_TX_DESC_ANTSEL_D(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+24, 25, 3, __val)
+
+/* Dword 7 */
+#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val)
+#define SET_TX_DESC_USB_TXAGG_NUM(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+28, 24, 8, __val)
+
+/* Dword 8 */
+#define SET_TX_DESC_RTS_RC(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+32, 0, 6, __val)
+#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+32, 6, 2, __val)
+#define SET_TX_DESC_DATA_RC(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+32, 8, 6, __val)
+#define SET_TX_DESC_ENABLE_HW_SELECT(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+32, 15, 1, __val)
+#define SET_TX_DESC_NEXT_HEAD_PAGE(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+32, 16, 8, __val)
+#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+32, 24, 8, __val)
+
+/* Dword 9 */
+#define SET_TX_DESC_PADDING_LENGTH(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+36, 0, 11, __val)
+#define SET_TX_DESC_TXBF_PATH(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+36, 11, 1, __val)
+#define SET_TX_DESC_SEQ(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+36, 12, 12, __val)
+#define SET_TX_DESC_FINAL_DATA_RATE(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+36, 24, 8, __val)
+
+/* Dword 10 */
+#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val)
+
+/* Dword 11*/
+#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+48, 0, 32, __val)
+
+#define SET_EARLYMODE_PKTNUM(__paddr, __val)		\
+	SET_BITS_TO_LE_4BYTE(__paddr, 0, 4, __val)
+#define SET_EARLYMODE_LEN0(__paddr, __val)		\
+	SET_BITS_TO_LE_4BYTE(__paddr, 4, 15, __val)
+#define SET_EARLYMODE_LEN1(__paddr, __val)		\
+	SET_BITS_TO_LE_4BYTE(__paddr, 16, 2, __val)
+#define SET_EARLYMODE_LEN1_1(__paddr, __val)		\
+	SET_BITS_TO_LE_4BYTE(__paddr, 19, 13, __val)
+#define SET_EARLYMODE_LEN1_2(__paddr, __val)		\
+	SET_BITS_TO_LE_4BYTE(__paddr+4, 0, 2, __val)
+#define SET_EARLYMODE_LEN2(__paddr, __val)		\
+	SET_BITS_TO_LE_4BYTE(__paddr+4, 2, 15,  __val)
+#define SET_EARLYMODE_LEN2_1(__paddr, __val)		\
+	SET_BITS_TO_LE_4BYTE(__paddr, 2, 4,  __val)
+#define SET_EARLYMODE_LEN2_2(__paddr, __val)		\
+	SET_BITS_TO_LE_4BYTE(__paddr+4, 0, 8,  __val)
+#define SET_EARLYMODE_LEN3(__paddr, __val)		\
+	SET_BITS_TO_LE_4BYTE(__paddr+4, 17, 15, __val)
+#define SET_EARLYMODE_LEN4(__paddr, __val)		\
+	SET_BITS_TO_LE_4BYTE(__paddr+4, 20, 12, __val)
+
+/* TX/RX buffer descriptor */
+
+#define SET_TX_EXTBUFF_DESC_LEN(__pdesc, __val, __set)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+(__set*16), 0, 16, __val)
+#define SET_TX_EXTBUFF_DESC_ADDR_LOW(__pdesc, __val, __set)\
+	SET_BITS_TO_LE_4BYTE(__pdesc+(__set*16)+4, 0, 32, __val)
+#define SET_TX_EXTBUFF_DESC_ADDR_HIGH(__pdesc, __val, __set)\
+	SET_BITS_TO_LE_4BYTE(__pdesc+(__set*16)+8, 0, 32, __val)
+
+/* for Txfilldescroptor92ee, fill the desc content. */
+#if (DMA_IS_64BIT == 1)
+#define SET_TXBUFFER_DESC_LEN_WITH_OFFSET(__pdesc, __offset, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*16), 0, 16, __val)
+#define SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(__pdesc, __offset, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*16), 31, 1, __val)
+#define SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(__pdesc, __offset, __val) \
+	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*16)+4, 0, 32, __val)
+#define SET_TXBUFFER_DESC_ADD_HIGT_WITH_OFFSET(__pdesc, __offset, __val)\
+	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*16)+8, 0, 32, __val)
+#define GET_TXBUFFER_DESC_ADDR_LOW(__pdesc, __offset)			\
+	LE_BITS_TO_4BYTE(__pdesc+(__offset*16)+4, 0, 32)
+#else
+#define SET_TXBUFFER_DESC_LEN_WITH_OFFSET(__pdesc, __offset, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*8), 0, 16, __val)
+#define SET_TXBUFFER_DESC_AMSDU_WITH_OFFSET(__pdesc, __offset, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*8), 31, 1, __val)
+#define SET_TXBUFFER_DESC_ADD_LOW_WITH_OFFSET(__pdesc, __offset, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+(__offset*8)+4, 0, 32, __val)
+#define SET_TXBUFFER_DESC_ADD_HIGT_WITH_OFFSET(__pdesc, __offset, __val)
+#define GET_TXBUFFER_DESC_ADDR_LOW(__pdesc, __offset)			\
+	LE_BITS_TO_4BYTE(__pdesc+(__offset*8)+4, 0, 32)
+#endif
+
+/* Dword 0 */
+#define SET_TX_BUFF_DESC_LEN_0(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val)
+#define SET_TX_BUFF_DESC_PSB(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 16, 15, __val)
+#define SET_TX_BUFF_DESC_OWN(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+/* Dword 1 */
+#define SET_TX_BUFF_DESC_ADDR_LOW_0(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 32, __val)
+#if (DMA_IS_64BIT == 1)
+/* Dword 2 */
+#define SET_TX_BUFF_DESC_ADDR_HIGH_0(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 32, __val)
+/* Dword 3 / RESERVED 0 */
+/* Dword 4 */
+#define SET_TX_BUFF_DESC_LEN_1(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 16, __val)
+#define SET_TX_BUFF_DESC_AMSDU_1(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 31, 1, __val)
+/* Dword 5 */
+#define SET_TX_BUFF_DESC_ADDR_LOW_1(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 32, __val)
+/* Dword 6 */
+#define SET_TX_BUFF_DESC_ADDR_HIGH_1(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val)
+/* Dword 7 / RESERVED 0 */
+/* Dword 8 */
+#define SET_TX_BUFF_DESC_LEN_2(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+32, 0, 16, __val)
+#define SET_TX_BUFF_DESC_AMSDU_2(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+32, 31, 1, __val)
+/* Dword 9 */
+#define SET_TX_BUFF_DESC_ADDR_LOW_2(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+36, 0, 32, __val)
+/* Dword 10 */
+#define SET_TX_BUFF_DESC_ADDR_HIGH_2(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val)
+/* Dword 11 / RESERVED 0 */
+/* Dword 12 */
+#define SET_TX_BUFF_DESC_LEN_3(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+48, 0, 16, __val)
+#define SET_TX_BUFF_DESC_AMSDU_3(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+48, 31, 1, __val)
+/* Dword 13 */
+#define SET_TX_BUFF_DESC_ADDR_LOW_3(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+52, 0, 32, __val)
+/* Dword 14 */
+#define SET_TX_BUFF_DESC_ADDR_HIGH_3(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+56, 0, 32, __val)
+/* Dword 15 / RESERVED 0 */
+#else
+#define SET_TX_BUFF_DESC_ADDR_HIGH_0(__pdesc, __val)
+/* Dword 2 */
+#define SET_TX_BUFF_DESC_LEN_1(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 16, __val)
+#define SET_TX_BUFF_DESC_AMSDU_1(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 31, 1, __val)
+/* Dword 3 */
+#define SET_TX_BUFF_DESC_ADDR_LOW_1(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 32, __val)
+#define SET_TX_BUFF_DESC_ADDR_HIGH_1(__pdesc, __val)
+/* Dword 4 */
+#define SET_TX_BUFF_DESC_LEN_2(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 16, __val)
+#define SET_TX_BUFF_DESC_AMSDU_2(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 31, 1, __val)
+/* Dword 5 */
+#define SET_TX_BUFF_DESC_ADDR_LOW_2(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 32, __val)
+#define SET_TX_BUFF_DESC_ADDR_HIGH_2(__pdesc, __val)
+/* Dword 6 */
+#define SET_TX_BUFF_DESC_LEN_3(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 16, __val)
+#define SET_TX_BUFF_DESC_AMSDU_3(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+24, 31, 1, __val)
+/* Dword 7 */
+#define SET_TX_BUFF_DESC_ADDR_LOW_3(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val)
+#define SET_TX_BUFF_DESC_ADDR_HIGH_3(__pdesc, __val)
+#endif
+
+/* RX buffer  */
+
+/* DWORD 0 */
+#define SET_RX_BUFFER_DESC_DATA_LENGTH(__status, __val)	\
+	SET_BITS_TO_LE_4BYTE(__status, 0, 14, __val)
+#define SET_RX_BUFFER_DESC_LS(__status, __val)		\
+	SET_BITS_TO_LE_4BYTE(__status, 15, 1, __val)
+#define SET_RX_BUFFER_DESC_FS(__status, __val)		\
+	SET_BITS_TO_LE_4BYTE(__status, 16, 1, __val)
+#define SET_RX_BUFFER_DESC_TOTAL_LENGTH(__status, __val)	\
+	SET_BITS_TO_LE_4BYTE(__status, 16, 15, __val)
+
+#define GET_RX_BUFFER_DESC_OWN(__status)			\
+	LE_BITS_TO_4BYTE(__status, 31, 1)
+#define GET_RX_BUFFER_DESC_LS(__status)			\
+	LE_BITS_TO_4BYTE(__status, 15, 1)
+#define GET_RX_BUFFER_DESC_FS(__status)			\
+	LE_BITS_TO_4BYTE(__status, 16, 1)
+#define GET_RX_BUFFER_DESC_TOTAL_LENGTH(__status)	\
+	LE_BITS_TO_4BYTE(__status, 16, 15)
+
+/* DWORD 1 */
+#define SET_RX_BUFFER_PHYSICAL_LOW(__status, __val)	\
+	SET_BITS_TO_LE_4BYTE(__status+4, 0, 32, __val)
+
+/* DWORD 2 */
+#define SET_RX_BUFFER_PHYSICAL_HIGH(__status, __val)	\
+	SET_BITS_TO_LE_4BYTE(__status+8, 0, 32, __val)
+
+#define GET_RX_DESC_PKT_LEN(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 0, 14)
+#define GET_RX_DESC_CRC32(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 14, 1)
+#define GET_RX_DESC_ICV(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 15, 1)
+#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc, 16, 4)
+#define GET_RX_DESC_SECURITY(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 20, 3)
+#define GET_RX_DESC_QOS(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 23, 1)
+#define GET_RX_DESC_SHIFT(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 24, 2)
+#define GET_RX_DESC_PHYST(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_RX_DESC_SWDEC(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_RX_DESC_LS(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_RX_DESC_FS(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_RX_DESC_EOR(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_RX_DESC_OWN(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_RX_DESC_PKT_LEN(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val)
+#define SET_RX_DESC_EOR(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_RX_DESC_OWN(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_RX_DESC_MACID(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 0, 7)
+#define GET_RX_DESC_TID(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 8, 4)
+#define GET_RX_DESC_MACID_VLD(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 12, 1)
+#define GET_RX_DESC_AMSDU(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 13, 1)
+#define GET_RX_DESC_RXID_MATCH(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_RX_DESC_PAGGR(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_RX_DESC_A1_FIT(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_RX_DESC_TCPOFFLOAD_CHKERR(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+4, 20, 1)
+#define GET_RX_DESC_TCPOFFLOAD_IPVER(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+4, 21, 1)
+#define GET_RX_DESC_TCPOFFLOAD_IS_TCPUDP(__pdesc)	\
+	LE_BITS_TO_4BYTE(__pdesc+4, 22, 1)
+#define GET_RX_DESC_TCPOFFLOAD_CHK_VLD(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+4, 23, 1)
+#define GET_RX_DESC_PAM(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 24, 1)
+#define GET_RX_DESC_PWR(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 25, 1)
+#define GET_RX_DESC_MD(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+4, 26, 1)
+#define GET_RX_DESC_MF(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+4, 27, 1)
+#define GET_RX_DESC_TYPE(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 28, 2)
+#define GET_RX_DESC_MC(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+4, 30, 1)
+#define GET_RX_DESC_BC(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+4, 31, 1)
+#define GET_RX_DESC_SEQ(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+8, 0, 12)
+#define GET_RX_DESC_FRAG(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+8, 12, 4)
+#define GET_RX_DESC_RX_IS_QOS(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+8, 16, 1)
+
+#define GET_RX_DESC_RXMCS(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+12, 0, 7)
+#define GET_RX_DESC_HTC(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+12, 10, 1)
+#define GET_RX_STATUS_DESC_EOSP(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+12, 11, 1)
+#define GET_RX_STATUS_DESC_BSSID_FIT(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+12, 12, 2)
+#define GET_RX_STATUS_DESC_DMA_AGG_NUM(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+12, 16, 8)
+#define GET_RX_STATUS_DESC_PATTERN_MATCH(__pdesc)	\
+	LE_BITS_TO_4BYTE(__pdesc+12, 29, 1)
+#define GET_RX_STATUS_DESC_UNICAST_MATCH(__pdesc)	\
+	LE_BITS_TO_4BYTE(__pdesc+12, 30, 1)
+#define GET_RX_STATUS_DESC_MAGIC_MATCH(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+12, 31, 1)
+
+#define GET_RX_DESC_TSFL(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+20, 0, 32)
+
+#define GET_RX_DESC_BUFF_ADDR(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+24, 0, 32)
+#define GET_RX_DESC_BUFF_ADDR64(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+28, 0, 32)
+
+#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val)
+#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val)
+
+/* TX report 2 format in Rx desc*/
+
+#define GET_RX_RPT2_DESC_PKT_LEN(__status)	\
+	LE_BITS_TO_4BYTE(__status, 0, 9)
+#define GET_RX_RPT2_DESC_MACID_VALID_1(__status)	\
+	LE_BITS_TO_4BYTE(__status+16, 0, 32)
+#define GET_RX_RPT2_DESC_MACID_VALID_2(__status)	\
+	LE_BITS_TO_4BYTE(__status+20, 0, 32)
+
+#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size)		\
+do {								\
+	if (_size > TX_DESC_NEXT_DESC_OFFSET)			\
+		memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET);	\
+	else							\
+		memset(__pdesc, 0, _size);			\
+} while (0)
+
+#define RTL92EE_RX_HAL_IS_CCK_RATE(rxmcs)\
+	(rxmcs == DESC92C_RATE1M ||\
+	 rxmcs == DESC92C_RATE2M ||\
+	 rxmcs == DESC92C_RATE5_5M ||\
+	 rxmcs == DESC92C_RATE11M)
+
+#define IS_LITTLE_ENDIAN	1
+
+struct phy_rx_agc_info_t {
+	#if IS_LITTLE_ENDIAN
+		u8 gain:7, trsw:1;
+	#else
+		u8 trsw:1, gain:7;
+	#endif
+};
+
+struct phy_status_rpt {
+	struct phy_rx_agc_info_t path_agc[2];
+	u8 ch_corr[2];
+	u8 cck_sig_qual_ofdm_pwdb_all;
+	u8 cck_agc_rpt_ofdm_cfosho_a;
+	u8 cck_rpt_b_ofdm_cfosho_b;
+	u8 rsvd_1;
+	u8 noise_power_db_msb;
+	u8 path_cfotail[2];
+	u8 pcts_mask[2];
+	u8 stream_rxevm[2];
+	u8 path_rxsnr[2];
+	u8 noise_power_db_lsb;
+	u8 rsvd_2[3];
+	u8 stream_csi[2];
+	u8 stream_target_csi[2];
+	u8 sig_evm;
+	u8 rsvd_3;
+#if IS_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 ant_sel_b:1;
+	u8 ant_sel:1;
+#else	/* _BIG_ENDIAN_	*/
+	u8 ant_sel:1;
+	u8 ant_sel_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
+} __packed;
+
+struct rx_fwinfo {
+	u8 gain_trsw[4];
+	u8 pwdb_all;
+	u8 cfosho[4];
+	u8 cfotail[4];
+	char rxevm[2];
+	char rxsnr[4];
+	u8 pdsnr[2];
+	u8 csi_current[2];
+	u8 csi_target[2];
+	u8 sigevm;
+	u8 max_ex_pwr;
+	u8 ex_intf_flag:1;
+	u8 sgi_en:1;
+	u8 rxsc:2;
+	u8 reserve:4;
+} __packed;
+
+struct tx_desc {
+	u32 pktsize:16;
+	u32 offset:8;
+	u32 bmc:1;
+	u32 htc:1;
+	u32 lastseg:1;
+	u32 firstseg:1;
+	u32 linip:1;
+	u32 noacm:1;
+	u32 gf:1;
+	u32 own:1;
+
+	u32 macid:6;
+	u32 rsvd0:2;
+	u32 queuesel:5;
+	u32 rd_nav_ext:1;
+	u32 lsig_txop_en:1;
+	u32 pifs:1;
+	u32 rateid:4;
+	u32 nav_usehdr:1;
+	u32 en_descid:1;
+	u32 sectype:2;
+	u32 pktoffset:8;
+
+	u32 rts_rc:6;
+	u32 data_rc:6;
+	u32 agg_en:1;
+	u32 rdg_en:1;
+	u32 bar_retryht:2;
+	u32 agg_break:1;
+	u32 morefrag:1;
+	u32 raw:1;
+	u32 ccx:1;
+	u32 ampdudensity:3;
+	u32 bt_int:1;
+	u32 ant_sela:1;
+	u32 ant_selb:1;
+	u32 txant_cck:2;
+	u32 txant_l:2;
+	u32 txant_ht:2;
+
+	u32 nextheadpage:8;
+	u32 tailpage:8;
+	u32 seq:12;
+	u32 cpu_handle:1;
+	u32 tag1:1;
+	u32 trigger_int:1;
+	u32 hwseq_en:1;
+
+	u32 rtsrate:5;
+	u32 apdcfe:1;
+	u32 qos:1;
+	u32 hwseq_ssn:1;
+	u32 userrate:1;
+	u32 dis_rtsfb:1;
+	u32 dis_datafb:1;
+	u32 cts2self:1;
+	u32 rts_en:1;
+	u32 hwrts_en:1;
+	u32 portid:1;
+	u32 pwr_status:3;
+	u32 waitdcts:1;
+	u32 cts2ap_en:1;
+	u32 txsc:2;
+	u32 stbc:2;
+	u32 txshort:1;
+	u32 txbw:1;
+	u32 rtsshort:1;
+	u32 rtsbw:1;
+	u32 rtssc:2;
+	u32 rtsstbc:2;
+
+	u32 txrate:6;
+	u32 shortgi:1;
+	u32 ccxt:1;
+	u32 txrate_fb_lmt:5;
+	u32 rtsrate_fb_lmt:4;
+	u32 retrylmt_en:1;
+	u32 txretrylmt:6;
+	u32 usb_txaggnum:8;
+
+	u32 txagca:5;
+	u32 txagcb:5;
+	u32 usemaxlen:1;
+	u32 maxaggnum:5;
+	u32 mcsg1maxlen:4;
+	u32 mcsg2maxlen:4;
+	u32 mcsg3maxlen:4;
+	u32 mcs7sgimaxlen:4;
+
+	u32 txbuffersize:16;
+	u32 sw_offset30:8;
+	u32 sw_offset31:4;
+	u32 rsvd1:1;
+	u32 antsel_c:1;
+	u32 null_0:1;
+	u32 null_1:1;
+
+	u32 txbuffaddr;
+	u32 txbufferaddr64;
+	u32 nextdescaddress;
+	u32 nextdescaddress64;
+
+	u32 reserve_pass_pcie_mm_limit[4];
+} __packed;
+
+struct rx_desc {
+	u32 length:14;
+	u32 crc32:1;
+	u32 icverror:1;
+	u32 drv_infosize:4;
+	u32 security:3;
+	u32 qos:1;
+	u32 shift:2;
+	u32 phystatus:1;
+	u32 swdec:1;
+	u32 lastseg:1;
+	u32 firstseg:1;
+	u32 eor:1;
+	u32 own:1;
+
+	u32 macid:6;
+	u32 tid:4;
+	u32 hwrsvd:5;
+	u32 paggr:1;
+	u32 faggr:1;
+	u32 a1_fit:4;
+	u32 a2_fit:4;
+	u32 pam:1;
+	u32 pwr:1;
+	u32 moredata:1;
+	u32 morefrag:1;
+	u32 type:2;
+	u32 mc:1;
+	u32 bc:1;
+
+	u32 seq:12;
+	u32 frag:4;
+	u32 nextpktlen:14;
+	u32 nextind:1;
+	u32 rsvd:1;
+
+	u32 rxmcs:6;
+	u32 rxht:1;
+	u32 amsdu:1;
+	u32 splcp:1;
+	u32 bandwidth:1;
+	u32 htc:1;
+	u32 tcpchk_rpt:1;
+	u32 ipcchk_rpt:1;
+	u32 tcpchk_valid:1;
+	u32 hwpcerr:1;
+	u32 hwpcind:1;
+	u32 iv0:16;
+
+	u32 iv1;
+
+	u32 tsfl;
+
+	u32 bufferaddress;
+	u32 bufferaddress64;
+
+} __packed;
+
+void rtl92ee_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc,
+			     u8 queue_index);
+u16	rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw,
+					  u8 queue_index);
+void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 queue_index);
+void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw,
+				 u8 *tx_bd_desc, u8 *desc, u8 queue_index,
+				 struct sk_buff *skb, dma_addr_t addr);
+
+void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw,
+			  struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+			  u8 *pbd_desc_tx,
+			  struct ieee80211_tx_info *info,
+			  struct ieee80211_sta *sta,
+			  struct sk_buff *skb,
+			  u8 hw_queue, struct rtl_tcb_desc *ptcb_desc);
+bool rtl92ee_rx_query_desc(struct ieee80211_hw *hw,
+			   struct rtl_stats *status,
+			   struct ieee80211_rx_status *rx_status,
+			   u8 *pdesc, struct sk_buff *skb);
+void rtl92ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
+		      u8 desc_name, u8 *val);
+
+u32 rtl92ee_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index);
+void rtl92ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
+void rtl92ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+			     bool firstseg, bool lastseg,
+			     struct sk_buff *skb);
+u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw,
+			      struct rtl_stats status,
+			      struct sk_buff *skb);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.h b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
index d53f433..b1e44b8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
@@ -336,7 +336,6 @@
 	H2C_TMP3,
 	H2C_WOWLAN_UPDATE_IV_CMD,			/*50*/
 	H2C_TMP4,
-	MAX_H2CCMD					/*52*/
 };
 
 /* The following macros are used for FW
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
index 2b3c78b..b358ebc 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -312,10 +312,6 @@
 		hdr = (struct ieee80211_hdr *)(skb->data +
 		       stats->rx_drvinfo_size + stats->rx_bufshift);
 
-		if (!hdr) {
-			/* during testing, hdr was NULL here */
-			return false;
-		}
 		if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
 			(ieee80211_has_protected(hdr->frame_control)))
 			rx_status->flag &= ~RX_FLAG_DECRYPTED;
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/btc.h b/drivers/net/wireless/rtlwifi/rtl8723ae/btc.h
index 417afee..06c448c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/btc.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/btc.h
@@ -11,10 +11,6 @@
  ** FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  ** more details.
  **
- ** You should have received a copy of the GNU General Public License along with
- ** this program; if not, write to the Free Software Foundation, Inc.,
- ** 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- **
  ** The full GNU General Public License is included in this distribution in the
  ** file called LICENSE.
  **
@@ -24,8 +20,7 @@
  ** Hsinchu 300, Taiwan.
  ** Larry Finger <Larry.Finger@lwfinger.net>
  **
- *****************************************************************************
- */
+ ******************************************************************************/
 
 #ifndef __RTL8723E_BTC_H__
 #define __RTL8723E_BTC_H__
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/def.h b/drivers/net/wireless/rtlwifi/rtl8723ae/def.h
index debe261..94bdd4b 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/def.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -25,55 +21,145 @@
  *
  * Larry Finger <Larry.Finger@lwfinger.net>
  *
- ****************************************************************************
- */
+ *****************************************************************************/
 
 #ifndef __RTL8723E_DEF_H__
 #define __RTL8723E_DEF_H__
 
+#define HAL_RETRY_LIMIT_INFRA				48
+#define HAL_RETRY_LIMIT_AP_ADHOC			7
+
+#define RESET_DELAY_8185					20
+
+#define RT_IBSS_INT_MASKS	(IMR_BCNINT | IMR_TBDOK | IMR_TBDER)
+#define RT_AC_INT_MASKS		(IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK)
+
+#define NUM_OF_FIRMWARE_QUEUE				10
+#define NUM_OF_PAGES_IN_FW					0x100
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK			0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE			0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI			0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO			0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA		0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_CMD			0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT		0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH		0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_BCN			0x2
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB			0xA1
+
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM		0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM		0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM		0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM		0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM		0x00
+
+#define MAX_LINES_HWCONFIG_TXT				1000
+#define MAX_BYTES_LINE_HWCONFIG_TXT			256
+
+#define SW_THREE_WIRE						0
+#define HW_THREE_WIRE						2
+
+#define BT_DEMO_BOARD						0
+#define BT_QA_BOARD							1
+#define BT_FPGA								2
+
+#define HAL_PRIME_CHNL_OFFSET_DONT_CARE		0
 #define HAL_PRIME_CHNL_OFFSET_LOWER			1
+#define HAL_PRIME_CHNL_OFFSET_UPPER			2
 
-#define RX_MPDU_QUEUE					0
+#define MAX_H2C_QUEUE_NUM					10
 
-#define CHIP_8723			BIT(0)
-#define NORMAL_CHIP			BIT(3)
-#define RF_TYPE_1T2R			BIT(4)
-#define RF_TYPE_2T2R			BIT(5)
-#define CHIP_VENDOR_UMC			BIT(7)
-#define B_CUT_VERSION			BIT(12)
-#define C_CUT_VERSION			BIT(13)
-#define D_CUT_VERSION			((BIT(12)|BIT(13)))
-#define E_CUT_VERSION			BIT(14)
-#define	RF_RL_ID			(BIT(31)|BIT(30)|BIT(29)|BIT(28))
+#define RX_MPDU_QUEUE						0
+#define RX_CMD_QUEUE						1
+#define RX_MAX_QUEUE						2
+#define AC2QUEUEID(_AC)						(_AC)
 
+#define	C2H_RX_CMD_HDR_LEN					8
+#define	GET_C2H_CMD_CMD_LEN(__prxhdr)		\
+	LE_BITS_TO_4BYTE((__prxhdr), 0, 16)
+#define	GET_C2H_CMD_ELEMENT_ID(__prxhdr)	\
+	LE_BITS_TO_4BYTE((__prxhdr), 16, 8)
+#define	GET_C2H_CMD_CMD_SEQ(__prxhdr)		\
+	LE_BITS_TO_4BYTE((__prxhdr), 24, 7)
+#define	GET_C2H_CMD_CONTINUE(__prxhdr)		\
+	LE_BITS_TO_4BYTE((__prxhdr), 31, 1)
+#define	GET_C2H_CMD_CONTENT(__prxhdr)		\
+	((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN)
+
+#define	GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr)	\
+	LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8)
+#define	GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr)		\
+	LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8)
+#define	GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr)	\
+	LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16)
+#define	GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr)	\
+	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5)
+#define	GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr)		\
+	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1)
+#define	GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr)	\
+	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5)
+#define	GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr)		\
+	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1)
+#define	GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr)		\
+	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4)
+#define	GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr)		\
+	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12)
+
+#define CHIP_BONDING_IDENTIFIER(_value)	(((_value)>>22)&0x3)
+#define	CHIP_BONDING_92C_1T2R		0x1
+
+#define CHIP_8723		BIT(0)
+#define NORMAL_CHIP		BIT(3)
+#define RF_TYPE_1T1R		(~(BIT(4)|BIT(5)|BIT(6)))
+#define RF_TYPE_1T2R		BIT(4)
+#define RF_TYPE_2T2R		BIT(5)
+#define CHIP_VENDOR_UMC		BIT(7)
+#define B_CUT_VERSION		BIT(12)
+#define C_CUT_VERSION		BIT(13)
+#define D_CUT_VERSION		((BIT(12)|BIT(13)))
+#define E_CUT_VERSION		BIT(14)
+#define	RF_RL_ID		(BIT(31)|BIT(30)|BIT(29)|BIT(28))
 
 /* MASK */
-#define IC_TYPE_MASK			(BIT(0)|BIT(1)|BIT(2))
-#define CHIP_TYPE_MASK			BIT(3)
-#define RF_TYPE_MASK			(BIT(4)|BIT(5)|BIT(6))
-#define MANUFACTUER_MASK		BIT(7)
-#define ROM_VERSION_MASK		(BIT(11)|BIT(10)|BIT(9)|BIT(8))
-#define CUT_VERSION_MASK		(BIT(15)|BIT(14)|BIT(13)|BIT(12))
+#define IC_TYPE_MASK		(BIT(0)|BIT(1)|BIT(2))
+#define CHIP_TYPE_MASK		BIT(3)
+#define RF_TYPE_MASK		(BIT(4)|BIT(5)|BIT(6))
+#define MANUFACTUER_MASK	BIT(7)
+#define ROM_VERSION_MASK	(BIT(11)|BIT(10)|BIT(9)|BIT(8))
+#define CUT_VERSION_MASK	(BIT(15)|BIT(14)|BIT(13)|BIT(12))
 
 /* Get element */
 #define GET_CVID_IC_TYPE(version)	((version) & IC_TYPE_MASK)
+#define GET_CVID_CHIP_TYPE(version)	((version) & CHIP_TYPE_MASK)
+#define GET_CVID_RF_TYPE(version)	((version) & RF_TYPE_MASK)
 #define GET_CVID_MANUFACTUER(version)	((version) & MANUFACTUER_MASK)
+#define GET_CVID_ROM_VERSION(version)	((version) & ROM_VERSION_MASK)
 #define GET_CVID_CUT_VERSION(version)	((version) & CUT_VERSION_MASK)
 
-#define IS_81XXC(version)		((GET_CVID_IC_TYPE(version) == 0) ?\
-					true : false)
-#define IS_8723_SERIES(version)						\
-		((GET_CVID_IC_TYPE(version) == CHIP_8723) ? true : false)
-#define IS_CHIP_VENDOR_UMC(version)					\
-		((GET_CVID_MANUFACTUER(version)) ? true : false)
+#define IS_81XXC(version)	((GET_CVID_IC_TYPE(version) == 0) ?\
+						true : false)
+#define IS_8723_SERIES(version)	((GET_CVID_IC_TYPE(version) == CHIP_8723) ? \
+						true : false)
+#define IS_1T1R(version)	((GET_CVID_RF_TYPE(version)) ? false : true)
+#define IS_1T2R(version)	((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R)\
+						? true : false)
+#define IS_2T2R(version)	((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R)\
+						? true : false)
+#define IS_CHIP_VENDOR_UMC(version)	((GET_CVID_MANUFACTUER(version)) ? \
+						true : false)
 
-#define IS_VENDOR_UMC_A_CUT(version)	((IS_CHIP_VENDOR_UMC(version)) ? \
-		((GET_CVID_CUT_VERSION(version)) ? false : true) : false)
-#define IS_VENDOR_8723_A_CUT(version)	((IS_8723_SERIES(version)) ?	\
-		((GET_CVID_CUT_VERSION(version)) ? false : true) : false)
-#define IS_81xxC_VENDOR_UMC_B_CUT(version)	((IS_CHIP_VENDOR_UMC(version)) \
-		? ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? \
-		true : false) : false)
+#define IS_VENDOR_UMC_A_CUT(version)	((IS_CHIP_VENDOR_UMC(version))\
+					? ((GET_CVID_CUT_VERSION(version)) ? \
+					false : true) : false)
+#define IS_VENDOR_8723_A_CUT(version)	((IS_8723_SERIES(version))\
+					? ((GET_CVID_CUT_VERSION(version)) ? \
+					false : true) : false)
+#define IS_VENDOR_8723A_B_CUT(version)	((IS_8723_SERIES(version))\
+		? ((GET_CVID_CUT_VERSION(version) == \
+		B_CUT_VERSION) ? true : false) : false)
+#define IS_81xxC_VENDOR_UMC_B_CUT(version)	((IS_CHIP_VENDOR_UMC(version))\
+		? ((GET_CVID_CUT_VERSION(version) == \
+		B_CUT_VERSION) ? true : false) : false)
 
 enum rf_optype {
 	RF_OP_BY_SW_3WIRE = 0,
@@ -93,7 +179,7 @@
 	POWER_SAVE_MODE_SAVE,
 };
 
-enum power_polocy_config {
+enum power_policy_config {
 	POWERCFG_MAX_POWER_SAVINGS,
 	POWERCFG_GLOBAL_POWER_SAVINGS,
 	POWERCFG_LOCAL_POWER_SAVINGS,
@@ -143,6 +229,41 @@
 	QSLT_CMD = 0x13,
 };
 
+enum rtl_desc8723e_rate {
+	DESC92C_RATE1M = 0x00,
+	DESC92C_RATE2M = 0x01,
+	DESC92C_RATE5_5M = 0x02,
+	DESC92C_RATE11M = 0x03,
+
+	DESC92C_RATE6M = 0x04,
+	DESC92C_RATE9M = 0x05,
+	DESC92C_RATE12M = 0x06,
+	DESC92C_RATE18M = 0x07,
+	DESC92C_RATE24M = 0x08,
+	DESC92C_RATE36M = 0x09,
+	DESC92C_RATE48M = 0x0a,
+	DESC92C_RATE54M = 0x0b,
+
+	DESC92C_RATEMCS0 = 0x0c,
+	DESC92C_RATEMCS1 = 0x0d,
+	DESC92C_RATEMCS2 = 0x0e,
+	DESC92C_RATEMCS3 = 0x0f,
+	DESC92C_RATEMCS4 = 0x10,
+	DESC92C_RATEMCS5 = 0x11,
+	DESC92C_RATEMCS6 = 0x12,
+	DESC92C_RATEMCS7 = 0x13,
+	DESC92C_RATEMCS8 = 0x14,
+	DESC92C_RATEMCS9 = 0x15,
+	DESC92C_RATEMCS10 = 0x16,
+	DESC92C_RATEMCS11 = 0x17,
+	DESC92C_RATEMCS12 = 0x18,
+	DESC92C_RATEMCS13 = 0x19,
+	DESC92C_RATEMCS14 = 0x1a,
+	DESC92C_RATEMCS15 = 0x1b,
+	DESC92C_RATEMCS15_SG = 0x1c,
+	DESC92C_RATEMCS32 = 0x20,
+};
+
 struct phy_sts_cck_8723e_t {
 	u8 adc_pwdb_X[4];
 	u8 sq_rpt;
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
index 25cc830..a0e8692 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -25,8 +21,7 @@
  *
  * Larry Finger <Larry.Finger@lwfinger.net>
  *
- ****************************************************************************
- */
+ *****************************************************************************/
 
 #include "../wifi.h"
 #include "../base.h"
@@ -151,7 +146,7 @@
 	{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}
 };
 
-static void rtl8723ae_dm_diginit(struct ieee80211_hw *hw)
+static void rtl8723e_dm_diginit(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
@@ -176,7 +171,7 @@
 	dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;
 }
 
-static u8 rtl_init_gain_min_pwdb(struct ieee80211_hw *hw)
+static u8 rtl8723e_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
@@ -195,14 +190,15 @@
 	} else if (dm_digtable->cursta_cstate == DIG_STA_CONNECT ||
 		   dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT) {
 		rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
-	} else if (dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) {
+	} else if (dm_digtable->curmultista_cstate ==
+		DIG_MULTISTA_CONNECT) {
 		rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb;
 	}
 
 	return (u8) rssi_val_min;
 }
 
-static void rtl8723ae_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
+static void rtl8723e_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
 {
 	u32 ret_value;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -239,8 +235,7 @@
 	rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 2);
 
 	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
-		 "cnt_parity_fail = %d, cnt_rate_illegal = %d, "
-		 "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
+		 "cnt_parity_fail = %d, cnt_rate_illegal = %d, cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
 		 falsealm_cnt->cnt_parity_fail,
 		 falsealm_cnt->cnt_rate_illegal,
 		 falsealm_cnt->cnt_crc8_fail, falsealm_cnt->cnt_mcs_fail);
@@ -263,52 +258,60 @@
 		value_igi += 0;
 	else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH2)
 		value_igi++;
-	else
+	else if (rtlpriv->falsealm_cnt.cnt_all >= DM_DIG_FA_TH2)
 		value_igi += 2;
-
-	value_igi = clamp(value_igi, (u8)DM_DIG_FA_LOWER, (u8)DM_DIG_FA_UPPER);
+	if (value_igi > DM_DIG_FA_UPPER)
+		value_igi = DM_DIG_FA_UPPER;
+	else if (value_igi < DM_DIG_FA_LOWER)
+		value_igi = DM_DIG_FA_LOWER;
 	if (rtlpriv->falsealm_cnt.cnt_all > 10000)
 		value_igi = 0x32;
 
 	dm_digtable->cur_igvalue = value_igi;
-	rtl8723ae_dm_write_dig(hw);
+	rtl8723e_dm_write_dig(hw);
 }
 
 static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct dig_t *dgtbl = &rtlpriv->dm_digtable;
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
-	if (rtlpriv->falsealm_cnt.cnt_all > dgtbl->fa_highthresh) {
-		if ((dgtbl->back_val - 2) < dgtbl->back_range_min)
-			dgtbl->back_val = dgtbl->back_range_min;
+	if (rtlpriv->falsealm_cnt.cnt_all > dm_digtable->fa_highthresh) {
+		if ((dm_digtable->back_val - 2) <
+		    dm_digtable->back_range_min)
+			dm_digtable->back_val =
+			    dm_digtable->back_range_min;
 		else
-			dgtbl->back_val -= 2;
-	} else if (rtlpriv->falsealm_cnt.cnt_all < dgtbl->fa_lowthresh) {
-		if ((dgtbl->back_val + 2) > dgtbl->back_range_max)
-			dgtbl->back_val = dgtbl->back_range_max;
+			dm_digtable->back_val -= 2;
+	} else if (rtlpriv->falsealm_cnt.cnt_all < dm_digtable->fa_lowthresh) {
+		if ((dm_digtable->back_val + 2) >
+		    dm_digtable->back_range_max)
+			dm_digtable->back_val =
+			    dm_digtable->back_range_max;
 		else
-			dgtbl->back_val += 2;
+			dm_digtable->back_val += 2;
 	}
 
-	if ((dgtbl->rssi_val_min + 10 - dgtbl->back_val) >
-	    dgtbl->rx_gain_max)
-		dgtbl->cur_igvalue = dgtbl->rx_gain_max;
-	else if ((dgtbl->rssi_val_min + 10 -
-		  dgtbl->back_val) < dgtbl->rx_gain_min)
-		dgtbl->cur_igvalue = dgtbl->rx_gain_min;
+	if ((dm_digtable->rssi_val_min + 10 - dm_digtable->back_val) >
+	    dm_digtable->rx_gain_max)
+		dm_digtable->cur_igvalue = dm_digtable->rx_gain_max;
+	else if ((dm_digtable->rssi_val_min + 10 -
+		  dm_digtable->back_val) < dm_digtable->rx_gain_min)
+		dm_digtable->cur_igvalue = dm_digtable->rx_gain_min;
 	else
-		dgtbl->cur_igvalue = dgtbl->rssi_val_min + 10 - dgtbl->back_val;
+		dm_digtable->cur_igvalue = dm_digtable->rssi_val_min + 10 -
+		    dm_digtable->back_val;
 
 	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
 		 "rssi_val_min = %x back_val %x\n",
-		 dgtbl->rssi_val_min, dgtbl->back_val);
+		  dm_digtable->rssi_val_min, dm_digtable->back_val);
 
-	rtl8723ae_dm_write_dig(hw);
+	rtl8723e_dm_write_dig(hw);
 }
 
-static void rtl8723ae_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
+static void rtl8723e_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
 {
+	static u8 binitialized;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
@@ -318,16 +321,15 @@
 	if (mac->opmode == NL80211_IFTYPE_ADHOC)
 		multi_sta = true;
 
-	if ((!multi_sta) ||
-	    (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT)) {
-		rtlpriv->initialized = false;
+	if (!multi_sta || (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT)) {
+		binitialized = false;
 		dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
 		return;
-	} else if (!rtlpriv->initialized) {
-		rtlpriv->initialized = true;
+	} else if (!binitialized) {
+		binitialized = true;
 		dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_0;
 		dm_digtable->cur_igvalue = 0x20;
-		rtl8723ae_dm_write_dig(hw);
+		rtl8723e_dm_write_dig(hw);
 	}
 
 	if (dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) {
@@ -337,7 +339,7 @@
 			if (dm_digtable->dig_ext_port_stage ==
 			    DIG_EXT_PORT_STAGE_2) {
 				dm_digtable->cur_igvalue = 0x20;
-				rtl8723ae_dm_write_dig(hw);
+				rtl8723e_dm_write_dig(hw);
 			}
 
 			dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_1;
@@ -348,7 +350,7 @@
 	} else if (dm_digtable->dig_ext_port_stage != DIG_EXT_PORT_STAGE_0) {
 		dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_0;
 		dm_digtable->cur_igvalue = 0x20;
-		rtl8723ae_dm_write_dig(hw);
+		rtl8723e_dm_write_dig(hw);
 	}
 
 	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
@@ -357,22 +359,22 @@
 		 dm_digtable->dig_ext_port_stage);
 }
 
-static void rtl8723ae_dm_initial_gain_sta(struct ieee80211_hw *hw)
+static void rtl8723e_dm_initial_gain_sta(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
 	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
 		 "presta_cstate = %x, cursta_cstate = %x\n",
-		 dm_digtable->presta_cstate,
-		 dm_digtable->cursta_cstate);
+		  dm_digtable->presta_cstate,
+		  dm_digtable->cursta_cstate);
 
 	if (dm_digtable->presta_cstate == dm_digtable->cursta_cstate ||
 	    dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT ||
 	    dm_digtable->cursta_cstate == DIG_STA_CONNECT) {
-
 		if (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) {
-			dm_digtable->rssi_val_min = rtl_init_gain_min_pwdb(hw);
+			dm_digtable->rssi_val_min =
+			    rtl8723e_dm_initial_gain_min_pwdb(hw);
 			rtl92c_dm_ctrl_initgain_by_rssi(hw);
 		}
 	} else {
@@ -381,16 +383,17 @@
 		dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
 		dm_digtable->cur_igvalue = 0x20;
 		dm_digtable->pre_igvalue = 0;
-		rtl8723ae_dm_write_dig(hw);
+		rtl8723e_dm_write_dig(hw);
 	}
 }
-static void rtl8723ae_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
+
+static void rtl8723e_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
 	if (dm_digtable->cursta_cstate == DIG_STA_CONNECT) {
-		dm_digtable->rssi_val_min = rtl_init_gain_min_pwdb(hw);
+		dm_digtable->rssi_val_min = rtl8723e_dm_initial_gain_min_pwdb(hw);
 
 		if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) {
 			if (dm_digtable->rssi_val_min <= 25)
@@ -418,12 +421,11 @@
 				    CCK_FA_STAGE_High;
 			else
 				dm_digtable->cur_cck_fa_state =
-							 CCK_FA_STAGE_Low;
-
+				    CCK_FA_STAGE_LOW;
 			if (dm_digtable->pre_cck_fa_state !=
 			    dm_digtable->cur_cck_fa_state) {
 				if (dm_digtable->cur_cck_fa_state ==
-				    CCK_FA_STAGE_Low)
+				    CCK_FA_STAGE_LOW)
 					rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2,
 						      0x83);
 				else
@@ -449,13 +451,13 @@
 
 }
 
-static void rtl8723ae_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
+static void rtl8723e_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
 {
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
-	if (mac->act_scanning == true)
+	if (mac->act_scanning)
 		return;
 
 	if (mac->link_state >= MAC80211_LINKED)
@@ -463,28 +465,29 @@
 	else
 		dm_digtable->cursta_cstate = DIG_STA_DISCONNECT;
 
-	rtl8723ae_dm_initial_gain_sta(hw);
-	rtl8723ae_dm_initial_gain_multi_sta(hw);
-	rtl8723ae_dm_cck_packet_detection_thresh(hw);
+	rtl8723e_dm_initial_gain_sta(hw);
+	rtl8723e_dm_initial_gain_multi_sta(hw);
+	rtl8723e_dm_cck_packet_detection_thresh(hw);
 
 	dm_digtable->presta_cstate = dm_digtable->cursta_cstate;
 
 }
 
-static void rtl8723ae_dm_dig(struct ieee80211_hw *hw)
+static void rtl8723e_dm_dig(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
-	if (rtlpriv->dm.dm_initialgain_enable == false)
+	if (!rtlpriv->dm.dm_initialgain_enable)
 		return;
-	if (dm_digtable->dig_enable_flag == false)
+	if (!dm_digtable->dig_enable_flag)
 		return;
 
-	rtl8723ae_dm_ctrl_initgain_by_twoport(hw);
+	rtl8723e_dm_ctrl_initgain_by_twoport(hw);
+
 }
 
-static void rtl8723ae_dm_dynamic_txpower(struct ieee80211_hw *hw)
+static void rtl8723e_dm_dynamic_txpower(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -502,7 +505,7 @@
 	if ((mac->link_state < MAC80211_LINKED) &&
 	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
-			 "Not connected\n");
+			 "Not connected to any\n");
 
 		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
 
@@ -512,18 +515,21 @@
 
 	if (mac->link_state >= MAC80211_LINKED) {
 		if (mac->opmode == NL80211_IFTYPE_ADHOC) {
-			undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
+			undec_sm_pwdb =
+			    rtlpriv->dm.entry_min_undec_sm_pwdb;
 			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 				 "AP Client PWDB = 0x%lx\n",
-				 undec_sm_pwdb);
+				  undec_sm_pwdb);
 		} else {
-			undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
+			undec_sm_pwdb =
+			    rtlpriv->dm.undec_sm_pwdb;
 			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 				 "STA Default Port PWDB = 0x%lx\n",
-				 undec_sm_pwdb);
+				  undec_sm_pwdb);
 		}
 	} else {
-		undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
+		undec_sm_pwdb =
+		    rtlpriv->dm.entry_min_undec_sm_pwdb;
 
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 			 "AP Ext Port PWDB = 0x%lx\n",
@@ -534,37 +540,39 @@
 		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 			 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n");
-	} else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
-		   (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
+	} else if ((undec_sm_pwdb <
+		    (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
+		   (undec_sm_pwdb >=
+		    TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
 		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 			 "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n");
-	} else if (undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
+	} else if (undec_sm_pwdb <
+		   (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
 		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 			 "TXHIGHPWRLEVEL_NORMAL\n");
 	}
 
-	if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) {
+	if (rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 			 "PHY_SetTxPowerLevel8192S() Channel = %d\n",
 			  rtlphy->current_channel);
-		rtl8723ae_phy_set_txpower_level(hw, rtlphy->current_channel);
+		rtl8723e_phy_set_txpower_level(hw, rtlphy->current_channel);
 	}
 
 	rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
 }
 
-void rtl8723ae_dm_write_dig(struct ieee80211_hw *hw)
+void rtl8723e_dm_write_dig(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
 	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
-		 "cur_igvalue = 0x%x, "
-		 "pre_igvalue = 0x%x, back_val = %d\n",
-		 dm_digtable->cur_igvalue, dm_digtable->pre_igvalue,
-		 dm_digtable->back_val);
+		 "cur_igvalue = 0x%x, pre_igvalue = 0x%x, back_val = %d\n",
+		  dm_digtable->cur_igvalue, dm_digtable->pre_igvalue,
+		  dm_digtable->back_val);
 
 	if (dm_digtable->pre_igvalue != dm_digtable->cur_igvalue) {
 		rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f,
@@ -576,32 +584,39 @@
 	}
 }
 
-static void rtl8723ae_dm_check_edca_turbo(struct ieee80211_hw *hw)
+static void rtl8723e_dm_pwdb_monitor(struct ieee80211_hw *hw)
+{
+}
+
+static void rtl8723e_dm_check_edca_turbo(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 
+	static u64 last_txok_cnt;
+	static u64 last_rxok_cnt;
+	static u32 last_bt_edca_ul;
+	static u32 last_bt_edca_dl;
 	u64 cur_txok_cnt = 0;
 	u64 cur_rxok_cnt = 0;
 	u32 edca_be_ul = 0x5ea42b;
 	u32 edca_be_dl = 0x5ea42b;
 	bool bt_change_edca = false;
 
-	if ((mac->last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) ||
-	    (mac->last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) {
+	if ((last_bt_edca_ul != rtlpriv->btcoexist.bt_edca_ul) ||
+	    (last_bt_edca_dl != rtlpriv->btcoexist.bt_edca_dl)) {
 		rtlpriv->dm.current_turbo_edca = false;
-		mac->last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
-		mac->last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl;
+		last_bt_edca_ul = rtlpriv->btcoexist.bt_edca_ul;
+		last_bt_edca_dl = rtlpriv->btcoexist.bt_edca_dl;
 	}
 
-	if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) {
-		edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+	if (rtlpriv->btcoexist.bt_edca_ul != 0) {
+		edca_be_ul = rtlpriv->btcoexist.bt_edca_ul;
 		bt_change_edca = true;
 	}
 
-	if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) {
-		edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl;
+	if (rtlpriv->btcoexist.bt_edca_dl != 0) {
+		edca_be_ul = rtlpriv->btcoexist.bt_edca_dl;
 		bt_change_edca = true;
 	}
 
@@ -609,22 +624,11 @@
 		rtlpriv->dm.current_turbo_edca = false;
 		return;
 	}
-
-	if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) {
-		if (!(edca_be_ul & 0xffff0000))
-			edca_be_ul |= 0x005e0000;
-
-		if (!(edca_be_dl & 0xffff0000))
-			edca_be_dl |= 0x005e0000;
-	}
-
 	if ((bt_change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) &&
 	     (!rtlpriv->dm.disable_framebursting))) {
 
-		cur_txok_cnt = rtlpriv->stats.txbytesunicast -
-			       mac->last_txok_cnt;
-		cur_rxok_cnt = rtlpriv->stats.rxbytesunicast -
-			       mac->last_rxok_cnt;
+		cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
+		cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
 
 		if (cur_rxok_cnt > 4 * cur_txok_cnt) {
 			if (!rtlpriv->dm.is_cur_rdlstate ||
@@ -647,18 +651,20 @@
 	} else {
 		if (rtlpriv->dm.current_turbo_edca) {
 			u8 tmp = AC0_BE;
-			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
-						      &tmp);
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_AC_PARAM,
+						      (u8 *)(&tmp));
 			rtlpriv->dm.current_turbo_edca = false;
 		}
 	}
 
 	rtlpriv->dm.is_any_nonbepkts = false;
-	mac->last_txok_cnt = rtlpriv->stats.txbytesunicast;
-	mac->last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
+	last_txok_cnt = rtlpriv->stats.txbytesunicast;
+	last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
 }
 
-static void rtl8723ae_dm_initialize_txpower_tracking(struct ieee80211_hw *hw)
+static void rtl8723e_dm_initialize_txpower_tracking_thermalmeter(
+				struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
@@ -667,10 +673,20 @@
 
 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
 		 "pMgntInfo->txpower_tracking = %d\n",
-		 rtlpriv->dm.txpower_tracking);
+		  rtlpriv->dm.txpower_tracking);
 }
 
-void rtl8723ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
+static void rtl8723e_dm_initialize_txpower_tracking(struct ieee80211_hw *hw)
+{
+	rtl8723e_dm_initialize_txpower_tracking_thermalmeter(hw);
+}
+
+void rtl8723e_dm_check_txpower_tracking(struct ieee80211_hw *hw)
+{
+	return;
+}
+
+void rtl8723e_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rate_adaptive *p_ra = &(rtlpriv->ra);
@@ -682,101 +698,32 @@
 		rtlpriv->dm.useramask = true;
 	else
 		rtlpriv->dm.useramask = false;
+
 }
 
-static void rtl8723ae_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	struct rate_adaptive *p_ra = &(rtlpriv->ra);
-	u32 low_rssithresh_for_ra, high_rssithresh_for_ra;
-	struct ieee80211_sta *sta = NULL;
-
-	if (is_hal_stop(rtlhal)) {
-		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
-			 " driver is going to unload\n");
-		return;
-	}
-
-	if (!rtlpriv->dm.useramask) {
-		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
-			 " driver does not control rate adaptive mask\n");
-		return;
-	}
-
-	if (mac->link_state == MAC80211_LINKED &&
-	    mac->opmode == NL80211_IFTYPE_STATION) {
-		switch (p_ra->pre_ratr_state) {
-		case DM_RATR_STA_HIGH:
-			high_rssithresh_for_ra = 50;
-			low_rssithresh_for_ra = 20;
-			break;
-		case DM_RATR_STA_MIDDLE:
-			high_rssithresh_for_ra = 55;
-			low_rssithresh_for_ra = 20;
-			break;
-		case DM_RATR_STA_LOW:
-			high_rssithresh_for_ra = 50;
-			low_rssithresh_for_ra = 25;
-			break;
-		default:
-			high_rssithresh_for_ra = 50;
-			low_rssithresh_for_ra = 20;
-			break;
-		}
-
-		if (rtlpriv->dm.undec_sm_pwdb > high_rssithresh_for_ra)
-			p_ra->ratr_state = DM_RATR_STA_HIGH;
-		else if (rtlpriv->dm.undec_sm_pwdb > low_rssithresh_for_ra)
-			p_ra->ratr_state = DM_RATR_STA_MIDDLE;
-		else
-			p_ra->ratr_state = DM_RATR_STA_LOW;
-
-		if (p_ra->pre_ratr_state != p_ra->ratr_state) {
-			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
-				 "RSSI = %ld\n",
-				 rtlpriv->dm.undec_sm_pwdb);
-			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
-				 "RSSI_LEVEL = %d\n", p_ra->ratr_state);
-			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
-				 "PreState = %d, CurState = %d\n",
-				 p_ra->pre_ratr_state, p_ra->ratr_state);
-
-			rcu_read_lock();
-			sta = rtl_find_sta(hw, mac->bssid);
-			if (sta)
-				rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
-							   p_ra->ratr_state);
-			rcu_read_unlock();
-
-			p_ra->pre_ratr_state = p_ra->ratr_state;
-		}
-	}
-}
-
-void rtl8723ae_dm_rf_saving(struct ieee80211_hw *hw, u8 force_in_normal)
+void rtl8723e_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct ps_t *dm_pstable = &rtlpriv->dm_pstable;
+	static u8 initialize;
+	static u32 reg_874, reg_c70, reg_85c, reg_a74;
 
-	if (!rtlpriv->reg_init) {
-		rtlpriv->reg_874 = (rtl_get_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
-				    MASKDWORD) & 0x1CC000) >> 14;
+	if (initialize == 0) {
+		reg_874 = (rtl_get_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
+					 MASKDWORD) & 0x1CC000) >> 14;
 
-		rtlpriv->reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1,
-				    MASKDWORD) & BIT(3)) >> 3;
+		reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1,
+					 MASKDWORD) & BIT(3)) >> 3;
 
-		rtlpriv->reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL,
-				    MASKDWORD) & 0xFF000000) >> 24;
+		reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL,
+					 MASKDWORD) & 0xFF000000) >> 24;
 
-		rtlpriv->reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) &
-				   0xF000) >> 12;
+		reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) & 0xF000) >> 12;
 
-		rtlpriv->reg_init = true;
+		initialize = 1;
 	}
 
-	if (!force_in_normal) {
+	if (!bforce_in_normal) {
 		if (dm_pstable->rssi_val_min != 0) {
 			if (dm_pstable->pre_rfstate == RF_NORMAL) {
 				if (dm_pstable->rssi_val_min >= 30)
@@ -798,7 +745,6 @@
 
 	if (dm_pstable->pre_rfstate != dm_pstable->cur_rfstate) {
 		if (dm_pstable->cur_rfstate == RF_SAVE) {
-
 			rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
 				      BIT(5), 0x1);
 			rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
@@ -813,12 +759,12 @@
 			rtl_set_bbreg(hw, 0x818, BIT(28), 0x1);
 		} else {
 			rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
-				      0x1CC000, rtlpriv->reg_874);
+				      0x1CC000, reg_874);
 			rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3),
-				      rtlpriv->reg_c70);
+				      reg_c70);
 			rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, 0xFF000000,
-				      rtlpriv->reg_85c);
-			rtl_set_bbreg(hw, 0xa74, 0xF000, rtlpriv->reg_a74);
+				      reg_85c);
+			rtl_set_bbreg(hw, 0xa74, 0xF000, reg_a74);
 			rtl_set_bbreg(hw, 0x818, BIT(28), 0x0);
 			rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
 				      BIT(5), 0x0);
@@ -828,7 +774,7 @@
 	}
 }
 
-static void rtl8723ae_dm_dynamic_bpowersaving(struct ieee80211_hw *hw)
+static void rtl8723e_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -847,48 +793,49 @@
 			    rtlpriv->dm.entry_min_undec_sm_pwdb;
 			RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
 				 "AP Client PWDB = 0x%lx\n",
-				 dm_pstable->rssi_val_min);
+				  dm_pstable->rssi_val_min);
 		} else {
-			dm_pstable->rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
+			dm_pstable->rssi_val_min =
+			    rtlpriv->dm.undec_sm_pwdb;
 			RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
 				 "STA Default Port PWDB = 0x%lx\n",
-				 dm_pstable->rssi_val_min);
+				  dm_pstable->rssi_val_min);
 		}
 	} else {
-		dm_pstable->rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb;
+		dm_pstable->rssi_val_min =
+		    rtlpriv->dm.entry_min_undec_sm_pwdb;
 
 		RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
 			 "AP Ext Port PWDB = 0x%lx\n",
-			 dm_pstable->rssi_val_min);
+			  dm_pstable->rssi_val_min);
 	}
 
-	rtl8723ae_dm_rf_saving(hw, false);
+	rtl8723e_dm_rf_saving(hw, false);
 }
 
-void rtl8723ae_dm_init(struct ieee80211_hw *hw)
+void rtl8723e_dm_init(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
-	rtl8723ae_dm_diginit(hw);
+	rtl8723e_dm_diginit(hw);
 	rtl8723_dm_init_dynamic_txpower(hw);
 	rtl8723_dm_init_edca_turbo(hw);
-	rtl8723ae_dm_init_rate_adaptive_mask(hw);
-	rtl8723ae_dm_initialize_txpower_tracking(hw);
+	rtl8723e_dm_init_rate_adaptive_mask(hw);
+	rtl8723e_dm_initialize_txpower_tracking(hw);
 	rtl8723_dm_init_dynamic_bb_powersaving(hw);
 }
 
-void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw)
+void rtl8723e_dm_watchdog(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	bool fw_current_inpsmode = false;
 	bool fw_ps_awake = true;
 	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
-				      (u8 *) (&fw_current_inpsmode));
+				      (u8 *)(&fw_current_inpsmode));
 	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
-				      (u8 *) (&fw_ps_awake));
+				      (u8 *)(&fw_ps_awake));
 
 	if (ppsc->p2p_ps_info.p2p_ps_mode)
 		fw_ps_awake = false;
@@ -896,58 +843,57 @@
 	if ((ppsc->rfpwr_state == ERFON) &&
 	    ((!fw_current_inpsmode) && fw_ps_awake) &&
 	    (!ppsc->rfchange_inprogress)) {
-		rtl8723ae_dm_dig(hw);
-		rtl8723ae_dm_false_alarm_counter_statistics(hw);
-		rtl8723ae_dm_dynamic_bpowersaving(hw);
-		rtl8723ae_dm_dynamic_txpower(hw);
-		rtl8723ae_dm_refresh_rate_adaptive_mask(hw);
-		rtl8723ae_dm_bt_coexist(hw);
-		rtl8723ae_dm_check_edca_turbo(hw);
+		rtl8723e_dm_pwdb_monitor(hw);
+		rtl8723e_dm_dig(hw);
+		rtl8723e_dm_false_alarm_counter_statistics(hw);
+		rtl8723e_dm_dynamic_bb_powersaving(hw);
+		rtl8723e_dm_dynamic_txpower(hw);
+		rtl8723e_dm_check_txpower_tracking(hw);
+		/* rtl92c_dm_refresh_rate_adaptive_mask(hw); */
+		rtl8723e_dm_bt_coexist(hw);
+		rtl8723e_dm_check_edca_turbo(hw);
 	}
-	if (rtlpcipriv->bt_coexist.init_set)
+	if (rtlpriv->btcoexist.init_set)
 		rtl_write_byte(rtlpriv, 0x76e, 0xc);
 }
 
-static void rtl8723ae_dm_init_bt_coexist(struct ieee80211_hw *hw)
+static void rtl8723e_dm_init_bt_coexist(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 
-	rtlpcipriv->bt_coexist.bt_rfreg_origin_1e
+	rtlpriv->btcoexist.bt_rfreg_origin_1e
 		= rtl_get_rfreg(hw, (enum radio_path)0, RF_RCK1, 0xfffff);
-	rtlpcipriv->bt_coexist.bt_rfreg_origin_1f
+	rtlpriv->btcoexist.bt_rfreg_origin_1f
 		= rtl_get_rfreg(hw, (enum radio_path)0, RF_RCK2, 0xf0);
 
-	rtlpcipriv->bt_coexist.cstate = 0;
-	rtlpcipriv->bt_coexist.previous_state = 0;
-	rtlpcipriv->bt_coexist.cstate_h = 0;
-	rtlpcipriv->bt_coexist.previous_state_h = 0;
-	rtlpcipriv->bt_coexist.lps_counter = 0;
+	rtlpriv->btcoexist.cstate = 0;
+	rtlpriv->btcoexist.previous_state = 0;
+	rtlpriv->btcoexist.cstate_h = 0;
+	rtlpriv->btcoexist.previous_state_h = 0;
+	rtlpriv->btcoexist.lps_counter = 0;
 
 	/*  Enable counter statistics */
 	rtl_write_byte(rtlpriv, 0x76e, 0x4);
 	rtl_write_byte(rtlpriv, 0x778, 0x3);
 	rtl_write_byte(rtlpriv, 0x40, 0x20);
 
-	rtlpcipriv->bt_coexist.init_set = true;
+	rtlpriv->btcoexist.init_set = true;
 }
 
-void rtl8723ae_dm_bt_coexist(struct ieee80211_hw *hw)
+void rtl8723e_dm_bt_coexist(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	u8 tmp_byte = 0;
-	if (!rtlpcipriv->bt_coexist.bt_coexistence) {
+	if (!rtlpriv->btcoexist.bt_coexistence) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
 			 "[DM]{BT], BT not exist!!\n");
 		return;
 	}
 
-	if (!rtlpcipriv->bt_coexist.init_set) {
+	if (!rtlpriv->btcoexist.init_set) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
-			 "[DM][BT], rtl8723ae_dm_bt_coexist()\n");
-
-		rtl8723ae_dm_init_bt_coexist(hw);
+			 "[DM][BT], rtl8723e_dm_bt_coexist()\n");
+		rtl8723e_dm_init_bt_coexist(hw);
 	}
 
 	tmp_byte = rtl_read_byte(rtlpriv, 0x40);
@@ -955,5 +901,5 @@
 		 "[DM][BT], 0x40 is 0x%x", tmp_byte);
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 		 "[DM][BT], bt_dm_coexist start");
-	rtl8723ae_dm_bt_coexist_8723(hw);
+	rtl8723e_dm_bt_coexist_8723(hw);
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
index d253bb5..6fa0feb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
@@ -25,17 +25,23 @@
  *
  * Larry Finger <Larry.Finger@lwfinger.net>
  *
- ****************************************************************************
- */
+ *****************************************************************************/
 
 #ifndef	__RTL8723E_DM_H__
 #define __RTL8723E_DM_H__
 
+#define HAL_DM_DIG_DISABLE			BIT(0)
 #define HAL_DM_HIPWR_DISABLE			BIT(1)
 
+#define OFDM_TABLE_LENGTH			37
+#define CCK_TABLE_LENGTH			33
+
 #define OFDM_TABLE_SIZE				37
 #define CCK_TABLE_SIZE				33
 
+#define BW_AUTO_SWITCH_HIGH_LOW			25
+#define BW_AUTO_SWITCH_LOW_HIGH			30
+
 #define DM_DIG_THRESH_HIGH			40
 #define DM_DIG_THRESH_LOW			35
 
@@ -63,12 +69,18 @@
 #define DM_RATR_STA_MIDDLE			2
 #define DM_RATR_STA_LOW				3
 
+#define CTS2SELF_THVAL				30
+#define REGC38_TH				20
+
+#define WAIOTTHVAL				25
+
 #define TXHIGHPWRLEVEL_NORMAL			0
 #define TXHIGHPWRLEVEL_LEVEL1			1
 #define TXHIGHPWRLEVEL_LEVEL2			2
 #define TXHIGHPWRLEVEL_BT1			3
 #define TXHIGHPWRLEVEL_BT2			4
 
+#define DM_TYPE_BYFW				0
 #define DM_TYPE_BYDRIVER			1
 
 #define TX_POWER_NEAR_FIELD_THRESH_LVL2		74
@@ -82,6 +94,7 @@
 	long trying_threshold;
 	u8 cur_antenna;
 	u8 pre_antenna;
+
 };
 
 enum tag_dynamic_init_gain_operation_type_definition {
@@ -98,7 +111,7 @@
 enum tag_cck_packet_detection_threshold_type_definition {
 	CCK_PD_STAGE_LowRssi = 0,
 	CCK_PD_STAGE_HighRssi = 1,
-	CCK_FA_STAGE_Low = 2,
+	CCK_FA_STAGE_LOW = 2,
 	CCK_FA_STAGE_High = 3,
 	CCK_PD_STAGE_MAX = 4,
 };
@@ -138,17 +151,24 @@
 	DIG_CONNECT_MAX
 };
 
+#define BT_RSSI_STATE_NORMAL_POWER      BIT_OFFSET_LEN_MASK_32(0, 1)
+#define BT_RSSI_STATE_AMDPU_OFF         BIT_OFFSET_LEN_MASK_32(1, 1)
+#define BT_RSSI_STATE_SPECIAL_LOW       BIT_OFFSET_LEN_MASK_32(2, 1)
+#define BT_RSSI_STATE_BG_EDCA_LOW       BIT_OFFSET_LEN_MASK_32(3, 1)
+#define BT_RSSI_STATE_TXPOWER_LOW       BIT_OFFSET_LEN_MASK_32(4, 1)
 #define GET_UNDECORATED_AVERAGE_RSSI(_priv)     \
-	((((struct rtl_priv *)(_priv))->mac80211.opmode ==	\
-	NL80211_IFTYPE_ADHOC) ?  \
-	(((struct rtl_priv *)(_priv))->dm.entry_min_undec_sm_pwdb) \
-	: (((struct rtl_priv *)(_priv))->dm.undec_sm_pwdb))
+	( \
+	(((struct rtl_priv *)(_priv))->mac80211.opmode ==		\
+			     NL80211_IFTYPE_ADHOC) ?			\
+	(((struct rtl_priv *)(_priv))->dm.entry_min_undec_sm_pwdb) :	\
+	(((struct rtl_priv *)(_priv))->dm.undec_sm_pwdb)		\
+	)
 
-void rtl8723ae_dm_init(struct ieee80211_hw *hw);
-void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw);
-void rtl8723ae_dm_write_dig(struct ieee80211_hw *hw);
-void rtl8723ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
-void rtl8723ae_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal);
-void rtl8723ae_dm_bt_coexist(struct ieee80211_hw *hw);
-
+void rtl8723e_dm_init(struct ieee80211_hw *hw);
+void rtl8723e_dm_watchdog(struct ieee80211_hw *hw);
+void rtl8723e_dm_write_dig(struct ieee80211_hw *hw);
+void rtl8723e_dm_check_txpower_tracking(struct ieee80211_hw *hw);
+void rtl8723e_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
+void rtl8723e_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal);
+void rtl8723e_dm_bt_coexist(struct ieee80211_hw *hw);
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
index 728b756..b7c0d38 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -25,18 +21,19 @@
  *
  * Larry Finger <Larry.Finger@lwfinger.net>
  *
- ****************************************************************************
- */
+ *****************************************************************************/
 
 #include "../wifi.h"
 #include "../pci.h"
 #include "../base.h"
+#include "../core.h"
 #include "reg.h"
 #include "def.h"
 #include "fw.h"
 #include "../rtl8723com/fw_common.h"
 
-static bool rtl8723ae_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
+static bool _rtl8723e_check_fw_read_last_h2c(struct ieee80211_hw *hw,
+					     u8 boxnum)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 val_hmetfr, val_mcutst_1;
@@ -50,17 +47,17 @@
 	return result;
 }
 
-static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw,
-					u8 element_id, u32 cmd_len,
-					u8 *p_cmdbuffer)
+static void _rtl8723e_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id,
+				       u32 cmd_len, u8 *cmdbuffer)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u8 boxnum;
 	u16 box_reg = 0, box_extreg = 0;
-	u8 u1tmp;
-	bool isfw_rd = false;
-	bool bwrite_success = false;
+	u8 u1b_tmp;
+	bool isfw_read = false;
+	u8 buf_index = 0;
+	bool bwrite_sucess = false;
 	u8 wait_h2c_limmit = 100;
 	u8 wait_writeh2c_limmit = 100;
 	u8 boxcontent[4], boxextcontent[2];
@@ -83,7 +80,7 @@
 				h2c_waitcounter++;
 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 					 "Wait 100 us (%d times)...\n",
-					 h2c_waitcounter);
+					  h2c_waitcounter);
 				udelay(100);
 
 				if (h2c_waitcounter > 1000)
@@ -99,12 +96,11 @@
 		}
 	}
 
-	while (!bwrite_success) {
+	while (!bwrite_sucess) {
 		wait_writeh2c_limmit--;
 		if (wait_writeh2c_limmit == 0) {
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Write H2C fail because no trigger "
-				 "for FW INT!\n");
+				 "Write H2C fail because no trigger for FW INT!\n");
 			break;
 		}
 
@@ -128,34 +124,35 @@
 			break;
 		default:
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
+				 "switch case not process\n");
 			break;
 		}
 
-		isfw_rd = rtl8723ae_check_fw_read_last_h2c(hw, boxnum);
-		while (!isfw_rd) {
+		isfw_read = _rtl8723e_check_fw_read_last_h2c(hw, boxnum);
+		while (!isfw_read) {
 
 			wait_h2c_limmit--;
 			if (wait_h2c_limmit == 0) {
 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
-					 "Waiting too long for FW read clear HMEBox(%d)!\n",
+					 "Wating too long for FW read clear HMEBox(%d)!\n",
 					 boxnum);
 				break;
 			}
 
 			udelay(10);
 
-			isfw_rd = rtl8723ae_check_fw_read_last_h2c(hw, boxnum);
-			u1tmp = rtl_read_byte(rtlpriv, 0x1BF);
+			isfw_read = _rtl8723e_check_fw_read_last_h2c(hw,
+								boxnum);
+			u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
-				 "Waiting for FW read clear HMEBox(%d)!!! "
-				 "0x1BF = %2x\n", boxnum, u1tmp);
+				 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
+				 boxnum, u1b_tmp);
 		}
 
-		if (!isfw_rd) {
+		if (!isfw_read) {
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
-				 "Write H2C register BOX[%d] fail!!!!! "
-				 "Fw do not read.\n", boxnum);
+				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
+				 boxnum);
 			break;
 		}
 
@@ -169,8 +166,8 @@
 		switch (cmd_len) {
 		case 1:
 			boxcontent[0] &= ~(BIT(7));
-			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer, 1);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index, 1);
 
 			for (idx = 0; idx < 4; idx++) {
 				rtl_write_byte(rtlpriv, box_reg + idx,
@@ -179,8 +176,8 @@
 			break;
 		case 2:
 			boxcontent[0] &= ~(BIT(7));
-			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer, 2);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index, 2);
 
 			for (idx = 0; idx < 4; idx++) {
 				rtl_write_byte(rtlpriv, box_reg + idx,
@@ -189,8 +186,8 @@
 			break;
 		case 3:
 			boxcontent[0] &= ~(BIT(7));
-			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer, 3);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index, 3);
 
 			for (idx = 0; idx < 4; idx++) {
 				rtl_write_byte(rtlpriv, box_reg + idx,
@@ -199,10 +196,10 @@
 			break;
 		case 4:
 			boxcontent[0] |= (BIT(7));
-			memcpy((u8 *) (boxextcontent),
-			       p_cmdbuffer, 2);
-			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer + 2, 2);
+			memcpy((u8 *)(boxextcontent),
+			       cmdbuffer + buf_index, 2);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index + 2, 2);
 
 			for (idx = 0; idx < 2; idx++) {
 				rtl_write_byte(rtlpriv, box_extreg + idx,
@@ -216,10 +213,10 @@
 			break;
 		case 5:
 			boxcontent[0] |= (BIT(7));
-			memcpy((u8 *) (boxextcontent),
-			       p_cmdbuffer, 2);
-			memcpy((u8 *) (boxcontent) + 1,
-			       p_cmdbuffer + 2, 3);
+			memcpy((u8 *)(boxextcontent),
+			       cmdbuffer + buf_index, 2);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index + 2, 3);
 
 			for (idx = 0; idx < 2; idx++) {
 				rtl_write_byte(rtlpriv, box_extreg + idx,
@@ -237,7 +234,7 @@
 			break;
 		}
 
-		bwrite_success = true;
+		bwrite_sucess = true;
 
 		rtlhal->last_hmeboxnum = boxnum + 1;
 		if (rtlhal->last_hmeboxnum == 4)
@@ -245,7 +242,7 @@
 
 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 			 "pHalData->last_hmeboxnum  = %d\n",
-			 rtlhal->last_hmeboxnum);
+			  rtlhal->last_hmeboxnum);
 	}
 
 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
@@ -255,53 +252,50 @@
 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
 }
 
-void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw,
-			    u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
+void rtl8723e_fill_h2c_cmd(struct ieee80211_hw *hw,
+			   u8 element_id, u32 cmd_len, u8 *cmdbuffer)
 {
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u32 tmp_cmdbuf[2];
 
-	if (rtlhal->fw_ready == false) {
+	if (!rtlhal->fw_ready) {
 		RT_ASSERT(false,
-			 "return H2C cmd because of Fw download fail!!!\n");
+			  "return H2C cmd because of Fw download fail!!!\n");
 		return;
 	}
-
-	_rtl8723ae_fill_h2c_command(hw, element_id, cmd_len, p_cmdbuffer);
-	return;
+	memset(tmp_cmdbuf, 0, 8);
+	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
+	_rtl8723e_fill_h2c_command(hw, element_id, cmd_len,
+				   (u8 *)&tmp_cmdbuf);
 }
 
-static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw,
-				       struct sk_buff *skb)
+void rtl8723e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-	struct rtl8192_tx_ring *ring;
-	struct rtl_tx_desc *pdesc;
-	unsigned long flags;
-	struct sk_buff *pskb = NULL;
+	u8 u1_h2c_set_pwrmode[3] = { 0 };
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 
-	ring = &rtlpci->tx_ring[BEACON_QUEUE];
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
 
-	pskb = __skb_dequeue(&ring->queue);
-	if (pskb)
-		kfree_skb(pskb);
+	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
+	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
+		(rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
+	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
+					      ppsc->reg_max_lps_awakeintvl);
 
-	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
-
-	pdesc = &ring->desc[0];
-
-	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
-
-	__skb_queue_tail(&ring->queue, skb);
-
-	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-
-	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
-
-	return true;
+	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+		      "rtl8723e_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
+		      u1_h2c_set_pwrmode, 3);
+	rtl8723e_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
 }
 
+#define BEACON_PG		0 /* ->1 */
+#define PSPOLL_PG		2
+#define NULL_PG			3
+#define PROBERSP_PG		4 /* ->5 */
+
+#define TOTAL_RESERVED_PKT_LEN	768
+
 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
 	/* page 0 beacon */
 	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
@@ -412,111 +406,111 @@
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
+void rtl8723e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct sk_buff *skb = NULL;
-
 	u32 totalpacketlen;
 	bool rtstatus;
-	u8 u1RsvdPageLoc[3] = { 0 };
-	bool dlok = false;
-
+	u8 u1rsvdpageloc[3] = { 0 };
+	bool b_dlok = false;
 	u8 *beacon;
 	u8 *p_pspoll;
 	u8 *nullfunc;
 	u8 *p_probersp;
+
 	/*---------------------------------------------------------
-				(1) beacon
-	---------------------------------------------------------
-	*/
+	 *			(1) beacon
+	 *---------------------------------------------------------
+	 */
 	beacon = &reserved_page_packet[BEACON_PG * 128];
 	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
 	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
 
 	/*-------------------------------------------------------
-				(2) ps-poll
-	--------------------------------------------------------
-	*/
+	 *			(2) ps-poll
+	 *--------------------------------------------------------
+	 */
 	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
 	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
 	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
 	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
 
-	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
+	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
 
 	/*--------------------------------------------------------
-				(3) null data
-	---------------------------------------------------------i
-	*/
+	 *			(3) null data
+	 *---------------------------------------------------------
+	 */
 	nullfunc = &reserved_page_packet[NULL_PG * 128];
 	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
 
-	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
+	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
 
 	/*---------------------------------------------------------
-				(4) probe response
-	----------------------------------------------------------
-	*/
+	 *			(4) probe response
+	 *----------------------------------------------------------
+	 */
 	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
 	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
 	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
 	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
 
-	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
+	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
 
 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
 
 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
-		      "rtl8723ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+		      "rtl8723e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
 		      &reserved_page_packet[0], totalpacketlen);
 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
-		      "rtl8723ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
-		      u1RsvdPageLoc, 3);
+		      "rtl8723e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+		      u1rsvdpageloc, 3);
 
 	skb = dev_alloc_skb(totalpacketlen);
-	memcpy((u8 *) skb_put(skb, totalpacketlen),
+	memcpy((u8 *)skb_put(skb, totalpacketlen),
 	       &reserved_page_packet, totalpacketlen);
 
-	rtstatus = _rtl8723ae_cmd_send_packet(hw, skb);
+	rtstatus = rtl_cmd_send_packet(hw, skb);
 
 	if (rtstatus)
-		dlok = true;
+		b_dlok = true;
 
-	if (dlok) {
+	if (b_dlok) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 			 "Set RSVD page location to Fw.\n");
 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
-				"H2C_RSVDPAGE:\n",
-				u1RsvdPageLoc, 3);
-		rtl8723ae_fill_h2c_cmd(hw, H2C_RSVDPAGE,
-				       sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
+			      "H2C_RSVDPAGE:\n",
+			      u1rsvdpageloc, 3);
+		rtl8723e_fill_h2c_cmd(hw, H2C_RSVDPAGE,
+				      sizeof(u1rsvdpageloc), u1rsvdpageloc);
 	} else
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
 }
 
-void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
+void rtl8723e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
 {
 	u8 u1_joinbssrpt_parm[1] = { 0 };
 
 	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
 
-	rtl8723ae_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
+	rtl8723e_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
 }
 
 static void rtl8723e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw,
 					    u8 ctwindow)
 {
-	u8 u1_ctwindow_period[1] = {ctwindow};
+	u8 u1_ctwindow_period[1] = { ctwindow};
 
-	rtl8723ae_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
+	rtl8723e_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
+
 }
 
-void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+void rtl8723e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
@@ -530,7 +524,7 @@
 	switch (p2p_ps_state) {
 	case P2P_PS_DISABLE:
 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
-		memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
+		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
 		break;
 	case P2P_PS_ENABLE:
 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
@@ -542,7 +536,7 @@
 		}
 
 		/* hw only support 2 set of NoA */
-		for (i = 0; i < p2pinfo->noa_num; i++) {
+		for (i = 0 ; i < p2pinfo->noa_num ; i++) {
 			/* To control the register setting for which NOA*/
 			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
 			if (i == 0)
@@ -561,27 +555,33 @@
 
 			start_time = p2pinfo->noa_start_time[i];
 			if (p2pinfo->noa_count_type[i] != 1) {
-				while (start_time <= (tsf_low+(50*1024))) {
-					start_time += p2pinfo->noa_interval[i];
+				while (start_time <=
+					(tsf_low+(50*1024))) {
+					start_time +=
+						p2pinfo->noa_interval[i];
 					if (p2pinfo->noa_count_type[i] != 255)
 						p2pinfo->noa_count_type[i]--;
 				}
 			}
 			rtl_write_dword(rtlpriv, 0x5E8, start_time);
 			rtl_write_dword(rtlpriv, 0x5EC,
-					p2pinfo->noa_count_type[i]);
+				p2pinfo->noa_count_type[i]);
+
 		}
+
 		if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
 			/* rst p2p circuit */
 			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
 
 			p2p_ps_offload->offload_en = 1;
+
 			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
 				p2p_ps_offload->role = 1;
 				p2p_ps_offload->allstasleep = 0;
 			} else {
 				p2p_ps_offload->role = 0;
 			}
+
 			p2p_ps_offload->discovery = 0;
 		}
 		break;
@@ -597,26 +597,7 @@
 	default:
 		break;
 	}
-	rtl8723ae_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
-}
 
-void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u8 u1_h2c_set_pwrmode[3] = { 0 };
-	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	rtl8723e_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
 
-	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
-
-	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
-	SET_H2CCMD_PWRMODE_PARM_SMART_PS_23A(u1_h2c_set_pwrmode,
-					     (rtlpriv->mac80211.p2p) ?
-					     ppsc->smart_ps : 1);
-	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
-					      ppsc->reg_max_lps_awakeintvl);
-
-	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
-		      "rtl8723ae_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
-		      u1_h2c_set_pwrmode, 3);
-	rtl8723ae_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
index d355b85..9d1fe25 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
@@ -24,50 +24,27 @@
  * Hsinchu 300, Taiwan.
  * Larry Finger <Larry.Finger@lwfinger.net>
  *
- ****************************************************************************
- */
+ *****************************************************************************/
 
 #ifndef __RTL92C__FW__H__
 #define __RTL92C__FW__H__
 
+#define FW_8192C_SIZE					0x3000
 #define FW_8192C_START_ADDRESS			0x1000
 #define FW_8192C_END_ADDRESS			0x3FFF
-#define FW_8192C_PAGE_SIZE			4096
+#define FW_8192C_PAGE_SIZE				4096
 #define FW_8192C_POLLING_DELAY			5
-#define FW_8192C_POLLING_TIMEOUT_COUNT		6000
 
-#define BEACON_PG				0
-#define PSPOLL_PG				2
-#define NULL_PG					3
-#define PROBERSP_PG				4 /* ->5 */
+#define IS_FW_HEADER_EXIST(_pfwhdr)	\
+	((_pfwhdr->signature&0xFFFF) == 0x2300 ||\
+	(_pfwhdr->signature&0xFFFF) == 0x2301 ||\
+	(_pfwhdr->signature&0xFFFF) == 0x2302)
 
-#define TOTAL_RESERVED_PKT_LEN			768
-
-#define IS_FW_HEADER_EXIST(_pfwhdr)		\
-	((_pfwhdr->signature&0xFF00) == 0x2300)
-
-struct rtl8723ae_firmware_header {
-	u16 signature;
-	u8 category;
-	u8 function;
-	u16 version;
-	u8 subversion;
-	u8 rsvd1;
-	u8 month;
-	u8 date;
-	u8 hour;
-	u8 minute;
-	u16 ramcodeSize;
-	u16 rsvd2;
-	u32 svnindex;
-	u32 rsvd3;
-	u32 rsvd4;
-	u32 rsvd5;
-};
+#define pagenum_128(_len)	(u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0))
 
 #define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val)			\
 	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
-#define SET_H2CCMD_PWRMODE_PARM_SMART_PS_23A(__ph2ccmd, __val)		\
+#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val)		\
 	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
 #define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__ph2ccmd, __val)	\
 	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
@@ -80,11 +57,10 @@
 #define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val)		\
 	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
 
-void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
-			    u32 cmd_len, u8 *p_cmdbuffer);
-void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
-void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
-void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
-void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
-
+void rtl8723e_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
+			   u32 cmd_len, u8 *p_cmdbuffer);
+void rtl8723e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
+void rtl8723e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
+void rtl8723e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
+void rtl8723e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c
index 5b4a714..5aac45d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -31,96 +27,102 @@
 #include "../pci.h"
 #include "dm.h"
 #include "fw.h"
-#include "../rtl8723com/fw_common.h"
 #include "phy.h"
 #include "reg.h"
 #include "hal_btc.h"
 
-void rtl8723ae_dm_bt_reject_ap_aggregated_packet(struct ieee80211_hw *hw,
-						 bool reject)
+static bool bt_operation_on;
+
+void rtl8723e_dm_bt_reject_ap_aggregated_packet(struct ieee80211_hw *hw,
+						bool b_reject)
 {
 }
 
 void _rtl8723_dm_bt_check_wifi_state(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 
 	if (rtlpriv->link_info.busytraffic) {
-		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_IDLE;
+		rtlpriv->btcoexist.cstate &=
+			~BT_COEX_STATE_WIFI_IDLE;
 
 		if (rtlpriv->link_info.tx_busy_traffic)
-			rtlpcipriv->bt_coexist.cstate |=
-					BT_COEX_STATE_WIFI_UPLINK;
+			rtlpriv->btcoexist.cstate |=
+				BT_COEX_STATE_WIFI_UPLINK;
 		else
-			rtlpcipriv->bt_coexist.cstate &=
-					~BT_COEX_STATE_WIFI_UPLINK;
+			rtlpriv->btcoexist.cstate &=
+				~BT_COEX_STATE_WIFI_UPLINK;
 
 		if (rtlpriv->link_info.rx_busy_traffic)
-			rtlpcipriv->bt_coexist.cstate |=
-					BT_COEX_STATE_WIFI_DOWNLINK;
+			rtlpriv->btcoexist.cstate |=
+				BT_COEX_STATE_WIFI_DOWNLINK;
 		else
-			rtlpcipriv->bt_coexist.cstate &=
-					~BT_COEX_STATE_WIFI_DOWNLINK;
+			rtlpriv->btcoexist.cstate &=
+				~BT_COEX_STATE_WIFI_DOWNLINK;
 	} else {
-		rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_WIFI_IDLE;
-		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_UPLINK;
-		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_DOWNLINK;
+		rtlpriv->btcoexist.cstate |= BT_COEX_STATE_WIFI_IDLE;
+		rtlpriv->btcoexist.cstate &=
+			~BT_COEX_STATE_WIFI_UPLINK;
+		rtlpriv->btcoexist.cstate &=
+			~BT_COEX_STATE_WIFI_DOWNLINK;
 	}
 
 	if (rtlpriv->mac80211.mode == WIRELESS_MODE_G ||
 	    rtlpriv->mac80211.mode == WIRELESS_MODE_B) {
-		rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_WIFI_LEGACY;
-		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_HT20;
-		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_HT40;
+		rtlpriv->btcoexist.cstate |=
+			BT_COEX_STATE_WIFI_LEGACY;
+		rtlpriv->btcoexist.cstate &=
+			~BT_COEX_STATE_WIFI_HT20;
+		rtlpriv->btcoexist.cstate &=
+			~BT_COEX_STATE_WIFI_HT40;
 	} else {
-		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_LEGACY;
+		rtlpriv->btcoexist.cstate &=
+			~BT_COEX_STATE_WIFI_LEGACY;
 		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
-			rtlpcipriv->bt_coexist.cstate |=
-					BT_COEX_STATE_WIFI_HT40;
-			rtlpcipriv->bt_coexist.cstate &=
-					~BT_COEX_STATE_WIFI_HT20;
+			rtlpriv->btcoexist.cstate |=
+				BT_COEX_STATE_WIFI_HT40;
+			rtlpriv->btcoexist.cstate &=
+				~BT_COEX_STATE_WIFI_HT20;
 		} else {
-			rtlpcipriv->bt_coexist.cstate |=
-					BT_COEX_STATE_WIFI_HT20;
-			rtlpcipriv->bt_coexist.cstate &=
-					~BT_COEX_STATE_WIFI_HT40;
+			rtlpriv->btcoexist.cstate |=
+				BT_COEX_STATE_WIFI_HT20;
+			rtlpriv->btcoexist.cstate &=
+				~BT_COEX_STATE_WIFI_HT40;
 		}
 	}
 
-	if (rtlpriv->bt_operation_on)
-		rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_BT30;
+	if (bt_operation_on)
+		rtlpriv->btcoexist.cstate |= BT_COEX_STATE_BT30;
 	else
-		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_BT30;
+		rtlpriv->btcoexist.cstate &= ~BT_COEX_STATE_BT30;
 }
 
-u8 rtl8723ae_dm_bt_check_coex_rssi_state1(struct ieee80211_hw *hw,
-					  u8 level_num, u8 rssi_thresh,
-					  u8 rssi_thresh1)
+u8 rtl8723e_dm_bt_check_coex_rssi_state1(struct ieee80211_hw *hw,
+					 u8 level_num, u8 rssi_thresh,
+					 u8 rssi_thresh1)
 
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	long smooth;
+	long undecoratedsmoothed_pwdb;
 	u8 bt_rssi_state = 0;
 
-	smooth =  rtl8723ae_dm_bt_get_rx_ss(hw);
+	undecoratedsmoothed_pwdb = rtl8723e_dm_bt_get_rx_ss(hw);
 
 	if (level_num == 2) {
-		rtlpcipriv->bt_coexist.cstate &=
-				~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+		rtlpriv->btcoexist.cstate &=
+			~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
 
-		if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
-		    BT_RSSI_STATE_LOW) ||
-		    (rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
-		    BT_RSSI_STATE_STAY_LOW)) {
-			if (smooth >= (rssi_thresh +
-			    BT_FW_COEX_THRESH_TOL)) {
+		if ((rtlpriv->btcoexist.bt_pre_rssi_state ==
+		     BT_RSSI_STATE_LOW) ||
+		    (rtlpriv->btcoexist.bt_pre_rssi_state ==
+		     BT_RSSI_STATE_STAY_LOW)) {
+			if (undecoratedsmoothed_pwdb >=
+			    (rssi_thresh + BT_FW_COEX_THRESH_TOL)) {
 				bt_rssi_state = BT_RSSI_STATE_HIGH;
-				rtlpcipriv->bt_coexist.cstate |=
+				rtlpriv->btcoexist.cstate |=
 					BT_COEX_STATE_WIFI_RSSI_1_HIGH;
-				rtlpcipriv->bt_coexist.cstate &=
+				rtlpriv->btcoexist.cstate &=
 					~BT_COEX_STATE_WIFI_RSSI_1_LOW;
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI_1 state switch to High\n");
@@ -130,12 +132,12 @@
 					 "[DM][BT], RSSI_1 state stay at Low\n");
 			}
 		} else {
-			if (smooth < rssi_thresh) {
+			if (undecoratedsmoothed_pwdb < rssi_thresh) {
 				bt_rssi_state = BT_RSSI_STATE_LOW;
-				rtlpcipriv->bt_coexist.cstate |=
-					 BT_COEX_STATE_WIFI_RSSI_1_LOW;
-				rtlpcipriv->bt_coexist.cstate &=
-					 ~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+				rtlpriv->btcoexist.cstate |=
+					BT_COEX_STATE_WIFI_RSSI_1_LOW;
+				rtlpriv->btcoexist.cstate &=
+					~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI_1 state switch to Low\n");
 			} else {
@@ -148,22 +150,22 @@
 		if (rssi_thresh > rssi_thresh1) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 				 "[DM][BT], RSSI_1 thresh error!!\n");
-			return rtlpcipriv->bt_coexist.bt_pre_rssi_state;
+			return rtlpriv->btcoexist.bt_pre_rssi_state;
 		}
 
-		if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
-		    BT_RSSI_STATE_LOW) ||
-		    (rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
-		    BT_RSSI_STATE_STAY_LOW)) {
-			if (smooth >=
+		if ((rtlpriv->btcoexist.bt_pre_rssi_state ==
+		     BT_RSSI_STATE_LOW) ||
+		    (rtlpriv->btcoexist.bt_pre_rssi_state ==
+		     BT_RSSI_STATE_STAY_LOW)) {
+			if (undecoratedsmoothed_pwdb >=
 			    (rssi_thresh+BT_FW_COEX_THRESH_TOL)) {
 				bt_rssi_state = BT_RSSI_STATE_MEDIUM;
-				rtlpcipriv->bt_coexist.cstate |=
-					 BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
-				rtlpcipriv->bt_coexist.cstate &=
-					 ~BT_COEX_STATE_WIFI_RSSI_1_LOW;
-				rtlpcipriv->bt_coexist.cstate &=
-					 ~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+				rtlpriv->btcoexist.cstate |=
+					BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+				rtlpriv->btcoexist.cstate &=
+					~BT_COEX_STATE_WIFI_RSSI_1_LOW;
+				rtlpriv->btcoexist.cstate &=
+					~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI_1 state switch to Medium\n");
 			} else {
@@ -171,28 +173,28 @@
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI_1 state stay at Low\n");
 			}
-		} else if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
-			   BT_RSSI_STATE_MEDIUM) ||
-			   (rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
-			   BT_RSSI_STATE_STAY_MEDIUM)) {
-			if (smooth >= (rssi_thresh1 +
-			    BT_FW_COEX_THRESH_TOL)) {
+		} else if ((rtlpriv->btcoexist.bt_pre_rssi_state ==
+			    BT_RSSI_STATE_MEDIUM) ||
+			   (rtlpriv->btcoexist.bt_pre_rssi_state ==
+			    BT_RSSI_STATE_STAY_MEDIUM)) {
+			if (undecoratedsmoothed_pwdb >=
+			    (rssi_thresh1 + BT_FW_COEX_THRESH_TOL)) {
 				bt_rssi_state = BT_RSSI_STATE_HIGH;
-				rtlpcipriv->bt_coexist.cstate |=
-					 BT_COEX_STATE_WIFI_RSSI_1_HIGH;
-				rtlpcipriv->bt_coexist.cstate &=
-					 ~BT_COEX_STATE_WIFI_RSSI_1_LOW;
-				rtlpcipriv->bt_coexist.cstate &=
-					 ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+				rtlpriv->btcoexist.cstate |=
+					BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+				rtlpriv->btcoexist.cstate &=
+					~BT_COEX_STATE_WIFI_RSSI_1_LOW;
+				rtlpriv->btcoexist.cstate &=
+					~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI_1 state switch to High\n");
-			} else if (smooth < rssi_thresh) {
+			} else if (undecoratedsmoothed_pwdb < rssi_thresh) {
 				bt_rssi_state = BT_RSSI_STATE_LOW;
-				rtlpcipriv->bt_coexist.cstate |=
+				rtlpriv->btcoexist.cstate |=
 					BT_COEX_STATE_WIFI_RSSI_1_LOW;
-				rtlpcipriv->bt_coexist.cstate &=
+				rtlpriv->btcoexist.cstate &=
 					~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
-				rtlpcipriv->bt_coexist.cstate &=
+				rtlpriv->btcoexist.cstate &=
 					~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI_1 state switch to Low\n");
@@ -202,13 +204,13 @@
 					 "[DM][BT], RSSI_1 state stay at Medium\n");
 			}
 		} else {
-			if (smooth < rssi_thresh1) {
+			if (undecoratedsmoothed_pwdb < rssi_thresh1) {
 				bt_rssi_state = BT_RSSI_STATE_MEDIUM;
-				rtlpcipriv->bt_coexist.cstate |=
+				rtlpriv->btcoexist.cstate |=
 					BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
-				rtlpcipriv->bt_coexist.cstate &=
+				rtlpriv->btcoexist.cstate &=
 					~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
-				rtlpcipriv->bt_coexist.cstate &=
+				rtlpriv->btcoexist.cstate &=
 					~BT_COEX_STATE_WIFI_RSSI_1_LOW;
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI_1 state switch to Medium\n");
@@ -219,38 +221,37 @@
 			}
 		}
 	}
-
-	rtlpcipriv->bt_coexist.bt_pre_rssi_state1 = bt_rssi_state;
+	rtlpriv->btcoexist.bt_pre_rssi_state1 = bt_rssi_state;
 
 	return bt_rssi_state;
 }
 
-u8 rtl8723ae_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw,
-					 u8 level_num, u8 rssi_thresh,
-					 u8 rssi_thresh1)
+u8 rtl8723e_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw,
+					u8 level_num,
+					u8 rssi_thresh,
+					u8 rssi_thresh1)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	long smooth;
+	long undecoratedsmoothed_pwdb = 0;
 	u8 bt_rssi_state = 0;
 
-	smooth = rtl8723ae_dm_bt_get_rx_ss(hw);
+	undecoratedsmoothed_pwdb = rtl8723e_dm_bt_get_rx_ss(hw);
 
 	if (level_num == 2) {
-		rtlpcipriv->bt_coexist.cstate &=
-					 ~BT_COEX_STATE_WIFI_RSSI_MEDIUM;
+		rtlpriv->btcoexist.cstate &=
+			~BT_COEX_STATE_WIFI_RSSI_MEDIUM;
 
-		if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
-		    BT_RSSI_STATE_LOW) ||
-		    (rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
-		    BT_RSSI_STATE_STAY_LOW)){
-			if (smooth >=
+		if ((rtlpriv->btcoexist.bt_pre_rssi_state ==
+		     BT_RSSI_STATE_LOW) ||
+		    (rtlpriv->btcoexist.bt_pre_rssi_state ==
+		     BT_RSSI_STATE_STAY_LOW)) {
+			if (undecoratedsmoothed_pwdb >=
 			    (rssi_thresh + BT_FW_COEX_THRESH_TOL)) {
 				bt_rssi_state = BT_RSSI_STATE_HIGH;
-				rtlpcipriv->bt_coexist.cstate |=
-					BT_COEX_STATE_WIFI_RSSI_HIGH;
-				rtlpcipriv->bt_coexist.cstate &=
-					~BT_COEX_STATE_WIFI_RSSI_LOW;
+				rtlpriv->btcoexist.cstate
+					|= BT_COEX_STATE_WIFI_RSSI_HIGH;
+				rtlpriv->btcoexist.cstate
+					&= ~BT_COEX_STATE_WIFI_RSSI_LOW;
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI state switch to High\n");
 			} else {
@@ -259,12 +260,12 @@
 					 "[DM][BT], RSSI state stay at Low\n");
 			}
 		} else {
-			if (smooth < rssi_thresh) {
+			if (undecoratedsmoothed_pwdb < rssi_thresh) {
 				bt_rssi_state = BT_RSSI_STATE_LOW;
-				rtlpcipriv->bt_coexist.cstate |=
-					BT_COEX_STATE_WIFI_RSSI_LOW;
-				rtlpcipriv->bt_coexist.cstate &=
-					~BT_COEX_STATE_WIFI_RSSI_HIGH;
+				rtlpriv->btcoexist.cstate
+					|= BT_COEX_STATE_WIFI_RSSI_LOW;
+				rtlpriv->btcoexist.cstate
+					&= ~BT_COEX_STATE_WIFI_RSSI_HIGH;
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI state switch to Low\n");
 			} else {
@@ -277,20 +278,20 @@
 		if (rssi_thresh > rssi_thresh1) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 				 "[DM][BT], RSSI thresh error!!\n");
-			return rtlpcipriv->bt_coexist.bt_pre_rssi_state;
+			return rtlpriv->btcoexist.bt_pre_rssi_state;
 		}
-		if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
-		    BT_RSSI_STATE_LOW) ||
-		    (rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
-		    BT_RSSI_STATE_STAY_LOW)) {
-			if (smooth >=
+		if ((rtlpriv->btcoexist.bt_pre_rssi_state ==
+		     BT_RSSI_STATE_LOW) ||
+		    (rtlpriv->btcoexist.bt_pre_rssi_state ==
+		     BT_RSSI_STATE_STAY_LOW)) {
+			if (undecoratedsmoothed_pwdb >=
 			    (rssi_thresh + BT_FW_COEX_THRESH_TOL)) {
 				bt_rssi_state = BT_RSSI_STATE_MEDIUM;
-				rtlpcipriv->bt_coexist.cstate
+				rtlpriv->btcoexist.cstate
 					|= BT_COEX_STATE_WIFI_RSSI_MEDIUM;
-				rtlpcipriv->bt_coexist.cstate
+				rtlpriv->btcoexist.cstate
 					&= ~BT_COEX_STATE_WIFI_RSSI_LOW;
-				rtlpcipriv->bt_coexist.cstate
+				rtlpriv->btcoexist.cstate
 					&= ~BT_COEX_STATE_WIFI_RSSI_HIGH;
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI state switch to Medium\n");
@@ -299,28 +300,28 @@
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI state stay at Low\n");
 			}
-		} else if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
-			   BT_RSSI_STATE_MEDIUM) ||
-			   (rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
-			   BT_RSSI_STATE_STAY_MEDIUM)) {
-			if (smooth >=
+		} else if ((rtlpriv->btcoexist.bt_pre_rssi_state ==
+				BT_RSSI_STATE_MEDIUM) ||
+			(rtlpriv->btcoexist.bt_pre_rssi_state ==
+				BT_RSSI_STATE_STAY_MEDIUM)) {
+			if (undecoratedsmoothed_pwdb >=
 			    (rssi_thresh1 + BT_FW_COEX_THRESH_TOL)) {
 				bt_rssi_state = BT_RSSI_STATE_HIGH;
-				rtlpcipriv->bt_coexist.cstate
+				rtlpriv->btcoexist.cstate
 					|= BT_COEX_STATE_WIFI_RSSI_HIGH;
-				rtlpcipriv->bt_coexist.cstate
+				rtlpriv->btcoexist.cstate
 					&= ~BT_COEX_STATE_WIFI_RSSI_LOW;
-				rtlpcipriv->bt_coexist.cstate
+				rtlpriv->btcoexist.cstate
 					&= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM;
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI state switch to High\n");
-			} else if (smooth < rssi_thresh) {
+			} else if (undecoratedsmoothed_pwdb < rssi_thresh) {
 				bt_rssi_state = BT_RSSI_STATE_LOW;
-				rtlpcipriv->bt_coexist.cstate
+				rtlpriv->btcoexist.cstate
 					|= BT_COEX_STATE_WIFI_RSSI_LOW;
-				rtlpcipriv->bt_coexist.cstate
+				rtlpriv->btcoexist.cstate
 					&= ~BT_COEX_STATE_WIFI_RSSI_HIGH;
-				rtlpcipriv->bt_coexist.cstate
+				rtlpriv->btcoexist.cstate
 					&= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM;
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI state switch to Low\n");
@@ -330,13 +331,13 @@
 					 "[DM][BT], RSSI state stay at Medium\n");
 			}
 		} else {
-			if (smooth < rssi_thresh1) {
+			if (undecoratedsmoothed_pwdb < rssi_thresh1) {
 				bt_rssi_state = BT_RSSI_STATE_MEDIUM;
-				rtlpcipriv->bt_coexist.cstate
+				rtlpriv->btcoexist.cstate
 					|= BT_COEX_STATE_WIFI_RSSI_MEDIUM;
-				rtlpcipriv->bt_coexist.cstate
+				rtlpriv->btcoexist.cstate
 					&= ~BT_COEX_STATE_WIFI_RSSI_HIGH;
-				rtlpcipriv->bt_coexist.cstate
+				rtlpriv->btcoexist.cstate
 					&= ~BT_COEX_STATE_WIFI_RSSI_LOW;
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 					 "[DM][BT], RSSI state switch to Medium\n");
@@ -347,31 +348,32 @@
 			}
 		}
 	}
-
-	rtlpcipriv->bt_coexist.bt_pre_rssi_state = bt_rssi_state;
+	rtlpriv->btcoexist.bt_pre_rssi_state = bt_rssi_state;
 	return bt_rssi_state;
 }
 
-long rtl8723ae_dm_bt_get_rx_ss(struct ieee80211_hw *hw)
+long rtl8723e_dm_bt_get_rx_ss(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	long smooth = 0;
+	long undecoratedsmoothed_pwdb = 0;
 
-	if (rtlpriv->mac80211.link_state >= MAC80211_LINKED)
-		smooth = GET_UNDECORATED_AVERAGE_RSSI(rtlpriv);
-	else
-		smooth = rtlpriv->dm.entry_min_undec_sm_pwdb;
-
+	if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
+		undecoratedsmoothed_pwdb =
+			GET_UNDECORATED_AVERAGE_RSSI(rtlpriv);
+	} else {
+		undecoratedsmoothed_pwdb
+			= rtlpriv->dm.entry_min_undec_sm_pwdb;
+	}
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "rtl8723ae_dm_bt_get_rx_ss() = %ld\n", smooth);
+		 "rtl8723e_dm_bt_get_rx_ss() = %ld\n",
+		 undecoratedsmoothed_pwdb);
 
-	return smooth;
+	return undecoratedsmoothed_pwdb;
 }
 
-void rtl8723ae_dm_bt_balance(struct ieee80211_hw *hw,
-			     bool balance_on, u8 ms0, u8 ms1)
+void rtl8723e_dm_bt_balance(struct ieee80211_hw *hw,
+			    bool balance_on, u8 ms0, u8 ms1)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 h2c_parameter[3] = {0};
 
@@ -379,27 +381,26 @@
 		h2c_parameter[2] = 1;
 		h2c_parameter[1] = ms1;
 		h2c_parameter[0] = ms0;
-		rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+		rtlpriv->btcoexist.fw_coexist_all_off = false;
 	} else {
 		h2c_parameter[2] = 0;
 		h2c_parameter[1] = 0;
 		h2c_parameter[0] = 0;
 	}
-	rtlpcipriv->bt_coexist.balance_on = balance_on;
+	rtlpriv->btcoexist.balance_on = balance_on;
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 		 "[DM][BT], Balance=[%s:%dms:%dms], write 0xc=0x%x\n",
-		 balance_on ? "ON" : "OFF", ms0, ms1,
-		 h2c_parameter[0]<<16 | h2c_parameter[1]<<8 | h2c_parameter[2]);
+		 balance_on ? "ON" : "OFF", ms0, ms1, h2c_parameter[0]<<16 |
+		 h2c_parameter[1]<<8 | h2c_parameter[2]);
 
-	rtl8723ae_fill_h2c_cmd(hw, 0xc, 3, h2c_parameter);
+	rtl8723e_fill_h2c_cmd(hw, 0xc, 3, h2c_parameter);
 }
 
 
-void rtl8723ae_dm_bt_agc_table(struct ieee80211_hw *hw, u8 type)
+void rtl8723e_dm_bt_agc_table(struct ieee80211_hw *hw, u8 type)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 
 	if (type == BT_AGCTABLE_OFF) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
@@ -410,15 +411,15 @@
 		rtl_write_dword(rtlpriv, 0xc78, 0x611f0001);
 		rtl_write_dword(rtlpriv, 0xc78, 0x60200001);
 
-		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+		rtl8723e_phy_set_rf_reg(hw, RF90_PATH_A,
 					RF_RX_AGC_HP, 0xfffff, 0x32000);
-		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+		rtl8723e_phy_set_rf_reg(hw, RF90_PATH_A,
 					RF_RX_AGC_HP, 0xfffff, 0x71000);
-		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+		rtl8723e_phy_set_rf_reg(hw, RF90_PATH_A,
 					RF_RX_AGC_HP, 0xfffff, 0xb0000);
-		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+		rtl8723e_phy_set_rf_reg(hw, RF90_PATH_A,
 					RF_RX_AGC_HP, 0xfffff, 0xfc000);
-		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+		rtl8723e_phy_set_rf_reg(hw, RF90_PATH_A,
 					RF_RX_G1, 0xfffff, 0x30355);
 	} else if (type == BT_AGCTABLE_ON) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
@@ -429,25 +430,24 @@
 		rtl_write_dword(rtlpriv, 0xc78, 0x4b1f0001);
 		rtl_write_dword(rtlpriv, 0xc78, 0x4a200001);
 
-		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+		rtl8723e_phy_set_rf_reg(hw, RF90_PATH_A,
 					RF_RX_AGC_HP, 0xfffff, 0xdc000);
-		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+		rtl8723e_phy_set_rf_reg(hw, RF90_PATH_A,
 					RF_RX_AGC_HP, 0xfffff, 0x90000);
-		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+		rtl8723e_phy_set_rf_reg(hw, RF90_PATH_A,
 					RF_RX_AGC_HP, 0xfffff, 0x51000);
-		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+		rtl8723e_phy_set_rf_reg(hw, RF90_PATH_A,
 					RF_RX_AGC_HP, 0xfffff, 0x12000);
-		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+		rtl8723e_phy_set_rf_reg(hw, RF90_PATH_A,
 					RF_RX_G1, 0xfffff, 0x00355);
 
-		rtlpcipriv->bt_coexist.sw_coexist_all_off = false;
+		rtlpriv->btcoexist.sw_coexist_all_off = false;
 	}
 }
 
-void rtl8723ae_dm_bt_bback_off_level(struct ieee80211_hw *hw, u8 type)
+void rtl8723e_dm_bt_bb_back_off_level(struct ieee80211_hw *hw, u8 type)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 
 	if (type == BT_BB_BACKOFF_OFF) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
@@ -457,87 +457,81 @@
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 			 "[BT]BBBackOffLevel On!\n");
 		rtl_write_dword(rtlpriv, 0xc04, 0x3a07611);
-		rtlpcipriv->bt_coexist.sw_coexist_all_off = false;
+		rtlpriv->btcoexist.sw_coexist_all_off = false;
 	}
 }
 
-void rtl8723ae_dm_bt_fw_coex_all_off(struct ieee80211_hw *hw)
+void rtl8723e_dm_bt_fw_coex_all_off(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "rtl8723ae_dm_bt_fw_coex_all_off()\n");
+		 "rtl8723e_dm_bt_fw_coex_all_off()\n");
 
-	if (rtlpcipriv->bt_coexist.fw_coexist_all_off)
+	if (rtlpriv->btcoexist.fw_coexist_all_off)
 		return;
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "rtl8723ae_dm_bt_fw_coex_all_off(), real Do\n");
-	rtl8723ae_dm_bt_fw_coex_all_off_8723a(hw);
-	rtlpcipriv->bt_coexist.fw_coexist_all_off = true;
+		 "rtl8723e_dm_bt_fw_coex_all_off(), real Do\n");
+	rtl8723e_dm_bt_fw_coex_all_off_8723a(hw);
+	rtlpriv->btcoexist.fw_coexist_all_off = true;
 }
 
-void rtl8723ae_dm_bt_sw_coex_all_off(struct ieee80211_hw *hw)
+void rtl8723e_dm_bt_sw_coex_all_off(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "rtl8723ae_dm_bt_sw_coex_all_off()\n");
+		 "rtl8723e_dm_bt_sw_coex_all_off()\n");
 
-	if (rtlpcipriv->bt_coexist.sw_coexist_all_off)
+	if (rtlpriv->btcoexist.sw_coexist_all_off)
 		return;
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "rtl8723ae_dm_bt_sw_coex_all_off(), real Do\n");
-	rtl8723ae_dm_bt_sw_coex_all_off_8723a(hw);
-	rtlpcipriv->bt_coexist.sw_coexist_all_off = true;
+		 "rtl8723e_dm_bt_sw_coex_all_off(), real Do\n");
+	rtl8723e_dm_bt_sw_coex_all_off_8723a(hw);
+	rtlpriv->btcoexist.sw_coexist_all_off = true;
 }
 
-void rtl8723ae_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw)
+void rtl8723e_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "rtl8723ae_dm_bt_hw_coex_all_off()\n");
+		 "rtl8723e_dm_bt_hw_coex_all_off()\n");
 
-	if (rtlpcipriv->bt_coexist.hw_coexist_all_off)
+	if (rtlpriv->btcoexist.hw_coexist_all_off)
 		return;
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "rtl8723ae_dm_bt_hw_coex_all_off(), real Do\n");
+		 "rtl8723e_dm_bt_hw_coex_all_off(), real Do\n");
 
-	rtl8723ae_dm_bt_hw_coex_all_off_8723a(hw);
+	rtl8723e_dm_bt_hw_coex_all_off_8723a(hw);
 
-	rtlpcipriv->bt_coexist.hw_coexist_all_off = true;
+	rtlpriv->btcoexist.hw_coexist_all_off = true;
 }
 
-void rtl8723ae_btdm_coex_all_off(struct ieee80211_hw *hw)
+void rtl8723e_btdm_coex_all_off(struct ieee80211_hw *hw)
 {
-	rtl8723ae_dm_bt_fw_coex_all_off(hw);
-	rtl8723ae_dm_bt_sw_coex_all_off(hw);
-	rtl8723ae_dm_bt_hw_coex_all_off(hw);
+	rtl8723e_dm_bt_fw_coex_all_off(hw);
+	rtl8723e_dm_bt_sw_coex_all_off(hw);
+	rtl8723e_dm_bt_hw_coex_all_off(hw);
 }
 
-bool rtl8723ae_dm_bt_is_coexist_state_changed(struct ieee80211_hw *hw)
+bool rtl8723e_dm_bt_is_coexist_state_changed(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-	if ((rtlpcipriv->bt_coexist.previous_state ==
-	    rtlpcipriv->bt_coexist.cstate) &&
-	    (rtlpcipriv->bt_coexist.previous_state_h ==
-	    rtlpcipriv->bt_coexist.cstate_h))
+	if ((rtlpriv->btcoexist.previous_state == rtlpriv->btcoexist.cstate) &&
+	    (rtlpriv->btcoexist.previous_state_h ==
+	     rtlpriv->btcoexist.cstate_h))
 		return false;
-	else
-		return true;
+	return true;
 }
 
-bool rtl8723ae_dm_bt_is_wifi_up_link(struct ieee80211_hw *hw)
+bool rtl8723e_dm_bt_is_wifi_up_link(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	if (rtlpriv->link_info.tx_busy_traffic)
 		return true;
-	else
-		return false;
+	return false;
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.h b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.h
index 76f4d12..bcd64a2 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.h
@@ -53,8 +53,8 @@
 #define BT_COEX_STATE_WIFI_LEGACY		BIT(3)
 
 #define BT_COEX_STATE_WIFI_RSSI_LOW		BIT(4)
-#define BT_COEX_STATE_WIFI_RSSI_MEDIUM		BIT(5)
-#define BT_COEX_STATE_WIFI_RSSI_HIGH		BIT(6)
+#define BT_COEX_STATE_WIFI_RSSI_MEDIUM	BIT(5)
+#define BT_COEX_STATE_WIFI_RSSI_HIGH	BIT(6)
 #define BT_COEX_STATE_DEC_BT_POWER		BIT(7)
 
 #define BT_COEX_STATE_WIFI_IDLE			BIT(8)
@@ -78,7 +78,7 @@
 #define BT_COEX_STATE_WIFI_RSSI_1_MEDIUM	BIT(25)
 #define BT_COEX_STATE_WIFI_RSSI_1_HIGH		BIT(26)
 
-#define BT_COEX_STATE_BTINFO_COMMON		BIT(30)
+#define BT_COEX_STATE_BTINFO_COMMON			BIT(30)
 #define BT_COEX_STATE_BTINFO_B_HID_SCOESCO	BIT(31)
 #define BT_COEX_STATE_BTINFO_B_FTP_A2DP		BIT(29)
 
@@ -133,28 +133,26 @@
 #define	BTINFO_B_SCO_ESCO			BIT(1)
 #define	BTINFO_B_CONNECTION			BIT(0)
 
+void rtl8723e_btdm_coex_all_off(struct ieee80211_hw *hw);
+void rtl8723e_dm_bt_fw_coex_all_off(struct ieee80211_hw *hw);
 
-void rtl8723ae_btdm_coex_all_off(struct ieee80211_hw *hw);
-void rtl8723ae_dm_bt_fw_coex_all_off(struct ieee80211_hw *hw);
-
-void rtl8723ae_dm_bt_sw_coex_all_off(struct ieee80211_hw *hw);
-void rtl8723ae_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw);
-long rtl8723ae_dm_bt_get_rx_ss(struct ieee80211_hw *hw);
-void rtl8723ae_dm_bt_balance(struct ieee80211_hw *hw,
+void rtl8723e_dm_bt_sw_coex_all_off(struct ieee80211_hw *hw);
+void rtl8723e_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw);
+long rtl8723e_dm_bt_get_rx_ss(struct ieee80211_hw *hw);
+void rtl8723e_dm_bt_balance(struct ieee80211_hw *hw,
 			    bool balance_on, u8 ms0, u8 ms1);
-void rtl8723ae_dm_bt_agc_table(struct ieee80211_hw *hw, u8 type);
-void rtl8723ae_dm_bt_bback_off_level(struct ieee80211_hw *hw, u8 type);
-u8 rtl8723ae_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw,
+void rtl8723e_dm_bt_agc_table(struct ieee80211_hw *hw, u8 tyep);
+void rtl8723e_dm_bt_bb_back_off_level(struct ieee80211_hw *hw, u8 type);
+u8 rtl8723e_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw,
 					u8 level_num, u8 rssi_thresh,
 					u8 rssi_thresh1);
-u8 rtl8723ae_dm_bt_check_coex_rssi_state1(struct ieee80211_hw *hw,
-					 u8  level_num, u8 rssi_thresh,
+u8 rtl8723e_dm_bt_check_coex_rssi_state1(struct ieee80211_hw *hw,
+					 u8 level_num, u8 rssi_thresh,
 					 u8 rssi_thresh1);
 void _rtl8723_dm_bt_check_wifi_state(struct ieee80211_hw *hw);
-void rtl8723ae_dm_bt_reject_ap_aggregated_packet(struct ieee80211_hw *hw,
-						bool reject);
-
-bool rtl8723ae_dm_bt_is_coexist_state_changed(struct ieee80211_hw *hw);
-bool rtl8723ae_dm_bt_is_wifi_up_link(struct ieee80211_hw *hw);
+void rtl8723e_dm_bt_reject_ap_aggregated_packet(struct ieee80211_hw *hw,
+						bool b_reject);
+bool rtl8723e_dm_bt_is_coexist_state_changed(struct ieee80211_hw *hw);
+bool rtl8723e_dm_bt_is_wifi_up_link(struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
index 5d534df..00a0531 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -25,45 +21,42 @@
  *
  * Larry Finger <Larry.Finger@lwfinger.net>
  *
- ****************************************************************************
- */
+ *****************************************************************************/
 #include "hal_btc.h"
 #include "../pci.h"
 #include "phy.h"
-#include "../rtl8723com/phy_common.h"
 #include "fw.h"
-#include "../rtl8723com/fw_common.h"
 #include "reg.h"
 #include "def.h"
+#include "../rtl8723com/phy_common.h"
 
-void rtl8723ae_bt_coex_off_before_lps(struct ieee80211_hw *hw)
+static struct bt_coexist_8723 hal_coex_8723;
+
+void rtl8723e_dm_bt_turn_off_bt_coexist_before_enter_lps(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 
-	if (!rtlpcipriv->bt_coexist.bt_coexistence)
+	if (!rtlpriv->btcoexist.bt_coexistence)
 		return;
 
 	if (ppsc->inactiveps) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BT][DM], Before enter IPS, turn off all Coexist DM\n");
-		rtlpcipriv->bt_coexist.cstate = 0;
-		rtlpcipriv->bt_coexist.previous_state = 0;
-		rtlpcipriv->bt_coexist.cstate_h = 0;
-		rtlpcipriv->bt_coexist.previous_state_h = 0;
-		rtl8723ae_btdm_coex_all_off(hw);
+			"[BT][DM], Before enter IPS, turn off all Coexist DM\n");
+		rtlpriv->btcoexist.cstate = 0;
+		rtlpriv->btcoexist.previous_state = 0;
+		rtlpriv->btcoexist.cstate_h = 0;
+		rtlpriv->btcoexist.previous_state_h = 0;
+		rtl8723e_btdm_coex_all_off(hw);
 	}
 }
 
-static enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw)
+static enum rt_media_status mgnt_link_status_query(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	enum _RT_MEDIA_STATUS m_status = RT_MEDIA_DISCONNECT;
-
+	enum rt_media_status    m_status = RT_MEDIA_DISCONNECT;
 	u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
-
 	if (bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED)
 		m_status = RT_MEDIA_CONNECT;
 
@@ -71,15 +64,14 @@
 }
 
 void rtl_8723e_bt_wifi_media_status_notify(struct ieee80211_hw *hw,
-					   bool mstatus)
+						bool mstatus)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	u8 h2c_parameter[3] = {0};
 	u8 chnl;
 
-	if (!rtlpcipriv->bt_coexist.bt_coexistence)
+	if (!rtlpriv->btcoexist.bt_coexistence)
 		return;
 
 	if (RT_MEDIA_CONNECT == mstatus)
@@ -98,14 +90,13 @@
 		h2c_parameter[2] = 0x20;
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-		 "[BTCoex], FW write 0x19 = 0x%x\n",
+		 "[BTCoex], FW write 0x19=0x%x\n",
 		 h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2]);
 
-	rtl8723ae_fill_h2c_cmd(hw, 0x19, 3, h2c_parameter);
-
+	rtl8723e_fill_h2c_cmd(hw, 0x19, 3, h2c_parameter);
 }
 
-static bool rtl8723ae_dm_bt_is_wifi_busy(struct ieee80211_hw *hw)
+static bool rtl8723e_dm_bt_is_wifi_busy(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	if (rtlpriv->link_info.busytraffic ||
@@ -116,12 +107,12 @@
 		return false;
 }
 
-static void rtl8723ae_dm_bt_set_fw_3a(struct ieee80211_hw *hw,
-				      u8 byte1, u8 byte2, u8 byte3,
-				      u8 byte4, u8 byte5)
+static void rtl8723e_dm_bt_set_fw_3a(struct ieee80211_hw *hw,
+				     u8 byte1, u8 byte2, u8 byte3, u8 byte4,
+				     u8 byte5)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u8 h2c_parameter[5] = {0};
+	u8 h2c_parameter[5];
 
 	h2c_parameter[0] = byte1;
 	h2c_parameter[1] = byte2;
@@ -129,37 +120,37 @@
 	h2c_parameter[3] = byte4;
 	h2c_parameter[4] = byte5;
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], FW write 0x3a(4bytes) = 0x%x%8x\n",
-		 h2c_parameter[0], h2c_parameter[1]<<24 | h2c_parameter[2]<<16 |
-		 h2c_parameter[3]<<8 | h2c_parameter[4]);
-	rtl8723ae_fill_h2c_cmd(hw, 0x3a, 5, h2c_parameter);
+		"[BTCoex], FW write 0x3a(4bytes)=0x%x%8x\n",
+		h2c_parameter[0], h2c_parameter[1]<<24 |
+		h2c_parameter[2]<<16 | h2c_parameter[3]<<8 |
+		h2c_parameter[4]);
+	rtl8723e_fill_h2c_cmd(hw, 0x3a, 5, h2c_parameter);
 }
 
-static bool rtl8723ae_dm_bt_need_to_dec_bt_pwr(struct ieee80211_hw *hw)
+static bool rtl8723e_dm_bt_need_to_dec_bt_pwr(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	if (mgnt_link_status_query(hw) == RT_MEDIA_CONNECT) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "Need to decrease bt power\n");
-		rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_DEC_BT_POWER;
-		return true;
+			"Need to decrease bt power\n");
+			rtlpriv->btcoexist.cstate |=
+			BT_COEX_STATE_DEC_BT_POWER;
+			return true;
 	}
 
-	rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_DEC_BT_POWER;
+	rtlpriv->btcoexist.cstate &= ~BT_COEX_STATE_DEC_BT_POWER;
 	return false;
 }
 
-static bool rtl8723ae_dm_bt_is_same_coexist_state(struct ieee80211_hw *hw)
+static bool rtl8723e_dm_bt_is_same_coexist_state(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 
-	if ((rtlpcipriv->bt_coexist.previous_state ==
-	    rtlpcipriv->bt_coexist.cstate) &&
-	    (rtlpcipriv->bt_coexist.previous_state_h ==
-	    rtlpcipriv->bt_coexist.cstate_h)) {
+	if ((rtlpriv->btcoexist.previous_state ==
+	     rtlpriv->btcoexist.cstate) &&
+	    (rtlpriv->btcoexist.previous_state_h ==
+	     rtlpriv->btcoexist.cstate_h)) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 			 "[DM][BT], Coexist state do not chang!!\n");
 		return true;
@@ -170,86 +161,84 @@
 	}
 }
 
-static void rtl8723ae_dm_bt_set_coex_table(struct ieee80211_hw *hw,
-					   u32 val_0x6c0, u32 val_0x6c8,
-					   u32 val_0x6cc)
+static void rtl8723e_dm_bt_set_coex_table(struct ieee80211_hw *hw,
+					  u32 val_0x6c0, u32 val_0x6c8,
+					  u32 val_0x6cc)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "set coex table, set 0x6c0 = 0x%x\n", val_0x6c0);
+		 "set coex table, set 0x6c0=0x%x\n", val_0x6c0);
 	rtl_write_dword(rtlpriv, 0x6c0, val_0x6c0);
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "set coex table, set 0x6c8 = 0x%x\n", val_0x6c8);
+		 "set coex table, set 0x6c8=0x%x\n", val_0x6c8);
 	rtl_write_dword(rtlpriv, 0x6c8, val_0x6c8);
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "set coex table, set 0x6cc = 0x%x\n", val_0x6cc);
+		 "set coex table, set 0x6cc=0x%x\n", val_0x6cc);
 	rtl_write_byte(rtlpriv, 0x6cc, val_0x6cc);
 }
 
-static void rtl8723ae_dm_bt_set_hw_pta_mode(struct ieee80211_hw *hw, bool mode)
+static void rtl8723e_dm_bt_set_hw_pta_mode(struct ieee80211_hw *hw, bool b_mode)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-	if (BT_PTA_MODE_ON == mode) {
+	if (BT_PTA_MODE_ON == b_mode) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, "PTA mode on, ");
 		/*  Enable GPIO 0/1/2/3/8 pins for bt */
 		rtl_write_byte(rtlpriv, 0x40, 0x20);
-		rtlpcipriv->bt_coexist.hw_coexist_all_off = false;
+		rtlpriv->btcoexist.hw_coexist_all_off = false;
 	} else {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, "PTA mode off\n");
 		rtl_write_byte(rtlpriv, 0x40, 0x0);
 	}
 }
 
-static void rtl8723ae_dm_bt_set_sw_rf_rx_lpf_corner(struct ieee80211_hw *hw,
-						    u8 type)
+static void rtl8723e_dm_bt_set_sw_rf_rx_lpf_corner(struct ieee80211_hw *hw,
+						   u8 type)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	if (BT_RF_RX_LPF_CORNER_SHRINK == type) {
-		/* Shrink RF Rx LPF corner, 0x1e[7:4]=1111 ==> [11:4] by Jenyu*/
+		/* Shrink RF Rx LPF corner, 0x1e[7:4]=1111 ==> [11:4] */
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 			 "Shrink RF Rx LPF corner!!\n");
-		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, 0x1e, 0xfffff,
-					0xf0ff7);
-		rtlpcipriv->bt_coexist.sw_coexist_all_off = false;
+		rtl8723e_phy_set_rf_reg(hw, RF90_PATH_A, 0x1e,
+					0xfffff, 0xf0ff7);
+		rtlpriv->btcoexist.sw_coexist_all_off = false;
 	} else if (BT_RF_RX_LPF_CORNER_RESUME == type) {
 		/*Resume RF Rx LPF corner*/
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 			 "Resume RF Rx LPF corner!!\n");
-		rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, 0x1e, 0xfffff,
-			rtlpcipriv->bt_coexist.bt_rfreg_origin_1e);
+		rtl8723e_phy_set_rf_reg(hw, RF90_PATH_A, 0x1e, 0xfffff,
+					rtlpriv->btcoexist.bt_rfreg_origin_1e);
 	}
 }
 
-static void rtl8723ae_bt_set_penalty_tx_rate_adap(struct ieee80211_hw *hw,
-						  u8 ra_type)
+static void dm_bt_set_sw_penalty_tx_rate_adapt(struct ieee80211_hw *hw,
+					       u8 ra_type)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
-	u8 tmu1;
+	u8 tmp_u1;
 
-	tmu1 = rtl_read_byte(rtlpriv, 0x4fd);
-	tmu1 |= BIT(0);
+	tmp_u1 = rtl_read_byte(rtlpriv, 0x4fd);
+	tmp_u1 |= BIT(0);
 	if (BT_TX_RATE_ADAPTIVE_LOW_PENALTY == ra_type) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-			 "Tx rate adaptive, set low penalty!!\n");
-		tmu1 &= ~BIT(2);
-		rtlpcipriv->bt_coexist.sw_coexist_all_off = false;
+			"Tx rate adaptive, set low penalty!!\n");
+		tmp_u1 &= ~BIT(2);
+		rtlpriv->btcoexist.sw_coexist_all_off = false;
 	} else if (BT_TX_RATE_ADAPTIVE_NORMAL == ra_type) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-			 "Tx rate adaptive, set normal!!\n");
-		tmu1 |= BIT(2);
+			"Tx rate adaptive, set normal!!\n");
+		tmp_u1 |= BIT(2);
 	}
-	rtl_write_byte(rtlpriv, 0x4fd, tmu1);
+
+	rtl_write_byte(rtlpriv, 0x4fd, tmp_u1);
 }
 
-static void rtl8723ae_dm_bt_btdm_structure_reload(struct ieee80211_hw *hw,
+static void rtl8723e_dm_bt_btdm_structure_reload(struct ieee80211_hw *hw,
 						 struct btdm_8723 *btdm)
 {
 	btdm->all_off = false;
@@ -292,32 +281,31 @@
 	btdm->dec_bt_pwr = false;
 }
 
-static void dm_bt_btdm_structure_reload_all_off(struct ieee80211_hw *hw,
-						struct btdm_8723 *btdm)
+static void rtl8723e_dm_bt_btdm_structure_reload_all_off(struct ieee80211_hw *hw,
+							 struct btdm_8723 *btdm)
 {
-	rtl8723ae_dm_bt_btdm_structure_reload(hw, btdm);
+	rtl8723e_dm_bt_btdm_structure_reload(hw, btdm);
 	btdm->all_off = true;
 	btdm->pta_on = false;
 	btdm->wlan_act_hi = 0x10;
 }
 
-static bool rtl8723ae_dm_bt_is_2_ant_common_action(struct ieee80211_hw *hw)
+static bool rtl8723e_dm_bt_is_2_ant_common_action(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct btdm_8723 btdm8723;
-	bool common = false;
+	bool b_common = false;
 
-	rtl8723ae_dm_bt_btdm_structure_reload(hw, &btdm8723);
+	rtl8723e_dm_bt_btdm_structure_reload(hw, &btdm8723);
 
-	if (!rtl8723ae_dm_bt_is_wifi_busy(hw)
-	    && !rtlpcipriv->bt_coexist.bt_busy) {
+	if (!rtl8723e_dm_bt_is_wifi_busy(hw) &&
+	    !rtlpriv->btcoexist.bt_busy) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 			 "Wifi idle + Bt idle, bt coex mechanism always off!!\n");
-		dm_bt_btdm_structure_reload_all_off(hw, &btdm8723);
-		common = true;
-	} else if (rtl8723ae_dm_bt_is_wifi_busy(hw)
-		   && !rtlpcipriv->bt_coexist.bt_busy) {
+		rtl8723e_dm_bt_btdm_structure_reload_all_off(hw, &btdm8723);
+		b_common = true;
+	} else if (rtl8723e_dm_bt_is_wifi_busy(hw) &&
+		   !rtlpriv->btcoexist.bt_busy) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 			 "Wifi non-idle + Bt disabled/idle!!\n");
 		btdm8723.low_penalty_rate_adaptive = true;
@@ -338,17 +326,17 @@
 		btdm8723.tdma_dac_swing = TDMA_DAC_SWING_OFF;
 		btdm8723.b2_ant_hid_en = false;
 
-		common = true;
-	} else if (rtlpcipriv->bt_coexist.bt_busy) {
+		b_common = true;
+	} else if (rtlpriv->btcoexist.bt_busy) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "Bt non-idle!\n");
+			"Bt non-idle!\n");
 		if (mgnt_link_status_query(hw) == RT_MEDIA_CONNECT) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-				 "Wifi connection exist\n");
-			common = false;
+				"Wifi connection exist\n");
+			b_common = false;
 		} else {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-				 "No Wifi connection!\n");
+				"No Wifi connection!\n");
 			btdm8723.rf_rx_lpf_shrink = true;
 			btdm8723.low_penalty_rate_adaptive = false;
 			btdm8723.reject_aggre_pkt = false;
@@ -367,27 +355,28 @@
 			btdm8723.tdma_dac_swing = TDMA_DAC_SWING_OFF;
 			btdm8723.b2_ant_hid_en = false;
 
-			common = true;
+			b_common = true;
 		}
 	}
 
-	if (rtl8723ae_dm_bt_need_to_dec_bt_pwr(hw))
+	if (rtl8723e_dm_bt_need_to_dec_bt_pwr(hw))
 		btdm8723.dec_bt_pwr = true;
 
-	if (common)
-		rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_BTINFO_COMMON;
+	if (b_common)
+		rtlpriv->btcoexist.cstate |=
+			BT_COEX_STATE_BTINFO_COMMON;
 
-	if (common && rtl8723ae_dm_bt_is_coexist_state_changed(hw))
-		rtl8723ae_dm_bt_set_bt_dm(hw, &btdm8723);
+	if (b_common && rtl8723e_dm_bt_is_coexist_state_changed(hw))
+		rtl8723e_dm_bt_set_bt_dm(hw, &btdm8723);
 
-	return common;
+	return b_common;
 }
 
-static void rtl8723ae_dm_bt_set_sw_full_time_dac_swing(struct ieee80211_hw *hw,
-						       bool sw_dac_swing_on,
-						       u32 sw_dac_swing_lvl)
+static void rtl8723e_dm_bt_set_sw_full_time_dac_swing(
+		struct ieee80211_hw *hw,
+		bool sw_dac_swing_on,
+		u32 sw_dac_swing_lvl)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	if (sw_dac_swing_on) {
@@ -395,7 +384,7 @@
 			 "[BTCoex], SwDacSwing = 0x%x\n", sw_dac_swing_lvl);
 		rtl8723_phy_set_bb_reg(hw, 0x880, 0xff000000,
 				       sw_dac_swing_lvl);
-		rtlpcipriv->bt_coexist.sw_coexist_all_off = false;
+		rtlpriv->btcoexist.sw_coexist_all_off = false;
 	} else {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 			 "[BTCoex], SwDacSwing Off!\n");
@@ -403,10 +392,9 @@
 	}
 }
 
-static void rtl8723ae_dm_bt_set_fw_dec_bt_pwr(struct ieee80211_hw *hw,
-					      bool dec_bt_pwr)
+static void rtl8723e_dm_bt_set_fw_dec_bt_pwr(
+		struct ieee80211_hw *hw, bool dec_bt_pwr)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 h2c_parameter[1] = {0};
 
@@ -414,87 +402,86 @@
 
 	if (dec_bt_pwr) {
 		h2c_parameter[0] |= BIT(1);
-		rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+		rtlpriv->btcoexist.fw_coexist_all_off = false;
 	}
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], decrease Bt Power : %s, write 0x21 = 0x%x\n",
+		 "[BTCoex], decrease Bt Power : %s, write 0x21=0x%x\n",
 		 (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]);
 
-	rtl8723ae_fill_h2c_cmd(hw, 0x21, 1, h2c_parameter);
+	rtl8723e_fill_h2c_cmd(hw, 0x21, 1, h2c_parameter);
 }
 
-static void rtl8723ae_dm_bt_set_fw_2_ant_hid(struct ieee80211_hw *hw,
-					    bool enable, bool dac_swing_on)
+static void rtl8723e_dm_bt_set_fw_2_ant_hid(struct ieee80211_hw *hw,
+					    bool b_enable, bool b_dac_swing_on)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 h2c_parameter[1] = {0};
 
-	if (enable) {
+	if (b_enable) {
 		h2c_parameter[0] |= BIT(0);
-		rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+		rtlpriv->btcoexist.fw_coexist_all_off = false;
 	}
-	if (dac_swing_on)
+	if (b_dac_swing_on)
 		h2c_parameter[0] |= BIT(1); /* Dac Swing default enable */
+
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], turn 2-Ant+HID mode %s, DACSwing:%s, write 0x15 = 0x%x\n",
-		 (enable ? "ON!!" : "OFF!!"), (dac_swing_on ? "ON" : "OFF"),
+		 "[BTCoex], turn 2-Ant+HID mode %s, DACSwing:%s, write 0x15=0x%x\n",
+		 (b_enable ? "ON!!" : "OFF!!"), (b_dac_swing_on ? "ON" : "OFF"),
 		 h2c_parameter[0]);
 
-	rtl8723ae_fill_h2c_cmd(hw, 0x15, 1, h2c_parameter);
+	rtl8723e_fill_h2c_cmd(hw, 0x15, 1, h2c_parameter);
 }
 
-static void rtl8723ae_dm_bt_set_fw_tdma_ctrl(struct ieee80211_hw *hw,
-					     bool enable, u8 ant_num, u8 nav_en,
-					     u8 dac_swing_en)
+static void rtl8723e_dm_bt_set_fw_tdma_ctrl(struct ieee80211_hw *hw,
+					    bool b_enable, u8 ant_num,
+					    u8 nav_en, u8 dac_swing_en)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	u8 h2c_parameter[1] = {0};
 	u8 h2c_parameter1[1] = {0};
 
 	h2c_parameter[0] = 0;
 	h2c_parameter1[0] = 0;
 
-	if (enable) {
+	if (b_enable) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 			 "[BTCoex], set BT PTA update manager to trigger update!!\n");
 		h2c_parameter1[0] |= BIT(0);
 
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-			 "[BTCoex], turn TDMA mode ON!!\n");
+			"[BTCoex], turn TDMA mode ON!!\n");
 		h2c_parameter[0] |= BIT(0);		/* function enable */
 		if (TDMA_1ANT == ant_num) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "[BTCoex], TDMA_1ANT\n");
+			"[BTCoex], TDMA_1ANT\n");
 			h2c_parameter[0] |= BIT(1);
 		} else if (TDMA_2ANT == ant_num) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "[BTCoex], TDMA_2ANT\n");
+			"[BTCoex], TDMA_2ANT\n");
 		} else {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "[BTCoex], Unknown Ant\n");
+			"[BTCoex], Unknown Ant\n");
 		}
 
 		if (TDMA_NAV_OFF == nav_en) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "[BTCoex], TDMA_NAV_OFF\n");
+			"[BTCoex], TDMA_NAV_OFF\n");
 		} else if (TDMA_NAV_ON == nav_en) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "[BTCoex], TDMA_NAV_ON\n");
+			"[BTCoex], TDMA_NAV_ON\n");
 			h2c_parameter[0] |= BIT(2);
 		}
 
 		if (TDMA_DAC_SWING_OFF == dac_swing_en) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "[BTCoex], TDMA_DAC_SWING_OFF\n");
+				"[BTCoex], TDMA_DAC_SWING_OFF\n");
 		} else if (TDMA_DAC_SWING_ON == dac_swing_en) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "[BTCoex], TDMA_DAC_SWING_ON\n");
+				"[BTCoex], TDMA_DAC_SWING_ON\n");
 			h2c_parameter[0] |= BIT(4);
 		}
-		rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+		rtlpriv->btcoexist.fw_coexist_all_off = false;
 	} else {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 			 "[BTCoex], set BT PTA update manager to no update!!\n");
@@ -503,46 +490,46 @@
 	}
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], FW2AntTDMA, write 0x26 = 0x%x\n",
+		 "[BTCoex], FW2AntTDMA, write 0x26=0x%x\n",
 		 h2c_parameter1[0]);
-	rtl8723ae_fill_h2c_cmd(hw, 0x26, 1, h2c_parameter1);
+	rtl8723e_fill_h2c_cmd(hw, 0x26, 1, h2c_parameter1);
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], FW2AntTDMA, write 0x14 = 0x%x\n", h2c_parameter[0]);
-	rtl8723ae_fill_h2c_cmd(hw, 0x14, 1, h2c_parameter);
+		"[BTCoex], FW2AntTDMA, write 0x14=0x%x\n",
+		h2c_parameter[0]);
+	rtl8723e_fill_h2c_cmd(hw, 0x14, 1, h2c_parameter);
 }
 
-static void rtl8723ae_dm_bt_set_fw_ignore_wlan_act(struct ieee80211_hw *hw,
-						   bool enable)
+static void rtl8723e_dm_bt_set_fw_ignore_wlan_act(struct ieee80211_hw *hw,
+						  bool b_enable)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	u8 h2c_parameter[1] = {0};
 
-	if (enable) {
+	if (b_enable) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-			 "[BTCoex], BT Ignore Wlan_Act !!\n");
+			"[BTCoex], BT Ignore Wlan_Act !!\n");
 		h2c_parameter[0] |= BIT(0);		/* function enable */
-		rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+		rtlpriv->btcoexist.fw_coexist_all_off = false;
 	} else {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-			 "[BTCoex], BT don't ignore Wlan_Act !!\n");
+			"[BTCoex], BT don't ignore Wlan_Act !!\n");
 	}
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], set FW for BT Ignore Wlan_Act, write 0x25 = 0x%x\n",
+		 "[BTCoex], set FW for BT Ignore Wlan_Act, write 0x25=0x%x\n",
 		 h2c_parameter[0]);
 
-	rtl8723ae_fill_h2c_cmd(hw, 0x25, 1, h2c_parameter);
+	rtl8723e_fill_h2c_cmd(hw, 0x25, 1, h2c_parameter);
 }
 
-static void rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(struct ieee80211_hw *hw,
-						 bool enable, u8 ant_num,
-						 u8 nav_en)
+static void rtl8723e_dm_bt_set_fw_tra_tdma_ctrl(struct ieee80211_hw *hw,
+						bool b_enable, u8 ant_num,
+						u8 nav_en)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
 	u8 h2c_parameter[2] = {0};
 
 	/* Only 8723 B cut should do this */
@@ -552,460 +539,467 @@
 		return;
 	}
 
-	if (enable) {
+	if (b_enable) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 			 "[BTCoex], turn TTDMA mode ON!!\n");
-		h2c_parameter[0] |= BIT(0);		/* function enable */
+		h2c_parameter[0] |= BIT(0);	/* function enable */
 		if (TDMA_1ANT == ant_num) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 				 "[BTCoex], TTDMA_1ANT\n");
 			h2c_parameter[0] |= BIT(1);
 		} else if (TDMA_2ANT == ant_num) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "[BTCoex], TTDMA_2ANT\n");
+			"[BTCoex], TTDMA_2ANT\n");
 		} else {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "[BTCoex], Unknown Ant\n");
+			"[BTCoex], Unknown Ant\n");
 		}
 
 		if (TDMA_NAV_OFF == nav_en) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "[BTCoex], TTDMA_NAV_OFF\n");
+			"[BTCoex], TTDMA_NAV_OFF\n");
 		} else if (TDMA_NAV_ON == nav_en) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "[BTCoex], TTDMA_NAV_ON\n");
+			"[BTCoex], TTDMA_NAV_ON\n");
 			h2c_parameter[1] |= BIT(0);
 		}
 
-		rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+		rtlpriv->btcoexist.fw_coexist_all_off = false;
 	} else {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-			 "[BTCoex], turn TTDMA mode OFF!!\n");
+			"[BTCoex], turn TTDMA mode OFF!!\n");
 	}
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], FW Traditional TDMA, write 0x33 = 0x%x\n",
-		 h2c_parameter[0] << 8 | h2c_parameter[1]);
+		"[BTCoex], FW Traditional TDMA, write 0x33=0x%x\n",
+		h2c_parameter[0] << 8 | h2c_parameter[1]);
 
-	rtl8723ae_fill_h2c_cmd(hw, 0x33, 2, h2c_parameter);
+	rtl8723e_fill_h2c_cmd(hw, 0x33, 2, h2c_parameter);
 }
 
-static void rtl8723ae_dm_bt_set_fw_dac_swing_level(struct ieee80211_hw *hw,
-						   u8 dac_swing_lvl)
+static void rtl8723e_dm_bt_set_fw_dac_swing_level(struct ieee80211_hw *hw,
+						  u8 dac_swing_lvl)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 h2c_parameter[1] = {0};
-
 	h2c_parameter[0] = dac_swing_lvl;
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swing_lvl);
+		"[BTCoex], Set Dac Swing Level=0x%x\n", dac_swing_lvl);
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], write 0x29 = 0x%x\n", h2c_parameter[0]);
+		"[BTCoex], write 0x29=0x%x\n", h2c_parameter[0]);
 
-	rtl8723ae_fill_h2c_cmd(hw, 0x29, 1, h2c_parameter);
+	rtl8723e_fill_h2c_cmd(hw, 0x29, 1, h2c_parameter);
 }
 
-static void rtl8723ae_dm_bt_set_fw_bt_hid_info(struct ieee80211_hw *hw,
-					       bool enable)
+static void rtl8723e_dm_bt_set_fw_bt_hid_info(struct ieee80211_hw *hw,
+					      bool b_enable)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 h2c_parameter[1] = {0};
-
 	h2c_parameter[0] = 0;
 
-	if (enable) {
+	if (b_enable) {
 		h2c_parameter[0] |= BIT(0);
-		rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+		rtlpriv->btcoexist.fw_coexist_all_off = false;
 	}
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], Set BT HID information = 0x%x\n", enable);
+		"[BTCoex], Set BT HID information=0x%x\n", b_enable);
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], write 0x24 = 0x%x\n", h2c_parameter[0]);
+		"[BTCoex], write 0x24=0x%x\n", h2c_parameter[0]);
 
-	rtl8723ae_fill_h2c_cmd(hw, 0x24, 1, h2c_parameter);
+	rtl8723e_fill_h2c_cmd(hw, 0x24, 1, h2c_parameter);
 }
 
-static void rtl8723ae_dm_bt_set_fw_bt_retry_index(struct ieee80211_hw *hw,
-						  u8 retry_index)
+static void rtl8723e_dm_bt_set_fw_bt_retry_index(struct ieee80211_hw *hw,
+						 u8 retry_index)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 h2c_parameter[1] = {0};
-
 	h2c_parameter[0] = retry_index;
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], Set BT Retry Index=%d\n", retry_index);
+		"[BTCoex], Set BT Retry Index=%d\n", retry_index);
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], write 0x23 = 0x%x\n", h2c_parameter[0]);
+		"[BTCoex], write 0x23=0x%x\n", h2c_parameter[0]);
 
-	rtl8723ae_fill_h2c_cmd(hw, 0x23, 1, h2c_parameter);
+	rtl8723e_fill_h2c_cmd(hw, 0x23, 1, h2c_parameter);
 }
 
-static void rtl8723ae_dm_bt_set_fw_wlan_act(struct ieee80211_hw *hw,
-					    u8 wlan_act_hi, u8 wlan_act_lo)
+static void rtl8723e_dm_bt_set_fw_wlan_act(struct ieee80211_hw *hw,
+					   u8 wlan_act_hi, u8 wlan_act_lo)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 h2c_parameter_hi[1] = {0};
 	u8 h2c_parameter_lo[1] = {0};
-
 	h2c_parameter_hi[0] = wlan_act_hi;
 	h2c_parameter_lo[0] = wlan_act_lo;
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], Set WLAN_ACT Hi:Lo = 0x%x/0x%x\n", wlan_act_hi,
-		 wlan_act_lo);
+		"[BTCoex], Set WLAN_ACT Hi:Lo=0x%x/0x%x\n",
+		wlan_act_hi, wlan_act_lo);
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], write 0x22 = 0x%x\n", h2c_parameter_hi[0]);
+		"[BTCoex], write 0x22=0x%x\n", h2c_parameter_hi[0]);
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "[BTCoex], write 0x11 = 0x%x\n", h2c_parameter_lo[0]);
+		"[BTCoex], write 0x11=0x%x\n", h2c_parameter_lo[0]);
 
 	/* WLAN_ACT = High duration, unit:ms */
-	rtl8723ae_fill_h2c_cmd(hw, 0x22, 1, h2c_parameter_hi);
+	rtl8723e_fill_h2c_cmd(hw, 0x22, 1, h2c_parameter_hi);
 	/*  WLAN_ACT = Low duration, unit:3*625us */
-	rtl8723ae_fill_h2c_cmd(hw, 0x11, 1, h2c_parameter_lo);
+	rtl8723e_fill_h2c_cmd(hw, 0x11, 1, h2c_parameter_lo);
 }
 
-void rtl8723ae_dm_bt_set_bt_dm(struct ieee80211_hw *hw, struct btdm_8723 *btdm)
+void rtl8723e_dm_bt_set_bt_dm(struct ieee80211_hw *hw,
+			      struct btdm_8723 *btdm)
 {
-	struct rtl_pci_priv	*rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv	*rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-	struct btdm_8723 *btdm_8723 = &rtlhal->hal_coex_8723.btdm;
+	struct btdm_8723 *btdm_8723 = &hal_coex_8723.btdm;
 	u8 i;
+
 	bool fw_current_inpsmode = false;
 	bool fw_ps_awake = true;
 
 	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
-				      (u8 *)(&fw_current_inpsmode));
+					      (u8 *)(&fw_current_inpsmode));
 	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
-				      (u8 *)(&fw_ps_awake));
+					      (u8 *)(&fw_ps_awake));
 
-	/* check new setting is different than the old one,
-	 * if all the same, don't do the setting again.
-	 */
+	/* check new setting is different with the old one, */
+	/* if all the same, don't do the setting again. */
 	if (memcmp(btdm_8723, btdm, sizeof(struct btdm_8723)) == 0) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], the same coexist setting, return!!\n");
+			"[BTCoex], the same coexist setting, return!!\n");
 		return;
 	} else {	/* save the new coexist setting */
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], UPDATE TO NEW COEX SETTING!!\n");
+			"[BTCoex], UPDATE TO NEW COEX SETTING!!\n");
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new bAllOff = 0x%x/ 0x%x\n",
-			 btdm_8723->all_off, btdm->all_off);
+			"[BTCoex], original/new bAllOff=0x%x/ 0x%x\n",
+			btdm_8723->all_off, btdm->all_off);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new agc_table_en = 0x%x/ 0x%x\n",
-			 btdm_8723->agc_table_en, btdm->agc_table_en);
+			"[BTCoex], original/new agc_table_en=0x%x/ 0x%x\n",
+			btdm_8723->agc_table_en, btdm->agc_table_en);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new adc_back_off_on = 0x%x/ 0x%x\n",
-			 btdm_8723->adc_back_off_on, btdm->adc_back_off_on);
+			 "[BTCoex], original/new adc_back_off_on=0x%x/ 0x%x\n",
+			 btdm_8723->adc_back_off_on,
+			 btdm->adc_back_off_on);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new b2_ant_hid_en = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new b2_ant_hid_en=0x%x/ 0x%x\n",
 			 btdm_8723->b2_ant_hid_en, btdm->b2_ant_hid_en);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new bLowPenaltyRateAdaptive = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new bLowPenaltyRateAdaptive=0x%x/ 0x%x\n",
 			 btdm_8723->low_penalty_rate_adaptive,
 			 btdm->low_penalty_rate_adaptive);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new bRfRxLpfShrink = 0x%x/ 0x%x\n",
-			 btdm_8723->rf_rx_lpf_shrink, btdm->rf_rx_lpf_shrink);
+			 "[BTCoex], original/new bRfRxLpfShrink=0x%x/ 0x%x\n",
+			 btdm_8723->rf_rx_lpf_shrink,
+			 btdm->rf_rx_lpf_shrink);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new bRejectAggrePkt = 0x%x/ 0x%x\n",
-			 btdm_8723->reject_aggre_pkt, btdm->reject_aggre_pkt);
+			 "[BTCoex], original/new bRejectAggrePkt=0x%x/ 0x%x\n",
+			 btdm_8723->reject_aggre_pkt,
+			 btdm->reject_aggre_pkt);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new tdma_on = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new tdma_on=0x%x/ 0x%x\n",
 			 btdm_8723->tdma_on, btdm->tdma_on);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new tdmaAnt = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new tdmaAnt=0x%x/ 0x%x\n",
 			 btdm_8723->tdma_ant, btdm->tdma_ant);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new tdmaNav = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new tdmaNav=0x%x/ 0x%x\n",
 			 btdm_8723->tdma_nav, btdm->tdma_nav);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new tdma_dac_swing = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new tdma_dac_swing=0x%x/ 0x%x\n",
 			 btdm_8723->tdma_dac_swing, btdm->tdma_dac_swing);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new fwDacSwingLvl = 0x%x/ 0x%x\n",
-			 btdm_8723->fw_dac_swing_lvl, btdm->fw_dac_swing_lvl);
+			 "[BTCoex], original/new fw_dac_swing_lvl=0x%x/ 0x%x\n",
+			 btdm_8723->fw_dac_swing_lvl,
+			 btdm->fw_dac_swing_lvl);
 
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new bTraTdmaOn = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new bTraTdmaOn=0x%x/ 0x%x\n",
 			 btdm_8723->tra_tdma_on, btdm->tra_tdma_on);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new traTdmaAnt = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new traTdmaAnt=0x%x/ 0x%x\n",
 			 btdm_8723->tra_tdma_ant, btdm->tra_tdma_ant);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new traTdmaNav = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new traTdmaNav=0x%x/ 0x%x\n",
 			 btdm_8723->tra_tdma_nav, btdm->tra_tdma_nav);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new bPsTdmaOn = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new bPsTdmaOn=0x%x/ 0x%x\n",
 			 btdm_8723->ps_tdma_on, btdm->ps_tdma_on);
 		for (i = 0; i < 5; i++) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-				 "[BTCoex], original/new psTdmaByte[i] = 0x%x/ 0x%x\n",
+				 "[BTCoex], original/new psTdmaByte[i]=0x%x/ 0x%x\n",
 				 btdm_8723->ps_tdma_byte[i],
 				 btdm->ps_tdma_byte[i]);
 		}
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new bIgnoreWlanAct = 0x%x/ 0x%x\n",
-			 btdm_8723->ignore_wlan_act, btdm->ignore_wlan_act);
+			"[BTCoex], original/new bIgnoreWlanAct=0x%x/ 0x%x\n",
+			btdm_8723->ignore_wlan_act,
+			btdm->ignore_wlan_act);
+
 
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new bPtaOn = 0x%x/ 0x%x\n",
-			 btdm_8723->pta_on, btdm->pta_on);
+			"[BTCoex], original/new bPtaOn=0x%x/ 0x%x\n",
+			btdm_8723->pta_on, btdm->pta_on);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new val_0x6c0 = 0x%x/ 0x%x\n",
-			 btdm_8723->val_0x6c0, btdm->val_0x6c0);
+			"[BTCoex], original/new val_0x6c0=0x%x/ 0x%x\n",
+			btdm_8723->val_0x6c0, btdm->val_0x6c0);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new val_0x6c8 = 0x%x/ 0x%x\n",
-			 btdm_8723->val_0x6c8, btdm->val_0x6c8);
+			"[BTCoex], original/new val_0x6c8=0x%x/ 0x%x\n",
+			btdm_8723->val_0x6c8, btdm->val_0x6c8);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new val_0x6cc = 0x%x/ 0x%x\n",
-			 btdm_8723->val_0x6cc, btdm->val_0x6cc);
+			"[BTCoex], original/new val_0x6cc=0x%x/ 0x%x\n",
+			btdm_8723->val_0x6cc, btdm->val_0x6cc);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new sw_dac_swing_on = 0x%x/ 0x%x\n",
-			 btdm_8723->sw_dac_swing_on, btdm->sw_dac_swing_on);
+			 "[BTCoex], original/new sw_dac_swing_on=0x%x/ 0x%x\n",
+			 btdm_8723->sw_dac_swing_on,
+			 btdm->sw_dac_swing_on);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new sw_dac_swing_lvl = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new sw_dac_swing_lvl=0x%x/ 0x%x\n",
 			 btdm_8723->sw_dac_swing_lvl,
 			 btdm->sw_dac_swing_lvl);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new wlanActHi = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new wlanActHi=0x%x/ 0x%x\n",
 			 btdm_8723->wlan_act_hi, btdm->wlan_act_hi);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new wlanActLo = 0x%x/ 0x%x\n",
+			 "[BTCoex], original/new wlanActLo=0x%x/ 0x%x\n",
 			 btdm_8723->wlan_act_lo, btdm->wlan_act_lo);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], original/new btRetryIndex = 0x%x/ 0x%x\n",
-			btdm_8723->bt_retry_index, btdm->bt_retry_index);
+			 "[BTCoex], original/new btRetryIndex=0x%x/ 0x%x\n",
+			 btdm_8723->bt_retry_index, btdm->bt_retry_index);
 
 		memcpy(btdm_8723, btdm, sizeof(struct btdm_8723));
 	}
-	/*
-	 * Here we only consider when Bt Operation
+	/* Here we only consider when Bt Operation
 	 * inquiry/paging/pairing is ON
 	 * we only need to turn off TDMA
 	 */
 
-	if (rtlpcipriv->bt_coexist.hold_for_bt_operation) {
+	if (rtlpriv->btcoexist.hold_for_bt_operation) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-			 "[BTCoex], set to ignore wlanAct for BT OP!!\n");
-		rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw, true);
+			"[BTCoex], set to ignore wlanAct for BT OP!!\n");
+		rtl8723e_dm_bt_set_fw_ignore_wlan_act(hw, true);
 		return;
 	}
 
 	if (btdm->all_off) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-			 "[BTCoex], disable all coexist mechanism !!\n");
-		rtl8723ae_btdm_coex_all_off(hw);
+			"[BTCoex], disable all coexist mechanism !!\n");
+		rtl8723e_btdm_coex_all_off(hw);
 		return;
 	}
 
-	rtl8723ae_dm_bt_reject_ap_aggregated_packet(hw, btdm->reject_aggre_pkt);
+	rtl8723e_dm_bt_reject_ap_aggregated_packet(hw, btdm->reject_aggre_pkt);
 
 	if (btdm->low_penalty_rate_adaptive)
-		rtl8723ae_bt_set_penalty_tx_rate_adap(hw,
-			BT_TX_RATE_ADAPTIVE_LOW_PENALTY);
+		dm_bt_set_sw_penalty_tx_rate_adapt(hw, BT_TX_RATE_ADAPTIVE_LOW_PENALTY);
 	else
-		rtl8723ae_bt_set_penalty_tx_rate_adap(hw,
-			BT_TX_RATE_ADAPTIVE_NORMAL);
+		dm_bt_set_sw_penalty_tx_rate_adapt(hw,
+						   BT_TX_RATE_ADAPTIVE_NORMAL);
 
 	if (btdm->rf_rx_lpf_shrink)
-		rtl8723ae_dm_bt_set_sw_rf_rx_lpf_corner(hw,
-					 BT_RF_RX_LPF_CORNER_SHRINK);
+		rtl8723e_dm_bt_set_sw_rf_rx_lpf_corner(hw,
+				BT_RF_RX_LPF_CORNER_SHRINK);
 	else
-		rtl8723ae_dm_bt_set_sw_rf_rx_lpf_corner(hw,
-					 BT_RF_RX_LPF_CORNER_RESUME);
+		rtl8723e_dm_bt_set_sw_rf_rx_lpf_corner(hw,
+				BT_RF_RX_LPF_CORNER_RESUME);
 
 	if (btdm->agc_table_en)
-		rtl8723ae_dm_bt_agc_table(hw, BT_AGCTABLE_ON);
+		rtl8723e_dm_bt_agc_table(hw, BT_AGCTABLE_ON);
 	else
-		rtl8723ae_dm_bt_agc_table(hw, BT_AGCTABLE_OFF);
+		rtl8723e_dm_bt_agc_table(hw, BT_AGCTABLE_OFF);
 
 	if (btdm->adc_back_off_on)
-		rtl8723ae_dm_bt_bback_off_level(hw, BT_BB_BACKOFF_ON);
+		rtl8723e_dm_bt_bb_back_off_level(hw, BT_BB_BACKOFF_ON);
 	else
-		rtl8723ae_dm_bt_bback_off_level(hw, BT_BB_BACKOFF_OFF);
+		rtl8723e_dm_bt_bb_back_off_level(hw, BT_BB_BACKOFF_OFF);
 
-	rtl8723ae_dm_bt_set_fw_bt_retry_index(hw, btdm->bt_retry_index);
+	rtl8723e_dm_bt_set_fw_bt_retry_index(hw, btdm->bt_retry_index);
 
-	rtl8723ae_dm_bt_set_fw_dac_swing_level(hw, btdm->fw_dac_swing_lvl);
-	rtl8723ae_dm_bt_set_fw_wlan_act(hw, btdm->wlan_act_hi,
+	rtl8723e_dm_bt_set_fw_dac_swing_level(hw, btdm->fw_dac_swing_lvl);
+	rtl8723e_dm_bt_set_fw_wlan_act(hw, btdm->wlan_act_hi,
 				       btdm->wlan_act_lo);
 
-	rtl8723ae_dm_bt_set_coex_table(hw, btdm->val_0x6c0,
-		btdm->val_0x6c8, btdm->val_0x6cc);
-	rtl8723ae_dm_bt_set_hw_pta_mode(hw, btdm->pta_on);
+	rtl8723e_dm_bt_set_coex_table(hw, btdm->val_0x6c0,
+				      btdm->val_0x6c8, btdm->val_0x6cc);
+	rtl8723e_dm_bt_set_hw_pta_mode(hw, btdm->pta_on);
 
 	/* Note: There is a constraint between TDMA and 2AntHID
-	 * Only one of 2AntHid and tdma can be turned on
-	 * We should turn off those mechanisms first
-	 * and then turn on them on.
+	 * Only one of 2AntHid and tdma can be turn on
+	 * We should turn off those mechanisms should be turned off first
+	 * and then turn on those mechanisms should be turned on.
 	*/
 	if (btdm->b2_ant_hid_en) {
 		/* turn off tdma */
-		rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on,
+		rtl8723e_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on,
 						    btdm->tra_tdma_ant,
 						    btdm->tra_tdma_nav);
-		rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, false, btdm->tdma_ant,
+		rtl8723e_dm_bt_set_fw_tdma_ctrl(hw, false, btdm->tdma_ant,
 						btdm->tdma_nav,
 						btdm->tdma_dac_swing);
 
 		/* turn off Pstdma */
-		rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw,
+		rtl8723e_dm_bt_set_fw_ignore_wlan_act(hw,
 						      btdm->ignore_wlan_act);
 		/* Antenna control by PTA, 0x870 = 0x300. */
-		rtl8723ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0);
+		rtl8723e_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0);
 
 		/* turn on 2AntHid */
-		rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, true);
-		rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, true, true);
+		rtl8723e_dm_bt_set_fw_bt_hid_info(hw, true);
+		rtl8723e_dm_bt_set_fw_2_ant_hid(hw, true, true);
 	} else if (btdm->tdma_on) {
 		/* turn off 2AntHid */
-		rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, false);
-		rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, false, false);
+		rtl8723e_dm_bt_set_fw_bt_hid_info(hw, false);
+		rtl8723e_dm_bt_set_fw_2_ant_hid(hw, false, false);
 
 		/* turn off pstdma */
-		rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw,
+		rtl8723e_dm_bt_set_fw_ignore_wlan_act(hw,
 						      btdm->ignore_wlan_act);
 		/* Antenna control by PTA, 0x870 = 0x300. */
-		rtl8723ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0);
+		rtl8723e_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0);
 
 		/* turn on tdma */
-		rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on,
-				 btdm->tra_tdma_ant, btdm->tra_tdma_nav);
-		rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, true, btdm->tdma_ant,
-				 btdm->tdma_nav, btdm->tdma_dac_swing);
+		rtl8723e_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on,
+						    btdm->tra_tdma_ant,
+						    btdm->tra_tdma_nav);
+		rtl8723e_dm_bt_set_fw_tdma_ctrl(hw, true, btdm->tdma_ant,
+						btdm->tdma_nav,
+						btdm->tdma_dac_swing);
 	} else if (btdm->ps_tdma_on) {
 		/* turn off 2AntHid */
-		rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, false);
-		rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, false, false);
+		rtl8723e_dm_bt_set_fw_bt_hid_info(hw, false);
+		rtl8723e_dm_bt_set_fw_2_ant_hid(hw, false, false);
 
 		/* turn off tdma */
-		rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on,
-				 btdm->tra_tdma_ant, btdm->tra_tdma_nav);
-		rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, false, btdm->tdma_ant,
-				 btdm->tdma_nav, btdm->tdma_dac_swing);
+		rtl8723e_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on,
+						    btdm->tra_tdma_ant,
+						    btdm->tra_tdma_nav);
+		rtl8723e_dm_bt_set_fw_tdma_ctrl(hw, false, btdm->tdma_ant,
+						btdm->tdma_nav,
+						btdm->tdma_dac_swing);
 
 		/* turn on pstdma */
-		rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw,
-				 btdm->ignore_wlan_act);
-		rtl8723ae_dm_bt_set_fw_3a(hw,
-			btdm->ps_tdma_byte[0],
-			btdm->ps_tdma_byte[1],
-			btdm->ps_tdma_byte[2],
-			btdm->ps_tdma_byte[3],
-			btdm->ps_tdma_byte[4]);
+		rtl8723e_dm_bt_set_fw_ignore_wlan_act(hw,
+						      btdm->ignore_wlan_act);
+		rtl8723e_dm_bt_set_fw_3a(hw, btdm->ps_tdma_byte[0],
+					 btdm->ps_tdma_byte[1],
+					 btdm->ps_tdma_byte[2],
+					 btdm->ps_tdma_byte[3],
+					 btdm->ps_tdma_byte[4]);
 	} else {
 		/* turn off 2AntHid */
-		rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, false);
-		rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, false, false);
+		rtl8723e_dm_bt_set_fw_bt_hid_info(hw, false);
+		rtl8723e_dm_bt_set_fw_2_ant_hid(hw, false, false);
 
 		/* turn off tdma */
-		rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on,
-				 btdm->tra_tdma_ant, btdm->tra_tdma_nav);
-		rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, false, btdm->tdma_ant,
-				 btdm->tdma_nav, btdm->tdma_dac_swing);
+		rtl8723e_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on,
+						    btdm->tra_tdma_ant,
+						    btdm->tra_tdma_nav);
+		rtl8723e_dm_bt_set_fw_tdma_ctrl(hw, false, btdm->tdma_ant,
+						btdm->tdma_nav,
+						btdm->tdma_dac_swing);
 
 		/* turn off pstdma */
-		rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw,
-						      btdm->ignore_wlan_act);
+		rtl8723e_dm_bt_set_fw_ignore_wlan_act(hw,
+						btdm->ignore_wlan_act);
 		/* Antenna control by PTA, 0x870 = 0x300. */
-		rtl8723ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0);
+		rtl8723e_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0);
 	}
 
 	/* Note:
-	 * We should add delay for making sure sw DacSwing can be set
-	 *  sucessfully. Because of that rtl8723ae_dm_bt_set_fw_2_ant_hid()
-	 * and rtl8723ae_dm_bt_set_fw_tdma_ctrl()
+	 * We should add delay for making sure
+	 *	sw DacSwing can be set sucessfully.
+	 * because of that rtl8723e_dm_bt_set_fw_2_ant_hid()
+	 *	and rtl8723e_dm_bt_set_fw_tdma_ctrl()
 	 * will overwrite the reg 0x880.
 	*/
 	mdelay(30);
-	rtl8723ae_dm_bt_set_sw_full_time_dac_swing(hw,
-		btdm->sw_dac_swing_on, btdm->sw_dac_swing_lvl);
-	rtl8723ae_dm_bt_set_fw_dec_bt_pwr(hw, btdm->dec_bt_pwr);
+	rtl8723e_dm_bt_set_sw_full_time_dac_swing(hw, btdm->sw_dac_swing_on,
+						  btdm->sw_dac_swing_lvl);
+	rtl8723e_dm_bt_set_fw_dec_bt_pwr(hw, btdm->dec_bt_pwr);
 }
 
-/*============================================================
- * extern function start with BTDM_
- *============================================================
+/* ============================================================ */
+/* extern function start with BTDM_ */
+/* ============================================================i
  */
-static u32 rtl8723ae_dm_bt_tx_rx_couter_h(struct ieee80211_hw *hw)
+static u32 rtl8723e_dm_bt_tx_rx_couter_h(struct ieee80211_hw *hw)
 {
-	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	u32 counters = 0;
+	u32	counters = 0;
 
-	counters = rtlhal->hal_coex_8723.high_priority_tx +
-		   rtlhal->hal_coex_8723.high_priority_rx;
+	counters = hal_coex_8723.high_priority_tx +
+			hal_coex_8723.high_priority_rx;
 	return counters;
 }
 
-static u32 rtl8723ae_dm_bt_tx_rx_couter_l(struct ieee80211_hw *hw)
+static u32 rtl8723e_dm_bt_tx_rx_couter_l(struct ieee80211_hw *hw)
 {
-	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u32 counters = 0;
 
-	return rtlhal->hal_coex_8723.low_priority_tx +
-	       rtlhal->hal_coex_8723.low_priority_rx;
+	counters = hal_coex_8723.low_priority_tx +
+			hal_coex_8723.low_priority_rx;
+	return counters;
 }
 
-static u8 rtl8723ae_dm_bt_bt_tx_rx_counter_level(struct ieee80211_hw *hw)
+static u8 rtl8723e_dm_bt_bt_tx_rx_counter_level(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
-	u32 bt_tx_rx_cnt = 0;
-	u8 bt_tx_rx_cnt_lvl = 0;
+	u32	bt_tx_rx_cnt = 0;
+	u8	bt_tx_rx_cnt_lvl = 0;
 
-	bt_tx_rx_cnt = rtl8723ae_dm_bt_tx_rx_couter_h(hw) +
-		       rtl8723ae_dm_bt_tx_rx_couter_l(hw);
+	bt_tx_rx_cnt = rtl8723e_dm_bt_tx_rx_couter_h(hw)
+				+ rtl8723e_dm_bt_tx_rx_couter_l(hw);
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 		 "[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt);
 
-	rtlpcipriv->bt_coexist.cstate_h &=
-		 ~(BT_COEX_STATE_BT_CNT_LEVEL_0 | BT_COEX_STATE_BT_CNT_LEVEL_1 |
+	rtlpriv->btcoexist.cstate_h &= ~
+		 (BT_COEX_STATE_BT_CNT_LEVEL_0 | BT_COEX_STATE_BT_CNT_LEVEL_1|
 		  BT_COEX_STATE_BT_CNT_LEVEL_2);
 
 	if (bt_tx_rx_cnt >= BT_TXRX_CNT_THRES_3) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 			 "[BTCoex], BT TxRx Counters at level 3\n");
 		bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_3;
-		rtlpcipriv->bt_coexist.cstate_h |= BT_COEX_STATE_BT_CNT_LEVEL_3;
+		rtlpriv->btcoexist.cstate_h |=
+			BT_COEX_STATE_BT_CNT_LEVEL_3;
 	} else if (bt_tx_rx_cnt >= BT_TXRX_CNT_THRES_2) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 			 "[BTCoex], BT TxRx Counters at level 2\n");
 		bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_2;
-		rtlpcipriv->bt_coexist.cstate_h |= BT_COEX_STATE_BT_CNT_LEVEL_2;
+		rtlpriv->btcoexist.cstate_h |=
+			BT_COEX_STATE_BT_CNT_LEVEL_2;
 	} else if (bt_tx_rx_cnt >= BT_TXRX_CNT_THRES_1) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 			 "[BTCoex], BT TxRx Counters at level 1\n");
 		bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_1;
-		rtlpcipriv->bt_coexist.cstate_h |= BT_COEX_STATE_BT_CNT_LEVEL_1;
+		rtlpriv->btcoexist.cstate_h  |=
+			BT_COEX_STATE_BT_CNT_LEVEL_1;
 	} else {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 			 "[BTCoex], BT TxRx Counters at level 0\n");
 		bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_0;
-		rtlpcipriv->bt_coexist.cstate_h |= BT_COEX_STATE_BT_CNT_LEVEL_0;
+		rtlpriv->btcoexist.cstate_h |=
+			BT_COEX_STATE_BT_CNT_LEVEL_0;
 	}
 	return bt_tx_rx_cnt_lvl;
 }
 
-static void rtl8723ae_dm_bt_2_ant_hid_sco_esco(struct ieee80211_hw *hw)
+static void rtl8723e_dm_bt_2_ant_hid_sco_esco(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct btdm_8723 btdm8723;
 	u8 bt_rssi_state, bt_rssi_state1;
-	u8 bt_tx_rx_cnt_lvl;
+	u8	bt_tx_rx_cnt_lvl = 0;
 
-	rtl8723ae_dm_bt_btdm_structure_reload(hw, &btdm8723);
+	rtl8723e_dm_bt_btdm_structure_reload(hw, &btdm8723);
 
 	btdm8723.rf_rx_lpf_shrink = true;
 	btdm8723.low_penalty_rate_adaptive = true;
 	btdm8723.reject_aggre_pkt = false;
 
-	bt_tx_rx_cnt_lvl = rtl8723ae_dm_bt_bt_tx_rx_counter_level(hw);
+	bt_tx_rx_cnt_lvl = rtl8723e_dm_bt_bt_tx_rx_counter_level(hw);
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 		 "[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt_lvl);
 
@@ -1051,10 +1045,10 @@
 	} else {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 			 "HT20 or Legacy\n");
-		bt_rssi_state = rtl8723ae_dm_bt_check_coex_rssi_state(hw, 2,
-								     47, 0);
-		bt_rssi_state1 = rtl8723ae_dm_bt_check_coex_rssi_state1(hw, 2,
-								       27, 0);
+		bt_rssi_state =
+		  rtl8723e_dm_bt_check_coex_rssi_state(hw, 2, 47, 0);
+		bt_rssi_state1 =
+		  rtl8723e_dm_bt_check_coex_rssi_state1(hw, 2, 27, 0);
 
 		/* coex table */
 		btdm8723.val_0x6c0 = 0x55555555;
@@ -1063,15 +1057,15 @@
 
 		/* sw mechanism */
 		if ((bt_rssi_state == BT_RSSI_STATE_HIGH) ||
-		    (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH)) {
+			(bt_rssi_state == BT_RSSI_STATE_STAY_HIGH)) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-				 "Wifi rssi high\n");
+					"Wifi rssi high\n");
 			btdm8723.agc_table_en = true;
 			btdm8723.adc_back_off_on = true;
 			btdm8723.sw_dac_swing_on = false;
 		} else {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-				 "Wifi rssi low\n");
+					"Wifi rssi low\n");
 			btdm8723.agc_table_en = false;
 			btdm8723.adc_back_off_on = false;
 			btdm8723.sw_dac_swing_on = false;
@@ -1080,16 +1074,15 @@
 		/* fw mechanism */
 		btdm8723.ps_tdma_on = true;
 		if ((bt_rssi_state1 == BT_RSSI_STATE_HIGH) ||
-		    (bt_rssi_state1 == BT_RSSI_STATE_STAY_HIGH)) {
+			(bt_rssi_state1 == BT_RSSI_STATE_STAY_HIGH)) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 				 "Wifi rssi-1 high\n");
-			/* only rssi high we need to do this,
-			 * when rssi low, the value will modified by fw
-			 */
+			/* only rssi high we need to do this, */
+			/* when rssi low, the value will modified by fw */
 			rtl_write_byte(rtlpriv, 0x883, 0x40);
 			if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) {
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-					 "[BTCoex], BT TxRx Counters >= 1400\n");
+				"[BTCoex], BT TxRx Counters >= 1400\n");
 				btdm8723.ps_tdma_byte[0] = 0xa3;
 				btdm8723.ps_tdma_byte[1] = 0x5;
 				btdm8723.ps_tdma_byte[2] = 0x5;
@@ -1097,7 +1090,7 @@
 				btdm8723.ps_tdma_byte[4] = 0x80;
 			} else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) {
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-					 "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n");
+					 "[BTCoex], BT TxRx Counters>= 1200 && < 1400\n");
 				btdm8723.ps_tdma_byte[0] = 0xa3;
 				btdm8723.ps_tdma_byte[1] = 0xa;
 				btdm8723.ps_tdma_byte[2] = 0xa;
@@ -1114,7 +1107,7 @@
 			}
 		} else {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-				 "Wifi rssi-1 low\n");
+					"Wifi rssi-1 low\n");
 			if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) {
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 					 "[BTCoex], BT TxRx Counters >= 1400\n");
@@ -1143,16 +1136,15 @@
 		}
 	}
 
-	if (rtl8723ae_dm_bt_need_to_dec_bt_pwr(hw))
+	if (rtl8723e_dm_bt_need_to_dec_bt_pwr(hw))
 		btdm8723.dec_bt_pwr = true;
 
 	/* Always ignore WlanAct if bHid|bSCOBusy|bSCOeSCO */
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 		 "[BTCoex], BT btInqPageStartTime = 0x%x, btTxRxCntLvl = %d\n",
-		 rtlhal->hal_coex_8723.bt_inq_page_start_time,
-		 bt_tx_rx_cnt_lvl);
-	if ((rtlhal->hal_coex_8723.bt_inq_page_start_time) ||
+		 hal_coex_8723.bt_inq_page_start_time, bt_tx_rx_cnt_lvl);
+	if ((hal_coex_8723.bt_inq_page_start_time) ||
 	    (BT_TXRX_CNT_LEVEL_3 == bt_tx_rx_cnt_lvl)) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 			 "[BTCoex], Set BT inquiry / page scan 0x3a setting\n");
@@ -1164,33 +1156,35 @@
 		btdm8723.ps_tdma_byte[4] = 0x80;
 	}
 
-	if (rtl8723ae_dm_bt_is_coexist_state_changed(hw))
-		rtl8723ae_dm_bt_set_bt_dm(hw, &btdm8723);
+	if (rtl8723e_dm_bt_is_coexist_state_changed(hw))
+		rtl8723e_dm_bt_set_bt_dm(hw, &btdm8723);
+
 }
 
-static void rtl8723ae_dm_bt_2_ant_fta2dp(struct ieee80211_hw *hw)
+static void rtl8723e_dm_bt_2_ant_ftp_a2dp(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct btdm_8723 btdm8723;
-	u8 bt_rssi_state, bt_rssi_state1;
-	u32 bt_tx_rx_cnt_lvl;
 
-	rtl8723ae_dm_bt_btdm_structure_reload(hw, &btdm8723);
+	u8 bt_rssi_state, bt_rssi_state1;
+	u32 bt_tx_rx_cnt_lvl = 0;
+
+	rtl8723e_dm_bt_btdm_structure_reload(hw, &btdm8723);
+
 	btdm8723.rf_rx_lpf_shrink = true;
 	btdm8723.low_penalty_rate_adaptive = true;
 	btdm8723.reject_aggre_pkt = false;
 
-	bt_tx_rx_cnt_lvl = rtl8723ae_dm_bt_bt_tx_rx_counter_level(hw);
+	bt_tx_rx_cnt_lvl = rtl8723e_dm_bt_bt_tx_rx_counter_level(hw);
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-		 "[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt_lvl);
+	"[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt_lvl);
 
 	if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, "HT40\n");
-		bt_rssi_state = rtl8723ae_dm_bt_check_coex_rssi_state(hw, 2,
-								     37, 0);
+		bt_rssi_state =
+		  rtl8723e_dm_bt_check_coex_rssi_state(hw, 2, 37, 0);
 
 		/* coex table */
 		btdm8723.val_0x6c0 = 0x55555555;
@@ -1205,12 +1199,12 @@
 		/* fw mechanism */
 		btdm8723.ps_tdma_on = true;
 		if ((bt_rssi_state == BT_RSSI_STATE_HIGH) ||
-		    (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH)) {
+			(bt_rssi_state == BT_RSSI_STATE_STAY_HIGH)) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-				 "Wifi rssi high\n");
+						"Wifi rssi high\n");
 			if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) {
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-					 "[BTCoex], BT TxRx Counters >= 1400\n");
+				"[BTCoex], BT TxRx Counters >= 1400\n");
 				btdm8723.ps_tdma_byte[0] = 0xa3;
 				btdm8723.ps_tdma_byte[1] = 0x5;
 				btdm8723.ps_tdma_byte[2] = 0x5;
@@ -1244,7 +1238,8 @@
 				btdm8723.ps_tdma_byte[2] = 0x5;
 				btdm8723.ps_tdma_byte[3] = 0x0;
 				btdm8723.ps_tdma_byte[4] = 0x80;
-			} else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) {
+			} else if (bt_tx_rx_cnt_lvl ==
+				BT_TXRX_CNT_LEVEL_1) {
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 					 "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n");
 				btdm8723.ps_tdma_byte[0] = 0xa3;
@@ -1265,10 +1260,10 @@
 	} else {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 			 "HT20 or Legacy\n");
-		bt_rssi_state = rtl8723ae_dm_bt_check_coex_rssi_state(hw, 2,
-								     47, 0);
-		bt_rssi_state1 = rtl8723ae_dm_bt_check_coex_rssi_state1(hw, 2,
-								       27, 0);
+		bt_rssi_state =
+		  rtl8723e_dm_bt_check_coex_rssi_state(hw, 2, 47, 0);
+		bt_rssi_state1 =
+		  rtl8723e_dm_bt_check_coex_rssi_state1(hw, 2, 27, 0);
 
 		/* coex table */
 		btdm8723.val_0x6c0 = 0x55555555;
@@ -1277,7 +1272,7 @@
 
 		/* sw mechanism */
 		if ((bt_rssi_state == BT_RSSI_STATE_HIGH) ||
-		    (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH)) {
+			(bt_rssi_state == BT_RSSI_STATE_STAY_HIGH)) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 				 "Wifi rssi high\n");
 			btdm8723.agc_table_en = true;
@@ -1294,12 +1289,11 @@
 		/* fw mechanism */
 		btdm8723.ps_tdma_on = true;
 		if ((bt_rssi_state1 == BT_RSSI_STATE_HIGH) ||
-		    (bt_rssi_state1 == BT_RSSI_STATE_STAY_HIGH)) {
+			(bt_rssi_state1 == BT_RSSI_STATE_STAY_HIGH)) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 				 "Wifi rssi-1 high\n");
-			/* only rssi high we need to do this,
-			 * when rssi low, the value will modified by fw
-			 */
+			/* only rssi high we need to do this, */
+			/* when rssi low, the value will modified by fw */
 			rtl_write_byte(rtlpriv, 0x883, 0x40);
 			if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) {
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
@@ -1357,15 +1351,14 @@
 		}
 	}
 
-	if (rtl8723ae_dm_bt_need_to_dec_bt_pwr(hw))
+	if (rtl8723e_dm_bt_need_to_dec_bt_pwr(hw))
 		btdm8723.dec_bt_pwr = true;
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 		 "[BTCoex], BT btInqPageStartTime = 0x%x, btTxRxCntLvl = %d\n",
-		 rtlhal->hal_coex_8723.bt_inq_page_start_time,
-		 bt_tx_rx_cnt_lvl);
+		 hal_coex_8723.bt_inq_page_start_time, bt_tx_rx_cnt_lvl);
 
-	if ((rtlhal->hal_coex_8723.bt_inq_page_start_time) ||
+	if ((hal_coex_8723.bt_inq_page_start_time) ||
 	    (BT_TXRX_CNT_LEVEL_3 == bt_tx_rx_cnt_lvl)) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 			 "[BTCoex], Set BT inquiry / page scan 0x3a setting\n");
@@ -1377,379 +1370,373 @@
 		btdm8723.ps_tdma_byte[4] = 0x80;
 	}
 
-	if (rtl8723ae_dm_bt_is_coexist_state_changed(hw))
-		rtl8723ae_dm_bt_set_bt_dm(hw, &btdm8723);
+	if (rtl8723e_dm_bt_is_coexist_state_changed(hw))
+		rtl8723e_dm_bt_set_bt_dm(hw, &btdm8723);
+
 }
 
-static void rtl8723ae_dm_bt_inq_page_monitor(struct ieee80211_hw *hw)
+static void rtl8723e_dm_bt_inq_page_monitor(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-	u32 cur_time = jiffies;
+	u32 cur_time;
 
-	if (rtlhal->hal_coex_8723.c2h_bt_inquiry_page) {
+	cur_time = jiffies;
+	if (hal_coex_8723.c2h_bt_inquiry_page) {
 		/* bt inquiry or page is started. */
-		if (rtlhal->hal_coex_8723.bt_inq_page_start_time == 0) {
-			rtlpcipriv->bt_coexist.cstate |=
-					 BT_COEX_STATE_BT_INQ_PAGE;
-			rtlhal->hal_coex_8723.bt_inq_page_start_time = cur_time;
+		if (hal_coex_8723.bt_inq_page_start_time == 0) {
+			rtlpriv->btcoexist.cstate  |=
+			BT_COEX_STATE_BT_INQ_PAGE;
+			hal_coex_8723.bt_inq_page_start_time = cur_time;
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 				 "[BTCoex], BT Inquiry/page is started at time : 0x%x\n",
-				 rtlhal->hal_coex_8723.bt_inq_page_start_time);
+				 hal_coex_8723.bt_inq_page_start_time);
 		}
 	}
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 		 "[BTCoex], BT Inquiry/page started time : 0x%x, cur_time : 0x%x\n",
-		 rtlhal->hal_coex_8723.bt_inq_page_start_time, cur_time);
+		 hal_coex_8723.bt_inq_page_start_time, cur_time);
 
-	if (rtlhal->hal_coex_8723.bt_inq_page_start_time) {
+	if (hal_coex_8723.bt_inq_page_start_time) {
 		if ((((long)cur_time -
-		    (long)rtlhal->hal_coex_8723.bt_inq_page_start_time) / HZ) >=
-		    10) {
+			(long)hal_coex_8723.bt_inq_page_start_time) / HZ)
+			>= 10) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-				 "[BTCoex], BT Inquiry/page >= 10sec!!!");
-			rtlhal->hal_coex_8723.bt_inq_page_start_time = 0;
-			rtlpcipriv->bt_coexist.cstate &=
-						 ~BT_COEX_STATE_BT_INQ_PAGE;
+				"[BTCoex], BT Inquiry/page >= 10sec!!!");
+			hal_coex_8723.bt_inq_page_start_time = 0;
+			rtlpriv->btcoexist.cstate &=
+				~BT_COEX_STATE_BT_INQ_PAGE;
 		}
 	}
 }
 
-static void rtl8723ae_dm_bt_reset_action_profile_state(struct ieee80211_hw *hw)
+static void rtl8723e_dm_bt_reset_action_profile_state(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-	rtlpcipriv->bt_coexist.cstate &=
-		~(BT_COEX_STATE_PROFILE_HID | BT_COEX_STATE_PROFILE_A2DP |
+	rtlpriv->btcoexist.cstate &= ~
+		(BT_COEX_STATE_PROFILE_HID | BT_COEX_STATE_PROFILE_A2DP|
 		BT_COEX_STATE_PROFILE_PAN | BT_COEX_STATE_PROFILE_SCO);
 
-	rtlpcipriv->bt_coexist.cstate &=
-		~(BT_COEX_STATE_BTINFO_COMMON |
-		BT_COEX_STATE_BTINFO_B_HID_SCOESCO |
+	rtlpriv->btcoexist.cstate &= ~
+		(BT_COEX_STATE_BTINFO_COMMON |
+		BT_COEX_STATE_BTINFO_B_HID_SCOESCO|
 		BT_COEX_STATE_BTINFO_B_FTP_A2DP);
 }
 
-static void _rtl8723ae_dm_bt_coexist_2_ant(struct ieee80211_hw *hw)
+static void _rtl8723e_dm_bt_coexist_2_ant(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+	u8 bt_retry_cnt;
 	u8 bt_info_original;
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-		 "[BTCoex] Get bt info by fw!!\n");
+		"[BTCoex] Get bt info by fw!!\n");
 
 	_rtl8723_dm_bt_check_wifi_state(hw);
 
-	if (rtlhal->hal_coex_8723.c2h_bt_info_req_sent) {
+	if (hal_coex_8723.c2h_bt_info_req_sent) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "[BTCoex] c2h for btInfo not rcvd yet!!\n");
+				"[BTCoex] c2h for bt_info not rcvd yet!!\n");
 	}
 
-	bt_info_original = rtlhal->hal_coex_8723.c2h_bt_info_original;
+	bt_retry_cnt = hal_coex_8723.bt_retry_cnt;
+	bt_info_original = hal_coex_8723.c2h_bt_info_original;
 
-	/* when bt inquiry or page scan, we have to set h2c 0x25
-	 * ignore wlanact for continuous 4x2secs
-	 */
-	rtl8723ae_dm_bt_inq_page_monitor(hw);
-	rtl8723ae_dm_bt_reset_action_profile_state(hw);
+	/* when bt inquiry or page scan, we have to set h2c 0x25 */
+	/* ignore wlanact for continuous 4x2secs */
+	rtl8723e_dm_bt_inq_page_monitor(hw);
+	rtl8723e_dm_bt_reset_action_profile_state(hw);
 
-	if (rtl8723ae_dm_bt_is_2_ant_common_action(hw)) {
-		rtlpcipriv->bt_coexist.bt_profile_case = BT_COEX_MECH_COMMON;
-		rtlpcipriv->bt_coexist.bt_profile_action = BT_COEX_MECH_COMMON;
-
+	if (rtl8723e_dm_bt_is_2_ant_common_action(hw)) {
+		rtlpriv->btcoexist.bt_profile_case = BT_COEX_MECH_COMMON;
+		rtlpriv->btcoexist.bt_profile_action = BT_COEX_MECH_COMMON;
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "Action 2-Ant common.\n");
+		"Action 2-Ant common.\n");
 	} else {
 		if ((bt_info_original & BTINFO_B_HID) ||
-		    (bt_info_original & BTINFO_B_SCO_BUSY) ||
-		    (bt_info_original & BTINFO_B_SCO_ESCO)) {
-			rtlpcipriv->bt_coexist.cstate |=
+			(bt_info_original & BTINFO_B_SCO_BUSY) ||
+			(bt_info_original & BTINFO_B_SCO_ESCO)) {
+				rtlpriv->btcoexist.cstate |=
 					BT_COEX_STATE_BTINFO_B_HID_SCOESCO;
-			rtlpcipriv->bt_coexist.bt_profile_case =
+				rtlpriv->btcoexist.bt_profile_case =
 					BT_COEX_MECH_HID_SCO_ESCO;
-			rtlpcipriv->bt_coexist.bt_profile_action =
+				rtlpriv->btcoexist.bt_profile_action =
 					BT_COEX_MECH_HID_SCO_ESCO;
-			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-				 "[BTCoex], BTInfo: bHid|bSCOBusy|bSCOeSCO\n");
-			rtl8723ae_dm_bt_2_ant_hid_sco_esco(hw);
+				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+					 "[BTCoex], BTInfo: bHid|bSCOBusy|bSCOeSCO\n");
+				rtl8723e_dm_bt_2_ant_hid_sco_esco(hw);
 		} else if ((bt_info_original & BTINFO_B_FTP) ||
-			   (bt_info_original & BTINFO_B_A2DP)) {
-			rtlpcipriv->bt_coexist.cstate |=
+				(bt_info_original & BTINFO_B_A2DP)) {
+				rtlpriv->btcoexist.cstate |=
 					BT_COEX_STATE_BTINFO_B_FTP_A2DP;
-			rtlpcipriv->bt_coexist.bt_profile_case =
+				rtlpriv->btcoexist.bt_profile_case =
 					BT_COEX_MECH_FTP_A2DP;
-			rtlpcipriv->bt_coexist.bt_profile_action =
+				rtlpriv->btcoexist.bt_profile_action =
 					BT_COEX_MECH_FTP_A2DP;
-			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-				 "BTInfo: bFTP|bA2DP\n");
-			rtl8723ae_dm_bt_2_ant_fta2dp(hw);
+				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+					 "BTInfo: bFTP|bA2DP\n");
+				rtl8723e_dm_bt_2_ant_ftp_a2dp(hw);
 		} else {
-			rtlpcipriv->bt_coexist.cstate |=
-					 BT_COEX_STATE_BTINFO_B_HID_SCOESCO;
-			rtlpcipriv->bt_coexist.bt_profile_case =
-					 BT_COEX_MECH_NONE;
-			rtlpcipriv->bt_coexist.bt_profile_action =
-					 BT_COEX_MECH_NONE;
-			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-				 "[BTCoex], BTInfo: undefined case!!!!\n");
-			rtl8723ae_dm_bt_2_ant_hid_sco_esco(hw);
+				rtlpriv->btcoexist.cstate |=
+					BT_COEX_STATE_BTINFO_B_HID_SCOESCO;
+				rtlpriv->btcoexist.bt_profile_case =
+					BT_COEX_MECH_NONE;
+				rtlpriv->btcoexist.bt_profile_action =
+					BT_COEX_MECH_NONE;
+				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+					 "[BTCoex], BTInfo: undefined case!!!!\n");
+				rtl8723e_dm_bt_2_ant_hid_sco_esco(hw);
 		}
 	}
 }
 
-static void _rtl8723ae_dm_bt_coexist_1_ant(struct ieee80211_hw *hw)
+static void _rtl8723e_dm_bt_coexist_1_ant(struct ieee80211_hw *hw)
 {
+	return;
 }
 
-void rtl8723ae_dm_bt_hw_coex_all_off_8723a(struct ieee80211_hw *hw)
+void rtl8723e_dm_bt_hw_coex_all_off_8723a(struct ieee80211_hw *hw)
 {
-	rtl8723ae_dm_bt_set_coex_table(hw, 0x5a5aaaaa, 0xcc, 0x3);
-	rtl8723ae_dm_bt_set_hw_pta_mode(hw, true);
+	rtl8723e_dm_bt_set_coex_table(hw, 0x5a5aaaaa, 0xcc, 0x3);
+	rtl8723e_dm_bt_set_hw_pta_mode(hw, true);
 }
 
-void rtl8723ae_dm_bt_fw_coex_all_off_8723a(struct ieee80211_hw *hw)
+void rtl8723e_dm_bt_fw_coex_all_off_8723a(struct ieee80211_hw *hw)
 {
-	rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw, false);
-	rtl8723ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0);
-	rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, false, false);
-	rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, false,
-					     TDMA_2ANT, TDMA_NAV_OFF);
-	rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, false, TDMA_2ANT,
-				TDMA_NAV_OFF, TDMA_DAC_SWING_OFF);
-	rtl8723ae_dm_bt_set_fw_dac_swing_level(hw, 0);
-	rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, false);
-	rtl8723ae_dm_bt_set_fw_bt_retry_index(hw, 2);
-	rtl8723ae_dm_bt_set_fw_wlan_act(hw, 0x10, 0x10);
-	rtl8723ae_dm_bt_set_fw_dec_bt_pwr(hw, false);
+	rtl8723e_dm_bt_set_fw_ignore_wlan_act(hw, false);
+	rtl8723e_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0);
+	rtl8723e_dm_bt_set_fw_2_ant_hid(hw, false, false);
+	rtl8723e_dm_bt_set_fw_tra_tdma_ctrl(hw, false, TDMA_2ANT,
+					    TDMA_NAV_OFF);
+	rtl8723e_dm_bt_set_fw_tdma_ctrl(hw, false, TDMA_2ANT, TDMA_NAV_OFF,
+					TDMA_DAC_SWING_OFF);
+	rtl8723e_dm_bt_set_fw_dac_swing_level(hw, 0);
+	rtl8723e_dm_bt_set_fw_bt_hid_info(hw, false);
+	rtl8723e_dm_bt_set_fw_bt_retry_index(hw, 2);
+	rtl8723e_dm_bt_set_fw_wlan_act(hw, 0x10, 0x10);
+	rtl8723e_dm_bt_set_fw_dec_bt_pwr(hw, false);
 }
 
-void rtl8723ae_dm_bt_sw_coex_all_off_8723a(struct ieee80211_hw *hw)
+void rtl8723e_dm_bt_sw_coex_all_off_8723a(struct ieee80211_hw *hw)
 {
-	rtl8723ae_dm_bt_agc_table(hw, BT_AGCTABLE_OFF);
-	rtl8723ae_dm_bt_bback_off_level(hw, BT_BB_BACKOFF_OFF);
-	rtl8723ae_dm_bt_reject_ap_aggregated_packet(hw, false);
+	rtl8723e_dm_bt_agc_table(hw, BT_AGCTABLE_OFF);
+	rtl8723e_dm_bt_bb_back_off_level(hw, BT_BB_BACKOFF_OFF);
+	rtl8723e_dm_bt_reject_ap_aggregated_packet(hw, false);
 
-	rtl8723ae_bt_set_penalty_tx_rate_adap(hw, BT_TX_RATE_ADAPTIVE_NORMAL);
-	rtl8723ae_dm_bt_set_sw_rf_rx_lpf_corner(hw, BT_RF_RX_LPF_CORNER_RESUME);
-	rtl8723ae_dm_bt_set_sw_full_time_dac_swing(hw, false, 0xc0);
+	dm_bt_set_sw_penalty_tx_rate_adapt(hw, BT_TX_RATE_ADAPTIVE_NORMAL);
+	rtl8723e_dm_bt_set_sw_rf_rx_lpf_corner(hw, BT_RF_RX_LPF_CORNER_RESUME);
+	rtl8723e_dm_bt_set_sw_full_time_dac_swing(hw, false, 0xc0);
 }
 
-static void rtl8723ae_dm_bt_query_bt_information(struct ieee80211_hw *hw)
+static void rtl8723e_dm_bt_query_bt_information(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	u8 h2c_parameter[1] = {0};
 
-	rtlhal->hal_coex_8723.c2h_bt_info_req_sent = true;
+	hal_coex_8723.c2h_bt_info_req_sent = true;
 
 	h2c_parameter[0] |=  BIT(0);
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-		 "Query Bt information, write 0x38 = 0x%x\n",
-		 h2c_parameter[0]);
+		"Query Bt information, write 0x38=0x%x\n", h2c_parameter[0]);
 
-	rtl8723ae_fill_h2c_cmd(hw, 0x38, 1, h2c_parameter);
+	rtl8723e_fill_h2c_cmd(hw, 0x38, 1, h2c_parameter);
 }
 
-static void rtl8723ae_dm_bt_bt_hw_counters_monitor(struct ieee80211_hw *hw)
+static void rtl8723e_dm_bt_bt_hw_counters_monitor(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
-	u32 reg_htx_rx, reg_ltx_rx, u32_tmp;
-	u32 reg_htx, reg_hrx, reg_ltx, reg_lrx;
+	u32 reg_hp_tx_rx, reg_lp_tx_rx, u32_tmp;
+	u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0;
 
-	reg_htx_rx = REG_HIGH_PRIORITY_TXRX;
-	reg_ltx_rx = REG_LOW_PRIORITY_TXRX;
+	reg_hp_tx_rx = REG_HIGH_PRIORITY_TXRX;
+	reg_lp_tx_rx = REG_LOW_PRIORITY_TXRX;
 
-	u32_tmp = rtl_read_dword(rtlpriv, reg_htx_rx);
-	reg_htx = u32_tmp & MASKLWORD;
-	reg_hrx = (u32_tmp & MASKHWORD)>>16;
+	u32_tmp = rtl_read_dword(rtlpriv, reg_hp_tx_rx);
+	reg_hp_tx = u32_tmp & MASKLWORD;
+	reg_hp_rx = (u32_tmp & MASKHWORD)>>16;
 
-	u32_tmp = rtl_read_dword(rtlpriv, reg_ltx_rx);
-	reg_ltx = u32_tmp & MASKLWORD;
-	reg_lrx = (u32_tmp & MASKHWORD)>>16;
+	u32_tmp = rtl_read_dword(rtlpriv, reg_lp_tx_rx);
+	reg_lp_tx = u32_tmp & MASKLWORD;
+	reg_lp_rx = (u32_tmp & MASKHWORD)>>16;
 
-	if (rtlpcipriv->bt_coexist.lps_counter > 1) {
-		reg_htx %= rtlpcipriv->bt_coexist.lps_counter;
-		reg_hrx %= rtlpcipriv->bt_coexist.lps_counter;
-		reg_ltx %= rtlpcipriv->bt_coexist.lps_counter;
-		reg_lrx %= rtlpcipriv->bt_coexist.lps_counter;
+	if (rtlpriv->btcoexist.lps_counter > 1) {
+		reg_hp_tx %= rtlpriv->btcoexist.lps_counter;
+		reg_hp_rx %= rtlpriv->btcoexist.lps_counter;
+		reg_lp_tx %= rtlpriv->btcoexist.lps_counter;
+		reg_lp_rx %= rtlpriv->btcoexist.lps_counter;
 	}
 
-	rtlhal->hal_coex_8723.high_priority_tx = reg_htx;
-	rtlhal->hal_coex_8723.high_priority_rx = reg_hrx;
-	rtlhal->hal_coex_8723.low_priority_tx = reg_ltx;
-	rtlhal->hal_coex_8723.low_priority_rx = reg_lrx;
+	hal_coex_8723.high_priority_tx = reg_hp_tx;
+	hal_coex_8723.high_priority_rx = reg_hp_rx;
+	hal_coex_8723.low_priority_tx = reg_lp_tx;
+	hal_coex_8723.low_priority_rx = reg_lp_rx;
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-		 "High Priority Tx/Rx (reg 0x%x)=%x(%d)/%x(%d)\n",
-		 reg_htx_rx, reg_htx, reg_htx, reg_hrx, reg_hrx);
+		"High Priority Tx/Rx (reg 0x%x)=%x(%d)/%x(%d)\n",
+		reg_hp_tx_rx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx);
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-		 "Low Priority Tx/Rx (reg 0x%x)=%x(%d)/%x(%d)\n",
-		 reg_ltx_rx, reg_ltx, reg_ltx, reg_lrx, reg_lrx);
-	rtlpcipriv->bt_coexist.lps_counter = 0;
+		"Low Priority Tx/Rx (reg 0x%x)=%x(%d)/%x(%d)\n",
+		reg_lp_tx_rx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx);
+	rtlpriv->btcoexist.lps_counter = 0;
+	/* rtl_write_byte(rtlpriv, 0x76e, 0xc); */
 }
 
-static void rtl8723ae_dm_bt_bt_enable_disable_check(struct ieee80211_hw *hw)
+static void rtl8723e_dm_bt_bt_enable_disable_check(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	bool bt_alife = true;
 
-	if (rtlhal->hal_coex_8723.high_priority_tx == 0 &&
-	    rtlhal->hal_coex_8723.high_priority_rx == 0 &&
-	    rtlhal->hal_coex_8723.low_priority_tx == 0 &&
-	    rtlhal->hal_coex_8723.low_priority_rx == 0)
+	if (hal_coex_8723.high_priority_tx == 0 &&
+	    hal_coex_8723.high_priority_rx == 0 &&
+	    hal_coex_8723.low_priority_tx == 0 &&
+	    hal_coex_8723.low_priority_rx == 0) {
 		bt_alife = false;
-	if (rtlhal->hal_coex_8723.high_priority_tx == 0xeaea &&
-	    rtlhal->hal_coex_8723.high_priority_rx == 0xeaea &&
-	    rtlhal->hal_coex_8723.low_priority_tx == 0xeaea &&
-	    rtlhal->hal_coex_8723.low_priority_rx == 0xeaea)
+	}
+	if (hal_coex_8723.high_priority_tx == 0xeaea &&
+	    hal_coex_8723.high_priority_rx == 0xeaea &&
+	    hal_coex_8723.low_priority_tx == 0xeaea &&
+	    hal_coex_8723.low_priority_rx == 0xeaea) {
 		bt_alife = false;
-	if (rtlhal->hal_coex_8723.high_priority_tx == 0xffff &&
-	    rtlhal->hal_coex_8723.high_priority_rx == 0xffff &&
-	    rtlhal->hal_coex_8723.low_priority_tx == 0xffff &&
-	    rtlhal->hal_coex_8723.low_priority_rx == 0xffff)
+	}
+	if (hal_coex_8723.high_priority_tx == 0xffff &&
+	    hal_coex_8723.high_priority_rx == 0xffff &&
+	    hal_coex_8723.low_priority_tx == 0xffff &&
+	    hal_coex_8723.low_priority_rx == 0xffff) {
 		bt_alife = false;
+	}
 	if (bt_alife) {
-		rtlpcipriv->bt_coexist.bt_active_zero_cnt = 0;
-		rtlpcipriv->bt_coexist.cur_bt_disabled = false;
+		rtlpriv->btcoexist.bt_active_zero_cnt = 0;
+		rtlpriv->btcoexist.cur_bt_disabled = false;
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 			 "8723A BT is enabled !!\n");
 	} else {
-		rtlpcipriv->bt_coexist.bt_active_zero_cnt++;
+		rtlpriv->btcoexist.bt_active_zero_cnt++;
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-			 "8723A bt all counters = 0, %d times!!\n",
-			 rtlpcipriv->bt_coexist.bt_active_zero_cnt);
-		if (rtlpcipriv->bt_coexist.bt_active_zero_cnt >= 2) {
-			rtlpcipriv->bt_coexist.cur_bt_disabled = true;
+			 "8723A bt all counters=0, %d times!!\n",
+			 rtlpriv->btcoexist.bt_active_zero_cnt);
+		if (rtlpriv->btcoexist.bt_active_zero_cnt >= 2) {
+			rtlpriv->btcoexist.cur_bt_disabled = true;
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 				 "8723A BT is disabled !!\n");
 		}
 	}
-	if (rtlpcipriv->bt_coexist.pre_bt_disabled !=
-		rtlpcipriv->bt_coexist.cur_bt_disabled) {
-		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-			 "8723A BT is from %s to %s!!\n",
-			 (rtlpcipriv->bt_coexist.pre_bt_disabled ?
-			 "disabled" : "enabled"),
-			 (rtlpcipriv->bt_coexist.cur_bt_disabled ?
-			 "disabled" : "enabled"));
-		rtlpcipriv->bt_coexist.pre_bt_disabled
-			= rtlpcipriv->bt_coexist.cur_bt_disabled;
+	if (rtlpriv->btcoexist.pre_bt_disabled !=
+		rtlpriv->btcoexist.cur_bt_disabled) {
+		RT_TRACE(rtlpriv, COMP_BT_COEXIST,
+			 DBG_TRACE, "8723A BT is from %s to %s!!\n",
+			 (rtlpriv->btcoexist.pre_bt_disabled ?
+				"disabled" : "enabled"),
+			 (rtlpriv->btcoexist.cur_bt_disabled ?
+				"disabled" : "enabled"));
+		rtlpriv->btcoexist.pre_bt_disabled
+			= rtlpriv->btcoexist.cur_bt_disabled;
 	}
 }
 
 
-void rtl8723ae_dm_bt_coexist_8723(struct ieee80211_hw *hw)
+void rtl8723e_dm_bt_coexist_8723(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 
-	rtl8723ae_dm_bt_query_bt_information(hw);
-	rtl8723ae_dm_bt_bt_hw_counters_monitor(hw);
-	rtl8723ae_dm_bt_bt_enable_disable_check(hw);
+	rtl8723e_dm_bt_query_bt_information(hw);
+	rtl8723e_dm_bt_bt_hw_counters_monitor(hw);
+	rtl8723e_dm_bt_bt_enable_disable_check(hw);
 
-	if (rtlpcipriv->bt_coexist.bt_ant_num == ANT_X2) {
+	if (rtlpriv->btcoexist.bt_ant_num == ANT_X2) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTCoex], 2 Ant mechanism\n");
-		_rtl8723ae_dm_bt_coexist_2_ant(hw);
+			"[BTCoex], 2 Ant mechanism\n");
+		_rtl8723e_dm_bt_coexist_2_ant(hw);
 	} else {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-			 "[BTCoex], 1 Ant mechanism\n");
-		_rtl8723ae_dm_bt_coexist_1_ant(hw);
+			"[BTCoex], 1 Ant mechanism\n");
+		_rtl8723e_dm_bt_coexist_1_ant(hw);
 	}
 
-	if (!rtl8723ae_dm_bt_is_same_coexist_state(hw)) {
+	if (!rtl8723e_dm_bt_is_same_coexist_state(hw)) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
 			 "[BTCoex], Coexist State[bitMap] change from 0x%x%8x to 0x%x%8x\n",
-			 rtlpcipriv->bt_coexist.previous_state_h,
-			 rtlpcipriv->bt_coexist.previous_state,
-			 rtlpcipriv->bt_coexist.cstate_h,
-			 rtlpcipriv->bt_coexist.cstate);
-		rtlpcipriv->bt_coexist.previous_state
-			= rtlpcipriv->bt_coexist.cstate;
-		rtlpcipriv->bt_coexist.previous_state_h
-			= rtlpcipriv->bt_coexist.cstate_h;
+			 rtlpriv->btcoexist.previous_state_h,
+			 rtlpriv->btcoexist.previous_state,
+			 rtlpriv->btcoexist.cstate_h,
+			 rtlpriv->btcoexist.cstate);
+		rtlpriv->btcoexist.previous_state
+			= rtlpriv->btcoexist.cstate;
+		rtlpriv->btcoexist.previous_state_h
+			= rtlpriv->btcoexist.cstate_h;
 	}
 }
 
-static void rtl8723ae_dm_bt_parse_bt_info(struct ieee80211_hw *hw,
-					  u8 *tmbuf, u8 len)
+static void rtl8723e_dm_bt_parse_bt_info(struct ieee80211_hw *hw,
+					 u8 *tmp_buf, u8 len)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-	struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
 	u8 bt_info;
 	u8 i;
 
-	rtlhal->hal_coex_8723.c2h_bt_info_req_sent = false;
-	rtlhal->hal_coex_8723.bt_retry_cnt = 0;
+	hal_coex_8723.c2h_bt_info_req_sent = false;
+	hal_coex_8723.bt_retry_cnt = 0;
 	for (i = 0; i < len; i++) {
 		if (i == 0)
-			rtlhal->hal_coex_8723.c2h_bt_info_original = tmbuf[i];
+			hal_coex_8723.c2h_bt_info_original = tmp_buf[i];
 		else if (i == 1)
-			rtlhal->hal_coex_8723.bt_retry_cnt = tmbuf[i];
-		if (i == len-1) {
+			hal_coex_8723.bt_retry_cnt = tmp_buf[i];
+		if (i == len-1)
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "0x%2x]", tmbuf[i]);
-		} else {
+				 "0x%2x]", tmp_buf[i]);
+		else
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
-				 "0x%2x, ", tmbuf[i]);
-		}
+				 "0x%2x, ", tmp_buf[i]);
+
 	}
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-		 "BT info bt_info (Data)= 0x%x\n",
-		 rtlhal->hal_coex_8723.c2h_bt_info_original);
-	bt_info = rtlhal->hal_coex_8723.c2h_bt_info_original;
+		"BT info bt_info (Data)= 0x%x\n",
+			hal_coex_8723.c2h_bt_info_original);
+	bt_info = hal_coex_8723.c2h_bt_info_original;
 
 	if (bt_info & BIT(2))
-		rtlhal->hal_coex_8723.c2h_bt_inquiry_page = true;
+		hal_coex_8723.c2h_bt_inquiry_page = true;
 	else
-		rtlhal->hal_coex_8723.c2h_bt_inquiry_page = false;
+		hal_coex_8723.c2h_bt_inquiry_page = false;
+
 
 	if (bt_info & BTINFO_B_CONNECTION) {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTC2H], BTInfo: bConnect=true\n");
-		rtlpcipriv->bt_coexist.bt_busy = true;
-		rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_BT_IDLE;
+			"[BTC2H], BTInfo: bConnect=true\n");
+		rtlpriv->btcoexist.bt_busy = true;
+		rtlpriv->btcoexist.cstate &= ~BT_COEX_STATE_BT_IDLE;
 	} else {
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
-			 "[BTC2H], BTInfo: bConnect=false\n");
-		rtlpcipriv->bt_coexist.bt_busy = false;
-		rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_BT_IDLE;
+			"[BTC2H], BTInfo: bConnect=false\n");
+		rtlpriv->btcoexist.bt_busy = false;
+		rtlpriv->btcoexist.cstate |= BT_COEX_STATE_BT_IDLE;
 	}
 }
 void rtl_8723e_c2h_command_handle(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct c2h_evt_hdr c2h_event;
-	u8 *ptmbuf;
-	u8 index;
-	u8 u1tmp;
-
+	u8 *ptmp_buf = NULL;
+	u8 index = 0;
+	u8 u1b_tmp = 0;
 	memset(&c2h_event, 0, sizeof(c2h_event));
-	u1tmp = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL);
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL);
 	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
-		 "&&&&&&: REG_C2HEVT_MSG_NORMAL is 0x%x\n", u1tmp);
-	c2h_event.cmd_id = u1tmp & 0xF;
-	c2h_event.cmd_len = (u1tmp & 0xF0) >> 4;
+		"&&&&&&: REG_C2HEVT_MSG_NORMAL is 0x%x\n", u1b_tmp);
+	c2h_event.cmd_id = u1b_tmp & 0xF;
+	c2h_event.cmd_len = (u1b_tmp & 0xF0) >> 4;
 	c2h_event.cmd_seq = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL + 1);
 	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
 		 "cmd_id: %d, cmd_len: %d, cmd_seq: %d\n",
 		 c2h_event.cmd_id , c2h_event.cmd_len, c2h_event.cmd_seq);
-	u1tmp = rtl_read_byte(rtlpriv, 0x01AF);
-	if (u1tmp == C2H_EVT_HOST_CLOSE) {
+	u1b_tmp = rtl_read_byte(rtlpriv, 0x01AF);
+	if (u1b_tmp == C2H_EVT_HOST_CLOSE) {
 		return;
-	} else if (u1tmp != C2H_EVT_FW_CLOSE) {
+	} else if (u1b_tmp != C2H_EVT_FW_CLOSE) {
 		rtl_write_byte(rtlpriv, 0x1AF, 0x00);
 		return;
 	}
-	ptmbuf = kmalloc(c2h_event.cmd_len, GFP_KERNEL);
-	if (ptmbuf == NULL) {
+	ptmp_buf = kzalloc(c2h_event.cmd_len, GFP_KERNEL);
+	if (ptmp_buf == NULL) {
 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 			 "malloc cmd buf failed\n");
 		return;
@@ -1757,30 +1744,37 @@
 
 	/* Read the content */
 	for (index = 0; index < c2h_event.cmd_len; index++)
-		ptmbuf[index] = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL +
-				  2 + index);
+		ptmp_buf[index] = rtl_read_byte(rtlpriv,
+					REG_C2HEVT_MSG_NORMAL + 2 + index);
+
 
 	switch (c2h_event.cmd_id) {
 	case C2H_BT_RSSI:
-		break;
+			break;
 
 	case C2H_BT_OP_MODE:
 			break;
 
 	case BT_INFO:
 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-			 "BT info Byte[0] (ID) is 0x%x\n", c2h_event.cmd_id);
+			"BT info Byte[0] (ID) is 0x%x\n",
+			c2h_event.cmd_id);
 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-			 "BT info Byte[1] (Seq) is 0x%x\n", c2h_event.cmd_seq);
+			"BT info Byte[1] (Seq) is 0x%x\n",
+			c2h_event.cmd_seq);
 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-			 "BT info Byte[2] (Data)= 0x%x\n", ptmbuf[0]);
+			"BT info Byte[2] (Data)= 0x%x\n", ptmp_buf[0]);
 
-		rtl8723ae_dm_bt_parse_bt_info(hw, ptmbuf, c2h_event.cmd_len);
+		rtl8723e_dm_bt_parse_bt_info(hw, ptmp_buf, c2h_event.cmd_len);
+
+		if (rtlpriv->cfg->ops->get_btc_status())
+			rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv);
+
 		break;
 	default:
 		break;
 	}
-	kfree(ptmbuf);
+	kfree(ptmp_buf);
 
 	rtl_write_byte(rtlpriv, 0x01AF, C2H_EVT_HOST_CLOSE);
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.h b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.h
index 4325ecd..3723d74 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -24,8 +20,7 @@
  * Hsinchu 300, Taiwan.
  * Larry Finger <Larry.Finger@lwfinger.net>
  *
- ****************************************************************************
- */
+ *****************************************************************************/
 
 #ifndef __RTL8723E_HAL_BTC_H__
 #define __RTL8723E_HAL_BTC_H__
@@ -34,21 +29,31 @@
 #include "btc.h"
 #include "hal_bt_coexist.h"
 
-#define	BT_TXRX_CNT_THRES_1		1200
-#define	BT_TXRX_CNT_THRES_2		1400
-#define	BT_TXRX_CNT_THRES_3		3000
-#define	BT_TXRX_CNT_LEVEL_0		0	/* < 1200 */
-#define	BT_TXRX_CNT_LEVEL_1		1	/* >= 1200 && < 1400 */
-#define	BT_TXRX_CNT_LEVEL_2		2	/* >= 1400 */
-#define	BT_TXRX_CNT_LEVEL_3		3
+#define	BT_TXRX_CNT_THRES_1			1200
+#define	BT_TXRX_CNT_THRES_2			1400
+#define	BT_TXRX_CNT_THRES_3			3000
+/* < 1200 */
+#define	BT_TXRX_CNT_LEVEL_0			0
+/* >= 1200 && < 1400 */
+#define	BT_TXRX_CNT_LEVEL_1			1
+/* >= 1400 */
+#define	BT_TXRX_CNT_LEVEL_2			2
+#define	BT_TXRX_CNT_LEVEL_3			3
+
+#define	BT_COEX_DISABLE			0
+#define	BT_Q_PKT_OFF			0
+#define	BT_Q_PKT_ON			1
+
+#define	BT_TX_PWR_OFF			0
+#define	BT_TX_PWR_ON			1
 
 /* TDMA mode definition */
-#define	TDMA_2ANT		0
-#define	TDMA_1ANT		1
-#define	TDMA_NAV_OFF		0
-#define	TDMA_NAV_ON		1
-#define	TDMA_DAC_SWING_OFF	0
-#define	TDMA_DAC_SWING_ON	1
+#define	TDMA_2ANT			0
+#define	TDMA_1ANT			1
+#define	TDMA_NAV_OFF			0
+#define	TDMA_NAV_ON			1
+#define	TDMA_DAC_SWING_OFF		0
+#define	TDMA_DAC_SWING_ON		1
 
 /* PTA mode related definition */
 #define	BT_PTA_MODE_OFF		0
@@ -80,6 +85,7 @@
 	BT_PROFILE_SCO
 };
 
+/*
 enum hci_ext_bt_operation {
 	HCI_BT_OP_NONE = 0x0,
 	HCI_BT_OP_INQUIRE_START	= 0x1,
@@ -93,6 +99,7 @@
 	HCI_BT_OP_BT_DEV_DISABLE = 0x9,
 	HCI_BT_OP_MAX,
 };
+*/
 
 enum bt_spec {
 	BT_SPEC_1_0_b = 0x00,
@@ -123,12 +130,12 @@
 	BT_INFO_STATE_MAX = 7
 };
 
-enum rtl8723ae_c2h_evt {
+enum rtl8723e_c2h_evt {
 	C2H_DBG = 0,
 	C2H_TSF = 1,
 	C2H_AP_RPT_RSP = 2,
-	C2H_CCX_TX_RPT = 3,	/* The FW notify the report of the specific */
-				/* tx packet. */
+	/* The FW notify the report of the specific tx packet. */
+	C2H_CCX_TX_RPT = 3,
 	C2H_BT_RSSI = 4,
 	C2H_BT_OP_MODE = 5,
 	C2H_HW_INFO_EXCH = 10,
@@ -137,15 +144,16 @@
 	MAX_C2HEVENT
 };
 
-void rtl8723ae_dm_bt_fw_coex_all_off_8723a(struct ieee80211_hw *hw);
-void rtl8723ae_dm_bt_sw_coex_all_off_8723a(struct ieee80211_hw *hw);
-void rtl8723ae_dm_bt_hw_coex_all_off_8723a(struct ieee80211_hw *hw);
-void rtl8723ae_dm_bt_coexist_8723(struct ieee80211_hw *hw);
-void rtl8723ae_dm_bt_set_bt_dm(struct ieee80211_hw *hw,
+void rtl8723e_dm_bt_fw_coex_all_off_8723a(struct ieee80211_hw *hw);
+void rtl8723e_dm_bt_sw_coex_all_off_8723a(struct ieee80211_hw *hw);
+void rtl8723e_dm_bt_hw_coex_all_off_8723a(struct ieee80211_hw *hw);
+void rtl8723e_dm_bt_coexist_8723(struct ieee80211_hw *hw);
+void rtl8723e_dm_bt_set_bt_dm(struct ieee80211_hw *hw,
 			      struct btdm_8723 *p_btdm);
 void rtl_8723e_c2h_command_handle(struct ieee80211_hw *hw);
 void rtl_8723e_bt_wifi_media_status_notify(struct ieee80211_hw *hw,
-					   bool mstatus);
-void rtl8723ae_bt_coex_off_before_lps(struct ieee80211_hw *hw);
+					bool mstatus);
+void rtl8723e_dm_bt_turn_off_bt_coexist_before_enter_lps(
+				struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
index 662a079..aa08546 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -37,17 +33,21 @@
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
+#include "../rtl8723com/phy_common.h"
 #include "dm.h"
 #include "../rtl8723com/dm_common.h"
 #include "fw.h"
 #include "../rtl8723com/fw_common.h"
 #include "led.h"
 #include "hw.h"
+#include "../pwrseqcmd.h"
 #include "pwrseq.h"
 #include "btc.h"
 
-static void _rtl8723ae_set_bcn_ctrl_reg(struct ieee80211_hw *hw,
-					u8 set_bits, u8 clear_bits)
+#define LLT_CONFIG	5
+
+static void _rtl8723e_set_bcn_ctrl_reg(struct ieee80211_hw *hw,
+				       u8 set_bits, u8 clear_bits)
 {
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -58,7 +58,7 @@
 	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val);
 }
 
-static void _rtl8723ae_stop_tx_beacon(struct ieee80211_hw *hw)
+static void _rtl8723e_stop_tx_beacon(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 tmp1byte;
@@ -71,7 +71,7 @@
 	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
 }
 
-static void _rtl8723ae_resume_tx_beacon(struct ieee80211_hw *hw)
+static void _rtl8723e_resume_tx_beacon(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 tmp1byte;
@@ -84,17 +84,17 @@
 	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
 }
 
-static void _rtl8723ae_enable_bcn_sufunc(struct ieee80211_hw *hw)
+static void _rtl8723e_enable_bcn_sub_func(struct ieee80211_hw *hw)
 {
-	_rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(1));
+	_rtl8723e_set_bcn_ctrl_reg(hw, 0, BIT(1));
 }
 
-static void _rtl8723ae_disable_bcn_sufunc(struct ieee80211_hw *hw)
+static void _rtl8723e_disable_bcn_sub_func(struct ieee80211_hw *hw)
 {
-	_rtl8723ae_set_bcn_ctrl_reg(hw, BIT(1), 0);
+	_rtl8723e_set_bcn_ctrl_reg(hw, BIT(1), 0);
 }
 
-void rtl8723ae_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+void rtl8723e_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
@@ -102,54 +102,55 @@
 
 	switch (variable) {
 	case HW_VAR_RCR:
-		*((u32 *) (val)) = rtlpci->receive_config;
+		*((u32 *)(val)) = rtlpci->receive_config;
 		break;
 	case HW_VAR_RF_STATE:
 		*((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
 		break;
 	case HW_VAR_FWLPS_RF_ON:{
-		enum rf_pwrstate rfState;
-		u32 val_rcr;
+			enum rf_pwrstate rfstate;
+			u32 val_rcr;
 
-		rtlpriv->cfg->ops->get_hw_reg(hw,
-					      HW_VAR_RF_STATE,
-					      (u8 *) (&rfState));
-		if (rfState == ERFOFF) {
-			*((bool *) (val)) = true;
-		} else {
-			val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
-			val_rcr &= 0x00070000;
-			if (val_rcr)
-				*((bool *) (val)) = false;
-			else
-				*((bool *) (val)) = true;
+			rtlpriv->cfg->ops->get_hw_reg(hw,
+						      HW_VAR_RF_STATE,
+						      (u8 *)(&rfstate));
+			if (rfstate == ERFOFF) {
+				*((bool *)(val)) = true;
+			} else {
+				val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+				val_rcr &= 0x00070000;
+				if (val_rcr)
+					*((bool *)(val)) = false;
+				else
+					*((bool *)(val)) = true;
+			}
+			break;
 		}
-		break; }
 	case HW_VAR_FW_PSMODE_STATUS:
-		*((bool *) (val)) = ppsc->fw_current_inpsmode;
+		*((bool *)(val)) = ppsc->fw_current_inpsmode;
 		break;
 	case HW_VAR_CORRECT_TSF:{
-		u64 tsf;
-		u32 *ptsf_low = (u32 *)&tsf;
-		u32 *ptsf_high = ((u32 *)&tsf) + 1;
+			u64 tsf;
+			u32 *ptsf_low = (u32 *)&tsf;
+			u32 *ptsf_high = ((u32 *)&tsf) + 1;
 
-		*ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4));
-		*ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+			*ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4));
+			*ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
 
-		*((u64 *) (val)) = tsf;
+			*((u64 *)(val)) = tsf;
 
-		break; }
+			break;
+		}
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 			 "switch case not process\n");
 		break;
 	}
 }
 
-void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+void rtl8723e_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
@@ -157,362 +158,400 @@
 	u8 idx;
 
 	switch (variable) {
-	case HW_VAR_ETHER_ADDR:
-		for (idx = 0; idx < ETH_ALEN; idx++) {
-			rtl_write_byte(rtlpriv, (REG_MACID + idx),
-				       val[idx]);
+	case HW_VAR_ETHER_ADDR:{
+			for (idx = 0; idx < ETH_ALEN; idx++) {
+				rtl_write_byte(rtlpriv, (REG_MACID + idx),
+					       val[idx]);
+			}
+			break;
 		}
-		break;
 	case HW_VAR_BASIC_RATE:{
-		u16 rate_cfg = ((u16 *) val)[0];
-		u8 rate_index = 0;
-		rate_cfg = rate_cfg & 0x15f;
-		rate_cfg |= 0x01;
-		rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff);
-		rtl_write_byte(rtlpriv, REG_RRSR + 1,
-			       (rate_cfg >> 8) & 0xff);
-		while (rate_cfg > 0x1) {
-			rate_cfg = (rate_cfg >> 1);
-			rate_index++;
-		}
-		rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL,
-			       rate_index);
-		break; }
-	case HW_VAR_BSSID:
-		for (idx = 0; idx < ETH_ALEN; idx++) {
-			rtl_write_byte(rtlpriv, (REG_BSSID + idx),
-				       val[idx]);
-		}
-		break;
-	case HW_VAR_SIFS:
-		rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]);
-		rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]);
+			u16 b_rate_cfg = ((u16 *)val)[0];
+			u8 rate_index = 0;
 
-		rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]);
-		rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]);
+			b_rate_cfg = b_rate_cfg & 0x15f;
+			b_rate_cfg |= 0x01;
+			rtl_write_byte(rtlpriv, REG_RRSR, b_rate_cfg & 0xff);
+			rtl_write_byte(rtlpriv, REG_RRSR + 1,
+				       (b_rate_cfg >> 8) & 0xff);
+			while (b_rate_cfg > 0x1) {
+				b_rate_cfg = (b_rate_cfg >> 1);
+				rate_index++;
+			}
+			rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL,
+				       rate_index);
+			break;
+		}
+	case HW_VAR_BSSID:{
+			for (idx = 0; idx < ETH_ALEN; idx++) {
+				rtl_write_byte(rtlpriv, (REG_BSSID + idx),
+					       val[idx]);
+			}
+			break;
+		}
+	case HW_VAR_SIFS:{
+			rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]);
+			rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]);
 
-		if (!mac->ht_enable)
-			rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
-				       0x0e0e);
-		else
-			rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
-				       *((u16 *) val));
-		break;
+			rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]);
+			rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]);
+
+			if (!mac->ht_enable)
+				rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
+					       0x0e0e);
+			else
+				rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
+					       *((u16 *)val));
+			break;
+		}
 	case HW_VAR_SLOT_TIME:{
-		u8 e_aci;
-
-		RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
-			 "HW_VAR_SLOT_TIME %x\n", val[0]);
-
-		rtl_write_byte(rtlpriv, REG_SLOT, val[0]);
-
-		for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
-			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
-						      &e_aci);
-		}
-		break; }
-	case HW_VAR_ACK_PREAMBLE:{
-		u8 reg_tmp;
-		u8 short_preamble = (bool)*val;
-		reg_tmp = (mac->cur_40_prime_sc) << 5;
-		if (short_preamble)
-			reg_tmp |= 0x80;
-
-		rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_tmp);
-		break; }
-	case HW_VAR_AMPDU_MIN_SPACE:{
-		u8 min_spacing_to_set;
-		u8 sec_min_space;
-
-		min_spacing_to_set = *val;
-		if (min_spacing_to_set <= 7) {
-			sec_min_space = 0;
-
-			if (min_spacing_to_set < sec_min_space)
-				min_spacing_to_set = sec_min_space;
-
-			mac->min_space_cfg = ((mac->min_space_cfg &
-					       0xf8) |
-					      min_spacing_to_set);
-
-			*val = min_spacing_to_set;
+			u8 e_aci;
 
 			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
-				 "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
+				 "HW_VAR_SLOT_TIME %x\n", val[0]);
+
+			rtl_write_byte(rtlpriv, REG_SLOT, val[0]);
+
+			for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
+				rtlpriv->cfg->ops->set_hw_reg(hw,
+							      HW_VAR_AC_PARAM,
+							      (u8 *)(&e_aci));
+			}
+			break;
+		}
+	case HW_VAR_ACK_PREAMBLE:{
+			u8 reg_tmp;
+			u8 short_preamble = (bool)(*(u8 *)val);
+
+			reg_tmp = (mac->cur_40_prime_sc) << 5;
+			if (short_preamble)
+				reg_tmp |= 0x80;
+
+			rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_tmp);
+			break;
+		}
+	case HW_VAR_AMPDU_MIN_SPACE:{
+			u8 min_spacing_to_set;
+			u8 sec_min_space;
+
+			min_spacing_to_set = *((u8 *)val);
+			if (min_spacing_to_set <= 7) {
+				sec_min_space = 0;
+
+				if (min_spacing_to_set < sec_min_space)
+					min_spacing_to_set = sec_min_space;
+
+				mac->min_space_cfg = ((mac->min_space_cfg &
+						       0xf8) |
+						      min_spacing_to_set);
+
+				*val = min_spacing_to_set;
+
+				RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+					 "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
+					  mac->min_space_cfg);
+
+				rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+					       mac->min_space_cfg);
+			}
+			break;
+		}
+	case HW_VAR_SHORTGI_DENSITY:{
+			u8 density_to_set;
+
+			density_to_set = *((u8 *)val);
+			mac->min_space_cfg |= (density_to_set << 3);
+
+			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+				 "Set HW_VAR_SHORTGI_DENSITY: %#x\n",
 				  mac->min_space_cfg);
 
 			rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
 				       mac->min_space_cfg);
+
+			break;
 		}
-		break; }
-	case HW_VAR_SHORTGI_DENSITY:{
-		u8 density_to_set;
-
-		density_to_set = *val;
-		mac->min_space_cfg |= (density_to_set << 3);
-
-		RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
-			 "Set HW_VAR_SHORTGI_DENSITY: %#x\n",
-			 mac->min_space_cfg);
-
-		rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
-			       mac->min_space_cfg);
-
-		break; }
 	case HW_VAR_AMPDU_FACTOR:{
-		u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9};
-		u8 regtoset_bt[4] = {0x31, 0x74, 0x42, 0x97};
-		u8 factor_toset;
-		u8 *p_regtoset = NULL;
-		u8 index;
+			u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 };
+			u8 regtoset_bt[4] = {0x31, 0x74, 0x42, 0x97};
+			u8 factor_toset;
+			u8 *p_regtoset = NULL;
+			u8 index = 0;
 
-		if ((pcipriv->bt_coexist.bt_coexistence) &&
-		    (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4))
-			p_regtoset = regtoset_bt;
-		else
-			p_regtoset = regtoset_normal;
+			if ((rtlpriv->btcoexist.bt_coexistence) &&
+			    (rtlpriv->btcoexist.bt_coexist_type ==
+				BT_CSR_BC4))
+				p_regtoset = regtoset_bt;
+			else
+				p_regtoset = regtoset_normal;
 
-		factor_toset = *val;
-		if (factor_toset <= 3) {
-			factor_toset = (1 << (factor_toset + 2));
-			if (factor_toset > 0xf)
-				factor_toset = 0xf;
+			factor_toset = *((u8 *)val);
+			if (factor_toset <= 3) {
+				factor_toset = (1 << (factor_toset + 2));
+				if (factor_toset > 0xf)
+					factor_toset = 0xf;
 
-			for (index = 0; index < 4; index++) {
-				if ((p_regtoset[index] & 0xf0) >
-				    (factor_toset << 4))
-					p_regtoset[index] =
-					    (p_regtoset[index] & 0x0f) |
-					    (factor_toset << 4);
+				for (index = 0; index < 4; index++) {
+					if ((p_regtoset[index] & 0xf0) >
+					    (factor_toset << 4))
+						p_regtoset[index] =
+						    (p_regtoset[index] & 0x0f) |
+						    (factor_toset << 4);
 
-				if ((p_regtoset[index] & 0x0f) >
-				    factor_toset)
-					p_regtoset[index] =
-					    (p_regtoset[index] & 0xf0) |
-					    (factor_toset);
+					if ((p_regtoset[index] & 0x0f) >
+					    factor_toset)
+						p_regtoset[index] =
+						    (p_regtoset[index] & 0xf0) |
+						    (factor_toset);
 
-				rtl_write_byte(rtlpriv,
-					       (REG_AGGLEN_LMT + index),
-					       p_regtoset[index]);
+					rtl_write_byte(rtlpriv,
+						       (REG_AGGLEN_LMT + index),
+						       p_regtoset[index]);
+				}
 
+				RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+					 "Set HW_VAR_AMPDU_FACTOR: %#x\n",
+					  factor_toset);
 			}
-
-			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
-				 "Set HW_VAR_AMPDU_FACTOR: %#x\n",
-				 factor_toset);
+			break;
 		}
-		break; }
 	case HW_VAR_AC_PARAM:{
-		u8 e_aci = *val;
-		rtl8723_dm_init_edca_turbo(hw);
+			u8 e_aci = *((u8 *)val);
 
-		if (rtlpci->acm_method != EACMWAY2_SW)
-			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
-						      &e_aci);
-		break; }
-	case HW_VAR_ACM_CTRL:{
-		u8 e_aci = *val;
-		union aci_aifsn *p_aci_aifsn =
-		    (union aci_aifsn *)(&(mac->ac[0].aifs));
-		u8 acm = p_aci_aifsn->f.acm;
-		u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL);
+			rtl8723_dm_init_edca_turbo(hw);
 
-		acm_ctrl |= ((rtlpci->acm_method == 2) ? 0x0 : 0x1);
-
-		if (acm) {
-			switch (e_aci) {
-			case AC0_BE:
-				acm_ctrl |= AcmHw_BeqEn;
-				break;
-			case AC2_VI:
-				acm_ctrl |= AcmHw_ViqEn;
-				break;
-			case AC3_VO:
-				acm_ctrl |= AcmHw_VoqEn;
-				break;
-			default:
-				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-					 "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n",
-					 acm);
-				break;
-			}
-		} else {
-			switch (e_aci) {
-			case AC0_BE:
-				acm_ctrl &= (~AcmHw_BeqEn);
-				break;
-			case AC2_VI:
-				acm_ctrl &= (~AcmHw_ViqEn);
-				break;
-			case AC3_VO:
-				acm_ctrl &= (~AcmHw_BeqEn);
-				break;
-			default:
-				RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-					 "switch case not processed\n");
-				break;
-			}
+			if (rtlpci->acm_method != EACMWAY2_SW)
+				rtlpriv->cfg->ops->set_hw_reg(hw,
+							      HW_VAR_ACM_CTRL,
+							      (u8 *)(&e_aci));
+			break;
 		}
+	case HW_VAR_ACM_CTRL:{
+			u8 e_aci = *((u8 *)val);
+			union aci_aifsn *p_aci_aifsn =
+			    (union aci_aifsn *)(&mac->ac[0].aifs);
+			u8 acm = p_aci_aifsn->f.acm;
+			u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL);
 
-		RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
-			 "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n",
-			 acm_ctrl);
-		rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl);
-		break; }
-	case HW_VAR_RCR:
-		rtl_write_dword(rtlpriv, REG_RCR, ((u32 *) (val))[0]);
-		rtlpci->receive_config = ((u32 *) (val))[0];
-		break;
+			acm_ctrl =
+			    acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1);
+
+			if (acm) {
+				switch (e_aci) {
+				case AC0_BE:
+					acm_ctrl |= ACMHW_BEQEN;
+					break;
+				case AC2_VI:
+					acm_ctrl |= ACMHW_VIQEN;
+					break;
+				case AC3_VO:
+					acm_ctrl |= ACMHW_VOQEN;
+					break;
+				default:
+					RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+						 "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n",
+						 acm);
+					break;
+				}
+			} else {
+				switch (e_aci) {
+				case AC0_BE:
+					acm_ctrl &= (~ACMHW_BEQEN);
+					break;
+				case AC2_VI:
+					acm_ctrl &= (~ACMHW_VIQEN);
+					break;
+				case AC3_VO:
+					acm_ctrl &= (~ACMHW_BEQEN);
+					break;
+				default:
+					RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+						 "switch case not process\n");
+					break;
+				}
+			}
+
+			RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
+				 "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n",
+				 acm_ctrl);
+			rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl);
+			break;
+		}
+	case HW_VAR_RCR:{
+			rtl_write_dword(rtlpriv, REG_RCR, ((u32 *)(val))[0]);
+			rtlpci->receive_config = ((u32 *)(val))[0];
+			break;
+		}
 	case HW_VAR_RETRY_LIMIT:{
-		u8 retry_limit = *val;
+			u8 retry_limit = ((u8 *)(val))[0];
 
-		rtl_write_word(rtlpriv, REG_RL,
-			       retry_limit << RETRY_LIMIT_SHORT_SHIFT |
-			       retry_limit << RETRY_LIMIT_LONG_SHIFT);
-		break; }
+			rtl_write_word(rtlpriv, REG_RL,
+				       retry_limit << RETRY_LIMIT_SHORT_SHIFT |
+				       retry_limit << RETRY_LIMIT_LONG_SHIFT);
+			break;
+		}
 	case HW_VAR_DUAL_TSF_RST:
 		rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1)));
 		break;
 	case HW_VAR_EFUSE_BYTES:
-		rtlefuse->efuse_usedbytes = *((u16 *) val);
+		rtlefuse->efuse_usedbytes = *((u16 *)val);
 		break;
 	case HW_VAR_EFUSE_USAGE:
-		rtlefuse->efuse_usedpercentage = *val;
+		rtlefuse->efuse_usedpercentage = *((u8 *)val);
 		break;
 	case HW_VAR_IO_CMD:
-		rtl8723ae_phy_set_io_cmd(hw, (*(enum io_type *)val));
+		rtl8723e_phy_set_io_cmd(hw, (*(enum io_type *)val));
 		break;
 	case HW_VAR_WPA_CONFIG:
-		rtl_write_byte(rtlpriv, REG_SECCFG, *val);
+		rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *)val));
 		break;
 	case HW_VAR_SET_RPWM:{
-		u8 rpwm_val;
+			u8 rpwm_val;
 
-		rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM);
-		udelay(1);
+			rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM);
+			udelay(1);
 
-		if (rpwm_val & BIT(7)) {
-			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val);
-		} else {
-			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val | BIT(7));
+			if (rpwm_val & BIT(7)) {
+				rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+					       (*(u8 *)val));
+			} else {
+				rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+					       ((*(u8 *)val) | BIT(7)));
+			}
+
+			break;
 		}
-
-		break; }
 	case HW_VAR_H2C_FW_PWRMODE:{
-		u8 psmode = *val;
+			u8 psmode = (*(u8 *)val);
 
-		if (psmode != FW_PS_ACTIVE_MODE)
-			rtl8723ae_dm_rf_saving(hw, true);
+			if (psmode != FW_PS_ACTIVE_MODE)
+				rtl8723e_dm_rf_saving(hw, true);
 
-		rtl8723ae_set_fw_pwrmode_cmd(hw, *val);
-		break; }
+			rtl8723e_set_fw_pwrmode_cmd(hw, (*(u8 *)val));
+			break;
+		}
 	case HW_VAR_FW_PSMODE_STATUS:
-		ppsc->fw_current_inpsmode = *((bool *) val);
+		ppsc->fw_current_inpsmode = *((bool *)val);
 		break;
 	case HW_VAR_H2C_FW_JOINBSSRPT:{
-		u8 mstatus = *val;
-		u8 tmp_regcr, tmp_reg422;
-		bool recover = false;
+			u8 mstatus = (*(u8 *)val);
+			u8 tmp_regcr, tmp_reg422;
+			bool b_recover = false;
 
-		if (mstatus == RT_MEDIA_CONNECT) {
-			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL);
+			if (mstatus == RT_MEDIA_CONNECT) {
+				rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID,
+							      NULL);
 
-			tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
-			rtl_write_byte(rtlpriv, REG_CR + 1,
-				       (tmp_regcr | BIT(0)));
+				tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
+				rtl_write_byte(rtlpriv, REG_CR + 1,
+					       (tmp_regcr | BIT(0)));
 
-			_rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(3));
-			_rtl8723ae_set_bcn_ctrl_reg(hw, BIT(4), 0);
+				_rtl8723e_set_bcn_ctrl_reg(hw, 0, BIT(3));
+				_rtl8723e_set_bcn_ctrl_reg(hw, BIT(4), 0);
 
-			tmp_reg422 = rtl_read_byte(rtlpriv,
-				     REG_FWHW_TXQ_CTRL + 2);
-			if (tmp_reg422 & BIT(6))
-				recover = true;
-			rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
-				       tmp_reg422 & (~BIT(6)));
-
-			rtl8723ae_set_fw_rsvdpagepkt(hw, 0);
-
-			_rtl8723ae_set_bcn_ctrl_reg(hw, BIT(3), 0);
-			_rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(4));
-
-			if (recover)
+				tmp_reg422 =
+				    rtl_read_byte(rtlpriv,
+						  REG_FWHW_TXQ_CTRL + 2);
+				if (tmp_reg422 & BIT(6))
+					b_recover = true;
 				rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
-					       tmp_reg422);
+					       tmp_reg422 & (~BIT(6)));
 
-			rtl_write_byte(rtlpriv, REG_CR + 1,
-				       (tmp_regcr & ~(BIT(0))));
+				rtl8723e_set_fw_rsvdpagepkt(hw, 0);
+
+				_rtl8723e_set_bcn_ctrl_reg(hw, BIT(3), 0);
+				_rtl8723e_set_bcn_ctrl_reg(hw, 0, BIT(4));
+
+				if (b_recover) {
+					rtl_write_byte(rtlpriv,
+						       REG_FWHW_TXQ_CTRL + 2,
+						       tmp_reg422);
+				}
+
+				rtl_write_byte(rtlpriv, REG_CR + 1,
+					       (tmp_regcr & ~(BIT(0))));
+			}
+			rtl8723e_set_fw_joinbss_report_cmd(hw, (*(u8 *)val));
+
+			break;
 		}
-		rtl8723ae_set_fw_joinbss_report_cmd(hw, *val);
-
-		break; }
-	case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
-		rtl8723ae_set_p2p_ps_offload_cmd(hw, *val);
+	case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:{
+		rtl8723e_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
 		break;
+	}
 	case HW_VAR_AID:{
-		u16 u2btmp;
-		u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
-		u2btmp &= 0xC000;
-		rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, (u2btmp |
-				mac->assoc_id));
-		break; }
-	case HW_VAR_CORRECT_TSF:{
-		u8 btype_ibss = *val;
+			u16 u2btmp;
 
-		if (btype_ibss == true)
-			_rtl8723ae_stop_tx_beacon(hw);
+			u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
+			u2btmp &= 0xC000;
+			rtl_write_word(rtlpriv, REG_BCN_PSR_RPT,
+				       (u2btmp | mac->assoc_id));
 
-		_rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(3));
-
-		rtl_write_dword(rtlpriv, REG_TSFTR,
-				(u32) (mac->tsf & 0xffffffff));
-		rtl_write_dword(rtlpriv, REG_TSFTR + 4,
-				(u32) ((mac->tsf >> 32) & 0xffffffff));
-
-		_rtl8723ae_set_bcn_ctrl_reg(hw, BIT(3), 0);
-
-		if (btype_ibss == true)
-			_rtl8723ae_resume_tx_beacon(hw);
-		break; }
-	case HW_VAR_FW_LPS_ACTION: {
-		bool enter_fwlps = *((bool *)val);
-		u8 rpwm_val, fw_pwrmode;
-		bool fw_current_inps;
-
-		if (enter_fwlps) {
-			rpwm_val = 0x02;	/* RF off */
-			fw_current_inps = true;
-			rtlpriv->cfg->ops->set_hw_reg(hw,
-					HW_VAR_FW_PSMODE_STATUS,
-					(u8 *)(&fw_current_inps));
-			rtlpriv->cfg->ops->set_hw_reg(hw,
-					HW_VAR_H2C_FW_PWRMODE,
-					&ppsc->fwctrl_psmode);
-
-			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
-						      &rpwm_val);
-		} else {
-			rpwm_val = 0x0C;	/* RF on */
-			fw_pwrmode = FW_PS_ACTIVE_MODE;
-			fw_current_inps = false;
-			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
-						      &rpwm_val);
-			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-						      &fw_pwrmode);
-
-			rtlpriv->cfg->ops->set_hw_reg(hw,
-					HW_VAR_FW_PSMODE_STATUS,
-					(u8 *)(&fw_current_inps));
+			break;
 		}
-		break; }
+	case HW_VAR_CORRECT_TSF:{
+			u8 btype_ibss = ((u8 *)(val))[0];
+
+			if (btype_ibss)
+				_rtl8723e_stop_tx_beacon(hw);
+
+			_rtl8723e_set_bcn_ctrl_reg(hw, 0, BIT(3));
+
+			rtl_write_dword(rtlpriv, REG_TSFTR,
+					(u32)(mac->tsf & 0xffffffff));
+			rtl_write_dword(rtlpriv, REG_TSFTR + 4,
+					(u32)((mac->tsf >> 32) & 0xffffffff));
+
+			_rtl8723e_set_bcn_ctrl_reg(hw, BIT(3), 0);
+
+			if (btype_ibss)
+				_rtl8723e_resume_tx_beacon(hw);
+
+			break;
+		}
+	case HW_VAR_FW_LPS_ACTION:{
+			bool b_enter_fwlps = *((bool *)val);
+			u8 rpwm_val, fw_pwrmode;
+			bool fw_current_inps;
+
+			if (b_enter_fwlps) {
+				rpwm_val = 0x02;	/* RF off */
+				fw_current_inps = true;
+				rtlpriv->cfg->ops->set_hw_reg(hw,
+						HW_VAR_FW_PSMODE_STATUS,
+						(u8 *)(&fw_current_inps));
+				rtlpriv->cfg->ops->set_hw_reg(hw,
+						HW_VAR_H2C_FW_PWRMODE,
+						(u8 *)(&ppsc->fwctrl_psmode));
+
+				rtlpriv->cfg->ops->set_hw_reg(hw,
+						HW_VAR_SET_RPWM,
+						(u8 *)(&rpwm_val));
+			} else {
+				rpwm_val = 0x0C;	/* RF on */
+				fw_pwrmode = FW_PS_ACTIVE_MODE;
+				fw_current_inps = false;
+				rtlpriv->cfg->ops->set_hw_reg(hw,
+							      HW_VAR_SET_RPWM,
+							      (u8 *)(&rpwm_val));
+				rtlpriv->cfg->ops->set_hw_reg(hw,
+						HW_VAR_H2C_FW_PWRMODE,
+						(u8 *)(&fw_pwrmode));
+
+				rtlpriv->cfg->ops->set_hw_reg(hw,
+						HW_VAR_FW_PSMODE_STATUS,
+						(u8 *)(&fw_current_inps));
+			}
+			 break;
+		}
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not processed\n");
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
 		break;
 	}
 }
 
-static bool _rtl8723ae_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
+static bool _rtl8723e_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	bool status = true;
@@ -539,24 +578,49 @@
 	return status;
 }
 
-static bool _rtl8723ae_llt_table_init(struct ieee80211_hw *hw)
+static bool _rtl8723e_llt_table_init(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	unsigned short i;
 	u8 txpktbuf_bndy;
-	u8 maxPage;
+	u8 maxpage;
 	bool status;
 	u8 ubyte;
 
-	maxPage = 255;
+#if LLT_CONFIG == 1
+	maxpage = 255;
+	txpktbuf_bndy = 252;
+#elif LLT_CONFIG == 2
+	maxpage = 127;
+	txpktbuf_bndy = 124;
+#elif LLT_CONFIG == 3
+	maxpage = 255;
+	txpktbuf_bndy = 174;
+#elif LLT_CONFIG == 4
+	maxpage = 255;
 	txpktbuf_bndy = 246;
+#elif LLT_CONFIG == 5
+	maxpage = 255;
+	txpktbuf_bndy = 246;
+#endif
 
 	rtl_write_byte(rtlpriv, REG_CR, 0x8B);
 
+#if LLT_CONFIG == 1
+	rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x1c);
+	rtl_write_dword(rtlpriv, REG_RQPN, 0x80a71c1c);
+#elif LLT_CONFIG == 2
+	rtl_write_dword(rtlpriv, REG_RQPN, 0x845B1010);
+#elif LLT_CONFIG == 3
+	rtl_write_dword(rtlpriv, REG_RQPN, 0x84838484);
+#elif LLT_CONFIG == 4
+	rtl_write_dword(rtlpriv, REG_RQPN, 0x80bd1c1c);
+#elif LLT_CONFIG == 5
 	rtl_write_word(rtlpriv, REG_RQPN_NPQ, 0x0000);
 
 	rtl_write_dword(rtlpriv, REG_RQPN, 0x80ac1c29);
 	rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x03);
+#endif
 
 	rtl_write_dword(rtlpriv, REG_TRXFF_BNDY, (0x27FF0000 | txpktbuf_bndy));
 	rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy);
@@ -569,22 +633,22 @@
 	rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4);
 
 	for (i = 0; i < (txpktbuf_bndy - 1); i++) {
-		status = _rtl8723ae_llt_write(hw, i, i + 1);
+		status = _rtl8723e_llt_write(hw, i, i + 1);
 		if (true != status)
 			return status;
 	}
 
-	status = _rtl8723ae_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
+	status = _rtl8723e_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
 	if (true != status)
 		return status;
 
-	for (i = txpktbuf_bndy; i < maxPage; i++) {
-		status = _rtl8723ae_llt_write(hw, i, (i + 1));
+	for (i = txpktbuf_bndy; i < maxpage; i++) {
+		status = _rtl8723e_llt_write(hw, i, (i + 1));
 		if (true != status)
 			return status;
 	}
 
-	status = _rtl8723ae_llt_write(hw, maxPage, txpktbuf_bndy);
+	status = _rtl8723e_llt_write(hw, maxpage, txpktbuf_bndy);
 	if (true != status)
 		return status;
 
@@ -595,28 +659,29 @@
 	return true;
 }
 
-static void _rtl8723ae_gen_refresh_led_state(struct ieee80211_hw *hw)
+static void _rtl8723e_gen_refresh_led_state(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-	struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+	struct rtl_led *pled0 = &pcipriv->ledctl.sw_led0;
 
 	if (rtlpriv->rtlhal.up_first_time)
 		return;
 
 	if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS)
-		rtl8723ae_sw_led_on(hw, pLed0);
+		rtl8723e_sw_led_on(hw, pled0);
 	else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT)
-		rtl8723ae_sw_led_on(hw, pLed0);
+		rtl8723e_sw_led_on(hw, pled0);
 	else
-		rtl8723ae_sw_led_off(hw, pLed0);
+		rtl8723e_sw_led_off(hw, pled0);
 }
 
 static bool _rtl8712e_init_mac(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
 	unsigned char bytetmp;
 	unsigned short wordtmp;
 	u16 retry = 0;
@@ -630,7 +695,6 @@
 	else
 		mac_func_enable = false;
 
-
 	/* HW Power on sequence */
 	if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
 		PWR_INTF_PCI_MSK, Rtl8723_NIC_ENABLE_FLOW))
@@ -669,7 +733,7 @@
 	rtl_write_word(rtlpriv, REG_CR + 1, 0x06);
 
 	if (!mac_func_enable) {
-		if (_rtl8723ae_llt_table_init(hw) == false)
+		if (!_rtl8723e_llt_table_init(hw))
 			return false;
 	}
 
@@ -678,7 +742,8 @@
 
 	rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, 0x27ff);
 
-	wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL) & 0xf;
+	wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL);
+	wordtmp &= 0xf;
 	wordtmp |= 0xF771;
 	rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp);
 
@@ -721,22 +786,23 @@
 		bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL);
 	} while ((retry < 200) && (bytetmp & BIT(7)));
 
-	_rtl8723ae_gen_refresh_led_state(hw);
+	_rtl8723e_gen_refresh_led_state(hw);
 
 	rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0);
 
 	return true;
 }
 
-static void _rtl8723ae_hw_configure(struct ieee80211_hw *hw)
+static void _rtl8723e_hw_configure(struct ieee80211_hw *hw)
 {
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	u8 reg_bw_opmode;
-	u32 reg_prsr;
+	u32 reg_ratr, reg_prsr;
 
 	reg_bw_opmode = BW_OPMODE_20MHZ;
+	reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
+	    RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
 	reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
 
 	rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8);
@@ -762,8 +828,8 @@
 	rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000);
 	rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504);
 
-	if ((pcipriv->bt_coexist.bt_coexistence) &&
-	    (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4))
+	if ((rtlpriv->btcoexist.bt_coexistence) &&
+	    (rtlpriv->btcoexist.bt_coexist_type == BT_CSR_BC4))
 		rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x97427431);
 	else
 		rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841);
@@ -782,8 +848,8 @@
 	rtl_write_byte(rtlpriv, REG_PIFS, 0x1C);
 	rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16);
 
-	if ((pcipriv->bt_coexist.bt_coexistence) &&
-	    (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) {
+	if ((rtlpriv->btcoexist.bt_coexistence) &&
+	    (rtlpriv->btcoexist.bt_coexist_type == BT_CSR_BC4)) {
 		rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
 		rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0402);
 	} else {
@@ -791,8 +857,8 @@
 		rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
 	}
 
-	if ((pcipriv->bt_coexist.bt_coexistence) &&
-	     (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4))
+	if ((rtlpriv->btcoexist.bt_coexistence) &&
+	    (rtlpriv->btcoexist.bt_coexist_type == BT_CSR_BC4))
 		rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666);
 	else
 		rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666);
@@ -812,7 +878,7 @@
 	rtl_write_dword(rtlpriv, 0x394, 0x1);
 }
 
-static void _rtl8723ae_enable_aspm_back_door(struct ieee80211_hw *hw)
+static void _rtl8723e_enable_aspm_back_door(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
@@ -830,15 +896,15 @@
 	rtl_write_byte(rtlpriv, 0x352, 0x1);
 }
 
-void rtl8723ae_enable_hw_security_config(struct ieee80211_hw *hw)
+void rtl8723e_enable_hw_security_config(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 sec_reg_value;
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 		 "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n",
-		 rtlpriv->sec.pairwise_enc_algorithm,
-		 rtlpriv->sec.group_enc_algorithm);
+		  rtlpriv->sec.pairwise_enc_algorithm,
+		  rtlpriv->sec.group_enc_algorithm);
 
 	if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
 		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
@@ -846,11 +912,11 @@
 		return;
 	}
 
-	sec_reg_value = SCR_TxEncEnable | SCR_RxDecEnable;
+	sec_reg_value = SCR_TXENCENABLE | SCR_RXDECENABLE;
 
 	if (rtlpriv->sec.use_defaultkey) {
-		sec_reg_value |= SCR_TxUseDK;
-		sec_reg_value |= SCR_RxUseDK;
+		sec_reg_value |= SCR_TXUSEDK;
+		sec_reg_value |= SCR_RXUSEDK;
 	}
 
 	sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK);
@@ -864,7 +930,7 @@
 
 }
 
-int rtl8723ae_hw_init(struct ieee80211_hw *hw)
+int rtl8723e_hw_init(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -887,6 +953,7 @@
 	 */
 	local_save_flags(flags);
 	local_irq_enable();
+	rtlhal->fw_ready = false;
 
 	rtlpriv->intf_ops->disable_aspm(hw);
 	rtstatus = _rtl8712e_init_mac(hw);
@@ -896,20 +963,19 @@
 		goto exit;
 	}
 
-	err = rtl8723_download_fw(hw, false);
+	err = rtl8723_download_fw(hw, false, FW_8723A_POLLING_TIMEOUT_COUNT);
 	if (err) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 			 "Failed to download FW. Init HW without FW now..\n");
 		err = 1;
 		goto exit;
-	} else {
-		rtlhal->fw_ready = true;
 	}
+	rtlhal->fw_ready = true;
 
 	rtlhal->last_hmeboxnum = 0;
-	rtl8723ae_phy_mac_config(hw);
-	/* because the last function modifies RCR, we update
-	 * rcr var here, or TP will be unstable as ther receive_config
+	rtl8723e_phy_mac_config(hw);
+	/* because last function modify RCR, so we update
+	 * rcr var here, or TP will unstable for receive_config
 	 * is wrong, RX RCR_ACRC32 will cause TP unstable & Rx
 	 * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252
 	 */
@@ -917,9 +983,9 @@
 	rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV);
 	rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
 
-	rtl8723ae_phy_bb_config(hw);
+	rtl8723e_phy_bb_config(hw);
 	rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
-	rtl8723ae_phy_rf_config(hw);
+	rtl8723e_phy_rf_config(hw);
 	if (IS_VENDOR_UMC_A_CUT(rtlhal->version)) {
 		rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD, 0x30255);
 		rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G2, MASKDWORD, 0x50a00);
@@ -938,28 +1004,29 @@
 	rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1);
 	rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1);
 	rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);
-	_rtl8723ae_hw_configure(hw);
+	_rtl8723e_hw_configure(hw);
 	rtl_cam_reset_all_entry(hw);
-	rtl8723ae_enable_hw_security_config(hw);
+	rtl8723e_enable_hw_security_config(hw);
 
 	ppsc->rfpwr_state = ERFON;
 
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
-	_rtl8723ae_enable_aspm_back_door(hw);
+	_rtl8723e_enable_aspm_back_door(hw);
 	rtlpriv->intf_ops->enable_aspm(hw);
 
-	rtl8723ae_bt_hw_init(hw);
+	rtl8723e_bt_hw_init(hw);
 
 	if (ppsc->rfpwr_state == ERFON) {
-		rtl8723ae_phy_set_rfpath_switch(hw, 1);
+		rtl8723e_phy_set_rfpath_switch(hw, 1);
 		if (rtlphy->iqk_initialized) {
-			rtl8723ae_phy_iq_calibrate(hw, true);
+			rtl8723e_phy_iq_calibrate(hw, true);
 		} else {
-			rtl8723ae_phy_iq_calibrate(hw, false);
+			rtl8723e_phy_iq_calibrate(hw, false);
 			rtlphy->iqk_initialized = true;
 		}
 
-		rtl8723ae_phy_lc_calibrate(hw);
+		rtl8723e_dm_check_txpower_tracking(hw);
+		rtl8723e_phy_lc_calibrate(hw);
 	}
 
 	tmp_u1b = efuse_read_1byte(hw, 0x1FA);
@@ -969,20 +1036,21 @@
 	}
 
 	if (!(tmp_u1b & BIT(4))) {
-		tmp_u1b = rtl_read_byte(rtlpriv, 0x16) & 0x0F;
+		tmp_u1b = rtl_read_byte(rtlpriv, 0x16);
+		tmp_u1b &= 0x0F;
 		rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x80);
 		udelay(10);
 		rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x90);
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n");
 	}
-	rtl8723ae_dm_init(hw);
+	rtl8723e_dm_init(hw);
 exit:
 	local_irq_restore(flags);
 	rtlpriv->rtlhal.being_init_adapter = false;
 	return err;
 }
 
-static enum version_8723e _rtl8723ae_read_chip_version(struct ieee80211_hw *hw)
+static enum version_8723e _rtl8723e_read_chip_version(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -992,41 +1060,41 @@
 	value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG);
 	if (value32 & TRP_VAUX_EN) {
 		version = (enum version_8723e)(version |
-			  ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0));
+			((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0));
 		/* RTL8723 with BT function. */
 		version = (enum version_8723e)(version |
-			  ((value32 & BT_FUNC) ? CHIP_8723 : 0));
+			((value32 & BT_FUNC) ? CHIP_8723 : 0));
 
 	} else {
 		/* Normal mass production chip. */
 		version = (enum version_8723e) NORMAL_CHIP;
 		version = (enum version_8723e)(version |
-			  ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0));
+			((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0));
 		/* RTL8723 with BT function. */
 		version = (enum version_8723e)(version |
-			  ((value32 & BT_FUNC) ? CHIP_8723 : 0));
+			((value32 & BT_FUNC) ? CHIP_8723 : 0));
 		if (IS_CHIP_VENDOR_UMC(version))
 			version = (enum version_8723e)(version |
 			((value32 & CHIP_VER_RTL_MASK)));/* IC version (CUT) */
 		if (IS_8723_SERIES(version)) {
 			value32 = rtl_read_dword(rtlpriv, REG_GPIO_OUTSTS);
-			/* ROM code version */
+			/* ROM code version. */
 			version = (enum version_8723e)(version |
-				  ((value32 & RF_RL_ID)>>20));
+				((value32 & RF_RL_ID)>>20));
 		}
 	}
 
 	if (IS_8723_SERIES(version)) {
 		value32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL);
 		rtlphy->polarity_ctl = ((value32 & WL_HWPDN_SL) ?
-				       RT_POLARITY_HIGH_ACT :
-				       RT_POLARITY_LOW_ACT);
+					RT_POLARITY_HIGH_ACT :
+					RT_POLARITY_LOW_ACT);
 	}
 	switch (version) {
 	case VERSION_TEST_UMC_CHIP_8723:
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "Chip Version ID: VERSION_TEST_UMC_CHIP_8723.\n");
-		break;
+			break;
 	case VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT:
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "Chip Version ID: VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT.\n");
@@ -1050,113 +1118,124 @@
 	return version;
 }
 
-static int _rtl8723ae_set_media_status(struct ieee80211_hw *hw,
-				     enum nl80211_iftype type)
+static int _rtl8723e_set_media_status(struct ieee80211_hw *hw,
+				      enum nl80211_iftype type)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 bt_msr = rtl_read_byte(rtlpriv, MSR) & 0xfc;
 	enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
+	u8 mode = MSR_NOLINK;
 
 	rtl_write_dword(rtlpriv, REG_BCN_CTRL, 0);
 	RT_TRACE(rtlpriv, COMP_BEACON, DBG_LOUD,
-		 "clear 0x550 when set HW_VAR_MEDIA_STATUS\n");
-
-	if (type == NL80211_IFTYPE_UNSPECIFIED ||
-	    type == NL80211_IFTYPE_STATION) {
-		_rtl8723ae_stop_tx_beacon(hw);
-		_rtl8723ae_enable_bcn_sufunc(hw);
-	} else if (type == NL80211_IFTYPE_ADHOC ||
-		type == NL80211_IFTYPE_AP) {
-		_rtl8723ae_resume_tx_beacon(hw);
-		_rtl8723ae_disable_bcn_sufunc(hw);
-	} else {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-			 "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n",
-			 type);
-	}
+		"clear 0x550 when set HW_VAR_MEDIA_STATUS\n");
 
 	switch (type) {
 	case NL80211_IFTYPE_UNSPECIFIED:
-		bt_msr |= MSR_NOLINK;
-		ledaction = LED_CTL_LINK;
+		mode = MSR_NOLINK;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "Set Network type to NO LINK!\n");
+			"Set Network type to NO LINK!\n");
 		break;
 	case NL80211_IFTYPE_ADHOC:
-		bt_msr |= MSR_ADHOC;
+		mode = MSR_ADHOC;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "Set Network type to Ad Hoc!\n");
+			"Set Network type to Ad Hoc!\n");
 		break;
 	case NL80211_IFTYPE_STATION:
-		bt_msr |= MSR_INFRA;
+		mode = MSR_INFRA;
 		ledaction = LED_CTL_LINK;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "Set Network type to STA!\n");
+			"Set Network type to STA!\n");
 		break;
 	case NL80211_IFTYPE_AP:
-		bt_msr |= MSR_AP;
+		mode = MSR_AP;
+		ledaction = LED_CTL_LINK;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "Set Network type to AP!\n");
+			"Set Network type to AP!\n");
 		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Network type %d not supported!\n",
-			 type);
+			"Network type %d not support!\n", type);
 		return 1;
-
+		break;
 	}
 
-	rtl_write_byte(rtlpriv, (MSR), bt_msr);
+	/* MSR_INFRA == Link in infrastructure network;
+	 * MSR_ADHOC == Link in ad hoc network;
+	 * Therefore, check link state is necessary.
+	 *
+	 * MSR_AP == AP mode; link state is not cared here.
+	 */
+	if (mode != MSR_AP &&
+	    rtlpriv->mac80211.link_state < MAC80211_LINKED) {
+		mode = MSR_NOLINK;
+		ledaction = LED_CTL_NO_LINK;
+	}
+	if (mode == MSR_NOLINK || mode == MSR_INFRA) {
+		_rtl8723e_stop_tx_beacon(hw);
+		_rtl8723e_enable_bcn_sub_func(hw);
+	} else if (mode == MSR_ADHOC || mode == MSR_AP) {
+		_rtl8723e_resume_tx_beacon(hw);
+		_rtl8723e_disable_bcn_sub_func(hw);
+	} else {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n",
+			 mode);
+	}
+
+	rtl_write_byte(rtlpriv, (MSR), bt_msr | mode);
 	rtlpriv->cfg->ops->led_control(hw, ledaction);
-	if ((bt_msr & MSR_MASK) == MSR_AP)
+	if (mode == MSR_AP)
 		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
 	else
 		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
 	return 0;
 }
 
-void rtl8723ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
+void rtl8723e_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 reg_rcr;
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u32 reg_rcr = rtlpci->receive_config;
 
 	if (rtlpriv->psc.rfpwr_state != ERFON)
 		return;
 
-	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
-
-	if (check_bssid == true) {
+	if (check_bssid) {
 		reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
 					      (u8 *)(&reg_rcr));
-		_rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(4));
-	} else if (check_bssid == false) {
+		_rtl8723e_set_bcn_ctrl_reg(hw, 0, BIT(4));
+	} else if (!check_bssid) {
 		reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN));
-		_rtl8723ae_set_bcn_ctrl_reg(hw, BIT(4), 0);
+		_rtl8723e_set_bcn_ctrl_reg(hw, BIT(4), 0);
 		rtlpriv->cfg->ops->set_hw_reg(hw,
-			HW_VAR_RCR, (u8 *) (&reg_rcr));
+			HW_VAR_RCR, (u8 *)(&reg_rcr));
 	}
 }
 
-int rtl8723ae_set_network_type(struct ieee80211_hw *hw,
-			       enum nl80211_iftype type)
+int rtl8723e_set_network_type(struct ieee80211_hw *hw,
+			      enum nl80211_iftype type)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-	if (_rtl8723ae_set_media_status(hw, type))
+	if (_rtl8723e_set_media_status(hw, type))
 		return -EOPNOTSUPP;
 
 	if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
 		if (type != NL80211_IFTYPE_AP)
-			rtl8723ae_set_check_bssid(hw, true);
+			rtl8723e_set_check_bssid(hw, true);
 	} else {
-		rtl8723ae_set_check_bssid(hw, false);
+		rtl8723e_set_check_bssid(hw, false);
 	}
+
 	return 0;
 }
 
-/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */
-void rtl8723ae_set_qos(struct ieee80211_hw *hw, int aci)
+/* don't set REG_EDCA_BE_PARAM here
+ * because mac80211 will send pkt when scan
+ */
+void rtl8723e_set_qos(struct ieee80211_hw *hw, int aci)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
@@ -1166,7 +1245,6 @@
 		rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
 		break;
 	case AC0_BE:
-		/* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4ac_param); */
 		break;
 	case AC2_VI:
 		rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322);
@@ -1180,7 +1258,19 @@
 	}
 }
 
-void rtl8723ae_enable_interrupt(struct ieee80211_hw *hw)
+static void rtl8723e_clear_interrupt(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 tmp;
+
+	tmp = rtl_read_dword(rtlpriv, REG_HISR);
+	rtl_write_dword(rtlpriv, REG_HISR, tmp);
+
+	tmp = rtl_read_dword(rtlpriv, REG_HISRE);
+	rtl_write_dword(rtlpriv, REG_HISRE, tmp);
+}
+
+void rtl8723e_enable_interrupt(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@@ -1190,37 +1280,39 @@
 	rtlpci->irq_enabled = true;
 }
 
-void rtl8723ae_disable_interrupt(struct ieee80211_hw *hw)
+void rtl8723e_disable_interrupt(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-
+	rtl8723e_clear_interrupt(hw);/*clear it here first*/
 	rtl_write_dword(rtlpriv, 0x3a8, IMR8190_DISABLED);
 	rtl_write_dword(rtlpriv, 0x3ac, IMR8190_DISABLED);
 	rtlpci->irq_enabled = false;
-	synchronize_irq(rtlpci->pdev->irq);
+	/*synchronize_irq(rtlpci->pdev->irq);*/
 }
 
-static void _rtl8723ae_poweroff_adapter(struct ieee80211_hw *hw)
+static void _rtl8723e_poweroff_adapter(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	u8 u1tmp;
+	u8 u1b_tmp;
 
 	/* Combo (PCIe + USB) Card and PCIe-MF Card */
 	/* 1. Run LPS WL RFOFF flow */
 	rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
-		PWR_INTF_PCI_MSK, Rtl8723_NIC_LPS_ENTER_FLOW);
+				 PWR_INTF_PCI_MSK, Rtl8723_NIC_LPS_ENTER_FLOW);
 
 	/* 2. 0x1F[7:0] = 0 */
 	/* turn off RF */
 	rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00);
-	if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && rtlhal->fw_ready)
+	if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) &&
+	    rtlhal->fw_ready) {
 		rtl8723ae_firmware_selfreset(hw);
+	}
 
 	/* Reset MCU. Suggested by Filen. */
-	u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
-	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1tmp & (~BIT(2))));
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
 
 	/* g.	MCUFWDL 0x80[1:0]=0	 */
 	/* reset MCU ready status */
@@ -1231,39 +1323,38 @@
 		PWR_INTF_PCI_MSK, Rtl8723_NIC_DISABLE_FLOW);
 
 	/* Reset MCU IO Wrapper */
-	u1tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
-	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1tmp & (~BIT(0))));
-	u1tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
-	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, u1tmp | BIT(0));
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, u1b_tmp | BIT(0));
 
 	/* 7. RSV_CTRL 0x1C[7:0] = 0x0E */
 	/* lock ISO/CLK/Power control register */
 	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e);
 }
 
-void rtl8723ae_card_disable(struct ieee80211_hw *hw)
+void rtl8723e_card_disable(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	enum nl80211_iftype opmode;
 
 	mac->link_state = MAC80211_NOLINK;
 	opmode = NL80211_IFTYPE_UNSPECIFIED;
-	_rtl8723ae_set_media_status(hw, opmode);
-	if (rtlpci->driver_is_goingto_unload ||
+	_rtl8723e_set_media_status(hw, opmode);
+	if (rtlpriv->rtlhal.driver_is_goingto_unload ||
 	    ppsc->rfoff_reason > RF_CHANGE_BY_PS)
 		rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
 	RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
-	_rtl8723ae_poweroff_adapter(hw);
+	_rtl8723e_poweroff_adapter(hw);
 
 	/* after power off we should do iqk again */
 	rtlpriv->phy.iqk_initialized = false;
 }
 
-void rtl8723ae_interrupt_recognized(struct ieee80211_hw *hw,
-				    u32 *p_inta, u32 *p_intb)
+void rtl8723e_interrupt_recognized(struct ieee80211_hw *hw,
+				   u32 *p_inta, u32 *p_intb)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@@ -1272,7 +1363,7 @@
 	rtl_write_dword(rtlpriv, 0x3a0, *p_inta);
 }
 
-void rtl8723ae_set_beacon_related_registers(struct ieee80211_hw *hw)
+void rtl8723e_set_beacon_related_registers(struct ieee80211_hw *hw)
 {
 
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1281,17 +1372,17 @@
 
 	bcn_interval = mac->beacon_interval;
 	atim_window = 2;	/*FIX MERGE */
-	rtl8723ae_disable_interrupt(hw);
+	rtl8723e_disable_interrupt(hw);
 	rtl_write_word(rtlpriv, REG_ATIMWND, atim_window);
 	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
 	rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f);
 	rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18);
 	rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18);
 	rtl_write_byte(rtlpriv, 0x606, 0x30);
-	rtl8723ae_enable_interrupt(hw);
+	rtl8723e_enable_interrupt(hw);
 }
 
-void rtl8723ae_set_beacon_interval(struct ieee80211_hw *hw)
+void rtl8723e_set_beacon_interval(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -1299,13 +1390,13 @@
 
 	RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
 		 "beacon_interval:%d\n", bcn_interval);
-	rtl8723ae_disable_interrupt(hw);
+	rtl8723e_disable_interrupt(hw);
 	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
-	rtl8723ae_enable_interrupt(hw);
+	rtl8723e_enable_interrupt(hw);
 }
 
-void rtl8723ae_update_interrupt_mask(struct ieee80211_hw *hw,
-				     u32 add_msr, u32 rm_msr)
+void rtl8723e_update_interrupt_mask(struct ieee80211_hw *hw,
+				    u32 add_msr, u32 rm_msr)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@@ -1317,11 +1408,11 @@
 		rtlpci->irq_mask[0] |= add_msr;
 	if (rm_msr)
 		rtlpci->irq_mask[0] &= (~rm_msr);
-	rtl8723ae_disable_interrupt(hw);
-	rtl8723ae_enable_interrupt(hw);
+	rtl8723e_disable_interrupt(hw);
+	rtl8723e_enable_interrupt(hw);
 }
 
-static u8 _rtl8723ae_get_chnl_group(u8 chnl)
+static u8 _rtl8723e_get_chnl_group(u8 chnl)
 {
 	u8 group;
 
@@ -1334,9 +1425,9 @@
 	return group;
 }
 
-static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
-						   bool autoload_fail,
-						   u8 *hwinfo)
+static void _rtl8723e_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
+						  bool autoload_fail,
+						  u8 *hwinfo)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
@@ -1346,19 +1437,14 @@
 	for (rf_path = 0; rf_path < 1; rf_path++) {
 		for (i = 0; i < 3; i++) {
 			if (!autoload_fail) {
-				rtlefuse->eeprom_chnlarea_txpwr_cck
-				    [rf_path][i] =
+				rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][i] =
 				    hwinfo[EEPROM_TXPOWERCCK + rf_path * 3 + i];
-				rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
-				    [rf_path][i] =
-				    hwinfo[EEPROM_TXPOWERHT40_1S + rf_path *
-				    3 + i];
+				rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] =
+				    hwinfo[EEPROM_TXPOWERHT40_1S + rf_path * 3 + i];
 			} else {
-				rtlefuse->eeprom_chnlarea_txpwr_cck
-				    [rf_path][i] =
+				rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][i] =
 				    EEPROM_DEFAULT_TXPOWERLEVEL;
-				rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
-				    [rf_path][i] =
+				rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] =
 				    EEPROM_DEFAULT_TXPOWERLEVEL;
 			}
 		}
@@ -1379,43 +1465,43 @@
 		for (i = 0; i < 3; i++)
 			RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
 				"RF(%d) EEPROM CCK Area(%d) = 0x%x\n", rf_path,
-				i, rtlefuse->eeprom_chnlarea_txpwr_cck
-				[rf_path][i]);
+				 i, rtlefuse->eeprom_chnlarea_txpwr_cck
+					[rf_path][i]);
 	for (rf_path = 0; rf_path < 2; rf_path++)
 		for (i = 0; i < 3; i++)
 			RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
 				"RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n",
 				rf_path, i,
 				rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
-				[rf_path][i]);
+					[rf_path][i]);
 	for (rf_path = 0; rf_path < 2; rf_path++)
 		for (i = 0; i < 3; i++)
 			RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
 				"RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n",
-				rf_path, i,
-				rtlefuse->eprom_chnl_txpwr_ht40_2sdf
-				[rf_path][i]);
+				 rf_path, i,
+				 rtlefuse->eprom_chnl_txpwr_ht40_2sdf
+					[rf_path][i]);
 
 	for (rf_path = 0; rf_path < 2; rf_path++) {
 		for (i = 0; i < 14; i++) {
-			index = _rtl8723ae_get_chnl_group((u8) i);
+			index = _rtl8723e_get_chnl_group((u8)i);
 
 			rtlefuse->txpwrlevel_cck[rf_path][i] =
 				rtlefuse->eeprom_chnlarea_txpwr_cck
-							[rf_path][index];
+					[rf_path][index];
 			rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
 				rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
-							[rf_path][index];
+					[rf_path][index];
 
 			if ((rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
-			    [rf_path][index] -
-			    rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path]
-			    [index]) > 0) {
-				rtlefuse->txpwrlevel_ht40_2s[rf_path][i] =
-					rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
 					[rf_path][index] -
-					rtlefuse->eprom_chnl_txpwr_ht40_2sdf
-					[rf_path][index];
+			     rtlefuse->eprom_chnl_txpwr_ht40_2sdf
+					[rf_path][index]) > 0) {
+				rtlefuse->txpwrlevel_ht40_2s[rf_path][i] =
+				  rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
+				  [rf_path][index] -
+				  rtlefuse->eprom_chnl_txpwr_ht40_2sdf
+				  [rf_path][index];
 			} else {
 				rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0;
 			}
@@ -1423,8 +1509,8 @@
 
 		for (i = 0; i < 14; i++) {
 			RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
-				"RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = "
-				"[0x%x / 0x%x / 0x%x]\n", rf_path, i,
+				"RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = [0x%x / 0x%x / 0x%x]\n",
+				rf_path, i,
 				rtlefuse->txpwrlevel_cck[rf_path][i],
 				rtlefuse->txpwrlevel_ht40_1s[rf_path][i],
 				rtlefuse->txpwrlevel_ht40_2s[rf_path][i]);
@@ -1445,22 +1531,20 @@
 
 	for (rf_path = 0; rf_path < 2; rf_path++) {
 		for (i = 0; i < 14; i++) {
-			index = _rtl8723ae_get_chnl_group((u8) i);
+			index = _rtl8723e_get_chnl_group((u8)i);
 
 			if (rf_path == RF90_PATH_A) {
 				rtlefuse->pwrgroup_ht20[rf_path][i] =
-				    (rtlefuse->eeprom_pwrlimit_ht20[index] &
-				    0xf);
+				  (rtlefuse->eeprom_pwrlimit_ht20[index] & 0xf);
 				rtlefuse->pwrgroup_ht40[rf_path][i] =
-				    (rtlefuse->eeprom_pwrlimit_ht40[index] &
-				    0xf);
+				  (rtlefuse->eeprom_pwrlimit_ht40[index] & 0xf);
 			} else if (rf_path == RF90_PATH_B) {
 				rtlefuse->pwrgroup_ht20[rf_path][i] =
-				    ((rtlefuse->eeprom_pwrlimit_ht20[index] &
-				    0xf0) >> 4);
+				  ((rtlefuse->eeprom_pwrlimit_ht20[index] &
+				   0xf0) >> 4);
 				rtlefuse->pwrgroup_ht40[rf_path][i] =
-				    ((rtlefuse->eeprom_pwrlimit_ht40[index] &
-				    0xf0) >> 4);
+				  ((rtlefuse->eeprom_pwrlimit_ht40[index] &
+				   0xf0) >> 4);
 			}
 
 			RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
@@ -1473,7 +1557,7 @@
 	}
 
 	for (i = 0; i < 14; i++) {
-		index = _rtl8723ae_get_chnl_group((u8) i);
+		index = _rtl8723e_get_chnl_group((u8)i);
 
 		if (!autoload_fail)
 			tempval = hwinfo[EEPROM_TXPOWERHT20DIFF + index];
@@ -1490,7 +1574,7 @@
 		if (rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] & BIT(3))
 			rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] |= 0xF0;
 
-		index = _rtl8723ae_get_chnl_group((u8) i);
+		index = _rtl8723e_get_chnl_group((u8)i);
 
 		if (!autoload_fail)
 			tempval = hwinfo[EEPROM_TXPOWER_OFDMDIFF + index];
@@ -1508,19 +1592,19 @@
 	for (i = 0; i < 14; i++)
 		RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
 			"RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i,
-			rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]);
+			 rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]);
 	for (i = 0; i < 14; i++)
 		RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
 			"RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i,
-			rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]);
+			 rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]);
 	for (i = 0; i < 14; i++)
 		RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
 			"RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i,
-			rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]);
+			 rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]);
 	for (i = 0; i < 14; i++)
 		RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
 			"RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i,
-			rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
+			 rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
 
 	if (!autoload_fail)
 		rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7);
@@ -1533,10 +1617,11 @@
 		rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A];
 	else
 		rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI;
+
 	RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
 		"TSSI_A = 0x%x, TSSI_B = 0x%x\n",
-		rtlefuse->eeprom_tssi[RF90_PATH_A],
-		rtlefuse->eeprom_tssi[RF90_PATH_B]);
+		 rtlefuse->eeprom_tssi[RF90_PATH_A],
+		 rtlefuse->eeprom_tssi[RF90_PATH_B]);
 
 	if (!autoload_fail)
 		tempval = hwinfo[EEPROM_THERMAL_METER];
@@ -1552,8 +1637,8 @@
 		"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
 }
 
-static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
-					 bool pseudo_test)
+static void _rtl8723e_read_adapter_info(struct ieee80211_hw *hw,
+					bool b_pseudo_test)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
@@ -1562,7 +1647,7 @@
 	u8 hwinfo[HWSET_MAX_SIZE];
 	u16 eeprom_id;
 
-	if (pseudo_test) {
+	if (b_pseudo_test) {
 		/* need add */
 		return;
 	}
@@ -1576,7 +1661,7 @@
 			 "RTL819X Not boot from eeprom, check it !!");
 	}
 
-	RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"),
+	RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP\n",
 		      hwinfo, HWSET_MAX_SIZE);
 
 	eeprom_id = *((u16 *)&hwinfo[0]);
@@ -1589,13 +1674,13 @@
 		rtlefuse->autoload_failflag = false;
 	}
 
-	if (rtlefuse->autoload_failflag == true)
+	if (rtlefuse->autoload_failflag)
 		return;
 
-	rtlefuse->eeprom_vid = *(u16 *) &hwinfo[EEPROM_VID];
-	rtlefuse->eeprom_did = *(u16 *) &hwinfo[EEPROM_DID];
-	rtlefuse->eeprom_svid = *(u16 *) &hwinfo[EEPROM_SVID];
-	rtlefuse->eeprom_smid = *(u16 *) &hwinfo[EEPROM_SMID];
+	rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID];
+	rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID];
+	rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID];
+	rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID];
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 		 "EEPROMId = 0x%4x\n", eeprom_id);
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
@@ -1609,16 +1694,16 @@
 
 	for (i = 0; i < 6; i += 2) {
 		usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
-		*((u16 *) (&rtlefuse->dev_addr[i])) = usvalue;
+		*((u16 *)(&rtlefuse->dev_addr[i])) = usvalue;
 	}
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 		 "dev_addr: %pM\n", rtlefuse->dev_addr);
 
-	_rtl8723ae_read_txpower_info_from_hwpg(hw,
-			rtlefuse->autoload_failflag, hwinfo);
+	_rtl8723e_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag,
+					      hwinfo);
 
-	rtl8723ae_read_bt_coexist_info_from_hwpg(hw,
+	rtl8723e_read_bt_coexist_info_from_hwpg(hw,
 			rtlefuse->autoload_failflag, hwinfo);
 
 	rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
@@ -1644,6 +1729,14 @@
 				    CHK_SVID_SMID(0x10EC, 0x6178) ||
 				    CHK_SVID_SMID(0x10EC, 0x6179) ||
 				    CHK_SVID_SMID(0x10EC, 0x6180) ||
+				    CHK_SVID_SMID(0x10EC, 0x7151) ||
+				    CHK_SVID_SMID(0x10EC, 0x7152) ||
+				    CHK_SVID_SMID(0x10EC, 0x7154) ||
+				    CHK_SVID_SMID(0x10EC, 0x7155) ||
+				    CHK_SVID_SMID(0x10EC, 0x7177) ||
+				    CHK_SVID_SMID(0x10EC, 0x7178) ||
+				    CHK_SVID_SMID(0x10EC, 0x7179) ||
+				    CHK_SVID_SMID(0x10EC, 0x7180) ||
 				    CHK_SVID_SMID(0x10EC, 0x8151) ||
 				    CHK_SVID_SMID(0x10EC, 0x8152) ||
 				    CHK_SVID_SMID(0x10EC, 0x8154) ||
@@ -1671,7 +1764,10 @@
 					 CHK_SVID_SMID(0x10EC, 0x7193) ||
 					 CHK_SVID_SMID(0x10EC, 0x8191) ||
 					 CHK_SVID_SMID(0x10EC, 0x8192) ||
-					 CHK_SVID_SMID(0x10EC, 0x8193))
+					 CHK_SVID_SMID(0x10EC, 0x8193) ||
+					 CHK_SVID_SMID(0x10EC, 0x9191) ||
+					 CHK_SVID_SMID(0x10EC, 0x9192) ||
+					 CHK_SVID_SMID(0x10EC, 0x9193))
 					rtlhal->oem_id = RT_CID_819X_SAMSUNG;
 				else if (CHK_SVID_SMID(0x10EC, 0x8195) ||
 					 CHK_SVID_SMID(0x10EC, 0x9195) ||
@@ -1728,7 +1824,7 @@
 				else
 					rtlhal->oem_id = RT_CID_DEFAULT;
 			} else {
-					rtlhal->oem_id = RT_CID_DEFAULT;
+				rtlhal->oem_id = RT_CID_DEFAULT;
 			}
 			break;
 		case EEPROM_CID_TOSHIBA:
@@ -1750,18 +1846,31 @@
 	}
 }
 
-static void _rtl8723ae_hal_customized_behavior(struct ieee80211_hw *hw)
+static void _rtl8723e_hal_customized_behavior(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
 	pcipriv->ledctl.led_opendrain = true;
+	switch (rtlhal->oem_id) {
+	case RT_CID_819X_HP:
+		pcipriv->ledctl.led_opendrain = true;
+		break;
+	case RT_CID_819X_LENOVO:
+	case RT_CID_DEFAULT:
+	case RT_CID_TOSHIBA:
+	case RT_CID_CCX:
+	case RT_CID_819X_ACER:
+	case RT_CID_WHQL:
+	default:
+		break;
+	}
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 		 "RT Customized ID: 0x%02X\n", rtlhal->oem_id);
 }
 
-void rtl8723ae_read_eeprom_info(struct ieee80211_hw *hw)
+void rtl8723e_read_eeprom_info(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
@@ -1774,7 +1883,7 @@
 	value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0);
 	rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST], value32);
 
-	rtlhal->version = _rtl8723ae_read_chip_version(hw);
+	rtlhal->version = _rtl8723e_read_chip_version(hw);
 
 	if (get_rf_type(rtlphy) == RF_1T1R)
 		rtlpriv->dm.rfpath_rxenable[0] = true;
@@ -1782,7 +1891,7 @@
 		rtlpriv->dm.rfpath_rxenable[0] =
 		    rtlpriv->dm.rfpath_rxenable[1] = true;
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n",
-		 rtlhal->version);
+						rtlhal->version);
 
 	tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR);
 	if (tmp_u1b & BIT(4)) {
@@ -1795,33 +1904,34 @@
 	if (tmp_u1b & BIT(5)) {
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
 		rtlefuse->autoload_failflag = false;
-		_rtl8723ae_read_adapter_info(hw, false);
+		_rtl8723e_read_adapter_info(hw, false);
 	} else {
 		rtlefuse->autoload_failflag = true;
-		_rtl8723ae_read_adapter_info(hw, false);
+		_rtl8723e_read_adapter_info(hw, false);
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n");
 	}
-	_rtl8723ae_hal_customized_behavior(hw);
+	_rtl8723e_hal_customized_behavior(hw);
 }
 
-static void rtl8723ae_update_hal_rate_table(struct ieee80211_hw *hw,
-					    struct ieee80211_sta *sta)
+static void rtl8723e_update_hal_rate_table(struct ieee80211_hw *hw,
+					   struct ieee80211_sta *sta)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u32 ratr_value;
 	u8 ratr_index = 0;
-	u8 nmode = mac->ht_enable;
-	u8 mimo_ps = IEEE80211_SMPS_OFF;
+	u8 b_nmode = mac->ht_enable;
+	u16 shortgi_rate;
+	u32 tmp_ratr_value;
 	u8 curtxbw_40mhz = mac->bw_40;
 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 				1 : 0;
 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
 				1 : 0;
 	enum wireless_mode wirelessmode = mac->mode;
+	u32 ratr_mask;
 
 	if (rtlhal->current_bandtype == BAND_ON_5G)
 		ratr_value = sta->supp_rates[1] << 4;
@@ -1830,7 +1940,7 @@
 	if (mac->opmode == NL80211_IFTYPE_ADHOC)
 		ratr_value = 0xfff;
 	ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
-		       sta->ht_cap.mcs.rx_mask[0] << 12);
+			sta->ht_cap.mcs.rx_mask[0] << 12);
 	switch (wirelessmode) {
 	case WIRELESS_MODE_B:
 		if (ratr_value & 0x0000000c)
@@ -1843,20 +1953,14 @@
 		break;
 	case WIRELESS_MODE_N_24G:
 	case WIRELESS_MODE_N_5G:
-		nmode = 1;
-		if (mimo_ps == IEEE80211_SMPS_STATIC) {
-			ratr_value &= 0x0007F005;
-		} else {
-			u32 ratr_mask;
+		b_nmode = 1;
+		if (get_rf_type(rtlphy) == RF_1T2R ||
+		    get_rf_type(rtlphy) == RF_1T1R)
+			ratr_mask = 0x000ff005;
+		else
+			ratr_mask = 0x0f0ff005;
 
-			if (get_rf_type(rtlphy) == RF_1T2R ||
-			    get_rf_type(rtlphy) == RF_1T1R)
-				ratr_mask = 0x000ff005;
-			else
-				ratr_mask = 0x0f0ff005;
-
-			ratr_value &= ratr_mask;
-		}
+		ratr_value &= ratr_mask;
 		break;
 	default:
 		if (rtlphy->rf_type == RF_1T2R)
@@ -1867,19 +1971,30 @@
 		break;
 	}
 
-	if ((pcipriv->bt_coexist.bt_coexistence) &&
-	    (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) &&
-	    (pcipriv->bt_coexist.bt_cur_state) &&
-	    (pcipriv->bt_coexist.bt_ant_isolation) &&
-	    ((pcipriv->bt_coexist.bt_service == BT_SCO) ||
-	    (pcipriv->bt_coexist.bt_service == BT_BUSY)))
+	if ((rtlpriv->btcoexist.bt_coexistence) &&
+	    (rtlpriv->btcoexist.bt_coexist_type == BT_CSR_BC4) &&
+	    (rtlpriv->btcoexist.bt_cur_state) &&
+	    (rtlpriv->btcoexist.bt_ant_isolation) &&
+	    ((rtlpriv->btcoexist.bt_service == BT_SCO) ||
+	    (rtlpriv->btcoexist.bt_service == BT_BUSY)))
 		ratr_value &= 0x0fffcfc0;
 	else
 		ratr_value &= 0x0FFFFFFF;
 
-	if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) ||
-	   (!curtxbw_40mhz && curshortgi_20mhz)))
+	if (b_nmode &&
+	    ((curtxbw_40mhz && curshortgi_40mhz) ||
+	     (!curtxbw_40mhz && curshortgi_20mhz))) {
 		ratr_value |= 0x10000000;
+		tmp_ratr_value = (ratr_value >> 12);
+
+		for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
+			if ((1 << shortgi_rate) & tmp_ratr_value)
+				break;
+		}
+
+		shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
+		    (shortgi_rate << 4) | (shortgi_rate);
+	}
 
 	rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
 
@@ -1887,8 +2002,9 @@
 		 "%x\n", rtl_read_dword(rtlpriv, REG_ARFR0));
 }
 
-static void rtl8723ae_update_hal_rate_mask(struct ieee80211_hw *hw,
-		struct ieee80211_sta *sta, u8 rssi_level)
+static void rtl8723e_update_hal_rate_mask(struct ieee80211_hw *hw,
+					  struct ieee80211_sta *sta,
+					  u8 rssi_level)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -1897,7 +2013,8 @@
 	struct rtl_sta_info *sta_entry = NULL;
 	u32 ratr_bitmap;
 	u8 ratr_index;
-	u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
+	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+				? 1 : 0;
 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
 				1 : 0;
 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
@@ -1906,9 +2023,9 @@
 	bool shortgi = false;
 	u8 rate_mask[5];
 	u8 macid = 0;
-	u8 mimo_ps = IEEE80211_SMPS_OFF;
+	/*u8 mimo_ps = IEEE80211_SMPS_OFF;*/
 
-	sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+	sta_entry = (struct rtl_sta_info *)sta->drv_priv;
 	wirelessmode = sta_entry->wireless_mode;
 	if (mac->opmode == NL80211_IFTYPE_STATION)
 		curtxbw_40mhz = mac->bw_40;
@@ -1943,54 +2060,44 @@
 			ratr_bitmap &= 0x00000ff5;
 		break;
 	case WIRELESS_MODE_A:
-		ratr_index = RATR_INX_WIRELESS_A;
+		ratr_index = RATR_INX_WIRELESS_G;
 		ratr_bitmap &= 0x00000ff0;
 		break;
 	case WIRELESS_MODE_N_24G:
 	case WIRELESS_MODE_N_5G:
 		ratr_index = RATR_INX_WIRELESS_NGB;
-
-		if (mimo_ps == IEEE80211_SMPS_STATIC) {
-			if (rssi_level == 1)
-				ratr_bitmap &= 0x00070000;
-			else if (rssi_level == 2)
-				ratr_bitmap &= 0x0007f000;
-			else
-				ratr_bitmap &= 0x0007f005;
-		} else {
-			if (rtlphy->rf_type == RF_1T2R ||
-			    rtlphy->rf_type == RF_1T1R) {
-				if (curtxbw_40mhz) {
-					if (rssi_level == 1)
-						ratr_bitmap &= 0x000f0000;
-					else if (rssi_level == 2)
-						ratr_bitmap &= 0x000ff000;
-					else
-						ratr_bitmap &= 0x000ff015;
-				} else {
-					if (rssi_level == 1)
-						ratr_bitmap &= 0x000f0000;
-					else if (rssi_level == 2)
-						ratr_bitmap &= 0x000ff000;
-					else
-						ratr_bitmap &= 0x000ff005;
-				}
+		if (rtlphy->rf_type == RF_1T2R ||
+		    rtlphy->rf_type == RF_1T1R) {
+			if (curtxbw_40mhz) {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x000f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x000ff000;
+				else
+					ratr_bitmap &= 0x000ff015;
 			} else {
-				if (curtxbw_40mhz) {
-					if (rssi_level == 1)
-						ratr_bitmap &= 0x0f0f0000;
-					else if (rssi_level == 2)
-						ratr_bitmap &= 0x0f0ff000;
-					else
-						ratr_bitmap &= 0x0f0ff015;
-				} else {
-					if (rssi_level == 1)
-						ratr_bitmap &= 0x0f0f0000;
-					else if (rssi_level == 2)
-						ratr_bitmap &= 0x0f0ff000;
-					else
-						ratr_bitmap &= 0x0f0ff005;
-				}
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x000f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x000ff000;
+				else
+					ratr_bitmap &= 0x000ff005;
+			}
+		} else {
+			if (curtxbw_40mhz) {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x0f0f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x0f0ff000;
+				else
+					ratr_bitmap &= 0x0f0ff015;
+			} else {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x0f0f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x0f0ff000;
+				else
+					ratr_bitmap &= 0x0f0ff005;
 			}
 		}
 
@@ -2015,30 +2122,30 @@
 
 	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
 		 "ratr_bitmap :%x\n", ratr_bitmap);
-	/* convert ratr_bitmap to le byte array */
-	rate_mask[0] = ratr_bitmap;
-	rate_mask[1] = (ratr_bitmap >>= 8);
-	rate_mask[2] = (ratr_bitmap >>= 8);
-	rate_mask[3] = ((ratr_bitmap >> 8) & 0x0f) | (ratr_index << 4);
+	*(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
+			     (ratr_index << 28);
 	rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
 	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
-		 "Rate_index:%x, ratr_bitmap: %*phC\n",
-		 ratr_index, 5, rate_mask);
-	rtl8723ae_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask);
+		 "Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x\n",
+		  ratr_index, ratr_bitmap,
+		  rate_mask[0], rate_mask[1],
+		  rate_mask[2], rate_mask[3],
+		  rate_mask[4]);
+	rtl8723e_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask);
 }
 
-void rtl8723ae_update_hal_rate_tbl(struct ieee80211_hw *hw,
-		struct ieee80211_sta *sta, u8 rssi_level)
+void rtl8723e_update_hal_rate_tbl(struct ieee80211_hw *hw,
+				  struct ieee80211_sta *sta, u8 rssi_level)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	if (rtlpriv->dm.useramask)
-		rtl8723ae_update_hal_rate_mask(hw, sta, rssi_level);
+		rtl8723e_update_hal_rate_mask(hw, sta, rssi_level);
 	else
-		rtl8723ae_update_hal_rate_table(hw, sta);
+		rtl8723e_update_hal_rate_table(hw, sta);
 }
 
-void rtl8723ae_update_channel_access_setting(struct ieee80211_hw *hw)
+void rtl8723e_update_channel_access_setting(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -2052,14 +2159,14 @@
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
 }
 
-bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
+bool rtl8723e_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	enum rf_pwrstate e_rfpowerstate_toset;
+	enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;
 	u8 u1tmp;
-	bool actuallyset = false;
+	bool b_actuallyset = false;
 
 	if (rtlpriv->rtlhal.being_init_adapter)
 		return false;
@@ -2076,6 +2183,8 @@
 		spin_unlock(&rtlpriv->locks.rf_ps_lock);
 	}
 
+	cur_rfstate = ppsc->rfpwr_state;
+
 	rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2,
 		       rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2)&~(BIT(1)));
 
@@ -2086,24 +2195,23 @@
 	else
 		e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFON : ERFOFF;
 
-	if ((ppsc->hwradiooff == true) && (e_rfpowerstate_toset == ERFON)) {
+	if (ppsc->hwradiooff && (e_rfpowerstate_toset == ERFON)) {
 		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 			 "GPIOChangeRF  - HW Radio ON, RF ON\n");
 
 		e_rfpowerstate_toset = ERFON;
 		ppsc->hwradiooff = false;
-		actuallyset = true;
-	} else if ((ppsc->hwradiooff == false)
-		   && (e_rfpowerstate_toset == ERFOFF)) {
+		b_actuallyset = true;
+	} else if (!ppsc->hwradiooff && (e_rfpowerstate_toset == ERFOFF)) {
 		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 			 "GPIOChangeRF  - HW Radio OFF, RF OFF\n");
 
 		e_rfpowerstate_toset = ERFOFF;
 		ppsc->hwradiooff = true;
-		actuallyset = true;
+		b_actuallyset = true;
 	}
 
-	if (actuallyset) {
+	if (b_actuallyset) {
 		spin_lock(&rtlpriv->locks.rf_ps_lock);
 		ppsc->rfchange_inprogress = false;
 		spin_unlock(&rtlpriv->locks.rf_ps_lock);
@@ -2118,11 +2226,12 @@
 
 	*valid = 1;
 	return !ppsc->hwradiooff;
+
 }
 
-void rtl8723ae_set_key(struct ieee80211_hw *hw, u32 key_index,
-		       u8 *p_macaddr, bool is_group, u8 enc_algo,
-		       bool is_wepkey, bool clear_all)
+void rtl8723e_set_key(struct ieee80211_hw *hw, u32 key_index,
+		      u8 *p_macaddr, bool is_group, u8 enc_algo,
+		      bool is_wepkey, bool clear_all)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -2130,6 +2239,7 @@
 	u8 *macaddr = p_macaddr;
 	u32 entry_id = 0;
 	bool is_pairwise = false;
+
 	static u8 cam_const_addr[4][6] = {
 		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
 		{0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
@@ -2157,6 +2267,7 @@
 				rtlpriv->sec.key_len[idx] = 0;
 			}
 		}
+
 	} else {
 		switch (enc_algo) {
 		case WEP40_ENCRYPTION:
@@ -2172,8 +2283,8 @@
 			enc_algo = CAM_AES;
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
 			enc_algo = CAM_TKIP;
 			break;
 		}
@@ -2187,8 +2298,8 @@
 				entry_id = key_index;
 			} else {
 				if (mac->opmode == NL80211_IFTYPE_AP) {
-					entry_id = rtl_cam_get_free_entry(hw,
-								macaddr);
+					entry_id =
+					  rtl_cam_get_free_entry(hw, p_macaddr);
 					if (entry_id >=  TOTAL_CAM_ENTRY) {
 						RT_TRACE(rtlpriv, COMP_SEC,
 							 DBG_EMERG,
@@ -2219,22 +2330,22 @@
 					 "set Pairwiase key\n");
 
 				rtl_cam_add_one_entry(hw, macaddr, key_index,
-					entry_id, enc_algo,
-					CAM_CONFIG_NO_USEDK,
-					rtlpriv->sec.key_buf[key_index]);
+						      entry_id, enc_algo,
+						      CAM_CONFIG_NO_USEDK,
+						      rtlpriv->sec.key_buf[key_index]);
 			} else {
 				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 					 "set group key\n");
 
 				if (mac->opmode == NL80211_IFTYPE_ADHOC) {
 					rtl_cam_add_one_entry(hw,
-						rtlefuse->dev_addr,
-						PAIRWISE_KEYIDX,
-						CAM_PAIRWISE_KEY_POSITION,
-						enc_algo,
-						CAM_CONFIG_NO_USEDK,
-						rtlpriv->sec.key_buf
-						[entry_id]);
+							rtlefuse->dev_addr,
+							PAIRWISE_KEYIDX,
+							CAM_PAIRWISE_KEY_POSITION,
+							enc_algo,
+							CAM_CONFIG_NO_USEDK,
+							rtlpriv->sec.key_buf
+							[entry_id]);
 				}
 
 				rtl_cam_add_one_entry(hw, macaddr, key_index,
@@ -2247,45 +2358,43 @@
 	}
 }
 
-static void rtl8723ae_bt_var_init(struct ieee80211_hw *hw)
+static void rtl8723e_bt_var_init(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-	pcipriv->bt_coexist.bt_coexistence =
-					pcipriv->bt_coexist.eeprom_bt_coexist;
-	pcipriv->bt_coexist.bt_ant_num =
-					pcipriv->bt_coexist.eeprom_bt_ant_num;
-	pcipriv->bt_coexist.bt_coexist_type =
-					pcipriv->bt_coexist.eeprom_bt_type;
+	rtlpriv->btcoexist.bt_coexistence =
+		rtlpriv->btcoexist.eeprom_bt_coexist;
+	rtlpriv->btcoexist.bt_ant_num =
+		rtlpriv->btcoexist.eeprom_bt_ant_num;
+	rtlpriv->btcoexist.bt_coexist_type =
+		rtlpriv->btcoexist.eeprom_bt_type;
 
-		pcipriv->bt_coexist.bt_ant_isolation =
-				pcipriv->bt_coexist.eeprom_bt_ant_isol;
+	rtlpriv->btcoexist.bt_ant_isolation =
+		rtlpriv->btcoexist.eeprom_bt_ant_isol;
 
-	pcipriv->bt_coexist.bt_radio_shared_type =
-				pcipriv->bt_coexist.eeprom_bt_radio_shared;
+	rtlpriv->btcoexist.bt_radio_shared_type =
+		rtlpriv->btcoexist.eeprom_bt_radio_shared;
 
 	RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 		 "BT Coexistance = 0x%x\n",
-		 pcipriv->bt_coexist.bt_coexistence);
+		 rtlpriv->btcoexist.bt_coexistence);
 
-	if (pcipriv->bt_coexist.bt_coexistence) {
-		pcipriv->bt_coexist.bt_busy_traffic = false;
-		pcipriv->bt_coexist.bt_traffic_mode_set = false;
-		pcipriv->bt_coexist.bt_non_traffic_mode_set = false;
+	if (rtlpriv->btcoexist.bt_coexistence) {
+		rtlpriv->btcoexist.bt_busy_traffic = false;
+		rtlpriv->btcoexist.bt_traffic_mode_set = false;
+		rtlpriv->btcoexist.bt_non_traffic_mode_set = false;
 
-		pcipriv->bt_coexist.cstate = 0;
-		pcipriv->bt_coexist.previous_state = 0;
+		rtlpriv->btcoexist.cstate = 0;
+		rtlpriv->btcoexist.previous_state = 0;
 
-		if (pcipriv->bt_coexist.bt_ant_num == ANT_X2) {
+		if (rtlpriv->btcoexist.bt_ant_num == ANT_X2) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 				 "BlueTooth BT_Ant_Num = Antx2\n");
-		} else if (pcipriv->bt_coexist.bt_ant_num == ANT_X1) {
+		} else if (rtlpriv->btcoexist.bt_ant_num == ANT_X1) {
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 				 "BlueTooth BT_Ant_Num = Antx1\n");
 		}
-
-		switch (pcipriv->bt_coexist.bt_coexist_type) {
+		switch (rtlpriv->btcoexist.bt_coexist_type) {
 		case BT_2WIRE:
 			RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 				 "BlueTooth BT_CoexistType = BT_2Wire\n");
@@ -2317,20 +2426,19 @@
 		}
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 			 "BlueTooth BT_Ant_isolation = %d\n",
-			 pcipriv->bt_coexist.bt_ant_isolation);
+			 rtlpriv->btcoexist.bt_ant_isolation);
 		RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
 			 "BT_RadioSharedType = 0x%x\n",
-			 pcipriv->bt_coexist.bt_radio_shared_type);
-		pcipriv->bt_coexist.bt_active_zero_cnt = 0;
-		pcipriv->bt_coexist.cur_bt_disabled = false;
-		pcipriv->bt_coexist.pre_bt_disabled = false;
+			 rtlpriv->btcoexist.bt_radio_shared_type);
+		rtlpriv->btcoexist.bt_active_zero_cnt = 0;
+		rtlpriv->btcoexist.cur_bt_disabled = false;
+		rtlpriv->btcoexist.pre_bt_disabled = false;
 	}
 }
 
-void rtl8723ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
-					      bool auto_load_fail, u8 *hwinfo)
+void rtl8723e_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+					     bool auto_load_fail, u8 *hwinfo)
 {
-	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 value;
 	u32 tmpu_32;
@@ -2338,47 +2446,50 @@
 	if (!auto_load_fail) {
 		tmpu_32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL);
 		if (tmpu_32 & BIT(18))
-			pcipriv->bt_coexist.eeprom_bt_coexist = 1;
+			rtlpriv->btcoexist.eeprom_bt_coexist = 1;
 		else
-			pcipriv->bt_coexist.eeprom_bt_coexist = 0;
+			rtlpriv->btcoexist.eeprom_bt_coexist = 0;
 		value = hwinfo[RF_OPTION4];
-		pcipriv->bt_coexist.eeprom_bt_type = BT_RTL8723A;
-		pcipriv->bt_coexist.eeprom_bt_ant_num = (value & 0x1);
-		pcipriv->bt_coexist.eeprom_bt_ant_isol = ((value & 0x10) >> 4);
-		pcipriv->bt_coexist.eeprom_bt_radio_shared =
-				((value & 0x20) >> 5);
+		rtlpriv->btcoexist.eeprom_bt_type = BT_RTL8723A;
+		rtlpriv->btcoexist.eeprom_bt_ant_num = (value & 0x1);
+		rtlpriv->btcoexist.eeprom_bt_ant_isol = ((value & 0x10) >> 4);
+		rtlpriv->btcoexist.eeprom_bt_radio_shared =
+		  ((value & 0x20) >> 5);
 	} else {
-		pcipriv->bt_coexist.eeprom_bt_coexist = 0;
-		pcipriv->bt_coexist.eeprom_bt_type = BT_RTL8723A;
-		pcipriv->bt_coexist.eeprom_bt_ant_num = ANT_X2;
-		pcipriv->bt_coexist.eeprom_bt_ant_isol = 0;
-		pcipriv->bt_coexist.eeprom_bt_radio_shared = BT_RADIO_SHARED;
+		rtlpriv->btcoexist.eeprom_bt_coexist = 0;
+		rtlpriv->btcoexist.eeprom_bt_type = BT_RTL8723A;
+		rtlpriv->btcoexist.eeprom_bt_ant_num = ANT_X2;
+		rtlpriv->btcoexist.eeprom_bt_ant_isol = 0;
+		rtlpriv->btcoexist.eeprom_bt_radio_shared = BT_RADIO_SHARED;
 	}
 
-	rtl8723ae_bt_var_init(hw);
+	rtl8723e_bt_var_init(hw);
 }
 
-void rtl8723ae_bt_reg_init(struct ieee80211_hw *hw)
+void rtl8723e_bt_reg_init(struct ieee80211_hw *hw)
 {
-	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	/* 0:Low, 1:High, 2:From Efuse. */
-	pcipriv->bt_coexist.reg_bt_iso = 2;
+	rtlpriv->btcoexist.reg_bt_iso = 2;
 	/* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */
-	pcipriv->bt_coexist.reg_bt_sco = 3;
+	rtlpriv->btcoexist.reg_bt_sco = 3;
 	/* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
-	pcipriv->bt_coexist.reg_bt_sco = 0;
+	rtlpriv->btcoexist.reg_bt_sco = 0;
 }
 
+void rtl8723e_bt_hw_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-void rtl8723ae_bt_hw_init(struct ieee80211_hw *hw)
+	if (rtlpriv->cfg->ops->get_btc_status())
+		rtlpriv->btcoexist.btc_ops->btc_init_hw_config(rtlpriv);
+}
+
+void rtl8723e_suspend(struct ieee80211_hw *hw)
 {
 }
 
-void rtl8723ae_suspend(struct ieee80211_hw *hw)
-{
-}
-
-void rtl8723ae_resume(struct ieee80211_hw *hw)
+void rtl8723e_resume(struct ieee80211_hw *hw)
 {
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.h
index d3bc39f..32c1ace 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -34,38 +30,38 @@
 	((rtlefuse->eeprom_svid == (_val1)) &&			\
 	 (rtlefuse->eeprom_smid == (_val2)))
 
-void rtl8723ae_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
-void rtl8723ae_read_eeprom_info(struct ieee80211_hw *hw);
+void rtl8723e_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl8723e_read_eeprom_info(struct ieee80211_hw *hw);
 
-void rtl8723ae_interrupt_recognized(struct ieee80211_hw *hw,
-				    u32 *p_inta, u32 *p_intb);
-int rtl8723ae_hw_init(struct ieee80211_hw *hw);
-void rtl8723ae_card_disable(struct ieee80211_hw *hw);
-void rtl8723ae_enable_interrupt(struct ieee80211_hw *hw);
-void rtl8723ae_disable_interrupt(struct ieee80211_hw *hw);
-int rtl8723ae_set_network_type(struct ieee80211_hw *hw,
-			       enum nl80211_iftype type);
-void rtl8723ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
-void rtl8723ae_set_qos(struct ieee80211_hw *hw, int aci);
-void rtl8723ae_set_beacon_related_registers(struct ieee80211_hw *hw);
-void rtl8723ae_set_beacon_interval(struct ieee80211_hw *hw);
-void rtl8723ae_update_interrupt_mask(struct ieee80211_hw *hw,
-				     u32 add_msr, u32 rm_msr);
-void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
-void rtl8723ae_update_hal_rate_tbl(struct ieee80211_hw *hw,
-				   struct ieee80211_sta *sta, u8 rssi_level);
-void rtl8723ae_update_channel_access_setting(struct ieee80211_hw *hw);
-bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
-void rtl8723ae_enable_hw_security_config(struct ieee80211_hw *hw);
-void rtl8723ae_set_key(struct ieee80211_hw *hw, u32 key_index,
-		       u8 *p_macaddr, bool is_group, u8 enc_algo,
-		       bool is_wepkey, bool clear_all);
+void rtl8723e_interrupt_recognized(struct ieee80211_hw *hw,
+				   u32 *p_inta, u32 *p_intb);
+int rtl8723e_hw_init(struct ieee80211_hw *hw);
+void rtl8723e_card_disable(struct ieee80211_hw *hw);
+void rtl8723e_enable_interrupt(struct ieee80211_hw *hw);
+void rtl8723e_disable_interrupt(struct ieee80211_hw *hw);
+int rtl8723e_set_network_type(struct ieee80211_hw *hw,
+			      enum nl80211_iftype type);
+void rtl8723e_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
+void rtl8723e_set_qos(struct ieee80211_hw *hw, int aci);
+void rtl8723e_set_beacon_related_registers(struct ieee80211_hw *hw);
+void rtl8723e_set_beacon_interval(struct ieee80211_hw *hw);
+void rtl8723e_update_interrupt_mask(struct ieee80211_hw *hw,
+				    u32 add_msr, u32 rm_msr);
+void rtl8723e_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl8723e_update_hal_rate_tbl(struct ieee80211_hw *hw,
+				  struct ieee80211_sta *sta, u8 rssi_level);
+void rtl8723e_update_channel_access_setting(struct ieee80211_hw *hw);
+bool rtl8723e_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
+void rtl8723e_enable_hw_security_config(struct ieee80211_hw *hw);
+void rtl8723e_set_key(struct ieee80211_hw *hw, u32 key_index,
+		      u8 *p_macaddr, bool is_group, u8 enc_algo,
+		      bool is_wepkey, bool clear_all);
 
-void rtl8723ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
-					      bool autoload_fail, u8 *hwinfo);
-void rtl8723ae_bt_reg_init(struct ieee80211_hw *hw);
-void rtl8723ae_bt_hw_init(struct ieee80211_hw *hw);
-void rtl8723ae_suspend(struct ieee80211_hw *hw);
-void rtl8723ae_resume(struct ieee80211_hw *hw);
+void rtl8723e_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+					     bool autoload_fail, u8 *hwinfo);
+void rtl8723e_bt_reg_init(struct ieee80211_hw *hw);
+void rtl8723e_bt_hw_init(struct ieee80211_hw *hw);
+void rtl8723e_suspend(struct ieee80211_hw *hw);
+void rtl8723e_resume(struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/led.c b/drivers/net/wireless/rtlwifi/rtl8723ae/led.c
index 061526f..1317335 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/led.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/led.c
@@ -32,44 +32,44 @@
 #include "reg.h"
 #include "led.h"
 
-static void _rtl8723ae_init_led(struct ieee80211_hw *hw,
-				struct rtl_led *pled, enum rtl_led_pin ledpin)
+static void _rtl8723e_init_led(struct ieee80211_hw *hw,
+			       struct rtl_led *pled, enum rtl_led_pin ledpin)
 {
 	pled->hw = hw;
 	pled->ledpin = ledpin;
 	pled->ledon = false;
 }
 
-void rtl8723ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
+void rtl8723e_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
 {
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 ledcfg;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
 		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
 
-	ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
-
 	switch (pled->ledpin) {
 	case LED_PIN_GPIO0:
 		break;
 	case LED_PIN_LED0:
+		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
 		ledcfg &= ~BIT(6);
 		rtl_write_byte(rtlpriv,
 			       REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5));
 		break;
 	case LED_PIN_LED1:
-		rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5));
+		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
+		rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg & 0x10);
 		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not processed\n");
+			 "switch case not process\n");
 		break;
 	}
 	pled->ledon = true;
 }
 
-void rtl8723ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
+void rtl8723e_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
@@ -86,7 +86,7 @@
 	case LED_PIN_LED0:
 		ledcfg &= 0xf0;
 		if (pcipriv->ledctl.led_opendrain) {
-			ledcfg &= 0x90;
+			ledcfg &= 0x90; /* Set to software control. */
 			rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg|BIT(3)));
 			ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG);
 			ledcfg &= 0xFE;
@@ -94,50 +94,51 @@
 		} else {
 			ledcfg &= ~BIT(6);
 			rtl_write_byte(rtlpriv, REG_LEDCFG2,
-				       (ledcfg | BIT(3) | BIT(5)));
+					(ledcfg | BIT(3) | BIT(5)));
 		}
 		break;
 	case LED_PIN_LED1:
-		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1) & 0x10;
-		rtl_write_byte(rtlpriv, REG_LEDCFG1, (ledcfg | BIT(3)));
+		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
+		ledcfg &= 0x10; /* Set to software control. */
+		rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg|BIT(3));
+
 		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not processed\n");
+			 "switch case not process\n");
 		break;
 	}
 	pled->ledon = false;
 }
 
-void rtl8723ae_init_sw_leds(struct ieee80211_hw *hw)
+void rtl8723e_init_sw_leds(struct ieee80211_hw *hw)
 {
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
-
-	_rtl8723ae_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0);
-	_rtl8723ae_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1);
+	_rtl8723e_init_led(hw, &pcipriv->ledctl.sw_led0, LED_PIN_LED0);
+	_rtl8723e_init_led(hw, &pcipriv->ledctl.sw_led1, LED_PIN_LED1);
 }
 
-static void _rtl8723ae_sw_led_control(struct ieee80211_hw *hw,
-				    enum led_ctl_mode ledaction)
+static void _rtl8723e_sw_led_control(struct ieee80211_hw *hw,
+				     enum led_ctl_mode ledaction)
 {
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
-
 	switch (ledaction) {
 	case LED_CTL_POWER_ON:
 	case LED_CTL_LINK:
 	case LED_CTL_NO_LINK:
-		rtl8723ae_sw_led_on(hw, pLed0);
+		rtl8723e_sw_led_on(hw, pLed0);
 		break;
 	case LED_CTL_POWER_OFF:
-		rtl8723ae_sw_led_off(hw, pLed0);
+		rtl8723e_sw_led_off(hw, pLed0);
 		break;
 	default:
 		break;
 	}
 }
 
-void rtl8723ae_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction)
+void rtl8723e_led_control(struct ieee80211_hw *hw,
+			  enum led_ctl_mode ledaction)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
@@ -152,6 +153,7 @@
 	     ledaction == LED_CTL_POWER_ON)) {
 		return;
 	}
-	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d,\n", ledaction);
-	_rtl8723ae_sw_led_control(hw, ledaction);
+	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d,\n",
+		 ledaction);
+	_rtl8723e_sw_led_control(hw, ledaction);
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/led.h b/drivers/net/wireless/rtlwifi/rtl8723ae/led.h
index 2cb88e7..c22b19f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/led.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/led.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,10 +26,9 @@
 #ifndef __RTL92CE_LED_H__
 #define __RTL92CE_LED_H__
 
-void rtl8723ae_init_sw_leds(struct ieee80211_hw *hw);
-void rtl8723ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
-void rtl8723ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
-void rtl8723ae_led_control(struct ieee80211_hw *hw,
-			   enum led_ctl_mode ledaction);
+void rtl8723e_init_sw_leds(struct ieee80211_hw *hw);
+void rtl8723e_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl8723e_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl8723e_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
index 3ea78af..d367097 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,7 +26,6 @@
 #include "../wifi.h"
 #include "../pci.h"
 #include "../ps.h"
-#include "../core.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
@@ -39,29 +34,31 @@
 #include "table.h"
 #include "../rtl8723com/phy_common.h"
 
-/* static forward definitions */
-static u32 _phy_fw_rf_serial_read(struct ieee80211_hw *hw,
-				  enum radio_path rfpath, u32 offset);
-static void _phy_fw_rf_serial_write(struct ieee80211_hw *hw,
-				    enum radio_path rfpath,
-				    u32 offset, u32 data);
-static bool _phy_bb8192c_config_parafile(struct ieee80211_hw *hw);
-static bool _phy_cfg_mac_w_header(struct ieee80211_hw *hw);
-static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype);
-static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype);
-static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel,
-				      u8 *stage, u8 *step, u32 *delay);
-static u8 _phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
-				enum wireless_mode wirelessmode,
-				long power_indbm);
-static void rtl8723ae_phy_set_io(struct ieee80211_hw *hw);
+static void _rtl8723e_phy_fw_rf_serial_write(struct ieee80211_hw *hw,
+					     enum radio_path rfpath, u32 offset,
+					     u32 data);
+static bool _rtl8723e_phy_bb8192c_config_parafile(struct ieee80211_hw *hw);
+static bool _rtl8723e_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
+static bool _rtl8723e_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+						    u8 configtype);
+static bool _rtl8723e_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+						      u8 configtype);
+static bool _rtl8723e_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+					       u8 channel, u8 *stage, u8 *step,
+					       u32 *delay);
+static u8 _rtl8723e_phy_dbm_to_txpwr_idx(struct ieee80211_hw *hw,
+					 enum wireless_mode wirelessmode,
+					 long power_indbm);
+static void rtl8723e_phy_set_rf_on(struct ieee80211_hw *hw);
+static void rtl8723e_phy_set_io(struct ieee80211_hw *hw);
 
-u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw,
-			       enum radio_path rfpath, u32 regaddr, u32 bitmask)
+u32 rtl8723e_phy_query_rf_reg(struct ieee80211_hw *hw,
+			      enum radio_path rfpath,
+			      u32 regaddr, u32 bitmask)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 original_value, readback_value, bitshift;
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	u32 original_value = 0, readback_value, bitshift;
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	unsigned long flags;
 
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
@@ -70,10 +67,10 @@
 
 	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
 
-	if (rtlphy->rf_mode != RF_OP_BY_FW)
-		original_value = rtl8723_phy_rf_serial_read(hw, rfpath, regaddr);
-	else
-		original_value = _phy_fw_rf_serial_read(hw, rfpath, regaddr);
+	if (rtlphy->rf_mode != RF_OP_BY_FW) {
+		original_value = rtl8723_phy_rf_serial_read(hw,
+							    rfpath, regaddr);
+	}
 
 	bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
 	readback_value = (original_value & bitmask) >> bitshift;
@@ -82,45 +79,46 @@
 
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
 		 "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
-		 regaddr, rfpath, bitmask, original_value);
+		  regaddr, rfpath, bitmask, original_value);
 
 	return readback_value;
 }
 
-void rtl8723ae_phy_set_rf_reg(struct ieee80211_hw *hw,
-			      enum radio_path rfpath,
-			      u32 regaddr, u32 bitmask, u32 data)
+void rtl8723e_phy_set_rf_reg(struct ieee80211_hw *hw,
+			     enum radio_path rfpath,
+			   u32 regaddr, u32 bitmask, u32 data)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	u32 original_value, bitshift;
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u32 original_value = 0, bitshift;
 	unsigned long flags;
 
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
 		 "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
-		 regaddr, bitmask, data, rfpath);
+		  regaddr, bitmask, data, rfpath);
 
 	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
 
 	if (rtlphy->rf_mode != RF_OP_BY_FW) {
 		if (bitmask != RFREG_OFFSET_MASK) {
-			original_value = rtl8723_phy_rf_serial_read(hw, rfpath,
+			original_value = rtl8723_phy_rf_serial_read(hw,
+								    rfpath,
 								    regaddr);
 			bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
-			data = ((original_value & (~bitmask)) |
-			       (data << bitshift));
+			data =
+			    ((original_value & (~bitmask)) |
+			     (data << bitshift));
 		}
 
 		rtl8723_phy_rf_serial_write(hw, rfpath, regaddr, data);
 	} else {
 		if (bitmask != RFREG_OFFSET_MASK) {
-			original_value = _phy_fw_rf_serial_read(hw, rfpath,
-								regaddr);
 			bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
-			data = ((original_value & (~bitmask)) |
-			       (data << bitshift));
+			data =
+			    ((original_value & (~bitmask)) |
+			     (data << bitshift));
 		}
-		_phy_fw_rf_serial_write(hw, rfpath, regaddr, data);
+		_rtl8723e_phy_fw_rf_serial_write(hw, rfpath, regaddr, data);
 	}
 
 	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
@@ -128,23 +126,17 @@
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
 		 "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
 		 regaddr, bitmask, data, rfpath);
+
 }
 
-static u32 _phy_fw_rf_serial_read(struct ieee80211_hw *hw,
-					    enum radio_path rfpath, u32 offset)
-{
-	RT_ASSERT(false, "deprecated!\n");
-	return 0;
-}
-
-static void _phy_fw_rf_serial_write(struct ieee80211_hw *hw,
-				    enum radio_path rfpath,
-				    u32 offset, u32 data)
+static void _rtl8723e_phy_fw_rf_serial_write(struct ieee80211_hw *hw,
+					     enum radio_path rfpath, u32 offset,
+					     u32 data)
 {
 	RT_ASSERT(false, "deprecated!\n");
 }
 
-static void _rtl8723ae_phy_bb_config_1t(struct ieee80211_hw *hw)
+static void _rtl8723e_phy_bb_config_1t(struct ieee80211_hw *hw)
 {
 	rtl_set_bbreg(hw, RFPGA0_TXINFO, 0x3, 0x2);
 	rtl_set_bbreg(hw, RFPGA1_TXINFO, 0x300033, 0x200022);
@@ -158,20 +150,20 @@
 	rtl_set_bbreg(hw, 0xe88, 0x0c000000, 0x2);
 }
 
-bool rtl8723ae_phy_mac_config(struct ieee80211_hw *hw)
+bool rtl8723e_phy_mac_config(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	bool rtstatus = _phy_cfg_mac_w_header(hw);
+	bool rtstatus = _rtl8723e_phy_config_mac_with_headerfile(hw);
 	rtl_write_byte(rtlpriv, 0x04CA, 0x0A);
 	return rtstatus;
 }
 
-bool rtl8723ae_phy_bb_config(struct ieee80211_hw *hw)
+bool rtl8723e_phy_bb_config(struct ieee80211_hw *hw)
 {
 	bool rtstatus = true;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 tmpu1b;
-	u8 reg_hwparafile = 1;
+	u8 b_reg_hwparafile = 1;
 
 	rtl8723_phy_init_bb_rf_reg_def(hw);
 
@@ -186,67 +178,72 @@
 
 	/* 3. 0x02[1:0] = 2b'11 */
 	tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN);
-	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, (tmpu1b |
-		       FEN_BB_GLB_RSTn | FEN_BBRSTB));
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN,
+		       (tmpu1b | FEN_BB_GLB_RSTN | FEN_BBRSTB));
 
 	/* 4. 0x25[6] = 0 */
 	tmpu1b = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+1);
-	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+1, (tmpu1b&(~BIT(6))));
+	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+1, (tmpu1b & (~BIT(6))));
 
-	/* 5. 0x24[20] = 0	Advised by SD3 Alex Wang. 2011.02.09. */
+	/* 5. 0x24[20] = 0	//Advised by SD3 Alex Wang. 2011.02.09. */
 	tmpu1b = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+2);
-	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+2, (tmpu1b&(~BIT(4))));
+	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+2, (tmpu1b & (~BIT(4))));
 
 	/* 6. 0x1f[7:0] = 0x07 */
 	rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x07);
 
-	if (reg_hwparafile == 1)
-		rtstatus = _phy_bb8192c_config_parafile(hw);
+	if (b_reg_hwparafile == 1)
+		rtstatus = _rtl8723e_phy_bb8192c_config_parafile(hw);
 	return rtstatus;
 }
 
-bool rtl8723ae_phy_rf_config(struct ieee80211_hw *hw)
+bool rtl8723e_phy_rf_config(struct ieee80211_hw *hw)
 {
-	return rtl8723ae_phy_rf6052_config(hw);
+	return rtl8723e_phy_rf6052_config(hw);
 }
 
-static bool _phy_bb8192c_config_parafile(struct ieee80211_hw *hw)
+static bool _rtl8723e_phy_bb8192c_config_parafile(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	bool rtstatus;
 
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "==>\n");
-	rtstatus = _phy_cfg_bb_w_header(hw, BASEBAND_CONFIG_PHY_REG);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
+	rtstatus = _rtl8723e_phy_config_bb_with_headerfile(hw,
+						BASEBAND_CONFIG_PHY_REG);
 	if (rtstatus != true) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!");
 		return false;
 	}
 
 	if (rtlphy->rf_type == RF_1T2R) {
-		_rtl8723ae_phy_bb_config_1t(hw);
+		_rtl8723e_phy_bb_config_1t(hw);
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Config to 1T!!\n");
 	}
 	if (rtlefuse->autoload_failflag == false) {
 		rtlphy->pwrgroup_cnt = 0;
-		rtstatus = _phy_cfg_bb_w_pgheader(hw, BASEBAND_CONFIG_PHY_REG);
+		rtstatus = _rtl8723e_phy_config_bb_with_pgheaderfile(hw,
+					BASEBAND_CONFIG_PHY_REG);
 	}
 	if (rtstatus != true) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!");
 		return false;
 	}
-	rtstatus = _phy_cfg_bb_w_header(hw, BASEBAND_CONFIG_AGC_TAB);
+	rtstatus =
+	  _rtl8723e_phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_AGC_TAB);
 	if (rtstatus != true) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
 		return false;
 	}
 	rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw,
-					 RFPGA0_XA_HSSIPARAMETER2, 0x200));
+					RFPGA0_XA_HSSIPARAMETER2,
+					0x200));
+
 	return true;
 }
 
-static bool _phy_cfg_mac_w_header(struct ieee80211_hw *hw)
+static bool _rtl8723e_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u32 i;
@@ -264,7 +261,8 @@
 	return true;
 }
 
-static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype)
+static bool _rtl8723e_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+						    u8 configtype)
 {
 	int i;
 	u32 *phy_regarray_table;
@@ -278,13 +276,23 @@
 	phy_regarray_table = RTL8723EPHY_REG_1TARRAY;
 	if (configtype == BASEBAND_CONFIG_PHY_REG) {
 		for (i = 0; i < phy_reg_arraylen; i = i + 2) {
-			rtl_addr_delay(phy_regarray_table[i]);
+			if (phy_regarray_table[i] == 0xfe)
+				mdelay(50);
+			else if (phy_regarray_table[i] == 0xfd)
+				mdelay(5);
+			else if (phy_regarray_table[i] == 0xfc)
+				mdelay(1);
+			else if (phy_regarray_table[i] == 0xfb)
+				udelay(50);
+			else if (phy_regarray_table[i] == 0xfa)
+				udelay(5);
+			else if (phy_regarray_table[i] == 0xf9)
+				udelay(1);
 			rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD,
 				      phy_regarray_table[i + 1]);
 			udelay(1);
 			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-				 "The phy_regarray_table[0] is %x"
-				 " Rtl819XPHY_REGArray[1] is %x\n",
+				 "The phy_regarray_table[0] is %x Rtl819XPHY_REGArray[1] is %x\n",
 				 phy_regarray_table[i],
 				 phy_regarray_table[i + 1]);
 		}
@@ -294,8 +302,7 @@
 				      agctab_array_table[i + 1]);
 			udelay(1);
 			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-				 "The agctab_array_table[0] is "
-				 "%x Rtl819XPHY_REGArray[1] is %x\n",
+				 "The agctab_array_table[0] is %x Rtl819XPHY_REGArray[1] is %x\n",
 				 agctab_array_table[i],
 				 agctab_array_table[i + 1]);
 		}
@@ -303,132 +310,163 @@
 	return true;
 }
 
-static void _st_pwrIdx_dfrate_off(struct ieee80211_hw *hw, u32 regaddr,
-				  u32 bitmask, u32 data)
+static void store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,
+					   u32 regaddr, u32 bitmask,
+					   u32 data)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 
-	switch (regaddr) {
-	case RTXAGC_A_RATE18_06:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][0] = data;
+	if (regaddr == RTXAGC_A_RATE18_06) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][0]);
-		break;
-	case RTXAGC_A_RATE54_24:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][1] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][0]);
+	}
+	if (regaddr == RTXAGC_A_RATE54_24) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][1]);
-		break;
-	case RTXAGC_A_CCK1_MCS32:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][6] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][1]);
+	}
+	if (regaddr == RTXAGC_A_CCK1_MCS32) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][6]);
-		break;
-	case RTXAGC_B_CCK11_A_CCK2_11:
-		if (bitmask == 0xffffff00) {
-			rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][7] = data;
-			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-				 "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n",
-				 rtlphy->pwrgroup_cnt,
-				 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][7]);
-		}
-		if (bitmask == 0x000000ff) {
-			rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][15] = data;
-			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-				 "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
-				 rtlphy->pwrgroup_cnt,
-				 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][15]);
-		}
-		break;
-	case RTXAGC_A_MCS03_MCS00:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][2] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][6]);
+	}
+	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][7] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][7]);
+	}
+	if (regaddr == RTXAGC_A_MCS03_MCS00) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][2]);
-		break;
-	case RTXAGC_A_MCS07_MCS04:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][3] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][2]);
+	}
+	if (regaddr == RTXAGC_A_MCS07_MCS04) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][3]);
-		break;
-	case RTXAGC_A_MCS11_MCS08:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][4] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][3]);
+	}
+	if (regaddr == RTXAGC_A_MCS11_MCS08) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][4]);
-		break;
-	case RTXAGC_A_MCS15_MCS12:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][5] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][4]);
+	}
+	if (regaddr == RTXAGC_A_MCS15_MCS12) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][5]);
-		break;
-	case RTXAGC_B_RATE18_06:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][8] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][5]);
+	}
+	if (regaddr == RTXAGC_B_RATE18_06) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][8] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][8]);
-		break;
-	case RTXAGC_B_RATE54_24:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][9] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][8]);
+	}
+	if (regaddr == RTXAGC_B_RATE54_24) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][9] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][9]);
-		break;
-	case RTXAGC_B_CCK1_55_MCS32:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][14] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][9]);
+	}
+	if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][14] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][14]);
-		break;
-	case RTXAGC_B_MCS03_MCS00:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][10] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][14]);
+	}
+	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][15] =
+		    data;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][15]);
+	}
+	if (regaddr == RTXAGC_B_MCS03_MCS00) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][10] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][10]);
-		break;
-	case RTXAGC_B_MCS07_MCS04:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][11] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][10]);
+	}
+	if (regaddr == RTXAGC_B_MCS07_MCS04) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][11] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][11]);
-		break;
-	case RTXAGC_B_MCS11_MCS08:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][12] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][11]);
+	}
+	if (regaddr == RTXAGC_B_MCS11_MCS08) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][12] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][12]);
-		break;
-	case RTXAGC_B_MCS15_MCS12:
-		rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][13] = data;
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][12]);
+	}
+	if (regaddr == RTXAGC_B_MCS15_MCS12) {
+		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][13] =
+		    data;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
-			 rtlphy->pwrgroup_cnt,
-			 rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][13]);
+			  rtlphy->pwrgroup_cnt,
+			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy->
+							    pwrgroup_cnt][13]);
+
 		rtlphy->pwrgroup_cnt++;
-		break;
 	}
 }
 
-static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype)
+static bool _rtl8723e_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+						      u8 configtype)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	int i;
@@ -440,11 +478,23 @@
 
 	if (configtype == BASEBAND_CONFIG_PHY_REG) {
 		for (i = 0; i < phy_regarray_pg_len; i = i + 3) {
-			rtl_addr_delay(phy_regarray_table_pg[i]);
+			if (phy_regarray_table_pg[i] == 0xfe)
+				mdelay(50);
+			else if (phy_regarray_table_pg[i] == 0xfd)
+				mdelay(5);
+			else if (phy_regarray_table_pg[i] == 0xfc)
+				mdelay(1);
+			else if (phy_regarray_table_pg[i] == 0xfb)
+				udelay(50);
+			else if (phy_regarray_table_pg[i] == 0xfa)
+				udelay(5);
+			else if (phy_regarray_table_pg[i] == 0xf9)
+				udelay(1);
 
-			_st_pwrIdx_dfrate_off(hw, phy_regarray_table_pg[i],
-					      phy_regarray_table_pg[i + 1],
-					      phy_regarray_table_pg[i + 2]);
+			store_pwrindex_diffrate_offset(hw,
+						phy_regarray_table_pg[i],
+						phy_regarray_table_pg[i + 1],
+						phy_regarray_table_pg[i + 2]);
 		}
 	} else {
 		RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
@@ -453,45 +503,57 @@
 	return true;
 }
 
-bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
-					     enum radio_path rfpath)
+bool rtl8723e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+					    enum radio_path rfpath)
 {
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	int i;
+	bool rtstatus = true;
 	u32 *radioa_array_table;
-	u16 radioa_arraylen;
+	u32 *radiob_array_table;
+	u16 radioa_arraylen, radiob_arraylen;
 
-	radioa_arraylen = Rtl8723ERADIOA_1TARRAYLENGTH;
+	radioa_arraylen = RTL8723ERADIOA_1TARRAYLENGTH;
 	radioa_array_table = RTL8723E_RADIOA_1TARRAY;
+	radiob_arraylen = RTL8723E_RADIOB_1TARRAYLENGTH;
+	radiob_array_table = RTL8723E_RADIOB_1TARRAY;
+
+	rtstatus = true;
 
 	switch (rfpath) {
 	case RF90_PATH_A:
 		for (i = 0; i < radioa_arraylen; i = i + 2) {
-			rtl_rfreg_delay(hw, rfpath, radioa_array_table[i],
-					RFREG_OFFSET_MASK,
-					radioa_array_table[i + 1]);
+			if (radioa_array_table[i] == 0xfe) {
+				mdelay(50);
+			} else if (radioa_array_table[i] == 0xfd) {
+				mdelay(5);
+			} else if (radioa_array_table[i] == 0xfc) {
+				mdelay(1);
+			} else if (radioa_array_table[i] == 0xfb) {
+				udelay(50);
+			} else if (radioa_array_table[i] == 0xfa) {
+				udelay(5);
+			} else if (radioa_array_table[i] == 0xf9) {
+				udelay(1);
+			} else {
+				rtl_set_rfreg(hw, rfpath, radioa_array_table[i],
+					      RFREG_OFFSET_MASK,
+					      radioa_array_table[i + 1]);
+				udelay(1);
+			}
 		}
 		break;
 	case RF90_PATH_B:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not process\n");
-		break;
 	case RF90_PATH_C:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not process\n");
-		break;
 	case RF90_PATH_D:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not process\n");
 		break;
 	}
 	return true;
 }
 
-void rtl8723ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
+void rtl8723e_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 
 	rtlphy->default_initialgain[0] =
 	    (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
@@ -504,10 +566,10 @@
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 		 "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x\n",
-		  rtlphy->default_initialgain[0],
-		  rtlphy->default_initialgain[1],
-		  rtlphy->default_initialgain[2],
-		  rtlphy->default_initialgain[3]);
+		 rtlphy->default_initialgain[0],
+		 rtlphy->default_initialgain[1],
+		 rtlphy->default_initialgain[2],
+		 rtlphy->default_initialgain[3]);
 
 	rtlphy->framesync = (u8) rtl_get_bbreg(hw,
 					       ROFDM0_RXDETECTOR3, MASKBYTE0);
@@ -516,37 +578,43 @@
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 		 "Default framesync (0x%x) = 0x%x\n",
-		 ROFDM0_RXDETECTOR3, rtlphy->framesync);
+		  ROFDM0_RXDETECTOR3, rtlphy->framesync);
 }
 
-void rtl8723ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
+void rtl8723e_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	u8 txpwr_level;
 	long txpwr_dbm;
 
 	txpwr_level = rtlphy->cur_cck_txpwridx;
-	txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, txpwr_level);
+	txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw,
+						 WIRELESS_MODE_B, txpwr_level);
 	txpwr_level = rtlphy->cur_ofdm24g_txpwridx +
 	    rtlefuse->legacy_ht_txpowerdiff;
-	if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > txpwr_dbm)
-		txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
-						  txpwr_level);
+	if (rtl8723_phy_txpwr_idx_to_dbm(hw,
+					 WIRELESS_MODE_G,
+					 txpwr_level) > txpwr_dbm)
+		txpwr_dbm =
+		    rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
+						 txpwr_level);
 	txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
-	if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, txpwr_level) >
-	    txpwr_dbm)
-		txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
-							 txpwr_level);
+	if (rtl8723_phy_txpwr_idx_to_dbm(hw,
+					 WIRELESS_MODE_N_24G,
+					 txpwr_level) > txpwr_dbm)
+		txpwr_dbm =
+		    rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
+						 txpwr_level);
 	*powerlevel = txpwr_dbm;
 }
 
-static void _rtl8723ae_get_txpower_index(struct ieee80211_hw *hw, u8 channel,
-					 u8 *cckpowerlevel, u8 *ofdmpowerlevel)
+static void _rtl8723e_get_txpower_index(struct ieee80211_hw *hw, u8 channel,
+					u8 *cckpowerlevel, u8 *ofdmpowerlevel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	u8 index = (channel - 1);
 
@@ -567,66 +635,70 @@
 	}
 }
 
-static void _rtl8723ae_ccxpower_index_check(struct ieee80211_hw *hw,
-					    u8 channel, u8 *cckpowerlevel,
-					    u8 *ofdmpowerlevel)
+static void _rtl8723e_ccxpower_index_check(struct ieee80211_hw *hw,
+					   u8 channel, u8 *cckpowerlevel,
+					   u8 *ofdmpowerlevel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 
 	rtlphy->cur_cck_txpwridx = cckpowerlevel[0];
 	rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0];
+
 }
 
-void rtl8723ae_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
+void rtl8723e_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
 {
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	u8 cckpowerlevel[2], ofdmpowerlevel[2];
 
 	if (rtlefuse->txpwr_fromeprom == false)
 		return;
-	_rtl8723ae_get_txpower_index(hw, channel, &cckpowerlevel[0],
-				     &ofdmpowerlevel[0]);
-	_rtl8723ae_ccxpower_index_check(hw, channel, &cckpowerlevel[0],
-					&ofdmpowerlevel[0]);
-	rtl8723ae_phy_rf6052_set_cck_txpower(hw, &cckpowerlevel[0]);
-	rtl8723ae_phy_rf6052_set_ofdm_txpower(hw, &ofdmpowerlevel[0], channel);
+	_rtl8723e_get_txpower_index(hw, channel,
+				    &cckpowerlevel[0], &ofdmpowerlevel[0]);
+	_rtl8723e_ccxpower_index_check(hw,
+				       channel, &cckpowerlevel[0],
+				       &ofdmpowerlevel[0]);
+	rtl8723e_phy_rf6052_set_cck_txpower(hw, &cckpowerlevel[0]);
+	rtl8723e_phy_rf6052_set_ofdm_txpower(hw, &ofdmpowerlevel[0], channel);
 }
 
-bool rtl8723ae_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm)
+bool rtl8723e_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	u8 idx;
 	u8 rf_path;
-	u8 ccktxpwridx = _phy_dbm_to_txpwr_Idx(hw, WIRELESS_MODE_B,
-					       power_indbm);
-	u8 ofdmtxpwridx = _phy_dbm_to_txpwr_Idx(hw, WIRELESS_MODE_N_24G,
-						power_indbm);
+	u8 ccktxpwridx = _rtl8723e_phy_dbm_to_txpwr_idx(hw,
+						      WIRELESS_MODE_B,
+						      power_indbm);
+	u8 ofdmtxpwridx = _rtl8723e_phy_dbm_to_txpwr_idx(hw,
+						       WIRELESS_MODE_N_24G,
+						       power_indbm);
 	if (ofdmtxpwridx - rtlefuse->legacy_ht_txpowerdiff > 0)
 		ofdmtxpwridx -= rtlefuse->legacy_ht_txpowerdiff;
 	else
 		ofdmtxpwridx = 0;
 	RT_TRACE(rtlpriv, COMP_TXAGC, DBG_TRACE,
 		 "%lx dBm, ccktxpwridx = %d, ofdmtxpwridx = %d\n",
-		 power_indbm, ccktxpwridx, ofdmtxpwridx);
+		  power_indbm, ccktxpwridx, ofdmtxpwridx);
 	for (idx = 0; idx < 14; idx++) {
 		for (rf_path = 0; rf_path < 2; rf_path++) {
 			rtlefuse->txpwrlevel_cck[rf_path][idx] = ccktxpwridx;
 			rtlefuse->txpwrlevel_ht40_1s[rf_path][idx] =
-							    ofdmtxpwridx;
+			    ofdmtxpwridx;
 			rtlefuse->txpwrlevel_ht40_2s[rf_path][idx] =
-							    ofdmtxpwridx;
+			    ofdmtxpwridx;
 		}
 	}
-	rtl8723ae_phy_set_txpower_level(hw, rtlphy->current_channel);
+	rtl8723e_phy_set_txpower_level(hw, rtlphy->current_channel);
 	return true;
 }
 
-static u8 _phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
-				enum wireless_mode wirelessmode,
-				long power_indbm)
+static u8 _rtl8723e_phy_dbm_to_txpwr_idx(struct ieee80211_hw *hw,
+					 enum wireless_mode wirelessmode,
+					 long power_indbm)
 {
 	u8 txpwridx;
 	long offset;
@@ -645,7 +717,7 @@
 	}
 
 	if ((power_indbm - offset) > 0)
-		txpwridx = (u8) ((power_indbm - offset) * 2);
+		txpwridx = (u8)((power_indbm - offset) * 2);
 	else
 		txpwridx = 0;
 
@@ -655,19 +727,48 @@
 	return txpwridx;
 }
 
-void rtl8723ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
+void rtl8723e_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	enum io_type iotype;
+
+	if (!is_hal_stop(rtlhal)) {
+		switch (operation) {
+		case SCAN_OPT_BACKUP_BAND0:
+			iotype = IO_CMD_PAUSE_BAND0_DM_BY_SCAN;
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_IO_CMD,
+						      (u8 *)&iotype);
+
+			break;
+		case SCAN_OPT_RESTORE:
+			iotype = IO_CMD_RESUME_DM_BY_SCAN;
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_IO_CMD,
+						      (u8 *)&iotype);
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "Unknown Scan Backup operation.\n");
+			break;
+		}
+	}
+}
+
+void rtl8723e_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	u8 reg_bw_opmode;
 	u8 reg_prsr_rsc;
 
 	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
 		 "Switch to %s bandwidth\n",
-		 rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
-		 "20MHz" : "40MHz");
+		  rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+		  "20MHz" : "40MHz");
 
 	if (is_hal_stop(rtlhal)) {
 		rtlphy->set_bwmode_inprogress = false;
@@ -719,16 +820,16 @@
 			 "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
 		break;
 	}
-	rtl8723ae_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+	rtl8723e_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
 	rtlphy->set_bwmode_inprogress = false;
-	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n");
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "\n");
 }
 
-void rtl8723ae_phy_set_bw_mode(struct ieee80211_hw *hw,
-			       enum nl80211_channel_type ch_type)
+void rtl8723e_phy_set_bw_mode(struct ieee80211_hw *hw,
+			      enum nl80211_channel_type ch_type)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u8 tmp_bw = rtlphy->current_chan_bw;
 
@@ -736,20 +837,20 @@
 		return;
 	rtlphy->set_bwmode_inprogress = true;
 	if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
-		rtl8723ae_phy_set_bw_mode_callback(hw);
+		rtl8723e_phy_set_bw_mode_callback(hw);
 	} else {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-			 "FALSE driver sleep or unload\n");
+			 "false driver sleep or unload\n");
 		rtlphy->set_bwmode_inprogress = false;
 		rtlphy->current_chan_bw = tmp_bw;
 	}
 }
 
-void rtl8723ae_phy_sw_chnl_callback(struct ieee80211_hw *hw)
+void rtl8723e_phy_sw_chnl_callback(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	u32 delay;
 
 	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
@@ -759,7 +860,7 @@
 	do {
 		if (!rtlphy->sw_chnl_inprogress)
 			break;
-		if (!_phy_sw_chnl_step_by_step
+		if (!_rtl8723e_phy_sw_chnl_step_by_step
 		    (hw, rtlphy->current_channel, &rtlphy->sw_chnl_stage,
 		     &rtlphy->sw_chnl_step, &delay)) {
 			if (delay > 0)
@@ -771,13 +872,13 @@
 		}
 		break;
 	} while (true);
-	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n");
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "\n");
 }
 
-u8 rtl8723ae_phy_sw_chnl(struct ieee80211_hw *hw)
+u8 rtl8723e_phy_sw_chnl(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
 	if (rtlphy->sw_chnl_inprogress)
@@ -790,9 +891,9 @@
 	rtlphy->sw_chnl_stage = 0;
 	rtlphy->sw_chnl_step = 0;
 	if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
-		rtl8723ae_phy_sw_chnl_callback(hw);
+		rtl8723e_phy_sw_chnl_callback(hw);
 		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
-			 "sw_chnl_inprogress false schedule workitem\n");
+			 "sw_chnl_inprogress false schdule workitem\n");
 		rtlphy->sw_chnl_inprogress = false;
 	} else {
 		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
@@ -802,31 +903,33 @@
 	return 1;
 }
 
-static void _rtl8723ae_phy_sw_rf_seting(struct ieee80211_hw *hw, u8 channel)
+static void _rtl8723e_phy_sw_rf_seting(struct ieee80211_hw *hw, u8 channel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
 	if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) {
 		if (channel == 6 && rtlphy->current_chan_bw ==
-		    HT_CHANNEL_WIDTH_20)
-			rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD,
-				      0x00255);
+				HT_CHANNEL_WIDTH_20)
+			rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1,
+				      MASKDWORD, 0x00255);
 		else{
-			u32 backupRF0x1A = (u32)rtl_get_rfreg(hw, RF90_PATH_A,
-					   RF_RX_G1, RFREG_OFFSET_MASK);
-			rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD,
-				      backupRF0x1A);
+			u32 backuprf0x1a = (u32)rtl_get_rfreg(hw,
+					RF90_PATH_A, RF_RX_G1,
+					RFREG_OFFSET_MASK);
+			rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1,
+				      MASKDWORD, backuprf0x1a);
 		}
 	}
 }
 
-static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel,
-				      u8 *stage, u8 *step, u32 *delay)
+static bool _rtl8723e_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+					       u8 channel, u8 *stage, u8 *step,
+					       u32 *delay)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
 	u32 precommoncmdcnt;
 	struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
@@ -839,14 +942,16 @@
 
 	precommoncmdcnt = 0;
 	rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
-					 MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL,
-					 0, 0, 0);
+					 MAX_PRECMD_CNT,
+					 CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0);
 	rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
 					 MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+
 	postcommoncmdcnt = 0;
 
 	rtl8723_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
 					 MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
+
 	rfdependcmdcnt = 0;
 
 	RT_ASSERT((channel >= 1 && channel <= 14),
@@ -854,10 +959,11 @@
 
 	rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
 					 MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
-				  RF_CHNLBW, channel, 10);
+					 RF_CHNLBW, channel, 10);
 
 	rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
-					 MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0);
+					 MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0,
+					 0);
 
 	do {
 		switch (*stage) {
@@ -870,6 +976,10 @@
 		case 2:
 			currentcmd = &postcommoncmd[*step];
 			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "Invalid 'stage' = %d, Check it!\n", *stage);
+			return true;
 		}
 
 		if (currentcmd->cmdid == CMDID_END) {
@@ -884,7 +994,7 @@
 
 		switch (currentcmd->cmdid) {
 		case CMDID_SET_TXPOWEROWER_LEVEL:
-			rtl8723ae_phy_set_txpower_level(hw, channel);
+			rtl8723e_phy_set_txpower_level(hw, channel);
 			break;
 		case CMDID_WRITEPORT_ULONG:
 			rtl_write_dword(rtlpriv, currentcmd->para1,
@@ -909,10 +1019,10 @@
 					      RFREG_OFFSET_MASK,
 					      rtlphy->rfreg_chnlval[rfpath]);
 			}
-			_rtl8723ae_phy_sw_rf_seting(hw, channel);
+			_rtl8723e_phy_sw_rf_seting(hw, channel);
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 				 "switch case not process\n");
 			break;
 		}
@@ -925,7 +1035,7 @@
 	return false;
 }
 
-static u8 _rtl8723ae_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
+static u8 _rtl8723e_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
 {
 	u32 reg_eac, reg_e94, reg_e9c, reg_ea4;
 	u8 result = 0x00;
@@ -968,7 +1078,7 @@
 	return result;
 }
 
-static u8 _rtl8723ae_phy_path_b_iqk(struct ieee80211_hw *hw)
+static u8 _rtl8723e_phy_path_b_iqk(struct ieee80211_hw *hw)
 {
 	u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc;
 	u8 result = 0x00;
@@ -995,8 +1105,8 @@
 	return result;
 }
 
-static bool phy_simularity_comp(struct ieee80211_hw *hw, long result[][8],
-				u8 c1, u8 c2)
+static bool _rtl8723e_phy_simularity_compare(struct ieee80211_hw *hw,
+					     long result[][8], u8 c1, u8 c2)
 {
 	u32 i, j, diff, simularity_bitmap, bound;
 
@@ -1047,11 +1157,11 @@
 
 }
 
-static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
-					long result[][8], u8 t, bool is2t)
+static void _rtl8723e_phy_iq_calibrate(struct ieee80211_hw *hw,
+				       long result[][8], u8 t, bool is2t)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	u32 i;
 	u8 patha_ok, pathb_ok;
 	u32 adda_reg[IQK_ADDA_REG_NUM] = {
@@ -1060,22 +1170,28 @@
 		0xe88, 0xe8c, 0xed0, 0xed4,
 		0xed8, 0xedc, 0xee0, 0xeec
 	};
+
 	u32 iqk_mac_reg[IQK_MAC_REG_NUM] = {
 		0x522, 0x550, 0x551, 0x040
 	};
+
 	const u32 retrycount = 2;
 
+	u32 bbvalue;
+
 	if (t == 0) {
-		rtl8723_save_adda_registers(hw, adda_reg, rtlphy->adda_backup,
-					    16);
+		bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD);
+
+		rtl8723_save_adda_registers(hw, adda_reg,
+					    rtlphy->adda_backup, 16);
 		rtl8723_phy_save_mac_registers(hw, iqk_mac_reg,
 					       rtlphy->iqk_mac_backup);
 	}
 	rtl8723_phy_path_adda_on(hw, adda_reg, true, is2t);
 	if (t == 0) {
 		rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw,
-						 RFPGA0_XA_HSSIPARAMETER1,
-						 BIT(8));
+					RFPGA0_XA_HSSIPARAMETER1,
+					BIT(8));
 	}
 
 	if (!rtlphy->rfpi_enable)
@@ -1101,7 +1217,7 @@
 	rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00);
 	rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800);
 	for (i = 0; i < retrycount; i++) {
-		patha_ok = _rtl8723ae_phy_path_a_iqk(hw, is2t);
+		patha_ok = _rtl8723e_phy_path_a_iqk(hw, is2t);
 		if (patha_ok == 0x03) {
 			result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
 					0x3FF0000) >> 16;
@@ -1115,7 +1231,8 @@
 		} else if (i == (retrycount - 1) && patha_ok == 0x01)
 
 			result[t][0] = (rtl_get_bbreg(hw, 0xe94,
-					MASKDWORD) & 0x3FF0000) >> 16;
+						      MASKDWORD) & 0x3FF0000) >>
+			    16;
 		result[t][1] =
 		    (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16;
 
@@ -1125,11 +1242,12 @@
 		rtl8723_phy_path_a_standby(hw);
 		rtl8723_phy_path_adda_on(hw, adda_reg, false, is2t);
 		for (i = 0; i < retrycount; i++) {
-			pathb_ok = _rtl8723ae_phy_path_b_iqk(hw);
+			pathb_ok = _rtl8723e_phy_path_b_iqk(hw);
 			if (pathb_ok == 0x03) {
-				result[t][4] =
-				    (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) &
-				     0x3FF0000) >> 16;
+				result[t][4] = (rtl_get_bbreg(hw,
+							      0xeb4,
+							      MASKDWORD) &
+						0x3FF0000) >> 16;
 				result[t][5] =
 				    (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
 				     0x3FF0000) >> 16;
@@ -1141,9 +1259,10 @@
 				     0x3FF0000) >> 16;
 				break;
 			} else if (i == (retrycount - 1) && pathb_ok == 0x01) {
-				result[t][4] =
-				    (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) &
-				     0x3FF0000) >> 16;
+				result[t][4] = (rtl_get_bbreg(hw,
+							      0xeb4,
+							      MASKDWORD) &
+						0x3FF0000) >> 16;
 			}
 			result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
 					0x3FF0000) >> 16;
@@ -1166,11 +1285,11 @@
 	}
 }
 
-static void _rtl8723ae_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
+static void _rtl8723e_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
 {
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 tmpreg;
 	u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	tmpreg = rtl_read_byte(rtlpriv, 0xd03);
 
@@ -1211,14 +1330,14 @@
 	}
 }
 
-static void _rtl8723ae_phy_set_rfpath_switch(struct ieee80211_hw *hw,
-					     bool bmain, bool is2t)
+static void _rtl8723e_phy_set_rfpath_switch(struct ieee80211_hw *hw,
+					    bool bmain, bool is2t)
 {
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
 	if (is_hal_stop(rtlhal)) {
 		rtl_set_bbreg(hw, REG_LEDCFG0, BIT(23), 0x01);
-		rtl_set_bbreg(hw, rFPGA0_XAB_RFPARAMETER, BIT(13), 0x01);
+		rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(13), 0x01);
 	}
 	if (is2t) {
 		if (bmain)
@@ -1234,21 +1353,23 @@
 			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1);
 
 	}
+
 }
 
 #undef IQK_ADDA_REG_NUM
 #undef IQK_DELAY_TIME
 
-void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
+void rtl8723e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
 	long result[4][8];
 	u8 i, final_candidate;
-	bool patha_ok, pathb_ok;
-	long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_tmp = 0;
+	bool b_patha_ok, b_pathb_ok;
+	long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4,
+	    reg_ecc, reg_tmp = 0;
 	bool is12simular, is13simular, is23simular;
-	bool start_conttx = false, singletone = false;
 	u32 iqk_bb_reg[10] = {
 		ROFDM0_XARXIQIMBALANCE,
 		ROFDM0_XBRXIQIMBALANCE,
@@ -1262,13 +1383,12 @@
 		ROFDM0_RXIQEXTANTA
 	};
 
-	if (recovery) {
-		rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg,
+	if (b_recovery) {
+		rtl8723_phy_reload_adda_registers(hw,
+						  iqk_bb_reg,
 						  rtlphy->iqk_bb_backup, 10);
 		return;
 	}
-	if (start_conttx || singletone)
-		return;
 	for (i = 0; i < 8; i++) {
 		result[0][i] = 0;
 		result[1][i] = 0;
@@ -1276,30 +1396,33 @@
 		result[3][i] = 0;
 	}
 	final_candidate = 0xff;
-	patha_ok = false;
-	pathb_ok = false;
+	b_patha_ok = false;
+	b_pathb_ok = false;
 	is12simular = false;
 	is23simular = false;
 	is13simular = false;
 	for (i = 0; i < 3; i++) {
-		_rtl8723ae_phy_iq_calibrate(hw, result, i, false);
+		_rtl8723e_phy_iq_calibrate(hw, result, i, false);
 		if (i == 1) {
-			is12simular = phy_simularity_comp(hw, result, 0, 1);
+			is12simular =
+			  _rtl8723e_phy_simularity_compare(hw, result, 0, 1);
 			if (is12simular) {
 				final_candidate = 0;
 				break;
 			}
 		}
 		if (i == 2) {
-			is13simular = phy_simularity_comp(hw, result, 0, 2);
+			is13simular =
+			  _rtl8723e_phy_simularity_compare(hw, result, 0, 2);
 			if (is13simular) {
 				final_candidate = 0;
 				break;
 			}
-			is23simular = phy_simularity_comp(hw, result, 1, 2);
-			if (is23simular) {
+			is23simular =
+			  _rtl8723e_phy_simularity_compare(hw, result, 1, 2);
+			if (is23simular)
 				final_candidate = 1;
-			} else {
+			else {
 				for (i = 0; i < 8; i++)
 					reg_tmp += result[3][i];
 
@@ -1314,50 +1437,54 @@
 		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 (final_candidate != 0xff) {
 		rtlphy->reg_e94 = reg_e94 = result[final_candidate][0];
 		rtlphy->reg_e9c = reg_e9c = result[final_candidate][1];
 		reg_ea4 = result[final_candidate][2];
+		reg_eac = result[final_candidate][3];
 		rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4];
 		rtlphy->reg_ebc = reg_ebc = result[final_candidate][5];
-		patha_ok = pathb_ok = true;
+		reg_ec4 = result[final_candidate][6];
+		reg_ecc = result[final_candidate][7];
+		b_patha_ok = true;
+		b_pathb_ok = true;
 	} else {
 		rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100;
 		rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0;
 	}
-	if (reg_e94 != 0) /*&&(reg_ea4 != 0) */
-		rtl8723_phy_path_a_fill_iqk_matrix(hw, patha_ok, result,
+	if (reg_e94 != 0)
+		rtl8723_phy_path_a_fill_iqk_matrix(hw, b_patha_ok, result,
 						   final_candidate,
 						   (reg_ea4 == 0));
-	rtl8723_save_adda_registers(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10);
+	rtl8723_save_adda_registers(hw, iqk_bb_reg,
+				    rtlphy->iqk_bb_backup, 10);
 }
 
-void rtl8723ae_phy_lc_calibrate(struct ieee80211_hw *hw)
+void rtl8723e_phy_lc_calibrate(struct ieee80211_hw *hw)
 {
-	bool start_conttx = false, singletone = false;
-
-	if (start_conttx || singletone)
-		return;
-	_rtl8723ae_phy_lc_calibrate(hw, false);
+	_rtl8723e_phy_lc_calibrate(hw, false);
 }
 
-void rtl8723ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
+void rtl8723e_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
 {
-	_rtl8723ae_phy_set_rfpath_switch(hw, bmain, false);
+	_rtl8723e_phy_set_rfpath_switch(hw, bmain, false);
 }
 
-bool rtl8723ae_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype)
+bool rtl8723e_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	bool postprocessing = false;
 
 	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
 		 "-->IO Cmd(%#x), set_io_inprogress(%d)\n",
-		 iotype, rtlphy->set_io_inprogress);
+		  iotype, rtlphy->set_io_inprogress);
 	do {
 		switch (iotype) {
 		case IO_CMD_RESUME_DM_BY_SCAN:
@@ -1365,13 +1492,13 @@
 				 "[IO CMD] Resume DM after scan.\n");
 			postprocessing = true;
 			break;
-		case IO_CMD_PAUSE_DM_BY_SCAN:
+		case IO_CMD_PAUSE_BAND0_DM_BY_SCAN:
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
 				 "[IO CMD] Pause DM before scan.\n");
 			postprocessing = true;
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 				 "switch case not process\n");
 			break;
 		}
@@ -1382,42 +1509,42 @@
 	} else {
 		return false;
 	}
-	rtl8723ae_phy_set_io(hw);
-	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "<--IO Type(%#x)\n", iotype);
+	rtl8723e_phy_set_io(hw);
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "IO Type(%#x)\n", iotype);
 	return true;
 }
 
-static void rtl8723ae_phy_set_io(struct ieee80211_hw *hw)
+static void rtl8723e_phy_set_io(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
 	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
 		 "--->Cmd(%#x), set_io_inprogress(%d)\n",
-		 rtlphy->current_io_type, rtlphy->set_io_inprogress);
+		  rtlphy->current_io_type, rtlphy->set_io_inprogress);
 	switch (rtlphy->current_io_type) {
 	case IO_CMD_RESUME_DM_BY_SCAN:
 		dm_digtable->cur_igvalue = rtlphy->initgain_backup.xaagccore1;
-		rtl8723ae_dm_write_dig(hw);
-		rtl8723ae_phy_set_txpower_level(hw, rtlphy->current_channel);
+		rtl8723e_dm_write_dig(hw);
+		rtl8723e_phy_set_txpower_level(hw, rtlphy->current_channel);
 		break;
-	case IO_CMD_PAUSE_DM_BY_SCAN:
+	case IO_CMD_PAUSE_BAND0_DM_BY_SCAN:
 		rtlphy->initgain_backup.xaagccore1 = dm_digtable->cur_igvalue;
 		dm_digtable->cur_igvalue = 0x17;
-		rtl8723ae_dm_write_dig(hw);
+		rtl8723e_dm_write_dig(hw);
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 			 "switch case not process\n");
 		break;
 	}
 	rtlphy->set_io_inprogress = false;
 	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
-		 "<---(%#x)\n", rtlphy->current_io_type);
+		 "(%#x)\n", rtlphy->current_io_type);
 }
 
-static void rtl8723ae_phy_set_rf_on(struct ieee80211_hw *hw)
+static void rtl8723e_phy_set_rf_on(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
@@ -1429,11 +1556,11 @@
 	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
 }
 
-static void _rtl8723ae_phy_set_rf_sleep(struct ieee80211_hw *hw)
+static void _rtl8723e_phy_set_rf_sleep(struct ieee80211_hw *hw)
 {
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u32 u4b_tmp;
 	u8 delay = 5;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
 	rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
@@ -1459,45 +1586,47 @@
 	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22);
 }
 
-static bool _rtl8723ae_phy_set_rf_power_state(struct ieee80211_hw *hw,
-					      enum rf_pwrstate rfpwr_state)
+static bool _rtl8723e_phy_set_rf_power_state(struct ieee80211_hw *hw,
+					     enum rf_pwrstate rfpwr_state)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-	struct rtl8192_tx_ring *ring = NULL;
 	bool bresult = true;
 	u8 i, queue_id;
+	struct rtl8192_tx_ring *ring = NULL;
 
 	switch (rfpwr_state) {
 	case ERFON:
 		if ((ppsc->rfpwr_state == ERFOFF) &&
 		    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
 			bool rtstatus;
-			u32 InitializeCount = 0;
+			u32 initializecount = 0;
+
 			do {
-				InitializeCount++;
+				initializecount++;
 				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 					 "IPS Set eRf nic enable\n");
 				rtstatus = rtl_ps_enable_nic(hw);
-			} while ((rtstatus != true) && (InitializeCount < 10));
+			} while (!rtstatus && (initializecount < 10));
 			RT_CLEAR_PS_LEVEL(ppsc,
 					  RT_RF_OFF_LEVL_HALT_NIC);
 		} else {
 			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 				 "Set ERFON sleeped:%d ms\n",
-				 jiffies_to_msecs(jiffies -
-				 ppsc->last_sleep_jiffies));
+				  jiffies_to_msecs(jiffies -
+						   ppsc->
+						   last_sleep_jiffies));
 			ppsc->last_awake_jiffies = jiffies;
-			rtl8723ae_phy_set_rf_on(hw);
+			rtl8723e_phy_set_rf_on(hw);
 		}
 		if (mac->link_state == MAC80211_LINKED) {
 			rtlpriv->cfg->ops->led_control(hw,
-					LED_CTL_LINK);
+						       LED_CTL_LINK);
 		} else {
 			rtlpriv->cfg->ops->led_control(hw,
-					LED_CTL_NO_LINK);
+						       LED_CTL_NO_LINK);
 		}
 		break;
 	case ERFOFF:
@@ -1509,10 +1638,10 @@
 		} else {
 			if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) {
 				rtlpriv->cfg->ops->led_control(hw,
-					LED_CTL_NO_LINK);
+						LED_CTL_NO_LINK);
 			} else {
 				rtlpriv->cfg->ops->led_control(hw,
-					LED_CTL_POWER_OFF);
+						LED_CTL_POWER_OFF);
 			}
 		}
 		break;
@@ -1522,7 +1651,8 @@
 		for (queue_id = 0, i = 0;
 		     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
 			ring = &pcipriv->dev.tx_ring[queue_id];
-			if (skb_queue_len(&ring->queue) == 0) {
+			if (queue_id == BEACON_QUEUE ||
+			    skb_queue_len(&ring->queue) == 0) {
 				queue_id++;
 				continue;
 			} else {
@@ -1536,22 +1666,23 @@
 			}
 			if (i >= MAX_DOZE_WAITING_TIMES_9x) {
 				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-					 "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
-					 MAX_DOZE_WAITING_TIMES_9x,
-					 queue_id,
-					 skb_queue_len(&ring->queue));
+					 "ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
+					  MAX_DOZE_WAITING_TIMES_9x,
+					  queue_id,
+					  skb_queue_len(&ring->queue));
 				break;
 			}
 		}
 		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 			 "Set ERFSLEEP awaked:%d ms\n",
-			 jiffies_to_msecs(jiffies - ppsc->last_awake_jiffies));
+			  jiffies_to_msecs(jiffies -
+					   ppsc->last_awake_jiffies));
 		ppsc->last_sleep_jiffies = jiffies;
-		_rtl8723ae_phy_set_rf_sleep(hw);
+		_rtl8723e_phy_set_rf_sleep(hw);
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not processed\n");
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
 		bresult = false;
 		break;
 	}
@@ -1560,14 +1691,15 @@
 	return bresult;
 }
 
-bool rtl8723ae_phy_set_rf_power_state(struct ieee80211_hw *hw,
-				      enum rf_pwrstate rfpwr_state)
+bool rtl8723e_phy_set_rf_power_state(struct ieee80211_hw *hw,
+				     enum rf_pwrstate rfpwr_state)
 {
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
 	bool bresult = false;
 
 	if (rfpwr_state == ppsc->rfpwr_state)
 		return bresult;
-	bresult = _rtl8723ae_phy_set_rf_power_state(hw, rfpwr_state);
+	bresult = _rtl8723e_phy_set_rf_power_state(hw, rfpwr_state);
 	return bresult;
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h
index cd43139..b85f5c7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -39,6 +35,7 @@
 #define RT_CANNOT_IO(hw)			false
 #define HIGHPOWER_RADIOA_ARRAYLEN		22
 
+#define IQK_ADDA_REG_NUM			16
 #define MAX_TOLERANCE				5
 #define	IQK_DELAY_TIME				1
 
@@ -49,12 +46,15 @@
 
 #define LOOP_LIMIT				5
 #define MAX_STALL_TIME				50
-#define AntennaDiversityValue			0x80
+#define ANTENNADIVERSITYVALUE			0x80
 #define MAX_TXPWR_IDX_NMODE_92S			63
 #define Reset_Cnt_Limit				3
 
+#define IQK_ADDA_REG_NUM			16
 #define IQK_MAC_REG_NUM				4
 
+#define IQK_DELAY_TIME				1
+
 #define RF6052_MAX_PATH				2
 
 #define CT_OFFSET_MAC_ADDR			0X16
@@ -166,36 +166,37 @@
 	u32 mcs_original_offset[4][16];
 };
 
-u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw,
-			       enum radio_path rfpath, u32 regaddr,
-			       u32 bitmask);
-void rtl8723ae_phy_set_rf_reg(struct ieee80211_hw *hw,
+u32 rtl8723e_phy_query_rf_reg(struct ieee80211_hw *hw,
 			      enum radio_path rfpath, u32 regaddr,
-			      u32 bitmask, u32 data);
-bool rtl8723ae_phy_mac_config(struct ieee80211_hw *hw);
-bool rtl8723ae_phy_bb_config(struct ieee80211_hw *hw);
-bool rtl8723ae_phy_rf_config(struct ieee80211_hw *hw);
+			      u32 bitmask);
+void rtl8723e_phy_set_rf_reg(struct ieee80211_hw *hw,
+			     enum radio_path rfpath, u32 regaddr,
+			     u32 bitmask, u32 data);
+bool rtl8723e_phy_mac_config(struct ieee80211_hw *hw);
+bool rtl8723e_phy_bb_config(struct ieee80211_hw *hw);
+bool rtl8723e_phy_rf_config(struct ieee80211_hw *hw);
 bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw,
 					  enum radio_path rfpath);
-void rtl8723ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
-void rtl8723ae_phy_get_txpower_level(struct ieee80211_hw *hw,
-				     long *powerlevel);
-void rtl8723ae_phy_set_txpower_level(struct ieee80211_hw *hw,
-				     u8 channel);
-bool rtl8723ae_phy_update_txpower_dbm(struct ieee80211_hw *hw,
-				      long power_indbm);
-void rtl8723ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
-void rtl8723ae_phy_set_bw_mode(struct ieee80211_hw *hw,
-			       enum nl80211_channel_type ch_type);
-void rtl8723ae_phy_sw_chnl_callback(struct ieee80211_hw *hw);
-u8 rtl8723ae_phy_sw_chnl(struct ieee80211_hw *hw);
-void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery);
-void rtl8723ae_phy_lc_calibrate(struct ieee80211_hw *hw);
-void rtl8723ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
-bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
-					     enum radio_path rfpath);
-bool rtl8723ae_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
-bool rtl8723ae_phy_set_rf_power_state(struct ieee80211_hw *hw,
-				      enum rf_pwrstate rfpwr_state);
+void rtl8723e_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+void rtl8723e_phy_get_txpower_level(struct ieee80211_hw *hw,
+				    long *powerlevel);
+void rtl8723e_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
+bool rtl8723e_phy_update_txpower_dbm(struct ieee80211_hw *hw,
+				     long power_indbm);
+void rtl8723e_phy_scan_operation_backup(struct ieee80211_hw *hw,
+					u8 operation);
+void rtl8723e_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+void rtl8723e_phy_set_bw_mode(struct ieee80211_hw *hw,
+			      enum nl80211_channel_type ch_type);
+void rtl8723e_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+u8 rtl8723e_phy_sw_chnl(struct ieee80211_hw *hw);
+void rtl8723e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
+void rtl8723e_phy_lc_calibrate(struct ieee80211_hw *hw);
+void rtl8723e_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
+bool rtl8723e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+					    enum radio_path rfpath);
+bool rtl8723e_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
+bool rtl8723e_phy_set_rf_power_state(struct ieee80211_hw *hw,
+				     enum rf_pwrstate rfpwr_state);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.c
index df6ca9a..2f7f81a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -27,83 +23,90 @@
  *
  *****************************************************************************/
 
-#include "pwrseqcmd.h"
+#include "../pwrseqcmd.h"
 #include "pwrseq.h"
 
-/* drivers should parse arrays below and do the corresponding actions */
-
+/* drivers should parse below arrays and do the corresponding actions */
 /*3 Power on  Array*/
-struct wlan_pwr_cfg rtl8723A_power_on_flow[RTL8723A_TRANS_CARDEMU_TO_ACT_STPS
-					+ RTL8723A_TRANS_END_STPS] = {
-	RTL8723A_TRANS_CARDEMU_TO_ACT,
+struct wlan_pwr_cfg rtl8723A_power_on_flow
+		[RTL8723A_TRANS_CARDEMU_TO_ACT_STEPS +
+		 RTL8723A_TRANS_END_STEPS] = {
+	RTL8723A_TRANS_CARDEMU_TO_ACT
 	RTL8723A_TRANS_END
 };
 
 /*3Radio off GPIO Array */
-struct wlan_pwr_cfg rtl8723A_radio_off_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
-					+ RTL8723A_TRANS_END_STPS] = {
-	RTL8723A_TRANS_ACT_TO_CARDEMU,
+struct wlan_pwr_cfg rtl8723A_radio_off_flow
+		[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8723A_TRANS_END_STEPS] = {
+	RTL8723A_TRANS_ACT_TO_CARDEMU
 	RTL8723A_TRANS_END
 };
 
 /*3Card Disable Array*/
-struct wlan_pwr_cfg
-rtl8723A_card_disable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
-			  + RTL8723A_TRANS_CARDEMU_TO_PDN_STPS
-			  + RTL8723A_TRANS_END_STPS] = {
-	RTL8723A_TRANS_ACT_TO_CARDEMU,
-	RTL8723A_TRANS_CARDEMU_TO_CARDDIS,
+struct wlan_pwr_cfg rtl8723A_card_disable_flow
+		[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8723A_TRANS_END_STEPS] = {
+	RTL8723A_TRANS_ACT_TO_CARDEMU
+	RTL8723A_TRANS_CARDEMU_TO_CARDDIS
 	RTL8723A_TRANS_END
 };
 
 /*3 Card Enable Array*/
-struct wlan_pwr_cfg rtl8723A_card_enable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
-					+ RTL8723A_TRANS_CARDEMU_TO_PDN_STPS
-					+ RTL8723A_TRANS_END_STPS] = {
-	RTL8723A_TRANS_CARDDIS_TO_CARDEMU,
-	RTL8723A_TRANS_CARDEMU_TO_ACT,
+struct wlan_pwr_cfg rtl8723A_card_enable_flow
+		[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8723A_TRANS_END_STEPS] = {
+	RTL8723A_TRANS_CARDDIS_TO_CARDEMU
+	RTL8723A_TRANS_CARDEMU_TO_ACT
 	RTL8723A_TRANS_END
 };
 
 /*3Suspend Array*/
-struct wlan_pwr_cfg rtl8723A_suspend_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
-					+ RTL8723A_TRANS_CARDEMU_TO_SUS_STPS
-					+ RTL8723A_TRANS_END_STPS] = {
-	RTL8723A_TRANS_ACT_TO_CARDEMU,
-	RTL8723A_TRANS_CARDEMU_TO_SUS,
+struct wlan_pwr_cfg rtl8723A_suspend_flow
+		[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS +
+		 RTL8723A_TRANS_END_STEPS] = {
+	RTL8723A_TRANS_ACT_TO_CARDEMU
+	RTL8723A_TRANS_CARDEMU_TO_SUS
 	RTL8723A_TRANS_END
 };
 
 /*3 Resume Array*/
-struct wlan_pwr_cfg rtl8723A_resume_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
-					+ RTL8723A_TRANS_CARDEMU_TO_SUS_STPS
-					+ RTL8723A_TRANS_END_STPS] = {
-	RTL8723A_TRANS_SUS_TO_CARDEMU,
-	RTL8723A_TRANS_CARDEMU_TO_ACT,
+struct wlan_pwr_cfg rtl8723A_resume_flow
+		[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS +
+		 RTL8723A_TRANS_END_STEPS] = {
+	RTL8723A_TRANS_SUS_TO_CARDEMU
+	RTL8723A_TRANS_CARDEMU_TO_ACT
 	RTL8723A_TRANS_END
 };
 
 /*3HWPDN Array*/
-struct wlan_pwr_cfg rtl8723A_hwpdn_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
-				+ RTL8723A_TRANS_CARDEMU_TO_PDN_STPS
-				+ RTL8723A_TRANS_END_STPS] = {
-	RTL8723A_TRANS_ACT_TO_CARDEMU,
-	RTL8723A_TRANS_CARDEMU_TO_PDN,
+struct wlan_pwr_cfg rtl8723A_hwpdn_flow
+		[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8723A_TRANS_END_STEPS] = {
+	RTL8723A_TRANS_ACT_TO_CARDEMU
+	RTL8723A_TRANS_CARDEMU_TO_PDN
 	RTL8723A_TRANS_END
 };
 
 /*3 Enter LPS */
-struct wlan_pwr_cfg rtl8723A_enter_lps_flow[RTL8723A_TRANS_ACT_TO_LPS_STPS
-					+ RTL8723A_TRANS_END_STPS] = {
+struct wlan_pwr_cfg rtl8723A_enter_lps_flow
+		[RTL8723A_TRANS_ACT_TO_LPS_STEPS +
+		 RTL8723A_TRANS_END_STEPS] = {
 	/*FW behavior*/
-	RTL8723A_TRANS_ACT_TO_LPS,
+	RTL8723A_TRANS_ACT_TO_LPS
 	RTL8723A_TRANS_END
 };
 
 /*3 Leave LPS */
-struct wlan_pwr_cfg rtl8723A_leave_lps_flow[RTL8723A_TRANS_LPS_TO_ACT_STPS
-					+ RTL8723A_TRANS_END_STPS] = {
+struct wlan_pwr_cfg rtl8723A_leave_lps_flow
+		[RTL8723A_TRANS_LPS_TO_ACT_STEPS +
+		 RTL8723A_TRANS_END_STEPS] = {
 	/*FW behavior*/
-	RTL8723A_TRANS_LPS_TO_ACT,
+	RTL8723A_TRANS_LPS_TO_ACT
 	RTL8723A_TRANS_END
 };
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h
index a418acb..4ac7db5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,282 +26,305 @@
 #ifndef __RTL8723E_PWRSEQ_H__
 #define __RTL8723E_PWRSEQ_H__
 
+#include "../pwrseqcmd.h"
 /*
-	Check document WM-20110607-Paul-RTL8723A_Power_Architecture-R02.vsd
-	There are 6 HW Power States:
-	0: POFF--Power Off
-	1: PDN--Power Down
-	2: CARDEMU--Card Emulation
-	3: ACT--Active Mode
-	4: LPS--Low Power State
-	5: SUS--Suspend
+ *	Check document WM-20110607-Paul-RTL8723A_Power_Architecture-R02.vsd
+ *	There are 6 HW Power States:
+ *	0: POFF--Power Off
+ *	1: PDN--Power Down
+ *	2: CARDEMU--Card Emulation
+ *	3: ACT--Active Mode
+ *	4: LPS--Low Power State
+ *	5: SUS--Suspend
+ *
+ *	The transision from different states are defined below
+ *	TRANS_CARDEMU_TO_ACT
+ *	TRANS_ACT_TO_CARDEMU
+ *	TRANS_CARDEMU_TO_SUS
+ *	TRANS_SUS_TO_CARDEMU
+ *	TRANS_CARDEMU_TO_PDN
+ *	TRANS_ACT_TO_LPS
+ *	TRANS_LPS_TO_ACT
+ *
+ *	TRANS_END
+ */
 
-	The transision from different states are defined below
-	TRANS_CARDEMU_TO_ACT
-	TRANS_ACT_TO_CARDEMU
-	TRANS_CARDEMU_TO_SUS
-	TRANS_SUS_TO_CARDEMU
-	TRANS_CARDEMU_TO_PDN
-	TRANS_ACT_TO_LPS
-	TRANS_LPS_TO_ACT
+#define	RTL8723A_TRANS_CARDEMU_TO_ACT_STEPS	10
+#define	RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS	10
+#define	RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS	10
+#define	RTL8723A_TRANS_SUS_TO_CARDEMU_STEPS	10
+#define	RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS	10
+#define	RTL8723A_TRANS_PDN_TO_CARDEMU_STEPS	10
+#define	RTL8723A_TRANS_ACT_TO_LPS_STEPS		15
+#define	RTL8723A_TRANS_LPS_TO_ACT_STEPS		15
+#define	RTL8723A_TRANS_END_STEPS		1
 
-	TRANS_END
-*/
+/* format */
+/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }*/
 
-#define	RTL8723A_TRANS_CARDEMU_TO_ACT_STPS	10
-#define	RTL8723A_TRANS_ACT_TO_CARDEMU_STPS	10
-#define	RTL8723A_TRANS_CARDEMU_TO_SUS_STPS	10
-#define	RTL8723A_TRANS_SUS_TO_CARDEMU_STPS	10
-#define	RTL8723A_TRANS_CARDEMU_TO_PDN_STPS	10
-#define	RTL8723A_TRANS_PDN_TO_CARDEMU_STPS	10
-#define	RTL8723A_TRANS_ACT_TO_LPS_STPS		15
-#define	RTL8723A_TRANS_LPS_TO_ACT_STPS		15
-#define	RTL8723A_TRANS_END_STPS			1
+#define RTL8723A_TRANS_CARDEMU_TO_ACT	\
+	/* disable SW LPS 0x04[10]=0*/	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), 0},\
+	/* wait till 0x04[17] = 1    power ready*/	\
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)},\
+	/* release WLON reset  0x04[16]=1*/	\
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},\
+	/* disable HWPDN 0x04[15]=0*/ \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},\
+	/* disable WL suspend*/ \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT(4)|BIT(3)), 0},\
+	/* polling until return 0*/ \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0},
 
+/* format */
+/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */
 
-#define RTL8723A_TRANS_CARDEMU_TO_ACT					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, \
-	 *  comments here*/						\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), 0},		\
-		/* disable SW LPS 0x04[10]=0*/				\
-	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)},	\
-		/* wait till 0x04[17] = 1    power ready*/		\
-	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},	\
-		/* release WLON reset  0x04[16]=1*/			\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},		\
-		/* disable HWPDN 0x04[15]=0*/				\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT(4)|BIT(3)), 0},	\
-	/* disable WL suspend*/						\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},	\
-		/* polling until return 0*/				\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0}
+#define RTL8723A_TRANS_ACT_TO_CARDEMU	\
+	/*0x1F[7:0] = 0 turn off RF*/ \
+	{0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},	\
+	{0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0},
 
-#define RTL8723A_TRANS_ACT_TO_CARDEMU					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, \
-	 *  comments here*/						\
-	{0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},		\
-		/*0x1F[7:0] = 0 turn off RF*/				\
-	{0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},		\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},	\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0}
-
-#define RTL8723A_TRANS_CARDEMU_TO_SUS					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, \
-	 *  comments here*/						\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4)|BIT(3),		\
-		(BIT(4)|BIT(3))},					\
+/* format */
+/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/
+#define RTL8723A_TRANS_CARDEMU_TO_SUS			\
 		/*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/	\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK |	\
-		PWR_INTF_SDIO_MSK,					\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},\
-		 /*0x04[12:11] = 2b'01 enable WL suspend*/		\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
-		PWR_BASEADDR_MAC,					\
-		PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)|BIT(4)},		\
-		 /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/	\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-		PWR_BASEADDR_SDIO,					\
-		PWR_CMD_WRITE, BIT(0), BIT(0)},				\
-		/*Set SDIO suspend local register*/			\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-		PWR_BASEADDR_SDIO,					\
-		PWR_CMD_POLLING, BIT(1), 0}				\
-		/*wait power state to suspend*/
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_WRITE, \
+		BIT(4)|BIT(3), (BIT(4)|BIT(3))},\
+/*0x04[12:11] = 2b'01 enable WL suspend*/	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK| \
+		PWR_INTF_SDIO_MSK,\
+		PWR_BASEADDR_MAC, \
+		PWR_CMD_WRITE, \
+		BIT(3)|BIT(4), BIT(3)}, \
+/*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, \
+		PWR_CMD_WRITE, BIT(3)|BIT(4), \
+		BIT(3)|BIT(4)}, \
+/*Set SDIO suspend local register*/	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO,\
+		PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+/*wait power state to suspend*/ \
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO,\
+		PWR_CMD_POLLING, BIT(1), 0},
 
-#define RTL8723A_TRANS_SUS_TO_CARDEMU					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-		PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0},		\
-		/*Set SDIO suspend local register*/			\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-		PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},	\
-		/*wait power state to suspend*/				\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}	\
-		/*0x04[12:11] = 2b'01enable WL suspend*/
+/* format */
+/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */
 
-#define RTL8723A_TRANS_CARDEMU_TO_CARDDIS				\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
-	PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,				\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},\
-		/*0x04[12:11] = 2b'01 enable WL suspend*/		\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), BIT(2)},	\
-		/*0x04[10] = 1, enable SW LPS*/				\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-		PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)},	\
-		/*Set SDIO suspend local register*/			\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-		PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0}		\
-		/*wait power state to suspend*/
+#define RTL8723A_TRANS_SUS_TO_CARDEMU	\
+ /*Set SDIO suspend local register*/	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+		PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0},\
+ /*wait power state to suspend*/ \
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+		PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},\
+ /*0x04[12:11] = 2b'01enable WL suspend*/ \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},
 
-#define RTL8723A_TRANS_CARDDIS_TO_CARDEMU				\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-		PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0},		\
-		/*Set SDIO suspend local register*/			\
-	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-		PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},	\
-		/*wait power state to suspend*/				\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},	\
-		/*0x04[12:11] = 2b'00enable WL suspend*/		\
-	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}		\
-		/*PCIe DMA start*/
+/* format */
+/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */
 
-#define RTL8723A_TRANS_CARDEMU_TO_PDN					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
-	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},		\
-		/* 0x04[16] = 0*/\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)}	\
-		/* 0x04[15] = 1*/
+#define RTL8723A_TRANS_CARDEMU_TO_CARDDIS \
+ /*0x04[12:11] = 2b'01 enable WL suspend*/	 \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, \
+/*0x04[10] = 1, enable SW LPS*/	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(2), BIT(2)}, \
+/*Set SDIO suspend local register*/ \
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO,\
+		PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ /*wait power state to suspend*/ \
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO,\
+		PWR_CMD_POLLING, BIT(1), 0},
 
-#define RTL8723A_TRANS_PDN_TO_CARDEMU					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
-	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0}		\
-		/* 0x04[15] = 0*/
+/* format */
+/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */
 
-#define RTL8723A_TRANS_ACT_TO_LPS					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
-	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},		\
-		/*PCIe DMA stop*/					\
-	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F},		\
-		/*Tx Pause*/						\
-	{0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},		\
-		/*Should be zero if no packet is transmitting*/		\
-	{0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},		\
-		/*Should be zero if no packet is transmitting*/		\
-	{0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},		\
-		/*Should be zero if no packet is transmitting*/		\
-	{0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},		\
-		/*Should be zero if no packet is transmitting*/		\
-	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},		\
-		/*CCK and OFDM are disabled,and clock are gated*/	\
-	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},	\
-		/*Delay 1us*/						\
-	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},		\
-		/*Whole BB is reset*/					\
-	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3F},		\
-		/*Reset MAC TRX*/					\
-	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},		\
-		/*check if removed later*/				\
-	{0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)}	\
-		/*Respond TxOK to scheduler*/
+#define RTL8723A_TRANS_CARDDIS_TO_CARDEMU\
+/*Set SDIO suspend local register*/	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO,\
+		PWR_CMD_WRITE, BIT(0), 0}, \
+ /*wait power state to suspend*/ \
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO,\
+		PWR_CMD_POLLING, BIT(1), BIT(1)},\
+ /*0x04[12:11] = 2b'00enable WL suspend*/ \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(3)|BIT(4), 0},\
+/*PCIe DMA start*/ \
+	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, 0xFF, 0},
 
-#define RTL8723A_TRANS_LPS_TO_ACT					\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
-	{0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-		 PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84},		\
-		 /*SDIO RPWM*/						\
-	{0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84},		\
-		/*USB RPWM*/						\
-	{0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84},		\
-		/*PCIe RPWM*/						\
-	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		 PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS},	\
-		/*Delay*/						\
-	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},		\
-		/* 0x08[4] = 0 switch TSF to 40M*/			\
-	{0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0},		\
-		/*Polling 0x109[7]=0  TSF in 40M*/			\
-	{0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6)|BIT(7), 0},	\
-		/*.	0x29[7:6] = 2b'00	 enable BB clock*/	\
-	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},	\
-		/*.	0x101[1] = 1*/					\
-	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},		\
-		/* 0x100[7:0] = 0xFF enable WMAC TRX*/			\
-	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1)|BIT(0),		\
-		BIT(1)|BIT(0)},						\
-		/* 0x02[1:0] = 2b'11  enable BB macro*/			\
-	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-		PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}		\
-		/*.	0x522 = 0*/
+/* format */
+/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */
+#define RTL8723A_TRANS_CARDEMU_TO_PDN	\
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(0), 0},/* 0x04[16] = 0*/\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(7), BIT(7)},/* 0x04[15] = 1*/
 
-#define RTL8723A_TRANS_END						\
-	/* format */							\
-	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
-	{0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+/* format */
+/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */
+#define RTL8723A_TRANS_PDN_TO_CARDEMU	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(7), 0},/* 0x04[15] = 0*/
+
+/* format */
+/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */
+
+#define RTL8723A_TRANS_ACT_TO_LPS	\
+	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/	\
+	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, 0xFF, 0x7F},/*Tx Pause*/	\
+	/*Should be zero if no packet is transmitting*/	\
+	{0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_POLLING, 0xFF, 0},\
+	/*Should be zero if no packet is transmitting*/	\
+	{0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_POLLING, 0xFF, 0},\
+	/*Should be zero if no packet is transmitting*/	\
+	{0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_POLLING, 0xFF, 0},\
+	/*Should be zero if no packet is transmitting*/	\
+	{0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_POLLING, 0xFF, 0},\
+	/*CCK and OFDM are disabled,and clock are gated*/ \
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(0), 0},\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(1), 0},/*Whole BB is reset*/	\
+	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, 0xFF, 0x3F},/*Reset MAC TRX*/	\
+	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(1), 0},/*check if removed later*/	\
+	/*Respond TxOK to scheduler*/	\
+	{0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(5), BIT(5)},\
+
+#define RTL8723A_TRANS_LPS_TO_ACT\
+/* format */	\
+/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */	\
+	{0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO,\
+		PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\
+	{0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_USB_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\
+	{0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\
+	/*.	0x08[4] = 0		 switch TSF to 40M*/\
+	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(4), 0},  \
+	/*Polling 0x109[7]=0  TSF in 40M*/\
+	{0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_POLLING, BIT(7), 0}, \
+	/*.	0x29[7:6] = 2b'00	 enable BB clock*/\
+	{0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(6)|BIT(7), 0},\
+	 /*.	0x101[1] = 1*/\
+	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(1), BIT(1)},\
+	 /*.	0x100[7:0] = 0xFF	 enable WMAC TRX*/\
+	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, 0xFF, 0xFF},\
+	 /*.	0x02[1:0] = 2b'11	 enable BB macro*/\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, BIT(1)|BIT(0), BIT(1)|BIT(0)},\
+	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+		PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\
+		PWR_CMD_WRITE, 0xFF, 0}, /*.	0x522 = 0*/
+
+/* format */
+/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */
+
+#define RTL8723A_TRANS_END \
+	{0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
 	0, PWR_CMD_END, 0, 0}
 
-extern struct
-wlan_pwr_cfg rtl8723A_power_on_flow[RTL8723A_TRANS_CARDEMU_TO_ACT_STPS
-				    + RTL8723A_TRANS_END_STPS];
-extern struct
-wlan_pwr_cfg rtl8723A_radio_off_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
-				     + RTL8723A_TRANS_END_STPS];
-extern struct
-wlan_pwr_cfg rtl8723A_card_disable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
-					+ RTL8723A_TRANS_CARDEMU_TO_PDN_STPS
-					+ RTL8723A_TRANS_END_STPS];
-extern struct
-wlan_pwr_cfg rtl8723A_card_enable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
-				       + RTL8723A_TRANS_CARDEMU_TO_PDN_STPS
-				       + RTL8723A_TRANS_END_STPS];
-extern struct
-wlan_pwr_cfg rtl8723A_suspend_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
-				   + RTL8723A_TRANS_CARDEMU_TO_SUS_STPS
-				   + RTL8723A_TRANS_END_STPS];
-extern struct
-wlan_pwr_cfg rtl8723A_resume_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
-				  + RTL8723A_TRANS_CARDEMU_TO_SUS_STPS
-				  + RTL8723A_TRANS_END_STPS];
-extern struct
-wlan_pwr_cfg rtl8723A_hwpdn_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
-				 + RTL8723A_TRANS_CARDEMU_TO_PDN_STPS
-				 + RTL8723A_TRANS_END_STPS];
-extern struct
-wlan_pwr_cfg rtl8723A_enter_lps_flow[RTL8723A_TRANS_ACT_TO_LPS_STPS
-				     + RTL8723A_TRANS_END_STPS];
-extern struct
-wlan_pwr_cfg rtl8723A_leave_lps_flow[RTL8723A_TRANS_LPS_TO_ACT_STPS
-				     + RTL8723A_TRANS_END_STPS];
+extern struct wlan_pwr_cfg rtl8723A_power_on_flow
+		[RTL8723A_TRANS_CARDEMU_TO_ACT_STEPS +
+		 RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723A_radio_off_flow
+		[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723A_card_disable_flow
+		[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723A_card_enable_flow
+		[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723A_suspend_flow
+		[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS +
+		 RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723A_resume_flow
+		[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS +
+		 RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723A_hwpdn_flow
+		[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723A_enter_lps_flow
+		[RTL8723A_TRANS_ACT_TO_LPS_STEPS + RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723A_leave_lps_flow
+		[RTL8723A_TRANS_LPS_TO_ACT_STEPS + RTL8723A_TRANS_END_STEPS];
 
 /* RTL8723 Power Configuration CMDs for PCIe interface */
 #define Rtl8723_NIC_PWR_ON_FLOW		rtl8723A_power_on_flow
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.c b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.c
deleted file mode 100644
index 2044b59..0000000
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2009-2012  Realtek Corporation.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * wlanfae <wlanfae@realtek.com>
- * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
- * Hsinchu 300, Taiwan.
- *
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- *****************************************************************************/
-
-#include "pwrseq.h"
-
-/*	Description:
- *		This routine deals with the Power Configuration CMD
- *		 parsing for RTL8723/RTL8188E Series IC.
- *	Assumption:
- *		We should follow specific format that was released from HW SD.
- */
-bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
-			      u8 faversion, u8 interface_type,
-			      struct wlan_pwr_cfg pwrcfgcmd[])
-{
-	struct wlan_pwr_cfg cfg_cmd = {0};
-	bool polling_bit = false;
-	u32 ary_idx = 0;
-	u8 value = 0;
-	u32 offset = 0;
-	u32 polling_count = 0;
-	u32 max_polling_cnt = 5000;
-
-	do {
-		cfg_cmd = pwrcfgcmd[ary_idx];
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			"rtl_hal_pwrseqcmdparsing(): offset(%#x),cut_msk(%#x), famsk(%#x),"
-			"interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), value(%#x)\n",
-			GET_PWR_CFG_OFFSET(cfg_cmd),
-					   GET_PWR_CFG_CUT_MASK(cfg_cmd),
-			GET_PWR_CFG_FAB_MASK(cfg_cmd),
-					     GET_PWR_CFG_INTF_MASK(cfg_cmd),
-			GET_PWR_CFG_BASE(cfg_cmd), GET_PWR_CFG_CMD(cfg_cmd),
-			GET_PWR_CFG_MASK(cfg_cmd), GET_PWR_CFG_VALUE(cfg_cmd));
-
-		if ((GET_PWR_CFG_FAB_MASK(cfg_cmd)&faversion) &&
-		    (GET_PWR_CFG_CUT_MASK(cfg_cmd)&cut_version) &&
-		    (GET_PWR_CFG_INTF_MASK(cfg_cmd)&interface_type)) {
-			switch (GET_PWR_CFG_CMD(cfg_cmd)) {
-			case PWR_CMD_READ:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_READ\n");
-				break;
-			case PWR_CMD_WRITE:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n");
-				offset = GET_PWR_CFG_OFFSET(cfg_cmd);
-
-				/*Read the value from system register*/
-				value = rtl_read_byte(rtlpriv, offset);
-				value &= (~(GET_PWR_CFG_MASK(cfg_cmd)));
-				value |= (GET_PWR_CFG_VALUE(cfg_cmd) &
-					  GET_PWR_CFG_MASK(cfg_cmd));
-
-				/*Write the value back to sytem register*/
-				rtl_write_byte(rtlpriv, offset, value);
-				break;
-			case PWR_CMD_POLLING:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n");
-				polling_bit = false;
-				offset = GET_PWR_CFG_OFFSET(cfg_cmd);
-
-				do {
-					value = rtl_read_byte(rtlpriv, offset);
-
-					value &= GET_PWR_CFG_MASK(cfg_cmd);
-					if (value ==
-					    (GET_PWR_CFG_VALUE(cfg_cmd)
-					    & GET_PWR_CFG_MASK(cfg_cmd)))
-						polling_bit = true;
-					else
-						udelay(10);
-
-					if (polling_count++ > max_polling_cnt)
-						return false;
-				} while (!polling_bit);
-				break;
-			case PWR_CMD_DELAY:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					"rtl_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n");
-				if (GET_PWR_CFG_VALUE(cfg_cmd) ==
-				    PWRSEQ_DELAY_US)
-					udelay(GET_PWR_CFG_OFFSET(cfg_cmd));
-				else
-					mdelay(GET_PWR_CFG_OFFSET(cfg_cmd));
-				break;
-			case PWR_CMD_END:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					 "rtl_hal_pwrseqcmdparsing(): PWR_CMD_END\n");
-				return true;
-			default:
-				RT_ASSERT(false,
-					 "rtl_hal_pwrseqcmdparsing(): Unknown CMD!!\n");
-				break;
-			}
-
-		}
-		ary_idx++;
-	} while (1);
-
-	return true;
-}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h
index ce2c66f..306059f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -34,13 +30,13 @@
 #define REG_SYS_FUNC_EN				0x0002
 #define REG_APS_FSMCO				0x0004
 #define REG_SYS_CLKR				0x0008
-#define REG_9346CR				0x000A
-#define REG_EE_VPD				0x000C
+#define REG_9346CR					0x000A
+#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 REG_RF_CTRL					0x001F
 #define REG_LDOA15_CTRL				0x0020
 #define REG_LDOV12D_CTRL			0x0021
 #define REG_LDOHCI12_CTRL			0x0022
@@ -57,12 +53,12 @@
 #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 REG_LEDCFG3				0x004F
-#define REG_FSIMR				0x0050
-#define REG_FSISR				0x0054
+#define REG_LEDCFG0					0x004C
+#define REG_LEDCFG1					0x004D
+#define REG_LEDCFG2					0x004E
+#define REG_LEDCFG3					0x004F
+#define REG_FSIMR					0x0050
+#define REG_FSISR					0x0054
 #define REG_GPIO_PIN_CTRL_2			0x0060
 #define REG_GPIO_IO_SEL_2			0x0062
 #define REG_MULTI_FUNC_CTRL			0x0068
@@ -80,25 +76,25 @@
 #define REG_USB_SIE_INTF			0x00E0
 #define REG_PCIE_MIO_INTF			0x00E4
 #define REG_PCIE_MIO_INTD			0x00E8
-#define REG_SYS_CFG				0x00F0
+#define REG_SYS_CFG					0x00F0
 #define REG_GPIO_OUTSTS				0x00F4
 
-#define REG_CR					0x0100
-#define REG_PBP					0x0104
+#define REG_CR						0x0100
+#define REG_PBP						0x0104
 #define REG_TRXDMA_CTRL				0x010C
 #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_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_PKTBUF_DBG_DATA_L		0x0144
+#define REG_PKTBUF_DBG_DATA_H		0x0148
 
 #define REG_TC0_CTRL				0x0150
 #define REG_TC1_CTRL				0x0154
@@ -109,11 +105,11 @@
 #define REG_MBIST_START				0x0174
 #define REG_MBIST_DONE				0x0178
 #define REG_MBIST_FAIL				0x017C
-#define REG_C2HEVT_MSG_NORMAL			0x01A0
+#define REG_C2HEVT_MSG_NORMAL		0x01A0
 #define REG_C2HEVT_MSG_TEST			0x01B8
 #define REG_MCUTST_1				0x01c0
-#define REG_FMETHR				0x01C8
-#define REG_HMETFR				0x01CC
+#define REG_FMETHR					0x01C8
+#define REG_HMETFR					0x01CC
 #define REG_HMEBOX_0				0x01D0
 #define REG_HMEBOX_1				0x01D4
 #define REG_HMEBOX_2				0x01D8
@@ -123,10 +119,10 @@
 #define REG_BB_ACCEESS_CTRL			0x01E8
 #define REG_BB_ACCESS_DATA			0x01EC
 
-#define REG_RQPN				0x0200
+#define REG_RQPN					0x0200
 #define REG_FIFOPAGE				0x0204
-#define REG_TDECTRL				0x0208
-#define REG_TXDMA_OFFSET_CHK			0x020C
+#define REG_TDECTRL					0x0208
+#define REG_TXDMA_OFFSET_CHK		0x020C
 #define REG_TXDMA_STATUS			0x0210
 #define REG_RQPN_NPQ				0x0214
 
@@ -135,18 +131,18 @@
 #define REG_RXDMA_STATUS			0x0288
 
 #define	REG_PCIE_CTRL_REG			0x0300
-#define	REG_INT_MIG				0x0304
+#define	REG_INT_MIG					0x0304
 #define	REG_BCNQ_DESA				0x0308
-#define	REG_HQ_DESA				0x0310
+#define	REG_HQ_DESA					0x0310
 #define	REG_MGQ_DESA				0x0318
 #define	REG_VOQ_DESA				0x0320
 #define	REG_VIQ_DESA				0x0328
 #define	REG_BEQ_DESA				0x0330
 #define	REG_BKQ_DESA				0x0338
-#define	REG_RX_DESA				0x0340
-#define	REG_DBI					0x0348
-#define	REG_MDIO				0x0354
-#define	REG_DBG_SEL				0x0360
+#define	REG_RX_DESA					0x0340
+#define	REG_DBI						0x0348
+#define	REG_MDIO					0x0354
+#define	REG_DBG_SEL					0x0360
 #define	REG_PCIE_HRPWM				0x0361
 #define	REG_PCIE_HCPWM				0x0363
 #define	REG_UART_CTRL				0x0364
@@ -162,31 +158,31 @@
 #define REG_BKQ_INFORMATION			0x040C
 #define REG_MGQ_INFORMATION			0x0410
 #define REG_HGQ_INFORMATION			0x0414
-#define REG_BCNQ_INFORMATION			0x0418
+#define REG_BCNQ_INFORMATION		0x0418
 
-#define REG_CPU_MGQ_INFORMATION			0x041C
+#define REG_CPU_MGQ_INFORMATION		0x041C
 #define REG_FWHW_TXQ_CTRL			0x0420
 #define REG_HWSEQ_CTRL				0x0423
-#define REG_TXPKTBUF_BCNQ_BDNY			0x0424
-#define REG_TXPKTBUF_MGQ_BDNY			0x0425
+#define REG_TXPKTBUF_BCNQ_BDNY		0x0424
+#define REG_TXPKTBUF_MGQ_BDNY		0x0425
 #define REG_MULTI_BCNQ_EN			0x0426
-#define REG_MULTI_BCNQ_OFFSET			0x0427
+#define REG_MULTI_BCNQ_OFFSET		0x0427
 #define REG_SPEC_SIFS				0x0428
-#define REG_RL					0x042A
-#define REG_DARFRC				0x0430
-#define REG_RARFRC				0x0438
-#define REG_RRSR				0x0440
-#define REG_ARFR0				0x0444
-#define REG_ARFR1				0x0448
-#define REG_ARFR2				0x044C
-#define REG_ARFR3				0x0450
+#define REG_RL						0x042A
+#define REG_DARFRC					0x0430
+#define REG_RARFRC					0x0438
+#define REG_RRSR					0x0440
+#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_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_INIDATA_RATE_SEL		0x0484
 #define REG_POWER_STATUS			0x04A4
 #define REG_POWER_STAGE1			0x04B4
 #define REG_POWER_STAGE2			0x04B8
@@ -194,29 +190,29 @@
 #define REG_STBC_SETTING			0x04C4
 #define REG_PROT_MODE_CTRL			0x04C8
 #define REG_BAR_MODE_CTRL			0x04CC
-#define REG_RA_TRY_RATE_AGG_LMT			0x04CF
+#define REG_RA_TRY_RATE_AGG_LMT		0x04CF
 #define REG_NQOS_SEQ				0x04DC
-#define REG_QOS_SEQ				0x04DE
+#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
+#define REG_DUMMY					0x04FC
 
 #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 REG_BCNTCFG				0x0510
-#define REG_PIFS				0x0512
+#define REG_BCNTCFG					0x0510
+#define REG_PIFS					0x0512
 #define REG_RDG_PIFS				0x0513
 #define REG_SIFS_CTX				0x0514
 #define REG_SIFS_TRX				0x0516
 #define REG_AGGR_BREAK_TIME			0x051A
-#define REG_SLOT				0x051B
+#define REG_SLOT					0x051B
 #define REG_TX_PTCL_CTRL			0x0520
-#define REG_TXPAUSE				0x0522
+#define REG_TXPAUSE					0x0522
 #define REG_DIS_TXREQ_CLR			0x0523
-#define REG_RD_CTRL				0x0524
+#define REG_RD_CTRL					0x0524
 #define REG_TBTT_PROHIBIT			0x0540
 #define REG_RD_NAV_NXT				0x0544
 #define REG_NAV_PROT_LEN			0x0546
@@ -225,21 +221,21 @@
 #define REG_MBID_NUM				0x0552
 #define REG_DUAL_TSF_RST			0x0553
 #define REG_BCN_INTERVAL			0x0554
-#define REG_MBSSID_BCN_SPACE			0x0554
+#define REG_MBSSID_BCN_SPACE		0x0554
 #define REG_DRVERLYINT				0x0558
 #define REG_BCNDMATIM				0x0559
-#define REG_ATIMWND				0x055A
+#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_RXTSF_OFFSET_CCK		0x055E
+#define REG_RXTSF_OFFSET_OFDM		0x055F
+#define REG_TSFTR					0x0560
 #define REG_INIT_TSFTR				0x0564
-#define REG_PSTIMER				0x0580
-#define REG_TIMER0				0x0584
-#define REG_TIMER1				0x0588
+#define REG_PSTIMER					0x0580
+#define REG_TIMER0					0x0584
+#define REG_TIMER1					0x0588
 #define REG_ACMHWCTRL				0x05C0
 #define REG_ACMRSTCTRL				0x05C1
-#define REG_ACMAVG				0x05C2
+#define REG_ACMAVG					0x05C2
 #define REG_VO_ADMTIME				0x05C4
 #define REG_VI_ADMTIME				0x05C6
 #define REG_BE_ADMTIME				0x05C8
@@ -248,38 +244,38 @@
 
 #define REG_APSD_CTRL				0x0600
 #define REG_BWOPMODE				0x0603
-#define REG_TCR					0x0604
-#define REG_RCR					0x0608
+#define REG_TCR						0x0604
+#define REG_RCR						0x0608
 #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_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
 #define REG_RESP_SIFS_CCK			0x063C
 #define REG_RESP_SIFS_OFDM			0x063E
-#define REG_ACKTO				0x0640
-#define REG_CTS2TO				0x0641
-#define REG_EIFS				0x0642
+#define REG_ACKTO					0x0640
+#define REG_CTS2TO					0x0641
+#define REG_EIFS					0x0642
 
 #define REG_NAV_CTRL				0x0650
 #define REG_BACAMCMD				0x0654
 #define REG_BACAMCONTENT			0x0658
-#define REG_LBDLY				0x0660
-#define REG_FWDLY				0x0661
+#define REG_LBDLY					0x0660
+#define REG_FWDLY					0x0661
 #define REG_RXERR_RPT				0x0664
-#define REG_WMAC_TRXPTCL_CTL			0x0668
+#define REG_WMAC_TRXPTCL_CTL		0x0668
 
-#define REG_CAMCMD				0x0670
+#define REG_CAMCMD					0x0670
 #define REG_CAMWRITE				0x0674
-#define REG_CAMREAD				0x0678
-#define REG_CAMDBG				0x067C
-#define REG_SECCFG				0x0680
+#define REG_CAMREAD					0x0678
+#define REG_CAMDBG					0x067C
+#define REG_SECCFG					0x0680
 
 #define REG_WOW_CTRL				0x0690
 #define REG_PSSTATUS				0x0691
@@ -294,10 +290,10 @@
 #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_WMAC_RESP_TXINFO		0x06D8
 
 #define REG_USB_INFO				0xFE17
-#define REG_USB_SPECIAL_OPTION			0xFE55
+#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
@@ -305,120 +301,148 @@
 #define REG_TEST_USB_TXQS			0xFE48
 #define REG_TEST_SIE_VID			0xFE60
 #define REG_TEST_SIE_PID			0xFE62
-#define REG_TEST_SIE_OPTIONAL			0xFE64
-#define REG_TEST_SIE_CHIRP_K			0xFE65
+#define REG_TEST_SIE_OPTIONAL		0xFE64
+#define REG_TEST_SIE_CHIRP_K		0xFE65
 #define REG_TEST_SIE_PHY			0xFE66
-#define REG_TEST_SIE_MAC_ADDR			0xFE70
+#define REG_TEST_SIE_MAC_ADDR		0xFE70
 #define REG_TEST_SIE_STRING			0xFE80
 
 #define REG_NORMAL_SIE_VID			0xFE60
 #define REG_NORMAL_SIE_PID			0xFE62
-#define REG_NORMAL_SIE_OPTIONAL			0xFE64
+#define REG_NORMAL_SIE_OPTIONAL		0xFE64
 #define REG_NORMAL_SIE_EP			0xFE65
 #define REG_NORMAL_SIE_PHY			0xFE68
-#define REG_NORMAL_SIE_MAC_ADDR			0xFE70
-#define REG_NORMAL_SIE_STRING			0xFE80
+#define REG_NORMAL_SIE_MAC_ADDR		0xFE70
+#define REG_NORMAL_SIE_STRING		0xFE80
 
-#define	CR9346					REG_9346CR
-#define	MSR					(REG_CR + 2)
-#define	ISR					REG_HISR
-#define	TSFR					REG_TSFTR
+#define	CR9346				REG_9346CR
+#define	MSR				(REG_CR + 2)
+#define	ISR				REG_HISR
+#define	TSFR				REG_TSFTR
 
-#define	MACIDR0					REG_MACID
-#define	MACIDR4					(REG_MACID + 4)
+#define	MACIDR0				REG_MACID
+#define	MACIDR4				(REG_MACID + 4)
 
-#define PBP					REG_PBP
+#define PBP				REG_PBP
 
-#define	IDR0					MACIDR0
-#define	IDR4					MACIDR4
+#define	IDR0				MACIDR0
+#define	IDR4				MACIDR4
 
-#define	UNUSED_REGISTER				0x1BF
-#define	DCAM					UNUSED_REGISTER
-#define	PSR					UNUSED_REGISTER
-#define BBADDR					UNUSED_REGISTER
-#define	PHYDATAR				UNUSED_REGISTER
+#define	UNUSED_REGISTER			0x1BF
+#define	DCAM				UNUSED_REGISTER
+#define	PSR				UNUSED_REGISTER
+#define BBADDR				UNUSED_REGISTER
+#define	PHYDATAR			UNUSED_REGISTER
 
-#define	INVALID_BBRF_VALUE			0x12345678
+#define	INVALID_BBRF_VALUE		0x12345678
 
-#define	MAX_MSS_DENSITY_2T			0x13
-#define	MAX_MSS_DENSITY_1T			0x0A
+#define	MAX_MSS_DENSITY_2T		0x13
+#define	MAX_MSS_DENSITY_1T		0x0A
 
-#define	CMDEEPROM_EN				BIT(5)
-#define	CMDEEPROM_SEL				BIT(4)
-#define	CMD9346CR_9356SEL			BIT(4)
-#define	AUTOLOAD_EEPROM				(CMDEEPROM_EN|CMDEEPROM_SEL)
-#define	AUTOLOAD_EFUSE				CMDEEPROM_EN
+#define	CMDEEPROM_EN			BIT(5)
+#define	CMDEEPROM_SEL			BIT(4)
+#define	CMD9346CR_9356SEL		BIT(4)
+#define	AUTOLOAD_EEPROM			(CMDEEPROM_EN|CMDEEPROM_SEL)
+#define	AUTOLOAD_EFUSE			CMDEEPROM_EN
 
-#define	GPIOSEL_GPIO				0
-#define	GPIOSEL_ENBT				BIT(5)
+#define	GPIOSEL_GPIO			0
+#define	GPIOSEL_ENBT			BIT(5)
 
-#define	GPIO_IN					REG_GPIO_PIN_CTRL
-#define	GPIO_OUT				(REG_GPIO_PIN_CTRL+1)
-#define	GPIO_IO_SEL				(REG_GPIO_PIN_CTRL+2)
-#define	GPIO_MOD				(REG_GPIO_PIN_CTRL+3)
+#define	GPIO_IN				REG_GPIO_PIN_CTRL
+#define	GPIO_OUT			(REG_GPIO_PIN_CTRL+1)
+#define	GPIO_IO_SEL			(REG_GPIO_PIN_CTRL+2)
+#define	GPIO_MOD			(REG_GPIO_PIN_CTRL+3)
 
-#define	MSR_NOLINK				0x00
-#define	MSR_ADHOC				0x01
-#define	MSR_INFRA				0x02
-#define	MSR_AP					0x03
-#define	MSR_MASK				0x03
+#define	MSR_NOLINK					0x00
+#define	MSR_ADHOC					0x01
+#define	MSR_INFRA					0x02
+#define	MSR_AP						0x03
 
 #define	RRSR_RSC_OFFSET				21
 #define	RRSR_SHORT_OFFSET			23
 #define	RRSR_RSC_BW_40M				0x600000
 #define	RRSR_RSC_UPSUBCHNL			0x400000
 #define	RRSR_RSC_LOWSUBCHNL			0x200000
-#define	RRSR_SHORT				0x800000
-#define	RRSR_1M					BIT(0)
-#define	RRSR_2M					BIT(1)
-#define	RRSR_5_5M				BIT(2)
-#define	RRSR_11M				BIT(3)
-#define	RRSR_6M					BIT(4)
-#define	RRSR_9M					BIT(5)
-#define	RRSR_12M				BIT(6)
-#define	RRSR_18M				BIT(7)
-#define	RRSR_24M				BIT(8)
-#define	RRSR_36M				BIT(9)
-#define	RRSR_48M				BIT(10)
-#define	RRSR_54M				BIT(11)
-#define	RRSR_MCS0				BIT(12)
-#define	RRSR_MCS1				BIT(13)
-#define	RRSR_MCS2				BIT(14)
-#define	RRSR_MCS3				BIT(15)
-#define	RRSR_MCS4				BIT(16)
-#define	RRSR_MCS5				BIT(17)
-#define	RRSR_MCS6				BIT(18)
-#define	RRSR_MCS7				BIT(19)
+#define	RRSR_SHORT					0x800000
+#define	RRSR_1M						BIT(0)
+#define	RRSR_2M						BIT(1)
+#define	RRSR_5_5M					BIT(2)
+#define	RRSR_11M					BIT(3)
+#define	RRSR_6M						BIT(4)
+#define	RRSR_9M						BIT(5)
+#define	RRSR_12M					BIT(6)
+#define	RRSR_18M					BIT(7)
+#define	RRSR_24M					BIT(8)
+#define	RRSR_36M					BIT(9)
+#define	RRSR_48M					BIT(10)
+#define	RRSR_54M					BIT(11)
+#define	RRSR_MCS0					BIT(12)
+#define	RRSR_MCS1					BIT(13)
+#define	RRSR_MCS2					BIT(14)
+#define	RRSR_MCS3					BIT(15)
+#define	RRSR_MCS4					BIT(16)
+#define	RRSR_MCS5					BIT(17)
+#define	RRSR_MCS6					BIT(18)
+#define	RRSR_MCS7					BIT(19)
 #define	BRSR_ACKSHORTPMB			BIT(23)
 
-#define	RATR_1M					0x00000001
-#define	RATR_2M					0x00000002
-#define	RATR_55M				0x00000004
-#define	RATR_11M				0x00000008
-#define	RATR_6M					0x00000010
-#define	RATR_9M					0x00000020
-#define	RATR_12M				0x00000040
-#define	RATR_18M				0x00000080
-#define	RATR_24M				0x00000100
-#define	RATR_36M				0x00000200
-#define	RATR_48M				0x00000400
-#define	RATR_54M				0x00000800
-#define	RATR_MCS0				0x00001000
-#define	RATR_MCS1				0x00002000
-#define	RATR_MCS2				0x00004000
-#define	RATR_MCS3				0x00008000
-#define	RATR_MCS4				0x00010000
-#define	RATR_MCS5				0x00020000
-#define	RATR_MCS6				0x00040000
-#define	RATR_MCS7				0x00080000
-#define	RATR_MCS8				0x00100000
-#define	RATR_MCS9				0x00200000
-#define	RATR_MCS10				0x00400000
-#define	RATR_MCS11				0x00800000
-#define	RATR_MCS12				0x01000000
-#define	RATR_MCS13				0x02000000
-#define	RATR_MCS14				0x04000000
-#define	RATR_MCS15				0x08000000
+#define	RATR_1M						0x00000001
+#define	RATR_2M						0x00000002
+#define	RATR_55M					0x00000004
+#define	RATR_11M					0x00000008
+#define	RATR_6M						0x00000010
+#define	RATR_9M						0x00000020
+#define	RATR_12M					0x00000040
+#define	RATR_18M					0x00000080
+#define	RATR_24M					0x00000100
+#define	RATR_36M					0x00000200
+#define	RATR_48M					0x00000400
+#define	RATR_54M					0x00000800
+#define	RATR_MCS0					0x00001000
+#define	RATR_MCS1					0x00002000
+#define	RATR_MCS2					0x00004000
+#define	RATR_MCS3					0x00008000
+#define	RATR_MCS4					0x00010000
+#define	RATR_MCS5					0x00020000
+#define	RATR_MCS6					0x00040000
+#define	RATR_MCS7					0x00080000
+#define	RATR_MCS8					0x00100000
+#define	RATR_MCS9					0x00200000
+#define	RATR_MCS10					0x00400000
+#define	RATR_MCS11					0x00800000
+#define	RATR_MCS12					0x01000000
+#define	RATR_MCS13					0x02000000
+#define	RATR_MCS14					0x04000000
+#define	RATR_MCS15					0x08000000
+
+#define RATE_1M						BIT(0)
+#define RATE_2M						BIT(1)
+#define RATE_5_5M					BIT(2)
+#define RATE_11M					BIT(3)
+#define RATE_6M						BIT(4)
+#define RATE_9M						BIT(5)
+#define RATE_12M					BIT(6)
+#define RATE_18M					BIT(7)
+#define RATE_24M					BIT(8)
+#define RATE_36M					BIT(9)
+#define RATE_48M					BIT(10)
+#define RATE_54M					BIT(11)
+#define RATE_MCS0					BIT(12)
+#define RATE_MCS1					BIT(13)
+#define RATE_MCS2					BIT(14)
+#define RATE_MCS3					BIT(15)
+#define RATE_MCS4					BIT(16)
+#define RATE_MCS5					BIT(17)
+#define RATE_MCS6					BIT(18)
+#define RATE_MCS7					BIT(19)
+#define RATE_MCS8					BIT(20)
+#define RATE_MCS9					BIT(21)
+#define RATE_MCS10					BIT(22)
+#define RATE_MCS11					BIT(23)
+#define RATE_MCS12					BIT(24)
+#define RATE_MCS13					BIT(25)
+#define RATE_MCS14					BIT(26)
+#define RATE_MCS15					BIT(27)
 
 #define	RATE_ALL_CCK		(RATR_1M | RATR_2M | RATR_55M | RATR_11M)
 #define	RATE_ALL_OFDM_AG	(RATR_6M | RATR_9M | RATR_12M | RATR_18M |\
@@ -434,31 +458,31 @@
 #define	BW_OPMODE_5G				BIT(1)
 #define	BW_OPMODE_11J				BIT(0)
 
-#define	CAM_VALID				BIT(15)
+#define	CAM_VALID					BIT(15)
 #define	CAM_NOTVALID				0x0000
-#define	CAM_USEDK				BIT(5)
+#define	CAM_USEDK					BIT(5)
 
-#define	CAM_NONE				0x0
-#define	CAM_WEP40				0x01
-#define	CAM_TKIP				0x02
-#define	CAM_AES					0x04
-#define	CAM_WEP104				0x05
+#define	CAM_NONE					0x0
+#define	CAM_WEP40					0x01
+#define	CAM_TKIP					0x02
+#define	CAM_AES						0x04
+#define	CAM_WEP104					0x05
 
 #define	TOTAL_CAM_ENTRY				32
 #define	HALF_CAM_ENTRY				16
 
-#define	CAM_WRITE				BIT(16)
-#define	CAM_READ				0x00000000
+#define	CAM_WRITE					BIT(16)
+#define	CAM_READ					0x00000000
 #define	CAM_POLLINIG				BIT(31)
 
-#define	SCR_USEDK				0x01
+#define	SCR_USEDK					0x01
 #define	SCR_TXSEC_ENABLE			0x02
 #define	SCR_RXSEC_ENABLE			0x04
 
-#define	WOW_PMEN				BIT(0)
-#define	WOW_WOMEN				BIT(1)
-#define	WOW_MAGIC				BIT(2)
-#define	WOW_UWF					BIT(3)
+#define	WOW_PMEN					BIT(0)
+#define	WOW_WOMEN					BIT(1)
+#define	WOW_MAGIC					BIT(2)
+#define	WOW_UWF						BIT(3)
 
 #define	IMR8190_DISABLED			0x0
 #define	IMR_BCNDMAINT6				BIT(31)
@@ -467,180 +491,179 @@
 #define	IMR_BCNDMAINT3				BIT(28)
 #define	IMR_BCNDMAINT2				BIT(27)
 #define	IMR_BCNDMAINT1				BIT(26)
-#define	IMR_BCNDOK8				BIT(25)
-#define	IMR_BCNDOK7				BIT(24)
-#define	IMR_BCNDOK6				BIT(23)
-#define	IMR_BCNDOK5				BIT(22)
-#define	IMR_BCNDOK4				BIT(21)
-#define	IMR_BCNDOK3				BIT(20)
-#define	IMR_BCNDOK2				BIT(19)
-#define	IMR_BCNDOK1				BIT(18)
+#define	IMR_BCNDOK8					BIT(25)
+#define	IMR_BCNDOK7					BIT(24)
+#define	IMR_BCNDOK6					BIT(23)
+#define	IMR_BCNDOK5					BIT(22)
+#define	IMR_BCNDOK4					BIT(21)
+#define	IMR_BCNDOK3					BIT(20)
+#define	IMR_BCNDOK2					BIT(19)
+#define	IMR_BCNDOK1					BIT(18)
 #define	IMR_TIMEOUT2				BIT(17)
 #define	IMR_TIMEOUT1				BIT(16)
-#define	IMR_TXFOVW				BIT(15)
+#define	IMR_TXFOVW					BIT(15)
 #define	IMR_PSTIMEOUT				BIT(14)
-#define	IMR_BCNINT				BIT(13)
-#define	IMR_RXFOVW				BIT(12)
-#define	IMR_RDU					BIT(11)
-#define	IMR_ATIMEND				BIT(10)
-#define	IMR_BDOK				BIT(9)
-#define	IMR_HIGHDOK				BIT(8)
-#define	IMR_TBDOK				BIT(7)
-#define	IMR_MGNTDOK				BIT(6)
-#define	IMR_TBDER				BIT(5)
-#define	IMR_BKDOK				BIT(4)
-#define	IMR_BEDOK				BIT(3)
-#define	IMR_VIDOK				BIT(2)
-#define	IMR_VODOK				BIT(1)
-#define	IMR_ROK					BIT(0)
+#define	IMR_BCNINT					BIT(13)
+#define	IMR_RXFOVW					BIT(12)
+#define	IMR_RDU						BIT(11)
+#define	IMR_ATIMEND					BIT(10)
+#define	IMR_BDOK					BIT(9)
+#define	IMR_HIGHDOK					BIT(8)
+#define	IMR_TBDOK					BIT(7)
+#define	IMR_MGNTDOK					BIT(6)
+#define	IMR_TBDER					BIT(5)
+#define	IMR_BKDOK					BIT(4)
+#define	IMR_BEDOK					BIT(3)
+#define	IMR_VIDOK					BIT(2)
+#define	IMR_VODOK					BIT(1)
+#define	IMR_ROK						BIT(0)
 
-#define	IMR_TXERR				BIT(11)
-#define	IMR_RXERR				BIT(10)
-#define	IMR_CPWM				BIT(8)
-#define	IMR_OCPINT				BIT(1)
-#define	IMR_WLANOFF				BIT(0)
+#define	IMR_TXERR					BIT(11)
+#define	IMR_RXERR					BIT(10)
+#define	IMR_CPWM					BIT(8)
+#define	IMR_OCPINT					BIT(1)
+#define	IMR_WLANOFF					BIT(0)
 
 /* 8723E series PCIE Host IMR/ISR bit */
 /* IMR DW0 Bit 0-31 */
-#define	PHIMR_TIMEOUT2				BIT(31)
-#define	PHIMR_TIMEOUT1				BIT(30)
+#define	PHIMR_TIMEOUT2					BIT(31)
+#define	PHIMR_TIMEOUT1					BIT(30)
 #define	PHIMR_PSTIMEOUT				BIT(29)
-#define	PHIMR_GTINT4				BIT(28)
-#define	PHIMR_GTINT3				BIT(27)
-#define	PHIMR_TXBCNERR				BIT(26)
-#define	PHIMR_TXBCNOK				BIT(25)
+#define	PHIMR_GTINT4					BIT(28)
+#define	PHIMR_GTINT3					BIT(27)
+#define	PHIMR_TXBCNERR					BIT(26)
+#define	PHIMR_TXBCNOK					BIT(25)
 #define	PHIMR_TSF_BIT32_TOGGLE			BIT(24)
-#define	PHIMR_BCNDMAINT3			BIT(23)
-#define	PHIMR_BCNDMAINT2			BIT(22)
-#define	PHIMR_BCNDMAINT1			BIT(21)
-#define	PHIMR_BCNDMAINT0			BIT(20)
-#define	PHIMR_BCNDOK3				BIT(19)
-#define	PHIMR_BCNDOK2				BIT(18)
-#define	PHIMR_BCNDOK1				BIT(17)
-#define	PHIMR_BCNDOK0				BIT(16)
+#define	PHIMR_BCNDMAINT3				BIT(23)
+#define	PHIMR_BCNDMAINT2				BIT(22)
+#define	PHIMR_BCNDMAINT1				BIT(21)
+#define	PHIMR_BCNDMAINT0				BIT(20)
+#define	PHIMR_BCNDOK3					BIT(19)
+#define	PHIMR_BCNDOK2					BIT(18)
+#define	PHIMR_BCNDOK1					BIT(17)
+#define	PHIMR_BCNDOK0					BIT(16)
 #define	PHIMR_HSISR_IND_ON			BIT(15)
-#define	PHIMR_BCNDMAINT_E			BIT(14)
+#define	PHIMR_BCNDMAINT_E				BIT(14)
 #define	PHIMR_ATIMEND_E				BIT(13)
 #define	PHIMR_ATIM_CTW_END			BIT(12)
 #define	PHIMR_HISRE_IND				BIT(11)
-#define	PHIMR_C2HCMD				BIT(10)
-#define	PHIMR_CPWM2				BIT(9)
-#define	PHIMR_CPWM				BIT(8)
-#define	PHIMR_HIGHDOK				BIT(7)
-#define	PHIMR_MGNTDOK				BIT(6)
-#define	PHIMR_BKDOK				BIT(5)
-#define	PHIMR_BEDOK				BIT(4)
-#define	PHIMR_VIDOK				BIT(3)
-#define	PHIMR_VODOK				BIT(2)
-#define	PHIMR_RDU				BIT(1)
-#define	PHIMR_ROK				BIT(0)
+#define	PHIMR_C2HCMD					BIT(10)
+#define	PHIMR_CPWM2					BIT(9)
+#define	PHIMR_CPWM					BIT(8)
+#define	PHIMR_HIGHDOK					BIT(7)
+#define	PHIMR_MGNTDOK					BIT(6)
+#define	PHIMR_BKDOK					BIT(5)
+#define	PHIMR_BEDOK					BIT(4)
+#define	PHIMR_VIDOK					BIT(3)
+#define	PHIMR_VODOK					BIT(2)
+#define	PHIMR_RDU						BIT(1)
+#define	PHIMR_ROK						BIT(0)
 
 /* PCIE Host Interrupt Status Extension bit */
-#define	PHIMR_BCNDMAINT7			BIT(23)
-#define	PHIMR_BCNDMAINT6			BIT(22)
-#define	PHIMR_BCNDMAINT5			BIT(21)
-#define	PHIMR_BCNDMAINT4			BIT(20)
-#define	PHIMR_BCNDOK7				BIT(19)
-#define	PHIMR_BCNDOK6				BIT(18)
-#define	PHIMR_BCNDOK5				BIT(17)
-#define	PHIMR_BCNDOK4				BIT(16)
+#define	PHIMR_BCNDMAINT7				BIT(23)
+#define	PHIMR_BCNDMAINT6				BIT(22)
+#define	PHIMR_BCNDMAINT5				BIT(21)
+#define	PHIMR_BCNDMAINT4				BIT(20)
+#define	PHIMR_BCNDOK7					BIT(19)
+#define	PHIMR_BCNDOK6					BIT(18)
+#define	PHIMR_BCNDOK5					BIT(17)
+#define	PHIMR_BCNDOK4					BIT(16)
 /* bit12-15: RSVD */
-#define	PHIMR_TXERR				BIT(11)
-#define	PHIMR_RXERR				BIT(10)
-#define	PHIMR_TXFOVW				BIT(9)
-#define	PHIMR_RXFOVW				BIT(8)
-/* bit2-7: RSV */
-#define	PHIMR_OCPINT				BIT(1)
+#define	PHIMR_TXERR					BIT(11)
+#define	PHIMR_RXERR					BIT(10)
+#define	PHIMR_TXFOVW					BIT(9)
+#define	PHIMR_RXFOVW					BIT(8)
+/* bit2-7: RSVD */
+#define	PHIMR_OCPINT					BIT(1)
 
 #define	HWSET_MAX_SIZE				256
 #define EFUSE_MAX_SECTION			32
 #define EFUSE_REAL_CONTENT_LEN			512
 #define EFUSE_OOB_PROTECT_BYTES			15
 
-#define	EEPROM_DEFAULT_TSSI			0x0
-#define EEPROM_DEFAULT_TXPOWERDIFF		0x0
-#define EEPROM_DEFAULT_CRYSTALCAP		0x5
-#define EEPROM_DEFAULT_BOARDTYPE		0x02
-#define EEPROM_DEFAULT_TXPOWER			0x1010
-#define	EEPROM_DEFAULT_HT2T_TXPWR		0x10
+#define	EEPROM_DEFAULT_TSSI					0x0
+#define EEPROM_DEFAULT_TXPOWERDIFF			0x0
+#define EEPROM_DEFAULT_CRYSTALCAP			0x5
+#define EEPROM_DEFAULT_BOARDTYPE			0x02
+#define EEPROM_DEFAULT_TXPOWER				0x1010
+#define	EEPROM_DEFAULT_HT2T_TXPWR			0x10
 
 #define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3
-#define	EEPROM_DEFAULT_THERMALMETER		0x12
+#define	EEPROM_DEFAULT_THERMALMETER			0x12
 #define	EEPROM_DEFAULT_ANTTXPOWERDIFF		0x0
 #define	EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP	0x5
-#define	EEPROM_DEFAULT_TXPOWERLEVEL		0x22
-#define	EEPROM_DEFAULT_HT40_2SDIFF		0x0
-#define EEPROM_DEFAULT_HT20_DIFF		2
+#define	EEPROM_DEFAULT_TXPOWERLEVEL			0x22
+#define	EEPROM_DEFAULT_HT40_2SDIFF			0x0
+#define EEPROM_DEFAULT_HT20_DIFF			2
 #define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3
 #define EEPROM_DEFAULT_HT40_PWRMAXOFFSET	0
 #define EEPROM_DEFAULT_HT20_PWRMAXOFFSET	0
 
-
-#define EEPROM_DEFAULT_PID			0x1234
-#define EEPROM_DEFAULT_VID			0x5678
-#define EEPROM_DEFAULT_CUSTOMERID		0xAB
+#define EEPROM_DEFAULT_PID					0x1234
+#define EEPROM_DEFAULT_VID					0x5678
+#define EEPROM_DEFAULT_CUSTOMERID			0xAB
 #define EEPROM_DEFAULT_SUBCUSTOMERID		0xCD
-#define EEPROM_DEFAULT_VERSION			0
+#define EEPROM_DEFAULT_VERSION				0
 
-#define	EEPROM_CHANNEL_PLAN_FCC			0x0
-#define	EEPROM_CHANNEL_PLAN_IC			0x1
-#define	EEPROM_CHANNEL_PLAN_ETSI		0x2
-#define	EEPROM_CHANNEL_PLAN_SPAIN		0x3
-#define	EEPROM_CHANNEL_PLAN_FRANCE		0x4
-#define	EEPROM_CHANNEL_PLAN_MKK			0x5
-#define	EEPROM_CHANNEL_PLAN_MKK1		0x6
-#define	EEPROM_CHANNEL_PLAN_ISRAEL		0x7
-#define	EEPROM_CHANNEL_PLAN_TELEC		0x8
+#define	EEPROM_CHANNEL_PLAN_FCC				0x0
+#define	EEPROM_CHANNEL_PLAN_IC				0x1
+#define	EEPROM_CHANNEL_PLAN_ETSI			0x2
+#define	EEPROM_CHANNEL_PLAN_SPAIN			0x3
+#define	EEPROM_CHANNEL_PLAN_FRANCE			0x4
+#define	EEPROM_CHANNEL_PLAN_MKK				0x5
+#define	EEPROM_CHANNEL_PLAN_MKK1			0x6
+#define	EEPROM_CHANNEL_PLAN_ISRAEL			0x7
+#define	EEPROM_CHANNEL_PLAN_TELEC			0x8
 #define	EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN	0x9
 #define	EEPROM_CHANNEL_PLAN_WORLD_WIDE_13	0xA
-#define	EEPROM_CHANNEL_PLAN_NCC			0xB
+#define	EEPROM_CHANNEL_PLAN_NCC				0xB
 #define	EEPROM_CHANNEL_PLAN_BY_HW_MASK		0x80
 
-#define EEPROM_CID_DEFAULT			0x0
-#define EEPROM_CID_TOSHIBA			0x4
-#define	EEPROM_CID_CCX				0x10
-#define	EEPROM_CID_QMI				0x0D
-#define EEPROM_CID_WHQL				0xFE
+#define EEPROM_CID_DEFAULT					0x0
+#define EEPROM_CID_TOSHIBA					0x4
+#define	EEPROM_CID_CCX						0x10
+#define	EEPROM_CID_QMI						0x0D
+#define EEPROM_CID_WHQL						0xFE
 
-#define	RTL8192_EEPROM_ID			0x8129
+#define	RTL8192_EEPROM_ID					0x8129
 
-#define RTL8190_EEPROM_ID			0x8129
-#define EEPROM_HPON				0x02
-#define EEPROM_CLK				0x06
-#define EEPROM_TESTR				0x08
+#define RTL8190_EEPROM_ID					0x8129
+#define EEPROM_HPON							0x02
+#define EEPROM_CLK							0x06
+#define EEPROM_TESTR						0x08
 
-#define EEPROM_VID				0x49
-#define EEPROM_DID				0x4B
-#define EEPROM_SVID				0x4D
-#define EEPROM_SMID				0x4F
+#define EEPROM_VID							0x49
+#define EEPROM_DID							0x4B
+#define EEPROM_SVID							0x4D
+#define EEPROM_SMID							0x4F
 
-#define EEPROM_MAC_ADDR				0x67
+#define EEPROM_MAC_ADDR						0x67
 
-#define EEPROM_CCK_TX_PWR_INX			0x5A
-#define EEPROM_HT40_1S_TX_PWR_INX		0x60
+#define EEPROM_CCK_TX_PWR_INX				0x5A
+#define EEPROM_HT40_1S_TX_PWR_INX			0x60
 #define EEPROM_HT40_2S_TX_PWR_INX_DIFF		0x66
-#define EEPROM_HT20_TX_PWR_INX_DIFF		0x69
-#define EEPROM_OFDM_TX_PWR_INX_DIFF		0x6C
-#define EEPROM_HT40_MAX_PWR_OFFSET		0x25
-#define EEPROM_HT20_MAX_PWR_OFFSET		0x22
+#define EEPROM_HT20_TX_PWR_INX_DIFF			0x69
+#define EEPROM_OFDM_TX_PWR_INX_DIFF			0x6C
+#define EEPROM_HT40_MAX_PWR_OFFSET			0x25
+#define EEPROM_HT20_MAX_PWR_OFFSET			0x22
 
-#define EEPROM_THERMAL_METER			0x2a
-#define EEPROM_XTAL_K				0x78
-#define EEPROM_RF_OPT1				0x79
-#define EEPROM_RF_OPT2				0x7A
-#define EEPROM_RF_OPT3				0x7B
-#define EEPROM_RF_OPT4				0x7C
-#define EEPROM_CHANNEL_PLAN			0x28
-#define EEPROM_VERSION				0x30
-#define EEPROM_CUSTOMER_ID			0x31
+#define EEPROM_THERMAL_METER				0x2a
+#define EEPROM_XTAL_K						0x78
+#define EEPROM_RF_OPT1						0x79
+#define EEPROM_RF_OPT2						0x7A
+#define EEPROM_RF_OPT3						0x7B
+#define EEPROM_RF_OPT4						0x7C
+#define EEPROM_CHANNEL_PLAN					0x28
+#define EEPROM_VERSION						0x30
+#define EEPROM_CUSTOMER_ID					0x31
 
 #define EEPROM_PWRDIFF				0x54
 
 #define EEPROM_TXPOWERCCK			0x10
-#define	EEPROM_TXPOWERHT40_1S			0x16
-#define	EEPROM_TXPOWERHT40_2SDIFF		0x66
-#define EEPROM_TXPOWERHT20DIFF			0x1C
-#define EEPROM_TXPOWER_OFDMDIFF			0x1F
+#define	EEPROM_TXPOWERHT40_1S		0x16
+#define	EEPROM_TXPOWERHT40_2SDIFF	0x66
+#define EEPROM_TXPOWERHT20DIFF		0x1C
+#define EEPROM_TXPOWER_OFDMDIFF		0x1F
 
 #define	EEPROM_TXPWR_GROUP			0x22
 
@@ -649,169 +672,169 @@
 
 #define EEPROM_CHANNELPLAN			0x28
 
-#define RF_OPTION1				0x2B
-#define RF_OPTION2				0x2C
-#define RF_OPTION3				0x2D
-#define RF_OPTION4				0x2E
+#define RF_OPTION1					0x2B
+#define RF_OPTION2					0x2C
+#define RF_OPTION3					0x2D
+#define RF_OPTION4					0x2E
 
-#define	STOPBECON				BIT(6)
-#define	STOPHIGHT				BIT(5)
-#define	STOPMGT					BIT(4)
-#define	STOPVO					BIT(3)
-#define	STOPVI					BIT(2)
-#define	STOPBE					BIT(1)
-#define	STOPBK					BIT(0)
+#define	STOPBECON					BIT(6)
+#define	STOPHIGHT					BIT(5)
+#define	STOPMGT						BIT(4)
+#define	STOPVO						BIT(3)
+#define	STOPVI						BIT(2)
+#define	STOPBE						BIT(1)
+#define	STOPBK						BIT(0)
 
-#define	RCR_APPFCS				BIT(31)
-#define	RCR_APP_MIC				BIT(30)
-#define	RCR_APP_ICV				BIT(29)
+#define	RCR_APPFCS					BIT(31)
+#define	RCR_APP_MIC					BIT(30)
+#define	RCR_APP_ICV					BIT(29)
 #define	RCR_APP_PHYST_RXFF			BIT(28)
 #define	RCR_APP_BA_SSN				BIT(27)
-#define	RCR_ENMBID				BIT(24)
-#define	RCR_LSIGEN				BIT(23)
-#define	RCR_MFBEN				BIT(22)
+#define	RCR_ENMBID					BIT(24)
+#define	RCR_LSIGEN					BIT(23)
+#define	RCR_MFBEN					BIT(22)
 #define	RCR_HTC_LOC_CTRL			BIT(14)
-#define	RCR_AMF					BIT(13)
-#define	RCR_ACF					BIT(12)
-#define	RCR_ADF					BIT(11)
-#define	RCR_AICV				BIT(9)
-#define	RCR_ACRC32				BIT(8)
+#define	RCR_AMF						BIT(13)
+#define	RCR_ACF						BIT(12)
+#define	RCR_ADF						BIT(11)
+#define	RCR_AICV					BIT(9)
+#define	RCR_ACRC32					BIT(8)
 #define	RCR_CBSSID_BCN				BIT(7)
 #define	RCR_CBSSID_DATA				BIT(6)
-#define	RCR_CBSSID				RCR_CBSSID_DATA
-#define	RCR_APWRMGT				BIT(5)
-#define	RCR_ADD3				BIT(4)
-#define	RCR_AB					BIT(3)
-#define	RCR_AM					BIT(2)
-#define	RCR_APM					BIT(1)
-#define	RCR_AAP					BIT(0)
+#define	RCR_CBSSID					RCR_CBSSID_DATA
+#define	RCR_APWRMGT					BIT(5)
+#define	RCR_ADD3					BIT(4)
+#define	RCR_AB						BIT(3)
+#define	RCR_AM						BIT(2)
+#define	RCR_APM						BIT(1)
+#define	RCR_AAP						BIT(0)
 #define	RCR_MXDMA_OFFSET			8
 #define	RCR_FIFO_OFFSET				13
 
-#define RSV_CTRL				0x001C
-#define RD_CTRL					0x0524
+#define RSV_CTRL					0x001C
+#define RD_CTRL						0x0524
 
 #define REG_USB_INFO				0xFE17
-#define REG_USB_SPECIAL_OPTION			0xFE55
+#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_USB_VID				0xFE60
-#define REG_USB_PID				0xFE62
+#define REG_USB_VID					0xFE60
+#define REG_USB_PID					0xFE62
 #define REG_USB_OPTIONAL			0xFE64
 #define REG_USB_CHIRP_K				0xFE65
-#define REG_USB_PHY				0xFE66
+#define REG_USB_PHY					0xFE66
 #define REG_USB_MAC_ADDR			0xFE70
 #define REG_USB_HRPWM				0xFE58
 #define REG_USB_HCPWM				0xFE57
 
-#define SW18_FPWM				BIT(3)
+#define SW18_FPWM					BIT(3)
 
-#define ISO_MD2PP				BIT(0)
-#define ISO_UA2USB				BIT(1)
-#define ISO_UD2CORE				BIT(2)
-#define ISO_PA2PCIE				BIT(3)
-#define ISO_PD2CORE				BIT(4)
-#define ISO_IP2MAC				BIT(5)
-#define ISO_DIOP				BIT(6)
-#define ISO_DIOE				BIT(7)
-#define ISO_EB2CORE				BIT(8)
-#define ISO_DIOR				BIT(9)
+#define ISO_MD2PP					BIT(0)
+#define ISO_UA2USB					BIT(1)
+#define ISO_UD2CORE					BIT(2)
+#define ISO_PA2PCIE					BIT(3)
+#define ISO_PD2CORE					BIT(4)
+#define ISO_IP2MAC					BIT(5)
+#define ISO_DIOP					BIT(6)
+#define ISO_DIOE					BIT(7)
+#define ISO_EB2CORE					BIT(8)
+#define ISO_DIOR					BIT(9)
 
-#define PWC_EV25V				BIT(14)
-#define PWC_EV12V				BIT(15)
+#define PWC_EV25V					BIT(14)
+#define PWC_EV12V					BIT(15)
 
-#define FEN_BBRSTB				BIT(0)
-#define FEN_BB_GLB_RSTn				BIT(1)
-#define FEN_USBA				BIT(2)
-#define FEN_UPLL				BIT(3)
-#define FEN_USBD				BIT(4)
+#define FEN_BBRSTB					BIT(0)
+#define FEN_BB_GLB_RSTN				BIT(1)
+#define FEN_USBA					BIT(2)
+#define FEN_UPLL					BIT(3)
+#define FEN_USBD					BIT(4)
 #define FEN_DIO_PCIE				BIT(5)
-#define FEN_PCIEA				BIT(6)
-#define FEN_PPLL				BIT(7)
-#define FEN_PCIED				BIT(8)
-#define FEN_DIOE				BIT(9)
-#define FEN_CPUEN				BIT(10)
-#define FEN_DCORE				BIT(11)
-#define FEN_ELDR				BIT(12)
-#define FEN_DIO_RF				BIT(13)
-#define FEN_HWPDN				BIT(14)
-#define FEN_MREGEN				BIT(15)
+#define FEN_PCIEA					BIT(6)
+#define FEN_PPLL					BIT(7)
+#define FEN_PCIED					BIT(8)
+#define FEN_DIOE					BIT(9)
+#define FEN_CPUEN					BIT(10)
+#define FEN_DCORE					BIT(11)
+#define FEN_ELDR					BIT(12)
+#define FEN_DIO_RF					BIT(13)
+#define FEN_HWPDN					BIT(14)
+#define FEN_MREGEN					BIT(15)
 
-#define PFM_LDALL				BIT(0)
-#define PFM_ALDN				BIT(1)
-#define PFM_LDKP				BIT(2)
-#define PFM_WOWL				BIT(3)
-#define EnPDN					BIT(4)
-#define PDN_PL					BIT(5)
-#define APFM_ONMAC				BIT(8)
-#define APFM_OFF				BIT(9)
-#define APFM_RSM				BIT(10)
-#define AFSM_HSUS				BIT(11)
-#define AFSM_PCIE				BIT(12)
-#define APDM_MAC				BIT(13)
-#define APDM_HOST				BIT(14)
-#define APDM_HPDN				BIT(15)
-#define RDY_MACON				BIT(16)
-#define SUS_HOST				BIT(17)
-#define ROP_ALD					BIT(20)
-#define ROP_PWR					BIT(21)
-#define ROP_SPS					BIT(22)
-#define SOP_MRST				BIT(25)
-#define SOP_FUSE				BIT(26)
-#define SOP_ABG					BIT(27)
-#define SOP_AMB					BIT(28)
-#define SOP_RCK					BIT(29)
-#define SOP_A8M					BIT(30)
-#define XOP_BTCK				BIT(31)
+#define PFM_LDALL					BIT(0)
+#define PFM_ALDN					BIT(1)
+#define PFM_LDKP					BIT(2)
+#define PFM_WOWL					BIT(3)
+#define ENPDN						BIT(4)
+#define PDN_PL						BIT(5)
+#define APFM_ONMAC					BIT(8)
+#define APFM_OFF					BIT(9)
+#define APFM_RSM					BIT(10)
+#define AFSM_HSUS					BIT(11)
+#define AFSM_PCIE					BIT(12)
+#define APDM_MAC					BIT(13)
+#define APDM_HOST					BIT(14)
+#define APDM_HPDN					BIT(15)
+#define RDY_MACON					BIT(16)
+#define SUS_HOST					BIT(17)
+#define ROP_ALD						BIT(20)
+#define ROP_PWR						BIT(21)
+#define ROP_SPS						BIT(22)
+#define SOP_MRST					BIT(25)
+#define SOP_FUSE					BIT(26)
+#define SOP_ABG						BIT(27)
+#define SOP_AMB						BIT(28)
+#define SOP_RCK						BIT(29)
+#define SOP_A8M						BIT(30)
+#define XOP_BTCK					BIT(31)
 
-#define ANAD16V_EN				BIT(0)
-#define ANA8M					BIT(1)
-#define MACSLP					BIT(4)
+#define ANAD16V_EN					BIT(0)
+#define ANA8M						BIT(1)
+#define MACSLP						BIT(4)
 #define LOADER_CLK_EN				BIT(5)
 #define _80M_SSC_DIS				BIT(7)
 #define _80M_SSC_EN_HO				BIT(8)
 #define PHY_SSC_RSTB				BIT(9)
-#define SEC_CLK_EN				BIT(10)
-#define MAC_CLK_EN				BIT(11)
-#define SYS_CLK_EN				BIT(12)
-#define RING_CLK_EN				BIT(13)
+#define SEC_CLK_EN					BIT(10)
+#define MAC_CLK_EN					BIT(11)
+#define SYS_CLK_EN					BIT(12)
+#define RING_CLK_EN					BIT(13)
 
 #define	BOOT_FROM_EEPROM			BIT(4)
-#define	EEPROM_EN				BIT(5)
+#define	EEPROM_EN					BIT(5)
 
-#define AFE_BGEN				BIT(0)
-#define AFE_MBEN				BIT(1)
-#define MAC_ID_EN				BIT(7)
+#define AFE_BGEN					BIT(0)
+#define AFE_MBEN					BIT(1)
+#define MAC_ID_EN					BIT(7)
 
-#define WLOCK_ALL				BIT(0)
-#define WLOCK_00				BIT(1)
-#define WLOCK_04				BIT(2)
-#define WLOCK_08				BIT(3)
-#define WLOCK_40				BIT(4)
+#define WLOCK_ALL					BIT(0)
+#define WLOCK_00					BIT(1)
+#define WLOCK_04					BIT(2)
+#define WLOCK_08					BIT(3)
+#define WLOCK_40					BIT(4)
 #define R_DIS_PRST_0				BIT(5)
 #define R_DIS_PRST_1				BIT(6)
-#define LOCK_ALL_EN				BIT(7)
+#define LOCK_ALL_EN					BIT(7)
 
-#define RF_EN					BIT(0)
-#define RF_RSTB					BIT(1)
-#define RF_SDMRSTB				BIT(2)
+#define RF_EN						BIT(0)
+#define RF_RSTB						BIT(1)
+#define RF_SDMRSTB					BIT(2)
 
-#define LDA15_EN				BIT(0)
-#define LDA15_STBY				BIT(1)
-#define LDA15_OBUF				BIT(2)
+#define LDA15_EN					BIT(0)
+#define LDA15_STBY					BIT(1)
+#define LDA15_OBUF					BIT(2)
 #define LDA15_REG_VOS				BIT(3)
 #define _LDA15_VOADJ(x)				(((x) & 0x7) << 4)
 
-#define LDV12_EN				BIT(0)
-#define LDV12_SDBY				BIT(1)
-#define LPLDO_HSM				BIT(2)
+#define LDV12_EN					BIT(0)
+#define LDV12_SDBY					BIT(1)
+#define LPLDO_HSM					BIT(2)
 #define LPLDO_LSM_DIS				BIT(3)
 #define _LDV12_VADJ(x)				(((x) & 0xF) << 4)
 
-#define XTAL_EN					BIT(0)
-#define XTAL_BSEL				BIT(1)
+#define XTAL_EN						BIT(0)
+#define XTAL_BSEL					BIT(1)
 #define _XTAL_BOSC(x)				(((x) & 0x3) << 2)
 #define _XTAL_CADJ(x)				(((x) & 0xF) << 4)
 #define XTAL_GATE_USB				BIT(8)
@@ -826,146 +849,146 @@
 #define _XTAL_BT_DRV(x)				(((x) & 0x3) << 21)
 #define _XTAL_GPIO(x)				(((x) & 0x7) << 23)
 
-#define CKDLY_AFE				BIT(26)
-#define CKDLY_USB				BIT(27)
-#define CKDLY_DIG				BIT(28)
-#define CKDLY_BT				BIT(29)
+#define CKDLY_AFE					BIT(26)
+#define CKDLY_USB					BIT(27)
+#define CKDLY_DIG					BIT(28)
+#define CKDLY_BT					BIT(29)
 
-#define APLL_EN					BIT(0)
-#define APLL_320_EN				BIT(1)
+#define APLL_EN						BIT(0)
+#define APLL_320_EN					BIT(1)
 #define APLL_FREF_SEL				BIT(2)
 #define APLL_EDGE_SEL				BIT(3)
-#define APLL_WDOGB				BIT(4)
-#define APLL_LPFEN				BIT(5)
+#define APLL_WDOGB					BIT(4)
+#define APLL_LPFEN					BIT(5)
 
 #define APLL_REF_CLK_13MHZ			0x1
-#define APLL_REF_CLK_19_2MHZ			0x2
+#define APLL_REF_CLK_19_2MHZ		0x2
 #define APLL_REF_CLK_20MHZ			0x3
 #define APLL_REF_CLK_25MHZ			0x4
 #define APLL_REF_CLK_26MHZ			0x5
-#define APLL_REF_CLK_38_4MHZ			0x6
+#define APLL_REF_CLK_38_4MHZ		0x6
 #define APLL_REF_CLK_40MHZ			0x7
 
-#define APLL_320EN				BIT(14)
-#define APLL_80EN				BIT(15)
-#define APLL_1MEN				BIT(24)
+#define APLL_320EN					BIT(14)
+#define APLL_80EN					BIT(15)
+#define APLL_1MEN					BIT(24)
 
-#define ALD_EN					BIT(18)
-#define EF_PD					BIT(19)
-#define EF_FLAG					BIT(31)
+#define ALD_EN						BIT(18)
+#define EF_PD						BIT(19)
+#define EF_FLAG						BIT(31)
 
-#define EF_TRPT					BIT(7)
-#define LDOE25_EN				BIT(31)
+#define EF_TRPT						BIT(7)
+#define LDOE25_EN					BIT(31)
 
-#define RSM_EN					BIT(0)
-#define Timer_EN				BIT(4)
+#define RSM_EN						BIT(0)
+#define TIMER_EN					BIT(4)
 
-#define TRSW0EN					BIT(2)
-#define TRSW1EN					BIT(3)
-#define EROM_EN					BIT(4)
-#define EnBT					BIT(5)
-#define EnUart					BIT(8)
-#define Uart_910				BIT(9)
-#define EnPMAC					BIT(10)
-#define SIC_SWRST				BIT(11)
-#define EnSIC					BIT(12)
-#define SIC_23					BIT(13)
-#define EnHDP					BIT(14)
-#define SIC_LBK					BIT(15)
+#define TRSW0EN						BIT(2)
+#define TRSW1EN						BIT(3)
+#define EROM_EN						BIT(4)
+#define ENBT						BIT(5)
+#define ENUART						BIT(8)
+#define UART_910					BIT(9)
+#define ENPMAC						BIT(10)
+#define SIC_SWRST					BIT(11)
+#define ENSIC						BIT(12)
+#define SIC_23						BIT(13)
+#define ENHDP						BIT(14)
+#define SIC_LBK						BIT(15)
 
-#define LED0PL					BIT(4)
-#define LED1PL					BIT(12)
-#define LED0DIS					BIT(7)
+#define LED0PL						BIT(4)
+#define LED1PL						BIT(12)
+#define LED0DIS						BIT(7)
 
-#define MCUFWDL_EN				BIT(0)
-#define MCUFWDL_RDY				BIT(1)
-#define FWDL_ChkSum_rpt				BIT(2)
-#define MACINI_RDY				BIT(3)
-#define BBINI_RDY				BIT(4)
-#define RFINI_RDY				BIT(5)
-#define WINTINI_RDY				BIT(6)
-#define CPRST					BIT(23)
+#define MCUFWDL_EN					BIT(0)
+#define MCUFWDL_RDY					BIT(1)
+#define FWDL_CHKSUM_RPT				BIT(2)
+#define MACINI_RDY					BIT(3)
+#define BBINI_RDY					BIT(4)
+#define RFINI_RDY					BIT(5)
+#define WINTINI_RDY					BIT(6)
+#define CPRST						BIT(23)
 
-#define XCLK_VLD				BIT(0)
-#define ACLK_VLD				BIT(1)
-#define UCLK_VLD				BIT(2)
-#define PCLK_VLD				BIT(3)
-#define PCIRSTB					BIT(4)
-#define V15_VLD					BIT(5)
-#define TRP_B15V_EN				BIT(7)
-#define SIC_IDLE				BIT(8)
-#define BD_MAC2					BIT(9)
-#define BD_MAC1					BIT(10)
+#define XCLK_VLD					BIT(0)
+#define ACLK_VLD					BIT(1)
+#define UCLK_VLD					BIT(2)
+#define PCLK_VLD					BIT(3)
+#define PCIRSTB						BIT(4)
+#define V15_VLD						BIT(5)
+#define TRP_B15V_EN					BIT(7)
+#define SIC_IDLE					BIT(8)
+#define BD_MAC2						BIT(9)
+#define BD_MAC1						BIT(10)
 #define IC_MACPHY_MODE				BIT(11)
-#define BT_FUNC					BIT(16)
-#define VENDOR_ID				BIT(19)
+#define BT_FUNC						BIT(16)
+#define VENDOR_ID					BIT(19)
 #define PAD_HWPD_IDN				BIT(22)
-#define TRP_VAUX_EN				BIT(23)
-#define TRP_BT_EN				BIT(24)
-#define BD_PKG_SEL				BIT(25)
-#define BD_HCI_SEL				BIT(26)
-#define TYPE_ID					BIT(27)
+#define TRP_VAUX_EN					BIT(23)
+#define TRP_BT_EN					BIT(24)
+#define BD_PKG_SEL					BIT(25)
+#define BD_HCI_SEL					BIT(26)
+#define TYPE_ID						BIT(27)
 
 #define CHIP_VER_RTL_MASK			0xF000
 #define CHIP_VER_RTL_SHIFT			12
 
-#define REG_LBMODE				(REG_CR + 3)
+#define REG_LBMODE					(REG_CR + 3)
 
 #define HCI_TXDMA_EN				BIT(0)
 #define HCI_RXDMA_EN				BIT(1)
-#define TXDMA_EN				BIT(2)
-#define RXDMA_EN				BIT(3)
-#define PROTOCOL_EN				BIT(4)
-#define SCHEDULE_EN				BIT(5)
-#define MACTXEN					BIT(6)
-#define MACRXEN					BIT(7)
-#define ENSWBCN					BIT(8)
-#define ENSEC					BIT(9)
+#define TXDMA_EN					BIT(2)
+#define RXDMA_EN					BIT(3)
+#define PROTOCOL_EN					BIT(4)
+#define SCHEDULE_EN					BIT(5)
+#define MACTXEN						BIT(6)
+#define MACRXEN						BIT(7)
+#define ENSWBCN						BIT(8)
+#define ENSEC						BIT(9)
 
-#define _NETTYPE(x)				(((x) & 0x3) << 16)
+#define _NETTYPE(x)					(((x) & 0x3) << 16)
 #define MASK_NETTYPE				0x30000
-#define NT_NO_LINK				0x0
+#define NT_NO_LINK					0x0
 #define NT_LINK_AD_HOC				0x1
-#define NT_LINK_AP				0x2
-#define NT_AS_AP				0x3
+#define NT_LINK_AP					0x2
+#define NT_AS_AP					0x3
 
-#define _LBMODE(x)				(((x) & 0xF) << 24)
-#define MASK_LBMODE				0xF000000
+#define _LBMODE(x)					(((x) & 0xF) << 24)
+#define MASK_LBMODE					0xF000000
 #define LOOPBACK_NORMAL				0x0
-#define LOOPBACK_IMMEDIATELY			0xB
+#define LOOPBACK_IMMEDIATELY		0xB
 #define LOOPBACK_MAC_DELAY			0x3
 #define LOOPBACK_PHY				0x1
 #define LOOPBACK_DMA				0x7
 
-#define GET_RX_PAGE_SIZE(value)			((value) & 0xF)
-#define GET_TX_PAGE_SIZE(value)			(((value) & 0xF0) >> 4)
-#define _PSRX_MASK				0xF
-#define _PSTX_MASK				0xF0
-#define _PSRX(x)				(x)
-#define _PSTX(x)				((x) << 4)
+#define GET_RX_PAGE_SIZE(value)		((value) & 0xF)
+#define GET_TX_PAGE_SIZE(value)		(((value) & 0xF0) >> 4)
+#define _PSRX_MASK					0xF
+#define _PSTX_MASK					0xF0
+#define _PSRX(x)					(x)
+#define _PSTX(x)					((x) << 4)
 
-#define PBP_64					0x0
-#define PBP_128					0x1
-#define PBP_256					0x2
-#define PBP_512					0x3
-#define PBP_1024				0x4
+#define PBP_64						0x0
+#define PBP_128						0x1
+#define PBP_256						0x2
+#define PBP_512						0x3
+#define PBP_1024					0x4
 
 #define RXDMA_ARBBW_EN				BIT(0)
-#define RXSHFT_EN				BIT(1)
+#define RXSHFT_EN					BIT(1)
 #define RXDMA_AGG_EN				BIT(2)
-#define QS_VO_QUEUE				BIT(8)
-#define QS_VI_QUEUE				BIT(9)
-#define QS_BE_QUEUE				BIT(10)
-#define QS_BK_QUEUE				BIT(11)
+#define QS_VO_QUEUE					BIT(8)
+#define QS_VI_QUEUE					BIT(9)
+#define QS_BE_QUEUE					BIT(10)
+#define QS_BK_QUEUE					BIT(11)
 #define QS_MANAGER_QUEUE			BIT(12)
 #define QS_HIGH_QUEUE				BIT(13)
 
-#define HQSEL_VOQ				BIT(0)
-#define HQSEL_VIQ				BIT(1)
-#define HQSEL_BEQ				BIT(2)
-#define HQSEL_BKQ				BIT(3)
-#define HQSEL_MGTQ				BIT(4)
-#define HQSEL_HIQ				BIT(5)
+#define HQSEL_VOQ					BIT(0)
+#define HQSEL_VIQ					BIT(1)
+#define HQSEL_BEQ					BIT(2)
+#define HQSEL_BKQ					BIT(3)
+#define HQSEL_MGTQ					BIT(4)
+#define HQSEL_HIQ					BIT(5)
 
 #define _TXDMA_HIQ_MAP(x)			(((x)&0x3) << 14)
 #define _TXDMA_MGQ_MAP(x)			(((x)&0x3) << 12)
@@ -974,9 +997,9 @@
 #define _TXDMA_VIQ_MAP(x)			(((x)&0x3) << 6)
 #define _TXDMA_VOQ_MAP(x)			(((x)&0x3) << 4)
 
-#define QUEUE_LOW				1
+#define QUEUE_LOW					1
 #define QUEUE_NORMAL				2
-#define QUEUE_HIGH				3
+#define QUEUE_HIGH					3
 
 #define _LLT_NO_ACTIVE				0x0
 #define _LLT_WRITE_ACCESS			0x1
@@ -984,25 +1007,25 @@
 
 #define _LLT_INIT_DATA(x)			((x) & 0xFF)
 #define _LLT_INIT_ADDR(x)			(((x) & 0xFF) << 8)
-#define _LLT_OP(x)				(((x) & 0x3) << 30)
+#define _LLT_OP(x)					(((x) & 0x3) << 30)
 #define _LLT_OP_VALUE(x)			(((x) >> 30) & 0x3)
 
 #define BB_WRITE_READ_MASK			(BIT(31) | BIT(30))
-#define BB_WRITE_EN				BIT(30)
-#define BB_READ_EN				BIT(31)
+#define BB_WRITE_EN					BIT(30)
+#define BB_READ_EN					BIT(31)
 
-#define _HPQ(x)					((x) & 0xFF)
-#define _LPQ(x)					(((x) & 0xFF) << 8)
-#define _PUBQ(x)				(((x) & 0xFF) << 16)
-#define _NPQ(x)					((x) & 0xFF)
+#define _HPQ(x)			((x) & 0xFF)
+#define _LPQ(x)			(((x) & 0xFF) << 8)
+#define _PUBQ(x)		(((x) & 0xFF) << 16)
+#define _NPQ(x)			((x) & 0xFF)
 
-#define HPQ_PUBLIC_DIS				BIT(24)
-#define LPQ_PUBLIC_DIS				BIT(25)
-#define LD_RQPN					BIT(31)
+#define HPQ_PUBLIC_DIS		BIT(24)
+#define LPQ_PUBLIC_DIS		BIT(25)
+#define LD_RQPN			BIT(31)
 
-#define BCN_VALID				BIT(16)
-#define BCN_HEAD(x)				(((x) & 0xFF) << 8)
-#define	BCN_HEAD_MASK				0xFF00
+#define BCN_VALID		BIT(16)
+#define BCN_HEAD(x)		(((x) & 0xFF) << 8)
+#define	BCN_HEAD_MASK		0xFF00
 
 #define BLK_DESC_NUM_SHIFT			4
 #define BLK_DESC_NUM_MASK			0xF
@@ -1022,9 +1045,9 @@
 
 #define _RRSR_RSC(x)				(((x) & 0x3) << 21)
 #define RRSR_RSC_RESERVED			0x0
-#define RRSR_RSC_UPPER_SUBCHANNEL		0x1
-#define RRSR_RSC_LOWER_SUBCHANNEL		0x2
-#define RRSR_RSC_DUPLICATE_MODE			0x3
+#define RRSR_RSC_UPPER_SUBCHANNEL	0x1
+#define RRSR_RSC_LOWER_SUBCHANNEL	0x2
+#define RRSR_RSC_DUPLICATE_MODE		0x3
 
 #define USE_SHORT_G1				BIT(20)
 
@@ -1037,8 +1060,8 @@
 #define _AGGLMT_MCS6(x)				(((x) & 0xF) << 24)
 #define _AGGLMT_MCS7(x)				(((x) & 0xF) << 28)
 
-#define	RETRY_LIMIT_SHORT_SHIFT			8
-#define	RETRY_LIMIT_LONG_SHIFT			0
+#define	RETRY_LIMIT_SHORT_SHIFT		8
+#define	RETRY_LIMIT_LONG_SHIFT		0
 
 #define _DARF_RC1(x)				((x) & 0x1F)
 #define _DARF_RC2(x)				(((x) & 0x1F) << 8)
@@ -1058,123 +1081,123 @@
 #define _RARF_RC7(x)				(((x) & 0x1F) << 16)
 #define _RARF_RC8(x)				(((x) & 0x1F) << 24)
 
-#define AC_PARAM_TXOP_LIMIT_OFFSET		16
-#define AC_PARAM_ECW_MAX_OFFSET			12
-#define AC_PARAM_ECW_MIN_OFFSET			8
-#define AC_PARAM_AIFS_OFFSET			0
+#define AC_PARAM_TXOP_LIMIT_OFFSET	16
+#define AC_PARAM_ECW_MAX_OFFSET		12
+#define AC_PARAM_ECW_MIN_OFFSET		8
+#define AC_PARAM_AIFS_OFFSET		0
 
-#define _AIFS(x)				(x)
+#define _AIFS(x)					(x)
 #define _ECW_MAX_MIN(x)				((x) << 8)
 #define _TXOP_LIMIT(x)				((x) << 16)
 
-#define _BCNIFS(x)				((x) & 0xFF)
-#define _BCNECW(x)				((((x) & 0xF)) << 8)
+#define _BCNIFS(x)					((x) & 0xFF)
+#define _BCNECW(x)					((((x) & 0xF)) << 8)
 
-#define _LRL(x)					((x) & 0x3F)
-#define _SRL(x)					(((x) & 0x3F) << 8)
+#define _LRL(x)						((x) & 0x3F)
+#define _SRL(x)						(((x) & 0x3F) << 8)
 
 #define _SIFS_CCK_CTX(x)			((x) & 0xFF)
-#define _SIFS_CCK_TRX(x)			(((x) & 0xFF) << 8);
+#define _SIFS_CCK_TRX(x)			(((x) & 0xFF) << 8)
 
 #define _SIFS_OFDM_CTX(x)			((x) & 0xFF)
-#define _SIFS_OFDM_TRX(x)			(((x) & 0xFF) << 8);
+#define _SIFS_OFDM_TRX(x)			(((x) & 0xFF) << 8)
 
-#define _TBTT_PROHIBIT_HOLD(x)			(((x) & 0xFF) << 8)
+#define _TBTT_PROHIBIT_HOLD(x)		(((x) & 0xFF) << 8)
 
 #define DIS_EDCA_CNT_DWN			BIT(11)
 
-#define EN_MBSSID				BIT(1)
+#define EN_MBSSID					BIT(1)
 #define EN_TXBCN_RPT				BIT(2)
 #define	EN_BCN_FUNCTION				BIT(3)
 
-#define TSFTR_RST				BIT(0)
-#define TSFTR1_RST				BIT(1)
+#define TSFTR_RST					BIT(0)
+#define TSFTR1_RST					BIT(1)
 
-#define STOP_BCNQ				BIT(6)
+#define STOP_BCNQ					BIT(6)
 
-#define	DIS_TSF_UDT0_NORMAL_CHIP		BIT(4)
-#define	DIS_TSF_UDT0_TEST_CHIP			BIT(5)
+#define	DIS_TSF_UDT0_NORMAL_CHIP	BIT(4)
+#define	DIS_TSF_UDT0_TEST_CHIP		BIT(5)
 
-#define	AcmHw_HwEn				BIT(0)
-#define	AcmHw_BeqEn				BIT(1)
-#define	AcmHw_ViqEn				BIT(2)
-#define	AcmHw_VoqEn				BIT(3)
-#define	AcmHw_BeqStatus				BIT(4)
-#define	AcmHw_ViqStatus				BIT(5)
-#define	AcmHw_VoqStatus				BIT(6)
+#define	ACMHW_HWEN					BIT(0)
+#define	ACMHW_BEQEN					BIT(1)
+#define	ACMHW_VIQEN					BIT(2)
+#define	ACMHW_VOQEN					BIT(3)
+#define	ACMHW_BEQSTATUS				BIT(4)
+#define	ACMHW_VIQSTATUS				BIT(5)
+#define	ACMHW_VOQSTATUS				BIT(6)
 
-#define APSDOFF					BIT(6)
+#define APSDOFF						BIT(6)
 #define APSDOFF_STATUS				BIT(7)
 
-#define BW_20MHZ				BIT(2)
+#define BW_20MHZ					BIT(2)
 
 #define RATE_BITMAP_ALL				0xFFFFF
 
-#define RATE_RRSR_CCK_ONLY_1M			0xFFFF1
+#define RATE_RRSR_CCK_ONLY_1M		0xFFFF1
 
-#define TSFRST					BIT(0)
-#define DIS_GCLK				BIT(1)
-#define PAD_SEL					BIT(2)
-#define PWR_ST					BIT(6)
+#define TSFRST						BIT(0)
+#define DIS_GCLK					BIT(1)
+#define PAD_SEL						BIT(2)
+#define PWR_ST						BIT(6)
 #define PWRBIT_OW_EN				BIT(7)
-#define ACRC					BIT(8)
-#define CFENDFORM				BIT(9)
-#define ICV					BIT(10)
+#define ACRC						BIT(8)
+#define CFENDFORM					BIT(9)
+#define ICV							BIT(10)
 
-#define AAP					BIT(0)
-#define APM					BIT(1)
-#define AM					BIT(2)
-#define AB					BIT(3)
-#define ADD3					BIT(4)
-#define APWRMGT					BIT(5)
-#define CBSSID					BIT(6)
-#define CBSSID_DATA				BIT(6)
-#define CBSSID_BCN				BIT(7)
-#define ACRC32					BIT(8)
-#define AICV					BIT(9)
-#define ADF					BIT(11)
-#define ACF					BIT(12)
-#define AMF					BIT(13)
+#define AAP							BIT(0)
+#define APM							BIT(1)
+#define AM							BIT(2)
+#define AB							BIT(3)
+#define ADD3						BIT(4)
+#define APWRMGT						BIT(5)
+#define CBSSID						BIT(6)
+#define CBSSID_DATA					BIT(6)
+#define CBSSID_BCN					BIT(7)
+#define ACRC32						BIT(8)
+#define AICV						BIT(9)
+#define ADF							BIT(11)
+#define ACF							BIT(12)
+#define AMF							BIT(13)
 #define HTC_LOC_CTRL				BIT(14)
-#define UC_DATA_EN				BIT(16)
-#define BM_DATA_EN				BIT(17)
-#define MFBEN					BIT(22)
-#define LSIGEN					BIT(23)
-#define EnMBID					BIT(24)
-#define APP_BASSN				BIT(27)
-#define APP_PHYSTS				BIT(28)
-#define APP_ICV					BIT(29)
-#define APP_MIC					BIT(30)
-#define APP_FCS					BIT(31)
+#define UC_DATA_EN					BIT(16)
+#define BM_DATA_EN					BIT(17)
+#define MFBEN						BIT(22)
+#define LSIGEN						BIT(23)
+#define ENMBID						BIT(24)
+#define APP_BASSN					BIT(27)
+#define APP_PHYSTS					BIT(28)
+#define APP_ICV						BIT(29)
+#define APP_MIC						BIT(30)
+#define APP_FCS						BIT(31)
 
 #define _MIN_SPACE(x)				((x) & 0x7)
-#define _SHORT_GI_PADDING(x)			(((x) & 0x1F) << 3)
+#define _SHORT_GI_PADDING(x)		(((x) & 0x1F) << 3)
 
-#define RXERR_TYPE_OFDM_PPDU			0
-#define RXERR_TYPE_OFDM_FALSE_ALARM		1
-#define	RXERR_TYPE_OFDM_MPDU_OK			2
-#define RXERR_TYPE_OFDM_MPDU_FAIL		3
+#define RXERR_TYPE_OFDM_PPDU		0
+#define RXERR_TYPE_OFDM_FALSE_ALARM	1
+#define	RXERR_TYPE_OFDM_MPDU_OK		2
+#define RXERR_TYPE_OFDM_MPDU_FAIL	3
 #define RXERR_TYPE_CCK_PPDU			4
-#define RXERR_TYPE_CCK_FALSE_ALARM		5
-#define RXERR_TYPE_CCK_MPDU_OK			6
-#define RXERR_TYPE_CCK_MPDU_FAIL		7
+#define RXERR_TYPE_CCK_FALSE_ALARM	5
+#define RXERR_TYPE_CCK_MPDU_OK		6
+#define RXERR_TYPE_CCK_MPDU_FAIL	7
 #define RXERR_TYPE_HT_PPDU			8
-#define RXERR_TYPE_HT_FALSE_ALARM		9
-#define RXERR_TYPE_HT_MPDU_TOTAL		10
-#define RXERR_TYPE_HT_MPDU_OK			11
-#define RXERR_TYPE_HT_MPDU_FAIL			12
-#define RXERR_TYPE_RX_FULL_DROP			15
+#define RXERR_TYPE_HT_FALSE_ALARM	9
+#define RXERR_TYPE_HT_MPDU_TOTAL	10
+#define RXERR_TYPE_HT_MPDU_OK		11
+#define RXERR_TYPE_HT_MPDU_FAIL		12
+#define RXERR_TYPE_RX_FULL_DROP		15
 
 #define RXERR_COUNTER_MASK			0xFFFFF
 #define RXERR_RPT_RST				BIT(27)
-#define _RXERR_RPT_SEL(type)			((type) << 28)
+#define _RXERR_RPT_SEL(type)		((type) << 28)
 
-#define	SCR_TxUseDK				BIT(0)
-#define	SCR_RxUseDK				BIT(1)
-#define	SCR_TxEncEnable				BIT(2)
-#define	SCR_RxDecEnable				BIT(3)
-#define	SCR_SKByA2				BIT(4)
-#define	SCR_NoSKMC				BIT(5)
+#define	SCR_TXUSEDK					BIT(0)
+#define	SCR_RXUSEDK					BIT(1)
+#define	SCR_TXENCENABLE				BIT(2)
+#define	SCR_RXDECENABLE				BIT(3)
+#define	SCR_SKBYA2					BIT(4)
+#define	SCR_NOSKMC					BIT(5)
 #define SCR_TXBCUSEDK				BIT(6)
 #define SCR_RXBCUSEDK				BIT(7)
 
@@ -1182,32 +1205,32 @@
 #define USB_IS_FULL_SPEED			1
 #define USB_SPEED_MASK				BIT(5)
 
-#define USB_NORMAL_SIE_EP_MASK			0xF
-#define USB_NORMAL_SIE_EP_SHIFT			4
+#define USB_NORMAL_SIE_EP_MASK		0xF
+#define USB_NORMAL_SIE_EP_SHIFT		4
 
 #define USB_TEST_EP_MASK			0x30
 #define USB_TEST_EP_SHIFT			4
 
-#define USB_AGG_EN				BIT(3)
+#define USB_AGG_EN					BIT(3)
 
 #define MAC_ADDR_LEN				6
-#define LAST_ENTRY_OF_TX_PKT_BUFFER		255
+#define LAST_ENTRY_OF_TX_PKT_BUFFER	255
 
-#define POLLING_LLT_THRESHOLD			20
-#define POLLING_READY_TIMEOUT_COUNT		1000
+#define POLLING_LLT_THRESHOLD		20
+#define POLLING_READY_TIMEOUT_COUNT	1000
 
 #define	MAX_MSS_DENSITY_2T			0x13
 #define	MAX_MSS_DENSITY_1T			0x0A
 
-#define EPROM_CMD_OPERATING_MODE_MASK		((1<<7)|(1<<6))
+#define EPROM_CMD_OPERATING_MODE_MASK	((1<<7)|(1<<6))
 #define EPROM_CMD_CONFIG			0x3
 #define EPROM_CMD_LOAD				1
 
 #define	HWSET_MAX_SIZE_92S			HWSET_MAX_SIZE
 
-#define	HAL_8192C_HW_GPIO_WPS_BIT		BIT(2)
+#define	HAL_8192C_HW_GPIO_WPS_BIT	BIT(2)
 
-#define	RPMAC_RESET				0x100
+#define	RPMAC_RESET					0x100
 #define	RPMAC_TXSTART				0x104
 #define	RPMAC_TXLEGACYSIG			0x108
 #define	RPMAC_TXHTSIG1				0x10c
@@ -1223,12 +1246,12 @@
 #define	RPMAC_TXMACHEADER5			0x134
 #define	RPMAC_TXDADATYPE			0x138
 #define	RPMAC_TXRANDOMSEED			0x13c
-#define	RPMAC_CCKPLCPPREAMBLE			0x140
+#define	RPMAC_CCKPLCPPREAMBLE		0x140
 #define	RPMAC_CCKPLCPHEADER			0x144
 #define	RPMAC_CCKCRC16				0x148
 #define	RPMAC_OFDMRXCRC32OK			0x170
-#define	RPMAC_OFDMRXCRC32Er			0x174
-#define	RPMAC_OFDMRXPARITYER			0x178
+#define	RPMAC_OFDMRXCRC32ER			0x174
+#define	RPMAC_OFDMRXPARITYER		0x178
 #define	RPMAC_OFDMRXCRC8ER			0x17c
 #define	RPMAC_CCKCRXRC16ER			0x180
 #define	RPMAC_CCKCRXRC32ER			0x184
@@ -1245,44 +1268,44 @@
 #define	RFPGA0_RFTIMING1			0x810
 #define	RFPGA0_RFTIMING2			0x814
 
-#define	RFPGA0_XA_HSSIPARAMETER1		0x820
-#define	RFPGA0_XA_HSSIPARAMETER2		0x824
-#define	RFPGA0_XB_HSSIPARAMETER1		0x828
-#define	RFPGA0_XB_HSSIPARAMETER2		0x82c
+#define	RFPGA0_XA_HSSIPARAMETER1	0x820
+#define	RFPGA0_XA_HSSIPARAMETER2	0x824
+#define	RFPGA0_XB_HSSIPARAMETER1	0x828
+#define	RFPGA0_XB_HSSIPARAMETER2	0x82c
 
-#define	RFPGA0_XA_LSSIPARAMETER			0x840
-#define	RFPGA0_XB_LSSIPARAMETER			0x844
+#define	RFPGA0_XA_LSSIPARAMETER		0x840
+#define	RFPGA0_XB_LSSIPARAMETER		0x844
 
-#define	RFPGA0_RFWAKEUPPARAMETER		0x850
-#define	RFPGA0_RFSLEEPUPPARAMETER		0x854
+#define	RFPGA0_RFWAKEUPPARAMETER	0x850
+#define	RFPGA0_RFSLEEPUPPARAMETER	0x854
 
-#define	RFPGA0_XAB_SWITCHCONTROL		0x858
-#define	RFPGA0_XCD_SWITCHCONTROL		0x85c
+#define	RFPGA0_XAB_SWITCHCONTROL	0x858
+#define	RFPGA0_XCD_SWITCHCONTROL	0x85c
 
-#define	RFPGA0_XA_RFINTERFACEOE			0x860
-#define	RFPGA0_XB_RFINTERFACEOE			0x864
+#define	RFPGA0_XA_RFINTERFACEOE		0x860
+#define	RFPGA0_XB_RFINTERFACEOE		0x864
 
-#define	RFPGA0_XAB_RFINTERFACESW		0x870
-#define	RFPGA0_XCD_RFINTERFACESW		0x874
+#define	RFPGA0_XAB_RFINTERFACESW	0x870
+#define	RFPGA0_XCD_RFINTERFACESW	0x874
 
-#define	rFPGA0_XAB_RFPARAMETER			0x878
-#define	rFPGA0_XCD_RFPARAMETER			0x87c
+#define	RFPGA0_XAB_RFPARAMETER		0x878
+#define	RFPGA0_XCD_RFPARAMETER		0x87c
 
-#define	RFPGA0_ANALOGPARAMETER1			0x880
-#define	RFPGA0_ANALOGPARAMETER2			0x884
-#define	RFPGA0_ANALOGPARAMETER3			0x888
-#define	RFPGA0_ANALOGPARAMETER4			0x88c
+#define	RFPGA0_ANALOGPARAMETER1		0x880
+#define	RFPGA0_ANALOGPARAMETER2		0x884
+#define	RFPGA0_ANALOGPARAMETER3		0x888
+#define	RFPGA0_ANALOGPARAMETER4		0x88c
 
-#define	RFPGA0_XA_LSSIREADBACK			0x8a0
-#define	RFPGA0_XB_LSSIREADBACK			0x8a4
-#define	RFPGA0_XC_LSSIREADBACK			0x8a8
-#define	RFPGA0_XD_LSSIREADBACK			0x8ac
+#define	RFPGA0_XA_LSSIREADBACK		0x8a0
+#define	RFPGA0_XB_LSSIREADBACK		0x8a4
+#define	RFPGA0_XC_LSSIREADBACK		0x8a8
+#define	RFPGA0_XD_LSSIREADBACK		0x8ac
 
 #define	RFPGA0_PSDREPORT			0x8b4
-#define	TRANSCEIVEA_HSPI_READBACK		0x8b8
-#define	TRANSCEIVEB_HSPI_READBACK		0x8bc
-#define	RFPGA0_XAB_RFINTERFACERB		0x8e0
-#define	RFPGA0_XCD_RFINTERFACERB		0x8e4
+#define	TRANSCEIVEA_HSPI_READBACK	0x8b8
+#define	TRANSCEIVEB_HSPI_READBACK	0x8bc
+#define	RFPGA0_XAB_RFINTERFACERB	0x8e0
+#define	RFPGA0_XCD_RFINTERFACERB	0x8e4
 
 #define	RFPGA1_RFMOD				0x900
 
@@ -1293,12 +1316,12 @@
 #define	RCCK0_SYSTEM				0xa00
 
 #define	RCCK0_AFESETTING			0xa04
-#define	RCCK0_CCA				0xa08
+#define	RCCK0_CCA					0xa08
 
 #define	RCCK0_RXAGC1				0xa0c
 #define	RCCK0_RXAGC2				0xa10
 
-#define	RCCK0_RXHP				0xa14
+#define	RCCK0_RXHP					0xa14
 
 #define	RCCK0_DSPPARAMETER1			0xa18
 #define	RCCK0_DSPPARAMETER2			0xa1c
@@ -1306,26 +1329,26 @@
 #define	RCCK0_TXFILTER1				0xa20
 #define	RCCK0_TXFILTER2				0xa24
 #define	RCCK0_DEBUGPORT				0xa28
-#define	RCCK0_FALSEALARMREPORT			0xa2c
-#define	RCCK0_TRSSIREPORT			0xa50
-#define	RCCK0_RXREPORT				0xa54
-#define	RCCK0_FACOUNTERLOWER			0xa5c
-#define	RCCK0_FACOUNTERUPPER			0xa58
+#define	RCCK0_FALSEALARMREPORT		0xa2c
+#define	RCCK0_TRSSIREPORT		0xa50
+#define	RCCK0_RXREPORT			0xa54
+#define	RCCK0_FACOUNTERLOWER		0xa5c
+#define	RCCK0_FACOUNTERUPPER		0xa58
 
-#define	ROFDM0_LSTF				0xc00
+#define	ROFDM0_LSTF					0xc00
 
-#define	ROFDM0_TRXPATHENABLE			0xc04
+#define	ROFDM0_TRXPATHENABLE		0xc04
 #define	ROFDM0_TRMUXPAR				0xc08
-#define	ROFDM0_TRSWISOLATION			0xc0c
+#define	ROFDM0_TRSWISOLATION		0xc0c
 
 #define	ROFDM0_XARXAFE				0xc10
-#define	ROFDM0_XARXIQIMBALANCE			0xc14
-#define	ROFDM0_XBRXAFE				0xc18
-#define	ROFDM0_XBRXIQIMBALANCE			0xc1c
-#define	ROFDM0_XCRXAFE				0xc20
-#define	ROFDM0_XCRXIQIMBANLANCE			0xc24
-#define	ROFDM0_XDRXAFE				0xc28
-#define	ROFDM0_XDRXIQIMBALANCE			0xc2c
+#define	ROFDM0_XARXIQIMBALANCE		0xc14
+#define	ROFDM0_XBRXAFE			0xc18
+#define	ROFDM0_XBRXIQIMBALANCE		0xc1c
+#define	ROFDM0_XCRXAFE			0xc20
+#define	ROFDM0_XCRXIQIMBANLANCE		0xc24
+#define	ROFDM0_XDRXAFE			0xc28
+#define	ROFDM0_XDRXIQIMBALANCE		0xc2c
 
 #define	ROFDM0_RXDETECTOR1			0xc30
 #define	ROFDM0_RXDETECTOR2			0xc34
@@ -1334,8 +1357,8 @@
 
 #define	ROFDM0_RXDSP				0xc40
 #define	ROFDM0_CFOANDDAGC			0xc44
-#define	ROFDM0_CCADROPTHRESHOLD			0xc48
-#define	ROFDM0_ECCATHRESHOLD			0xc4c
+#define	ROFDM0_CCADROPTHRESHOLD		0xc48
+#define	ROFDM0_ECCATHRESHOLD		0xc4c
 
 #define	ROFDM0_XAAGCCORE1			0xc50
 #define	ROFDM0_XAAGCCORE2			0xc54
@@ -1346,24 +1369,24 @@
 #define	ROFDM0_XDAGCCORE1			0xc68
 #define	ROFDM0_XDAGCCORE2			0xc6c
 
-#define	ROFDM0_AGCPARAMETER1			0xc70
-#define	ROFDM0_AGCPARAMETER2			0xc74
+#define	ROFDM0_AGCPARAMETER1		0xc70
+#define	ROFDM0_AGCPARAMETER2		0xc74
 #define	ROFDM0_AGCRSSITABLE			0xc78
 #define	ROFDM0_HTSTFAGC				0xc7c
 
-#define	ROFDM0_XATXIQIMBALANCE			0xc80
+#define	ROFDM0_XATXIQIMBALANCE		0xc80
 #define	ROFDM0_XATXAFE				0xc84
-#define	ROFDM0_XBTXIQIMBALANCE			0xc88
+#define	ROFDM0_XBTXIQIMBALANCE		0xc88
 #define	ROFDM0_XBTXAFE				0xc8c
-#define	ROFDM0_XCTXIQIMBALANCE			0xc90
-#define	ROFDM0_XCTXAFE				0xc94
-#define	ROFDM0_XDTXIQIMBALANCE			0xc98
+#define	ROFDM0_XCTXIQIMBALANCE		0xc90
+#define	ROFDM0_XCTXAFE			0xc94
+#define	ROFDM0_XDTXIQIMBALANCE		0xc98
 #define	ROFDM0_XDTXAFE				0xc9c
 
 #define ROFDM0_RXIQEXTANTA			0xca0
 
-#define	ROFDM0_RXHPPARAMETER			0xce0
-#define	ROFDM0_TXPSEUDONOISEWGT			0xce4
+#define	ROFDM0_RXHPPARAMETER		0xce0
+#define	ROFDM0_TXPSEUDONOISEWGT		0xce4
 #define	ROFDM0_FRAMESYNC			0xcf0
 #define	ROFDM0_DFSREPORT			0xcf4
 #define	ROFDM0_TXCOEFF1				0xca4
@@ -1373,19 +1396,19 @@
 #define	ROFDM0_TXCOEFF5				0xcb4
 #define	ROFDM0_TXCOEFF6				0xcb8
 
-#define	ROFDM1_LSTF				0xd00
-#define	ROFDM1_TRXPATHENABLE			0xd04
+#define	ROFDM1_LSTF					0xd00
+#define	ROFDM1_TRXPATHENABLE		0xd04
 
-#define	ROFDM1_CF0				0xd08
-#define	ROFDM1_CSI1				0xd10
-#define	ROFDM1_SBD				0xd14
-#define	ROFDM1_CSI2				0xd18
+#define	ROFDM1_CF0					0xd08
+#define	ROFDM1_CSI1					0xd10
+#define	ROFDM1_SBD					0xd14
+#define	ROFDM1_CSI2					0xd18
 #define	ROFDM1_CFOTRACKING			0xd2c
 #define	ROFDM1_TRXMESAURE1			0xd34
 #define	ROFDM1_INTFDET				0xd3c
-#define	ROFDM1_PSEUDONOISESTATEAB		0xd50
-#define	ROFDM1_PSEUDONOISESTATECD		0xd54
-#define	ROFDM1_RXPSEUDONOISEWGT			0xd58
+#define	ROFDM1_PSEUDONOISESTATEAB	0xd50
+#define	ROFDM1_PSEUDONOISESTATECD	0xd54
+#define	ROFDM1_RXPSEUDONOISEWGT		0xd58
 
 #define	ROFDM_PHYCOUNTER1			0xda0
 #define	ROFDM_PHYCOUNTER2			0xda4
@@ -1397,35 +1420,35 @@
 #define	ROFDM_LONGCFOCD				0xdb8
 #define	ROFDM_TAILCF0AB				0xdbc
 #define	ROFDM_TAILCF0CD				0xdc0
-#define	ROFDM_PWMEASURE1			0xdc4
-#define	ROFDM_PWMEASURE2			0xdc8
+#define	ROFDM_PWMEASURE1		0xdc4
+#define	ROFDM_PWMEASURE2		0xdc8
 #define	ROFDM_BWREPORT				0xdcc
 #define	ROFDM_AGCREPORT				0xdd0
-#define	ROFDM_RXSNR				0xdd4
+#define	ROFDM_RXSNR					0xdd4
 #define	ROFDM_RXEVMCSI				0xdd8
 #define	ROFDM_SIGREPORT				0xddc
 
 #define	RTXAGC_A_RATE18_06			0xe00
 #define	RTXAGC_A_RATE54_24			0xe04
 #define	RTXAGC_A_CCK1_MCS32			0xe08
-#define	RTXAGC_A_MCS03_MCS00			0xe10
-#define	RTXAGC_A_MCS07_MCS04			0xe14
-#define	RTXAGC_A_MCS11_MCS08			0xe18
-#define	RTXAGC_A_MCS15_MCS12			0xe1c
+#define	RTXAGC_A_MCS03_MCS00		0xe10
+#define	RTXAGC_A_MCS07_MCS04		0xe14
+#define	RTXAGC_A_MCS11_MCS08		0xe18
+#define	RTXAGC_A_MCS15_MCS12		0xe1c
 
 #define	RTXAGC_B_RATE18_06			0x830
 #define	RTXAGC_B_RATE54_24			0x834
-#define	RTXAGC_B_CCK1_55_MCS32			0x838
-#define	RTXAGC_B_MCS03_MCS00			0x83c
-#define	RTXAGC_B_MCS07_MCS04			0x848
-#define	RTXAGC_B_MCS11_MCS08			0x84c
-#define	RTXAGC_B_MCS15_MCS12			0x868
-#define	RTXAGC_B_CCK11_A_CCK2_11		0x86c
+#define	RTXAGC_B_CCK1_55_MCS32		0x838
+#define	RTXAGC_B_MCS03_MCS00		0x83c
+#define	RTXAGC_B_MCS07_MCS04		0x848
+#define	RTXAGC_B_MCS11_MCS08		0x84c
+#define	RTXAGC_B_MCS15_MCS12		0x868
+#define	RTXAGC_B_CCK11_A_CCK2_11	0x86c
 
 #define	RZEBRA1_HSSIENABLE			0x0
 #define	RZEBRA1_TRXENABLE1			0x1
 #define	RZEBRA1_TRXENABLE2			0x2
-#define	RZEBRA1_AGC				0x4
+#define	RZEBRA1_AGC					0x4
 #define	RZEBRA1_CHARGEPUMP			0x5
 #define	RZEBRA1_CHANNEL				0x7
 
@@ -1434,649 +1457,664 @@
 #define	RZEBRA1_RXLPF				0xb
 #define	RZEBRA1_RXHPFCORNER			0xc
 
-#define	RGLOBALCTRL				0
+#define	RGLOBALCTRL					0
 #define	RRTL8256_TXLPF				19
 #define	RRTL8256_RXLPF				11
 #define	RRTL8258_TXLPF				0x11
 #define	RRTL8258_RXLPF				0x13
 #define	RRTL8258_RSSILPF			0xa
 
-#define	RF_AC					0x00
+#define	RF_AC						0x00
 
-#define	RF_IQADJ_G1				0x01
-#define	RF_IQADJ_G2				0x02
-#define	RF_POW_TRSW				0x05
+#define	RF_IQADJ_G1					0x01
+#define	RF_IQADJ_G2					0x02
+#define	RF_POW_TRSW					0x05
 
-#define	RF_GAIN_RX				0x06
-#define	RF_GAIN_TX				0x07
+#define	RF_GAIN_RX					0x06
+#define	RF_GAIN_TX					0x07
 
-#define	RF_TXM_IDAC				0x08
-#define	RF_BS_IQGEN				0x0F
+#define	RF_TXM_IDAC					0x08
+#define	RF_BS_IQGEN					0x0F
 
-#define	RF_MODE1				0x10
-#define	RF_MODE2				0x11
+#define	RF_MODE1					0x10
+#define	RF_MODE2					0x11
 
 #define	RF_RX_AGC_HP				0x12
-#define	RF_TX_AGC				0x13
-#define	RF_BIAS					0x14
-#define	RF_IPA					0x15
+#define	RF_TX_AGC					0x13
+#define	RF_BIAS						0x14
+#define	RF_IPA						0x15
 #define	RF_POW_ABILITY				0x17
-#define	RF_MODE_AG				0x18
-#define	RRFCHANNEL				0x18
-#define	RF_CHNLBW				0x18
-#define	RF_TOP					0x19
+#define	RF_MODE_AG					0x18
+#define	RRFCHANNEL					0x18
+#define	RF_CHNLBW					0x18
+#define	RF_TOP						0x19
 
-#define	RF_RX_G1				0x1A
-#define	RF_RX_G2				0x1B
+#define	RF_RX_G1					0x1A
+#define	RF_RX_G2					0x1B
 
-#define	RF_RX_BB2				0x1C
-#define	RF_RX_BB1				0x1D
+#define	RF_RX_BB2					0x1C
+#define	RF_RX_BB1					0x1D
 
-#define	RF_RCK1					0x1E
-#define	RF_RCK2					0x1F
+#define	RF_RCK1						0x1E
+#define	RF_RCK2						0x1F
 
-#define	RF_TX_G1				0x20
-#define	RF_TX_G2				0x21
-#define	RF_TX_G3				0x22
+#define	RF_TX_G1					0x20
+#define	RF_TX_G2					0x21
+#define	RF_TX_G3					0x22
 
-#define	RF_TX_BB1				0x23
-#define	RF_T_METER				0x24
+#define	RF_TX_BB1					0x23
+#define	RF_T_METER					0x24
 
-#define	RF_SYN_G1				0x25
-#define	RF_SYN_G2				0x26
-#define	RF_SYN_G3				0x27
-#define	RF_SYN_G4				0x28
-#define	RF_SYN_G5				0x29
-#define	RF_SYN_G6				0x2A
-#define	RF_SYN_G7				0x2B
-#define	RF_SYN_G8				0x2C
+#define	RF_SYN_G1					0x25
+#define	RF_SYN_G2					0x26
+#define	RF_SYN_G3					0x27
+#define	RF_SYN_G4					0x28
+#define	RF_SYN_G5					0x29
+#define	RF_SYN_G6					0x2A
+#define	RF_SYN_G7					0x2B
+#define	RF_SYN_G8					0x2C
 
-#define	RF_RCK_OS				0x30
-#define	RF_TXPA_G1				0x31
-#define	RF_TXPA_G2				0x32
-#define	RF_TXPA_G3				0x33
+#define	RF_RCK_OS					0x30
+#define	RF_TXPA_G1					0x31
+#define	RF_TXPA_G2					0x32
+#define	RF_TXPA_G3					0x33
 
-#define	BBBRESETB				0x100
+#define	BBBRESETB					0x100
 #define	BGLOBALRESETB				0x200
 #define	BOFDMTXSTART				0x4
-#define	BCCKTXSTART				0x8
-#define	BCRC32DEBUG				0x100
+#define	BCCKTXSTART					0x8
+#define	BCRC32DEBUG					0x100
 #define	BPMACLOOPBACK				0x10
-#define	BTXLSIG					0xffffff
-#define	BOFDMTXRATE				0xf
+#define	BTXLSIG						0xffffff
+#define	BOFDMTXRATE					0xf
 #define	BOFDMTXRESERVED				0x10
 #define	BOFDMTXLENGTH				0x1ffe0
 #define	BOFDMTXPARITY				0x20000
-#define	BTXHTSIG1				0xffffff
+#define	BTXHTSIG1					0xffffff
 #define	BTXHTMCSRATE				0x7f
-#define	BTXHTBW					0x80
-#define	BTXHTLENGTH				0xffff00
-#define	BTXHTSIG2				0xffffff
+#define	BTXHTBW						0x80
+#define	BTXHTLENGTH					0xffff00
+#define	BTXHTSIG2					0xffffff
 #define	BTXHTSMOOTHING				0x1
 #define	BTXHTSOUNDING				0x2
 #define	BTXHTRESERVED				0x4
 #define	BTXHTAGGREATION				0x8
-#define	BTXHTSTBC				0x30
+#define	BTXHTSTBC					0x30
 #define	BTXHTADVANCECODING			0x40
 #define	BTXHTSHORTGI				0x80
 #define	BTXHTNUMBERHT_LTF			0x300
-#define	BTXHTCRC8				0x3fc00
+#define	BTXHTCRC8					0x3fc00
 #define	BCOUNTERRESET				0x10000
 #define	BNUMOFOFDMTX				0xffff
-#define	BNUMOFCCKTX				0xffff0000
+#define	BNUMOFCCKTX					0xffff0000
 #define	BTXIDLEINTERVAL				0xffff
 #define	BOFDMSERVICE				0xffff0000
 #define	BTXMACHEADER				0xffffffff
-#define	BTXDATAINIT				0xff
-#define	BTXHTMODE				0x100
-#define	BTXDATATYPE				0x30000
+#define	BTXDATAINIT					0xff
+#define	BTXHTMODE					0x100
+#define	BTXDATATYPE					0x30000
 #define	BTXRANDOMSEED				0xffffffff
 #define	BCCKTXPREAMBLE				0x1
-#define	BCCKTXSFD				0xffff0000
-#define	BCCKTXSIG				0xff
+#define	BCCKTXSFD					0xffff0000
+#define	BCCKTXSIG					0xff
 #define	BCCKTXSERVICE				0xff00
 #define	BCCKLENGTHEXT				0x8000
 #define	BCCKTXLENGHT				0xffff0000
-#define	BCCKTXCRC16				0xffff
+#define	BCCKTXCRC16					0xffff
 #define	BCCKTXSTATUS				0x1
 #define	BOFDMTXSTATUS				0x2
-#define IS_BB_REG_OFFSET_92S(_Offset)	\
-	((_Offset >= 0x800) && (_Offset <= 0xfff))
+#define IS_BB_REG_OFFSET_92S(_offset)	\
+	((_offset >= 0x800) && (_offset <= 0xfff))
 
-#define	BRFMOD					0x1
-#define	BJAPANMODE				0x2
-#define	BCCKTXSC				0x30
-#define	BCCKEN					0x1000000
-#define	BOFDMEN					0x2000000
+#define	BRFMOD						0x1
+#define	BJAPANMODE					0x2
+#define	BCCKTXSC					0x30
+#define	BCCKEN						0x1000000
+#define	BOFDMEN						0x2000000
 
-#define	BOFDMRXADCPHASE				0x10000
-#define	BOFDMTXDACPHASE				0x40000
-#define	BXATXAGC				0x3f
+#define	BOFDMRXADCPHASE			0x10000
+#define	BOFDMTXDACPHASE			0x40000
+#define	BXATXAGC			0x3f
 
-#define	BXBTXAGC				0xf00
-#define	BXCTXAGC				0xf000
-#define	BXDTXAGC				0xf0000
+#define	BXBTXAGC			0xf00
+#define	BXCTXAGC			0xf000
+#define	BXDTXAGC			0xf0000
 
-#define	BPASTART				0xf0000000
-#define	BTRSTART				0x00f00000
-#define	BRFSTART				0x0000f000
-#define	BBBSTART				0x000000f0
-#define	BBBCCKSTART				0x0000000f
-#define	BPAEND					0xf
-#define	BTREND					0x0f000000
-#define	BRFEND					0x000f0000
-#define	BCCAMASK				0x000000f0
-#define	BR2RCCAMASK				0x00000f00
-#define	BHSSI_R2TDELAY				0xf8000000
-#define	BHSSI_T2RDELAY				0xf80000
-#define	BCONTXHSSI				0x400
-#define	BIGFROMCCK				0x200
-#define	BAGCADDRESS				0x3f
-#define	BRXHPTX					0x7000
-#define	BRXHP2RX				0x38000
-#define	BRXHPCCKINI				0xc0000
-#define	BAGCTXCODE				0xc00000
-#define	BAGCRXCODE				0x300000
+#define	BPASTART			0xf0000000
+#define	BTRSTART			0x00f00000
+#define	BRFSTART			0x0000f000
+#define	BBBSTART			0x000000f0
+#define	BBBCCKSTART			0x0000000f
+#define	BPAEND				0xf
+#define	BTREND				0x0f000000
+#define	BRFEND				0x000f0000
+#define	BCCAMASK			0x000000f0
+#define	BR2RCCAMASK			0x00000f00
+#define	BHSSI_R2TDELAY			0xf8000000
+#define	BHSSI_T2RDELAY			0xf80000
+#define	BCONTXHSSI			0x400
+#define	BIGFROMCCK			0x200
+#define	BAGCADDRESS			0x3f
+#define	BRXHPTX				0x7000
+#define	BRXHP2RX			0x38000
+#define	BRXHPCCKINI			0xc0000
+#define	BAGCTXCODE			0xc00000
+#define	BAGCRXCODE			0x300000
 
-#define	B3WIREDATALENGTH			0x800
-#define	B3WIREADDREAALENGTH			0x400
+#define	B3WIREDATALENGTH		0x800
+#define	B3WIREADDREAALENGTH		0x400
 
-#define	B3WIRERFPOWERDOWN			0x1
-#define	B5GPAPEPOLARITY				0x40000000
-#define	B2GPAPEPOLARITY				0x80000000
-#define	BRFSW_TXDEFAULTANT			0x3
-#define	BRFSW_TXOPTIONANT			0x30
-#define	BRFSW_RXDEFAULTANT			0x300
-#define	BRFSW_RXOPTIONANT			0x3000
-#define	BRFSI_3WIREDATA				0x1
-#define	BRFSI_3WIRECLOCK			0x2
-#define	BRFSI_3WIRELOAD				0x4
-#define	BRFSI_3WIRERW				0x8
-#define	BRFSI_3WIRE				0xf
+#define	B3WIRERFPOWERDOWN		0x1
+#define	B5GPAPEPOLARITY			0x40000000
+#define	B2GPAPEPOLARITY			0x80000000
+#define	BRFSW_TXDEFAULTANT		0x3
+#define	BRFSW_TXOPTIONANT		0x30
+#define	BRFSW_RXDEFAULTANT		0x300
+#define	BRFSW_RXOPTIONANT		0x3000
+#define	BRFSI_3WIREDATA			0x1
+#define	BRFSI_3WIRECLOCK		0x2
+#define	BRFSI_3WIRELOAD			0x4
+#define	BRFSI_3WIRERW			0x8
+#define	BRFSI_3WIRE			0xf
 
-#define	BRFSI_RFENV				0x10
+#define	BRFSI_RFENV			0x10
 
-#define	BRFSI_TRSW				0x20
-#define	BRFSI_TRSWB				0x40
-#define	BRFSI_ANTSW				0x100
-#define	BRFSI_ANTSWB				0x200
-#define	BRFSI_PAPE				0x400
-#define	BRFSI_PAPE5G				0x800
-#define	BBANDSELECT				0x1
-#define	BHTSIG2_GI				0x80
-#define	BHTSIG2_SMOOTHING			0x01
-#define	BHTSIG2_SOUNDING			0x02
-#define	BHTSIG2_AGGREATON			0x08
-#define	BHTSIG2_STBC				0x30
-#define	BHTSIG2_ADVCODING			0x40
-#define	BHTSIG2_NUMOFHTLTF			0x300
-#define	BHTSIG2_CRC8				0x3fc
-#define	BHTSIG1_MCS				0x7f
-#define	BHTSIG1_BANDWIDTH			0x80
-#define	BHTSIG1_HTLENGTH			0xffff
-#define	BLSIG_RATE				0xf
-#define	BLSIG_RESERVED				0x10
-#define	BLSIG_LENGTH				0x1fffe
-#define	BLSIG_PARITY				0x20
-#define	BCCKRXPHASE				0x4
+#define	BRFSI_TRSW			0x20
+#define	BRFSI_TRSWB			0x40
+#define	BRFSI_ANTSW			0x100
+#define	BRFSI_ANTSWB			0x200
+#define	BRFSI_PAPE			0x400
+#define	BRFSI_PAPE5G			0x800
+#define	BBANDSELECT			0x1
+#define	BHTSIG2_GI			0x80
+#define	BHTSIG2_SMOOTHING		0x01
+#define	BHTSIG2_SOUNDING		0x02
+#define	BHTSIG2_AGGREATON		0x08
+#define	BHTSIG2_STBC			0x30
+#define	BHTSIG2_ADVCODING		0x40
+#define	BHTSIG2_NUMOFHTLTF		0x300
+#define	BHTSIG2_CRC8			0x3fc
+#define	BHTSIG1_MCS			0x7f
+#define	BHTSIG1_BANDWIDTH		0x80
+#define	BHTSIG1_HTLENGTH		0xffff
+#define	BLSIG_RATE			0xf
+#define	BLSIG_RESERVED			0x10
+#define	BLSIG_LENGTH			0x1fffe
+#define	BLSIG_PARITY			0x20
+#define	BCCKRXPHASE			0x4
 
-#define	BLSSIREADADDRESS			0x7f800000
-#define	BLSSIREADEDGE				0x80000000
+#define	BLSSIREADADDRESS		0x7f800000
+#define	BLSSIREADEDGE			0x80000000
 
-#define	BLSSIREADBACKDATA			0xfffff
+#define	BLSSIREADBACKDATA		0xfffff
 
-#define	BLSSIREADOKFLAG				0x1000
-#define	BCCKSAMPLERATE				0x8
-#define	BREGULATOR0STANDBY			0x1
-#define	BREGULATORPLLSTANDBY			0x2
-#define	BREGULATOR1STANDBY			0x4
-#define	BPLLPOWERUP				0x8
-#define	BDPLLPOWERUP				0x10
-#define	BDA10POWERUP				0x20
-#define	BAD7POWERUP				0x200
-#define	BDA6POWERUP				0x2000
-#define	BXTALPOWERUP				0x4000
-#define	B40MDCLKPOWERUP				0x8000
-#define	BDA6DEBUGMODE				0x20000
-#define	BDA6SWING				0x380000
+#define	BLSSIREADOKFLAG			0x1000
+#define	BCCKSAMPLERATE			0x8
+#define	BREGULATOR0STANDBY		0x1
+#define	BREGULATORPLLSTANDBY		0x2
+#define	BREGULATOR1STANDBY		0x4
+#define	BPLLPOWERUP			0x8
+#define	BDPLLPOWERUP			0x10
+#define	BDA10POWERUP			0x20
+#define	BAD7POWERUP			0x200
+#define	BDA6POWERUP			0x2000
+#define	BXTALPOWERUP			0x4000
+#define	B40MDCLKPOWERUP			0x8000
+#define	BDA6DEBUGMODE			0x20000
+#define	BDA6SWING			0x380000
 
-#define	BADCLKPHASE				0x4000000
-#define	B80MCLKDELAY				0x18000000
-#define	BAFEWATCHDOGENABLE			0x20000000
+#define	BADCLKPHASE			0x4000000
+#define	B80MCLKDELAY			0x18000000
+#define	BAFEWATCHDOGENABLE		0x20000000
 
-#define	BXTALCAP01				0xc0000000
-#define	BXTALCAP23				0x3
-#define	BXTALCAP92X				0x0f000000
-#define BXTALCAP				0x0f000000
+#define	BXTALCAP01			0xc0000000
+#define	BXTALCAP23			0x3
+#define	BXTALCAP92X					0x0f000000
+#define BXTALCAP			0x0f000000
 
-#define	BINTDIFCLKENABLE			0x400
-#define	BEXTSIGCLKENABLE			0x800
-#define	BBANDGAP_MBIAS_POWERUP			0x10000
-#define	BAD11SH_GAIN				0xc0000
-#define	BAD11NPUT_RANGE				0x700000
-#define	BAD110P_CURRENT				0x3800000
-#define	BLPATH_LOOPBACK				0x4000000
-#define	BQPATH_LOOPBACK				0x8000000
-#define	BAFE_LOOPBACK				0x10000000
-#define	BDA10_SWING				0x7e0
-#define	BDA10_REVERSE				0x800
-#define	BDA_CLK_SOURCE				0x1000
-#define	BDA7INPUT_RANGE				0x6000
-#define	BDA7_GAIN				0x38000
-#define	BDA7OUTPUT_CM_MODE			0x40000
-#define	BDA7INPUT_CM_MODE			0x380000
-#define	BDA7CURRENT				0xc00000
-#define	BREGULATOR_ADJUST			0x7000000
-#define	BAD11POWERUP_ATTX			0x1
-#define	BDA10PS_ATTX				0x10
-#define	BAD11POWERUP_ATRX			0x100
-#define	BDA10PS_ATRX				0x1000
-#define	BCCKRX_AGC_FORMAT			0x200
-#define	BPSDFFT_SAMPLE_POINT			0xc000
-#define	BPSD_AVERAGE_NUM			0x3000
-#define	BIQPATH_CONTROL				0xc00
-#define	BPSD_FREQ				0x3ff
-#define	BPSD_ANTENNA_PATH			0x30
-#define	BPSD_IQ_SWITCH				0x40
-#define	BPSD_RX_TRIGGER				0x400000
-#define	BPSD_TX_TRIGGER				0x80000000
-#define	BPSD_SINE_TONE_SCALE			0x7f000000
-#define	BPSD_REPORT				0xffff
+#define	BINTDIFCLKENABLE		0x400
+#define	BEXTSIGCLKENABLE		0x800
+#define	BBANDGAP_MBIAS_POWERUP      0x10000
+#define	BAD11SH_GAIN			0xc0000
+#define	BAD11NPUT_RANGE			0x700000
+#define	BAD110P_CURRENT			0x3800000
+#define	BLPATH_LOOPBACK			0x4000000
+#define	BQPATH_LOOPBACK			0x8000000
+#define	BAFE_LOOPBACK			0x10000000
+#define	BDA10_SWING			0x7e0
+#define	BDA10_REVERSE			0x800
+#define	BDA_CLK_SOURCE              0x1000
+#define	BDA7INPUT_RANGE			0x6000
+#define	BDA7_GAIN			0x38000
+#define	BDA7OUTPUT_CM_MODE          0x40000
+#define	BDA7INPUT_CM_MODE           0x380000
+#define	BDA7CURRENT			0xc00000
+#define	BREGULATOR_ADJUST		0x7000000
+#define	BAD11POWERUP_ATTX		0x1
+#define	BDA10PS_ATTX			0x10
+#define	BAD11POWERUP_ATRX		0x100
+#define	BDA10PS_ATRX			0x1000
+#define	BCCKRX_AGC_FORMAT           0x200
+#define	BPSDFFT_SAMPLE_POINT		0xc000
+#define	BPSD_AVERAGE_NUM            0x3000
+#define	BIQPATH_CONTROL			0xc00
+#define	BPSD_FREQ			0x3ff
+#define	BPSD_ANTENNA_PATH           0x30
+#define	BPSD_IQ_SWITCH              0x40
+#define	BPSD_RX_TRIGGER             0x400000
+#define	BPSD_TX_TRIGGER             0x80000000
+#define	BPSD_SINE_TONE_SCALE        0x7f000000
+#define	BPSD_REPORT			0xffff
 
-#define	BOFDM_TXSC				0x30000000
-#define	BCCK_TXON				0x1
-#define	BOFDM_TXON				0x2
-#define	BDEBUG_PAGE				0xfff
-#define	BDEBUG_ITEM				0xff
-#define	BANTL					0x10
-#define	BANT_NONHT				0x100
-#define	BANT_HT1				0x1000
-#define	BANT_HT2				0x10000
-#define	BANT_HT1S1				0x100000
-#define	BANT_NONHTS1				0x1000000
+#define	BOFDM_TXSC			0x30000000
+#define	BCCK_TXON			0x1
+#define	BOFDM_TXON			0x2
+#define	BDEBUG_PAGE			0xfff
+#define	BDEBUG_ITEM			0xff
+#define	BANTL				0x10
+#define	BANT_NONHT		    0x100
+#define	BANT_HT1			0x1000
+#define	BANT_HT2			0x10000
+#define	BANT_HT1S1			0x100000
+#define	BANT_NONHTS1			0x1000000
 
-#define	BCCK_BBMODE				0x3
-#define	BCCK_TXPOWERSAVING			0x80
-#define	BCCK_RXPOWERSAVING			0x40
+#define	BCCK_BBMODE			0x3
+#define	BCCK_TXPOWERSAVING		0x80
+#define	BCCK_RXPOWERSAVING		0x40
 
-#define	BCCK_SIDEBAND				0x10
+#define	BCCK_SIDEBAND			0x10
 
-#define	BCCK_SCRAMBLE				0x8
-#define	BCCK_ANTDIVERSITY			0x8000
-#define	BCCK_CARRIER_RECOVERY			0x4000
-#define	BCCK_TXRATE				0x3000
-#define	BCCK_DCCANCEL				0x0800
-#define	BCCK_ISICANCEL				0x0400
-#define	BCCK_MATCH_FILTER			0x0200
-#define	BCCK_EQUALIZER				0x0100
-#define	BCCK_PREAMBLE_DETECT			0x800000
-#define	BCCK_FAST_FALSECCAi			0x400000
-#define	BCCK_CH_ESTSTARTi			0x300000
-#define	BCCK_CCA_COUNTi				0x080000
-#define	BCCK_CS_LIM				0x070000
-#define	BCCK_BIST_MODEi				0x80000000
-#define	BCCK_CCAMASK				0x40000000
-#define	BCCK_TX_DAC_PHASE			0x4
-#define	BCCK_RX_ADC_PHASE			0x20000000
-#define	BCCKR_CP_MODE				0x0100
-#define	BCCK_TXDC_OFFSET			0xf0
-#define	BCCK_RXDC_OFFSET			0xf
-#define	BCCK_CCA_MODE				0xc000
-#define	BCCK_FALSECS_LIM			0x3f00
-#define	BCCK_CS_RATIO				0xc00000
-#define	BCCK_CORGBIT_SEL			0x300000
-#define	BCCK_PD_LIM				0x0f0000
-#define	BCCK_NEWCCA				0x80000000
-#define	BCCK_RXHP_OF_IG				0x8000
-#define	BCCK_RXIG				0x7f00
-#define	BCCK_LNA_POLARITY			0x800000
-#define	BCCK_RX1ST_BAIN				0x7f0000
-#define	BCCK_RF_EXTEND				0x20000000
-#define	BCCK_RXAGC_SATLEVEL			0x1f000000
-#define	BCCK_RXAGC_SATCOUNT			0xe0
-#define	bCCKRxRFSettle				0x1f
-#define	BCCK_FIXED_RXAGC			0x8000
-#define	BCCK_ANTENNA_POLARITY			0x2000
-#define	BCCK_TXFILTER_TYPE			0x0c00
-#define	BCCK_RXAGC_REPORTTYPE			0x0300
-#define	BCCK_RXDAGC_EN				0x80000000
-#define	BCCK_RXDAGC_PERIOD			0x20000000
-#define	BCCK_RXDAGC_SATLEVEL			0x1f000000
-#define	BCCK_TIMING_RECOVERY			0x800000
-#define	BCCK_TXC0				0x3f0000
-#define	BCCK_TXC1				0x3f000000
-#define	BCCK_TXC2				0x3f
-#define	BCCK_TXC3				0x3f00
-#define	BCCK_TXC4				0x3f0000
-#define	BCCK_TXC5				0x3f000000
-#define	BCCK_TXC6				0x3f
-#define	BCCK_TXC7				0x3f00
-#define	BCCK_DEBUGPORT				0xff0000
-#define	BCCK_DAC_DEBUG				0x0f000000
-#define	BCCK_FALSEALARM_ENABLE			0x8000
-#define	BCCK_FALSEALARM_READ			0x4000
-#define	BCCK_TRSSI				0x7f
-#define	BCCK_RXAGC_REPORT			0xfe
-#define	BCCK_RXREPORT_ANTSEL			0x80000000
-#define	BCCK_RXREPORT_MFOFF			0x40000000
-#define	BCCK_RXREPORT_SQLOSS			0x20000000
-#define	BCCK_RXREPORT_PKTLOSS			0x10000000
-#define	BCCK_RXREPORT_LOCKEDBIT			0x08000000
-#define	BCCK_RXREPORT_RATEERROR			0x04000000
-#define	BCCK_RXREPORT_RXRATE			0x03000000
-#define	BCCK_RXFA_COUNTER_LOWER			0xff
-#define	BCCK_RXFA_COUNTER_UPPER			0xff000000
-#define	BCCK_RXHPAGC_START			0xe000
-#define	BCCK_RXHPAGC_FINAL			0x1c00
-#define	BCCK_RXFALSEALARM_ENABLE		0x8000
-#define	BCCK_FACOUNTER_FREEZE			0x4000
-#define	BCCK_TXPATH_SEL				0x10000000
-#define	BCCK_DEFAULT_RXPATH			0xc000000
-#define	BCCK_OPTION_RXPATH			0x3000000
+#define	BCCK_SCRAMBLE			0x8
+#define	BCCK_ANTDIVERSITY		0x8000
+#define	BCCK_CARRIER_RECOVERY		0x4000
+#define	BCCK_TXRATE			0x3000
+#define	BCCK_DCCANCEL			0x0800
+#define	BCCK_ISICANCEL			0x0400
+#define	BCCK_MATCH_FILTER           0x0200
+#define	BCCK_EQUALIZER			0x0100
+#define	BCCK_PREAMBLE_DETECT		0x800000
+#define	BCCK_FAST_FALSECCA          0x400000
+#define	BCCK_CH_ESTSTART            0x300000
+#define	BCCK_CCA_COUNT              0x080000
+#define	BCCK_CS_LIM			0x070000
+#define	BCCK_BIST_MODE              0x80000000
+#define	BCCK_CCAMASK			0x40000000
+#define	BCCK_TX_DAC_PHASE		0x4
+#define	BCCK_RX_ADC_PHASE		0x20000000
+#define	BCCKR_CP_MODE			0x0100
+#define	BCCK_TXDC_OFFSET		0xf0
+#define	BCCK_RXDC_OFFSET		0xf
+#define	BCCK_CCA_MODE			0xc000
+#define	BCCK_FALSECS_LIM		0x3f00
+#define	BCCK_CS_RATIO			0xc00000
+#define	BCCK_CORGBIT_SEL		0x300000
+#define	BCCK_PD_LIM			0x0f0000
+#define	BCCK_NEWCCA			0x80000000
+#define	BCCK_RXHP_OF_IG             0x8000
+#define	BCCK_RXIG			0x7f00
+#define	BCCK_LNA_POLARITY           0x800000
+#define	BCCK_RX1ST_BAIN             0x7f0000
+#define	BCCK_RF_EXTEND              0x20000000
+#define	BCCK_RXAGC_SATLEVEL		0x1f000000
+#define	BCCK_RXAGC_SATCOUNT		0xe0
+#define	BCCKRXRFSETTLE			0x1f
+#define	BCCK_FIXED_RXAGC		0x8000
+#define	BCCK_ANTENNA_POLARITY		0x2000
+#define	BCCK_TXFILTER_TYPE          0x0c00
+#define	BCCK_RXAGC_REPORTTYPE		0x0300
+#define	BCCK_RXDAGC_EN              0x80000000
+#define	BCCK_RXDAGC_PERIOD		0x20000000
+#define	BCCK_RXDAGC_SATLEVEL		0x1f000000
+#define	BCCK_TIMING_RECOVERY		0x800000
+#define	BCCK_TXC0			0x3f0000
+#define	BCCK_TXC1			0x3f000000
+#define	BCCK_TXC2			0x3f
+#define	BCCK_TXC3			0x3f00
+#define	BCCK_TXC4			0x3f0000
+#define	BCCK_TXC5			0x3f000000
+#define	BCCK_TXC6			0x3f
+#define	BCCK_TXC7			0x3f00
+#define	BCCK_DEBUGPORT			0xff0000
+#define	BCCK_DAC_DEBUG              0x0f000000
+#define	BCCK_FALSEALARM_ENABLE      0x8000
+#define	BCCK_FALSEALARM_READ        0x4000
+#define	BCCK_TRSSI			0x7f
+#define	BCCK_RXAGC_REPORT           0xfe
+#define	BCCK_RXREPORT_ANTSEL		0x80000000
+#define	BCCK_RXREPORT_MFOFF		0x40000000
+#define	BCCK_RXREPORT_SQLOSS		0x20000000
+#define	BCCK_RXREPORT_PKTLOSS		0x10000000
+#define	BCCK_RXREPORT_LOCKEDBIT		0x08000000
+#define	BCCK_RXREPORT_RATEERROR		0x04000000
+#define	BCCK_RXREPORT_RXRATE		0x03000000
+#define	BCCK_RXFA_COUNTER_LOWER     0xff
+#define	BCCK_RXFA_COUNTER_UPPER     0xff000000
+#define	BCCK_RXHPAGC_START          0xe000
+#define	BCCK_RXHPAGC_FINAL          0x1c00
+#define	BCCK_RXFALSEALARM_ENABLE    0x8000
+#define	BCCK_FACOUNTER_FREEZE       0x4000
+#define	BCCK_TXPATH_SEL             0x10000000
+#define	BCCK_DEFAULT_RXPATH         0xc000000
+#define	BCCK_OPTION_RXPATH          0x3000000
 
-#define	BNUM_OFSTF				0x3
-#define	BSHIFT_L				0xc0
-#define	BGI_TH					0xc
-#define	BRXPATH_A				0x1
-#define	BRXPATH_B				0x2
-#define	BRXPATH_C				0x4
-#define	BRXPATH_D				0x8
-#define	BTXPATH_A				0x1
-#define	BTXPATH_B				0x2
-#define	BTXPATH_C				0x4
-#define	BTXPATH_D				0x8
-#define	BTRSSI_FREQ				0x200
-#define	BADC_BACKOFF				0x3000
-#define	BDFIR_BACKOFF				0xc000
-#define	BTRSSI_LATCH_PHASE			0x10000
-#define	BRX_LDC_OFFSET				0xff
-#define	BRX_QDC_OFFSET				0xff00
-#define	BRX_DFIR_MODE				0x1800000
-#define	BRX_DCNF_TYPE				0xe000000
-#define	BRXIQIMB_A				0x3ff
-#define	BRXIQIMB_B				0xfc00
-#define	BRXIQIMB_C				0x3f0000
-#define	BRXIQIMB_D				0xffc00000
-#define	BDC_DC_NOTCH				0x60000
-#define	BRXNB_NOTCH				0x1f000000
-#define	BPD_TH					0xf
-#define	BPD_TH_OPT2				0xc000
-#define	BPWED_TH				0x700
-#define	BIFMF_WIN_L				0x800
-#define	BPD_OPTION				0x1000
-#define	BMF_WIN_L				0xe000
-#define	BBW_SEARCH_L				0x30000
-#define	BWIN_ENH_L				0xc0000
-#define	BBW_TH					0x700000
-#define	BED_TH2					0x3800000
-#define	BBW_OPTION				0x4000000
-#define	BRADIO_TH				0x18000000
-#define	BWINDOW_L				0xe0000000
-#define	BSBD_OPTION				0x1
-#define	BFRAME_TH				0x1c
-#define	BFS_OPTION				0x60
-#define	BDC_SLOPE_CHECK				0x80
-#define	BFGUARD_COUNTER_DC_L			0xe00
-#define	BFRAME_WEIGHT_SHORT			0x7000
-#define	BSUB_TUNE				0xe00000
-#define	BFRAME_DC_LENGTH			0xe000000
-#define	BSBD_START_OFFSET			0x30000000
-#define	BFRAME_TH_2				0x7
-#define	BFRAME_GI2_TH				0x38
-#define	BGI2_SYNC_EN				0x40
-#define	BSARCH_SHORT_EARLY			0x300
-#define	BSARCH_SHORT_LATE			0xc00
-#define	BSARCH_GI2_LATE				0x70000
-#define	BCFOANTSUM				0x1
-#define	BCFOACC					0x2
-#define	BCFOSTARTOFFSET				0xc
-#define	BCFOLOOPBACK				0x70
-#define	BCFOSUMWEIGHT				0x80
-#define	BDAGCENABLE				0x10000
-#define	BTXIQIMB_A				0x3ff
-#define	BTXIQIMB_b				0xfc00
-#define	BTXIQIMB_C				0x3f0000
-#define	BTXIQIMB_D				0xffc00000
-#define	BTXIDCOFFSET				0xff
-#define	BTXIQDCOFFSET				0xff00
-#define	BTXDFIRMODE				0x10000
-#define	BTXPESUDO_NOISEON			0x4000000
-#define	BTXPESUDO_NOISE_A			0xff
-#define	BTXPESUDO_NOISE_B			0xff00
-#define	BTXPESUDO_NOISE_C			0xff0000
-#define	BTXPESUDO_NOISE_D			0xff000000
-#define	BCCA_DROPOPTION				0x20000
-#define	BCCA_DROPTHRES				0xfff00000
-#define	BEDCCA_H				0xf
-#define	BEDCCA_L				0xf0
-#define	BLAMBDA_ED				0x300
-#define	BRX_INITIALGAIN				0x7f
-#define	BRX_ANTDIV_EN				0x80
-#define	BRX_AGC_ADDRESS_FOR_LNA			0x7f00
-#define	BRX_HIGHPOWER_FLOW			0x8000
-#define	BRX_AGC_FREEZE_THRES			0xc0000
-#define	BRX_FREEZESTEP_AGC1			0x300000
-#define	BRX_FREEZESTEP_AGC2			0xc00000
-#define	BRX_FREEZESTEP_AGC3			0x3000000
-#define	BRX_FREEZESTEP_AGC0			0xc000000
-#define	BRXRSSI_CMP_EN				0x10000000
-#define	BRXQUICK_AGCEN				0x20000000
-#define	BRXAGC_FREEZE_THRES_MODE		0x40000000
-#define	BRX_OVERFLOW_CHECKTYPE			0x80000000
-#define	BRX_AGCSHIFT				0x7f
-#define	BTRSW_TRI_ONLY				0x80
-#define	BPOWER_THRES				0x300
-#define	BRXAGC_EN				0x1
-#define	BRXAGC_TOGETHER_EN			0x2
-#define	BRXAGC_MIN				0x4
-#define	BRXHP_INI				0x7
-#define	BRXHP_TRLNA				0x70
-#define	BRXHP_RSSI				0x700
-#define	BRXHP_BBP1				0x7000
-#define	BRXHP_BBP2				0x70000
-#define	BRXHP_BBP3				0x700000
-#define	BRSSI_H					0x7f0000
-#define	BRSSI_GEN				0x7f000000
-#define	BRXSETTLE_TRSW				0x7
-#define	BRXSETTLE_LNA				0x38
-#define	BRXSETTLE_RSSI				0x1c0
-#define	BRXSETTLE_BBP				0xe00
-#define	BRXSETTLE_RXHP				0x7000
-#define	BRXSETTLE_ANTSW_RSSI			0x38000
-#define	BRXSETTLE_ANTSW				0xc0000
-#define	BRXPROCESS_TIME_DAGC			0x300000
-#define	BRXSETTLE_HSSI				0x400000
-#define	BRXPROCESS_TIME_BBPPW			0x800000
-#define	BRXANTENNA_POWER_SHIFT			0x3000000
-#define	BRSSI_TABLE_SELECT			0xc000000
-#define	BRXHP_FINAL				0x7000000
-#define	BRXHPSETTLE_BBP				0x7
-#define	BRXHTSETTLE_HSSI			0x8
-#define	BRXHTSETTLE_RXHP			0x70
-#define	BRXHTSETTLE_BBPPW			0x80
-#define	BRXHTSETTLE_IDLE			0x300
-#define	BRXHTSETTLE_RESERVED			0x1c00
-#define	BRXHT_RXHP_EN				0x8000
-#define	BRXAGC_FREEZE_THRES			0x30000
-#define	BRXAGC_TOGETHEREN			0x40000
-#define	BRXHTAGC_MIN				0x80000
-#define	BRXHTAGC_EN				0x100000
-#define	BRXHTDAGC_EN				0x200000
-#define	BRXHT_RXHP_BBP				0x1c00000
-#define	BRXHT_RXHP_FINAL			0xe0000000
-#define	BRXPW_RADIO_TH				0x3
-#define	BRXPW_RADIO_EN				0x4
-#define	BRXMF_HOLD				0x3800
-#define	BRXPD_DELAY_TH1				0x38
-#define	BRXPD_DELAY_TH2				0x1c0
-#define	BRXPD_DC_COUNT_MAX			0x600
-#define	BRXPD_DELAY_TH				0x8000
-#define	BRXPROCESS_DELAY			0xf0000
-#define	BRXSEARCHRANGE_GI2_EARLY		0x700000
-#define	BRXFRAME_FUARD_COUNTER_L		0x3800000
-#define	BRXSGI_GUARD_L				0xc000000
-#define	BRXSGI_SEARCH_L				0x30000000
-#define	BRXSGI_TH				0xc0000000
-#define	BDFSCNT0				0xff
-#define	BDFSCNT1				0xff00
-#define	BDFSFLAG				0xf0000
-#define	BMF_WEIGHT_SUM				0x300000
-#define	BMINIDX_TH				0x7f000000
-#define	BDAFORMAT				0x40000
-#define	BTXCH_EMU_ENABLE			0x01000000
-#define	BTRSW_ISOLATION_A			0x7f
-#define	BTRSW_ISOLATION_B			0x7f00
-#define	BTRSW_ISOLATION_C			0x7f0000
-#define	BTRSW_ISOLATION_D			0x7f000000
-#define	BEXT_LNA_GAIN				0x7c00
+#define	BNUM_OFSTF			0x3
+#define	BSHIFT_L			0xc0
+#define	BGI_TH				0xc
+#define	BRXPATH_A			0x1
+#define	BRXPATH_B			0x2
+#define	BRXPATH_C			0x4
+#define	BRXPATH_D			0x8
+#define	BTXPATH_A			0x1
+#define	BTXPATH_B			0x2
+#define	BTXPATH_C			0x4
+#define	BTXPATH_D			0x8
+#define	BTRSSI_FREQ			0x200
+#define	BADC_BACKOFF			0x3000
+#define	BDFIR_BACKOFF			0xc000
+#define	BTRSSI_LATCH_PHASE		0x10000
+#define	BRX_LDC_OFFSET			0xff
+#define	BRX_QDC_OFFSET			0xff00
+#define	BRX_DFIR_MODE			0x1800000
+#define	BRX_DCNF_TYPE			0xe000000
+#define	BRXIQIMB_A			0x3ff
+#define	BRXIQIMB_B			0xfc00
+#define	BRXIQIMB_C			0x3f0000
+#define	BRXIQIMB_D			0xffc00000
+#define	BDC_DC_NOTCH			0x60000
+#define	BRXNB_NOTCH			0x1f000000
+#define	BPD_TH				0xf
+#define	BPD_TH_OPT2			0xc000
+#define	BPWED_TH			0x700
+#define	BIFMF_WIN_L			0x800
+#define	BPD_OPTION			0x1000
+#define	BMF_WIN_L			0xe000
+#define	BBW_SEARCH_L			0x30000
+#define	BWIN_ENH_L			0xc0000
+#define	BBW_TH				0x700000
+#define	BED_TH2				0x3800000
+#define	BBW_OPTION			0x4000000
+#define	BRADIO_TH			0x18000000
+#define	BWINDOW_L			0xe0000000
+#define	BSBD_OPTION			0x1
+#define	BFRAME_TH			0x1c
+#define	BFS_OPTION			0x60
+#define	BDC_SLOPE_CHECK			0x80
+#define	BFGUARD_COUNTER_DC_L		0xe00
+#define	BFRAME_WEIGHT_SHORT		0x7000
+#define	BSUB_TUNE			0xe00000
+#define	BFRAME_DC_LENGTH		0xe000000
+#define	BSBD_START_OFFSET		0x30000000
+#define	BFRAME_TH_2			0x7
+#define	BFRAME_GI2_TH			0x38
+#define	BGI2_SYNC_EN			0x40
+#define	BSARCH_SHORT_EARLY		0x300
+#define	BSARCH_SHORT_LATE		0xc00
+#define	BSARCH_GI2_LATE			0x70000
+#define	BCFOANTSUM			0x1
+#define	BCFOACC				0x2
+#define	BCFOSTARTOFFSET			0xc
+#define	BCFOLOOPBACK			0x70
+#define	BCFOSUMWEIGHT			0x80
+#define	BDAGCENABLE			0x10000
+#define	BTXIQIMB_A			0x3ff
+#define	BTXIQIMB_b			0xfc00
+#define	BTXIQIMB_C			0x3f0000
+#define	BTXIQIMB_D			0xffc00000
+#define	BTXIDCOFFSET			0xff
+#define	BTXIQDCOFFSET			0xff00
+#define	BTXDFIRMODE			0x10000
+#define	BTXPESUDO_NOISEON		0x4000000
+#define	BTXPESUDO_NOISE_A		0xff
+#define	BTXPESUDO_NOISE_B		0xff00
+#define	BTXPESUDO_NOISE_C		0xff0000
+#define	BTXPESUDO_NOISE_D		0xff000000
+#define	BCCA_DROPOPTION			0x20000
+#define	BCCA_DROPTHRES			0xfff00000
+#define	BEDCCA_H			0xf
+#define	BEDCCA_L			0xf0
+#define	BLAMBDA_ED			0x300
+#define	BRX_INITIALGAIN			0x7f
+#define	BRX_ANTDIV_EN			0x80
+#define	BRX_AGC_ADDRESS_FOR_LNA     0x7f00
+#define	BRX_HIGHPOWER_FLOW		0x8000
+#define	BRX_AGC_FREEZE_THRES        0xc0000
+#define	BRX_FREEZESTEP_AGC1		0x300000
+#define	BRX_FREEZESTEP_AGC2		0xc00000
+#define	BRX_FREEZESTEP_AGC3		0x3000000
+#define	BRX_FREEZESTEP_AGC0		0xc000000
+#define	BRXRSSI_CMP_EN			0x10000000
+#define	BRXQUICK_AGCEN			0x20000000
+#define	BRXAGC_FREEZE_THRES_MODE    0x40000000
+#define	BRX_OVERFLOW_CHECKTYPE		0x80000000
+#define	BRX_AGCSHIFT			0x7f
+#define	BTRSW_TRI_ONLY			0x80
+#define	BPOWER_THRES			0x300
+#define	BRXAGC_EN			0x1
+#define	BRXAGC_TOGETHER_EN		0x2
+#define	BRXAGC_MIN			0x4
+#define	BRXHP_INI			0x7
+#define	BRXHP_TRLNA			0x70
+#define	BRXHP_RSSI			0x700
+#define	BRXHP_BBP1			0x7000
+#define	BRXHP_BBP2			0x70000
+#define	BRXHP_BBP3			0x700000
+#define	BRSSI_H				0x7f0000
+#define	BRSSI_GEN			0x7f000000
+#define	BRXSETTLE_TRSW			0x7
+#define	BRXSETTLE_LNA			0x38
+#define	BRXSETTLE_RSSI			0x1c0
+#define	BRXSETTLE_BBP			0xe00
+#define	BRXSETTLE_RXHP			0x7000
+#define	BRXSETTLE_ANTSW_RSSI		0x38000
+#define	BRXSETTLE_ANTSW			0xc0000
+#define	BRXPROCESS_TIME_DAGC		0x300000
+#define	BRXSETTLE_HSSI			0x400000
+#define	BRXPROCESS_TIME_BBPPW		0x800000
+#define	BRXANTENNA_POWER_SHIFT		0x3000000
+#define	BRSSI_TABLE_SELECT		0xc000000
+#define	BRXHP_FINAL			0x7000000
+#define	BRXHPSETTLE_BBP			0x7
+#define	BRXHTSETTLE_HSSI		0x8
+#define	BRXHTSETTLE_RXHP		0x70
+#define	BRXHTSETTLE_BBPPW		0x80
+#define	BRXHTSETTLE_IDLE		0x300
+#define	BRXHTSETTLE_RESERVED		0x1c00
+#define	BRXHT_RXHP_EN			0x8000
+#define	BRXAGC_FREEZE_THRES		0x30000
+#define	BRXAGC_TOGETHEREN		0x40000
+#define	BRXHTAGC_MIN			0x80000
+#define	BRXHTAGC_EN			0x100000
+#define	BRXHTDAGC_EN			0x200000
+#define	BRXHT_RXHP_BBP			0x1c00000
+#define	BRXHT_RXHP_FINAL		0xe0000000
+#define	BRXPW_RADIO_TH			0x3
+#define	BRXPW_RADIO_EN			0x4
+#define	BRXMF_HOLD			0x3800
+#define	BRXPD_DELAY_TH1			0x38
+#define	BRXPD_DELAY_TH2			0x1c0
+#define	BRXPD_DC_COUNT_MAX		0x600
+#define	BRXPD_DELAY_TH			0x8000
+#define	BRXPROCESS_DELAY		0xf0000
+#define	BRXSEARCHRANGE_GI2_EARLY	0x700000
+#define	BRXFRAME_FUARD_COUNTER_L	0x3800000
+#define	BRXSGI_GUARD_L			0xc000000
+#define	BRXSGI_SEARCH_L			0x30000000
+#define	BRXSGI_TH			0xc0000000
+#define	BDFSCNT0			0xff
+#define	BDFSCNT1			0xff00
+#define	BDFSFLAG			0xf0000
+#define	BMF_WEIGHT_SUM			0x300000
+#define	BMINIDX_TH			0x7f000000
+#define	BDAFORMAT			0x40000
+#define	BTXCH_EMU_ENABLE		0x01000000
+#define	BTRSW_ISOLATION_A		0x7f
+#define	BTRSW_ISOLATION_B		0x7f00
+#define	BTRSW_ISOLATION_C		0x7f0000
+#define	BTRSW_ISOLATION_D		0x7f000000
+#define	BEXT_LNA_GAIN			0x7c00
 
-#define	BSTBC_EN				0x4
-#define	BANTENNA_MAPPING			0x10
-#define	BNSS					0x20
-#define	BCFO_ANTSUM_ID				0x200
-#define	BPHY_COUNTER_RESET			0x8000000
-#define	BCFO_REPORT_GET				0x4000000
-#define	BOFDM_CONTINUE_TX			0x10000000
-#define	BOFDM_SINGLE_CARRIER			0x20000000
-#define	BOFDM_SINGLE_TONE			0x40000000
-#define	BHT_DETECT				0x100
-#define	BCFOEN					0x10000
-#define	BCFOVALUE				0xfff00000
-#define	BSIGTONE_RE				0x3f
-#define	BSIGTONE_IM				0x7f00
-#define	BCOUNTER_CCA				0xffff
-#define	BCOUNTER_PARITYFAIL			0xffff0000
-#define	BCOUNTER_RATEILLEGAL			0xffff
-#define	BCOUNTER_CRC8FAIL			0xffff0000
-#define	BCOUNTER_MCSNOSUPPORT			0xffff
-#define	BCOUNTER_FASTSYNC			0xffff
-#define	BSHORTCFO				0xfff
-#define	BSHORTCFOT_LENGTH			12
-#define	BSHORTCFOF_LENGTH			11
-#define	BLONGCFO				0x7ff
-#define	BLONGCFOT_LENGTH			11
-#define	BLONGCFOF_LENGTH			11
-#define	BTAILCFO				0x1fff
-#define	BTAILCFOT_LENGTH			13
-#define	BTAILCFOF_LENGTH			12
-#define	BNOISE_EN_PWDB				0xffff
-#define	BCC_POWER_DB				0xffff0000
-#define	BMOISE_PWDB				0xffff
-#define	BPOWERMEAST_LENGTH			10
-#define	BPOWERMEASF_LENGTH			3
-#define	BRX_HT_BW				0x1
-#define	BRXSC					0x6
-#define	BRX_HT					0x8
-#define	BNB_INTF_DET_ON				0x1
-#define	BINTF_WIN_LEN_CFG			0x30
-#define	BNB_INTF_TH_CFG				0x1c0
-#define	BRFGAIN					0x3f
-#define	BTABLESEL				0x40
-#define	BTRSW					0x80
-#define	BRXSNR_A				0xff
-#define	BRXSNR_B				0xff00
-#define	BRXSNR_C				0xff0000
-#define	BRXSNR_D				0xff000000
-#define	BSNR_EVMT_LENGTH			8
-#define	BSNR_EVMF_LENGTH			1
-#define	BCSI1ST					0xff
-#define	BCSI2ND					0xff00
-#define	BRXEVM1ST				0xff0000
-#define	BRXEVM2ND				0xff000000
-#define	BSIGEVM					0xff
-#define	BPWDB					0xff00
-#define	BSGIEN					0x10000
+#define	BSTBC_EN			0x4
+#define	BANTENNA_MAPPING		0x10
+#define	BNSS				0x20
+#define	BCFO_ANTSUM_ID              0x200
+#define	BPHY_COUNTER_RESET		0x8000000
+#define	BCFO_REPORT_GET			0x4000000
+#define	BOFDM_CONTINUE_TX		0x10000000
+#define	BOFDM_SINGLE_CARRIER		0x20000000
+#define	BOFDM_SINGLE_TONE		0x40000000
+#define	BHT_DETECT			0x100
+#define	BCFOEN				0x10000
+#define	BCFOVALUE			0xfff00000
+#define	BSIGTONE_RE			0x3f
+#define	BSIGTONE_IM			0x7f00
+#define	BCOUNTER_CCA			0xffff
+#define	BCOUNTER_PARITYFAIL		0xffff0000
+#define	BCOUNTER_RATEILLEGAL		0xffff
+#define	BCOUNTER_CRC8FAIL		0xffff0000
+#define	BCOUNTER_MCSNOSUPPORT		0xffff
+#define	BCOUNTER_FASTSYNC		0xffff
+#define	BSHORTCFO			0xfff
+#define	BSHORTCFOT_LENGTH		12
+#define	BSHORTCFOF_LENGTH		11
+#define	BLONGCFO			0x7ff
+#define	BLONGCFOT_LENGTH		11
+#define	BLONGCFOF_LENGTH		11
+#define	BTAILCFO			0x1fff
+#define	BTAILCFOT_LENGTH		13
+#define	BTAILCFOF_LENGTH		12
+#define	BNOISE_EN_PWDB			0xffff
+#define	BCC_POWER_DB			0xffff0000
+#define	BMOISE_PWDB			0xffff
+#define	BPOWERMEAST_LENGTH		10
+#define	BPOWERMEASF_LENGTH		3
+#define	BRX_HT_BW			0x1
+#define	BRXSC				0x6
+#define	BRX_HT				0x8
+#define	BNB_INTF_DET_ON			0x1
+#define	BINTF_WIN_LEN_CFG		0x30
+#define	BNB_INTF_TH_CFG			0x1c0
+#define	BRFGAIN				0x3f
+#define	BTABLESEL			0x40
+#define	BTRSW				0x80
+#define	BRXSNR_A			0xff
+#define	BRXSNR_B			0xff00
+#define	BRXSNR_C			0xff0000
+#define	BRXSNR_D			0xff000000
+#define	BSNR_EVMT_LENGTH		8
+#define	BSNR_EVMF_LENGTH		1
+#define	BCSI1ST				0xff
+#define	BCSI2ND				0xff00
+#define	BRXEVM1ST			0xff0000
+#define	BRXEVM2ND			0xff000000
+#define	BSIGEVM				0xff
+#define	BPWDB				0xff00
+#define	BSGIEN				0x10000
 
-#define	BSFACTOR_QMA1				0xf
-#define	BSFACTOR_QMA2				0xf0
-#define	BSFACTOR_QMA3				0xf00
-#define	BSFACTOR_QMA4				0xf000
-#define	BSFACTOR_QMA5				0xf0000
-#define	BSFACTOR_QMA6				0xf0000
-#define	BSFACTOR_QMA7				0xf00000
-#define	BSFACTOR_QMA8				0xf000000
-#define	BSFACTOR_QMA9				0xf0000000
-#define	BCSI_SCHEME				0x100000
+#define	BSFACTOR_QMA1			0xf
+#define	BSFACTOR_QMA2			0xf0
+#define	BSFACTOR_QMA3			0xf00
+#define	BSFACTOR_QMA4			0xf000
+#define	BSFACTOR_QMA5			0xf0000
+#define	BSFACTOR_QMA6			0xf0000
+#define	BSFACTOR_QMA7			0xf00000
+#define	BSFACTOR_QMA8			0xf000000
+#define	BSFACTOR_QMA9			0xf0000000
+#define	BCSI_SCHEME			0x100000
 
-#define	BNOISE_LVL_TOP_SET			0x3
-#define	BCHSMOOTH				0x4
-#define	BCHSMOOTH_CFG1				0x38
-#define	BCHSMOOTH_CFG2				0x1c0
-#define	BCHSMOOTH_CFG3				0xe00
-#define	BCHSMOOTH_CFG4				0x7000
-#define	BMRCMODE				0x800000
-#define	BTHEVMCFG				0x7000000
+#define	BNOISE_LVL_TOP_SET          0x3
+#define	BCHSMOOTH			0x4
+#define	BCHSMOOTH_CFG1			0x38
+#define	BCHSMOOTH_CFG2			0x1c0
+#define	BCHSMOOTH_CFG3			0xe00
+#define	BCHSMOOTH_CFG4			0x7000
+#define	BMRCMODE			0x800000
+#define	BTHEVMCFG			0x7000000
 
-#define	BLOOP_FIT_TYPE				0x1
-#define	BUPD_CFO				0x40
-#define	BUPD_CFO_OFFDATA			0x80
-#define	BADV_UPD_CFO				0x100
-#define	BADV_TIME_CTRL				0x800
-#define	BUPD_CLKO				0x1000
-#define	BFC					0x6000
-#define	BTRACKING_MODE				0x8000
-#define	BPHCMP_ENABLE				0x10000
-#define	BUPD_CLKO_LTF				0x20000
-#define	BCOM_CH_CFO				0x40000
-#define	BCSI_ESTI_MODE				0x80000
-#define	BADV_UPD_EQZ				0x100000
-#define	BUCHCFG					0x7000000
-#define	BUPDEQZ					0x8000000
+#define	BLOOP_FIT_TYPE			0x1
+#define	BUPD_CFO			0x40
+#define	BUPD_CFO_OFFDATA		0x80
+#define	BADV_UPD_CFO			0x100
+#define	BADV_TIME_CTRL			0x800
+#define	BUPD_CLKO			0x1000
+#define	BFC				0x6000
+#define	BTRACKING_MODE			0x8000
+#define	BPHCMP_ENABLE			0x10000
+#define	BUPD_CLKO_LTF			0x20000
+#define	BCOM_CH_CFO			0x40000
+#define	BCSI_ESTI_MODE			0x80000
+#define	BADV_UPD_EQZ			0x100000
+#define	BUCHCFG				0x7000000
+#define	BUPDEQZ				0x8000000
 
-#define	BRX_PESUDO_NOISE_ON			0x20000000
-#define	BRX_PESUDO_NOISE_A			0xff
-#define	BRX_PESUDO_NOISE_B			0xff00
-#define	BRX_PESUDO_NOISE_C			0xff0000
-#define	BRX_PESUDO_NOISE_D			0xff000000
-#define	BRX_PESUDO_NOISESTATE_A			0xffff
-#define	BRX_PESUDO_NOISESTATE_B			0xffff0000
-#define	BRX_PESUDO_NOISESTATE_C			0xffff
-#define	BRX_PESUDO_NOISESTATE_D			0xffff0000
+#define	BRX_PESUDO_NOISE_ON         0x20000000
+#define	BRX_PESUDO_NOISE_A		0xff
+#define	BRX_PESUDO_NOISE_B		0xff00
+#define	BRX_PESUDO_NOISE_C		0xff0000
+#define	BRX_PESUDO_NOISE_D		0xff000000
+#define	BRX_PESUDO_NOISESTATE_A     0xffff
+#define	BRX_PESUDO_NOISESTATE_B     0xffff0000
+#define	BRX_PESUDO_NOISESTATE_C     0xffff
+#define	BRX_PESUDO_NOISESTATE_D     0xffff0000
 
-#define	BZEBRA1_HSSIENABLE			0x8
-#define	BZEBRA1_TRXCONTROL			0xc00
-#define	BZEBRA1_TRXGAINSETTING			0x07f
-#define	BZEBRA1_RXCOUNTER			0xc00
-#define	BZEBRA1_TXCHANGEPUMP			0x38
-#define	BZEBRA1_RXCHANGEPUMP			0x7
-#define	BZEBRA1_CHANNEL_NUM			0xf80
-#define	BZEBRA1_TXLPFBW				0x400
-#define	BZEBRA1_RXLPFBW				0x600
+#define	BZEBRA1_HSSIENABLE		0x8
+#define	BZEBRA1_TRXCONTROL		0xc00
+#define	BZEBRA1_TRXGAINSETTING		0x07f
+#define	BZEBRA1_RXCOUNTER		0xc00
+#define	BZEBRA1_TXCHANGEPUMP		0x38
+#define	BZEBRA1_RXCHANGEPUMP		0x7
+#define	BZEBRA1_CHANNEL_NUM		0xf80
+#define	BZEBRA1_TXLPFBW			0x400
+#define	BZEBRA1_RXLPFBW			0x600
 
-#define	BRTL8256REG_MODE_CTRL1			0x100
-#define	BRTL8256REG_MODE_CTRL0			0x40
-#define	BRTL8256REG_TXLPFBW			0x18
-#define	BRTL8256REG_RXLPFBW			0x600
+#define	BRTL8256REG_MODE_CTRL1      0x100
+#define	BRTL8256REG_MODE_CTRL0      0x40
+#define	BRTL8256REG_TXLPFBW         0x18
+#define	BRTL8256REG_RXLPFBW         0x600
 
-#define	BRTL8258_TXLPFBW			0xc
-#define	BRTL8258_RXLPFBW			0xc00
-#define	BRTL8258_RSSILPFBW			0xc0
+#define	BRTL8258_TXLPFBW		0xc
+#define	BRTL8258_RXLPFBW		0xc00
+#define	BRTL8258_RSSILPFBW		0xc0
 
-#define	BBYTE0					0x1
-#define	BBYTE1					0x2
-#define	BBYTE2					0x4
-#define	BBYTE3					0x8
-#define	BWORD0					0x3
-#define	BWORD1					0xc
-#define	BWORD					0xf
+#define	BBYTE0				0x1
+#define	BBYTE1				0x2
+#define	BBYTE2				0x4
+#define	BBYTE3				0x8
+#define	BWORD0				0x3
+#define	BWORD1				0xc
+#define	BWORD				0xf
 
-#define	BENABLE					0x1
-#define	BDISABLE				0x0
+#define	MASKBYTE0			0xff
+#define	MASKBYTE1			0xff00
+#define	MASKBYTE2			0xff0000
+#define	MASKBYTE3			0xff000000
+#define	MASKHWORD			0xffff0000
+#define	MASKLWORD			0x0000ffff
+#define	MASKDWORD					0xffffffff
+#define	MASK12BITS					0xfff
+#define	MASKH4BITS					0xf0000000
+#define MASKOFDM_D					0xffc00000
+#define	MASKCCK						0x3f3f3f3f
 
-#define	LEFT_ANTENNA				0x0
-#define	RIGHT_ANTENNA				0x1
+#define	MASK4BITS			0x0f
+#define	MASK20BITS			0xfffff
+#define RFREG_OFFSET_MASK			0xfffff
 
-#define	TCHECK_TXSTATUS				500
-#define	TUPDATE_RXCOUNTER			100
+#define	BENABLE				0x1
+#define	BDISABLE			0x0
+
+#define	LEFT_ANTENNA			0x0
+#define	RIGHT_ANTENNA			0x1
+
+#define	TCHECK_TXSTATUS			500
+#define	TUPDATE_RXCOUNTER		100
 
 /* 2 EFUSE_TEST (For RTL8723 partially) */
-#define EFUSE_SEL(x)				(((x) & 0x3) << 8)
+#define EFUSE_SEL(x)					(((x) & 0x3) << 8)
 #define EFUSE_SEL_MASK				0x300
-#define EFUSE_WIFI_SEL_0			0x0
-
+#define EFUSE_WIFI_SEL_0				0x0
 /* Enable GPIO[9] as WiFi HW PDn source*/
-#define	WL_HWPDN_EN				BIT(0)
+#define	WL_HWPDN_EN					BIT(0)
 /* WiFi HW PDn polarity control*/
-#define	WL_HWPDN_SL				BIT(1)
+#define	WL_HWPDN_SL					BIT(1)
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/rf.c b/drivers/net/wireless/rtlwifi/rtl8723ae/rf.c
index 50dd2fb..9ebc828 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/rf.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -34,10 +30,12 @@
 #include "rf.h"
 #include "dm.h"
 
-void rtl8723ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+static bool _rtl8723e_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
+
+void rtl8723e_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 
 	switch (bandwidth) {
 	case HT_CHANNEL_WIDTH_20:
@@ -59,11 +57,11 @@
 	}
 }
 
-void rtl8723ae_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
-					  u8 *ppowerlevel)
+void rtl8723e_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+					 u8 *ppowerlevel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	u32 tx_agc[2] = {0, 0}, tmpval;
@@ -79,7 +77,8 @@
 		tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
 
 		if (turbo_scanoff) {
-			for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+			for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B;
+				idx1++) {
 				tx_agc[idx1] = ppowerlevel[idx1] |
 				    (ppowerlevel[idx1] << 8) |
 				    (ppowerlevel[idx1] << 16) |
@@ -89,24 +88,27 @@
 	} else {
 		for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
 			tx_agc[idx1] = ppowerlevel[idx1] |
-				       (ppowerlevel[idx1] << 8) |
-				       (ppowerlevel[idx1] << 16) |
-				       (ppowerlevel[idx1] << 24);
+			    (ppowerlevel[idx1] << 8) |
+			    (ppowerlevel[idx1] << 16) |
+			    (ppowerlevel[idx1] << 24);
 		}
 
 		if (rtlefuse->eeprom_regulatory == 0) {
-			tmpval = (rtlphy->mcs_offset[0][6]) +
-				(rtlphy->mcs_offset[0][7] << 8);
+			tmpval =
+			    (rtlphy->mcs_txpwrlevel_origoffset[0][6]) +
+			    (rtlphy->mcs_txpwrlevel_origoffset[0][7] <<
+			     8);
 			tx_agc[RF90_PATH_A] += tmpval;
 
-			tmpval = (rtlphy->mcs_offset[0][14]) +
-			    (rtlphy->mcs_offset[0][15] << 24);
+			tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) +
+			    (rtlphy->mcs_txpwrlevel_origoffset[0][15] <<
+			     24);
 			tx_agc[RF90_PATH_B] += tmpval;
 		}
 	}
 
 	for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
-		ptr = (u8 *) (&(tx_agc[idx1]));
+		ptr = (u8 *)&tx_agc[idx1];
 		for (idx2 = 0; idx2 < 4; idx2++) {
 			if (*ptr > RF6052_MAX_TX_PWR)
 				*ptr = RF6052_MAX_TX_PWR;
@@ -119,7 +121,7 @@
 
 	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 		"CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
-		RTXAGC_A_CCK1_MCS32);
+		 RTXAGC_A_CCK1_MCS32);
 
 	tmpval = tx_agc[RF90_PATH_A] >> 8;
 
@@ -129,100 +131,99 @@
 
 	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 		"CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
-		RTXAGC_B_CCK11_A_CCK2_11);
+		 RTXAGC_B_CCK11_A_CCK2_11);
 
 	tmpval = tx_agc[RF90_PATH_B] >> 24;
 	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);
 
 	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 		"CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
-		RTXAGC_B_CCK11_A_CCK2_11);
+		 RTXAGC_B_CCK11_A_CCK2_11);
 
 	tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff;
 	rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval);
 
 	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 		"CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
-		RTXAGC_B_CCK1_55_MCS32);
+		 RTXAGC_B_CCK1_55_MCS32);
 }
 
-static void rtl8723ae_phy_get_power_base(struct ieee80211_hw *hw,
-					 u8 *ppowerlevel, u8 channel,
-					 u32 *ofdmbase, u32 *mcsbase)
+static void rtl8723e_phy_get_power_base(struct ieee80211_hw *hw,
+					u8 *ppowerlevel, u8 channel,
+					u32 *ofdmbase, u32 *mcsbase)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
-	u32 powerBase0, powerBase1;
+	u32 powerbase0, powerbase1;
 	u8 legacy_pwrdiff, ht20_pwrdiff;
 	u8 i, powerlevel[2];
 
 	for (i = 0; i < 2; i++) {
 		powerlevel[i] = ppowerlevel[i];
 		legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1];
-		powerBase0 = powerlevel[i] + legacy_pwrdiff;
+		powerbase0 = powerlevel[i] + legacy_pwrdiff;
 
-		powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) |
-		    (powerBase0 << 8) | powerBase0;
-		*(ofdmbase + i) = powerBase0;
+		powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) |
+		    (powerbase0 << 8) | powerbase0;
+		*(ofdmbase + i) = powerbase0;
 		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 			" [OFDM power base index rf(%c) = 0x%x]\n",
-			((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
+			 ((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
 	}
 
 	for (i = 0; i < 2; i++) {
 		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {
-			ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1];
+			ht20_pwrdiff =
+				rtlefuse->txpwr_ht20diff[i][channel - 1];
 			powerlevel[i] += ht20_pwrdiff;
 		}
-		powerBase1 = powerlevel[i];
-		powerBase1 = (powerBase1 << 24) |
-		    (powerBase1 << 16) | (powerBase1 << 8) | powerBase1;
+		powerbase1 = powerlevel[i];
+		powerbase1 = (powerbase1 << 24) |
+		    (powerbase1 << 16) | (powerbase1 << 8) | powerbase1;
 
-		*(mcsbase + i) = powerBase1;
+		*(mcsbase + i) = powerbase1;
 
 		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 			" [MCS power base index rf(%c) = 0x%x]\n",
-			((i == 0) ? 'A' : 'B'), *(mcsbase + i));
+			 ((i == 0) ? 'A' : 'B'), *(mcsbase + i));
 	}
 }
 
-static void rtl8723ae_get_txpwr_val_by_reg(struct ieee80211_hw *hw,
-					   u8 channel, u8 index,
-					   u32 *powerBase0,
-					   u32 *powerBase1,
-					   u32 *p_outwriteval)
+static void get_txpower_writeval_by_reg(struct ieee80211_hw *hw,
+					u8 channel, u8 index,
+					u32 *powerbase0,
+					u32 *powerbase1,
+					u32 *p_outwriteval)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	u8 i, chnlgroup = 0, pwr_diff_limit[4];
-	u32 writeVal, customer_limit, rf;
+	u32 writeval, customer_limit, rf;
 
 	for (rf = 0; rf < 2; rf++) {
 		switch (rtlefuse->eeprom_regulatory) {
 		case 0:
 			chnlgroup = 0;
 
-			writeVal = rtlphy->mcs_offset[chnlgroup]
-				   [index + (rf ? 8 : 0)] +
-				   ((index < 2) ? powerBase0[rf] :
-				   powerBase1[rf]);
+			writeval =
+			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index +
+								(rf ? 8 : 0)]
+			    + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 
 			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
-				"RTK better performance, "
-				"writeVal(%c) = 0x%x\n",
-				((rf == 0) ? 'A' : 'B'), writeVal);
+				"RTK better performance, writeval(%c) = 0x%x\n",
+				((rf == 0) ? 'A' : 'B'), writeval);
 			break;
 		case 1:
 			if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
-				writeVal = ((index < 2) ? powerBase0[rf] :
-					    powerBase1[rf]);
+				writeval = ((index < 2) ? powerbase0[rf] :
+					    powerbase1[rf]);
 
 				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
-					"Realtek regulatory, 40MHz, "
-					"writeVal(%c) = 0x%x\n",
-					((rf == 0) ? 'A' : 'B'), writeVal);
+					"Realtek regulatory, 40MHz, writeval(%c) = 0x%x\n",
+					((rf == 0) ? 'A' : 'B'), writeval);
 			} else {
 				if (rtlphy->pwrgroup_cnt == 1)
 					chnlgroup = 0;
@@ -234,29 +235,30 @@
 					else if (channel > 9)
 						chnlgroup = 2;
 					if (rtlphy->current_chan_bw ==
-					    HT_CHANNEL_WIDTH_20)
+						HT_CHANNEL_WIDTH_20)
 						chnlgroup++;
 					else
 						chnlgroup += 4;
 				}
 
-				writeVal = rtlphy->mcs_offset[chnlgroup]
+				writeval =
+				    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
 				    [index + (rf ? 8 : 0)] + ((index < 2) ?
-							      powerBase0[rf] :
-							      powerBase1[rf]);
+							      powerbase0[rf] :
+							      powerbase1[rf]);
 
 				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
-					"Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n",
-					((rf == 0) ? 'A' : 'B'), writeVal);
+					"Realtek regulatory, 20MHz, writeval(%c) = 0x%x\n",
+					((rf == 0) ? 'A' : 'B'), writeval);
 			}
 			break;
 		case 2:
-			writeVal =
-			    ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+			writeval =
+			    ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 
 			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
-				"Better regulatory, writeVal(%c) = 0x%x\n",
-				((rf == 0) ? 'A' : 'B'), writeVal);
+				"Better regulatory, writeval(%c) = 0x%x\n",
+				((rf == 0) ? 'A' : 'B'), writeval);
 			break;
 		case 3:
 			chnlgroup = 0;
@@ -265,18 +267,21 @@
 				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 					"customer's limit, 40MHz rf(%c) = 0x%x\n",
 					((rf == 0) ? 'A' : 'B'),
-					rtlefuse->pwrgroup_ht40[rf][channel-1]);
+					rtlefuse->pwrgroup_ht40[rf][channel -
+								     1]);
 			} else {
 				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 					"customer's limit, 20MHz rf(%c) = 0x%x\n",
 					((rf == 0) ? 'A' : 'B'),
-					rtlefuse->pwrgroup_ht20[rf][channel-1]);
+					rtlefuse->pwrgroup_ht20[rf][channel -
+								     1]);
 			}
 			for (i = 0; i < 4; i++) {
 				pwr_diff_limit[i] =
-					(u8) ((rtlphy->mcs_offset
-					[chnlgroup][index + (rf ? 8 : 0)] &
-					(0x7f << (i * 8))) >> (i * 8));
+				    (u8)((rtlphy->mcs_txpwrlevel_origoffset
+					  [chnlgroup][index +
+						(rf ? 8 : 0)] & (0x7f <<
+						(i * 8))) >> (i * 8));
 
 				if (rtlphy->current_chan_bw ==
 				    HT_CHANNEL_WIDTH_20_40) {
@@ -302,41 +307,42 @@
 
 			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 				"Customer's limit rf(%c) = 0x%x\n",
-				((rf == 0) ? 'A' : 'B'), customer_limit);
+				 ((rf == 0) ? 'A' : 'B'), customer_limit);
 
-			writeVal = customer_limit +
-			    ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+			writeval = customer_limit +
+			    ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 
 			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
-				"Customer, writeVal rf(%c)= 0x%x\n",
-				((rf == 0) ? 'A' : 'B'), writeVal);
+				"Customer, writeval rf(%c)= 0x%x\n",
+				 ((rf == 0) ? 'A' : 'B'), writeval);
 			break;
 		default:
 			chnlgroup = 0;
-			writeVal = rtlphy->mcs_offset[chnlgroup][index +
-			    (rf ? 8 : 0)] + ((index < 2) ? powerBase0[rf] :
-			    powerBase1[rf]);
+			writeval =
+			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
+			    [index + (rf ? 8 : 0)]
+			    + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 
 			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
-				"RTK better performance, writeVal rf(%c) = 0x%x\n",
-				((rf == 0) ? 'A' : 'B'), writeVal);
+				"RTK better performance, writeval rf(%c) = 0x%x\n",
+				((rf == 0) ? 'A' : 'B'), writeval);
 			break;
 		}
 
 		if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
-			writeVal = writeVal - 0x06060606;
+			writeval = writeval - 0x06060606;
 		else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
 			 TXHIGHPWRLEVEL_BT2)
-			writeVal = writeVal - 0x0c0c0c0c;
-		*(p_outwriteval + rf) = writeVal;
+			writeval = writeval - 0x0c0c0c0c;
+		*(p_outwriteval + rf) = writeval;
 	}
 }
 
-static void _rtl8723ae_write_ofdm_power_reg(struct ieee80211_hw *hw,
-					    u8 index, u32 *pValue)
+static void _rtl8723e_write_ofdm_power_reg(struct ieee80211_hw *hw,
+					   u8 index, u32 *pvalue)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 
 	u16 regoffset_a[6] = {
 		RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24,
@@ -349,29 +355,29 @@
 		RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12
 	};
 	u8 i, rf, pwr_val[4];
-	u32 writeVal;
+	u32 writeval;
 	u16 regoffset;
 
 	for (rf = 0; rf < 2; rf++) {
-		writeVal = pValue[rf];
+		writeval = pvalue[rf];
 		for (i = 0; i < 4; i++) {
-			pwr_val[i] = (u8) ((writeVal & (0x7f <<
-							(i * 8))) >> (i * 8));
+			pwr_val[i] = (u8)((writeval & (0x7f <<
+					   (i * 8))) >> (i * 8));
 
 			if (pwr_val[i] > RF6052_MAX_TX_PWR)
 				pwr_val[i] = RF6052_MAX_TX_PWR;
 		}
-		writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
+		writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
 		    (pwr_val[1] << 8) | pwr_val[0];
 
 		if (rf == 0)
 			regoffset = regoffset_a[index];
 		else
 			regoffset = regoffset_b[index];
-		rtl_set_bbreg(hw, regoffset, MASKDWORD, writeVal);
+		rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);
 
 		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
-			"Set 0x%x = %08x\n", regoffset, writeVal);
+			"Set 0x%x = %08x\n", regoffset, writeval);
 
 		if (((get_rf_type(rtlphy) == RF_2T2R) &&
 		     (regoffset == RTXAGC_A_MCS15_MCS12 ||
@@ -380,7 +386,7 @@
 		     (regoffset == RTXAGC_A_MCS07_MCS04 ||
 		      regoffset == RTXAGC_B_MCS07_MCS04))) {
 
-			writeVal = pwr_val[3];
+			writeval = pwr_val[3];
 			if (regoffset == RTXAGC_A_MCS15_MCS12 ||
 			    regoffset == RTXAGC_A_MCS07_MCS04)
 				regoffset = 0xc90;
@@ -389,37 +395,49 @@
 				regoffset = 0xc98;
 
 			for (i = 0; i < 3; i++) {
-				writeVal = (writeVal > 6) ? (writeVal - 6) : 0;
+				writeval = (writeval > 6) ? (writeval - 6) : 0;
 				rtl_write_byte(rtlpriv, (u32) (regoffset + i),
-					       (u8) writeVal);
+					       (u8)writeval);
 			}
 		}
 	}
 }
 
-void rtl8723ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
-					   u8 *ppowerlevel, u8 channel)
+void rtl8723e_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+					  u8 *ppowerlevel, u8 channel)
 {
-	u32 writeVal[2], powerBase0[2], powerBase1[2];
+	u32 writeval[2], powerbase0[2], powerbase1[2];
 	u8 index;
 
-	rtl8723ae_phy_get_power_base(hw, ppowerlevel,
-				  channel, &powerBase0[0], &powerBase1[0]);
+	rtl8723e_phy_get_power_base(hw, ppowerlevel,
+				    channel, &powerbase0[0], &powerbase1[0]);
 
 	for (index = 0; index < 6; index++) {
-		rtl8723ae_get_txpwr_val_by_reg(hw, channel, index,
-					      &powerBase0[0],
-					      &powerBase1[0],
-					      &writeVal[0]);
+		get_txpower_writeval_by_reg(hw, channel, index, &powerbase0[0],
+					    &powerbase1[0],
+					    &writeval[0]);
 
-		_rtl8723ae_write_ofdm_power_reg(hw, index, &writeVal[0]);
+		_rtl8723e_write_ofdm_power_reg(hw, index, &writeval[0]);
 	}
 }
 
-static bool _rtl8723ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
+bool rtl8723e_phy_rf6052_config(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	if (rtlphy->rf_type == RF_1T1R)
+		rtlphy->num_total_rfpath = 1;
+	else
+		rtlphy->num_total_rfpath = 2;
+
+	return _rtl8723e_phy_rf6052_config_parafile(hw);
+}
+
+static bool _rtl8723e_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	u32 u4_regvalue = 0;
 	u8 rfpath;
 	bool rtstatus = true;
@@ -457,11 +475,12 @@
 
 		switch (rfpath) {
 		case RF90_PATH_A:
-			rtstatus = rtl8723ae_phy_config_rf_with_headerfile(hw,
+			rtstatus = rtl8723e_phy_config_rf_with_headerfile(hw,
 						(enum radio_path)rfpath);
 			break;
 		case RF90_PATH_B:
-			rtstatus = rtl8723ae_phy_config_rf_with_headerfile(hw,
+			rtstatus =
+			  rtl8723e_phy_config_rf_with_headerfile(hw,
 						(enum radio_path)rfpath);
 			break;
 		case RF90_PATH_C:
@@ -469,6 +488,7 @@
 		case RF90_PATH_D:
 			break;
 		}
+
 		switch (rfpath) {
 		case RF90_PATH_A:
 		case RF90_PATH_C:
@@ -481,25 +501,14 @@
 				      BRFSI_RFENV << 16, u4_regvalue);
 			break;
 		}
+
 		if (rtstatus != true) {
 			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 				 "Radio[%d] Fail!!", rfpath);
 			return false;
 		}
 	}
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n");
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
 	return rtstatus;
 }
-
-bool rtl8723ae_phy_rf6052_config(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-
-	if (rtlphy->rf_type == RF_1T1R)
-		rtlphy->num_total_rfpath = 1;
-	else
-		rtlphy->num_total_rfpath = 2;
-
-	return _rtl8723ae_phy_rf6052_config_parafile(hw);
-}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/rf.h b/drivers/net/wireless/rtlwifi/rtl8723ae/rf.h
index 57f1933..f3f45b1 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/rf.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/rf.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -31,12 +27,14 @@
 #define __RTL8723E_RF_H__
 
 #define RF6052_MAX_TX_PWR		0x3F
+#define RF6052_MAX_REG			0x3F
 
-void rtl8723ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth);
-void rtl8723ae_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
-					  u8 *ppowerlevel);
-void rtl8723ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
-					   u8 *ppowerlevel, u8 channel);
-bool rtl8723ae_phy_rf6052_config(struct ieee80211_hw *hw);
+void rtl8723e_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+				       u8 bandwidth);
+void rtl8723e_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+					 u8 *ppowerlevel);
+void rtl8723e_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+					  u8 *ppowerlevel, u8 channel);
+bool rtl8723e_phy_rf6052_config(struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
index 73cba1e..8280bab 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -28,34 +24,35 @@
  *****************************************************************************/
 
 #include "../wifi.h"
-#include <linux/vmalloc.h>
-#include <linux/module.h>
-
 #include "../core.h"
 #include "../pci.h"
-#include "../base.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
-#include "../rtl8723com/phy_common.h"
 #include "dm.h"
-#include "hw.h"
 #include "fw.h"
 #include "../rtl8723com/fw_common.h"
+#include "hw.h"
 #include "sw.h"
 #include "trx.h"
 #include "led.h"
 #include "table.h"
 #include "hal_btc.h"
+#include "../btcoexist/rtl_btc.h"
+#include "../rtl8723com/phy_common.h"
 
-static void rtl8723ae_init_aspm_vars(struct ieee80211_hw *hw)
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+
+static void rtl8723e_init_aspm_vars(struct ieee80211_hw *hw)
 {
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 
 	/*close ASPM for AMD defaultly */
 	rtlpci->const_amdpci_aspm = 0;
 
-	/* ASPM PS mode.
+	/**
+	 * ASPM PS mode.
 	 * 0 - Disable ASPM,
 	 * 1 - Enable ASPM without Clock Req,
 	 * 2 - Enable ASPM with Clock Req,
@@ -71,7 +68,8 @@
 	/*Setting for PCI-E bridge */
 	rtlpci->const_hostpci_aspm_setting = 0x02;
 
-	/* In Hw/Sw Radio Off situation.
+	/**
+	 * In Hw/Sw Radio Off situation.
 	 * 0 - Default,
 	 * 1 - From ASPM setting without low Mac Pwr,
 	 * 2 - From ASPM setting with low Mac Pwr,
@@ -80,7 +78,8 @@
 	 */
 	rtlpci->const_hwsw_rfoff_d3 = 0;
 
-	/* This setting works for those device with
+	/**
+	 * This setting works for those device with
 	 * backdoor ASPM setting such as EPHY setting.
 	 * 0 - Not support ASPM,
 	 * 1 - Support ASPM,
@@ -89,14 +88,17 @@
 	rtlpci->const_support_pciaspm = 1;
 }
 
-int rtl8723ae_init_sw_vars(struct ieee80211_hw *hw)
+int rtl8723e_init_sw_vars(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	int err;
+	int err = 0;
 
-	rtl8723ae_bt_reg_init(hw);
+	rtl8723e_bt_reg_init(hw);
+
+	rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer();
+
 	rtlpriv->dm.dm_initialgain_enable = 1;
 	rtlpriv->dm.dm_flag = 0;
 	rtlpriv->dm.disable_framebursting = 0;
@@ -138,7 +140,9 @@
 		   PHIMR_PSTIMEOUT |
 		   0);
 
-	rtlpci->irq_mask[1] = (u32)(PHIMR_RXFOVW | 0);
+	rtlpci->irq_mask[1]	=
+		 (u32)(PHIMR_RXFOVW |
+				0);
 
 	/* for debug level */
 	rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
@@ -146,12 +150,11 @@
 	rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
 	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
 	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+	if (rtlpriv->cfg->mod_params->disable_watchdog)
+		pr_info("watchdog disabled\n");
 	rtlpriv->psc.reg_fwctrl_lps = 3;
 	rtlpriv->psc.reg_max_lps_awakeintvl = 5;
-	/* for ASPM, you can close aspm through
-	 * set const_support_pciaspm = 0
-	 */
-	rtl8723ae_init_aspm_vars(hw);
+	rtl8723e_init_aspm_vars(hw);
 
 	if (rtlpriv->psc.reg_fwctrl_lps == 1)
 		rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE;
@@ -161,7 +164,7 @@
 		rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
 
 	/* for firmware buf */
-	rtlpriv->rtlhal.pfirmware = vmalloc(0x6000);
+	rtlpriv->rtlhal.pfirmware = vzalloc(0x6000);
 	if (!rtlpriv->rtlhal.pfirmware) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 "Can't alloc buffer for fw.\n");
@@ -186,7 +189,7 @@
 	return 0;
 }
 
-void rtl8723ae_deinit_sw_vars(struct ieee80211_hw *hw)
+void rtl8723e_deinit_sw_vars(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
@@ -196,59 +199,69 @@
 	}
 }
 
-static bool is_fw_header(struct rtl92c_firmware_header *hdr)
+/* get bt coexist status */
+bool rtl8723e_get_btc_status(void)
+{
+	return true;
+}
+
+static bool is_fw_header(struct rtl8723e_firmware_header *hdr)
 {
 	return (hdr->signature & 0xfff0) == 0x2300;
 }
 
-static struct rtl_hal_ops rtl8723ae_hal_ops = {
-	.init_sw_vars = rtl8723ae_init_sw_vars,
-	.deinit_sw_vars = rtl8723ae_deinit_sw_vars,
-	.read_eeprom_info = rtl8723ae_read_eeprom_info,
-	.interrupt_recognized = rtl8723ae_interrupt_recognized,
-	.hw_init = rtl8723ae_hw_init,
-	.hw_disable = rtl8723ae_card_disable,
-	.hw_suspend = rtl8723ae_suspend,
-	.hw_resume = rtl8723ae_resume,
-	.enable_interrupt = rtl8723ae_enable_interrupt,
-	.disable_interrupt = rtl8723ae_disable_interrupt,
-	.set_network_type = rtl8723ae_set_network_type,
-	.set_chk_bssid = rtl8723ae_set_check_bssid,
-	.set_qos = rtl8723ae_set_qos,
-	.set_bcn_reg = rtl8723ae_set_beacon_related_registers,
-	.set_bcn_intv = rtl8723ae_set_beacon_interval,
-	.update_interrupt_mask = rtl8723ae_update_interrupt_mask,
-	.get_hw_reg = rtl8723ae_get_hw_reg,
-	.set_hw_reg = rtl8723ae_set_hw_reg,
-	.update_rate_tbl = rtl8723ae_update_hal_rate_tbl,
-	.fill_tx_desc = rtl8723ae_tx_fill_desc,
-	.fill_tx_cmddesc = rtl8723ae_tx_fill_cmddesc,
-	.query_rx_desc = rtl8723ae_rx_query_desc,
-	.set_channel_access = rtl8723ae_update_channel_access_setting,
-	.radio_onoff_checking = rtl8723ae_gpio_radio_on_off_checking,
-	.set_bw_mode = rtl8723ae_phy_set_bw_mode,
-	.switch_channel = rtl8723ae_phy_sw_chnl,
-	.dm_watchdog = rtl8723ae_dm_watchdog,
-	.scan_operation_backup = rtl_phy_scan_operation_backup,
-	.set_rf_power_state = rtl8723ae_phy_set_rf_power_state,
-	.led_control = rtl8723ae_led_control,
-	.set_desc = rtl8723ae_set_desc,
-	.get_desc = rtl8723ae_get_desc,
-	.tx_polling = rtl8723ae_tx_polling,
-	.enable_hw_sec = rtl8723ae_enable_hw_security_config,
-	.set_key = rtl8723ae_set_key,
-	.init_sw_leds = rtl8723ae_init_sw_leds,
+static struct rtl_hal_ops rtl8723e_hal_ops = {
+	.init_sw_vars = rtl8723e_init_sw_vars,
+	.deinit_sw_vars = rtl8723e_deinit_sw_vars,
+	.read_eeprom_info = rtl8723e_read_eeprom_info,
+	.interrupt_recognized = rtl8723e_interrupt_recognized,
+	.hw_init = rtl8723e_hw_init,
+	.hw_disable = rtl8723e_card_disable,
+	.hw_suspend = rtl8723e_suspend,
+	.hw_resume = rtl8723e_resume,
+	.enable_interrupt = rtl8723e_enable_interrupt,
+	.disable_interrupt = rtl8723e_disable_interrupt,
+	.set_network_type = rtl8723e_set_network_type,
+	.set_chk_bssid = rtl8723e_set_check_bssid,
+	.set_qos = rtl8723e_set_qos,
+	.set_bcn_reg = rtl8723e_set_beacon_related_registers,
+	.set_bcn_intv = rtl8723e_set_beacon_interval,
+	.update_interrupt_mask = rtl8723e_update_interrupt_mask,
+	.get_hw_reg = rtl8723e_get_hw_reg,
+	.set_hw_reg = rtl8723e_set_hw_reg,
+	.update_rate_tbl = rtl8723e_update_hal_rate_tbl,
+	.fill_tx_desc = rtl8723e_tx_fill_desc,
+	.fill_tx_cmddesc = rtl8723e_tx_fill_cmddesc,
+	.query_rx_desc = rtl8723e_rx_query_desc,
+	.set_channel_access = rtl8723e_update_channel_access_setting,
+	.radio_onoff_checking = rtl8723e_gpio_radio_on_off_checking,
+	.set_bw_mode = rtl8723e_phy_set_bw_mode,
+	.switch_channel = rtl8723e_phy_sw_chnl,
+	.dm_watchdog = rtl8723e_dm_watchdog,
+	.scan_operation_backup = rtl8723e_phy_scan_operation_backup,
+	.set_rf_power_state = rtl8723e_phy_set_rf_power_state,
+	.led_control = rtl8723e_led_control,
+	.set_desc = rtl8723e_set_desc,
+	.get_desc = rtl8723e_get_desc,
+	.is_tx_desc_closed = rtl8723e_is_tx_desc_closed,
+	.tx_polling = rtl8723e_tx_polling,
+	.enable_hw_sec = rtl8723e_enable_hw_security_config,
+	.set_key = rtl8723e_set_key,
+	.init_sw_leds = rtl8723e_init_sw_leds,
 	.get_bbreg = rtl8723_phy_query_bb_reg,
 	.set_bbreg = rtl8723_phy_set_bb_reg,
-	.get_rfreg = rtl8723ae_phy_query_rf_reg,
-	.set_rfreg = rtl8723ae_phy_set_rf_reg,
+	.get_rfreg = rtl8723e_phy_query_rf_reg,
+	.set_rfreg = rtl8723e_phy_set_rf_reg,
 	.c2h_command_handle = rtl_8723e_c2h_command_handle,
 	.bt_wifi_media_status_notify = rtl_8723e_bt_wifi_media_status_notify,
-	.bt_coex_off_before_lps = rtl8723ae_bt_coex_off_before_lps,
+	.bt_coex_off_before_lps =
+		rtl8723e_dm_bt_turn_off_bt_coexist_before_enter_lps,
+	.get_btc_status = rtl8723e_get_btc_status,
+	.rx_command_packet = rtl8723e_rx_command_packet,
 	.is_fw_header = is_fw_header,
 };
 
-static struct rtl_mod_params rtl8723ae_mod_params = {
+static struct rtl_mod_params rtl8723e_mod_params = {
 	.sw_crypto = false,
 	.inactiveps = true,
 	.swctrl_lps = false,
@@ -256,13 +269,13 @@
 	.debug = DBG_EMERG,
 };
 
-static struct rtl_hal_cfg rtl8723ae_hal_cfg = {
+static struct rtl_hal_cfg rtl8723e_hal_cfg = {
 	.bar_id = 2,
 	.write_readback = true,
-	.name = "rtl8723ae_pci",
-	.fw_name = "rtlwifi/rtl8723fw.bin",
-	.ops = &rtl8723ae_hal_ops,
-	.mod_params = &rtl8723ae_mod_params,
+	.name = "rtl8723e_pci",
+	.fw_name = "rtlwifi/rtl8723efw.bin",
+	.ops = &rtl8723e_hal_ops,
+	.mod_params = &rtl8723e_mod_params,
 	.maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
 	.maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN,
 	.maps[SYS_CLK] = REG_SYS_CLKR,
@@ -271,6 +284,8 @@
 	.maps[MAC_RCR_ACRC32] = ACRC32,
 	.maps[MAC_RCR_ACF] = ACF,
 	.maps[MAC_RCR_AAP] = AAP,
+	.maps[MAC_HIMR] = REG_HIMR,
+	.maps[MAC_HIMRE] = REG_HIMRE,
 	.maps[EFUSE_TEST] = REG_EFUSE_TEST,
 	.maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
 	.maps[EFUSE_CLK] = 0,
@@ -328,62 +343,63 @@
 	.maps[RTL_IMR_VIDOK] = PHIMR_VIDOK,
 	.maps[RTL_IMR_VODOK] = PHIMR_VODOK,
 	.maps[RTL_IMR_ROK] = PHIMR_ROK,
-	.maps[RTL_IBSS_INT_MASKS] = (PHIMR_BCNDMAINT0 |
-				     PHIMR_TXBCNOK | PHIMR_TXBCNERR),
+	.maps[RTL_IBSS_INT_MASKS] =
+		(PHIMR_BCNDMAINT0 | PHIMR_TXBCNOK | PHIMR_TXBCNERR),
 	.maps[RTL_IMR_C2HCMD] = PHIMR_C2HCMD,
 
 
-	.maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
-	.maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
-	.maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
-	.maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
-	.maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
-	.maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
-	.maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
-	.maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
-	.maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
-	.maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
-	.maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
-	.maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
+	.maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
+	.maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M,
+	.maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M,
+	.maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M,
+	.maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M,
+	.maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M,
+	.maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M,
+	.maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M,
+	.maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M,
+	.maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M,
+	.maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M,
+	.maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M,
 
-	.maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
-	.maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
+	.maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7,
+	.maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
 };
 
-static struct pci_device_id rtl8723ae_pci_ids[] = {
-	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8723, rtl8723ae_hal_cfg)},
+static struct pci_device_id rtl8723e_pci_ids[] = {
+	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8723, rtl8723e_hal_cfg)},
 	{},
 };
 
-MODULE_DEVICE_TABLE(pci, rtl8723ae_pci_ids);
+MODULE_DEVICE_TABLE(pci, rtl8723e_pci_ids);
 
 MODULE_AUTHOR("lizhaoming	<chaoming_li@realsil.com.cn>");
 MODULE_AUTHOR("Realtek WlanFAE	<wlanfae@realtek.com>");
-MODULE_AUTHOR("Larry Finger	<Larry.Finger@lwfinger.net>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Realtek 8723E 802.11n PCI wireless");
-MODULE_FIRMWARE("rtlwifi/rtl8723fw.bin");
-MODULE_FIRMWARE("rtlwifi/rtl8723fw_B.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8723efw.bin");
 
-module_param_named(swenc, rtl8723ae_mod_params.sw_crypto, bool, 0444);
-module_param_named(debug, rtl8723ae_mod_params.debug, int, 0444);
-module_param_named(ips, rtl8723ae_mod_params.inactiveps, bool, 0444);
-module_param_named(swlps, rtl8723ae_mod_params.swctrl_lps, bool, 0444);
-module_param_named(fwlps, rtl8723ae_mod_params.fwctrl_lps, bool, 0444);
+module_param_named(swenc, rtl8723e_mod_params.sw_crypto, bool, 0444);
+module_param_named(debug, rtl8723e_mod_params.debug, int, 0444);
+module_param_named(ips, rtl8723e_mod_params.inactiveps, bool, 0444);
+module_param_named(swlps, rtl8723e_mod_params.swctrl_lps, bool, 0444);
+module_param_named(fwlps, rtl8723e_mod_params.fwctrl_lps, bool, 0444);
+module_param_named(disable_watchdog, rtl8723e_mod_params.disable_watchdog,
+		   bool, 0444);
 MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
 MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
 MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
 MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
 MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n");
 
 static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
 
-static struct pci_driver rtl8723ae_driver = {
+static struct pci_driver rtl8723e_driver = {
 	.name = KBUILD_MODNAME,
-	.id_table = rtl8723ae_pci_ids,
+	.id_table = rtl8723e_pci_ids,
 	.probe = rtl_pci_probe,
 	.remove = rtl_pci_disconnect,
 	.driver.pm = &rtlwifi_pm_ops,
 };
 
-module_pci_driver(rtl8723ae_driver);
+module_pci_driver(rtl8723e_driver);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.h
index fc4fde5..4647878 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,8 +26,10 @@
 #ifndef __RTL8723E_SW_H__
 #define __RTL8723E_SW_H__
 
-int rtl8723ae_init_sw_vars(struct ieee80211_hw *hw);
-void rtl8723ae_deinit_sw_vars(struct ieee80211_hw *hw);
-void rtl8723ae_init_var_map(struct ieee80211_hw *hw);
+int rtl8723e_init_sw_vars(struct ieee80211_hw *hw);
+void rtl8723e_deinit_sw_vars(struct ieee80211_hw *hw);
+void rtl8723e_init_var_map(struct ieee80211_hw *hw);
+bool rtl8723e_get_btc_status(void);
+
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/table.c b/drivers/net/wireless/rtlwifi/rtl8723ae/table.c
index 9b0b50c..61e8604 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/table.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/table.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -335,7 +331,7 @@
 	0x868, 0xffffffff, 0x00000000,
 };
 
-u32 RTL8723E_RADIOA_1TARRAY[Rtl8723ERADIOA_1TARRAYLENGTH] = {
+u32 RTL8723E_RADIOA_1TARRAY[RTL8723ERADIOA_1TARRAYLENGTH] = {
 	0x000, 0x00030159,
 	0x001, 0x00031284,
 	0x002, 0x00098000,
@@ -479,12 +475,10 @@
 	0x000, 0x00030159,
 };
 
-
 u32 RTL8723E_RADIOB_1TARRAY[RTL8723E_RADIOB_1TARRAYLENGTH] = {
 	0x0,
 };
 
-
 u32 RTL8723EMAC_ARRAY[RTL8723E_MACARRAYLENGTH] = {
 	0x420, 0x00000080,
 	0x423, 0x00000000,
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/table.h b/drivers/net/wireless/rtlwifi/rtl8723ae/table.h
index f5ce713..57a548c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/table.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/table.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -38,8 +34,8 @@
 extern u32 RTL8723EPHY_REG_1TARRAY[RTL8723E_PHY_REG_1TARRAY_LENGTH];
 #define RTL8723E_PHY_REG_ARRAY_PGLENGTH		336
 extern u32 RTL8723EPHY_REG_ARRAY_PG[RTL8723E_PHY_REG_ARRAY_PGLENGTH];
-#define Rtl8723ERADIOA_1TARRAYLENGTH		 282
-extern u32 RTL8723E_RADIOA_1TARRAY[Rtl8723ERADIOA_1TARRAYLENGTH];
+#define RTL8723ERADIOA_1TARRAYLENGTH		282
+extern u32 RTL8723E_RADIOA_1TARRAY[RTL8723ERADIOA_1TARRAYLENGTH];
 #define RTL8723E_RADIOB_1TARRAYLENGTH		1
 extern u32 RTL8723E_RADIOB_1TARRAY[RTL8723E_RADIOB_1TARRAYLENGTH];
 #define RTL8723E_MACARRAYLENGTH			172
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
index 10b7577..d372cca 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -37,7 +33,7 @@
 #include "trx.h"
 #include "led.h"
 
-static u8 _rtl8723ae_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
+static u8 _rtl8723e_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
 {
 	__le16 fc = rtl_get_fc(skb);
 
@@ -49,16 +45,174 @@
 	return skb->priority;
 }
 
-static void _rtl8723ae_query_rxphystatus(struct ieee80211_hw *hw,
-			struct rtl_stats *pstatus, u8 *pdesc,
-			struct rx_fwinfo_8723e *p_drvinfo,
-			bool bpacket_match_bssid,
-			bool bpacket_toself, bool packet_beacon)
+/* mac80211's rate_idx is like this:
+ *
+ * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
+ *
+ * B/G rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
+ *
+ * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
+ * A rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
+ */
+static int _rtl8723e_rate_mapping(struct ieee80211_hw *hw,
+				  bool isht, u8 desc_rate)
+{
+	int rate_idx;
+
+	if (!isht) {
+		if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
+			switch (desc_rate) {
+			case DESC92C_RATE1M:
+				rate_idx = 0;
+				break;
+			case DESC92C_RATE2M:
+				rate_idx = 1;
+				break;
+			case DESC92C_RATE5_5M:
+				rate_idx = 2;
+				break;
+			case DESC92C_RATE11M:
+				rate_idx = 3;
+				break;
+			case DESC92C_RATE6M:
+				rate_idx = 4;
+				break;
+			case DESC92C_RATE9M:
+				rate_idx = 5;
+				break;
+			case DESC92C_RATE12M:
+				rate_idx = 6;
+				break;
+			case DESC92C_RATE18M:
+				rate_idx = 7;
+				break;
+			case DESC92C_RATE24M:
+				rate_idx = 8;
+				break;
+			case DESC92C_RATE36M:
+				rate_idx = 9;
+				break;
+			case DESC92C_RATE48M:
+				rate_idx = 10;
+				break;
+			case DESC92C_RATE54M:
+				rate_idx = 11;
+				break;
+			default:
+				rate_idx = 0;
+				break;
+			}
+		} else {
+			switch (desc_rate) {
+			case DESC92C_RATE6M:
+				rate_idx = 0;
+				break;
+			case DESC92C_RATE9M:
+				rate_idx = 1;
+				break;
+			case DESC92C_RATE12M:
+				rate_idx = 2;
+				break;
+			case DESC92C_RATE18M:
+				rate_idx = 3;
+				break;
+			case DESC92C_RATE24M:
+				rate_idx = 4;
+				break;
+			case DESC92C_RATE36M:
+				rate_idx = 5;
+				break;
+			case DESC92C_RATE48M:
+				rate_idx = 6;
+				break;
+			case DESC92C_RATE54M:
+				rate_idx = 7;
+				break;
+			default:
+				rate_idx = 0;
+				break;
+			}
+		}
+	} else {
+		switch (desc_rate) {
+		case DESC92C_RATEMCS0:
+			rate_idx = 0;
+			break;
+		case DESC92C_RATEMCS1:
+			rate_idx = 1;
+			break;
+		case DESC92C_RATEMCS2:
+			rate_idx = 2;
+			break;
+		case DESC92C_RATEMCS3:
+			rate_idx = 3;
+			break;
+		case DESC92C_RATEMCS4:
+			rate_idx = 4;
+			break;
+		case DESC92C_RATEMCS5:
+			rate_idx = 5;
+			break;
+		case DESC92C_RATEMCS6:
+			rate_idx = 6;
+			break;
+		case DESC92C_RATEMCS7:
+			rate_idx = 7;
+			break;
+		case DESC92C_RATEMCS8:
+			rate_idx = 8;
+			break;
+		case DESC92C_RATEMCS9:
+			rate_idx = 9;
+			break;
+		case DESC92C_RATEMCS10:
+			rate_idx = 10;
+			break;
+		case DESC92C_RATEMCS11:
+			rate_idx = 11;
+			break;
+		case DESC92C_RATEMCS12:
+			rate_idx = 12;
+			break;
+		case DESC92C_RATEMCS13:
+			rate_idx = 13;
+			break;
+		case DESC92C_RATEMCS14:
+			rate_idx = 14;
+			break;
+		case DESC92C_RATEMCS15:
+			rate_idx = 15;
+			break;
+		default:
+			rate_idx = 0;
+			break;
+		}
+	}
+	return rate_idx;
+}
+
+static void _rtl8723e_query_rxphystatus(struct ieee80211_hw *hw,
+					struct rtl_stats *pstatus, u8 *pdesc,
+					struct rx_fwinfo_8723e *p_drvinfo,
+					bool bpacket_match_bssid,
+					bool bpacket_toself, bool packet_beacon)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
 	struct phy_sts_cck_8723e_t *cck_buf;
-	s8 rx_pwr_all, rx_pwr[4];
+	s8 rx_pwr_all = 0, rx_pwr[4];
 	u8 rf_rx_num = 0, evm, pwdb_all;
 	u8 i, max_spatial_stream;
 	u32 rssi, total_rssi = 0;
@@ -68,8 +222,8 @@
 	pstatus->packet_matchbssid = bpacket_match_bssid;
 	pstatus->packet_toself = bpacket_toself;
 	pstatus->packet_beacon = packet_beacon;
-	pstatus->rx_mimo_sig_qual[0] = -1;
-	pstatus->rx_mimo_sig_qual[1] = -1;
+	pstatus->rx_mimo_signalquality[0] = -1;
+	pstatus->rx_mimo_signalquality[1] = -1;
 
 	if (is_cck) {
 		u8 report, cck_highpwr;
@@ -77,14 +231,14 @@
 		/* CCK Driver info Structure is not the same as OFDM packet. */
 		cck_buf = (struct phy_sts_cck_8723e_t *)p_drvinfo;
 
-		/* (1)Hardware does not provide RSSI for CCK
-		 * (2)PWDB, Average PWDB cacluated by
+		/* (1)Hardware does not provide RSSI for CCK */
+		/* (2)PWDB, Average PWDB cacluated by
 		 * hardware (for rate adaptive)
 		 */
 		if (ppsc->rfpwr_state == ERFON)
-			cck_highpwr = (u8) rtl_get_bbreg(hw,
-						 RFPGA0_XA_HSSIPARAMETER2,
-						 BIT(9));
+			cck_highpwr = (u8)rtl_get_bbreg(hw,
+					RFPGA0_XA_HSSIPARAMETER2,
+					BIT(9));
 		else
 			cck_highpwr = false;
 
@@ -127,8 +281,9 @@
 		}
 
 		pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
-		/* CCK gain is smaller than OFDM/MCS gain,
-		 * so we add gain diff. From experience, the val is 6
+		/* CCK gain is smaller than OFDM/MCS gain,  */
+		/* so we add gain diff by experiences,
+		 * the val is 6
 		 */
 		pwdb_all += 6;
 		if (pwdb_all > 100)
@@ -152,9 +307,9 @@
 		if (bpacket_match_bssid) {
 			u8 sq;
 
-			if (pstatus->rx_pwdb_all > 40) {
+			if (pstatus->rx_pwdb_all > 40)
 				sq = 100;
-			} else {
+			else {
 				sq = cck_buf->sq_rpt;
 				if (sq > 64)
 					sq = 0;
@@ -165,8 +320,8 @@
 			}
 
 			pstatus->signalquality = sq;
-			pstatus->rx_mimo_sig_qual[0] = sq;
-			pstatus->rx_mimo_sig_qual[1] = -1;
+			pstatus->rx_mimo_signalquality[0] = sq;
+			pstatus->rx_mimo_signalquality[1] = -1;
 		}
 	} else {
 		rtlpriv->dm.rfpath_rxenable[0] =
@@ -179,18 +334,20 @@
 			if (rtlpriv->dm.rfpath_rxenable[i])
 				rf_rx_num++;
 
-			rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f)*2) - 110;
+			rx_pwr[i] = ((p_drvinfo->gain_trsw[i] &
+				      0x3f) * 2) - 110;
 
 			/* Translate DBM to percentage. */
 			rssi = rtl_query_rxpwrpercentage(rx_pwr[i]);
 			total_rssi += rssi;
 
 			/* Get Rx snr value in DB */
-			rtlpriv->stats.rx_snr_db[i] = (p_drvinfo->rxsnr[i] / 2);
+			rtlpriv->stats.rx_snr_db[i] =
+				(long)(p_drvinfo->rxsnr[i] / 2);
 
 			/* Record Signal Strength for next packet */
 			if (bpacket_match_bssid)
-				pstatus->rx_mimo_signalstrength[i] = (u8) rssi;
+				pstatus->rx_mimo_signalstrength[i] = (u8)rssi;
 		}
 
 		/* (2)PWDB, Average PWDB cacluated by
@@ -204,8 +361,8 @@
 		pstatus->recvsignalpower = rx_pwr_all;
 
 		/* (3)EVM of HT rate */
-		if (pstatus->is_ht && pstatus->rate >= DESC92_RATEMCS8 &&
-		    pstatus->rate <= DESC92_RATEMCS15)
+		if (pstatus->is_ht && pstatus->rate >= DESC92C_RATEMCS8 &&
+		    pstatus->rate <= DESC92C_RATEMCS15)
 			max_spatial_stream = 2;
 		else
 			max_spatial_stream = 1;
@@ -218,8 +375,10 @@
 				 * spatial stream only
 				 */
 				if (i == 0)
-					pstatus->signalquality = (evm & 0xff);
-				pstatus->rx_mimo_sig_qual[i] = (evm & 0xff);
+					pstatus->signalquality =
+						(u8)(evm & 0xff);
+				pstatus->rx_mimo_signalquality[i] =
+					(u8)(evm & 0xff);
 			}
 		}
 	}
@@ -235,78 +394,83 @@
 			total_rssi /= rf_rx_num));
 }
 
-static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw,
-		struct sk_buff *skb, struct rtl_stats *pstatus,
-		u8 *pdesc, struct rx_fwinfo_8723e *p_drvinfo)
+static void translate_rx_signal_stuff(struct ieee80211_hw *hw,
+				      struct sk_buff *skb,
+				      struct rtl_stats *pstatus, u8 *pdesc,
+				      struct rx_fwinfo_8723e *p_drvinfo)
 {
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	struct ieee80211_hdr *hdr;
 	u8 *tmp_buf;
 	u8 *praddr;
-	__le16 fc;
-	u16 type;
-	bool packet_matchbssid, packet_toself, packet_beacon = false;
+	/*u8 *psaddr;*/
+	u16 fc, type;
+	bool packet_matchbssid, packet_toself, packet_beacon;
 
 	tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
 
 	hdr = (struct ieee80211_hdr *)tmp_buf;
-	fc = hdr->frame_control;
-	type = WLAN_FC_GET_TYPE(fc);
+	fc = le16_to_cpu(hdr->frame_control);
+	type = WLAN_FC_GET_TYPE(hdr->frame_control);
 	praddr = hdr->addr1;
 
-	packet_matchbssid =
-		((IEEE80211_FTYPE_CTL != type) &&
-		 ether_addr_equal(mac->bssid,
-				  (le16_to_cpu(fc) & IEEE80211_FCTL_TODS) ? hdr->addr1 :
-				  (le16_to_cpu(fc) & IEEE80211_FCTL_FROMDS) ? hdr->addr2 :
-				  hdr->addr3) &&
-		 (!pstatus->hwerror) && (!pstatus->crc) && (!pstatus->icv));
+	packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) &&
+		(ether_addr_equal(mac->bssid, (fc & IEEE80211_FCTL_TODS) ?
+		 hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ?
+		 hdr->addr2 : hdr->addr3)) &&
+		 (!pstatus->hwerror) &&
+		 (!pstatus->crc) && (!pstatus->icv));
 
-	packet_toself = (packet_matchbssid &&
-			 ether_addr_equal(praddr, rtlefuse->dev_addr));
+	packet_toself = packet_matchbssid &&
+	    (ether_addr_equal(praddr, rtlefuse->dev_addr));
 
-	if (ieee80211_is_beacon(fc))
+	if (ieee80211_is_beacon(hdr->frame_control))
 		packet_beacon = true;
+	else
+		packet_beacon = false;
 
-	_rtl8723ae_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo,
-				   packet_matchbssid, packet_toself,
-				   packet_beacon);
+	_rtl8723e_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo,
+				    packet_matchbssid, packet_toself,
+				    packet_beacon);
 
 	rtl_process_phyinfo(hw, tmp_buf, pstatus);
 }
 
-bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
-			     struct rtl_stats *status,
-			     struct ieee80211_rx_status *rx_status,
-			     u8 *pdesc, struct sk_buff *skb)
+bool rtl8723e_rx_query_desc(struct ieee80211_hw *hw,
+			    struct rtl_stats *status,
+			    struct ieee80211_rx_status *rx_status,
+			    u8 *pdesc, struct sk_buff *skb)
 {
 	struct rx_fwinfo_8723e *p_drvinfo;
 	struct ieee80211_hdr *hdr;
 	u32 phystatus = GET_RX_DESC_PHYST(pdesc);
 
-	status->length = (u16) GET_RX_DESC_PKT_LEN(pdesc);
-	status->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
-				   RX_DRV_INFO_SIZE_UNIT;
-	status->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03);
-	status->icv = (u16) GET_RX_DESC_ICV(pdesc);
-	status->crc = (u16) GET_RX_DESC_CRC32(pdesc);
+	status->length = (u16)GET_RX_DESC_PKT_LEN(pdesc);
+	status->rx_drvinfo_size = (u8)GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
+	    RX_DRV_INFO_SIZE_UNIT;
+	status->rx_bufshift = (u8)(GET_RX_DESC_SHIFT(pdesc) & 0x03);
+	status->icv = (u16)GET_RX_DESC_ICV(pdesc);
+	status->crc = (u16)GET_RX_DESC_CRC32(pdesc);
 	status->hwerror = (status->crc | status->icv);
 	status->decrypted = !GET_RX_DESC_SWDEC(pdesc);
-	status->rate = (u8) GET_RX_DESC_RXMCS(pdesc);
-	status->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
-	status->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
-	status->isfirst_ampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1)
-				 && (GET_RX_DESC_FAGGR(pdesc) == 1));
+	status->rate = (u8)GET_RX_DESC_RXMCS(pdesc);
+	status->shortpreamble = (u16)GET_RX_DESC_SPLCP(pdesc);
+	status->isampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1);
+	status->isfirst_ampdu = (bool)((GET_RX_DESC_PAGGR(pdesc) == 1) &&
+				       (GET_RX_DESC_FAGGR(pdesc) == 1));
 	status->timestamp_low = GET_RX_DESC_TSFL(pdesc);
-	status->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
+	status->rx_is40Mhzpacket = (bool)GET_RX_DESC_BW(pdesc);
 	status->is_ht = (bool)GET_RX_DESC_RXHT(pdesc);
 
-	status->is_cck = RTL8723E_RX_HAL_IS_CCK_RATE(status->rate);
+	status->is_cck = RX_HAL_IS_CCK_RATE(status->rate);
 
 	rx_status->freq = hw->conf.chandef.chan->center_freq;
 	rx_status->band = hw->conf.chandef.chan->band;
 
+	hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size
+			+ status->rx_bufshift);
+
 	if (status->crc)
 		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
 
@@ -320,69 +484,62 @@
 
 	/* hw will set status->decrypted true, if it finds the
 	 * frame is open data frame or mgmt frame.
-	 * Thus hw will not decrypt a robust managment frame
+	 * So hw will not decryption robust managment frame
 	 * for IEEE80211w but still set status->decrypted
 	 * true, so here we should set it back to undecrypted
 	 * for IEEE80211w frame, and mac80211 sw will help
 	 * to decrypt it
 	 */
 	if (status->decrypted) {
-		hdr = (struct ieee80211_hdr *)(skb->data +
-		       status->rx_drvinfo_size + status->rx_bufshift);
-
-		if (!hdr) {
-			/* during testing, hdr could be NULL here */
-			return false;
-		}
-		if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
-			(ieee80211_has_protected(hdr->frame_control)))
-			rx_status->flag &= ~RX_FLAG_DECRYPTED;
-		else
+		if ((!_ieee80211_is_robust_mgmt_frame(hdr)) &&
+		    (ieee80211_has_protected(hdr->frame_control)))
 			rx_status->flag |= RX_FLAG_DECRYPTED;
+		else
+			rx_status->flag &= ~RX_FLAG_DECRYPTED;
 	}
 
 	/* rate_idx: index of data rate into band's
 	 * supported rates or MCS index if HT rates
 	 * are use (RX_FLAG_HT)
+	 * Notice: this is diff with windows define
 	 */
-	rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht,
-						   status->rate, false);
+	rx_status->rate_idx = _rtl8723e_rate_mapping(hw,
+				status->is_ht, status->rate);
 
 	rx_status->mactime = status->timestamp_low;
 	if (phystatus == true) {
 		p_drvinfo = (struct rx_fwinfo_8723e *)(skb->data +
-			     status->rx_bufshift);
+						     status->rx_bufshift);
 
-		_rtl8723ae_translate_rx_signal_stuff(hw,
-			   skb, status, pdesc, p_drvinfo);
+		translate_rx_signal_stuff(hw, skb, status, pdesc, p_drvinfo);
 	}
-
-	/*rx_status->qual = status->signal; */
 	rx_status->signal = status->recvsignalpower + 10;
-
 	return true;
 }
 
-void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
-			    struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-			    u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
-			    struct ieee80211_sta *sta,
-			    struct sk_buff *skb, u8 hw_queue,
-			    struct rtl_tcb_desc *ptcdesc)
+void rtl8723e_tx_fill_desc(struct ieee80211_hw *hw,
+			   struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+			   u8 *txbd, struct ieee80211_tx_info *info,
+			   struct ieee80211_sta *sta,
+			   struct sk_buff *skb,
+			   u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-	bool defaultadapter = true;
-	u8 *pdesc = pdesc_tx;
+	bool b_defaultadapter = true;
+	/* bool b_trigger_ac = false; */
+	u8 *pdesc = (u8 *)pdesc_tx;
 	u16 seq_number;
 	__le16 fc = hdr->frame_control;
-	u8 fw_qsel = _rtl8723ae_map_hwqueue_to_fwqueue(skb, hw_queue);
+	u8 fw_qsel = _rtl8723e_map_hwqueue_to_fwqueue(skb, hw_queue);
 	bool firstseg = ((hdr->seq_ctrl &
-			    cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
+			  cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
+
 	bool lastseg = ((hdr->frame_control &
-			   cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
+			 cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
+
 	dma_addr_t mapping = pci_map_single(rtlpci->pdev,
 					    skb->data, skb->len,
 					    PCI_DMA_TODEVICE);
@@ -398,12 +555,13 @@
 	} else if (mac->opmode == NL80211_IFTYPE_AP ||
 		mac->opmode == NL80211_IFTYPE_ADHOC) {
 		if (sta)
-			bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
+			bw_40 = sta->ht_cap.cap &
+				IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 	}
 
 	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
 
-	rtl_get_tcb_desc(hw, info, sta, skb, ptcdesc);
+	rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
 
 	CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_8723e));
 
@@ -415,9 +573,9 @@
 	if (firstseg) {
 		SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
 
-		SET_TX_DESC_TX_RATE(pdesc, ptcdesc->hw_rate);
+		SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
 
-		if (ptcdesc->use_shortgi || ptcdesc->use_shortpreamble)
+		if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble)
 			SET_TX_DESC_DATA_SHORTGI(pdesc, 1);
 
 		if (info->flags & IEEE80211_TX_CTL_AMPDU) {
@@ -426,31 +584,33 @@
 		}
 		SET_TX_DESC_SEQ(pdesc, seq_number);
 
-		SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcdesc->rts_enable &&
-						!ptcdesc->
-						cts_enable) ? 1 : 0));
+		SET_TX_DESC_RTS_ENABLE(pdesc,
+				       ((ptcb_desc->rts_enable &&
+					!ptcb_desc->cts_enable) ? 1 : 0));
 		SET_TX_DESC_HW_RTS_ENABLE(pdesc,
-					  ((ptcdesc->rts_enable
-					    || ptcdesc->cts_enable) ? 1 : 0));
-		SET_TX_DESC_CTS2SELF(pdesc, ((ptcdesc->cts_enable) ? 1 : 0));
-		SET_TX_DESC_RTS_STBC(pdesc, ((ptcdesc->rts_stbc) ? 1 : 0));
+					  ((ptcb_desc->rts_enable ||
+					  ptcb_desc->cts_enable) ? 1 : 0));
+		SET_TX_DESC_CTS2SELF(pdesc,
+				     ((ptcb_desc->cts_enable) ? 1 : 0));
+		SET_TX_DESC_RTS_STBC(pdesc,
+				     ((ptcb_desc->rts_stbc) ? 1 : 0));
 
-		SET_TX_DESC_RTS_RATE(pdesc, ptcdesc->rts_rate);
+		SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
 		SET_TX_DESC_RTS_BW(pdesc, 0);
-		SET_TX_DESC_RTS_SC(pdesc, ptcdesc->rts_sc);
+		SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc);
 		SET_TX_DESC_RTS_SHORT(pdesc,
-				      ((ptcdesc->rts_rate <= DESC92_RATE54M) ?
-				       (ptcdesc->rts_use_shortpreamble ? 1 : 0)
-				       : (ptcdesc->rts_use_shortgi ? 1 : 0)));
+				((ptcb_desc->rts_rate <= DESC92C_RATE54M) ?
+				(ptcb_desc->rts_use_shortpreamble ? 1 : 0)
+				: (ptcb_desc->rts_use_shortgi ? 1 : 0)));
 
 		if (bw_40) {
-			if (ptcdesc->packet_bw) {
+			if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40) {
 				SET_TX_DESC_DATA_BW(pdesc, 1);
 				SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3);
 			} else {
 				SET_TX_DESC_DATA_BW(pdesc, 0);
 				SET_TX_DESC_TX_SUB_CARRIER(pdesc,
-							 mac->cur_40_prime_sc);
+					mac->cur_40_prime_sc);
 			}
 		} else {
 			SET_TX_DESC_DATA_BW(pdesc, 0);
@@ -481,6 +641,7 @@
 			default:
 				SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
 				break;
+
 			}
 		}
 
@@ -490,7 +651,7 @@
 		SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
 		SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
 		SET_TX_DESC_DISABLE_FB(pdesc, 0);
-		SET_TX_DESC_USE_RATE(pdesc, ptcdesc->use_driver_rate ? 1 : 0);
+		SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0);
 
 		if (ieee80211_is_data_qos(fc)) {
 			if (mac->rdg_en) {
@@ -510,18 +671,21 @@
 	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
 
 	if (rtlpriv->dm.useramask) {
-		SET_TX_DESC_RATE_ID(pdesc, ptcdesc->ratr_index);
-		SET_TX_DESC_MACID(pdesc, ptcdesc->mac_id);
+		SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index);
+		SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
 	} else {
-		SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcdesc->ratr_index);
-		SET_TX_DESC_MACID(pdesc, ptcdesc->ratr_index);
+		SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcb_desc->ratr_index);
+		SET_TX_DESC_MACID(pdesc, ptcb_desc->ratr_index);
 	}
 
 	if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) {
 		SET_TX_DESC_HWSEQ_EN_8723(pdesc, 1);
+		/* SET_TX_DESC_HWSEQ_EN(pdesc, 1); */
+		/* SET_TX_DESC_PKT_ID(pdesc, 8); */
 
-		if (!defaultadapter)
+		if (!b_defaultadapter)
 			SET_TX_DESC_HWSEQ_SEL_8723(pdesc, 1);
+	/* SET_TX_DESC_QOS(pdesc, 1); */
 	}
 
 	SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1));
@@ -534,17 +698,19 @@
 	RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n");
 }
 
-void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw,
+void rtl8723e_tx_fill_cmddesc(struct ieee80211_hw *hw,
 			      u8 *pdesc, bool firstseg,
 			      bool lastseg, struct sk_buff *skb)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
 	u8 fw_queue = QSLT_BEACON;
+
 	dma_addr_t mapping = pci_map_single(rtlpci->pdev,
 					    skb->data, skb->len,
 					    PCI_DMA_TODEVICE);
+
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
 	__le16 fc = hdr->frame_control;
 
 	if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
@@ -557,7 +723,7 @@
 	if (firstseg)
 		SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
 
-	SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M);
+	SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
 
 	SET_TX_DESC_SEQ(pdesc, 0);
 
@@ -577,7 +743,7 @@
 
 	SET_TX_DESC_OWN(pdesc, 1);
 
-	SET_TX_DESC_PKT_SIZE(pdesc, (u16) (skb->len));
+	SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len));
 
 	SET_TX_DESC_FIRST_SEG(pdesc, 1);
 	SET_TX_DESC_LAST_SEG(pdesc, 1);
@@ -597,8 +763,8 @@
 		      pdesc, TX_DESC_SIZE);
 }
 
-void rtl8723ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
-			u8 desc_name, u8 *val)
+void rtl8723e_set_desc(struct ieee80211_hw *hw, u8 *pdesc,
+		       bool istx, u8 desc_name, u8 *val)
 {
 	if (istx == true) {
 		switch (desc_name) {
@@ -635,7 +801,7 @@
 	}
 }
 
-u32 rtl8723ae_get_desc(u8 *pdesc, bool istx, u8 desc_name)
+u32 rtl8723e_get_desc(u8 *pdesc, bool istx, u8 desc_name)
 {
 	u32 ret = 0;
 
@@ -660,6 +826,9 @@
 		case HW_DESC_RXPKT_LEN:
 			ret = GET_RX_DESC_PKT_LEN(pdesc);
 			break;
+		case HW_DESC_RXBUFF_ADDR:
+			ret = GET_RX_DESC_BUFF_ADDR(pdesc);
+			break;
 		default:
 			RT_ASSERT(false, "ERR rxdesc :%d not process\n",
 				  desc_name);
@@ -669,7 +838,25 @@
 	return ret;
 }
 
-void rtl8723ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
+bool rtl8723e_is_tx_desc_closed(struct ieee80211_hw *hw,
+				u8 hw_queue, u16 index)
+{
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+	u8 *entry = (u8 *)(&ring->desc[ring->idx]);
+	u8 own = (u8)rtl8723e_get_desc(entry, true, HW_DESC_OWN);
+
+	/**
+	 *beacon packet will only use the first
+	 *descriptor defautly,and the own may not
+	 *be cleared by the hardware
+	 */
+	if (own)
+		return false;
+	return true;
+}
+
+void rtl8723e_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	if (hw_queue == BEACON_QUEUE) {
@@ -679,3 +866,10 @@
 			       BIT(0) << (hw_queue));
 	}
 }
+
+u32 rtl8723e_rx_command_packet(struct ieee80211_hw *hw,
+			       struct rtl_stats status,
+			       struct sk_buff *skb)
+{
+	return 0;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h
index 4380b7d..017da7e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -30,77 +26,77 @@
 #ifndef __RTL8723E_TRX_H__
 #define __RTL8723E_TRX_H__
 
-#define TX_DESC_SIZE				64
+#define TX_DESC_SIZE					64
 #define TX_DESC_AGGR_SUBFRAME_SIZE		32
 
-#define RX_DESC_SIZE				32
+#define RX_DESC_SIZE					32
 #define RX_DRV_INFO_SIZE_UNIT			8
 
 #define	TX_DESC_NEXT_DESC_OFFSET		40
 #define USB_HWDESC_HEADER_LEN			32
-#define CRCLENGTH				4
+#define CRCLENGTH						4
 
 #define SET_TX_DESC_PKT_SIZE(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val)
-#define SET_TX_DESC_OFFSET(__pdesc, __val)		\
+#define SET_TX_DESC_OFFSET(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val)
-#define SET_TX_DESC_BMC(__pdesc, __val)		\
+#define SET_TX_DESC_BMC(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val)
-#define SET_TX_DESC_HTC(__pdesc, __val)		\
+#define SET_TX_DESC_HTC(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val)
 #define SET_TX_DESC_LAST_SEG(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val)
 #define SET_TX_DESC_FIRST_SEG(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val)
-#define SET_TX_DESC_LINIP(__pdesc, __val)		\
+#define SET_TX_DESC_LINIP(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val)
-#define SET_TX_DESC_NO_ACM(__pdesc, __val)		\
+#define SET_TX_DESC_NO_ACM(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val)
-#define SET_TX_DESC_GF(__pdesc, __val)			\
+#define SET_TX_DESC_GF(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
-#define SET_TX_DESC_OWN(__pdesc, __val)		\
+#define SET_TX_DESC_OWN(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
 
-#define GET_TX_DESC_PKT_SIZE(__pdesc)			\
+#define GET_TX_DESC_PKT_SIZE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 0, 16)
-#define GET_TX_DESC_OFFSET(__pdesc)			\
+#define GET_TX_DESC_OFFSET(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 16, 8)
-#define GET_TX_DESC_BMC(__pdesc)			\
+#define GET_TX_DESC_BMC(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 24, 1)
-#define GET_TX_DESC_HTC(__pdesc)			\
+#define GET_TX_DESC_HTC(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 25, 1)
-#define GET_TX_DESC_LAST_SEG(__pdesc)			\
+#define GET_TX_DESC_LAST_SEG(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 26, 1)
-#define GET_TX_DESC_FIRST_SEG(__pdesc)			\
+#define GET_TX_DESC_FIRST_SEG(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 27, 1)
-#define GET_TX_DESC_LINIP(__pdesc)			\
+#define GET_TX_DESC_LINIP(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 28, 1)
-#define GET_TX_DESC_NO_ACM(__pdesc)			\
+#define GET_TX_DESC_NO_ACM(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 29, 1)
-#define GET_TX_DESC_GF(__pdesc)				\
+#define GET_TX_DESC_GF(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc, 30, 1)
-#define GET_TX_DESC_OWN(__pdesc)			\
+#define GET_TX_DESC_OWN(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 31, 1)
 
-#define SET_TX_DESC_MACID(__pdesc, __val)		\
+#define SET_TX_DESC_MACID(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 5, __val)
 #define SET_TX_DESC_AGG_BREAK(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 5, 1, __val)
-#define SET_TX_DESC_BK(__pdesc, __val)			\
+#define SET_TX_DESC_BK(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 6, 1, __val)
 #define SET_TX_DESC_RDG_ENABLE(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 7, 1, __val)
 #define SET_TX_DESC_QUEUE_SEL(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val)
-#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val)	\
+#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val)
 #define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val)	\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val)
-#define SET_TX_DESC_PIFS(__pdesc, __val)		\
+#define SET_TX_DESC_PIFS(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val)
 #define SET_TX_DESC_RATE_ID(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 4, __val)
-#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val)	\
+#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 20, 1, __val)
 #define SET_TX_DESC_EN_DESC_ID(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val)
@@ -109,34 +105,34 @@
 #define SET_TX_DESC_PKT_OFFSET(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 8, __val)
 
-#define GET_TX_DESC_MACID(__pdesc)			\
+#define GET_TX_DESC_MACID(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 0, 5)
-#define GET_TX_DESC_AGG_ENABLE(__pdesc)		\
+#define GET_TX_DESC_AGG_ENABLE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 5, 1)
-#define GET_TX_DESC_AGG_BREAK(__pdesc)			\
+#define GET_TX_DESC_AGG_BREAK(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 6, 1)
-#define GET_TX_DESC_RDG_ENABLE(__pdesc)		\
+#define GET_TX_DESC_RDG_ENABLE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 7, 1)
-#define GET_TX_DESC_QUEUE_SEL(__pdesc)			\
+#define GET_TX_DESC_QUEUE_SEL(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 8, 5)
-#define GET_TX_DESC_RDG_NAV_EXT(__pdesc)		\
+#define GET_TX_DESC_RDG_NAV_EXT(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+4, 13, 1)
-#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc)		\
+#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
-#define GET_TX_DESC_PIFS(__pdesc)			\
+#define GET_TX_DESC_PIFS(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
-#define GET_TX_DESC_RATE_ID(__pdesc)			\
+#define GET_TX_DESC_RATE_ID(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
-#define GET_TX_DESC_NAV_USE_HDR(__pdesc)		\
+#define GET_TX_DESC_NAV_USE_HDR(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+4, 20, 1)
-#define GET_TX_DESC_EN_DESC_ID(__pdesc)		\
+#define GET_TX_DESC_EN_DESC_ID(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 21, 1)
-#define GET_TX_DESC_SEC_TYPE(__pdesc)			\
+#define GET_TX_DESC_SEC_TYPE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 22, 2)
-#define GET_TX_DESC_PKT_OFFSET(__pdesc)		\
+#define GET_TX_DESC_PKT_OFFSET(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 24, 8)
 
-#define SET_TX_DESC_RTS_RC(__pdesc, __val)		\
+#define SET_TX_DESC_RTS_RC(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 6, __val)
 #define SET_TX_DESC_DATA_RC(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+8, 6, 6, __val)
@@ -144,9 +140,9 @@
 	SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val)
 #define SET_TX_DESC_MORE_FRAG(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val)
-#define SET_TX_DESC_RAW(__pdesc, __val)		\
+#define SET_TX_DESC_RAW(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val)
-#define SET_TX_DESC_CCX(__pdesc, __val)		\
+#define SET_TX_DESC_CCX(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val)
 #define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val)	\
 	SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val)
@@ -161,62 +157,62 @@
 #define SET_TX_DESC_TX_ANT_HT(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+8, 30, 2, __val)
 
-#define GET_TX_DESC_RTS_RC(__pdesc)			\
+#define GET_TX_DESC_RTS_RC(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 0, 6)
-#define GET_TX_DESC_DATA_RC(__pdesc)			\
+#define GET_TX_DESC_DATA_RC(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 6, 6)
-#define GET_TX_DESC_BAR_RTY_TH(__pdesc)		\
+#define GET_TX_DESC_BAR_RTY_TH(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 14, 2)
-#define GET_TX_DESC_MORE_FRAG(__pdesc)			\
+#define GET_TX_DESC_MORE_FRAG(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 17, 1)
-#define GET_TX_DESC_RAW(__pdesc)			\
+#define GET_TX_DESC_RAW(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 18, 1)
-#define GET_TX_DESC_CCX(__pdesc)			\
+#define GET_TX_DESC_CCX(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 19, 1)
-#define GET_TX_DESC_AMPDU_DENSITY(__pdesc)		\
+#define GET_TX_DESC_AMPDU_DENSITY(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+8, 20, 3)
-#define GET_TX_DESC_ANTSEL_A(__pdesc)			\
+#define GET_TX_DESC_ANTSEL_A(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 24, 1)
-#define GET_TX_DESC_ANTSEL_B(__pdesc)			\
+#define GET_TX_DESC_ANTSEL_B(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 25, 1)
-#define GET_TX_DESC_TX_ANT_CCK(__pdesc)		\
+#define GET_TX_DESC_TX_ANT_CCK(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 26, 2)
-#define GET_TX_DESC_TX_ANTL(__pdesc)			\
+#define GET_TX_DESC_TX_ANTL(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 28, 2)
-#define GET_TX_DESC_TX_ANT_HT(__pdesc)			\
+#define GET_TX_DESC_TX_ANT_HT(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 30, 2)
 
 #define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val)	\
 	SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 8, __val)
 #define SET_TX_DESC_TAIL_PAGE(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 8, __val)
-#define SET_TX_DESC_SEQ(__pdesc, __val)		\
+#define SET_TX_DESC_SEQ(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 12, __val)
-#define SET_TX_DESC_PKT_ID(__pdesc, __val)		\
+#define SET_TX_DESC_PKT_ID(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc+12, 28, 4, __val)
 
 #define GET_TX_DESC_NEXT_HEAP_PAGE(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+12, 0, 8)
-#define GET_TX_DESC_TAIL_PAGE(__pdesc)			\
+#define GET_TX_DESC_TAIL_PAGE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+12, 8, 8)
-#define GET_TX_DESC_SEQ(__pdesc)			\
+#define GET_TX_DESC_SEQ(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+12, 16, 12)
-#define GET_TX_DESC_PKT_ID(__pdesc)			\
+#define GET_TX_DESC_PKT_ID(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+12, 28, 4)
 
 /* For RTL8723 */
 #define SET_TX_DESC_TRIGGER_INT(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+12, 30, 1, __val)
-#define SET_TX_DESC_HWSEQ_EN_8723(__pdesc, __val)	\
+#define SET_TX_DESC_HWSEQ_EN_8723(__pdesc, __val)   \
 	SET_BITS_TO_LE_4BYTE(__pdesc+12, 31, 1, __val)
-#define SET_TX_DESC_HWSEQ_SEL_8723(__pTxDesc, __Value)	\
-	SET_BITS_TO_LE_4BYTE(__pTxDesc+16, 6, 2, __Value)
+#define SET_TX_DESC_HWSEQ_SEL_8723(__txdesc, __value) \
+	SET_BITS_TO_LE_4BYTE(__txdesc+16, 6, 2, __value)
 
 #define SET_TX_DESC_RTS_RATE(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 5, __val)
 #define SET_TX_DESC_AP_DCFE(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+16, 5, 1, __val)
-#define SET_TX_DESC_QOS(__pdesc, __val)		\
+#define SET_TX_DESC_QOS(__pdesc, __val)				\
 	SET_BITS_TO_LE_4BYTE(__pdesc+16, 6, 1, __val)
 #define SET_TX_DESC_HWSEQ_EN(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+16, 7, 1, __val)
@@ -248,54 +244,54 @@
 	SET_BITS_TO_LE_4BYTE(__pdesc+16, 25, 1, __val)
 #define SET_TX_DESC_RTS_SHORT(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+16, 26, 1, __val)
-#define SET_TX_DESC_RTS_BW(__pdesc, __val)		\
+#define SET_TX_DESC_RTS_BW(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc+16, 27, 1, __val)
-#define SET_TX_DESC_RTS_SC(__pdesc, __val)		\
+#define SET_TX_DESC_RTS_SC(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc+16, 28, 2, __val)
 #define SET_TX_DESC_RTS_STBC(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+16, 30, 2, __val)
 
-#define GET_TX_DESC_RTS_RATE(__pdesc)			\
+#define GET_TX_DESC_RTS_RATE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 0, 5)
-#define GET_TX_DESC_AP_DCFE(__pdesc)			\
+#define GET_TX_DESC_AP_DCFE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 5, 1)
-#define GET_TX_DESC_QOS(__pdesc)			\
+#define GET_TX_DESC_QOS(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 6, 1)
-#define GET_TX_DESC_HWSEQ_EN(__pdesc)			\
+#define GET_TX_DESC_HWSEQ_EN(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 7, 1)
-#define GET_TX_DESC_USE_RATE(__pdesc)			\
+#define GET_TX_DESC_USE_RATE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 8, 1)
 #define GET_TX_DESC_DISABLE_RTS_FB(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+16, 9, 1)
-#define GET_TX_DESC_DISABLE_FB(__pdesc)		\
+#define GET_TX_DESC_DISABLE_FB(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 10, 1)
-#define GET_TX_DESC_CTS2SELF(__pdesc)			\
+#define GET_TX_DESC_CTS2SELF(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 11, 1)
-#define GET_TX_DESC_RTS_ENABLE(__pdesc)		\
+#define GET_TX_DESC_RTS_ENABLE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 12, 1)
-#define GET_TX_DESC_HW_RTS_ENABLE(__pdesc)		\
+#define GET_TX_DESC_HW_RTS_ENABLE(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+16, 13, 1)
-#define GET_TX_DESC_PORT_ID(__pdesc)			\
+#define GET_TX_DESC_PORT_ID(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 14, 1)
-#define GET_TX_DESC_WAIT_DCTS(__pdesc)			\
+#define GET_TX_DESC_WAIT_DCTS(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 18, 1)
-#define GET_TX_DESC_CTS2AP_EN(__pdesc)			\
+#define GET_TX_DESC_CTS2AP_EN(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 19, 1)
 #define GET_TX_DESC_TX_SUB_CARRIER(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+16, 20, 2)
-#define GET_TX_DESC_TX_STBC(__pdesc)			\
+#define GET_TX_DESC_TX_STBC(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 22, 2)
-#define GET_TX_DESC_DATA_SHORT(__pdesc)		\
+#define GET_TX_DESC_DATA_SHORT(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 24, 1)
-#define GET_TX_DESC_DATA_BW(__pdesc)			\
+#define GET_TX_DESC_DATA_BW(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 25, 1)
-#define GET_TX_DESC_RTS_SHORT(__pdesc)			\
+#define GET_TX_DESC_RTS_SHORT(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 26, 1)
-#define GET_TX_DESC_RTS_BW(__pdesc)			\
+#define GET_TX_DESC_RTS_BW(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 27, 1)
-#define GET_TX_DESC_RTS_SC(__pdesc)			\
+#define GET_TX_DESC_RTS_SC(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 28, 2)
-#define GET_TX_DESC_RTS_STBC(__pdesc)			\
+#define GET_TX_DESC_RTS_STBC(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 30, 2)
 
 #define SET_TX_DESC_TX_RATE(__pdesc, __val)		\
@@ -315,17 +311,17 @@
 #define SET_TX_DESC_USB_TXAGG_NUM(__pdesc, __val)	\
 	SET_BITS_TO_LE_4BYTE(__pdesc+20, 24, 8, __val)
 
-#define GET_TX_DESC_TX_RATE(__pdesc)			\
+#define GET_TX_DESC_TX_RATE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+20, 0, 6)
-#define GET_TX_DESC_DATA_SHORTGI(__pdesc)		\
+#define GET_TX_DESC_DATA_SHORTGI(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+20, 6, 1)
-#define GET_TX_DESC_CCX_TAG(__pdesc)			\
+#define GET_TX_DESC_CCX_TAG(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+20, 7, 1)
-#define GET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc)	\
+#define GET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+20, 8, 5)
 #define GET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+20, 13, 4)
-#define GET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc)	\
+#define GET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+20, 17, 1)
 #define GET_TX_DESC_DATA_RETRY_LIMIT(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+20, 18, 6)
@@ -336,9 +332,9 @@
 	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 5, __val)
 #define SET_TX_DESC_TXAGC_B(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+24, 5, 5, __val)
-#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val)	\
+#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+24, 10, 1, __val)
-#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val)	\
+#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val)		\
 	SET_BITS_TO_LE_4BYTE(__pdesc+24, 11, 5, __val)
 #define SET_TX_DESC_MCSG1_MAX_LEN(__pdesc, __val)	\
 	SET_BITS_TO_LE_4BYTE(__pdesc+24, 16, 4, __val)
@@ -349,19 +345,19 @@
 #define SET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc, __val)\
 	SET_BITS_TO_LE_4BYTE(__pdesc+24, 28, 4, __val)
 
-#define GET_TX_DESC_TXAGC_A(__pdesc)			\
+#define GET_TX_DESC_TXAGC_A(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+24, 0, 5)
-#define GET_TX_DESC_TXAGC_B(__pdesc)			\
+#define GET_TX_DESC_TXAGC_B(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+24, 5, 5)
-#define GET_TX_DESC_USE_MAX_LEN(__pdesc)		\
+#define GET_TX_DESC_USE_MAX_LEN(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+24, 10, 1)
-#define GET_TX_DESC_MAX_AGG_NUM(__pdesc)		\
+#define GET_TX_DESC_MAX_AGG_NUM(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+24, 11, 5)
-#define GET_TX_DESC_MCSG1_MAX_LEN(__pdesc)		\
+#define GET_TX_DESC_MCSG1_MAX_LEN(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+24, 16, 4)
-#define GET_TX_DESC_MCSG2_MAX_LEN(__pdesc)		\
+#define GET_TX_DESC_MCSG2_MAX_LEN(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+24, 20, 4)
-#define GET_TX_DESC_MCSG3_MAX_LEN(__pdesc)		\
+#define GET_TX_DESC_MCSG3_MAX_LEN(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+24, 24, 4)
 #define GET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+24, 28, 4)
@@ -379,11 +375,11 @@
 
 #define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+28, 0, 16)
-#define GET_TX_DESC_MCSG4_MAX_LEN(__pdesc)		\
+#define GET_TX_DESC_MCSG4_MAX_LEN(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+28, 16, 4)
-#define GET_TX_DESC_MCSG5_MAX_LEN(__pdesc)		\
+#define GET_TX_DESC_MCSG5_MAX_LEN(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+28, 20, 4)
-#define GET_TX_DESC_MCSG6_MAX_LEN(__pdesc)		\
+#define GET_TX_DESC_MCSG6_MAX_LEN(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+28, 24, 4)
 #define GET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+28, 28, 4)
@@ -395,7 +391,7 @@
 
 #define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+32, 0, 32)
-#define GET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc)	\
+#define GET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+36, 0, 32)
 
 #define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val)	\
@@ -410,97 +406,97 @@
 
 #define GET_RX_DESC_PKT_LEN(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc, 0, 14)
-#define GET_RX_DESC_CRC32(__pdesc)			\
+#define GET_RX_DESC_CRC32(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 14, 1)
-#define GET_RX_DESC_ICV(__pdesc)			\
+#define GET_RX_DESC_ICV(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 15, 1)
 #define GET_RX_DESC_DRV_INFO_SIZE(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc, 16, 4)
 #define GET_RX_DESC_SECURITY(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc, 20, 3)
-#define GET_RX_DESC_QOS(__pdesc)			\
+#define GET_RX_DESC_QOS(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 23, 1)
-#define GET_RX_DESC_SHIFT(__pdesc)			\
+#define GET_RX_DESC_SHIFT(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 24, 2)
-#define GET_RX_DESC_PHYST(__pdesc)			\
+#define GET_RX_DESC_PHYST(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 26, 1)
-#define GET_RX_DESC_SWDEC(__pdesc)			\
+#define GET_RX_DESC_SWDEC(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 27, 1)
-#define GET_RX_DESC_LS(__pdesc)				\
+#define GET_RX_DESC_LS(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc, 28, 1)
-#define GET_RX_DESC_FS(__pdesc)				\
+#define GET_RX_DESC_FS(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc, 29, 1)
-#define GET_RX_DESC_EOR(__pdesc)			\
+#define GET_RX_DESC_EOR(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 30, 1)
-#define GET_RX_DESC_OWN(__pdesc)			\
+#define GET_RX_DESC_OWN(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc, 31, 1)
 
-#define SET_RX_DESC_PKT_LEN(__pdesc, __val)		\
+#define SET_RX_DESC_PKT_LEN(__pdesc, __val)	\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val)
 #define SET_RX_DESC_EOR(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
 #define SET_RX_DESC_OWN(__pdesc, __val)			\
 	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
 
-#define GET_RX_DESC_MACID(__pdesc)			\
+#define GET_RX_DESC_MACID(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 0, 5)
-#define GET_RX_DESC_TID(__pdesc)			\
+#define GET_RX_DESC_TID(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 5, 4)
 #define GET_RX_DESC_HWRSVD(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+4, 9, 5)
-#define GET_RX_DESC_PAGGR(__pdesc)			\
+#define GET_RX_DESC_PAGGR(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
-#define GET_RX_DESC_FAGGR(__pdesc)			\
+#define GET_RX_DESC_FAGGR(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
 #define GET_RX_DESC_A1_FIT(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
 #define GET_RX_DESC_A2_FIT(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+4, 20, 4)
-#define GET_RX_DESC_PAM(__pdesc)			\
+#define GET_RX_DESC_PAM(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 24, 1)
-#define GET_RX_DESC_PWR(__pdesc)			\
+#define GET_RX_DESC_PWR(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 25, 1)
-#define GET_RX_DESC_MD(__pdesc)				\
+#define GET_RX_DESC_MD(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc+4, 26, 1)
-#define GET_RX_DESC_MF(__pdesc)				\
+#define GET_RX_DESC_MF(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc+4, 27, 1)
-#define GET_RX_DESC_TYPE(__pdesc)			\
+#define GET_RX_DESC_TYPE(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+4, 28, 2)
-#define GET_RX_DESC_MC(__pdesc)				\
+#define GET_RX_DESC_MC(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc+4, 30, 1)
-#define GET_RX_DESC_BC(__pdesc)				\
+#define GET_RX_DESC_BC(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc+4, 31, 1)
-#define GET_RX_DESC_SEQ(__pdesc)			\
+#define GET_RX_DESC_SEQ(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 0, 12)
-#define GET_RX_DESC_FRAG(__pdesc)			\
+#define GET_RX_DESC_FRAG(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 12, 4)
 #define GET_RX_DESC_NEXT_PKT_LEN(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+8, 16, 14)
 #define GET_RX_DESC_NEXT_IND(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+8, 30, 1)
-#define GET_RX_DESC_RSVD(__pdesc)			\
+#define GET_RX_DESC_RSVD(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+8, 31, 1)
 
-#define GET_RX_DESC_RXMCS(__pdesc)			\
+#define GET_RX_DESC_RXMCS(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+12, 0, 6)
-#define GET_RX_DESC_RXHT(__pdesc)			\
+#define GET_RX_DESC_RXHT(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+12, 6, 1)
-#define GET_RX_DESC_SPLCP(__pdesc)			\
+#define GET_RX_DESC_SPLCP(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+12, 8, 1)
-#define GET_RX_DESC_BW(__pdesc)				\
+#define GET_RX_DESC_BW(__pdesc)					\
 	LE_BITS_TO_4BYTE(__pdesc+12, 9, 1)
-#define GET_RX_DESC_HTC(__pdesc)			\
+#define GET_RX_DESC_HTC(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+12, 10, 1)
 #define GET_RX_DESC_HWPC_ERR(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+12, 14, 1)
 #define GET_RX_DESC_HWPC_IND(__pdesc)			\
 	LE_BITS_TO_4BYTE(__pdesc+12, 15, 1)
-#define GET_RX_DESC_IV0(__pdesc)			\
+#define GET_RX_DESC_IV0(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+12, 16, 16)
 
-#define GET_RX_DESC_IV1(__pdesc)			\
+#define GET_RX_DESC_IV1(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+16, 0, 32)
-#define GET_RX_DESC_TSFL(__pdesc)			\
+#define GET_RX_DESC_TSFL(__pdesc)				\
 	LE_BITS_TO_4BYTE(__pdesc+20, 0, 32)
 
 #define GET_RX_DESC_BUFF_ADDR(__pdesc)			\
@@ -508,17 +504,17 @@
 #define GET_RX_DESC_BUFF_ADDR64(__pdesc)		\
 	LE_BITS_TO_4BYTE(__pdesc+28, 0, 32)
 
-#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val)		\
+#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val)	\
 	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val)
-#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val)		\
+#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) \
 	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val)
 
-#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size)	\
-do {							\
-	if (_size > TX_DESC_NEXT_DESC_OFFSET)		\
+#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size)		\
+do {								\
+	if (_size > TX_DESC_NEXT_DESC_OFFSET)			\
 		memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET);	\
-	else						\
-		memset(__pdesc, 0, _size);		\
+	else							\
+		memset(__pdesc, 0, _size);			\
 } while (0)
 
 struct rx_fwinfo_8723e {
@@ -699,22 +695,27 @@
 
 } __packed;
 
-void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
-			    struct ieee80211_hdr *hdr, u8 *pdesc,
-			    u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
-			    struct ieee80211_sta *sta,
-			    struct sk_buff *skb, u8 hw_queue,
-			    struct rtl_tcb_desc *ptcb_desc);
-bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
-			     struct rtl_stats *status,
-			     struct ieee80211_rx_status *rx_status,
-			     u8 *pdesc, struct sk_buff *skb);
-void rtl8723ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
-			u8 desc_name, u8 *val);
-u32 rtl8723ae_get_desc(u8 *pdesc, bool istx, u8 desc_name);
-void rtl8723ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
-void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
-			       bool b_firstseg, bool b_lastseg,
+void rtl8723e_tx_fill_desc(struct ieee80211_hw *hw,
+			   struct ieee80211_hdr *hdr,
+			   u8 *pdesc, u8 *txbd,
+			   struct ieee80211_tx_info *info,
+			   struct ieee80211_sta *sta,
+			   struct sk_buff *skb, u8 hw_queue,
+			   struct rtl_tcb_desc *ptcb_desc);
+bool rtl8723e_rx_query_desc(struct ieee80211_hw *hw,
+			    struct rtl_stats *status,
+			    struct ieee80211_rx_status *rx_status,
+			    u8 *pdesc, struct sk_buff *skb);
+void rtl8723e_set_desc(struct ieee80211_hw *hw,
+		       u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+u32 rtl8723e_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+bool rtl8723e_is_tx_desc_closed(struct ieee80211_hw *hw,
+				u8 hw_queue, u16 index);
+void rtl8723e_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
+void rtl8723e_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+			      bool firstseg, bool lastseg,
+			      struct sk_buff *skb);
+u32 rtl8723e_rx_command_packet(struct ieee80211_hw *hw,
+			       struct rtl_stats status,
 			       struct sk_buff *skb);
-
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/def.h b/drivers/net/wireless/rtlwifi/rtl8723be/def.h
index 3c30b74..025ea5c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/def.h
@@ -26,158 +26,24 @@
 #ifndef __RTL8723BE_DEF_H__
 #define __RTL8723BE_DEF_H__
 
-#define HAL_RETRY_LIMIT_INFRA				48
-#define HAL_RETRY_LIMIT_AP_ADHOC			7
-
-#define RESET_DELAY_8185				20
-
-#define RT_IBSS_INT_MASKS	(IMR_BCNINT | IMR_TBDOK | IMR_TBDER)
-#define RT_AC_INT_MASKS		(IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK)
-
-#define NUM_OF_FIRMWARE_QUEUE			10
-#define NUM_OF_PAGES_IN_FW			0x100
-#define NUM_OF_PAGE_IN_FW_QUEUE_BK		0x07
-#define NUM_OF_PAGE_IN_FW_QUEUE_BE		0x07
-#define NUM_OF_PAGE_IN_FW_QUEUE_VI		0x07
-#define NUM_OF_PAGE_IN_FW_QUEUE_VO		0x07
-#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA		0x0
-#define NUM_OF_PAGE_IN_FW_QUEUE_CMD		0x0
-#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT		0x02
-#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH		0x02
-#define NUM_OF_PAGE_IN_FW_QUEUE_BCN		0x2
-#define NUM_OF_PAGE_IN_FW_QUEUE_PUB		0xA1
-
-#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM		0x026
-#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM		0x048
-#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM		0x048
-#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM		0x026
-#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM		0x00
-
-#define MAX_LINES_HWCONFIG_TXT			1000
-#define MAX_BYTES_LINE_HWCONFIG_TXT		256
-
-#define SW_THREE_WIRE				0
-#define HW_THREE_WIRE				2
-
-#define BT_DEMO_BOARD				0
-#define BT_QA_BOARD				1
-#define BT_FPGA					2
-
 #define HAL_PRIME_CHNL_OFFSET_DONT_CARE		0
 #define HAL_PRIME_CHNL_OFFSET_LOWER		1
 #define HAL_PRIME_CHNL_OFFSET_UPPER		2
 
-#define MAX_H2C_QUEUE_NUM			10
 
 #define RX_MPDU_QUEUE				0
-#define RX_CMD_QUEUE				1
-#define RX_MAX_QUEUE				2
-#define AC2QUEUEID(_AC)				(_AC)
+#define CHIP_8723B				(BIT(1) | BIT(2))
+#define NORMAL_CHIP				BIT(3)
+#define CHIP_VENDOR_SMIC			BIT(8)
+/* Currently only for RTL8723B */
+#define EXT_VENDOR_ID				(BIT(18) | BIT(19))
 
-#define	C2H_RX_CMD_HDR_LEN			8
-#define	GET_C2H_CMD_CMD_LEN(__prxhdr)		\
-	LE_BITS_TO_4BYTE((__prxhdr), 0, 16)
-#define	GET_C2H_CMD_ELEMENT_ID(__prxhdr)	\
-	LE_BITS_TO_4BYTE((__prxhdr), 16, 8)
-#define	GET_C2H_CMD_CMD_SEQ(__prxhdr)		\
-	LE_BITS_TO_4BYTE((__prxhdr), 24, 7)
-#define	GET_C2H_CMD_CONTINUE(__prxhdr)		\
-	LE_BITS_TO_4BYTE((__prxhdr), 31, 1)
-#define	GET_C2H_CMD_CONTENT(__prxhdr)		\
-	((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN)
-
-#define	GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr)	\
-	LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8)
-#define	GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr)	\
-	LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8)
-#define	GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr)	\
-	LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16)
-#define	GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr)	\
-	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5)
-#define	GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr)	\
-	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1)
-#define	GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr)	\
-	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5)
-#define	GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr)	\
-	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1)
-#define	GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr)	\
-	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4)
-#define	GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr)	\
-	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12)
-
-#define CHIP_BONDING_IDENTIFIER(_value)	(((_value)>>22)&0x3)
-#define	CHIP_BONDING_92C_1T2R		0x1
-
-#define CHIP_8723			BIT(0)
-#define CHIP_8723B			(BIT(1) | BIT(2))
-#define NORMAL_CHIP			BIT(3)
-#define RF_TYPE_1T1R			(~(BIT(4) | BIT(5) | BIT(6)))
-#define RF_TYPE_1T2R			BIT(4)
-#define RF_TYPE_2T2R			BIT(5)
-#define CHIP_VENDOR_UMC			BIT(7)
-#define B_CUT_VERSION			BIT(12)
-#define C_CUT_VERSION			BIT(13)
-#define D_CUT_VERSION			((BIT(12) | BIT(13)))
-#define E_CUT_VERSION			BIT(14)
-#define	RF_RL_ID			(BIT(31) | BIT(30) | BIT(29) | BIT(28))
-
-/* MASK */
-#define IC_TYPE_MASK			(BIT(0) | BIT(1) | BIT(2))
-#define CHIP_TYPE_MASK			BIT(3)
-#define RF_TYPE_MASK			(BIT(4) | BIT(5) | BIT(6))
-#define MANUFACTUER_MASK		BIT(7)
-#define ROM_VERSION_MASK		(BIT(11) | BIT(10) | BIT(9) | BIT(8))
-#define CUT_VERSION_MASK		(BIT(15) | BIT(14) | BIT(13) | BIT(12))
-
-/* Get element */
-#define GET_CVID_IC_TYPE(version)	((version) & IC_TYPE_MASK)
-#define GET_CVID_CHIP_TYPE(version)	((version) & CHIP_TYPE_MASK)
-#define GET_CVID_RF_TYPE(version)	((version) & RF_TYPE_MASK)
-#define GET_CVID_MANUFACTUER(version)	((version) & MANUFACTUER_MASK)
-#define GET_CVID_ROM_VERSION(version)	((version) & ROM_VERSION_MASK)
-#define GET_CVID_CUT_VERSION(version)	((version) & CUT_VERSION_MASK)
-
-#define IS_92C_SERIAL(version)   ((IS_81XXC(version) && IS_2T2R(version)) ?\
-								true : false)
-#define IS_81XXC(version)	((GET_CVID_IC_TYPE(version) == 0) ?\
-							true : false)
-#define IS_8723_SERIES(version)	((GET_CVID_IC_TYPE(version) == CHIP_8723) ?\
-							true : false)
-#define IS_1T1R(version)	((GET_CVID_RF_TYPE(version)) ? false : true)
-#define IS_1T2R(version)	((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R)\
-							? true : false)
-#define IS_2T2R(version)	((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R)\
-							? true : false)
-enum rf_optype {
-	RF_OP_BY_SW_3WIRE = 0,
-	RF_OP_BY_FW,
-	RF_OP_MAX
-};
-
-enum rf_power_state {
-	RF_ON,
-	RF_OFF,
-	RF_SLEEP,
-	RF_SHUT_DOWN,
-};
-
-enum power_save_mode {
-	POWER_SAVE_MODE_ACTIVE,
-	POWER_SAVE_MODE_SAVE,
-};
-
-enum power_polocy_config {
-	POWERCFG_MAX_POWER_SAVINGS,
-	POWERCFG_GLOBAL_POWER_SAVINGS,
-	POWERCFG_LOCAL_POWER_SAVINGS,
-	POWERCFG_LENOVO,
-};
-
-enum interface_select_pci {
-	INTF_SEL1_MINICARD = 0,
-	INTF_SEL0_PCIE = 1,
-	INTF_SEL2_RSV = 2,
-	INTF_SEL3_RSV = 3,
+enum rx_packet_type {
+	NORMAL_RX,
+	TX_REPORT1,
+	TX_REPORT2,
+	HIS_REPORT,
+	C2H_PACKET,
 };
 
 enum rtl_desc_qsel {
@@ -222,27 +88,5 @@
 	DESC92C_RATEMCS13 = 0x19,
 	DESC92C_RATEMCS14 = 0x1a,
 	DESC92C_RATEMCS15 = 0x1b,
-	DESC92C_RATEMCS15_SG = 0x1c,
-	DESC92C_RATEMCS32 = 0x20,
 };
-
-enum rx_packet_type {
-	NORMAL_RX,
-	TX_REPORT1,
-	TX_REPORT2,
-	HIS_REPORT,
-};
-
-struct phy_sts_cck_8723e_t {
-	u8 adc_pwdb_X[4];
-	u8 sq_rpt;
-	u8 cck_agc_rpt;
-};
-
-struct h2c_cmd_8723e {
-	u8 element_id;
-	u32 cmd_len;
-	u8 *p_cmdbuffer;
-};
-
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
index 13d53a1..dd7eb43 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
@@ -32,7 +32,6 @@
 #include "dm.h"
 #include "../rtl8723com/dm_common.h"
 #include "fw.h"
-#include "../rtl8723com/fw_common.h"
 #include "trx.h"
 #include "../btcoexist/rtl_btc.h"
 
@@ -209,7 +208,7 @@
 		pwr_val = TXPWRTRACK_MAX_IDX;
 
 	*poutwrite_val = pwr_val | (pwr_val << 8) |
-			(pwr_val << 16) | (pwr_val << 24);
+		(pwr_val << 16) | (pwr_val << 24);
 }
 
 static void rtl8723be_dm_diginit(struct ieee80211_hw *hw)
@@ -218,8 +217,7 @@
 	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
 	dm_digtable->dig_enable_flag = true;
-	dm_digtable->cur_igvalue = rtl_get_bbreg(hw,
-		ROFDM0_XAAGCCORE1, 0x7f);
+	dm_digtable->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f);
 	dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
 	dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
 	dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
@@ -234,8 +232,8 @@
 	dm_digtable->forbidden_igi = DM_DIG_MIN;
 	dm_digtable->large_fa_hit = 0;
 	dm_digtable->recover_cnt = 0;
-	dm_digtable->dig_min_0 = DM_DIG_MIN;
-	dm_digtable->dig_min_1 = DM_DIG_MIN;
+	dm_digtable->dig_dynamic_min = DM_DIG_MIN;
+	dm_digtable->dig_dynamic_min_1 = DM_DIG_MIN;
 	dm_digtable->media_connect_0 = false;
 	dm_digtable->media_connect_1 = false;
 	rtlpriv->dm.dm_initialgain_enable = true;
@@ -245,18 +243,18 @@
 void rtl8723be_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rate_adaptive *ra = &(rtlpriv->ra);
+	struct rate_adaptive *p_ra = &rtlpriv->ra;
 
-	ra->ratr_state = DM_RATR_STA_INIT;
-	ra->pre_ratr_state = DM_RATR_STA_INIT;
+	p_ra->ratr_state = DM_RATR_STA_INIT;
+	p_ra->pre_ratr_state = DM_RATR_STA_INIT;
 
 	if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
 		rtlpriv->dm.useramask = true;
 	else
 		rtlpriv->dm.useramask = false;
 
-	ra->high_rssi_thresh_for_ra = 50;
-	ra->low_rssi_thresh_for_ra40m = 20;
+	p_ra->high_rssi_thresh_for_ra = 50;
+	p_ra->low_rssi_thresh_for_ra40m = 20;
 }
 
 static void rtl8723be_dm_init_txpower_tracking(struct ieee80211_hw *hw)
@@ -279,7 +277,7 @@
 
 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
 		 "  rtlpriv->dm.txpower_tracking = %d\n",
-		 rtlpriv->dm.txpower_tracking);
+		  rtlpriv->dm.txpower_tracking);
 }
 
 static void rtl8723be_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw)
@@ -287,6 +285,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	rtlpriv->dm.crystal_cap = rtlpriv->efuse.crystalcap;
+
 	rtlpriv->dm.atc_status = rtl_get_bbreg(hw, ROFDM1_CFOTRACKING, 0x800);
 	rtlpriv->dm.cfo_threshold = CFO_THRESHOLD_XTAL;
 }
@@ -308,7 +307,7 @@
 static void rtl8723be_dm_find_minimum_rssi(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct dig_t *rtl_dm_dig = &(rtlpriv->dm_digtable);
+	struct dig_t *rtl_dm_dig = &rtlpriv->dm_digtable;
 	struct rtl_mac *mac = rtl_mac(rtlpriv);
 
 	/* Determine the minimum RSSI  */
@@ -325,20 +324,20 @@
 			    rtlpriv->dm.entry_min_undec_sm_pwdb;
 			RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
 				 "AP Client PWDB = 0x%lx\n",
-				 rtlpriv->dm.entry_min_undec_sm_pwdb);
+			       rtlpriv->dm.entry_min_undec_sm_pwdb);
 		} else {
 			rtl_dm_dig->min_undec_pwdb_for_dm =
 			    rtlpriv->dm.undec_sm_pwdb;
 			RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
 				 "STA Default Port PWDB = 0x%x\n",
-				 rtl_dm_dig->min_undec_pwdb_for_dm);
+				  rtl_dm_dig->min_undec_pwdb_for_dm);
 		}
 	} else {
 		rtl_dm_dig->min_undec_pwdb_for_dm =
 				rtlpriv->dm.entry_min_undec_sm_pwdb;
 		RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
 			 "AP Ext Port or disconnet PWDB = 0x%x\n",
-			 rtl_dm_dig->min_undec_pwdb_for_dm);
+			  rtl_dm_dig->min_undec_pwdb_for_dm);
 	}
 	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "MinUndecoratedPWDBForDM =%d\n",
 		 rtl_dm_dig->min_undec_pwdb_for_dm);
@@ -347,6 +346,7 @@
 static void rtl8723be_dm_check_rssi_monitor(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 	struct rtl_sta_info *drv_priv;
 	u8 h2c_parameter[3] = { 0 };
 	long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff;
@@ -367,69 +367,78 @@
 
 	/* If associated entry is found */
 	if (tmp_entry_max_pwdb != 0) {
-		rtlpriv->dm.entry_max_undec_sm_pwdb = tmp_entry_max_pwdb;
-		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
-			 "EntryMaxPWDB = 0x%lx(%ld)\n",
+		rtlpriv->dm.entry_max_undec_sm_pwdb =
+							tmp_entry_max_pwdb;
+		RTPRINT(rtlpriv, FDM, DM_PWDB,
+			"EntryMaxPWDB = 0x%lx(%ld)\n",
 			 tmp_entry_max_pwdb, tmp_entry_max_pwdb);
 	} else {
 		rtlpriv->dm.entry_max_undec_sm_pwdb = 0;
 	}
 	/* If associated entry is found */
 	if (tmp_entry_min_pwdb != 0xff) {
-		rtlpriv->dm.entry_min_undec_sm_pwdb = tmp_entry_min_pwdb;
-		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
-			 "EntryMinPWDB = 0x%lx(%ld)\n",
+		rtlpriv->dm.entry_min_undec_sm_pwdb =
+							tmp_entry_min_pwdb;
+		RTPRINT(rtlpriv, FDM, DM_PWDB,
+			"EntryMinPWDB = 0x%lx(%ld)\n",
 			 tmp_entry_min_pwdb, tmp_entry_min_pwdb);
 	} else {
 		rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
 	}
 	/* Indicate Rx signal strength to FW. */
 	if (rtlpriv->dm.useramask) {
-		h2c_parameter[2] = (u8) (rtlpriv->dm.undec_sm_pwdb & 0xFF);
+		h2c_parameter[2] =
+			(u8)(rtlpriv->dm.undec_sm_pwdb & 0xFF);
 		h2c_parameter[1] = 0x20;
 		h2c_parameter[0] = 0;
-		rtl8723be_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter);
+		rtl8723be_fill_h2c_cmd(hw, H2C_RSSIBE_REPORT, 3, h2c_parameter);
 	} else {
-		rtl_write_byte(rtlpriv, 0x4fe, rtlpriv->dm.undec_sm_pwdb);
+		rtl_write_byte(rtlpriv, 0x4fe,
+			       rtlpriv->dm.undec_sm_pwdb);
 	}
 	rtl8723be_dm_find_minimum_rssi(hw);
-	rtlpriv->dm_digtable.rssi_val_min =
-		rtlpriv->dm_digtable.min_undec_pwdb_for_dm;
+	dm_digtable->rssi_val_min =
+			rtlpriv->dm_digtable.min_undec_pwdb_for_dm;
 }
 
 void rtl8723be_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 
-	if (rtlpriv->dm_digtable.cur_igvalue != current_igi) {
+	if (dm_digtable->stop_dig)
+		return;
+
+	if (dm_digtable->cur_igvalue != current_igi) {
 		rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, current_igi);
 		if (rtlpriv->phy.rf_type != RF_1T1R)
-			rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, current_igi);
+			rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1,
+				      0x7f, current_igi);
 	}
-	rtlpriv->dm_digtable.pre_igvalue = rtlpriv->dm_digtable.cur_igvalue;
-	rtlpriv->dm_digtable.cur_igvalue = current_igi;
+	dm_digtable->pre_igvalue = dm_digtable->cur_igvalue;
+	dm_digtable->cur_igvalue = current_igi;
 }
 
 static void rtl8723be_dm_dig(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	struct dig_t *dm_digtable = &(rtlpriv->dm_digtable);
 	u8 dig_dynamic_min, dig_maxofmin;
-	bool firstconnect, firstdisconnect;
+	bool bfirstconnect, bfirstdisconnect;
 	u8 dm_dig_max, dm_dig_min;
 	u8 current_igi = dm_digtable->cur_igvalue;
 	u8 offset;
 
-	/* AP, BT */
+	/* AP,BT */
 	if (mac->act_scanning)
 		return;
 
-	dig_dynamic_min = dm_digtable->dig_min_0;
-	firstconnect = (mac->link_state >= MAC80211_LINKED) &&
+	dig_dynamic_min = dm_digtable->dig_dynamic_min;
+	bfirstconnect = (mac->link_state >= MAC80211_LINKED) &&
 			!dm_digtable->media_connect_0;
-	firstdisconnect = (mac->link_state < MAC80211_LINKED) &&
-			   dm_digtable->media_connect_0;
+	bfirstdisconnect = (mac->link_state < MAC80211_LINKED) &&
+			(dm_digtable->media_connect_0);
 
 	dm_dig_max = 0x5a;
 	dm_dig_min = DM_DIG_MIN;
@@ -457,6 +466,7 @@
 		} else {
 			dig_dynamic_min = dm_dig_min;
 		}
+
 	} else {
 		dm_digtable->rx_gain_max = dm_dig_max;
 		dig_dynamic_min = dm_dig_min;
@@ -506,7 +516,7 @@
 		dm_digtable->rx_gain_min = dm_digtable->rx_gain_max;
 
 	if (mac->link_state >= MAC80211_LINKED) {
-		if (firstconnect) {
+		if (bfirstconnect) {
 			if (dm_digtable->rssi_val_min <= dig_maxofmin)
 				current_igi = dm_digtable->rssi_val_min;
 			else
@@ -522,7 +532,7 @@
 				current_igi -= 2;
 		}
 	} else {
-		if (firstdisconnect) {
+		if (bfirstdisconnect) {
 			current_igi = dm_digtable->rx_gain_min;
 		} else {
 			if (rtlpriv->falsealm_cnt.cnt_all > 10000)
@@ -542,14 +552,15 @@
 	rtl8723be_dm_write_dig(hw, current_igi);
 	dm_digtable->media_connect_0 =
 		((mac->link_state >= MAC80211_LINKED) ? true : false);
-	dm_digtable->dig_min_0 = dig_dynamic_min;
+	dm_digtable->dig_dynamic_min = dig_dynamic_min;
 }
 
-static void rtl8723be_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
+static void rtl8723be_dm_false_alarm_counter_statistics(
+					struct ieee80211_hw *hw)
 {
 	u32 ret_value;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
+	struct false_alarm_statistics *falsealm_cnt = &rtlpriv->falsealm_cnt;
 
 	rtl_set_bbreg(hw, DM_REG_OFDM_FA_HOLDC_11N, BIT(31), 1);
 	rtl_set_bbreg(hw, DM_REG_OFDM_FA_RSTD_11N, BIT(31), 1);
@@ -615,16 +626,14 @@
 	rtl_set_bbreg(hw, DM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 2);
 
 	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
-		 "cnt_parity_fail = %d, cnt_rate_illegal = %d, "
-		 "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
+		 "cnt_parity_fail = %d, cnt_rate_illegal = %d, cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
 		 falsealm_cnt->cnt_parity_fail,
 		 falsealm_cnt->cnt_rate_illegal,
 		 falsealm_cnt->cnt_crc8_fail,
 		 falsealm_cnt->cnt_mcs_fail);
 
 	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
-		 "cnt_ofdm_fail = %x, cnt_cck_fail = %x,"
-		 " cnt_all = %x\n",
+		 "cnt_ofdm_fail = %x, cnt_cck_fail = %x, cnt_all = %x\n",
 		 falsealm_cnt->cnt_ofdm_fail,
 		 falsealm_cnt->cnt_cck_fail,
 		 falsealm_cnt->cnt_all);
@@ -690,7 +699,7 @@
 					u8 rfpath, u8 idx)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
 	u8 swing_idx_ofdm_limit = 36;
 
@@ -762,7 +771,8 @@
 	}
 }
 
-static void txpwr_track_cb_therm(struct ieee80211_hw *hw)
+static void rtl8723be_dm_txpower_tracking_callback_thermalmeter(
+							struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
@@ -773,30 +783,29 @@
 	int i = 0;
 
 	u8 ofdm_min_index = 6;
-	u8 index = 0;
+	u8 index_for_channel = 0;
 
-	char delta_swing_table_idx_tup_a[] = {
+	char delta_swing_table_idx_tup_a[TXSCALE_TABLE_SIZE] = {
 		0, 0, 1, 2, 2, 2, 3, 3, 3, 4,  5,
 		5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10,
 		10, 11, 11, 12, 12, 13, 14, 15};
-	char delta_swing_table_idx_tdown_a[] = {
+	char delta_swing_table_idx_tdown_a[TXSCALE_TABLE_SIZE] = {
 		0, 0, 1, 2, 2, 2, 3, 3, 3, 4,  5,
 		5, 6, 6, 6, 6, 7, 7, 7, 8, 8,  9,
 		9, 10, 10, 11, 12, 13, 14, 15};
 
-	/*Initilization ( 7 steps in total)*/
+	/*Initilization ( 7 steps in total )*/
 	rtlpriv->dm.txpower_trackinginit = true;
 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
-		 "rtl8723be_dm_txpower_tracking"
-		 "_callback_thermalmeter\n");
+		 "rtl8723be_dm_txpower_tracking_callback_thermalmeter\n");
 
-	thermalvalue = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0xfc00);
+	thermalvalue = (u8)rtl_get_rfreg(hw,
+		RF90_PATH_A, RF_T_METER, 0xfc00);
 	if (!rtlpriv->dm.txpower_track_control || thermalvalue == 0 ||
 	    rtlefuse->eeprom_thermalmeter == 0xFF)
 		return;
 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
-		 "Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
-		 "eeprom_thermalmeter 0x%x\n",
+		 "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x\n",
 		 thermalvalue, rtldm->thermalvalue,
 		 rtlefuse->eeprom_thermalmeter);
 	/*3 Initialize ThermalValues of RFCalibrateInfo*/
@@ -833,9 +842,7 @@
 		    (rtlpriv->dm.thermalvalue_iqk - thermalvalue);
 
 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
-		 "Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
-		 "eeprom_thermalmeter 0x%x delta 0x%x "
-		 "delta_lck 0x%x delta_iqk 0x%x\n",
+		 "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x delta 0x%x delta_lck 0x%x delta_iqk 0x%x\n",
 		 thermalvalue, rtlpriv->dm.thermalvalue,
 		 rtlefuse->eeprom_thermalmeter, delta, delta_lck, delta_iqk);
 	/* 6 If necessary, do LCK.*/
@@ -905,10 +912,10 @@
 		rtldm->done_txpower = true;
 		if (thermalvalue > rtlefuse->eeprom_thermalmeter)
 			rtl8723be_dm_tx_power_track_set_power(hw, BBSWING, 0,
-							      index);
+							     index_for_channel);
 		else
 			rtl8723be_dm_tx_power_track_set_power(hw, BBSWING, 0,
-							      index);
+							     index_for_channel);
 
 		rtldm->swing_idx_cck_base = rtldm->swing_idx_cck;
 		rtldm->swing_idx_ofdm_base[RF90_PATH_A] =
@@ -923,6 +930,7 @@
 
 	rtldm->txpowercount = 0;
 	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "end\n");
+
 }
 
 void rtl8723be_dm_check_txpower_tracking(struct ieee80211_hw *hw)
@@ -943,7 +951,7 @@
 	} else {
 		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
 			 "Schedule TxPowerTracking !!\n");
-		txpwr_track_cb_therm(hw);
+		rtl8723be_dm_txpower_tracking_callback_thermalmeter(hw);
 		tm_trigger = 0;
 	}
 }
@@ -953,11 +961,11 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	struct rate_adaptive *ra = &(rtlpriv->ra);
-	struct ieee80211_sta *sta = NULL;
-	u32 low_rssithresh_for_ra = ra->low2high_rssi_thresh_for_ra40m;
-	u32 high_rssithresh_for_ra = ra->high_rssi_thresh_for_ra;
+	struct rate_adaptive *p_ra = &rtlpriv->ra;
+	u32 low_rssithresh_for_ra = p_ra->low2high_rssi_thresh_for_ra40m;
+	u32 high_rssithresh_for_ra = p_ra->high_rssi_thresh_for_ra;
 	u8 go_up_gap = 5;
+	struct ieee80211_sta *sta = NULL;
 
 	if (is_hal_stop(rtlhal)) {
 		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
@@ -972,8 +980,8 @@
 	}
 
 	if (mac->link_state == MAC80211_LINKED &&
-	    mac->opmode == NL80211_IFTYPE_STATION) {
-		switch (ra->pre_ratr_state) {
+		mac->opmode == NL80211_IFTYPE_STATION) {
+		switch (p_ra->pre_ratr_state) {
 		case DM_RATR_STA_MIDDLE:
 			high_rssithresh_for_ra += go_up_gap;
 			break;
@@ -987,31 +995,31 @@
 
 		if (rtlpriv->dm.undec_sm_pwdb >
 		    (long)high_rssithresh_for_ra)
-			ra->ratr_state = DM_RATR_STA_HIGH;
+			p_ra->ratr_state = DM_RATR_STA_HIGH;
 		else if (rtlpriv->dm.undec_sm_pwdb >
 			 (long)low_rssithresh_for_ra)
-			ra->ratr_state = DM_RATR_STA_MIDDLE;
+			p_ra->ratr_state = DM_RATR_STA_MIDDLE;
 		else
-			ra->ratr_state = DM_RATR_STA_LOW;
+			p_ra->ratr_state = DM_RATR_STA_LOW;
 
-		if (ra->pre_ratr_state != ra->ratr_state) {
+		if (p_ra->pre_ratr_state != p_ra->ratr_state) {
 			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
 				 "RSSI = %ld\n",
 				 rtlpriv->dm.undec_sm_pwdb);
 			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
-				 "RSSI_LEVEL = %d\n", ra->ratr_state);
+				 "RSSI_LEVEL = %d\n", p_ra->ratr_state);
 			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
 				 "PreState = %d, CurState = %d\n",
-				 ra->pre_ratr_state, ra->ratr_state);
+				  p_ra->pre_ratr_state, p_ra->ratr_state);
 
 			rcu_read_lock();
 			sta = rtl_find_sta(hw, mac->bssid);
 			if (sta)
 				rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
-							   ra->ratr_state);
+							   p_ra->ratr_state);
 			rcu_read_unlock();
 
-			ra->pre_ratr_state = ra->ratr_state;
+			p_ra->pre_ratr_state = p_ra->ratr_state;
 		}
 	}
 }
@@ -1020,10 +1028,6 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-	if (rtlpriv->cfg->ops->get_btc_status()) {
-		if (rtlpriv->btcoexist.btc_ops->btc_is_disable_edca_turbo(rtlpriv))
-			return true;
-	}
 	if (rtlpriv->mac80211.mode == WIRELESS_MODE_B)
 		return true;
 
@@ -1034,6 +1038,7 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
 	static u64 last_txok_cnt;
 	static u64 last_rxok_cnt;
 	u64 cur_txok_cnt = 0;
@@ -1042,22 +1047,22 @@
 	u32 edca_be_dl = 0x6ea42b;/*not sure*/
 	u32 edca_be = 0x5ea42b;
 	u32 iot_peer = 0;
-	bool is_cur_rdlstate;
-	bool last_is_cur_rdlstate = false;
-	bool bias_on_rx = false;
-	bool edca_turbo_on = false;
+	bool b_is_cur_rdlstate;
+	bool b_last_is_cur_rdlstate = false;
+	bool b_bias_on_rx = false;
+	bool b_edca_turbo_on = false;
 
-	last_is_cur_rdlstate = rtlpriv->dm.is_cur_rdlstate;
+	b_last_is_cur_rdlstate = rtlpriv->dm.is_cur_rdlstate;
 
 	cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
 	cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
 
 	iot_peer = rtlpriv->mac80211.vendor;
-	bias_on_rx = (iot_peer == PEER_RAL || iot_peer == PEER_ATH) ?
-		     true : false;
-	edca_turbo_on = ((!rtlpriv->dm.is_any_nonbepkts) &&
-			 (!rtlpriv->dm.disable_framebursting)) ?
-			 true : false;
+	b_bias_on_rx = (iot_peer == PEER_RAL || iot_peer == PEER_ATH) ?
+		       true : false;
+	b_edca_turbo_on = ((!rtlpriv->dm.is_any_nonbepkts) &&
+			   (!rtlpriv->dm.disable_framebursting)) ?
+			   true : false;
 
 	if ((iot_peer == PEER_CISCO) &&
 	    (mac->mode == WIRELESS_MODE_N_24G)) {
@@ -1067,23 +1072,23 @@
 	if (rtl8723be_dm_is_edca_turbo_disable(hw))
 		goto exit;
 
-	if (edca_turbo_on) {
-		if (bias_on_rx)
-			is_cur_rdlstate = (cur_txok_cnt > cur_rxok_cnt * 4) ?
-					  false : true;
+	if (b_edca_turbo_on) {
+		if (b_bias_on_rx)
+			b_is_cur_rdlstate = (cur_txok_cnt > cur_rxok_cnt * 4) ?
+					    false : true;
 		else
-			is_cur_rdlstate = (cur_rxok_cnt > cur_txok_cnt * 4) ?
-					  true : false;
+			b_is_cur_rdlstate = (cur_rxok_cnt > cur_txok_cnt * 4) ?
+					    true : false;
 
-		edca_be = (is_cur_rdlstate) ? edca_be_dl : edca_be_ul;
+		edca_be = (b_is_cur_rdlstate) ? edca_be_dl : edca_be_ul;
 		rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, edca_be);
-		rtlpriv->dm.is_cur_rdlstate = is_cur_rdlstate;
+		rtlpriv->dm.is_cur_rdlstate = b_is_cur_rdlstate;
 		rtlpriv->dm.current_turbo_edca = true;
 	} else {
 		if (rtlpriv->dm.current_turbo_edca) {
 			u8 tmp = AC0_BE;
 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
-						      &tmp);
+						      (u8 *)(&tmp));
 		}
 		rtlpriv->dm.current_turbo_edca = false;
 	}
@@ -1097,13 +1102,14 @@
 static void rtl8723be_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
 	u8 cur_cck_cca_thresh;
 
 	if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
-		if (rtlpriv->dm_digtable.rssi_val_min > 25) {
+		if (dm_digtable->rssi_val_min > 25) {
 			cur_cck_cca_thresh = 0xcd;
-		} else if ((rtlpriv->dm_digtable.rssi_val_min <= 25) &&
-			   (rtlpriv->dm_digtable.rssi_val_min > 10)) {
+		} else if ((dm_digtable->rssi_val_min <= 25) &&
+			   (dm_digtable->rssi_val_min > 10)) {
 			cur_cck_cca_thresh = 0x83;
 		} else {
 			if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
@@ -1118,14 +1124,13 @@
 			cur_cck_cca_thresh = 0x40;
 	}
 
-	if (rtlpriv->dm_digtable.cur_cck_cca_thres != cur_cck_cca_thresh)
+	if (dm_digtable->cur_cck_cca_thres != cur_cck_cca_thresh)
 		rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, cur_cck_cca_thresh);
 
-	rtlpriv->dm_digtable.pre_cck_cca_thres = rtlpriv->dm_digtable.cur_cck_cca_thres;
-	rtlpriv->dm_digtable.cur_cck_cca_thres = cur_cck_cca_thresh;
+	dm_digtable->pre_cck_cca_thres = dm_digtable->cur_cck_cca_thres;
+	dm_digtable->cur_cck_cca_thres = cur_cck_cca_thresh;
 	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
-		 "CCK cca thresh hold =%x\n",
-		 rtlpriv->dm_digtable.cur_cck_cca_thres);
+		 "CCK cca thresh hold =%x\n", dm_digtable->cur_cck_cca_thres);
 }
 
 static void rtl8723be_dm_dynamic_edcca(struct ieee80211_hw *hw)
@@ -1173,8 +1178,7 @@
 		if (rtlpriv->cfg->ops->get_btc_status()) {
 			if (!rtlpriv->btcoexist.btc_ops->btc_is_bt_disabled(rtlpriv)) {
 				RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
-					 "odm_DynamicATCSwitch(): Disable"
-					 " CFO tracking for BT!!\n");
+					 "odm_DynamicATCSwitch(): Disable CFO tracking for BT!!\n");
 				return;
 			}
 		}
@@ -1207,9 +1211,8 @@
 		if (cfo_ave_diff > 20 && rtldm->large_cfo_hit == 0) {
 			rtldm->large_cfo_hit = 1;
 			return;
-		} else {
+		} else
 			rtldm->large_cfo_hit = 0;
-		}
 
 		rtldm->cfo_ave_pre = cfo_ave;
 
@@ -1263,20 +1266,20 @@
 static void rtl8723be_dm_common_info_self_update(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_sta_info *drv_priv;
 	u8 cnt = 0;
+	struct rtl_sta_info *drv_priv;
 
 	rtlpriv->dm.one_entry_only = false;
 
 	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION &&
-	    rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
+		rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
 		rtlpriv->dm.one_entry_only = true;
 		return;
 	}
 
 	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP ||
-	    rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC ||
-	    rtlpriv->mac80211.opmode == NL80211_IFTYPE_MESH_POINT) {
+		rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC ||
+		rtlpriv->mac80211.opmode == NL80211_IFTYPE_MESH_POINT) {
 		spin_lock_bh(&rtlpriv->locks.entry_list_lock);
 		list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
 			cnt++;
@@ -1305,8 +1308,8 @@
 		fw_ps_awake = false;
 
 	if ((ppsc->rfpwr_state == ERFON) &&
-	    ((!fw_current_inpsmode) && fw_ps_awake) &&
-	    (!ppsc->rfchange_inprogress)) {
+		((!fw_current_inpsmode) && fw_ps_awake) &&
+		(!ppsc->rfchange_inprogress)) {
 		rtl8723be_dm_common_info_self_update(hw);
 		rtl8723be_dm_false_alarm_counter_statistics(hw);
 		rtl8723be_dm_check_rssi_monitor(hw);
@@ -1318,8 +1321,6 @@
 		rtl8723be_dm_dynamic_atc_switch(hw);
 		rtl8723be_dm_check_txpower_tracking(hw);
 		rtl8723be_dm_dynamic_txpower(hw);
-		if (rtlpriv->cfg->ops->get_btc_status())
-			rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv);
 	}
 	rtlpriv->dm.dbginfo.num_qry_beacon_pkt = 0;
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h
index c6c2f2a..e4c0e8a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h
@@ -141,7 +141,7 @@
 #define	DM_REG_TX_CCK_BBON_11N			0xE78
 #define	DM_REG_OFDM_RFON_11N			0xE7C
 #define	DM_REG_OFDM_BBON_11N			0xE80
-#define DM_REG_TX2RX_11N			0xE84
+#define		DM_REG_TX2RX_11N		0xE84
 #define	DM_REG_TX2TX_11N			0xE88
 #define	DM_REG_RX_CCK_11N			0xE8C
 #define	DM_REG_RX_OFDM_11N			0xED0
@@ -202,6 +202,7 @@
 #define DM_DIG_BACKOFF_MIN			-4
 #define DM_DIG_BACKOFF_DEFAULT			10
 
+#define RXPATHSELECTION_SS_TH_LOW		30
 #define RXPATHSELECTION_DIFF_TH			18
 
 #define DM_RATR_STA_INIT			0
@@ -212,6 +213,8 @@
 #define CTS2SELF_THVAL				30
 #define REGC38_TH				20
 
+#define WAIOTTHVAL				25
+
 #define TXHIGHPWRLEVEL_NORMAL			0
 #define TXHIGHPWRLEVEL_LEVEL1			1
 #define TXHIGHPWRLEVEL_LEVEL2			2
@@ -231,22 +234,6 @@
 #define	CFO_THRESHOLD_XTAL			10 /* kHz */
 #define	CFO_THRESHOLD_ATC			80 /* kHz */
 
-enum FAT_STATE {
-	FAT_NORMAL_STATE	= 0,
-	FAT_TRAINING_STATE	= 1,
-};
-
-enum tag_dynamic_init_gain_operation_type_definition {
-	DIG_TYPE_THRESH_HIGH	= 0,
-	DIG_TYPE_THRESH_LOW	= 1,
-	DIG_TYPE_BACKOFF	= 2,
-	DIG_TYPE_RX_GAIN_MIN	= 3,
-	DIG_TYPE_RX_GAIN_MAX	= 4,
-	DIG_TYPE_ENABLE		= 5,
-	DIG_TYPE_DISABLE	= 6,
-	DIG_OP_TYPE_MAX
-};
-
 enum dm_1r_cca_e {
 	CCA_1R		= 0,
 	CCA_2R		= 1,
@@ -292,12 +279,17 @@
 #define BT_RSSI_STATE_SPECIAL_LOW       BIT_OFFSET_LEN_MASK_32(2, 1)
 #define BT_RSSI_STATE_BG_EDCA_LOW       BIT_OFFSET_LEN_MASK_32(3, 1)
 #define BT_RSSI_STATE_TXPOWER_LOW       BIT_OFFSET_LEN_MASK_32(4, 1)
+#define GET_UNDECORATED_AVERAGE_RSSI(_priv)     \
+	((((struct rtl_priv *)(_priv))->mac80211.opmode == \
+		NL80211_IFTYPE_ADHOC) ? \
+	(((struct rtl_priv *)(_priv))->dm.entry_min_undecoratedsmoothed_pwdb) :\
+	(((struct rtl_priv *)(_priv))->dm.undecorated_smoothed_pwdb))
 
 void rtl8723be_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw, u8 *pdesc,
 					u32 mac_id);
 void rtl8723be_dm_ant_sel_statistics(struct ieee80211_hw *hw, u8 antsel_tr_mux,
 				     u32 mac_id, u32 rx_pwdb_all);
-void rtl8723be_dm_fast_antenna_trainning_callback(unsigned long data);
+void rtl8723be_dm_fast_antenna_training_callback(unsigned long data);
 void rtl8723be_dm_init(struct ieee80211_hw *hw);
 void rtl8723be_dm_watchdog(struct ieee80211_hw *hw);
 void rtl8723be_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi);
@@ -305,6 +297,4 @@
 void rtl8723be_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
 void rtl8723be_dm_txpower_track_adjust(struct ieee80211_hw *hw, u8 type,
 				       u8 *pdirection, u32 *poutwrite_val);
-void rtl8723be_dm_init_edca_turbo(struct ieee80211_hw *hw);
-
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c
index f856be6..69d4f0f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/fw.c
@@ -26,6 +26,7 @@
 #include "../wifi.h"
 #include "../pci.h"
 #include "../base.h"
+#include "../core.h"
 #include "reg.h"
 #include "def.h"
 #include "fw.h"
@@ -55,8 +56,8 @@
 	bool isfw_read = false;
 	u8 buf_index = 0;
 	bool bwrite_sucess = false;
-	u8 wait_h2c_limit = 100;
-	u8 wait_writeh2c_limit = 100;
+	u8 wait_h2c_limmit = 100;
+	u8 wait_writeh2c_limmit = 100;
 	u8 boxcontent[4], boxextcontent[4];
 	u32 h2c_waitcounter = 0;
 	unsigned long flag;
@@ -68,8 +69,8 @@
 		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 		if (rtlhal->h2c_setinprogress) {
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
-				 "H2C set in progress! Wait to set.."
-				 "element_id(%d).\n", element_id);
+				 "H2C set in progress! Wait to set..element_id(%d).\n",
+				 element_id);
 
 			while (rtlhal->h2c_setinprogress) {
 				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
@@ -92,14 +93,15 @@
 			break;
 		}
 	}
+
 	while (!bwrite_sucess) {
-		wait_writeh2c_limit--;
-		if (wait_writeh2c_limit == 0) {
+		wait_writeh2c_limmit--;
+		if (wait_writeh2c_limmit == 0) {
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Write H2C fail because no trigger "
-				 "for FW INT!\n");
+				 "Write H2C fail because no trigger for FW INT!\n");
 			break;
 		}
+
 		boxnum = rtlhal->last_hmeboxnum;
 		switch (boxnum) {
 		case 0:
@@ -120,39 +122,43 @@
 			break;
 		default:
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case not processed\n");
+				 "switch case not process\n");
 			break;
 		}
+
 		isfw_read = _rtl8723be_check_fw_read_last_h2c(hw, boxnum);
 		while (!isfw_read) {
-			wait_h2c_limit--;
-			if (wait_h2c_limit == 0) {
+			wait_h2c_limmit--;
+			if (wait_h2c_limmit == 0) {
 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
-					 "Wating too long for FW read "
-					 "clear HMEBox(%d)!\n", boxnum);
+					 "Waiting too long for FW read clear HMEBox(%d)!\n",
+					 boxnum);
 				break;
 			}
+
 			udelay(10);
 
 			isfw_read = _rtl8723be_check_fw_read_last_h2c(hw,
 								boxnum);
 			u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
-				 "Wating for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
+				 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
 				 boxnum, u1b_tmp);
 		}
+
 		if (!isfw_read) {
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
-				 "Write H2C register BOX[%d] fail!!!!! "
-				 "Fw do not read.\n", boxnum);
+				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
+				 boxnum);
 			break;
 		}
+
 		memset(boxcontent, 0, sizeof(boxcontent));
 		memset(boxextcontent, 0, sizeof(boxextcontent));
 		boxcontent[0] = element_id;
 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 			 "Write element_id box_reg(%4x) = %2x\n",
-			 box_reg, element_id);
+			  box_reg, element_id);
 
 		switch (cmd_len) {
 		case 1:
@@ -181,6 +187,7 @@
 				rtl_write_byte(rtlpriv, box_extreg + idx,
 					       boxextcontent[idx]);
 			}
+
 			for (idx = 0; idx < 4; idx++) {
 				rtl_write_byte(rtlpriv, box_reg + idx,
 					       boxcontent[idx]);
@@ -191,6 +198,7 @@
 				 "switch case not process\n");
 			break;
 		}
+
 		bwrite_sucess = true;
 
 		rtlhal->last_hmeboxnum = boxnum + 1;
@@ -199,8 +207,9 @@
 
 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
 			 "pHalData->last_hmeboxnum  = %d\n",
-			 rtlhal->last_hmeboxnum);
+			  rtlhal->last_hmeboxnum);
 	}
+
 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
 	rtlhal->h2c_setinprogress = false;
 	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
@@ -219,6 +228,7 @@
 			  "return H2C cmd because of Fw download fail!!!\n");
 		return;
 	}
+
 	memset(tmp_cmdbuf, 0, 8);
 	memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
 	_rtl8723be_fill_h2c_command(hw, element_id, cmd_len,
@@ -229,17 +239,17 @@
 void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u8 u1_h2c_set_pwrmode[H2C_8723BE_PWEMODE_LENGTH] = { 0 };
+	u8 u1_h2c_set_pwrmode[H2C_PWEMODE_LENGTH] = { 0 };
 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 	u8 rlbm, power_state = 0;
 	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
 
 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
-	rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM = 2.*/
+	rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/
 	SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
 					 (rtlpriv->mac80211.p2p) ?
-					 ppsc->smart_ps : 1);
+					  ppsc->smart_ps : 1);
 	SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
 					       ppsc->reg_max_lps_awakeintvl);
 	SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
@@ -251,44 +261,26 @@
 
 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
 		      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
-		      u1_h2c_set_pwrmode, H2C_8723BE_PWEMODE_LENGTH);
-	rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_SETPWRMODE,
-			       H2C_8723BE_PWEMODE_LENGTH,
+		      u1_h2c_set_pwrmode, H2C_PWEMODE_LENGTH);
+	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_SETPWRMODE, H2C_PWEMODE_LENGTH,
 			       u1_h2c_set_pwrmode);
 }
 
-static bool _rtl8723be_cmd_send_packet(struct ieee80211_hw *hw,
-				       struct sk_buff *skb)
+void rtl8723be_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus)
 {
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-	struct rtl8192_tx_ring *ring;
-	struct rtl_tx_desc *pdesc;
-	struct sk_buff *pskb = NULL;
-	u8 own;
-	unsigned long flags;
+	u8 parm[3] = { 0, 0, 0 };
+	/* parm[0]: bit0=0-->Disconnect, bit0=1-->Connect
+	 *          bit1=0-->update Media Status to MACID
+	 *          bit1=1-->update Media Status from MACID to MACID_End
+	 * parm[1]: MACID, if this is INFRA_STA, MacID = 0
+	 * parm[2]: MACID_End
+	*/
+	SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, mstatus);
+	SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0);
 
-	ring = &rtlpci->tx_ring[BEACON_QUEUE];
-
-	pskb = __skb_dequeue(&ring->queue);
-	if (pskb)
-		kfree_skb(pskb);
-
-	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
-
-	pdesc = &ring->desc[0];
-	own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc, true, HW_DESC_OWN);
-
-	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
-
-	__skb_queue_tail(&ring->queue, skb);
-
-	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-
-	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
-
-	return true;
+	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_MSRRPT, 3, parm);
 }
+
 #define BEACON_PG		0 /* ->1 */
 #define PSPOLL_PG		2
 #define NULL_PG			3
@@ -407,7 +399,7 @@
 };
 
 void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
-				  bool dl_finished)
+				  bool b_dl_finished)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -416,7 +408,7 @@
 	u32 totalpacketlen;
 	bool rtstatus;
 	u8 u1rsvdpageloc[5] = { 0 };
-	bool dlok = false;
+	bool b_dlok = false;
 
 	u8 *beacon;
 	u8 *p_pspoll;
@@ -466,43 +458,40 @@
 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
 
 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
-		      "rtl8723be_set_fw_rsvdpagepkt(): "
-		      "HW_VAR_SET_TX_CMD: ALL\n",
+		      "rtl8723be_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
 		      &reserved_page_packet[0], totalpacketlen);
 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
-		      "rtl8723be_set_fw_rsvdpagepkt(): "
-		      "HW_VAR_SET_TX_CMD: ALL\n", u1rsvdpageloc, 3);
-
+		      "rtl8723be_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+		      u1rsvdpageloc, 3);
 
 	skb = dev_alloc_skb(totalpacketlen);
 	memcpy((u8 *)skb_put(skb, totalpacketlen),
 	       &reserved_page_packet, totalpacketlen);
 
-	rtstatus = _rtl8723be_cmd_send_packet(hw, skb);
+	rtstatus = rtl_cmd_send_packet(hw, skb);
 
 	if (rtstatus)
-		dlok = true;
+		b_dlok = true;
 
-	if (dlok) {
+	if (b_dlok) {
 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
 			 "Set RSVD page location to Fw.\n");
 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "H2C_RSVDPAGE:\n",
 			      u1rsvdpageloc, 3);
-		rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_RSVDPAGE,
+		rtl8723be_fill_h2c_cmd(hw, H2C_8723B_RSVDPAGE,
 				       sizeof(u1rsvdpageloc), u1rsvdpageloc);
-	} else {
+	} else
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
-	}
 }
 
 /*Should check FW support p2p or not.*/
 static void rtl8723be_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw,
 					     u8 ctwindow)
 {
-	u8 u1_ctwindow_period[1] = {ctwindow};
+	u8 u1_ctwindow_period[1] = { ctwindow};
 
-	rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_P2P_PS_CTW_CMD, 1,
+	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_P2P_PS_CTW_CMD, 1,
 			       u1_ctwindow_period);
 }
 
@@ -521,7 +510,7 @@
 	switch (p2p_ps_state) {
 	case P2P_PS_DISABLE:
 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
-		memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
+		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
 		break;
 	case P2P_PS_ENABLE:
 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
@@ -532,7 +521,7 @@
 			rtl8723be_set_p2p_ctw_period_cmd(hw, ctwindow);
 		}
 		/* hw only support 2 set of NoA */
-		for (i = 0; i < p2pinfo->noa_num; i++) {
+		for (i = 0 ; i < p2pinfo->noa_num ; i++) {
 			/* To control the register setting
 			 * for which NOA
 			 */
@@ -563,6 +552,7 @@
 			rtl_write_dword(rtlpriv, 0x5EC,
 					p2pinfo->noa_count_type[i]);
 		}
+
 		if ((p2pinfo->opp_ps == 1) ||
 		    (p2pinfo->noa_num > 0)) {
 			/* rst p2p circuit */
@@ -591,30 +581,60 @@
 	default:
 		break;
 	}
-	rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_P2P_PS_OFFLOAD, 1,
+
+	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_P2P_PS_OFFLOAD, 1,
 			       (u8 *)p2p_ps_offload);
 }
 
-void rtl8723be_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
+static void _rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw,
+					   u8 c2h_cmd_id,
+					   u8 c2h_cmd_len, u8 *tmp_buf)
 {
-	u8 u1_joinbssrpt_parm[1] = { 0 };
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
-
-	rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_JOINBSSRPT, 1,
-			       u1_joinbssrpt_parm);
+	switch (c2h_cmd_id) {
+	case C2H_8723B_DBG:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+			 "[C2H], C2H_8723BE_DBG!!\n");
+		break;
+	case C2H_8723B_TX_REPORT:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+			 "[C2H], C2H_8723BE_TX_REPORT!\n");
+		break;
+	case C2H_8723B_BT_INFO:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+			 "[C2H], C2H_8723BE_BT_INFO!!\n");
+		rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf,
+							      c2h_cmd_len);
+		break;
+	case C2H_8723B_BT_MP:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+			 "[C2H], C2H_8723BE_BT_MP!!\n");
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+			 "[C2H], Unkown packet!! CmdId(%#X)!\n", c2h_cmd_id);
+		break;
+	}
 }
 
-void rtl8723be_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
-				      u8 ap_offload_enable)
+void rtl8723be_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len)
 {
-	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	u8 u1_apoffload_parm[H2C_8723BE_AP_OFFLOAD_LENGTH] = { 0 };
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0;
+	u8 *tmp_buf = NULL;
 
-	SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
-	SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
-	SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
+	c2h_cmd_id = buffer[0];
+	c2h_cmd_seq = buffer[1];
+	c2h_cmd_len = len - 2;
+	tmp_buf = buffer + 2;
 
-	rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_AP_OFFLOAD,
-			       H2C_8723BE_AP_OFFLOAD_LENGTH, u1_apoffload_parm);
+	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+		 "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n",
+		 c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len);
+
+	RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE,
+		      "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
+
+	_rtl8723be_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
 }
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/fw.h b/drivers/net/wireless/rtlwifi/rtl8723be/fw.h
index 31eec28..0674296 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/fw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/fw.h
@@ -30,50 +30,23 @@
 #define FW_8192C_END_ADDRESS			0x5FFF
 #define FW_8192C_PAGE_SIZE			4096
 #define FW_8192C_POLLING_DELAY			5
-#define FW_8192C_POLLING_TIMEOUT_COUNT		6000
 
-#define IS_FW_HEADER_EXIST(_pfwhdr)	\
-	((_pfwhdr->signature&0xFFF0) == 0x5300)
 #define USE_OLD_WOWLAN_DEBUG_FW			0
 
-#define H2C_8723BE_RSVDPAGE_LOC_LEN		5
-#define H2C_8723BE_PWEMODE_LENGTH		5
-#define H2C_8723BE_JOINBSSRPT_LENGTH		1
-#define H2C_8723BE_AP_OFFLOAD_LENGTH		3
-#define H2C_8723BE_WOWLAN_LENGTH		3
-#define H2C_8723BE_KEEP_ALIVE_CTRL_LENGTH	3
-#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
-#define H2C_8723BE_REMOTE_WAKE_CTRL_LEN		1
-#else
-#define H2C_8723BE_REMOTE_WAKE_CTRL_LEN		3
-#endif
-#define H2C_8723BE_AOAC_GLOBAL_INFO_LEN		2
-#define H2C_8723BE_AOAC_RSVDPAGE_LOC_LEN	7
-
+#define H2C_PWEMODE_LENGTH			5
 
 /* Fw PS state for RPWM.
 *BIT[2:0] = HW state
 *BIT[3] = Protocol PS state, 1: register active state , 0: register sleep state
 *BIT[4] = sub-state
 */
-#define	FW_PS_GO_ON		BIT(0)
-#define	FW_PS_TX_NULL		BIT(1)
 #define	FW_PS_RF_ON		BIT(2)
 #define	FW_PS_REGISTER_ACTIVE	BIT(3)
 
-#define	FW_PS_DPS		BIT(0)
-#define	FW_PS_LCLK		(FW_PS_DPS)
-#define	FW_PS_RF_OFF		BIT(1)
-#define	FW_PS_ALL_ON		BIT(2)
-#define	FW_PS_ST_ACTIVE	BIT(3)
-#define	FW_PS_ISR_ENABLE	BIT(4)
-#define	FW_PS_IMR_ENABLE	BIT(5)
-
-
 #define	FW_PS_ACK		BIT(6)
 #define	FW_PS_TOGGLE		BIT(7)
 
- /* 88E RPWM value*/
+ /* 8723BE RPWM value*/
  /* BIT[0] = 1: 32k, 0: 40M*/
 #define	FW_PS_CLOCK_OFF		BIT(0)		/* 32k*/
 #define	FW_PS_CLOCK_ON		0		/*40M*/
@@ -83,75 +56,61 @@
 /*ISR_ENABLE, IMR_ENABLE, and PS mode should be inherited.*/
 #define	FW_PS_STATE_INT_MASK	(0x3F)
 
-#define	FW_PS_STATE(x)	(FW_PS_STATE_MASK & (x))
-#define	FW_PS_STATE_HW(x)	(FW_PS_STATE_HW_MASK & (x))
-#define	FW_PS_STATE_INT(x)	(FW_PS_STATE_INT_MASK & (x))
-#define	FW_PS_ISR_VAL(x)	((x) & 0x70)
-#define	FW_PS_IMR_MASK(x)	((x) & 0xDF)
-#define	FW_PS_KEEP_IMR(x)	((x) & 0x20)
-
-
-#define	FW_PS_STATE_S0		(FW_PS_DPS)
-#define	FW_PS_STATE_S1		(FW_PS_LCLK)
-#define	FW_PS_STATE_S2		(FW_PS_RF_OFF)
-#define	FW_PS_STATE_S3		(FW_PS_ALL_ON)
-#define	FW_PS_STATE_S4		((FW_PS_ST_ACTIVE) | (FW_PS_ALL_ON))
+#define	FW_PS_STATE(x)		(FW_PS_STATE_MASK & (x))
 
 /* ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))*/
-#define	FW_PS_STATE_ALL_ON_88E	(FW_PS_CLOCK_ON)
+#define	FW_PS_STATE_ALL_ON	(FW_PS_CLOCK_ON)
 /* (FW_PS_RF_ON)*/
-#define	FW_PS_STATE_RF_ON_88E	(FW_PS_CLOCK_ON)
+#define	FW_PS_STATE_RF_ON	(FW_PS_CLOCK_ON)
 /* 0x0*/
-#define	FW_PS_STATE_RF_OFF_88E	(FW_PS_CLOCK_ON)
+#define	FW_PS_STATE_RF_OFF	(FW_PS_CLOCK_ON)
 /* (FW_PS_STATE_RF_OFF)*/
-#define	FW_PS_STATE_RF_OFF_LOW_PWR_88E	(FW_PS_CLOCK_OFF)
-
-#define	FW_PS_STATE_ALL_ON_92C	(FW_PS_STATE_S4)
-#define	FW_PS_STATE_RF_ON_92C		(FW_PS_STATE_S3)
-#define	FW_PS_STATE_RF_OFF_92C	(FW_PS_STATE_S2)
-#define	FW_PS_STATE_RF_OFF_LOW_PWR_92C	(FW_PS_STATE_S1)
+#define	FW_PS_STATE_RF_OFF_LOW_PWR	(FW_PS_CLOCK_OFF)
 
 
-/* For 88E H2C PwrMode Cmd ID 5.*/
+/* For 8723BE H2C PwrMode Cmd ID 5.*/
 #define	FW_PWR_STATE_ACTIVE	((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
 #define	FW_PWR_STATE_RF_OFF	0
 
-#define	FW_PS_IS_ACK(x)	((x) & FW_PS_ACK)
-#define	FW_PS_IS_CLK_ON(x)	((x) & (FW_PS_RF_OFF | FW_PS_ALL_ON))
-#define	FW_PS_IS_RF_ON(x)	((x) & (FW_PS_ALL_ON))
-#define	FW_PS_IS_ACTIVE(x)	((x) & (FW_PS_ST_ACTIVE))
-#define	FW_PS_IS_CPWM_INT(x)	((x) & 0x40)
+#define	FW_PS_IS_ACK(x)		((x) & FW_PS_ACK)
 
-#define	FW_CLR_PS_STATE(x)	((x) = ((x) & (0xF0)))
-
-#define	IS_IN_LOW_POWER_STATE_88E(fwpsstate)		\
-			(FW_PS_STATE(fwpsstate) == FW_PS_CLOCK_OFF)
+#define	IS_IN_LOW_POWER_STATE(__fwpsstate)	\
+	(FW_PS_STATE(__fwpsstate) == FW_PS_CLOCK_OFF)
 
 #define	FW_PWR_STATE_ACTIVE	((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
 #define	FW_PWR_STATE_RF_OFF	0
 
-#define pagenum_128(_len)	(u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0))
+enum rtl8723b_h2c_cmd {
+	H2C_8723B_RSVDPAGE = 0,
+	H2C_8723B_MSRRPT = 1,
+	H2C_8723B_SCAN = 2,
+	H2C_8723B_KEEP_ALIVE_CTRL = 3,
+	H2C_8723B_DISCONNECT_DECISION = 4,
+	H2C_8723B_BCN_RSVDPAGE = 9,
+	H2C_8723B_PROBERSP_RSVDPAGE = 10,
 
-#define SET_88E_H2CCMD_WOWLAN_FUNC_ENABLE(__ph2ccmd, __val)		\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val)
-#define SET_88E_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(__ph2ccmd, __val)	\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val)
-#define SET_88E_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(__ph2ccmd, __val)	\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 2, 1, __val)
-#define SET_88E_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(__ph2ccmd, __val)	\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 3, 1, __val)
-#define SET_88E_H2CCMD_WOWLAN_ALL_PKT_DROP(__ph2ccmd, __val)		\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 4, 1, __val)
-#define SET_88E_H2CCMD_WOWLAN_GPIO_ACTIVE(__ph2ccmd, __val)		\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 5, 1, __val)
-#define SET_88E_H2CCMD_WOWLAN_REKEY_WAKE_UP(__ph2ccmd, __val)		\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 6, 1, __val)
-#define SET_88E_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(__ph2ccmd, __val)	\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 7, 1, __val)
-#define SET_88E_H2CCMD_WOWLAN_GPIONUM(__ph2ccmd, __val)			\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
-#define SET_88E_H2CCMD_WOWLAN_GPIO_DURATION(__ph2ccmd, __val)		\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+	H2C_8723B_SETPWRMODE = 0x20,
+	H2C_8723B_PS_LPS_PARA = 0x23,
+	H2C_8723B_P2P_PS_OFFLOAD = 0x24,
+
+	H2C_8723B_RA_MASK = 0x40,
+	H2C_RSSIBE_REPORT = 0x42,
+	/*Not defined CTW CMD for P2P yet*/
+	H2C_8723B_P2P_PS_CTW_CMD,
+	MAX_8723B_H2CCMD
+};
+
+enum rtl8723b_c2h_evt {
+	C2H_8723B_DBG = 0,
+	C2H_8723B_LB = 1,
+	C2H_8723B_TXBF = 2,
+	C2H_8723B_TX_REPORT = 3,
+	C2H_8723B_BT_INFO = 9,
+	C2H_8723B_BT_MP = 11,
+	MAX_8723B_C2HEVENT
+};
+
+#define pagenum_128(_len) (u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0))
 
 
 #define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val)			\
@@ -169,8 +128,11 @@
 #define GET_88E_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd)			\
 	LE_BITS_TO_1BYTE(__ph2ccmd, 0, 8)
 
-#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val)		\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_MSRRPT_PARM_OPMODE(__ph2ccmd, __val)		\
+	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val)
+#define SET_H2CCMD_MSRRPT_PARM_MACID_IND(__ph2ccmd, __val)	\
+	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val)
+
 #define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val)		\
 	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
 #define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val)		\
@@ -178,71 +140,13 @@
 #define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val)		\
 	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
 
-/* AP_OFFLOAD */
-#define SET_H2CCMD_AP_OFFLOAD_ON(__ph2ccmd, __val)			\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
-#define SET_H2CCMD_AP_OFFLOAD_HIDDEN(__ph2ccmd, __val)			\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
-#define SET_H2CCMD_AP_OFFLOAD_DENYANY(__ph2ccmd, __val)			\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
-#define SET_H2CCMD_AP_OFFLOAD_WAKEUP_EVT_RPT(__ph2ccmd, __val)		\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val)
 
-/* Keep Alive Control*/
-#define SET_88E_H2CCMD_KEEP_ALIVE_ENABLE(__ph2ccmd, __val)		\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val)
-#define SET_88E_H2CCMD_KEEP_ALIVE_ACCPEPT_USER_DEFINED(__ph2ccmd, __val)\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val)
-#define SET_88E_H2CCMD_KEEP_ALIVE_PERIOD(__ph2ccmd, __val)		\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
-
-/*REMOTE_WAKE_CTRL */
-#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_EN(__ph2ccmd, __val)		\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 1, __val)
-#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
-#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN(__ph2ccmd, __val)\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 1, 1, __val)
-#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_NDP_OFFLOAD_EN(__ph2ccmd, __val)\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 2, 1, __val)
-#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(__ph2ccmd, __val)\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 3, 1, __val)
-#else
-#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_PAIRWISE_ENC_ALG(__ph2ccmd, __val)\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
-#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_GROUP_ENC_ALG(__ph2ccmd, __val)	\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
-#endif
-
-/* GTK_OFFLOAD */
-#define SET_88E_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(__ph2ccmd, __val)\
-	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
-#define SET_88E_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(__ph2ccmd, __val)	\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
-
-/* AOAC_RSVDPAGE_LOC */
-#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_REM_WAKE_CTRL_INFO(__ph2ccmd, __val)\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd), 0, 8, __val)
-#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(__ph2ccmd, __val)	\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
-#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(__ph2ccmd, __val)	\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
-#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(__ph2ccmd, __val)	\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val)
-#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(__ph2ccmd, __val)	\
-	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+4, 0, 8, __val)
-
-void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
-void rtl8723be_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
-				      u8 ap_offload_enable);
 void rtl8723be_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
 			    u32 cmd_len, u8 *p_cmdbuffer);
-void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw);
-void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
-				  bool dl_finished);
-void rtl8723be_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
-int rtl8723be_download_fw(struct ieee80211_hw *hw,
-			  bool buse_wake_on_wlan_fw);
-void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw,
-				      u8 p2p_ps_state);
+void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
+void rtl8723be_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus);
+void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
+void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
+void rtl8723be_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c
index 3cd2869..6dad28e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c
@@ -33,12 +33,14 @@
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
+#include "../rtl8723com/phy_common.h"
 #include "dm.h"
 #include "../rtl8723com/dm_common.h"
 #include "fw.h"
 #include "../rtl8723com/fw_common.h"
 #include "led.h"
 #include "hw.h"
+#include "../pwrseqcmd.h"
 #include "pwrseq.h"
 #include "../btcoexist/rtl_btc.h"
 
@@ -49,7 +51,9 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
+	unsigned long flags;
 
+	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 	while (skb_queue_len(&ring->queue)) {
 		struct rtl_tx_desc *entry = &ring->desc[ring->idx];
 		struct sk_buff *skb = __skb_dequeue(&ring->queue);
@@ -61,6 +65,7 @@
 		kfree_skb(skb);
 		ring->idx = (ring->idx + 1) % ring->entries;
 	}
+	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
 }
 
 static void _rtl8723be_set_bcn_ctrl_reg(struct ieee80211_hw *hw,
@@ -72,7 +77,7 @@
 	rtlpci->reg_bcn_ctrl_val |= set_bits;
 	rtlpci->reg_bcn_ctrl_val &= ~clear_bits;
 
-	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val);
+	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8)rtlpci->reg_bcn_ctrl_val);
 }
 
 static void _rtl8723be_stop_tx_beacon(struct ieee80211_hw *hw)
@@ -112,15 +117,15 @@
 }
 
 static void _rtl8723be_set_fw_clock_on(struct ieee80211_hw *hw, u8 rpwm_val,
-				       bool need_turn_off_ckk)
+				       bool b_need_turn_off_ckk)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	bool support_remote_wake_up;
+	bool b_support_remote_wake_up;
 	u32 count = 0, isr_regaddr, content;
-	bool schedule_timer = need_turn_off_ckk;
+	bool b_schedule_timer = b_need_turn_off_ckk;
 	rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
-				      (u8 *)(&support_remote_wake_up));
+				      (u8 *)(&b_support_remote_wake_up));
 
 	if (!rtlhal->fw_ready)
 		return;
@@ -145,9 +150,10 @@
 			break;
 		}
 	}
-	if (IS_IN_LOW_POWER_STATE_88E(rtlhal->fw_ps_state)) {
+
+	if (IS_IN_LOW_POWER_STATE(rtlhal->fw_ps_state)) {
 		rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM,
-					      &rpwm_val);
+					      (u8 *)(&rpwm_val));
 		if (FW_PS_IS_ACK(rpwm_val)) {
 			isr_regaddr = REG_HISR;
 			content = rtl_read_dword(rtlpriv, isr_regaddr);
@@ -159,20 +165,19 @@
 
 			if (content & IMR_CPWM) {
 				rtl_write_word(rtlpriv, isr_regaddr, 0x0100);
-				rtlhal->fw_ps_state = FW_PS_STATE_RF_ON_88E;
+				rtlhal->fw_ps_state = FW_PS_STATE_RF_ON;
 				RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
-					 "Receive CPWM INT!!! Set "
-					 "pHalData->FwPSState = %X\n",
+					 "Receive CPWM INT!!! Set pHalData->FwPSState = %X\n",
 					 rtlhal->fw_ps_state);
 			}
 		}
+
 		spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
 		rtlhal->fw_clk_change_in_progress = false;
 		spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
-		if (schedule_timer) {
+		if (b_schedule_timer)
 			mod_timer(&rtlpriv->works.fw_clockoff_timer,
 				  jiffies + MSECS(10));
-		}
 	} else  {
 		spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
 		rtlhal->fw_clk_change_in_progress = false;
@@ -187,7 +192,7 @@
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl8192_tx_ring *ring;
 	enum rf_pwrstate rtstate;
-	bool schedule_timer = false;
+	bool b_schedule_timer = false;
 	u8 queue;
 
 	if (!rtlhal->fw_ready)
@@ -203,17 +208,18 @@
 	for (queue = 0; queue < RTL_PCI_MAX_TX_QUEUE_COUNT; queue++) {
 		ring = &rtlpci->tx_ring[queue];
 		if (skb_queue_len(&ring->queue)) {
-			schedule_timer = true;
+			b_schedule_timer = true;
 			break;
 		}
 	}
-	if (schedule_timer) {
+
+	if (b_schedule_timer) {
 		mod_timer(&rtlpriv->works.fw_clockoff_timer,
 			  jiffies + MSECS(10));
 		return;
 	}
-	if (FW_PS_STATE(rtlhal->fw_ps_state) !=
-	    FW_PS_STATE_RF_OFF_LOW_PWR_88E) {
+
+	if (FW_PS_STATE(rtlhal->fw_ps_state) != FW_PS_STATE_RF_OFF_LOW_PWR) {
 		spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
 		if (!rtlhal->fw_clk_change_in_progress) {
 			rtlhal->fw_clk_change_in_progress = true;
@@ -221,7 +227,7 @@
 			rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val);
 			rtl_write_word(rtlpriv, REG_HISR, 0x0100);
 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
-						      &rpwm_val);
+						      (u8 *)(&rpwm_val));
 			spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
 			rtlhal->fw_clk_change_in_progress = false;
 			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
@@ -231,12 +237,13 @@
 				  jiffies + MSECS(10));
 		}
 	}
+
 }
 
 static void _rtl8723be_set_fw_ps_rf_on(struct ieee80211_hw *hw)
 {
 	u8 rpwm_val = 0;
-	rpwm_val |= (FW_PS_STATE_RF_OFF_88E | FW_PS_ACK);
+	rpwm_val |= (FW_PS_STATE_RF_OFF | FW_PS_ACK);
 	_rtl8723be_set_fw_clock_on(hw, rpwm_val, true);
 }
 
@@ -249,21 +256,23 @@
 	u8 rpwm_val = 0, fw_pwrmode = FW_PS_ACTIVE_MODE;
 
 	if (ppsc->low_power_enable) {
-		rpwm_val = (FW_PS_STATE_ALL_ON_88E | FW_PS_ACK);/* RF on */
+		rpwm_val = (FW_PS_STATE_ALL_ON | FW_PS_ACK);/* RF on */
 		_rtl8723be_set_fw_clock_on(hw, rpwm_val, false);
 		rtlhal->allow_sw_to_change_hwclc = false;
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-					      &fw_pwrmode);
+					      (u8 *)(&fw_pwrmode));
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
 					      (u8 *)(&fw_current_inps));
 	} else {
-		rpwm_val = FW_PS_STATE_ALL_ON_88E;	/* RF on */
-		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, &rpwm_val);
+		rpwm_val = FW_PS_STATE_ALL_ON;	/* RF on */
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+					      (u8 *)(&rpwm_val));
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-					      &fw_pwrmode);
+					      (u8 *)(&fw_pwrmode));
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
 					      (u8 *)(&fw_current_inps));
 	}
+
 }
 
 static void _rtl8723be_fwlps_enter(struct ieee80211_hw *hw)
@@ -275,22 +284,23 @@
 	u8 rpwm_val;
 
 	if (ppsc->low_power_enable) {
-		rpwm_val = FW_PS_STATE_RF_OFF_LOW_PWR_88E;	/* RF off */
+		rpwm_val = FW_PS_STATE_RF_OFF_LOW_PWR;	/* RF off */
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
 					      (u8 *)(&fw_current_inps));
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-					      &ppsc->fwctrl_psmode);
+					      (u8 *)(&ppsc->fwctrl_psmode));
 		rtlhal->allow_sw_to_change_hwclc = true;
 		_rtl8723be_set_fw_clock_off(hw, rpwm_val);
-
 	} else {
-		rpwm_val = FW_PS_STATE_RF_OFF_88E;	/* RF off */
+		rpwm_val = FW_PS_STATE_RF_OFF;	/* RF off */
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
 					      (u8 *)(&fw_current_inps));
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
-					      &ppsc->fwctrl_psmode);
-		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, &rpwm_val);
+					      (u8 *)(&ppsc->fwctrl_psmode));
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+					      (u8 *)(&rpwm_val));
 	}
+
 }
 
 void rtl8723be_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
@@ -306,13 +316,13 @@
 	case HW_VAR_RF_STATE:
 		*((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
 		break;
-	case HW_VAR_FWLPS_RF_ON: {
-		enum rf_pwrstate rfstate;
+	case HW_VAR_FWLPS_RF_ON:{
+		enum rf_pwrstate rfState;
 		u32 val_rcr;
 
 		rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE,
-					      (u8 *)(&rfstate));
-		if (rfstate == ERFOFF) {
+					      (u8 *)(&rfState));
+		if (rfState == ERFOFF) {
 			*((bool *)(val)) = true;
 		} else {
 			val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
@@ -322,11 +332,12 @@
 			else
 				*((bool *)(val)) = true;
 		}
-		break; }
+		}
+		break;
 	case HW_VAR_FW_PSMODE_STATUS:
 		*((bool *)(val)) = ppsc->fw_current_inpsmode;
 		break;
-	case HW_VAR_CORRECT_TSF: {
+	case HW_VAR_CORRECT_TSF:{
 		u64 tsf;
 		u32 *ptsf_low = (u32 *)&tsf;
 		u32 *ptsf_high = ((u32 *)&tsf) + 1;
@@ -335,15 +346,65 @@
 		*ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
 
 		*((u64 *)(val)) = tsf;
-
-		break; }
+		}
+		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 			 "switch case not process %x\n", variable);
 		break;
 	}
 }
 
+static void _rtl8723be_download_rsvd_page(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 tmp_regcr, tmp_reg422, bcnvalid_reg;
+	u8 count = 0, dlbcn_count = 0;
+	bool b_recover = false;
+
+	tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
+	rtl_write_byte(rtlpriv, REG_CR + 1,
+		       (tmp_regcr | BIT(0)));
+
+	_rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(3));
+	_rtl8723be_set_bcn_ctrl_reg(hw, BIT(4), 0);
+
+	tmp_reg422 = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp_reg422 & (~BIT(6)));
+	if (tmp_reg422 & BIT(6))
+		b_recover = true;
+
+	do {
+		bcnvalid_reg = rtl_read_byte(rtlpriv, REG_TDECTRL + 2);
+		rtl_write_byte(rtlpriv, REG_TDECTRL + 2,
+			       (bcnvalid_reg | BIT(0)));
+		_rtl8723be_return_beacon_queue_skb(hw);
+
+		rtl8723be_set_fw_rsvdpagepkt(hw, 0);
+		bcnvalid_reg = rtl_read_byte(rtlpriv, REG_TDECTRL + 2);
+		count = 0;
+		while (!(bcnvalid_reg & BIT(0)) && count < 20) {
+			count++;
+			udelay(10);
+			bcnvalid_reg = rtl_read_byte(rtlpriv,
+						     REG_TDECTRL + 2);
+		}
+		dlbcn_count++;
+	} while (!(bcnvalid_reg & BIT(0)) && dlbcn_count < 5);
+
+	if (bcnvalid_reg & BIT(0))
+		rtl_write_byte(rtlpriv, REG_TDECTRL + 2, BIT(0));
+
+	_rtl8723be_set_bcn_ctrl_reg(hw, BIT(3), 0);
+	_rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(4));
+
+	if (b_recover)
+		rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp_reg422);
+
+	tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
+	rtl_write_byte(rtlpriv, REG_CR + 1, (tmp_regcr & ~(BIT(0))));
+}
+
 void rtl8723be_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -358,22 +419,24 @@
 		for (idx = 0; idx < ETH_ALEN; idx++)
 			rtl_write_byte(rtlpriv, (REG_MACID + idx), val[idx]);
 		break;
-	case HW_VAR_BASIC_RATE: {
-		u16 rate_cfg = ((u16 *)val)[0];
+	case HW_VAR_BASIC_RATE:{
+		u16 b_rate_cfg = ((u16 *)val)[0];
 		u8 rate_index = 0;
-		rate_cfg = rate_cfg & 0x15f;
-		rate_cfg |= 0x01;
-		rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff);
-		rtl_write_byte(rtlpriv, REG_RRSR + 1, (rate_cfg >> 8) & 0xff);
-		while (rate_cfg > 0x1) {
-			rate_cfg = (rate_cfg >> 1);
+		b_rate_cfg = b_rate_cfg & 0x15f;
+		b_rate_cfg |= 0x01;
+		rtl_write_byte(rtlpriv, REG_RRSR, b_rate_cfg & 0xff);
+		rtl_write_byte(rtlpriv, REG_RRSR + 1, (b_rate_cfg >> 8) & 0xff);
+		while (b_rate_cfg > 0x1) {
+			b_rate_cfg = (b_rate_cfg >> 1);
 			rate_index++;
 		}
 		rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, rate_index);
-		break; }
+		}
+		break;
 	case HW_VAR_BSSID:
 		for (idx = 0; idx < ETH_ALEN; idx++)
 			rtl_write_byte(rtlpriv, (REG_BSSID + idx), val[idx]);
+
 		break;
 	case HW_VAR_SIFS:
 		rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]);
@@ -388,7 +451,7 @@
 			rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
 				       *((u16 *)val));
 		break;
-	case HW_VAR_SLOT_TIME: {
+	case HW_VAR_SLOT_TIME:{
 		u8 e_aci;
 
 		RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
@@ -398,12 +461,13 @@
 
 		for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
-						      &e_aci);
+						      (u8 *)(&e_aci));
 		}
-		break; }
-	case HW_VAR_ACK_PREAMBLE: {
+		}
+		break;
+	case HW_VAR_ACK_PREAMBLE:{
 		u8 reg_tmp;
-		u8 short_preamble = (bool)*val;
+		u8 short_preamble = (bool)(*(u8 *)val);
 		reg_tmp = rtl_read_byte(rtlpriv, REG_TRXPTCL_CTL + 2);
 		if (short_preamble) {
 			reg_tmp |= 0x02;
@@ -412,15 +476,16 @@
 			reg_tmp &= 0xFD;
 			rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp);
 		}
-		break; }
-	case HW_VAR_WPA_CONFIG:
-		rtl_write_byte(rtlpriv, REG_SECCFG, *val);
+		}
 		break;
-	case HW_VAR_AMPDU_MIN_SPACE: {
+	case HW_VAR_WPA_CONFIG:
+		rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *)val));
+		break;
+	case HW_VAR_AMPDU_MIN_SPACE:{
 		u8 min_spacing_to_set;
 		u8 sec_min_space;
 
-		min_spacing_to_set = *val;
+		min_spacing_to_set = *((u8 *)val);
 		if (min_spacing_to_set <= 7) {
 			sec_min_space = 0;
 
@@ -434,26 +499,28 @@
 
 			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
 				 "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
-				 mac->min_space_cfg);
+				  mac->min_space_cfg);
 
 			rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
 				       mac->min_space_cfg);
 		}
-		break; }
-	case HW_VAR_SHORTGI_DENSITY: {
+		}
+		break;
+	case HW_VAR_SHORTGI_DENSITY:{
 		u8 density_to_set;
 
-		density_to_set = *val;
+		density_to_set = *((u8 *)val);
 		mac->min_space_cfg |= (density_to_set << 3);
 
 		RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
 			 "Set HW_VAR_SHORTGI_DENSITY: %#x\n",
-			 mac->min_space_cfg);
+			  mac->min_space_cfg);
 
 		rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
 			       mac->min_space_cfg);
-		break; }
-	case HW_VAR_AMPDU_FACTOR: {
+		}
+		break;
+	case HW_VAR_AMPDU_FACTOR:{
 		u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9};
 		u8 factor_toset;
 		u8 *p_regtoset = NULL;
@@ -461,7 +528,7 @@
 
 		p_regtoset = regtoset_normal;
 
-		factor_toset = *val;
+		factor_toset = *((u8 *)val);
 		if (factor_toset <= 3) {
 			factor_toset = (1 << (factor_toset + 2));
 			if (factor_toset > 0xf)
@@ -482,22 +549,26 @@
 				rtl_write_byte(rtlpriv,
 					       (REG_AGGLEN_LMT + index),
 					       p_regtoset[index]);
+
 			}
+
 			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
 				 "Set HW_VAR_AMPDU_FACTOR: %#x\n",
-				 factor_toset);
+				  factor_toset);
 		}
-		break; }
-	case HW_VAR_AC_PARAM: {
-		u8 e_aci = *val;
+		}
+		break;
+	case HW_VAR_AC_PARAM:{
+		u8 e_aci = *((u8 *)val);
 		rtl8723_dm_init_edca_turbo(hw);
 
 		if (rtlpci->acm_method != EACMWAY2_SW)
 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
-						      &e_aci);
-		break; }
-	case HW_VAR_ACM_CTRL: {
-		u8 e_aci = *val;
+						      (u8 *)(&e_aci));
+		}
+		break;
+	case HW_VAR_ACM_CTRL:{
+		u8 e_aci = *((u8 *)val);
 		union aci_aifsn *p_aci_aifsn =
 				(union aci_aifsn *)(&(mac->ac[0].aifs));
 		u8 acm = p_aci_aifsn->f.acm;
@@ -519,8 +590,8 @@
 				break;
 			default:
 				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-					 "HW_VAR_ACM_CTRL acm set "
-					  "failed: eACI is %d\n", acm);
+					 "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n",
+					 acm);
 				break;
 			}
 		} else {
@@ -535,27 +606,30 @@
 				acm_ctrl &= (~ACMHW_BEQEN);
 				break;
 			default:
-				RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 					 "switch case not process\n");
 				break;
 			}
 		}
+
 		RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
-			 "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] "
-			 "Write 0x%X\n", acm_ctrl);
+			 "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n",
+			 acm_ctrl);
 		rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl);
-		break; }
+		}
+		break;
 	case HW_VAR_RCR:
 		rtl_write_dword(rtlpriv, REG_RCR, ((u32 *)(val))[0]);
 		rtlpci->receive_config = ((u32 *)(val))[0];
 		break;
-	case HW_VAR_RETRY_LIMIT: {
-		u8 retry_limit = *val;
+	case HW_VAR_RETRY_LIMIT:{
+		u8 retry_limit = ((u8 *)(val))[0];
 
 		rtl_write_word(rtlpriv, REG_RL,
 			       retry_limit << RETRY_LIMIT_SHORT_SHIFT |
 			       retry_limit << RETRY_LIMIT_LONG_SHIFT);
-		break; }
+		}
+		break;
 	case HW_VAR_DUAL_TSF_RST:
 		rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1)));
 		break;
@@ -563,25 +637,27 @@
 		rtlefuse->efuse_usedbytes = *((u16 *)val);
 		break;
 	case HW_VAR_EFUSE_USAGE:
-		rtlefuse->efuse_usedpercentage = *val;
+		rtlefuse->efuse_usedpercentage = *((u8 *)val);
 		break;
 	case HW_VAR_IO_CMD:
 		rtl8723be_phy_set_io_cmd(hw, (*(enum io_type *)val));
 		break;
-	case HW_VAR_SET_RPWM: {
+	case HW_VAR_SET_RPWM:{
 		u8 rpwm_val;
 
 		rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM);
 		udelay(1);
 
 		if (rpwm_val & BIT(7)) {
-			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val);
+			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, (*(u8 *)val));
 		} else {
-			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, *val | BIT(7));
+			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+				       ((*(u8 *)val) | BIT(7)));
 		}
-		break; }
+		}
+		break;
 	case HW_VAR_H2C_FW_PWRMODE:
-		rtl8723be_set_fw_pwrmode_cmd(hw, *val);
+		rtl8723be_set_fw_pwrmode_cmd(hw, (*(u8 *)val));
 		break;
 	case HW_VAR_FW_PSMODE_STATUS:
 		ppsc->fw_current_inpsmode = *((bool *)val);
@@ -589,85 +665,38 @@
 	case HW_VAR_RESUME_CLK_ON:
 		_rtl8723be_set_fw_ps_rf_on(hw);
 		break;
-	case HW_VAR_FW_LPS_ACTION: {
-		bool enter_fwlps = *((bool *)val);
+	case HW_VAR_FW_LPS_ACTION:{
+		bool b_enter_fwlps = *((bool *)val);
 
-		if (enter_fwlps)
+		if (b_enter_fwlps)
 			_rtl8723be_fwlps_enter(hw);
 		else
 			_rtl8723be_fwlps_leave(hw);
-
-		break; }
-	case HW_VAR_H2C_FW_JOINBSSRPT: {
-		u8 mstatus = *val;
-		u8 tmp_regcr, tmp_reg422, bcnvalid_reg;
-		u8 count = 0, dlbcn_count = 0;
-		bool recover = false;
+		}
+		break;
+	case HW_VAR_H2C_FW_JOINBSSRPT:{
+		u8 mstatus = (*(u8 *)val);
 
 		if (mstatus == RT_MEDIA_CONNECT) {
 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL);
-
-			tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
-			rtl_write_byte(rtlpriv, REG_CR + 1,
-				       (tmp_regcr | BIT(0)));
-
-			_rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(3));
-			_rtl8723be_set_bcn_ctrl_reg(hw, BIT(4), 0);
-
-			tmp_reg422 = rtl_read_byte(rtlpriv,
-						   REG_FWHW_TXQ_CTRL + 2);
-			rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
-				       tmp_reg422 & (~BIT(6)));
-			if (tmp_reg422 & BIT(6))
-				recover = true;
-
-			do {
-				bcnvalid_reg = rtl_read_byte(rtlpriv,
-							     REG_TDECTRL + 2);
-				rtl_write_byte(rtlpriv, REG_TDECTRL + 2,
-					       (bcnvalid_reg | BIT(0)));
-				_rtl8723be_return_beacon_queue_skb(hw);
-
-				rtl8723be_set_fw_rsvdpagepkt(hw, 0);
-				bcnvalid_reg = rtl_read_byte(rtlpriv,
-							     REG_TDECTRL + 2);
-				count = 0;
-				while (!(bcnvalid_reg & BIT(0)) && count < 20) {
-					count++;
-					udelay(10);
-					bcnvalid_reg = rtl_read_byte(rtlpriv,
-							       REG_TDECTRL + 2);
-				}
-				dlbcn_count++;
-			} while (!(bcnvalid_reg & BIT(0)) && dlbcn_count < 5);
-
-			if (bcnvalid_reg & BIT(0))
-				rtl_write_byte(rtlpriv, REG_TDECTRL+2, BIT(0));
-
-			_rtl8723be_set_bcn_ctrl_reg(hw, BIT(3), 0);
-			_rtl8723be_set_bcn_ctrl_reg(hw, 0, BIT(4));
-
-			if (recover) {
-				rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
-					       tmp_reg422);
-			}
-			rtl_write_byte(rtlpriv, REG_CR + 1,
-				       (tmp_regcr & ~(BIT(0))));
+			_rtl8723be_download_rsvd_page(hw);
 		}
-		rtl8723be_set_fw_joinbss_report_cmd(hw, *val);
-		break; }
-	case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
-		rtl8723be_set_p2p_ps_offload_cmd(hw, *val);
+		rtl8723be_set_fw_media_status_rpt_cmd(hw, mstatus);
+		}
 		break;
-	case HW_VAR_AID: {
+	case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+		rtl8723be_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+		break;
+	case HW_VAR_AID:{
 		u16 u2btmp;
 		u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
 		u2btmp &= 0xC000;
 		rtl_write_word(rtlpriv, REG_BCN_PSR_RPT,
 			       (u2btmp | mac->assoc_id));
-		break; }
-	case HW_VAR_CORRECT_TSF: {
-		u8 btype_ibss = *val;
+		}
+		break;
+	case HW_VAR_CORRECT_TSF:{
+		u8 btype_ibss = ((u8 *)(val))[0];
 
 		if (btype_ibss)
 			_rtl8723be_stop_tx_beacon(hw);
@@ -683,16 +712,17 @@
 
 		if (btype_ibss)
 			_rtl8723be_resume_tx_beacon(hw);
-		break; }
-	case HW_VAR_KEEP_ALIVE: {
+		}
+		break;
+	case HW_VAR_KEEP_ALIVE:{
 		u8 array[2];
 		array[0] = 0xff;
-		array[1] = *val;
-		rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_KEEP_ALIVE_CTRL,
-				       2, array);
-		break; }
+		array[1] = *((u8 *)val);
+		rtl8723be_fill_h2c_cmd(hw, H2C_8723B_KEEP_ALIVE_CTRL, 2, array);
+		}
+		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 			 "switch case not process %x\n",
 			 variable);
 		break;
@@ -703,7 +733,7 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	bool status = true;
-	int count = 0;
+	long count = 0;
 	u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) |
 		    _LLT_OP(_LLT_WRITE_ACCESS);
 
@@ -716,8 +746,8 @@
 
 		if (count > POLLING_LLT_THRESHOLD) {
 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Failed to polling write LLT done at "
-				  "address %d!\n", address);
+				 "Failed to polling write LLT done at address %d!\n",
+				 address);
 			status = false;
 			break;
 		}
@@ -731,10 +761,10 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	unsigned short i;
 	u8 txpktbuf_bndy;
-	u8 maxpage;
+	u8 maxPage;
 	bool status;
 
-	maxpage = 255;
+	maxPage = 255;
 	txpktbuf_bndy = 245;
 
 	rtl_write_dword(rtlpriv, REG_TRXFF_BNDY,
@@ -753,17 +783,19 @@
 		if (!status)
 			return status;
 	}
+
 	status = _rtl8723be_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
 
 	if (!status)
 		return status;
 
-	for (i = txpktbuf_bndy; i < maxpage; i++) {
+	for (i = txpktbuf_bndy; i < maxPage; i++) {
 		status = _rtl8723be_llt_write(hw, i, (i + 1));
 		if (!status)
 			return status;
 	}
-	status = _rtl8723be_llt_write(hw, maxpage, txpktbuf_bndy);
+
+	status = _rtl8723be_llt_write(hw, maxPage, txpktbuf_bndy);
 	if (!status)
 		return status;
 
@@ -795,11 +827,9 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
 	unsigned char bytetmp;
 	unsigned short wordtmp;
-	u16 retry = 0;
-	bool mac_func_enable;
 
 	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00);
 
@@ -807,12 +837,6 @@
 	bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) & (~BIT(7));
 	rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp);
 
-	bytetmp = rtl_read_byte(rtlpriv, REG_CR);
-	if (bytetmp == 0xFF)
-		mac_func_enable = true;
-	else
-		mac_func_enable = false;
-
 	/* HW Power on sequence */
 	if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK,
 				      PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,
@@ -821,6 +845,10 @@
 			 "init MAC Fail as power on failure\n");
 		return false;
 	}
+
+	bytetmp = rtl_read_byte(rtlpriv, REG_MULTI_FUNC_CTRL);
+	rtl_write_byte(rtlpriv, REG_MULTI_FUNC_CTRL, bytetmp | BIT(3));
+
 	bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO) | BIT(4);
 	rtl_write_byte(rtlpriv, REG_APS_FSMCO, bytetmp);
 
@@ -837,25 +865,21 @@
 	bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CFG + 3);
 	if (bytetmp & BIT(0)) {
 		bytetmp = rtl_read_byte(rtlpriv, 0x7c);
-		bytetmp |= BIT(6);
-		rtl_write_byte(rtlpriv, 0x7c, bytetmp);
+		rtl_write_byte(rtlpriv, 0x7c, bytetmp | BIT(6));
 	}
-	bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CLKR);
-	bytetmp |= BIT(3);
-	rtl_write_byte(rtlpriv, REG_SYS_CLKR, bytetmp);
-	bytetmp = rtl_read_byte(rtlpriv, REG_GPIO_MUXCFG + 1);
-	bytetmp &= ~BIT(4);
-	rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG + 1, bytetmp);
 
-	bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG+3);
-	rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+3, bytetmp | 0x77);
+	bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CLKR);
+	rtl_write_byte(rtlpriv, REG_SYS_CLKR, bytetmp | BIT(3));
+	bytetmp = rtl_read_byte(rtlpriv, REG_GPIO_MUXCFG + 1);
+	rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG + 1, bytetmp & (~BIT(4)));
 
 	rtl_write_word(rtlpriv, REG_CR, 0x2ff);
 
-	if (!mac_func_enable) {
-		if (!_rtl8723be_llt_table_init(hw))
+	if (!rtlhal->mac_func_enable) {
+		if (_rtl8723be_llt_table_init(hw) == false)
 			return false;
 	}
+
 	rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff);
 	rtl_write_dword(rtlpriv, REG_HISRE, 0xffffffff);
 
@@ -873,8 +897,6 @@
 	rtl_write_word(rtlpriv, REG_RXFLTMAP2, 0xFFFF);
 	rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config);
 
-	rtl_write_byte(rtlpriv, 0x4d0, 0x0);
-
 	rtl_write_dword(rtlpriv, REG_BCNQ_DESA,
 			((u64) rtlpci->tx_ring[BEACON_QUEUE].dma) &
 			DMA_BIT_MASK(32));
@@ -901,57 +923,213 @@
 
 	rtl_write_dword(rtlpriv, REG_INT_MIG, 0);
 
-	bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL);
-	rtl_write_byte(rtlpriv, REG_APSD_CTRL, bytetmp & ~BIT(6));
+	rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0);
 
 	rtl_write_byte(rtlpriv, REG_SECONDARY_CCA_CTRL, 0x3);
 
-	do {
-		retry++;
-		bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL);
-	} while ((retry < 200) && (bytetmp & BIT(7)));
-
-	_rtl8723be_gen_refresh_led_state(hw);
-
-	rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0);
+	/* <20130114, Kordan> The following setting is
+	 * only for DPDT and Fixed board type.
+	 * TODO:  A better solution is configure it
+	 * according EFUSE during the run-time.
+	 */
+	rtl_set_bbreg(hw, 0x64, BIT(20), 0x0);/* 0x66[4]=0 */
+	rtl_set_bbreg(hw, 0x64, BIT(24), 0x0);/* 0x66[8]=0 */
+	rtl_set_bbreg(hw, 0x40, BIT(4), 0x0)/* 0x40[4]=0 */;
+	rtl_set_bbreg(hw, 0x40, BIT(3), 0x1)/* 0x40[3]=1 */;
+	rtl_set_bbreg(hw, 0x4C, BIT(24) | BIT(23), 0x2)/* 0x4C[24:23]=10 */;
+	rtl_set_bbreg(hw, 0x944, BIT(1) | BIT(0), 0x3)/* 0x944[1:0]=11 */;
+	rtl_set_bbreg(hw, 0x930, MASKBYTE0, 0x77)/* 0x930[7:0]=77 */;
+	rtl_set_bbreg(hw, 0x38, BIT(11), 0x1)/* 0x38[11]=1 */;
 
 	bytetmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
-	rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, bytetmp & ~BIT(2));
+	rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, bytetmp & (~BIT(2)));
 
+	_rtl8723be_gen_refresh_led_state(hw);
 	return true;
 }
 
 static void _rtl8723be_hw_configure(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u8 reg_bw_opmode;
-	u32 reg_ratr, reg_prsr;
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u32 reg_rrsr;
 
-	reg_bw_opmode = BW_OPMODE_20MHZ;
-	reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
-		   RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
-	reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
+	reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
+	/* Init value for RRSR. */
+	rtl_write_dword(rtlpriv, REG_RRSR, reg_rrsr);
 
-	rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr);
-	rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF);
+	/* ARFB table 9 for 11ac 5G 2SS */
+	rtl_write_dword(rtlpriv, REG_ARFR0 + 4, 0xfffff000);
+
+	/* ARFB table 10 for 11ac 5G 1SS */
+	rtl_write_dword(rtlpriv, REG_ARFR1 + 4, 0x003ff000);
+
+	/* CF-End setting. */
+	rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F00);
+
+	/* 0x456 = 0x70, sugguested by Zhilin */
+	rtl_write_byte(rtlpriv, REG_AMPDU_MAX_TIME, 0x70);
+
+	/* Set retry limit */
+	rtl_write_word(rtlpriv, REG_RL, 0x0707);
+
+	/* Set Data / Response auto rate fallack retry count */
+	rtl_write_dword(rtlpriv, REG_DARFRC, 0x01000000);
+	rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x07060504);
+	rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000);
+	rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504);
+
+	rtlpci->reg_bcn_ctrl_val = 0x1d;
+	rtl_write_byte(rtlpriv, REG_BCN_CTRL, rtlpci->reg_bcn_ctrl_val);
+
+	/* TBTT prohibit hold time. Suggested by designer TimChen. */
+	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); /* 8 ms */
+
+	rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0040);
+
+	/*For Rx TP. Suggested by SD1 Richard. Added by tynli. 2010.04.12.*/
+	rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666);
+
+	rtl_write_byte(rtlpriv, REG_HT_SINGLE_AMPDU, 0x80);
+
+	rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x20);
+
+	rtl_write_byte(rtlpriv, REG_MAX_AGGR_NUM, 0x1F);
+}
+
+static u8 _rtl8723be_dbi_read(struct rtl_priv *rtlpriv, u16 addr)
+{
+	u16 read_addr = addr & 0xfffc;
+	u8 ret = 0, tmp = 0, count = 0;
+
+	rtl_write_word(rtlpriv, REG_DBI_ADDR, read_addr);
+	rtl_write_byte(rtlpriv, REG_DBI_FLAG, 0x2);
+	tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG);
+	count = 0;
+	while (tmp && count < 20) {
+		udelay(10);
+		tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG);
+		count++;
+	}
+	if (0 == tmp) {
+		read_addr = REG_DBI_RDATA + addr % 4;
+		ret = rtl_read_byte(rtlpriv, read_addr);
+	}
+
+	return ret;
+}
+
+static void _rtl8723be_dbi_write(struct rtl_priv *rtlpriv, u16 addr, u8 data)
+{
+	u8 tmp = 0, count = 0;
+	u16 write_addr = 0, remainder = addr % 4;
+
+	/* Write DBI 1Byte Data */
+	write_addr = REG_DBI_WDATA + remainder;
+	rtl_write_byte(rtlpriv, write_addr, data);
+
+	/* Write DBI 2Byte Address & Write Enable */
+	write_addr = (addr & 0xfffc) | (BIT(0) << (remainder + 12));
+	rtl_write_word(rtlpriv, REG_DBI_ADDR, write_addr);
+
+	/* Write DBI Write Flag */
+	rtl_write_byte(rtlpriv, REG_DBI_FLAG, 0x1);
+
+	tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG);
+	count = 0;
+	while (tmp && count < 20) {
+		udelay(10);
+		tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG);
+		count++;
+	}
+}
+
+static u16 _rtl8723be_mdio_read(struct rtl_priv *rtlpriv, u8 addr)
+{
+	u16 ret = 0;
+	u8 tmp = 0, count = 0;
+
+	rtl_write_byte(rtlpriv, REG_MDIO_CTL, addr | BIT(6));
+	tmp = rtl_read_byte(rtlpriv, REG_MDIO_CTL) & BIT(6);
+	count = 0;
+	while (tmp && count < 20) {
+		udelay(10);
+		tmp = rtl_read_byte(rtlpriv, REG_MDIO_CTL) & BIT(6);
+		count++;
+	}
+
+	if (0 == tmp)
+		ret = rtl_read_word(rtlpriv, REG_MDIO_RDATA);
+
+	return ret;
+}
+
+static void _rtl8723be_mdio_write(struct rtl_priv *rtlpriv, u8 addr, u16 data)
+{
+	u8 tmp = 0, count = 0;
+
+	rtl_write_word(rtlpriv, REG_MDIO_WDATA, data);
+	rtl_write_byte(rtlpriv, REG_MDIO_CTL, addr | BIT(5));
+	tmp = rtl_read_byte(rtlpriv, REG_MDIO_CTL) & BIT(5);
+	count = 0;
+	while (tmp && count < 20) {
+		udelay(10);
+		tmp = rtl_read_byte(rtlpriv, REG_MDIO_CTL) & BIT(5);
+		count++;
+	}
 }
 
 static void _rtl8723be_enable_aspm_back_door(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	u8 tmp8 = 0;
+	u16 tmp16 = 0;
 
-	rtl_write_byte(rtlpriv, 0x34b, 0x93);
-	rtl_write_word(rtlpriv, 0x350, 0x870c);
-	rtl_write_byte(rtlpriv, 0x352, 0x1);
+	/* <Roger_Notes> Overwrite following ePHY parameter for
+	 * some platform compatibility issue,
+	 * especially when CLKReq is enabled, 2012.11.09.
+	 */
+	tmp16 = _rtl8723be_mdio_read(rtlpriv, 0x01);
+	if (tmp16 != 0x0663)
+		_rtl8723be_mdio_write(rtlpriv, 0x01, 0x0663);
 
-	if (ppsc->support_backdoor)
-		rtl_write_byte(rtlpriv, 0x349, 0x1b);
-	else
-		rtl_write_byte(rtlpriv, 0x349, 0x03);
+	tmp16 = _rtl8723be_mdio_read(rtlpriv, 0x04);
+	if (tmp16 != 0x7544)
+		_rtl8723be_mdio_write(rtlpriv, 0x04, 0x7544);
 
-	rtl_write_word(rtlpriv, 0x350, 0x2718);
-	rtl_write_byte(rtlpriv, 0x352, 0x1);
+	tmp16 = _rtl8723be_mdio_read(rtlpriv, 0x06);
+	if (tmp16 != 0xB880)
+		_rtl8723be_mdio_write(rtlpriv, 0x06, 0xB880);
+
+	tmp16 = _rtl8723be_mdio_read(rtlpriv, 0x07);
+	if (tmp16 != 0x4000)
+		_rtl8723be_mdio_write(rtlpriv, 0x07, 0x4000);
+
+	tmp16 = _rtl8723be_mdio_read(rtlpriv, 0x08);
+	if (tmp16 != 0x9003)
+		_rtl8723be_mdio_write(rtlpriv, 0x08, 0x9003);
+
+	tmp16 = _rtl8723be_mdio_read(rtlpriv, 0x09);
+	if (tmp16 != 0x0D03)
+		_rtl8723be_mdio_write(rtlpriv, 0x09, 0x0D03);
+
+	tmp16 = _rtl8723be_mdio_read(rtlpriv, 0x0A);
+	if (tmp16 != 0x4037)
+		_rtl8723be_mdio_write(rtlpriv, 0x0A, 0x4037);
+
+	tmp16 = _rtl8723be_mdio_read(rtlpriv, 0x0B);
+	if (tmp16 != 0x0070)
+		_rtl8723be_mdio_write(rtlpriv, 0x0B, 0x0070);
+
+	/* Configuration Space offset 0x70f BIT7 is used to control L0S */
+	tmp8 = _rtl8723be_dbi_read(rtlpriv, 0x70f);
+	_rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7));
+
+	/* Configuration Space offset 0x719 Bit3 is for L1
+	 * BIT4 is for clock request
+	 */
+	tmp8 = _rtl8723be_dbi_read(rtlpriv, 0x719);
+	_rtl8723be_dbi_write(rtlpriv, 0x719, tmp8 | BIT(3) | BIT(4));
 }
 
 void rtl8723be_enable_hw_security_config(struct ieee80211_hw *hw)
@@ -961,30 +1139,208 @@
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
 		 "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n",
-		 rtlpriv->sec.pairwise_enc_algorithm,
-		 rtlpriv->sec.group_enc_algorithm);
+		  rtlpriv->sec.pairwise_enc_algorithm,
+		  rtlpriv->sec.group_enc_algorithm);
 
 	if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
 		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 			 "not open hw encryption\n");
 		return;
 	}
+
 	sec_reg_value = SCR_TXENCENABLE | SCR_RXDECENABLE;
 
 	if (rtlpriv->sec.use_defaultkey) {
 		sec_reg_value |= SCR_TXUSEDK;
 		sec_reg_value |= SCR_RXUSEDK;
 	}
+
 	sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK);
 
 	rtl_write_byte(rtlpriv, REG_CR + 1, 0x02);
 
-	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "The SECR-value %x\n",
-		 sec_reg_value);
+	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+		 "The SECR-value %x\n", sec_reg_value);
 
 	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
 }
 
+static void _rtl8723be_poweroff_adapter(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 u1b_tmp;
+
+	rtlhal->mac_func_enable = false;
+	/* Combo (PCIe + USB) Card and PCIe-MF Card */
+	/* 1. Run LPS WL RFOFF flow */
+	rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+				 PWR_INTF_PCI_MSK, RTL8723_NIC_LPS_ENTER_FLOW);
+
+	/* 2. 0x1F[7:0] = 0 */
+	/* turn off RF */
+	/* rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00); */
+	if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) &&
+	    rtlhal->fw_ready) {
+		rtl8723be_firmware_selfreset(hw);
+	}
+
+	/* Reset MCU. Suggested by Filen. */
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
+
+	/* g.	MCUFWDL 0x80[1:0]=0	 */
+	/* reset MCU ready status */
+	rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
+
+	/* HW card disable configuration. */
+	rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+				 PWR_INTF_PCI_MSK, RTL8723_NIC_DISABLE_FLOW);
+
+	/* Reset MCU IO Wrapper */
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, u1b_tmp | BIT(0));
+
+	/* 7. RSV_CTRL 0x1C[7:0] = 0x0E */
+	/* lock ISO/CLK/Power control register */
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e);
+}
+
+static bool _rtl8723be_check_pcie_dma_hang(struct rtl_priv *rtlpriv)
+{
+	u8 tmp;
+
+	/* write reg 0x350 Bit[26]=1. Enable debug port. */
+	tmp = rtl_read_byte(rtlpriv, REG_DBI_CTRL + 3);
+	if (!(tmp & BIT(2))) {
+		rtl_write_byte(rtlpriv, REG_DBI_CTRL + 3, (tmp | BIT(2)));
+		mdelay(100); /* Suggested by DD Justin_tsai. */
+	}
+
+	/* read reg 0x350 Bit[25] if 1 : RX hang
+	 * read reg 0x350 Bit[24] if 1 : TX hang
+	 */
+	tmp = rtl_read_byte(rtlpriv, REG_DBI_CTRL + 3);
+	if ((tmp & BIT(0)) || (tmp & BIT(1))) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "CheckPcieDMAHang8723BE(): true!!\n");
+		return true;
+	}
+	return false;
+}
+
+static void _rtl8723be_reset_pcie_interface_dma(struct rtl_priv *rtlpriv,
+						bool mac_power_on)
+{
+	u8 tmp;
+	bool release_mac_rx_pause;
+	u8 backup_pcie_dma_pause;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "ResetPcieInterfaceDMA8723BE()\n");
+
+	/* Revise Note: Follow the document "PCIe RX DMA Hang Reset Flow_v03"
+	 * released by SD1 Alan.
+	 * 2013.05.07, by tynli.
+	 */
+
+	/* 1. disable register write lock
+	 *	write 0x1C bit[1:0] = 2'h0
+	 *	write 0xCC bit[2] = 1'b1
+	 */
+	tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL);
+	tmp &= ~(BIT(1) | BIT(0));
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL, tmp);
+	tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2);
+	tmp |= BIT(2);
+	rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp);
+
+	/* 2. Check and pause TRX DMA
+	 *	write 0x284 bit[18] = 1'b1
+	 *	write 0x301 = 0xFF
+	 */
+	tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+	if (tmp & BIT(2)) {
+		/* Already pause before the function for another purpose. */
+		release_mac_rx_pause = false;
+	} else {
+		rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, (tmp | BIT(2)));
+		release_mac_rx_pause = true;
+	}
+
+	backup_pcie_dma_pause = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 1);
+	if (backup_pcie_dma_pause != 0xFF)
+		rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xFF);
+
+	if (mac_power_on) {
+		/* 3. reset TRX function
+		 *	write 0x100 = 0x00
+		 */
+		rtl_write_byte(rtlpriv, REG_CR, 0);
+	}
+
+	/* 4. Reset PCIe DMA
+	 *	write 0x003 bit[0] = 0
+	 */
+	tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+	tmp &= ~(BIT(0));
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp);
+
+	/* 5. Enable PCIe DMA
+	 *	write 0x003 bit[0] = 1
+	 */
+	tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+	tmp |= BIT(0);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp);
+
+	if (mac_power_on) {
+		/* 6. enable TRX function
+		 *	write 0x100 = 0xFF
+		 */
+		rtl_write_byte(rtlpriv, REG_CR, 0xFF);
+
+		/* We should init LLT & RQPN and
+		 * prepare Tx/Rx descrptor address later
+		 * because MAC function is reset.
+		 */
+	}
+
+	/* 7. Restore PCIe autoload down bit
+	 *	write 0xF8 bit[17] = 1'b1
+	 */
+	tmp = rtl_read_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2);
+	tmp |= BIT(1);
+	rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2, tmp);
+
+	/* In MAC power on state, BB and RF maybe in ON state,
+	 * if we release TRx DMA here
+	 * it will cause packets to be started to Tx/Rx,
+	 * so we release Tx/Rx DMA later.
+	 */
+	if (!mac_power_on) {
+		/* 8. release TRX DMA
+		 *	write 0x284 bit[18] = 1'b0
+		 *	write 0x301 = 0x00
+		 */
+		if (release_mac_rx_pause) {
+			tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+			rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL,
+				       (tmp & (~BIT(2))));
+		}
+		rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1,
+			       backup_pcie_dma_pause);
+	}
+
+	/* 9. lock system register
+	 *	write 0xCC bit[2] = 1'b0
+	 */
+	tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2);
+	tmp &= ~(BIT(2));
+	rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp);
+}
+
 int rtl8723be_hw_init(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1002,33 +1358,51 @@
 	local_save_flags(flags);
 	local_irq_enable();
 
+	rtlhal->fw_ready = false;
 	rtlpriv->rtlhal.being_init_adapter = true;
 	rtlpriv->intf_ops->disable_aspm(hw);
+
+	tmp_u1b = rtl_read_byte(rtlpriv, REG_CR);
+	if (tmp_u1b != 0 && tmp_u1b != 0xea) {
+		rtlhal->mac_func_enable = true;
+	} else {
+		rtlhal->mac_func_enable = false;
+		rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON;
+	}
+
+	if (_rtl8723be_check_pcie_dma_hang(rtlpriv)) {
+		_rtl8723be_reset_pcie_interface_dma(rtlpriv,
+						    rtlhal->mac_func_enable);
+		rtlhal->mac_func_enable = false;
+	}
+	if (rtlhal->mac_func_enable) {
+		_rtl8723be_poweroff_adapter(hw);
+		rtlhal->mac_func_enable = false;
+	}
 	rtstatus = _rtl8723be_init_mac(hw);
 	if (!rtstatus) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
 		err = 1;
 		goto exit;
 	}
-	tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CFG);
-	tmp_u1b &= 0x7F;
-	rtl_write_byte(rtlpriv, REG_SYS_CFG, tmp_u1b);
 
-	err = rtl8723_download_fw(hw, true);
+	tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CFG);
+	rtl_write_byte(rtlpriv, REG_SYS_CFG, tmp_u1b & 0x7F);
+
+	err = rtl8723_download_fw(hw, true, FW_8723B_POLLING_TIMEOUT_COUNT);
 	if (err) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
 			 "Failed to download FW. Init HW without FW now..\n");
 		err = 1;
-		rtlhal->fw_ready = false;
 		goto exit;
-	} else {
-		rtlhal->fw_ready = true;
 	}
+	rtlhal->fw_ready = true;
+
 	rtlhal->last_hmeboxnum = 0;
 	rtl8723be_phy_mac_config(hw);
 	/* because last function modify RCR, so we update
 	 * rcr var here, or TP will unstable for receive_config
-	 * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx
+	 * is wrong, RX RCR_ACRC32 will cause TP unstable & Rx
 	 * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252
 	 */
 	rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR);
@@ -1036,7 +1410,6 @@
 	rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
 
 	rtl8723be_phy_bb_config(hw);
-	rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
 	rtl8723be_phy_rf_config(hw);
 
 	rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,
@@ -1046,10 +1419,8 @@
 	rtlphy->rfreg_chnlval[0] &= 0xFFF03FF;
 	rtlphy->rfreg_chnlval[0] |= (BIT(10) | BIT(11));
 
-	rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1);
-	rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1);
-	rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);
 	_rtl8723be_hw_configure(hw);
+	rtlhal->mac_func_enable = true;
 	rtl_cam_reset_all_entry(hw);
 	rtl8723be_enable_hw_security_config(hw);
 
@@ -1061,36 +1432,32 @@
 
 	rtl8723be_bt_hw_init(hw);
 
-	rtl_set_bbreg(hw, 0x64, BIT(20), 0);
-	rtl_set_bbreg(hw, 0x64, BIT(24), 0);
-
-	rtl_set_bbreg(hw, 0x40, BIT(4), 0);
-	rtl_set_bbreg(hw, 0x40, BIT(3), 1);
-
-	rtl_set_bbreg(hw, 0x944, BIT(0)|BIT(1), 0x3);
-	rtl_set_bbreg(hw, 0x930, 0xff, 0x77);
-
-	rtl_set_bbreg(hw, 0x38, BIT(11), 0x1);
-
-	rtl_set_bbreg(hw, 0xb2c, 0xffffffff, 0x80000000);
-
 	if (ppsc->rfpwr_state == ERFON) {
+		rtl8723be_phy_set_rfpath_switch(hw, 1);
+		/* when use 1ant NIC, iqk will disturb BT music
+		 * root cause is not clear now, is something
+		 * related with 'mdelay' and Reg[0x948]
+		 */
+		if (rtlpriv->btcoexist.btc_info.ant_num == ANT_X2 ||
+		    !rtlpriv->cfg->ops->get_btc_status()) {
+			rtl8723be_phy_iq_calibrate(hw, false);
+			rtlphy->iqk_initialized = true;
+		}
 		rtl8723be_dm_check_txpower_tracking(hw);
 		rtl8723be_phy_lc_calibrate(hw);
 	}
-	tmp_u1b = efuse_read_1byte(hw, 0x1FA);
-	if (!(tmp_u1b & BIT(0))) {
-		rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05);
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "PA BIAS path A\n");
+	rtl_write_byte(rtlpriv, REG_NAV_UPPER, ((30000 + 127) / 128));
+
+	/* Release Rx DMA. */
+	tmp_u1b = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+	if (tmp_u1b & BIT(2)) {
+		/* Release Rx DMA if needed */
+		tmp_u1b &= (~BIT(2));
+		rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, tmp_u1b);
 	}
-	if (!(tmp_u1b & BIT(4))) {
-		tmp_u1b = rtl_read_byte(rtlpriv, 0x16);
-		tmp_u1b &= 0x0F;
-		rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x80);
-		udelay(10);
-		rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x90);
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n");
-	}
+	/* Release Tx/Rx PCIE DMA. */
+	rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0);
+
 	rtl8723be_dm_init(hw);
 exit:
 	local_irq_restore(flags);
@@ -1103,43 +1470,29 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	enum version_8723e version = VERSION_UNKNOWN;
-	u8 count = 0;
-	u8 value8;
 	u32 value32;
 
-	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0);
-
-	value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 2);
-	rtl_write_byte(rtlpriv, REG_APS_FSMCO + 2, value8 | BIT(0));
-
-	value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1);
-	rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, value8 | BIT(0));
-
-	value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1);
-	while (((value8 & BIT(0))) && (count++ < 100)) {
-		udelay(10);
-		value8 = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1);
-	}
-	count = 0;
-	value8 = rtl_read_byte(rtlpriv, REG_ROM_VERSION);
-	while ((value8 == 0) && (count++ < 50)) {
-		value8 = rtl_read_byte(rtlpriv, REG_ROM_VERSION);
-		mdelay(1);
-	}
 	value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG1);
 	if ((value32 & (CHIP_8723B)) != CHIP_8723B)
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "unkown chip version\n");
 	else
-		version = (enum version_8723e) VERSION_TEST_CHIP_1T1R_8723B;
+		version = (enum version_8723e)CHIP_8723B;
 
-		rtlphy->rf_type = RF_1T1R;
+	rtlphy->rf_type = RF_1T1R;
 
-	value8 = rtl_read_byte(rtlpriv, REG_ROM_VERSION);
-	if (value8 >= 0x02)
-		version |= BIT(3);
+	/* treat rtl8723be chip as  MP version in default */
+	version = (enum version_8723e)(version | NORMAL_CHIP);
+
+	value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG);
+	/* cut version */
+	version |= (enum version_8723e)(value32 & CHIP_VER_RTL_MASK);
+	/* Manufacture */
+	if (((value32 & EXT_VENDOR_ID) >> 18) == 0x01)
+		version = (enum version_8723e)(version | CHIP_VENDOR_SMIC);
+
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 		 "Chip RF Type: %s\n", (rtlphy->rf_type == RF_2T2R) ?
-		 "RF_2T2R" : "RF_1T1R");
+		  "RF_2T2R" : "RF_1T1R");
 
 	return version;
 }
@@ -1150,43 +1503,29 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 bt_msr = rtl_read_byte(rtlpriv, MSR) & 0xfc;
 	enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
+	u8 mode = MSR_NOLINK;
 
-	rtl_write_dword(rtlpriv, REG_BCN_CTRL, 0);
-	RT_TRACE(rtlpriv, COMP_BEACON, DBG_LOUD,
-		 "clear 0x550 when set HW_VAR_MEDIA_STATUS\n");
-
-	if (type == NL80211_IFTYPE_UNSPECIFIED ||
-	    type == NL80211_IFTYPE_STATION) {
-		_rtl8723be_stop_tx_beacon(hw);
-		_rtl8723be_enable_bcn_sub_func(hw);
-	} else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP) {
-		_rtl8723be_resume_tx_beacon(hw);
-		_rtl8723be_disable_bcn_sub_func(hw);
-	} else {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-			 "Set HW_VAR_MEDIA_STATUS: "
-			 "No such media status(%x).\n", type);
-	}
 	switch (type) {
 	case NL80211_IFTYPE_UNSPECIFIED:
-		bt_msr |= MSR_NOLINK;
-		ledaction = LED_CTL_LINK;
+		mode = MSR_NOLINK;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "Set Network type to NO LINK!\n");
 		break;
 	case NL80211_IFTYPE_ADHOC:
-		bt_msr |= MSR_ADHOC;
+	case NL80211_IFTYPE_MESH_POINT:
+		mode = MSR_ADHOC;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "Set Network type to Ad Hoc!\n");
 		break;
 	case NL80211_IFTYPE_STATION:
-		bt_msr |= MSR_INFRA;
+		mode = MSR_INFRA;
 		ledaction = LED_CTL_LINK;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "Set Network type to STA!\n");
 		break;
 	case NL80211_IFTYPE_AP:
-		bt_msr |= MSR_AP;
+		mode = MSR_AP;
+		ledaction = LED_CTL_LINK;
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
 			 "Set Network type to AP!\n");
 		break;
@@ -1195,9 +1534,33 @@
 			 "Network type %d not support!\n", type);
 		return 1;
 	}
-	rtl_write_byte(rtlpriv, (MSR), bt_msr);
+
+	/* MSR_INFRA == Link in infrastructure network;
+	 * MSR_ADHOC == Link in ad hoc network;
+	 * Therefore, check link state is necessary.
+	 *
+	 * MSR_AP == AP mode; link state is not cared here.
+	 */
+	if (mode != MSR_AP && rtlpriv->mac80211.link_state < MAC80211_LINKED) {
+		mode = MSR_NOLINK;
+		ledaction = LED_CTL_NO_LINK;
+	}
+
+	if (mode == MSR_NOLINK || mode == MSR_INFRA) {
+		_rtl8723be_stop_tx_beacon(hw);
+		_rtl8723be_enable_bcn_sub_func(hw);
+	} else if (mode == MSR_ADHOC || mode == MSR_AP) {
+		_rtl8723be_resume_tx_beacon(hw);
+		_rtl8723be_disable_bcn_sub_func(hw);
+	} else {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n",
+			 mode);
+	}
+
+	rtl_write_byte(rtlpriv, (MSR), bt_msr | mode);
 	rtlpriv->cfg->ops->led_control(hw, ledaction);
-	if ((bt_msr & MSR_MASK) == MSR_AP)
+	if (mode == MSR_AP)
 		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
 	else
 		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
@@ -1224,6 +1587,7 @@
 		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
 					      (u8 *)(&reg_rcr));
 	}
+
 }
 
 int rtl8723be_set_network_type(struct ieee80211_hw *hw,
@@ -1240,6 +1604,7 @@
 	} else {
 		rtl8723be_set_check_bssid(hw, false);
 	}
+
 	return 0;
 }
 
@@ -1249,6 +1614,7 @@
 void rtl8723be_set_qos(struct ieee80211_hw *hw, int aci)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
 	rtl8723_dm_init_edca_turbo(hw);
 	switch (aci) {
 	case AC1_BK:
@@ -1268,20 +1634,32 @@
 	}
 }
 
+static void rtl8723be_clear_interrupt(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 tmp;
+
+	tmp = rtl_read_dword(rtlpriv, REG_HISR);
+	rtl_write_dword(rtlpriv, REG_HISR, tmp);
+
+	tmp = rtl_read_dword(rtlpriv, REG_HISRE);
+	rtl_write_dword(rtlpriv, REG_HISRE, tmp);
+
+	tmp = rtl_read_dword(rtlpriv, REG_HSISR);
+	rtl_write_dword(rtlpriv, REG_HSISR, tmp);
+}
+
 void rtl8723be_enable_interrupt(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 
+	rtl8723be_clear_interrupt(hw);/*clear it here first*/
+
 	rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
 	rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
 	rtlpci->irq_enabled = true;
-	/* there are some C2H CMDs have been sent
-	 * before system interrupt is enabled, e.g., C2H, CPWM.
-	 * So we need to clear all C2H events that FW has notified,
-	 * otherwise FW won't schedule any commands anymore.
-	 */
-	rtl_write_byte(rtlpriv, REG_C2HEVT_CLEAR, 0);
+
 	/*enable system interrupt*/
 	rtl_write_dword(rtlpriv, REG_HSIMR, rtlpci->sys_irq_mask & 0xFFFFFFFF);
 }
@@ -1294,48 +1672,7 @@
 	rtl_write_dword(rtlpriv, REG_HIMR, IMR_DISABLED);
 	rtl_write_dword(rtlpriv, REG_HIMRE, IMR_DISABLED);
 	rtlpci->irq_enabled = false;
-	synchronize_irq(rtlpci->pdev->irq);
-}
-
-static void _rtl8723be_poweroff_adapter(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	u8 u1b_tmp;
-
-	/* Combo (PCIe + USB) Card and PCIe-MF Card */
-	/* 1. Run LPS WL RFOFF flow */
-	rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
-				 PWR_INTF_PCI_MSK, RTL8723_NIC_LPS_ENTER_FLOW);
-
-	/* 2. 0x1F[7:0] = 0 */
-	/* turn off RF */
-	rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00);
-	if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) &&
-	    rtlhal->fw_ready)
-		rtl8723be_firmware_selfreset(hw);
-
-	/* Reset MCU. Suggested by Filen. */
-	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
-	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
-
-	/* g.	MCUFWDL 0x80[1:0]= 0	 */
-	/* reset MCU ready status */
-	rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
-
-	/* HW card disable configuration. */
-	rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
-				 PWR_INTF_PCI_MSK, RTL8723_NIC_DISABLE_FLOW);
-
-	/* Reset MCU IO Wrapper */
-	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
-	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
-	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
-	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, u1b_tmp | BIT(0));
-
-	/* 7. RSV_CTRL 0x1C[7:0] = 0x0E */
-	/* lock ISO/CLK/Power control register */
-	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e);
+	/*synchronize_irq(rtlpci->pdev->irq);*/
 }
 
 void rtl8723be_card_disable(struct ieee80211_hw *hw)
@@ -1442,10 +1779,9 @@
 	u32 path, addr = EEPROM_TX_PWR_INX, group, cnt = 0;
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-		 "hal_ReadPowerValueFromPROM8723BE(): "
-		 "PROMContent[0x%x]= 0x%x\n",
+		 "hal_ReadPowerValueFromPROM8723BE(): PROMContent[0x%x]=0x%x\n",
 		 (addr + 1), hwinfo[addr + 1]);
-	if (0xFF == hwinfo[addr + 1])  /*YJ, add, 120316*/
+	if (0xFF == hwinfo[addr + 1])  /*YJ,add,120316*/
 		autoload_fail = true;
 
 	if (autoload_fail) {
@@ -1453,7 +1789,7 @@
 			 "auto load fail : Use Default value!\n");
 		for (path = 0; path < MAX_RF_PATH; path++) {
 			/* 2.4G default value */
-			for (group = 0; group < MAX_CHNL_GROUP_24G; group++) {
+			for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) {
 				pw2g->index_cck_base[path][group] = 0x2D;
 				pw2g->index_bw40_base[path][group] = 0x2D;
 			}
@@ -1471,12 +1807,14 @@
 		}
 		return;
 	}
+
 	for (path = 0; path < MAX_RF_PATH; path++) {
 		/*2.4G default value*/
 		for (group = 0; group < MAX_CHNL_GROUP_24G; group++) {
 			pw2g->index_cck_base[path][group] = hwinfo[addr++];
 			if (pw2g->index_cck_base[path][group] == 0xFF)
 				pw2g->index_cck_base[path][group] = 0x2D;
+
 		}
 		for (group = 0; group < MAX_CHNL_GROUP_24G - 1; group++) {
 			pw2g->index_bw40_base[path][group] = hwinfo[addr++];
@@ -1493,8 +1831,10 @@
 						(hwinfo[addr] & 0xf0) >> 4;
 					/*bit sign number to 8 bit sign number*/
 					if (pw2g->bw20_diff[path][cnt] & BIT(3))
-						pw2g->bw20_diff[path][cnt] |= 0xF0;
+						pw2g->bw20_diff[path][cnt] |=
+									  0xF0;
 				}
+
 				if (hwinfo[addr] == 0xFF) {
 					pw2g->ofdm_diff[path][cnt] = 0x04;
 				} else {
@@ -1517,6 +1857,7 @@
 						pw2g->bw40_diff[path][cnt] |=
 									  0xF0;
 				}
+
 				if (hwinfo[addr] == 0xFF) {
 					pw2g->bw20_diff[path][cnt] = 0xFE;
 				} else {
@@ -1537,9 +1878,10 @@
 						pw2g->ofdm_diff[path][cnt] |=
 									  0xF0;
 				}
-				if (hwinfo[addr] == 0xFF) {
+
+				if (hwinfo[addr] == 0xFF)
 					pw2g->cck_diff[path][cnt] = 0xFE;
-				} else {
+				else {
 					pw2g->cck_diff[path][cnt] =
 							(hwinfo[addr] & 0x0f);
 					if (pw2g->cck_diff[path][cnt] & BIT(3))
@@ -1549,12 +1891,14 @@
 				addr++;
 			}
 		}
+
 		/*5G default value*/
 		for (group = 0; group < MAX_CHNL_GROUP_5G; group++) {
 			pw5g->index_bw40_base[path][group] = hwinfo[addr++];
 			if (pw5g->index_bw40_base[path][group] == 0xFF)
 				pw5g->index_bw40_base[path][group] = 0xFE;
 		}
+
 		for (cnt = 0; cnt < MAX_TX_COUNT; cnt++) {
 			if (cnt == 0) {
 				pw5g->bw40_diff[path][cnt] = 0;
@@ -1568,9 +1912,10 @@
 						pw5g->bw20_diff[path][cnt] |=
 									  0xF0;
 				}
-				if (hwinfo[addr] == 0xFF) {
+
+				if (hwinfo[addr] == 0xFF)
 					pw5g->ofdm_diff[path][cnt] = 0x04;
-				} else {
+				else {
 					pw5g->ofdm_diff[path][0] =
 							(hwinfo[addr] & 0x0f);
 					if (pw5g->ofdm_diff[path][cnt] & BIT(3))
@@ -1587,6 +1932,7 @@
 					if (pw5g->bw40_diff[path][cnt] & BIT(3))
 						pw5g->bw40_diff[path][cnt] |= 0xF0;
 				}
+
 				if (hwinfo[addr] == 0xFF) {
 					pw5g->bw20_diff[path][cnt] = 0xFE;
 				} else {
@@ -1598,6 +1944,7 @@
 				addr++;
 			}
 		}
+
 		if (hwinfo[addr] == 0xFF) {
 			pw5g->ofdm_diff[path][1] = 0xFE;
 			pw5g->ofdm_diff[path][2] = 0xFE;
@@ -1653,14 +2000,16 @@
 			rtlefuse->txpwr_legacyhtdiff[rf_path][i] =
 						pw2g.ofdm_diff[rf_path][i];
 		}
+
 		for (i = 0; i < 14; i++) {
-			RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
-				"RF(%d)-Ch(%d) [CCK / HT40_1S ] = "
-				"[0x%x / 0x%x ]\n", rf_path, i,
+			RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
+				"RF(%d)-Ch(%d) [CCK / HT40_1S ] = [0x%x / 0x%x ]\n",
+				rf_path, i,
 				rtlefuse->txpwrlevel_cck[rf_path][i],
 				rtlefuse->txpwrlevel_ht40_1s[rf_path][i]);
 		}
 	}
+
 	if (!autoload_fail)
 		rtlefuse->eeprom_thermalmeter =
 					hwinfo[EEPROM_THERMAL_METER_88E];
@@ -1671,8 +2020,9 @@
 		rtlefuse->apk_thermalmeterignore = true;
 		rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER;
 	}
+
 	rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
-	RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+	RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
 		"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
 
 	if (!autoload_fail) {
@@ -1683,7 +2033,7 @@
 	} else {
 		rtlefuse->eeprom_regulatory = 0;
 	}
-	RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+	RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
 		"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
 }
 
@@ -1743,6 +2093,7 @@
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
 		rtlefuse->autoload_failflag = false;
 	}
+
 	if (rtlefuse->autoload_failflag)
 		return;
 
@@ -1958,100 +2309,10 @@
 	_rtl8723be_hal_customized_behavior(hw);
 }
 
-static void rtl8723be_update_hal_rate_table(struct ieee80211_hw *hw,
-					    struct ieee80211_sta *sta)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	u32 ratr_value;
-	u8 ratr_index = 0;
-	u8 nmode = mac->ht_enable;
-	u8 mimo_ps = IEEE80211_SMPS_OFF;
-	u16 shortgi_rate;
-	u32 tmp_ratr_value;
-	u8 curtxbw_40mhz = mac->bw_40;
-	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
-			       1 : 0;
-	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
-			       1 : 0;
-	enum wireless_mode wirelessmode = mac->mode;
-
-	if (rtlhal->current_bandtype == BAND_ON_5G)
-		ratr_value = sta->supp_rates[1] << 4;
-	else
-		ratr_value = sta->supp_rates[0];
-	if (mac->opmode == NL80211_IFTYPE_ADHOC)
-		ratr_value = 0xfff;
-	ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
-		       sta->ht_cap.mcs.rx_mask[0] << 12);
-	switch (wirelessmode) {
-	case WIRELESS_MODE_B:
-		if (ratr_value & 0x0000000c)
-			ratr_value &= 0x0000000d;
-		else
-			ratr_value &= 0x0000000f;
-		break;
-	case WIRELESS_MODE_G:
-		ratr_value &= 0x00000FF5;
-		break;
-	case WIRELESS_MODE_N_24G:
-	case WIRELESS_MODE_N_5G:
-		nmode = 1;
-		if (mimo_ps == IEEE80211_SMPS_STATIC) {
-			ratr_value &= 0x0007F005;
-		} else {
-			u32 ratr_mask;
-
-			if (get_rf_type(rtlphy) == RF_1T2R ||
-			    get_rf_type(rtlphy) == RF_1T1R)
-				ratr_mask = 0x000ff005;
-			else
-				ratr_mask = 0x0f0ff005;
-			ratr_value &= ratr_mask;
-		}
-		break;
-	default:
-		if (rtlphy->rf_type == RF_1T2R)
-			ratr_value &= 0x000ff0ff;
-		else
-			ratr_value &= 0x0f0ff0ff;
-		break;
-	}
-	if ((rtlpriv->btcoexist.bt_coexistence) &&
-	    (rtlpriv->btcoexist.bt_coexist_type == BT_CSR_BC4) &&
-	    (rtlpriv->btcoexist.bt_cur_state) &&
-	    (rtlpriv->btcoexist.bt_ant_isolation) &&
-	    ((rtlpriv->btcoexist.bt_service == BT_SCO) ||
-	     (rtlpriv->btcoexist.bt_service == BT_BUSY)))
-		ratr_value &= 0x0fffcfc0;
-	else
-		ratr_value &= 0x0FFFFFFF;
-
-	if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) ||
-		      (!curtxbw_40mhz && curshortgi_20mhz))) {
-		ratr_value |= 0x10000000;
-		tmp_ratr_value = (ratr_value >> 12);
-
-		for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
-			if ((1 << shortgi_rate) & tmp_ratr_value)
-				break;
-		}
-		shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
-			       (shortgi_rate << 4) | (shortgi_rate);
-	}
-	rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
-
-	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
-		 "%x\n", rtl_read_dword(rtlpriv, REG_ARFR0));
-}
-
 static u8 _rtl8723be_mrate_idx_to_arfr_id(struct ieee80211_hw *hw,
 					  u8 rate_index)
 {
 	u8 ret = 0;
-
 	switch (rate_index) {
 	case RATR_INX_WIRELESS_NGB:
 		ret = 1;
@@ -2090,16 +2351,15 @@
 	u32 ratr_bitmap;
 	u8 ratr_index;
 	u8 curtxbw_40mhz = (sta->ht_cap.cap &
-			    IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0;
+			      IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0;
 	u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
-			       1 : 0;
+				1 : 0;
 	u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
-			       1 : 0;
+				1 : 0;
 	enum wireless_mode wirelessmode = 0;
 	bool shortgi = false;
 	u8 rate_mask[7];
 	u8 macid = 0;
-	u8 mimo_ps = IEEE80211_SMPS_OFF;
 
 	sta_entry = (struct rtl_sta_info *)sta->drv_priv;
 	wirelessmode = sta_entry->wireless_mode;
@@ -2135,55 +2395,40 @@
 		else
 			ratr_bitmap &= 0x00000ff5;
 		break;
-	case WIRELESS_MODE_A:
-		ratr_index = RATR_INX_WIRELESS_A;
-		ratr_bitmap &= 0x00000ff0;
-		break;
 	case WIRELESS_MODE_N_24G:
 	case WIRELESS_MODE_N_5G:
 		ratr_index = RATR_INX_WIRELESS_NGB;
-
-		if (mimo_ps == IEEE80211_SMPS_STATIC  ||
-		    mimo_ps == IEEE80211_SMPS_DYNAMIC) {
-			if (rssi_level == 1)
-				ratr_bitmap &= 0x00070000;
-			else if (rssi_level == 2)
-				ratr_bitmap &= 0x0007f000;
-			else
-				ratr_bitmap &= 0x0007f005;
-		} else {
-			if (rtlphy->rf_type == RF_1T1R) {
-				if (curtxbw_40mhz) {
-					if (rssi_level == 1)
-						ratr_bitmap &= 0x000f0000;
-					else if (rssi_level == 2)
-						ratr_bitmap &= 0x000ff000;
-					else
-						ratr_bitmap &= 0x000ff015;
-				} else {
-					if (rssi_level == 1)
-						ratr_bitmap &= 0x000f0000;
-					else if (rssi_level == 2)
-						ratr_bitmap &= 0x000ff000;
-					else
-						ratr_bitmap &= 0x000ff005;
-				}
+		if (rtlphy->rf_type == RF_1T1R) {
+			if (curtxbw_40mhz) {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x000f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x000ff000;
+				else
+					ratr_bitmap &= 0x000ff015;
 			} else {
-				if (curtxbw_40mhz) {
-					if (rssi_level == 1)
-						ratr_bitmap &= 0x0f8f0000;
-					else if (rssi_level == 2)
-						ratr_bitmap &= 0x0f8ff000;
-					else
-						ratr_bitmap &= 0x0f8ff015;
-				} else {
-					if (rssi_level == 1)
-						ratr_bitmap &= 0x0f8f0000;
-					else if (rssi_level == 2)
-						ratr_bitmap &= 0x0f8ff000;
-					else
-						ratr_bitmap &= 0x0f8ff005;
-				}
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x000f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x000ff000;
+				else
+					ratr_bitmap &= 0x000ff005;
+			}
+		} else {
+			if (curtxbw_40mhz) {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x0f8f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x0f8ff000;
+				else
+					ratr_bitmap &= 0x0f8ff015;
+			} else {
+				if (rssi_level == 1)
+					ratr_bitmap &= 0x0f8f0000;
+				else if (rssi_level == 2)
+					ratr_bitmap &= 0x0f8ff000;
+				else
+					ratr_bitmap &= 0x0f8ff005;
 			}
 		}
 		if ((curtxbw_40mhz && curshortgi_40mhz) ||
@@ -2203,18 +2448,17 @@
 			ratr_bitmap &= 0x0f0ff0ff;
 		break;
 	}
+
 	sta_entry->ratr_index = ratr_index;
 
 	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
 		 "ratr_bitmap :%x\n", ratr_bitmap);
-	*(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) | (ratr_index << 28);
+	*(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
+				       (ratr_index << 28);
 	rate_mask[0] = macid;
 	rate_mask[1] = _rtl8723be_mrate_idx_to_arfr_id(hw, ratr_index) |
-						       (shortgi ? 0x80 : 0x00);
+						      (shortgi ? 0x80 : 0x00);
 	rate_mask[2] = curtxbw_40mhz;
-	/* if (prox_priv->proxim_modeinfo->power_output > 0)
-	 *	rate_mask[2] |= BIT(6);
-	 */
 
 	rate_mask[3] = (u8)(ratr_bitmap & 0x000000ff);
 	rate_mask[4] = (u8)((ratr_bitmap & 0x0000ff00) >> 8);
@@ -2228,7 +2472,7 @@
 		 rate_mask[2], rate_mask[3],
 		 rate_mask[4], rate_mask[5],
 		 rate_mask[6]);
-	rtl8723be_fill_h2c_cmd(hw, H2C_8723BE_RA_MASK, 7, rate_mask);
+	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_RA_MASK, 7, rate_mask);
 	_rtl8723be_set_bcn_ctrl_reg(hw, BIT(3), 0);
 }
 
@@ -2239,8 +2483,6 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	if (rtlpriv->dm.useramask)
 		rtl8723be_update_hal_rate_mask(hw, sta, rssi_level);
-	else
-		rtl8723be_update_hal_rate_table(hw, sta);
 }
 
 void rtl8723be_update_channel_access_setting(struct ieee80211_hw *hw)
@@ -2264,7 +2506,7 @@
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;
 	u8 u1tmp;
-	bool actuallyset = false;
+	bool b_actuallyset = false;
 
 	if (rtlpriv->rtlhal.being_init_adapter)
 		return false;
@@ -2280,6 +2522,7 @@
 		ppsc->rfchange_inprogress = true;
 		spin_unlock(&rtlpriv->locks.rf_ps_lock);
 	}
+
 	cur_rfstate = ppsc->rfpwr_state;
 
 	rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2,
@@ -2292,24 +2535,23 @@
 	else
 		e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFON : ERFOFF;
 
-	if (ppsc->hwradiooff &&
-	    (e_rfpowerstate_toset == ERFON)) {
+	if ((ppsc->hwradiooff) && (e_rfpowerstate_toset == ERFON)) {
 		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 			 "GPIOChangeRF  - HW Radio ON, RF ON\n");
 
 		e_rfpowerstate_toset = ERFON;
 		ppsc->hwradiooff = false;
-		actuallyset = true;
-	} else if (!ppsc->hwradiooff &&
-		   (e_rfpowerstate_toset == ERFOFF)) {
+		b_actuallyset = true;
+	} else if (!ppsc->hwradiooff && (e_rfpowerstate_toset == ERFOFF)) {
 		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 			 "GPIOChangeRF  - HW Radio OFF, RF OFF\n");
 
 		e_rfpowerstate_toset = ERFOFF;
 		ppsc->hwradiooff = true;
-		actuallyset = true;
+		b_actuallyset = true;
 	}
-	if (actuallyset) {
+
+	if (b_actuallyset) {
 		spin_lock(&rtlpriv->locks.rf_ps_lock);
 		ppsc->rfchange_inprogress = false;
 		spin_unlock(&rtlpriv->locks.rf_ps_lock);
@@ -2321,8 +2563,10 @@
 		ppsc->rfchange_inprogress = false;
 		spin_unlock(&rtlpriv->locks.rf_ps_lock);
 	}
+
 	*valid = 1;
 	return !ppsc->hwradiooff;
+
 }
 
 void rtl8723be_set_key(struct ieee80211_hw *hw, u32 key_index,
@@ -2363,6 +2607,7 @@
 				rtlpriv->sec.key_len[idx] = 0;
 			}
 		}
+
 	} else {
 		switch (enc_algo) {
 		case WEP40_ENCRYPTION:
@@ -2378,7 +2623,7 @@
 			enc_algo = CAM_AES;
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 				 "switch case not process\n");
 			enc_algo = CAM_TKIP;
 			break;
@@ -2398,22 +2643,22 @@
 					if (entry_id >=  TOTAL_CAM_ENTRY) {
 						RT_TRACE(rtlpriv, COMP_SEC,
 							 DBG_EMERG,
-							 "Can not find free"
-							 " hw security cam "
-							 "entry\n");
+							 "Can not find free hw security cam entry\n");
 						return;
 					}
 				} else {
 					entry_id = CAM_PAIRWISE_KEY_POSITION;
 				}
+
 				key_index = PAIRWISE_KEYIDX;
 				is_pairwise = true;
 			}
 		}
+
 		if (rtlpriv->sec.key_len[key_index] == 0) {
 			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 				 "delete one entry, entry_id is %d\n",
-				 entry_id);
+				  entry_id);
 			if (mac->opmode == NL80211_IFTYPE_AP)
 				rtl_cam_del_entry(hw, p_macaddr);
 			rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
@@ -2422,12 +2667,12 @@
 				 "add one entry\n");
 			if (is_pairwise) {
 				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
-					 "set Pairwise key\n");
+					 "set Pairwiase key\n");
 
 				rtl_cam_add_one_entry(hw, macaddr, key_index,
-						      entry_id, enc_algo,
-						      CAM_CONFIG_NO_USEDK,
-						      rtlpriv->sec.key_buf[key_index]);
+					       entry_id, enc_algo,
+					       CAM_CONFIG_NO_USEDK,
+					       rtlpriv->sec.key_buf[key_index]);
 			} else {
 				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
 					 "set group key\n");
@@ -2442,10 +2687,11 @@
 						rtlpriv->sec.key_buf
 						[entry_id]);
 				}
+
 				rtl_cam_add_one_entry(hw, macaddr, key_index,
-						      entry_id, enc_algo,
-						      CAM_CONFIG_NO_USEDK,
-						      rtlpriv->sec.key_buf[entry_id]);
+						entry_id, enc_algo,
+						CAM_CONFIG_NO_USEDK,
+						rtlpriv->sec.key_buf[entry_id]);
 			}
 		}
 	}
@@ -2464,7 +2710,7 @@
 			rtlpriv->btcoexist.btc_info.btcoexist = 1;
 		else
 			rtlpriv->btcoexist.btc_info.btcoexist = 0;
-		value = hwinfo[RF_OPTION4];
+		value = hwinfo[EEPROM_RF_BT_SETTING_8723B];
 		rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8723B;
 		rtlpriv->btcoexist.btc_info.ant_num = (value & 0x1);
 	} else {
@@ -2472,6 +2718,7 @@
 		rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8723B;
 		rtlpriv->btcoexist.btc_info.ant_num = ANT_X2;
 	}
+
 }
 
 void rtl8723be_bt_reg_init(struct ieee80211_hw *hw)
@@ -2492,6 +2739,7 @@
 
 	if (rtlpriv->cfg->ops->get_btc_status())
 		rtlpriv->btcoexist.btc_ops->btc_init_hw_config(rtlpriv);
+
 }
 
 void rtl8723be_suspend(struct ieee80211_hw *hw)
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.h b/drivers/net/wireless/rtlwifi/rtl8723be/hw.h
index 64c7551..eae863d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/hw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.h
@@ -59,4 +59,5 @@
 void rtl8723be_bt_hw_init(struct ieee80211_hw *hw);
 void rtl8723be_suspend(struct ieee80211_hw *hw);
 void rtl8723be_resume(struct ieee80211_hw *hw);
+
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/led.c b/drivers/net/wireless/rtlwifi/rtl8723be/led.c
index cb931a3..4196efb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/led.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/led.c
@@ -42,7 +42,7 @@
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
-		 "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin);
+		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
 
 	switch (pled->ledpin) {
 	case LED_PIN_GPIO0:
@@ -71,7 +71,7 @@
 	u8 ledcfg;
 
 	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
-		 "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin);
+		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
 
 	ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
 
@@ -100,7 +100,7 @@
 		break;
 	default:
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not processed\n");
+			 "switch case not process\n");
 		break;
 	}
 	pled->ledon = false;
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c
index 1575ef9..20dcc25 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c
@@ -26,224 +26,28 @@
 #include "../wifi.h"
 #include "../pci.h"
 #include "../ps.h"
-#include "../core.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
 #include "../rtl8723com/phy_common.h"
 #include "rf.h"
 #include "dm.h"
+#include "../rtl8723com/dm_common.h"
 #include "table.h"
 #include "trx.h"
 
 static bool _rtl8723be_phy_bb8723b_config_parafile(struct ieee80211_hw *hw);
+static bool _rtl8723be_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
+static bool _rtl8723be_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+						     u8 configtype);
 static bool _rtl8723be_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
 						       u8 configtype);
-static bool rtl8723be_phy_sw_chn_step_by_step(struct ieee80211_hw *hw,
-					      u8 channel, u8 *stage,
-					      u8 *step, u32 *delay);
-static bool _rtl8723be_check_condition(struct ieee80211_hw *hw,
-				       const u32  condition)
-{
-	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
-	u32 _board = rtlefuse->board_type; /*need efuse define*/
-	u32 _interface = rtlhal->interface;
-	u32 _platform = 0x08;/*SupportPlatform */
-	u32 cond = condition;
+static bool _rtl8723be_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+						u8 channel, u8 *stage,
+						u8 *step, u32 *delay);
 
-	if (condition == 0xCDCDCDCD)
-		return true;
-
-	cond = condition & 0xFF;
-	if ((_board & cond) == 0 && cond != 0x1F)
-		return false;
-
-	cond = condition & 0xFF00;
-	cond = cond >> 8;
-	if ((_interface & cond) == 0 && cond != 0x07)
-		return false;
-
-	cond = condition & 0xFF0000;
-	cond = cond >> 16;
-	if ((_platform & cond) == 0 && cond != 0x0F)
-		return false;
-	return true;
-}
-
-static bool _rtl8723be_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 i;
-	u32 arraylength;
-	u32 *ptrarray;
-
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read rtl8723beMACPHY_Array\n");
-	arraylength = RTL8723BEMAC_1T_ARRAYLEN;
-	ptrarray = RTL8723BEMAC_1T_ARRAY;
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-		 "Img:RTL8723bEMAC_1T_ARRAY LEN %d\n", arraylength);
-	for (i = 0; i < arraylength; i = i + 2)
-		rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]);
-	return true;
-}
-
-static bool _rtl8723be_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
-						     u8 configtype)
-{
-	#define READ_NEXT_PAIR(v1, v2, i) \
-		do { \
-			i += 2; \
-			v1 = array_table[i];\
-			v2 = array_table[i+1]; \
-		} while (0)
-
-	int i;
-	u32 *array_table;
-	u16 arraylen;
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	u32 v1 = 0, v2 = 0;
-
-	if (configtype == BASEBAND_CONFIG_PHY_REG) {
-		arraylen = RTL8723BEPHY_REG_1TARRAYLEN;
-		array_table = RTL8723BEPHY_REG_1TARRAY;
-
-		for (i = 0; i < arraylen; i = i + 2) {
-			v1 = array_table[i];
-			v2 = array_table[i+1];
-			if (v1 < 0xcdcdcdcd) {
-				rtl_bb_delay(hw, v1, v2);
-			} else {/*This line is the start line of branch.*/
-				if (!_rtl8723be_check_condition(hw, array_table[i])) {
-					/*Discard the following (offset, data) pairs*/
-					READ_NEXT_PAIR(v1, v2, i);
-					while (v2 != 0xDEAD &&
-					       v2 != 0xCDEF &&
-					       v2 != 0xCDCD &&
-					       i < arraylen - 2) {
-						READ_NEXT_PAIR(v1, v2, i);
-					}
-					i -= 2; /* prevent from for-loop += 2*/
-				/* Configure matched pairs and
-				 * skip to end of if-else.
-				 */
-				} else {
-					READ_NEXT_PAIR(v1, v2, i);
-					while (v2 != 0xDEAD &&
-					       v2 != 0xCDEF &&
-					       v2 != 0xCDCD &&
-					       i < arraylen - 2) {
-						rtl_bb_delay(hw,
-								    v1, v2);
-						READ_NEXT_PAIR(v1, v2, i);
-					}
-
-					while (v2 != 0xDEAD && i < arraylen - 2)
-						READ_NEXT_PAIR(v1, v2, i);
-				}
-			}
-		}
-	} else if (configtype == BASEBAND_CONFIG_AGC_TAB) {
-		arraylen = RTL8723BEAGCTAB_1TARRAYLEN;
-		array_table = RTL8723BEAGCTAB_1TARRAY;
-
-		for (i = 0; i < arraylen; i = i + 2) {
-			v1 = array_table[i];
-			v2 = array_table[i+1];
-			if (v1 < 0xCDCDCDCD) {
-				rtl_set_bbreg(hw, array_table[i],
-					      MASKDWORD,
-					      array_table[i + 1]);
-				udelay(1);
-				continue;
-			} else {/*This line is the start line of branch.*/
-				if (!_rtl8723be_check_condition(hw, array_table[i])) {
-					/* Discard the following
-					 * (offset, data) pairs
-					 */
-					READ_NEXT_PAIR(v1, v2, i);
-					while (v2 != 0xDEAD &&
-					       v2 != 0xCDEF &&
-					       v2 != 0xCDCD &&
-					       i < arraylen - 2) {
-						READ_NEXT_PAIR(v1, v2, i);
-					}
-					i -= 2; /* prevent from for-loop += 2*/
-				/*Configure matched pairs and
-				 *skip to end of if-else.
-				 */
-				} else {
-					READ_NEXT_PAIR(v1, v2, i);
-					while (v2 != 0xDEAD &&
-					       v2 != 0xCDEF &&
-					       v2 != 0xCDCD &&
-					       i < arraylen - 2) {
-						rtl_set_bbreg(hw, array_table[i],
-							      MASKDWORD,
-							      array_table[i + 1]);
-						udelay(1);
-						READ_NEXT_PAIR(v1, v2, i);
-					}
-
-					while (v2 != 0xDEAD && i < arraylen - 2)
-						READ_NEXT_PAIR(v1, v2, i);
-				}
-			}
-			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-				 "The agctab_array_table[0] is "
-				  "%x Rtl818EEPHY_REGArray[1] is %x\n",
-				  array_table[i], array_table[i + 1]);
-		}
-	}
-	return true;
-}
-
-static u8 _rtl8723be_get_rate_section_index(u32 regaddr)
-{
-	u8 index = 0;
-
-	switch (regaddr) {
-	case RTXAGC_A_RATE18_06:
-	case RTXAGC_B_RATE18_06:
-		index = 0;
-		break;
-	case RTXAGC_A_RATE54_24:
-	case RTXAGC_B_RATE54_24:
-		index = 1;
-		break;
-	case RTXAGC_A_CCK1_MCS32:
-	case RTXAGC_B_CCK1_55_MCS32:
-		index = 2;
-		break;
-	case RTXAGC_B_CCK11_A_CCK2_11:
-		index = 3;
-		break;
-	case RTXAGC_A_MCS03_MCS00:
-	case RTXAGC_B_MCS03_MCS00:
-		index = 4;
-		break;
-	case RTXAGC_A_MCS07_MCS04:
-	case RTXAGC_B_MCS07_MCS04:
-		index = 5;
-		break;
-	case RTXAGC_A_MCS11_MCS08:
-	case RTXAGC_B_MCS11_MCS08:
-		index = 6;
-		break;
-	case RTXAGC_A_MCS15_MCS12:
-	case RTXAGC_B_MCS15_MCS12:
-		index = 7;
-		break;
-	default:
-		regaddr &= 0xFFF;
-		if (regaddr >= 0xC20 && regaddr <= 0xC4C)
-			index = (u8) ((regaddr - 0xC20) / 4);
-		else if (regaddr >= 0xE20 && regaddr <= 0xE4C)
-			index = (u8) ((regaddr - 0xE20) / 4);
-		break;
-	};
-	return index;
-}
+static void rtl8723be_phy_set_rf_on(struct ieee80211_hw *hw);
+static void rtl8723be_phy_set_io(struct ieee80211_hw *hw);
 
 u32 rtl8723be_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
 			       u32 regaddr, u32 bitmask)
@@ -265,9 +69,8 @@
 	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
 
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
-		 "regaddr(%#x), rfpath(%#x), "
-		  "bitmask(%#x), original_value(%#x)\n",
-		  regaddr, rfpath, bitmask, original_value);
+		 "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
+		 regaddr, rfpath, bitmask, original_value);
 
 	return readback_value;
 }
@@ -300,6 +103,7 @@
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
 		 "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
 		  regaddr, bitmask, data, path);
+
 }
 
 bool rtl8723be_phy_mac_config(struct ieee80211_hw *hw)
@@ -316,7 +120,7 @@
 	bool rtstatus = true;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u16 regval;
-	u8 reg_hwparafile = 1;
+	u8 b_reg_hwparafile = 1;
 	u32 tmp;
 	u8 crystalcap = rtlpriv->efuse.crystalcap;
 	rtl8723_phy_init_bb_rf_reg_def(hw);
@@ -333,7 +137,7 @@
 
 	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
 
-	if (reg_hwparafile == 1)
+	if (b_reg_hwparafile == 1)
 		rtstatus = _rtl8723be_phy_bb8723b_config_parafile(hw);
 
 	crystalcap = crystalcap & 0x3F;
@@ -348,18 +152,49 @@
 	return rtl8723be_phy_rf6052_config(hw);
 }
 
+static bool _rtl8723be_check_condition(struct ieee80211_hw *hw,
+				       const u32  condition)
+{
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	u32 _board = rtlefuse->board_type; /*need efuse define*/
+	u32 _interface = rtlhal->interface;
+	u32 _platform = 0x08;/*SupportPlatform */
+	u32 cond = condition;
+
+	if (condition == 0xCDCDCDCD)
+		return true;
+
+	cond = condition & 0xFF;
+	if ((_board & cond) == 0 && cond != 0x1F)
+		return false;
+
+	cond = condition & 0xFF00;
+	cond = cond >> 8;
+	if ((_interface & cond) == 0 && cond != 0x07)
+		return false;
+
+	cond = condition & 0xFF0000;
+	cond = cond >> 16;
+	if ((_platform & cond) == 0 && cond != 0x0F)
+		return false;
+	return true;
+}
+
 static void _rtl8723be_config_rf_reg(struct ieee80211_hw *hw, u32 addr,
 				     u32 data, enum radio_path rfpath,
 				     u32 regaddr)
 {
 	if (addr == 0xfe || addr == 0xffe) {
+		/* In order not to disturb BT music
+		 *	when wifi init.(1ant NIC only)
+		 */
 		mdelay(50);
 	} else {
 		rtl_set_rfreg(hw, rfpath, regaddr, RFREG_OFFSET_MASK, data);
 		udelay(1);
 	}
 }
-
 static void _rtl8723be_config_rf_radio_a(struct ieee80211_hw *hw,
 					 u32 addr, u32 data)
 {
@@ -368,12 +203,13 @@
 
 	_rtl8723be_config_rf_reg(hw, addr, data, RF90_PATH_A,
 				 addr | maskforphyset);
+
 }
 
 static void _rtl8723be_phy_init_tx_power_by_rate(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 
 	u8 band, path, txnum, section;
 
@@ -383,16 +219,38 @@
 				for (section = 0;
 				     section < TX_PWR_BY_RATE_NUM_SECTION;
 				     ++section)
-					rtlphy->tx_power_by_rate_offset[band]
-						[path][txnum][section] = 0;
+					rtlphy->tx_power_by_rate_offset
+					  [band][path][txnum][section] = 0;
 }
 
-static void phy_set_txpwr_by_rate_base(struct ieee80211_hw *hw, u8 band,
-				       u8 path, u8 rate_section,
-				       u8 txnum, u8 value)
+static void _rtl8723be_config_bb_reg(struct ieee80211_hw *hw,
+				     u32 addr, u32 data)
+{
+	if (addr == 0xfe) {
+		mdelay(50);
+	} else if (addr == 0xfd) {
+		mdelay(5);
+	} else if (addr == 0xfc) {
+		mdelay(1);
+	} else if (addr == 0xfb) {
+		udelay(50);
+	} else if (addr == 0xfa) {
+		udelay(5);
+	} else if (addr == 0xf9) {
+		udelay(1);
+	} else {
+		rtl_set_bbreg(hw, addr, MASKDWORD, data);
+		udelay(1);
+	}
+}
+
+static void _rtl8723be_phy_set_txpower_by_rate_base(struct ieee80211_hw *hw,
+						    u8 band,
+						    u8 path, u8 rate_section,
+						    u8 txnum, u8 value)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 
 	if (path > RF90_PATH_D) {
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
@@ -417,23 +275,24 @@
 			break;
 		default:
 			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-				 "Invalid RateSection %d in Band 2.4G, Rf Path"
-				  " %d, %dTx in PHY_SetTxPowerByRateBase()\n",
-				  rate_section, path, txnum);
+				 "Invalid RateSection %d in Band 2.4G, Rf Path %d, %dTx in PHY_SetTxPowerByRateBase()\n",
+				 rate_section, path, txnum);
 			break;
 		};
 	} else {
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 			 "Invalid Band %d in PHY_SetTxPowerByRateBase()\n",
-			  band);
+			 band);
 	}
+
 }
 
-static u8 phy_get_txpwr_by_rate_base(struct ieee80211_hw *hw, u8 band, u8 path,
-				     u8 txnum, u8 rate_section)
+static u8 _rtl8723be_phy_get_txpower_by_rate_base(struct ieee80211_hw *hw,
+						  u8 band, u8 path, u8 txnum,
+						  u8 rate_section)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	u8 value = 0;
 	if (path > RF90_PATH_D) {
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
@@ -458,15 +317,14 @@
 			break;
 		default:
 			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-				 "Invalid RateSection %d in Band 2.4G, Rf Path"
-				  " %d, %dTx in PHY_GetTxPowerByRateBase()\n",
-				  rate_section, path, txnum);
+				 "Invalid RateSection %d in Band 2.4G, Rf Path %d, %dTx in PHY_GetTxPowerByRateBase()\n",
+				 rate_section, path, txnum);
 			break;
 		};
 	} else {
 		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
 			 "Invalid Band %d in PHY_GetTxPowerByRateBase()\n",
-			  band);
+			 band);
 	}
 
 	return value;
@@ -475,45 +333,51 @@
 static void _rtl8723be_phy_store_txpower_by_rate_base(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	u16 raw_value = 0;
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u16 rawvalue = 0;
 	u8 base = 0, path = 0;
 
 	for (path = RF90_PATH_A; path <= RF90_PATH_B; ++path) {
 		if (path == RF90_PATH_A) {
-			raw_value = (u16) (rtlphy->tx_power_by_rate_offset
+			rawvalue = (u16)(rtlphy->tx_power_by_rate_offset
 				[BAND_ON_2_4G][path][RF_1TX][3] >> 24) & 0xFF;
-			base = (raw_value >> 4) * 10 + (raw_value & 0xF);
-			phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, CCK,
-						   RF_1TX, base);
+			base = (rawvalue >> 4) * 10 + (rawvalue & 0xF);
+			_rtl8723be_phy_set_txpower_by_rate_base(hw,
+				BAND_ON_2_4G, path, CCK, RF_1TX, base);
 		} else if (path == RF90_PATH_B) {
-			raw_value = (u16) (rtlphy->tx_power_by_rate_offset
+			rawvalue = (u16)(rtlphy->tx_power_by_rate_offset
 				[BAND_ON_2_4G][path][RF_1TX][3] >> 0) & 0xFF;
-			base = (raw_value >> 4) * 10 + (raw_value & 0xF);
-			phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path,
-						   CCK, RF_1TX, base);
+			base = (rawvalue >> 4) * 10 + (rawvalue & 0xF);
+			_rtl8723be_phy_set_txpower_by_rate_base(hw,
+								BAND_ON_2_4G,
+								path, CCK,
+								RF_1TX, base);
 		}
-		raw_value = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
-					  [path][RF_1TX][1] >> 24) & 0xFF;
-		base = (raw_value >> 4) * 10 + (raw_value & 0xF);
-		phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, OFDM, RF_1TX,
-					   base);
+		rawvalue = (u16)(rtlphy->tx_power_by_rate_offset
+				[BAND_ON_2_4G][path][RF_1TX][1] >> 24) & 0xFF;
+		base = (rawvalue >> 4) * 10 + (rawvalue & 0xF);
+		_rtl8723be_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G,
+							path, OFDM, RF_1TX,
+							base);
 
-		raw_value = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
-					  [path][RF_1TX][5] >> 24) & 0xFF;
-		base = (raw_value >> 4) * 10 + (raw_value & 0xF);
-		phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path, HT_MCS0_MCS7,
-					   RF_1TX, base);
+		rawvalue = (u16)(rtlphy->tx_power_by_rate_offset
+				[BAND_ON_2_4G][path][RF_1TX][5] >> 24) & 0xFF;
+		base = (rawvalue >> 4) * 10 + (rawvalue & 0xF);
+		_rtl8723be_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G,
+							path, HT_MCS0_MCS7,
+							RF_1TX, base);
 
-		raw_value = (u16) (rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
-					  [path][RF_2TX][7] >> 24) & 0xFF;
-		base = (raw_value >> 4) * 10 + (raw_value & 0xF);
-		phy_set_txpwr_by_rate_base(hw, BAND_ON_2_4G, path,
-					   HT_MCS8_MCS15, RF_2TX, base);
+		rawvalue = (u16)(rtlphy->tx_power_by_rate_offset
+				[BAND_ON_2_4G][path][RF_2TX][7] >> 24) & 0xFF;
+		base = (rawvalue >> 4) * 10 + (rawvalue & 0xF);
+		_rtl8723be_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G,
+							path, HT_MCS8_MCS15,
+							RF_2TX, base);
 	}
 }
 
-static void phy_conv_dbm_to_rel(u32 *data, u8 start, u8 end, u8 base_val)
+static void _phy_convert_txpower_dbm_to_relative_value(u32 *data, u8 start,
+						u8 end, u8 base_val)
 {
 	char i = 0;
 	u8 temp_value = 0;
@@ -522,15 +386,15 @@
 	for (i = 3; i >= 0; --i) {
 		if (i >= start && i <= end) {
 			/* Get the exact value */
-			temp_value = (u8) (*data >> (i * 8)) & 0xF;
-			temp_value += ((u8) ((*data >> (i*8 + 4)) & 0xF)) * 10;
+			temp_value = (u8)(*data >> (i * 8)) & 0xF;
+			temp_value += ((u8)((*data >> (i*8 + 4)) & 0xF)) * 10;
 
 			/* Change the value to a relative value */
 			temp_value = (temp_value > base_val) ?
 				     temp_value - base_val :
 				     base_val - temp_value;
 		} else {
-			temp_value = (u8) (*data >> (i * 8)) & 0xFF;
+			temp_value = (u8)(*data >> (i * 8)) & 0xFF;
 		}
 		temp_data <<= 8;
 		temp_data |= temp_value;
@@ -538,56 +402,65 @@
 	*data = temp_data;
 }
 
-static void conv_dbm_to_rel(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	u8 base = 0, rfpath = RF90_PATH_A;
-
-	base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath,
-					  RF_1TX, CCK);
-	phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
-			    [rfpath][RF_1TX][2]), 1, 1, base);
-	phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
-			    [rfpath][RF_1TX][3]), 1, 3, base);
-
-	base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath,
-					  RF_1TX, OFDM);
-	phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
-			    [rfpath][RF_1TX][0]), 0, 3, base);
-	phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
-			    [rfpath][RF_1TX][1]), 0, 3, base);
-
-	base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath,
-					  RF_1TX, HT_MCS0_MCS7);
-	phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
-			    [rfpath][RF_1TX][4]), 0, 3, base);
-	phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
-			    [rfpath][RF_1TX][5]), 0, 3, base);
-
-	base = phy_get_txpwr_by_rate_base(hw, BAND_ON_2_4G, rfpath,
-					  RF_2TX, HT_MCS8_MCS15);
-	phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
-			    [rfpath][RF_2TX][6]), 0, 3, base);
-
-	phy_conv_dbm_to_rel(&(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G]
-			    [rfpath][RF_2TX][7]), 0, 3, base);
-
-	RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
-		 "<=== conv_dbm_to_rel()\n");
-}
-
-static void _rtl8723be_phy_txpower_by_rate_configuration(
+static void _rtl8723be_phy_convert_txpower_dbm_to_relative_value(
 							struct ieee80211_hw *hw)
 {
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 base = 0, rfpath = RF90_PATH_A;
+
+	base = _rtl8723be_phy_get_txpower_by_rate_base(hw,
+			BAND_ON_2_4G, rfpath, RF_1TX, CCK);
+	_phy_convert_txpower_dbm_to_relative_value(
+	    &rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfpath][RF_1TX][2],
+	    1, 1, base);
+	_phy_convert_txpower_dbm_to_relative_value(
+	    &rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfpath][RF_1TX][3],
+	    1, 3, base);
+
+	base = _rtl8723be_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfpath,
+						       RF_1TX, OFDM);
+	_phy_convert_txpower_dbm_to_relative_value(
+	    &rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfpath][RF_1TX][0],
+	    0, 3, base);
+	_phy_convert_txpower_dbm_to_relative_value(
+	    &rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfpath][RF_1TX][1],
+	    0, 3, base);
+
+	base = _rtl8723be_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G,
+						rfpath, RF_1TX, HT_MCS0_MCS7);
+	_phy_convert_txpower_dbm_to_relative_value(
+	    &rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfpath][RF_1TX][4],
+	    0, 3, base);
+	_phy_convert_txpower_dbm_to_relative_value(
+	    &rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfpath][RF_1TX][5],
+	    0, 3, base);
+
+	base = _rtl8723be_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G,
+						       rfpath, RF_2TX,
+						       HT_MCS8_MCS15);
+	_phy_convert_txpower_dbm_to_relative_value(
+	    &rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfpath][RF_2TX][6],
+	    0, 3, base);
+
+	_phy_convert_txpower_dbm_to_relative_value(
+	    &rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfpath][RF_2TX][7],
+	    0, 3, base);
+
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+	    "<===_rtl8723be_phy_convert_txpower_dbm_to_relative_value()\n");
+}
+
+static void phy_txpower_by_rate_config(struct ieee80211_hw *hw)
+{
 	_rtl8723be_phy_store_txpower_by_rate_base(hw);
-	conv_dbm_to_rel(hw);
+	_rtl8723be_phy_convert_txpower_dbm_to_relative_value(hw);
 }
 
 static bool _rtl8723be_phy_bb8723b_config_parafile(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	bool rtstatus;
 
@@ -603,7 +476,7 @@
 		rtstatus = _rtl8723be_phy_config_bb_with_pgheaderfile(hw,
 						BASEBAND_CONFIG_PHY_REG);
 	}
-	_rtl8723be_phy_txpower_by_rate_configuration(hw);
+	phy_txpower_by_rate_config(hw);
 	if (!rtstatus) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!");
 		return false;
@@ -614,39 +487,237 @@
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
 		return false;
 	}
-	rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw,
-						       RFPGA0_XA_HSSIPARAMETER2,
-						       0x200));
+	rtlphy->cck_high_power = (bool)(rtl_get_bbreg(hw,
+						      RFPGA0_XA_HSSIPARAMETER2,
+						      0x200));
 	return true;
 }
 
+static bool _rtl8723be_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 i;
+	u32 arraylength;
+	u32 *ptrarray;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read rtl8723beMACPHY_Array\n");
+	arraylength = RTL8723BEMAC_1T_ARRAYLEN;
+	ptrarray = RTL8723BEMAC_1T_ARRAY;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "Img:RTL8723bEMAC_1T_ARRAY LEN %d\n", arraylength);
+	for (i = 0; i < arraylength; i = i + 2)
+		rtl_write_byte(rtlpriv, ptrarray[i], (u8)ptrarray[i + 1]);
+	return true;
+}
+
+static bool _rtl8723be_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+						     u8 configtype)
+{
+	#define READ_NEXT_PAIR(v1, v2, i) \
+		do { \
+			i += 2; \
+			v1 = array_table[i];\
+			v2 = array_table[i+1]; \
+		} while (0)
+
+	int i;
+	u32 *array_table;
+	u16 arraylen;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 v1 = 0, v2 = 0;
+
+	if (configtype == BASEBAND_CONFIG_PHY_REG) {
+		arraylen = RTL8723BEPHY_REG_1TARRAYLEN;
+		array_table = RTL8723BEPHY_REG_1TARRAY;
+
+		for (i = 0; i < arraylen; i = i + 2) {
+			v1 = array_table[i];
+			v2 = array_table[i+1];
+			if (v1 < 0xcdcdcdcd) {
+				_rtl8723be_config_bb_reg(hw, v1, v2);
+			} else {/*This line is the start line of branch.*/
+				/* to protect READ_NEXT_PAIR not overrun */
+				if (i >= arraylen - 2)
+					break;
+
+				if (!_rtl8723be_check_condition(hw,
+						array_table[i])) {
+					/*Discard the following
+					 *(offset, data) pairs
+					 */
+					READ_NEXT_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD &&
+					       i < arraylen - 2) {
+						READ_NEXT_PAIR(v1, v2, i);
+					}
+					i -= 2; /* prevent from for-loop += 2*/
+				/*Configure matched pairs and
+				 *skip to end of if-else.
+				 */
+				} else {
+					READ_NEXT_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD &&
+					       i < arraylen - 2) {
+						_rtl8723be_config_bb_reg(hw,
+								    v1, v2);
+						READ_NEXT_PAIR(v1, v2, i);
+					}
+
+					while (v2 != 0xDEAD && i < arraylen - 2)
+						READ_NEXT_PAIR(v1, v2, i);
+				}
+			}
+		}
+	} else if (configtype == BASEBAND_CONFIG_AGC_TAB) {
+		arraylen = RTL8723BEAGCTAB_1TARRAYLEN;
+		array_table = RTL8723BEAGCTAB_1TARRAY;
+
+		for (i = 0; i < arraylen; i = i + 2) {
+			v1 = array_table[i];
+			v2 = array_table[i+1];
+			if (v1 < 0xCDCDCDCD) {
+				rtl_set_bbreg(hw, array_table[i],
+					      MASKDWORD,
+					      array_table[i + 1]);
+				udelay(1);
+				continue;
+			} else {/*This line is the start line of branch.*/
+				/* to protect READ_NEXT_PAIR not overrun */
+				if (i >= arraylen - 2)
+					break;
+
+				if (!_rtl8723be_check_condition(hw,
+					array_table[i])) {
+					/*Discard the following
+					 *(offset, data) pairs
+					 */
+					READ_NEXT_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD &&
+					       i < arraylen - 2) {
+						READ_NEXT_PAIR(v1, v2, i);
+					}
+					i -= 2; /* prevent from for-loop += 2*/
+				/*Configure matched pairs and
+				 *skip to end of if-else.
+				 */
+				} else {
+					READ_NEXT_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD &&
+					       i < arraylen - 2) {
+						rtl_set_bbreg(hw, array_table[i],
+							      MASKDWORD,
+							      array_table[i + 1]);
+						udelay(1);
+						READ_NEXT_PAIR(v1, v2, i);
+					}
+
+					while (v2 != 0xDEAD && i < arraylen - 2)
+						READ_NEXT_PAIR(v1, v2, i);
+				}
+			}
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+				 "The agctab_array_table[0] is %x Rtl818EEPHY_REGArray[1] is %x\n",
+				 array_table[i], array_table[i + 1]);
+		}
+	}
+	return true;
+}
+
+static u8 _rtl8723be_get_rate_section_index(u32 regaddr)
+{
+	u8 index = 0;
+
+	switch (regaddr) {
+	case RTXAGC_A_RATE18_06:
+		index = 0;
+	break;
+	case RTXAGC_A_RATE54_24:
+		index = 1;
+	break;
+	case RTXAGC_A_CCK1_MCS32:
+		index = 2;
+	break;
+	case RTXAGC_B_CCK11_A_CCK2_11:
+		index = 3;
+	break;
+	case RTXAGC_A_MCS03_MCS00:
+		index = 4;
+	break;
+	case RTXAGC_A_MCS07_MCS04:
+		index = 5;
+	break;
+	case RTXAGC_A_MCS11_MCS08:
+		index = 6;
+	break;
+	case RTXAGC_A_MCS15_MCS12:
+		index = 7;
+	break;
+	case RTXAGC_B_RATE18_06:
+		index = 0;
+	break;
+	case RTXAGC_B_RATE54_24:
+		index = 1;
+	break;
+	case RTXAGC_B_CCK1_55_MCS32:
+		index = 2;
+	break;
+	case RTXAGC_B_MCS03_MCS00:
+		index = 4;
+	break;
+	case RTXAGC_B_MCS07_MCS04:
+		index = 5;
+	break;
+	case RTXAGC_B_MCS11_MCS08:
+		index = 6;
+	break;
+	case RTXAGC_B_MCS15_MCS12:
+		index = 7;
+	break;
+	default:
+		regaddr &= 0xFFF;
+		if (regaddr >= 0xC20 && regaddr <= 0xC4C)
+			index = (u8)((regaddr - 0xC20) / 4);
+		else if (regaddr >= 0xE20 && regaddr <= 0xE4C)
+			index = (u8)((regaddr - 0xE20) / 4);
+		break;
+	};
+	return index;
+}
+
 static void _rtl8723be_store_tx_power_by_rate(struct ieee80211_hw *hw,
 					      u32 band, u32 rfpath,
 					      u32 txnum, u32 regaddr,
 					      u32 bitmask, u32 data)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	u8 rate_section = _rtl8723be_get_rate_section_index(regaddr);
 
 	if (band != BAND_ON_2_4G && band != BAND_ON_5G) {
-		RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR,
-			 "Invalid Band %d\n", band);
+		RT_TRACE(rtlpriv, FPHY, PHY_TXPWR, "Invalid Band %d\n", band);
 		return;
 	}
-
-	if (rfpath > TX_PWR_BY_RATE_NUM_RF) {
-		RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR,
+	if (rfpath > MAX_RF_PATH - 1) {
+		RT_TRACE(rtlpriv, FPHY, PHY_TXPWR,
 			 "Invalid RfPath %d\n", rfpath);
 		return;
 	}
-	if (txnum > TX_PWR_BY_RATE_NUM_RF) {
-		RT_TRACE(rtlpriv, COMP_POWER, PHY_TXPWR,
-			 "Invalid TxNum %d\n", txnum);
+	if (txnum > MAX_RF_PATH - 1) {
+		RT_TRACE(rtlpriv, FPHY, PHY_TXPWR, "Invalid TxNum %d\n", txnum);
 		return;
 	}
+
 	rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section] =
 									data;
+
 }
 
 static bool _rtl8723be_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
@@ -678,21 +749,6 @@
 					_rtl8723be_store_tx_power_by_rate(hw,
 							v1, v2, v3, v4, v5, v6);
 				continue;
-			} else {
-				/*don't need the hw_body*/
-				if (!_rtl8723be_check_condition(hw,
-						phy_regarray_table_pg[i])) {
-					i += 2; /* skip the pair of expression*/
-					v1 = phy_regarray_table_pg[i];
-					v2 = phy_regarray_table_pg[i+1];
-					v3 = phy_regarray_table_pg[i+2];
-					while (v2 != 0xDEAD) {
-						i += 3;
-						v1 = phy_regarray_table_pg[i];
-						v2 = phy_regarray_table_pg[i+1];
-						v3 = phy_regarray_table_pg[i+2];
-					}
-				}
 			}
 		}
 	} else {
@@ -733,22 +789,27 @@
 			v2 = radioa_array_table[i+1];
 			if (v1 < 0xcdcdcdcd) {
 				_rtl8723be_config_rf_radio_a(hw, v1, v2);
-			} else { /*This line is the start line of branch.*/
+			} else {/*This line is the start line of branch.*/
+				/* to protect READ_NEXT_PAIR not overrun */
+				if (i >= radioa_arraylen - 2)
+					break;
+
 				if (!_rtl8723be_check_condition(hw,
 						radioa_array_table[i])) {
-					/* Discard the following
-					 * (offset, data) pairs
+					/*Discard the following
+					 *(offset, data) pairs
 					 */
 					READ_NEXT_RF_PAIR(v1, v2, i);
 					while (v2 != 0xDEAD &&
 					       v2 != 0xCDEF &&
 					       v2 != 0xCDCD &&
-					       i < radioa_arraylen - 2)
+					       i < radioa_arraylen - 2) {
 						READ_NEXT_RF_PAIR(v1, v2, i);
+					}
 					i -= 2; /* prevent from for-loop += 2*/
 				} else {
-					/* Configure matched pairs
-					 * and skip to end of if-else.
+					/*Configure matched pairs
+					 *and skip to end of if-else.
 					 */
 					READ_NEXT_RF_PAIR(v1, v2, i);
 					while (v2 != 0xDEAD &&
@@ -770,18 +831,12 @@
 
 		if (rtlhal->oem_id == RT_CID_819X_HP)
 			_rtl8723be_config_rf_radio_a(hw, 0x52, 0x7E4BD);
-
 		break;
 	case RF90_PATH_B:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not process\n");
-		break;
 	case RF90_PATH_C:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not process\n");
 		break;
 	case RF90_PATH_D:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 			 "switch case not process\n");
 		break;
 	}
@@ -791,26 +846,25 @@
 void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 
 	rtlphy->default_initialgain[0] =
-	    (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
 	rtlphy->default_initialgain[1] =
-	    (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
 	rtlphy->default_initialgain[2] =
-	    (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
 	rtlphy->default_initialgain[3] =
-	    (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
 
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-		 "Default initial gain (c50 = 0x%x, "
-		  "c58 = 0x%x, c60 = 0x%x, c68 = 0x%x\n",
-		  rtlphy->default_initialgain[0],
-		  rtlphy->default_initialgain[1],
-		  rtlphy->default_initialgain[2],
-		  rtlphy->default_initialgain[3]);
+		 "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x\n",
+		 rtlphy->default_initialgain[0],
+		 rtlphy->default_initialgain[1],
+		 rtlphy->default_initialgain[2],
+		 rtlphy->default_initialgain[3]);
 
-	rtlphy->framesync = (u8) rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3,
+	rtlphy->framesync = (u8)rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3,
 					       MASKBYTE0);
 	rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2,
 					      MASKDWORD);
@@ -823,7 +877,7 @@
 void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	u8 txpwr_level;
 	long txpwr_dbm;
 
@@ -854,6 +908,7 @@
 	case DESC92C_RATE1M:
 		rate_section = 2;
 		break;
+
 	case DESC92C_RATE2M:
 	case DESC92C_RATE5_5M:
 		if (path == RF90_PATH_A)
@@ -861,49 +916,58 @@
 		else if (path == RF90_PATH_B)
 			rate_section = 2;
 		break;
+
 	case DESC92C_RATE11M:
 		rate_section = 3;
 		break;
+
 	case DESC92C_RATE6M:
 	case DESC92C_RATE9M:
 	case DESC92C_RATE12M:
 	case DESC92C_RATE18M:
 		rate_section = 0;
 		break;
+
 	case DESC92C_RATE24M:
 	case DESC92C_RATE36M:
 	case DESC92C_RATE48M:
 	case DESC92C_RATE54M:
 		rate_section = 1;
 		break;
+
 	case DESC92C_RATEMCS0:
 	case DESC92C_RATEMCS1:
 	case DESC92C_RATEMCS2:
 	case DESC92C_RATEMCS3:
 		rate_section = 4;
 		break;
+
 	case DESC92C_RATEMCS4:
 	case DESC92C_RATEMCS5:
 	case DESC92C_RATEMCS6:
 	case DESC92C_RATEMCS7:
 		rate_section = 5;
 		break;
+
 	case DESC92C_RATEMCS8:
 	case DESC92C_RATEMCS9:
 	case DESC92C_RATEMCS10:
 	case DESC92C_RATEMCS11:
 		rate_section = 6;
 		break;
+
 	case DESC92C_RATEMCS12:
 	case DESC92C_RATEMCS13:
 	case DESC92C_RATEMCS14:
 	case DESC92C_RATEMCS15:
 		rate_section = 7;
 		break;
+
 	default:
 		RT_ASSERT(true, "Rate_Section is Illegal\n");
 		break;
 	}
+
 	return rate_section;
 }
 
@@ -912,7 +976,7 @@
 					 enum radio_path rfpath, u8 rate)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	u8 shift = 0, rate_section, tx_num;
 	char tx_pwr_diff = 0;
 
@@ -988,7 +1052,7 @@
 		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
 			 "Illegal channel!\n");
 	}
-	if (RTL8723E_RX_HAL_IS_CCK_RATE(rate))
+	if (RX_HAL_IS_CCK_RATE(rate))
 		txpower = rtlefuse->txpwrlevel_cck[path][index];
 	else if (DESC92C_RATE6M <= rate)
 		txpower = rtlefuse->txpwrlevel_ht40_1s[path][index];
@@ -997,7 +1061,7 @@
 			 "invalid rate\n");
 
 	if (DESC92C_RATE6M <= rate && rate <= DESC92C_RATE54M &&
-	    !RTL8723E_RX_HAL_IS_CCK_RATE(rate))
+	    !RX_HAL_IS_CCK_RATE(rate))
 		txpower += rtlefuse->txpwr_legacyhtdiff[0][TX_1S];
 
 	if (bandwidth == HT_CHANNEL_WIDTH_20) {
@@ -1011,6 +1075,7 @@
 		if (DESC92C_RATEMCS8 <= rate && rate <= DESC92C_RATEMCS15)
 			txpower += rtlefuse->txpwr_ht40diff[0][TX_2S];
 	}
+
 	if (rtlefuse->eeprom_regulatory != 2)
 		power_diff_byrate = _rtl8723be_get_txpower_by_rate(hw,
 								   BAND_ON_2_4G,
@@ -1046,6 +1111,7 @@
 			rtl8723_phy_set_bb_reg(hw, RTXAGC_B_CCK11_A_CCK2_11,
 					       MASKBYTE3, power_index);
 			break;
+
 		case DESC92C_RATE6M:
 			rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06,
 					       MASKBYTE0, power_index);
@@ -1062,6 +1128,7 @@
 			rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE18_06,
 					       MASKBYTE3, power_index);
 			break;
+
 		case DESC92C_RATE24M:
 			rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24,
 					       MASKBYTE0, power_index);
@@ -1078,6 +1145,7 @@
 			rtl8723_phy_set_bb_reg(hw, RTXAGC_A_RATE54_24,
 					       MASKBYTE3, power_index);
 			break;
+
 		case DESC92C_RATEMCS0:
 			rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00,
 					       MASKBYTE0, power_index);
@@ -1094,6 +1162,7 @@
 			rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS03_MCS00,
 					       MASKBYTE3, power_index);
 			break;
+
 		case DESC92C_RATEMCS4:
 			rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04,
 					       MASKBYTE0, power_index);
@@ -1110,6 +1179,7 @@
 			rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS07_MCS04,
 					       MASKBYTE3, power_index);
 			break;
+
 		case DESC92C_RATEMCS8:
 			rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08,
 					       MASKBYTE0, power_index);
@@ -1126,9 +1196,9 @@
 			rtl8723_phy_set_bb_reg(hw, RTXAGC_A_MCS11_MCS08,
 					       MASKBYTE3, power_index);
 			break;
+
 		default:
-			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
-				 "Invalid Rate!!\n");
+			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Invalid Rate!!\n");
 			break;
 		}
 	} else {
@@ -1192,10 +1262,11 @@
 
 	if (!is_hal_stop(rtlhal)) {
 		switch (operation) {
-		case SCAN_OPT_BACKUP:
-			iotype = IO_CMD_PAUSE_DM_BY_SCAN;
+		case SCAN_OPT_BACKUP_BAND0:
+			iotype = IO_CMD_PAUSE_BAND0_DM_BY_SCAN;
 			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD,
 						      (u8 *)&iotype);
+
 			break;
 		case SCAN_OPT_RESTORE:
 			iotype = IO_CMD_RESUME_DM_BY_SCAN;
@@ -1214,15 +1285,15 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	u8 reg_bw_opmode;
 	u8 reg_prsr_rsc;
 
 	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
 		 "Switch to %s bandwidth\n",
-		 rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
-		 "20MHz" : "40MHz");
+		  rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+		  "20MHz" : "40MHz");
 
 	if (is_hal_stop(rtlhal)) {
 		rtlphy->set_bwmode_inprogress = false;
@@ -1254,13 +1325,17 @@
 	case HT_CHANNEL_WIDTH_20:
 		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
 		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
+	/*	rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);*/
 		break;
 	case HT_CHANNEL_WIDTH_20_40:
 		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
 		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+
 		rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
 			      (mac->cur_40_prime_sc >> 1));
 		rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
+		/*rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0);*/
+
 		rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
 			      (mac->cur_40_prime_sc ==
 			       HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
@@ -1279,7 +1354,7 @@
 			    enum nl80211_channel_type ch_type)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u8 tmp_bw = rtlphy->current_chan_bw;
 
@@ -1300,7 +1375,7 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	u32 delay;
 
 	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
@@ -1310,11 +1385,11 @@
 	do {
 		if (!rtlphy->sw_chnl_inprogress)
 			break;
-		if (!rtl8723be_phy_sw_chn_step_by_step(hw,
-						       rtlphy->current_channel,
-						       &rtlphy->sw_chnl_stage,
-						       &rtlphy->sw_chnl_step,
-						       &delay)) {
+		if (!_rtl8723be_phy_sw_chnl_step_by_step(hw,
+							 rtlphy->current_channel,
+							 &rtlphy->sw_chnl_stage,
+							 &rtlphy->sw_chnl_step,
+							 &delay)) {
 			if (delay > 0)
 				mdelay(delay);
 			else
@@ -1330,7 +1405,7 @@
 u8 rtl8723be_phy_sw_chnl(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
 	if (rtlphy->sw_chnl_inprogress)
@@ -1345,25 +1420,23 @@
 	if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
 		rtl8723be_phy_sw_chnl_callback(hw);
 		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
-			 "sw_chnl_inprogress false schdule "
-			  "workitem current channel %d\n",
-			  rtlphy->current_channel);
+			 "sw_chnl_inprogress false schdule workitem current channel %d\n",
+			 rtlphy->current_channel);
 		rtlphy->sw_chnl_inprogress = false;
 	} else {
 		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
-			 "sw_chnl_inprogress false driver sleep or"
-			  " unload\n");
+			 "sw_chnl_inprogress false driver sleep or unload\n");
 		rtlphy->sw_chnl_inprogress = false;
 	}
 	return 1;
 }
 
-static bool rtl8723be_phy_sw_chn_step_by_step(struct ieee80211_hw *hw,
-					      u8 channel, u8 *stage,
-					      u8 *step, u32 *delay)
+static bool _rtl8723be_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+						u8 channel, u8 *stage,
+						u8 *step, u32 *delay)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
 	u32 precommoncmdcnt;
 	struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
@@ -1381,10 +1454,13 @@
 					 0, 0, 0);
 	rtl8723_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
 					 MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+
 	postcommoncmdcnt = 0;
+
 	rtl8723_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
 					 MAX_POSTCMD_CNT, CMDID_END,
-					 0, 0, 0);
+					    0, 0, 0);
+
 	rfdependcmdcnt = 0;
 
 	RT_ASSERT((channel >= 1 && channel <= 14),
@@ -1397,7 +1473,7 @@
 
 	rtl8723_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
 					 MAX_RFDEPENDCMD_CNT,
-					 CMDID_END, 0, 0, 0);
+					    CMDID_END, 0, 0, 0);
 
 	do {
 		switch (*stage) {
@@ -1410,6 +1486,10 @@
 		case 2:
 			currentcmd = &postcommoncmd[*step];
 			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "Invalid 'stage' = %d, Check it!\n", *stage);
+			return true;
 		}
 
 		if (currentcmd->cmdid == CMDID_END) {
@@ -1432,11 +1512,11 @@
 			break;
 		case CMDID_WRITEPORT_USHORT:
 			rtl_write_word(rtlpriv, currentcmd->para1,
-				       (u16) currentcmd->para2);
+				       (u16)currentcmd->para2);
 			break;
 		case CMDID_WRITEPORT_UCHAR:
 			rtl_write_byte(rtlpriv, currentcmd->para1,
-				       (u8) currentcmd->para2);
+				       (u8)currentcmd->para2);
 			break;
 		case CMDID_RF_WRITEREG:
 			for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
@@ -1451,7 +1531,7 @@
 			}
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 				 "switch case not process\n");
 			break;
 		}
@@ -1464,54 +1544,515 @@
 	return false;
 }
 
-static u8 _rtl8723be_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
+static u8 _rtl8723be_phy_path_a_iqk(struct ieee80211_hw *hw)
 {
-	u32 reg_eac, reg_e94, reg_e9c, reg_ea4;
+	u32 reg_eac, reg_e94, reg_e9c, tmp;
 	u8 result = 0x00;
 
-	rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1c);
-	rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x30008c1c);
-	rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x8214032a);
-	rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x28160000);
+	/* leave IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	/* switch to path A */
+	rtl_set_bbreg(hw, 0x948, MASKDWORD, 0x00000000);
+	/* enable path A PA in TXIQK mode */
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x20000);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0003f);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xc7f87);
 
-	rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911);
-	rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000);
-	rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
+	/* 1. TX IQK */
+	/* path-A IQK setting */
+	/* IQK setting */
+	rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, 0x01007c00);
+	rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+	/* path-A IQK setting */
+	rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x18008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RTX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+
+	rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x821403ea);
+	rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x28160000);
+	rtl_set_bbreg(hw, RTX_IQK_PI_B, MASKDWORD, 0x82110000);
+	rtl_set_bbreg(hw, RRX_IQK_PI_B, MASKDWORD, 0x28110000);
+	/* LO calibration setting */
+	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x00462911);
+	/* enter IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	/* One shot, path A LOK & IQK */
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
 
 	mdelay(IQK_DELAY_TIME);
 
+	/* leave IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+
+	/* Check failed */
 	reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
 	reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
 	reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
-	reg_ea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD);
 
 	if (!(reg_eac & BIT(28)) &&
 	    (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
 	    (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
 		result |= 0x01;
+	else /* if Tx not OK, ignore Rx */
+		return result;
+
+	/* Allen 20131125 */
+	tmp = (reg_e9c & 0x03FF0000) >> 16;
+	if ((tmp & 0x200) > 0)
+		tmp = 0x400 - tmp;
+
+	if (!(reg_eac & BIT(28)) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) < 0x110) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) > 0xf0) &&
+	    (tmp < 0xf))
+		result |= 0x01;
+	else /* if Tx not OK, ignore Rx */
+		return result;
+
 	return result;
 }
 
-static bool phy_similarity_cmp(struct ieee80211_hw *hw, long result[][8],
-			       u8 c1, u8 c2)
+/* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */
+static u8 _rtl8723be_phy_path_a_rx_iqk(struct ieee80211_hw *hw)
 {
-	u32 i, j, diff, simularity_bitmap, bound;
-	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u32 reg_eac, reg_e94, reg_e9c, reg_ea4, u32tmp, tmp;
+	u8 result = 0x00;
 
-	u8 final_candidate[2] = { 0xFF, 0xFF };
-	bool bresult = true, is2t = IS_92C_SERIAL(rtlhal->version);
+	/* leave IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
 
-	if (is2t)
-		bound = 8;
+	/* switch to path A */
+	rtl_set_bbreg(hw, 0x948, MASKDWORD, 0x00000000);
+
+	/* 1 Get TXIMR setting */
+	/* modify RXIQK mode table */
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, 0x80000, 0x1);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0001f);
+	/* LNA2 off, PA on for Dcut */
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7fb7);
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	/* IQK setting */
+	rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, 0x01007c00);
+	rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+
+	/* path-A IQK setting */
+	rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x18008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RTX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+
+	rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x82160ff0);
+	rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x28110000);
+	rtl_set_bbreg(hw, RTX_IQK_PI_B, MASKDWORD, 0x82110000);
+	rtl_set_bbreg(hw, RRX_IQK_PI_B, MASKDWORD, 0x28110000);
+
+	/* LO calibration setting */
+	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a911);
+
+	/* enter IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	/* One shot, path A LOK & IQK */
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+	mdelay(IQK_DELAY_TIME);
+
+	/* leave IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+
+	/* Check failed */
+	reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+	reg_e94 = rtl_get_bbreg(hw, RTX_POWER_BEFORE_IQK_A, MASKDWORD);
+	reg_e9c = rtl_get_bbreg(hw, RTX_POWER_AFTER_IQK_A, MASKDWORD);
+
+	if (!(reg_eac & BIT(28)) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+	    (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
+		result |= 0x01;
+	else /* if Tx not OK, ignore Rx */
+		return result;
+
+	/* Allen 20131125 */
+	tmp = (reg_e9c & 0x03FF0000) >> 16;
+	if ((tmp & 0x200) > 0)
+		tmp = 0x400 - tmp;
+
+	if (!(reg_eac & BIT(28)) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) < 0x110) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) > 0xf0) &&
+	    (tmp < 0xf))
+		result |= 0x01;
+	else /* if Tx not OK, ignore Rx */
+		return result;
+
+	u32tmp = 0x80007C00 | (reg_e94 & 0x3FF0000) |
+		 ((reg_e9c & 0x3FF0000) >> 16);
+	rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, u32tmp);
+
+	/* 1 RX IQK */
+	/* modify RXIQK mode table */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, 0x80000, 0x1);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0001f);
+	/* LAN2 on, PA off for Dcut */
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7d77);
+
+	/* PA, PAD setting */
+	rtl_set_rfreg(hw, RF90_PATH_A, 0xdf, RFREG_OFFSET_MASK, 0xf80);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0x55, RFREG_OFFSET_MASK, 0x4021f);
+
+	/* IQK setting */
+	rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+
+	/* path-A IQK setting */
+	rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x18008c1c);
+	rtl_set_bbreg(hw, RTX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+
+	rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x82110000);
+	rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x2816001f);
+	rtl_set_bbreg(hw, RTX_IQK_PI_B, MASKDWORD, 0x82110000);
+	rtl_set_bbreg(hw, RRX_IQK_PI_B, MASKDWORD, 0x28110000);
+
+	/* LO calibration setting */
+	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a8d1);
+
+	/* enter IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	/* One shot, path A LOK & IQK */
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+	mdelay(IQK_DELAY_TIME);
+
+	/* leave IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+
+	/* Check failed */
+	reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+	reg_ea4 = rtl_get_bbreg(hw, RRX_POWER_BEFORE_IQK_A_2, MASKDWORD);
+
+	/* leave IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0xdf, RFREG_OFFSET_MASK, 0x780);
+
+	/* Allen 20131125 */
+	tmp = (reg_eac & 0x03FF0000) >> 16;
+		if ((tmp & 0x200) > 0)
+			tmp = 0x400 - tmp;
+	/* if Tx is OK, check whether Rx is OK */
+	if (!(reg_eac & BIT(27)) &&
+	    (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) &&
+	    (((reg_eac & 0x03FF0000) >> 16) != 0x36))
+		result |= 0x02;
+	else if (!(reg_eac & BIT(27)) &&
+		 (((reg_ea4 & 0x03FF0000) >> 16) < 0x110) &&
+		 (((reg_ea4 & 0x03FF0000) >> 16) > 0xf0) &&
+		 (tmp < 0xf))
+		result |= 0x02;
+
+	return result;
+}
+
+static u8 _rtl8723be_phy_path_b_iqk(struct ieee80211_hw *hw)
+{
+	u32 reg_eac, reg_e94, reg_e9c, tmp;
+	u8 result = 0x00;
+
+	/* leave IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	/* switch to path B */
+	rtl_set_bbreg(hw, 0x948, MASKDWORD, 0x00000280);
+
+	/* enable path B PA in TXIQK mode */
+	rtl_set_rfreg(hw, RF90_PATH_A, 0xed, RFREG_OFFSET_MASK, 0x00020);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0x43, RFREG_OFFSET_MASK, 0x40fc1);
+
+	/* 1 Tx IQK */
+	/* IQK setting */
+	rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, 0x01007c00);
+	rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+	/* path-A IQK setting */
+	rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x18008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RTX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+
+	rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x821403ea);
+	rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x28110000);
+	rtl_set_bbreg(hw, RTX_IQK_PI_B, MASKDWORD, 0x82110000);
+	rtl_set_bbreg(hw, RRX_IQK_PI_B, MASKDWORD, 0x28110000);
+
+	/* LO calibration setting */
+	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x00462911);
+
+	/* enter IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	/* One shot, path B LOK & IQK */
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+	mdelay(IQK_DELAY_TIME);
+
+	/* leave IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+
+	/* Check failed */
+	reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+	reg_e94 = rtl_get_bbreg(hw, RTX_POWER_BEFORE_IQK_A, MASKDWORD);
+	reg_e9c = rtl_get_bbreg(hw, RTX_POWER_AFTER_IQK_A, MASKDWORD);
+
+	if (!(reg_eac & BIT(28)) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+	    (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
+		result |= 0x01;
 	else
-		bound = 4;
+		return result;
+
+	/* Allen 20131125 */
+	tmp = (reg_e9c & 0x03FF0000) >> 16;
+	if ((tmp & 0x200) > 0)
+		tmp = 0x400 - tmp;
+
+	if (!(reg_eac & BIT(28)) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) < 0x110) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) > 0xf0) &&
+	    (tmp < 0xf))
+		result |= 0x01;
+	else
+		return result;
+
+	return result;
+}
+
+/* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */
+static u8 _rtl8723be_phy_path_b_rx_iqk(struct ieee80211_hw *hw)
+{
+	u32 reg_e94, reg_e9c, reg_ea4, reg_eac, u32tmp, tmp;
+	u8 result = 0x00;
+
+	/* leave IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	/* switch to path B */
+	rtl_set_bbreg(hw, 0x948, MASKDWORD, 0x00000280);
+
+	/* 1 Get TXIMR setting */
+	/* modify RXIQK mode table */
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0001f);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7ff7);
+
+	/* open PA S1 & SMIXER */
+	rtl_set_rfreg(hw, RF90_PATH_A, 0xed, RFREG_OFFSET_MASK, 0x00020);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0x43, RFREG_OFFSET_MASK, 0x60fed);
+
+	/* IQK setting */
+	rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, 0x01007c00);
+	rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+
+	/* path-B IQK setting */
+	rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x18008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RTX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+
+	rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x82160ff0);
+	rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x28110000);
+	rtl_set_bbreg(hw, RTX_IQK_PI_B, MASKDWORD, 0x82110000);
+	rtl_set_bbreg(hw, RRX_IQK_PI_B, MASKDWORD, 0x28110000);
+
+	/* LO calibration setting */
+	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a911);
+	/* enter IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	/* One shot, path B TXIQK @ RXIQK */
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+	mdelay(IQK_DELAY_TIME);
+
+	/* leave IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	/* Check failed */
+	reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+	reg_e94 = rtl_get_bbreg(hw, RTX_POWER_BEFORE_IQK_A, MASKDWORD);
+	reg_e9c = rtl_get_bbreg(hw, RTX_POWER_AFTER_IQK_A, MASKDWORD);
+
+	if (!(reg_eac & BIT(28)) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+	    (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
+		result |= 0x01;
+	else	/* if Tx not OK, ignore Rx */
+		return result;
+
+	/* Allen 20131125 */
+	tmp = (reg_e9c & 0x03FF0000) >> 16;
+	if ((tmp & 0x200) > 0)
+		tmp = 0x400 - tmp;
+
+	if (!(reg_eac & BIT(28)) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) < 0x110) &&
+	    (((reg_e94 & 0x03FF0000) >> 16) > 0xf0) &&
+	    (tmp < 0xf))
+		result |= 0x01;
+	else
+		return result;
+
+	u32tmp = 0x80007C00 | (reg_e94 & 0x3FF0000)  |
+		 ((reg_e9c & 0x3FF0000) >> 16);
+	rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, u32tmp);
+
+	/* 1 RX IQK */
+
+	/* <20121009, Kordan> RF Mode = 3 */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, 0x80000, 0x1);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0001f);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7d77);
+	rtl_set_rfreg(hw, RF90_PATH_A, RF_WE_LUT, 0x80000, 0x0);
+
+	/* open PA S1 & close SMIXER */
+	rtl_set_rfreg(hw, RF90_PATH_A, 0xed, RFREG_OFFSET_MASK, 0x00020);
+	rtl_set_rfreg(hw, RF90_PATH_A, 0x43, RFREG_OFFSET_MASK, 0x60fbd);
+
+	/* IQK setting */
+	rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+
+	/* path-B IQK setting */
+	rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x18008c1c);
+	rtl_set_bbreg(hw, RTX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+	rtl_set_bbreg(hw, RRX_IQK_TONE_B, MASKDWORD, 0x38008c1c);
+
+	rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x82110000);
+	rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x2816001f);
+	rtl_set_bbreg(hw, RTX_IQK_PI_B, MASKDWORD, 0x82110000);
+	rtl_set_bbreg(hw, RRX_IQK_PI_B, MASKDWORD, 0x28110000);
+
+	/* LO calibration setting */
+	rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a8d1);
+	/* enter IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+	/* One shot, path B LOK & IQK */
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
+	rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+	mdelay(IQK_DELAY_TIME);
+
+	/* leave IQK mode */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+	/* Check failed */
+	reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+	reg_ea4 = rtl_get_bbreg(hw, RRX_POWER_BEFORE_IQK_A_2, MASKDWORD);
+
+	/* Allen 20131125 */
+	tmp = (reg_eac & 0x03FF0000) >> 16;
+	if ((tmp & 0x200) > 0)
+		tmp = 0x400 - tmp;
+
+	/* if Tx is OK, check whether Rx is OK */
+	if (!(reg_eac & BIT(27)) &&
+	    (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) &&
+	    (((reg_eac & 0x03FF0000) >> 16) != 0x36))
+		result |= 0x02;
+	else if (!(reg_eac & BIT(27)) &&
+		 (((reg_ea4 & 0x03FF0000) >> 16) < 0x110) &&
+		 (((reg_ea4 & 0x03FF0000) >> 16) > 0xf0) &&
+		 (tmp < 0xf))
+		result |= 0x02;
+	else
+		return result;
+
+	return result;
+}
+
+static void _rtl8723be_phy_path_b_fill_iqk_matrix(struct ieee80211_hw *hw,
+						  bool b_iqk_ok,
+						  long result[][8],
+						  u8 final_candidate,
+						  bool btxonly)
+{
+	u32 oldval_1, x, tx1_a, reg;
+	long y, tx1_c;
+
+	if (final_candidate == 0xFF) {
+		return;
+	} else if (b_iqk_ok) {
+		oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE,
+					  MASKDWORD) >> 22) & 0x3FF;
+		x = result[final_candidate][4];
+		if ((x & 0x00000200) != 0)
+			x = x | 0xFFFFFC00;
+		tx1_a = (x * oldval_1) >> 8;
+		rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, 0x3FF, tx1_a);
+		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(27),
+			      ((x * oldval_1 >> 7) & 0x1));
+		y = result[final_candidate][5];
+		if ((y & 0x00000200) != 0)
+			y = y | 0xFFFFFC00;
+		tx1_c = (y * oldval_1) >> 8;
+		rtl_set_bbreg(hw, ROFDM0_XDTXAFE, 0xF0000000,
+			      ((tx1_c & 0x3C0) >> 6));
+		rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, 0x003F0000,
+			      (tx1_c & 0x3F));
+		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(25),
+			      ((y * oldval_1 >> 7) & 0x1));
+		if (btxonly)
+			return;
+		reg = result[final_candidate][6];
+		rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, 0x3FF, reg);
+		reg = result[final_candidate][7] & 0x3F;
+		rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, 0xFC00, reg);
+		reg = (result[final_candidate][7] >> 6) & 0xF;
+		/* rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg); */
+	}
+}
+
+static bool _rtl8723be_phy_simularity_compare(struct ieee80211_hw *hw,
+					      long result[][8], u8 c1, u8 c2)
+{
+	u32 i, j, diff, simularity_bitmap, bound = 0;
+
+	u8 final_candidate[2] = {0xFF, 0xFF}; /* for path A and path B */
+	bool bresult = true; /* is2t = true*/
+	s32 tmp1 = 0, tmp2 = 0;
+
+	bound = 8;
 
 	simularity_bitmap = 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 ((i == 1) || (i == 3) || (i == 5) || (i == 7)) {
+			if ((result[c1][i] & 0x00000200) != 0)
+				tmp1 = result[c1][i] | 0xFFFFFC00;
+			else
+				tmp1 = result[c1][i];
+
+			if ((result[c2][i] & 0x00000200) != 0)
+				tmp2 = result[c2][i] | 0xFFFFFC00;
+			else
+				tmp2 = result[c2][i];
+		} else {
+			tmp1 = result[c1][i];
+			tmp2 = result[c2][i];
+		}
+
+		diff = (tmp1 > tmp2) ? (tmp1 - tmp2) : (tmp2 - tmp1);
 
 		if (diff > MAX_TOLERANCE) {
 			if ((i == 2 || i == 6) && !simularity_bitmap) {
@@ -1521,9 +2062,8 @@
 					final_candidate[(i / 4)] = c1;
 				else
 					simularity_bitmap |= (1 << i);
-			} else {
+			} else
 				simularity_bitmap |= (1 << i);
-			}
 		}
 	}
 
@@ -1537,15 +2077,23 @@
 			}
 		}
 		return bresult;
-	} else if (!(simularity_bitmap & 0x0F)) {
-		for (i = 0; i < 4; i++)
-			result[3][i] = result[c1][i];
-		return false;
-	} else if (!(simularity_bitmap & 0xF0) && is2t) {
-		for (i = 4; i < 8; i++)
-			result[3][i] = result[c1][i];
-		return false;
 	} else {
+		if (!(simularity_bitmap & 0x03)) { /* path A TX OK */
+			for (i = 0; i < 2; i++)
+				result[3][i] = result[c1][i];
+		}
+		if (!(simularity_bitmap & 0x0c)) { /* path A RX OK */
+			for (i = 2; i < 4; i++)
+				result[3][i] = result[c1][i];
+		}
+		if (!(simularity_bitmap & 0x30)) { /* path B TX OK */
+			for (i = 4; i < 6; i++)
+				result[3][i] = result[c1][i];
+		}
+		if (!(simularity_bitmap & 0xc0)) { /* path B RX OK */
+			for (i = 6; i < 8; i++)
+				result[3][i] = result[c1][i];
+		}
 		return false;
 	}
 }
@@ -1554,9 +2102,9 @@
 					long result[][8], u8 t, bool is2t)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	u32 i;
-	u8 patha_ok;
+	u8 patha_ok, pathb_ok;
 	u32 adda_reg[IQK_ADDA_REG_NUM] = {
 		0x85c, 0xe6c, 0xe70, 0xe74,
 		0xe78, 0xe7c, 0xe80, 0xe84,
@@ -1571,10 +2119,12 @@
 		ROFDM0_TRXPATHENABLE, ROFDM0_TRMUXPAR,
 		RFPGA0_XCD_RFINTERFACESW, 0xb68, 0xb6c,
 		0x870, 0x860,
-		0x864, 0x800
+		0x864, 0xa04
 	};
 	const u32 retrycount = 2;
-	u32 path_sel_bb, path_sel_rf;
+
+	u32 path_sel_bb;/* path_sel_rf */
+
 	u8 tmp_reg_c50, tmp_reg_c58;
 
 	tmp_reg_c50 = rtl_get_bbreg(hw, 0xc50, MASKBYTE0);
@@ -1591,62 +2141,97 @@
 	}
 	rtl8723_phy_path_adda_on(hw, adda_reg, true, is2t);
 	if (t == 0) {
-		rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw,
+		rtlphy->rfpi_enable = (u8)rtl_get_bbreg(hw,
 						RFPGA0_XA_HSSIPARAMETER1,
 						BIT(8));
 	}
-	if (!rtlphy->rfpi_enable)
-		rtl8723_phy_pi_mode_switch(hw, true);
 
 	path_sel_bb = rtl_get_bbreg(hw, 0x948, MASKDWORD);
-	path_sel_rf = rtl_get_rfreg(hw, RF90_PATH_A, 0xb0, 0xfffff);
 
+	rtl8723_phy_mac_setting_calibration(hw, iqk_mac_reg,
+					    rtlphy->iqk_mac_backup);
 	/*BB Setting*/
-	rtl_set_bbreg(hw, 0x800, BIT(24), 0x00);
+	rtl_set_bbreg(hw, 0xa04, 0x0f000000, 0xf);
 	rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600);
 	rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4);
 	rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000);
 
-	rtl_set_bbreg(hw, 0x870, BIT(10), 0x01);
-	rtl_set_bbreg(hw, 0x870, BIT(26), 0x01);
-	rtl_set_bbreg(hw, 0x860, BIT(10), 0x00);
-	rtl_set_bbreg(hw, 0x864, BIT(10), 0x00);
-
-	if (is2t)
-		rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASKDWORD, 0x10000);
-	rtl8723_phy_mac_setting_calibration(hw, iqk_mac_reg,
-					    rtlphy->iqk_mac_backup);
-	rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000);
-
-	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
-	rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00);
-	rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x81004800);
+	/* path A TX IQK */
 	for (i = 0; i < retrycount; i++) {
-		patha_ok = _rtl8723be_phy_path_a_iqk(hw, is2t);
+		patha_ok = _rtl8723be_phy_path_a_iqk(hw);
 		if (patha_ok == 0x01) {
 			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-				 "Path A Tx IQK Success!!\n");
+				"Path A Tx IQK Success!!\n");
 			result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
 					0x3FF0000) >> 16;
 			result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
 					0x3FF0000) >> 16;
 			break;
+		} else {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "Path A Tx IQK Fail!!\n");
+		}
+	}
+	/* path A RX IQK */
+	for (i = 0; i < retrycount; i++) {
+		patha_ok = _rtl8723be_phy_path_a_rx_iqk(hw);
+		if (patha_ok == 0x03) {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "Path A Rx IQK Success!!\n");
+			result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) &
+					0x3FF0000) >> 16;
+			result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) &
+					0x3FF0000) >> 16;
+			break;
+		}
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Path A Rx IQK Fail!!\n");
+	}
+
+	if (0x00 == patha_ok)
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Path A IQK Fail!!\n");
+
+	if (is2t) {
+		/* path B TX IQK */
+		for (i = 0; i < retrycount; i++) {
+			pathb_ok = _rtl8723be_phy_path_b_iqk(hw);
+			if (pathb_ok == 0x01) {
+				RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+					 "Path B Tx IQK Success!!\n");
+				result[t][4] = (rtl_get_bbreg(hw, 0xe94,
+							      MASKDWORD) &
+							      0x3FF0000) >> 16;
+				result[t][5] = (rtl_get_bbreg(hw, 0xe9c,
+							      MASKDWORD) &
+							      0x3FF0000) >> 16;
+				break;
+			}
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "Path B Tx IQK Fail!!\n");
+		}
+		/* path B RX IQK */
+		for (i = 0; i < retrycount; i++) {
+			pathb_ok = _rtl8723be_phy_path_b_rx_iqk(hw);
+			if (pathb_ok == 0x03) {
+				RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+					 "Path B Rx IQK Success!!\n");
+				result[t][6] = (rtl_get_bbreg(hw, 0xea4,
+							      MASKDWORD) &
+							      0x3FF0000) >> 16;
+				result[t][7] = (rtl_get_bbreg(hw, 0xeac,
+							      MASKDWORD) &
+							      0x3FF0000) >> 16;
+				break;
+			}
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "Path B Rx IQK Fail!!\n");
 		}
 	}
 
-	if (0 == patha_ok)
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-			 "Path A IQK Success!!\n");
-	if (is2t) {
-		rtl8723_phy_path_a_standby(hw);
-		rtl8723_phy_path_adda_on(hw, adda_reg, false, is2t);
-	}
-
-	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
+	/* Back to BB mode, load original value */
+	rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0);
 
 	if (t != 0) {
-		if (!rtlphy->rfpi_enable)
-			rtl8723_phy_pi_mode_switch(hw, false);
 		rtl8723_phy_reload_adda_registers(hw, adda_reg,
 						  rtlphy->adda_backup, 16);
 		rtl8723_phy_reload_mac_registers(hw, iqk_mac_reg,
@@ -1656,7 +2241,7 @@
 						  IQK_BB_REG_NUM);
 
 		rtl_set_bbreg(hw, 0x948, MASKDWORD, path_sel_bb);
-		rtl_set_rfreg(hw, RF90_PATH_B, 0xb0, 0xfffff, path_sel_rf);
+		/*rtl_set_rfreg(hw, RF90_PATH_B, 0xb0, 0xfffff, path_sel_rf);*/
 
 		rtl_set_bbreg(hw, 0xc50, MASKBYTE0, 0x50);
 		rtl_set_bbreg(hw, 0xc50, MASKBYTE0, tmp_reg_c50);
@@ -1670,11 +2255,33 @@
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "8723be IQK Finish!!\n");
 }
 
+static u8 _get_right_chnl_place_for_iqk(u8 chnl)
+{
+	u8 channel_all[TARGET_CHNL_NUM_2G_5G] = {
+			1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+			13, 14, 36, 38, 40, 42, 44, 46,
+			48, 50, 52, 54, 56, 58, 60, 62, 64,
+			100, 102, 104, 106, 108, 110,
+			112, 114, 116, 118, 120, 122,
+			124, 126, 128, 130, 132, 134, 136,
+			138, 140, 149, 151, 153, 155, 157,
+			159, 161, 163, 165};
+	u8 place = chnl;
+
+	if (chnl > 14) {
+		for (place = 14; place < sizeof(channel_all); place++) {
+			if (channel_all[place] == chnl)
+				return place - 13;
+		}
+	}
+	return 0;
+}
+
 static void _rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
 {
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 tmpreg;
 	u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	tmpreg = rtl_read_byte(rtlpriv, 0xd03);
 
@@ -1702,7 +2309,10 @@
 	rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, RFREG_OFFSET_MASK, 0xdfbe0);
 	rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, 0x8c0a);
 
-	mdelay(100);
+	/* In order not to disturb BT music when wifi init.(1ant NIC only) */
+	/*mdelay(100);*/
+	/* In order not to disturb BT music when wifi init.(1ant NIC only) */
+	mdelay(50);
 
 	rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, RFREG_OFFSET_MASK, 0xdffe0);
 
@@ -1716,68 +2326,34 @@
 	} else {
 		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
 	}
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+
 }
 
 static void _rtl8723be_phy_set_rfpath_switch(struct ieee80211_hw *hw,
 					     bool bmain, bool is2t)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
 
-	if (is_hal_stop(rtlhal)) {
-		u8 u1btmp;
-		u1btmp = rtl_read_byte(rtlpriv, REG_LEDCFG0);
-		rtl_write_byte(rtlpriv, REG_LEDCFG0, u1btmp | BIT(7));
-		rtl_set_bbreg(hw, RFPGA0_XAB_RFPARAMETER, BIT(13), 0x01);
-	}
-	if (is2t) {
-		if (bmain)
-			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
-				      BIT(5) | BIT(6), 0x1);
-		else
-			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
-				      BIT(5) | BIT(6), 0x2);
-	} else {
-		rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(8) | BIT(9), 0);
-		rtl_set_bbreg(hw, 0x914, MASKLWORD, 0x0201);
-
-		/* We use the RF definition of MAIN and AUX,
-		 * left antenna and right antenna repectively.
-		 * Default output at AUX.
-		 */
-		if (bmain) {
-			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE,
-				      BIT(14) | BIT(13) | BIT(12), 0);
-			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
-				      BIT(5) | BIT(4) | BIT(3), 0);
-			if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
-				rtl_set_bbreg(hw, CONFIG_RAM64X16, BIT(31), 0);
-		} else {
-			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE,
-				      BIT(14) | BIT(13) | BIT(12), 1);
-			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
-				      BIT(5) | BIT(4) | BIT(3), 1);
-			if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
-				rtl_set_bbreg(hw, CONFIG_RAM64X16, BIT(31), 1);
-		}
-	}
+	if (bmain) /* left antenna */
+		rtl_set_bbreg(hw, 0x92C, MASKDWORD, 0x1);
+	else
+		rtl_set_bbreg(hw, 0x92C, MASKDWORD, 0x2);
 }
 
 #undef IQK_ADDA_REG_NUM
 #undef IQK_DELAY_TIME
-
-void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
+/* IQK is merge from Merge Temp */
+void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
 	long result[4][8];
-	u8 i, final_candidate;
-	bool patha_ok, pathb_ok;
-	long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4,
-	    reg_ecc, reg_tmp = 0;
+	u8 i, final_candidate, idx;
+	bool b_patha_ok, b_pathb_ok;
+	long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4;
+	long reg_ecc, reg_tmp = 0;
 	bool is12simular, is13simular, is23simular;
 	u32 iqk_bb_reg[9] = {
 		ROFDM0_XARXIQIMBALANCE,
@@ -1790,12 +2366,23 @@
 		ROFDM0_XDTXAFE,
 		ROFDM0_RXIQEXTANTA
 	};
+	u32 path_sel_bb = 0; /* path_sel_rf = 0 */
 
-	if (recovery) {
+	if (rtlphy->lck_inprogress)
+		return;
+
+	spin_lock(&rtlpriv->locks.iqk_lock);
+	rtlphy->lck_inprogress = true;
+	spin_unlock(&rtlpriv->locks.iqk_lock);
+
+	if (b_recovery) {
 		rtl8723_phy_reload_adda_registers(hw, iqk_bb_reg,
 						  rtlphy->iqk_bb_backup, 9);
 		return;
 	}
+	/* Save RF Path */
+	path_sel_bb = rtl_get_bbreg(hw, 0x948, MASKDWORD);
+	/* path_sel_rf = rtl_get_rfreg(hw, RF90_PATH_A, 0xb0, 0xfffff); */
 
 	for (i = 0; i < 8; i++) {
 		result[0][i] = 0;
@@ -1804,30 +2391,33 @@
 		result[3][i] = 0;
 	}
 	final_candidate = 0xff;
-	patha_ok = false;
-	pathb_ok = false;
+	b_patha_ok = false;
+	b_pathb_ok = false;
 	is12simular = false;
 	is23simular = false;
 	is13simular = false;
 	for (i = 0; i < 3; i++) {
-		if (get_rf_type(rtlphy) == RF_2T2R)
-			_rtl8723be_phy_iq_calibrate(hw, result, i, true);
-		else
-			_rtl8723be_phy_iq_calibrate(hw, result, i, false);
+		_rtl8723be_phy_iq_calibrate(hw, result, i, true);
 		if (i == 1) {
-			is12simular = phy_similarity_cmp(hw, result, 0, 1);
+			is12simular = _rtl8723be_phy_simularity_compare(hw,
+									result,
+									0, 1);
 			if (is12simular) {
 				final_candidate = 0;
 				break;
 			}
 		}
 		if (i == 2) {
-			is13simular = phy_similarity_cmp(hw, result, 0, 2);
+			is13simular = _rtl8723be_phy_simularity_compare(hw,
+									result,
+									0, 2);
 			if (is13simular) {
 				final_candidate = 0;
 				break;
 			}
-			is23simular = phy_similarity_cmp(hw, result, 1, 2);
+			is23simular = _rtl8723be_phy_simularity_compare(hw,
+									result,
+									1, 2);
 			if (is23simular) {
 				final_candidate = 1;
 			} else {
@@ -1864,32 +2454,48 @@
 		rtlphy->reg_ebc = reg_ebc;
 		reg_ec4 = result[final_candidate][6];
 		reg_ecc = result[final_candidate][7];
-		patha_ok = true;
-		pathb_ok = true;
+		b_patha_ok = true;
+		b_pathb_ok = true;
 	} else {
 		rtlphy->reg_e94 = 0x100;
 		rtlphy->reg_eb4 = 0x100;
 		rtlphy->reg_e9c = 0x0;
 		rtlphy->reg_ebc = 0x0;
 	}
-	if (reg_e94 != 0) /*&&(reg_ea4 != 0) */
-		rtl8723_phy_path_a_fill_iqk_matrix(hw, patha_ok, result,
+	if (reg_e94 != 0)
+		rtl8723_phy_path_a_fill_iqk_matrix(hw, b_patha_ok, result,
 						   final_candidate,
 						   (reg_ea4 == 0));
-	if (final_candidate != 0xFF) {
+	if (reg_eb4 != 0)
+		_rtl8723be_phy_path_b_fill_iqk_matrix(hw, b_pathb_ok, result,
+						      final_candidate,
+						      (reg_ec4 == 0));
+
+	idx = _get_right_chnl_place_for_iqk(rtlphy->current_channel);
+
+	if (final_candidate < 4) {
 		for (i = 0; i < IQK_MATRIX_REG_NUM; i++)
-			rtlphy->iqk_matrix[0].value[0][i] =
+			rtlphy->iqk_matrix[idx].value[0][i] =
 						result[final_candidate][i];
-		rtlphy->iqk_matrix[0].iqk_done = true;
+		rtlphy->iqk_matrix[idx].iqk_done = true;
+
 	}
-	rtl8723_save_adda_registers(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 9);
+	rtl8723_save_adda_registers(hw, iqk_bb_reg,
+				    rtlphy->iqk_bb_backup, 9);
+
+	rtl_set_bbreg(hw, 0x948, MASKDWORD, path_sel_bb);
+	/* rtl_set_rfreg(hw, RF90_PATH_A, 0xb0, 0xfffff, path_sel_rf); */
+
+	spin_lock(&rtlpriv->locks.iqk_lock);
+	rtlphy->lck_inprogress = false;
+	spin_unlock(&rtlpriv->locks.iqk_lock);
 }
 
 void rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct rtl_hal *rtlhal = &(rtlpriv->rtlhal);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = &rtlpriv->rtlhal;
 	u32 timeout = 2000, timecount = 0;
 
 	while (rtlpriv->mac80211.act_scanning && timecount < timeout) {
@@ -1898,68 +2504,25 @@
 	}
 
 	rtlphy->lck_inprogress = true;
-	RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+	RTPRINT(rtlpriv, FINIT, INIT_IQK,
 		"LCK:Start!!! currentband %x delay %d ms\n",
-		rtlhal->current_bandtype, timecount);
+		 rtlhal->current_bandtype, timecount);
 
 	_rtl8723be_phy_lc_calibrate(hw, false);
 
 	rtlphy->lck_inprogress = false;
 }
 
-void rtl23b_phy_ap_calibrate(struct ieee80211_hw *hw, char delta)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-
-	if (rtlphy->apk_done)
-		return;
-
-	return;
-}
-
 void rtl8723be_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
 {
-	_rtl8723be_phy_set_rfpath_switch(hw, bmain, false);
-}
-
-static void rtl8723be_phy_set_io(struct ieee80211_hw *hw)
-{
-	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-
-	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
-		 "--->Cmd(%#x), set_io_inprogress(%d)\n",
-		  rtlphy->current_io_type, rtlphy->set_io_inprogress);
-	switch (rtlphy->current_io_type) {
-	case IO_CMD_RESUME_DM_BY_SCAN:
-		rtlpriv->dm_digtable.cur_igvalue =
-				 rtlphy->initgain_backup.xaagccore1;
-		/*rtl92c_dm_write_dig(hw);*/
-		rtl8723be_phy_set_txpower_level(hw, rtlphy->current_channel);
-		rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x83);
-		break;
-	case IO_CMD_PAUSE_DM_BY_SCAN:
-		rtlphy->initgain_backup.xaagccore1 =
-				 rtlpriv->dm_digtable.cur_igvalue;
-		rtlpriv->dm_digtable.cur_igvalue = 0x17;
-		rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x40);
-		break;
-	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case not process\n");
-		break;
-	}
-	rtlphy->set_io_inprogress = false;
-	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
-		 "(%#x)\n", rtlphy->current_io_type);
+	_rtl8723be_phy_set_rfpath_switch(hw, bmain, true);
 }
 
 bool rtl8723be_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	bool postprocessing = false;
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	bool b_postprocessing = false;
 
 	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
 		 "-->IO Cmd(%#x), set_io_inprogress(%d)\n",
@@ -1969,20 +2532,20 @@
 		case IO_CMD_RESUME_DM_BY_SCAN:
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
 				 "[IO CMD] Resume DM after scan.\n");
-			postprocessing = true;
+			b_postprocessing = true;
 			break;
-		case IO_CMD_PAUSE_DM_BY_SCAN:
+		case IO_CMD_PAUSE_BAND0_DM_BY_SCAN:
 			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
 				 "[IO CMD] Pause DM before scan.\n");
-			postprocessing = true;
+			b_postprocessing = true;
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 				 "switch case not process\n");
 			break;
 		}
 	} while (false);
-	if (postprocessing && !rtlphy->set_io_inprogress) {
+	if (b_postprocessing && !rtlphy->set_io_inprogress) {
 		rtlphy->set_io_inprogress = true;
 		rtlphy->current_io_type = iotype;
 	} else {
@@ -1993,6 +2556,37 @@
 	return true;
 }
 
+static void rtl8723be_phy_set_io(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+		 "--->Cmd(%#x), set_io_inprogress(%d)\n",
+		  rtlphy->current_io_type, rtlphy->set_io_inprogress);
+	switch (rtlphy->current_io_type) {
+	case IO_CMD_RESUME_DM_BY_SCAN:
+		dm_digtable->cur_igvalue = rtlphy->initgain_backup.xaagccore1;
+		/*rtl92c_dm_write_dig(hw);*/
+		rtl8723be_phy_set_txpower_level(hw, rtlphy->current_channel);
+		rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x83);
+		break;
+	case IO_CMD_PAUSE_BAND0_DM_BY_SCAN:
+		rtlphy->initgain_backup.xaagccore1 = dm_digtable->cur_igvalue;
+		dm_digtable->cur_igvalue = 0x17;
+		rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x40);
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
+		break;
+	}
+	rtlphy->set_io_inprogress = false;
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+		 "(%#x)\n", rtlphy->current_io_type);
+}
+
 static void rtl8723be_phy_set_rf_on(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -2028,15 +2622,15 @@
 	switch (rfpwr_state) {
 	case ERFON:
 		if ((ppsc->rfpwr_state == ERFOFF) &&
-		    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+		     RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
 			bool rtstatus;
-			u32 initialize_count = 0;
+			u32 initializecount = 0;
 			do {
-				initialize_count++;
+				initializecount++;
 				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
 					 "IPS Set eRf nic enable\n");
 				rtstatus = rtl_ps_enable_nic(hw);
-			} while (!rtstatus && (initialize_count < 10));
+			} while (!rtstatus && (initializecount < 10));
 				RT_CLEAR_PS_LEVEL(ppsc,
 						  RT_RF_OFF_LEVL_HALT_NIC);
 		} else {
@@ -2051,28 +2645,33 @@
 			rtlpriv->cfg->ops->led_control(hw, LED_CTL_LINK);
 		else
 			rtlpriv->cfg->ops->led_control(hw, LED_CTL_NO_LINK);
+
 		break;
+
 	case ERFOFF:
 		for (queue_id = 0, i = 0;
 		     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
 			ring = &pcipriv->dev.tx_ring[queue_id];
-			if (skb_queue_len(&ring->queue) == 0) {
+			/* Don't check BEACON Q.
+			 * BEACON Q is always not empty,
+			 * because '_rtl8723be_cmd_send_packet'
+			 */
+			if (queue_id == BEACON_QUEUE ||
+			    skb_queue_len(&ring->queue) == 0) {
 				queue_id++;
 				continue;
 			} else {
 				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-					 "eRf Off/Sleep: %d times "
-					  "TcbBusyQueue[%d] =%d before "
-					  "doze!\n", (i + 1), queue_id,
-					  skb_queue_len(&ring->queue));
+					 "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n",
+					 (i + 1), queue_id,
+					 skb_queue_len(&ring->queue));
 
 				udelay(10);
 				i++;
 			}
 			if (i >= MAX_DOZE_WAITING_TIMES_9x) {
 				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-					 "\n ERFSLEEP: %d times "
-					  "TcbBusyQueue[%d] = %d !\n",
+					 "ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
 					  MAX_DOZE_WAITING_TIMES_9x,
 					  queue_id,
 					  skb_queue_len(&ring->queue));
@@ -2095,6 +2694,7 @@
 			}
 		}
 		break;
+
 	case ERFSLEEP:
 		if (ppsc->rfpwr_state == ERFOFF)
 			break;
@@ -2106,21 +2706,19 @@
 				continue;
 			} else {
 				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-					 "eRf Off/Sleep: %d times "
-					  "TcbBusyQueue[%d] =%d before "
-					  "doze!\n", (i + 1), queue_id,
-					  skb_queue_len(&ring->queue));
+					 "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n",
+					 (i + 1), queue_id,
+					 skb_queue_len(&ring->queue));
 
 				udelay(10);
 				i++;
 			}
 			if (i >= MAX_DOZE_WAITING_TIMES_9x) {
 				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-					 "\n ERFSLEEP: %d times "
-					  "TcbBusyQueue[%d] = %d !\n",
-					  MAX_DOZE_WAITING_TIMES_9x,
-					  queue_id,
-					  skb_queue_len(&ring->queue));
+					 "ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
+					 MAX_DOZE_WAITING_TIMES_9x,
+					 queue_id,
+					 skb_queue_len(&ring->queue));
 				break;
 			}
 		}
@@ -2131,8 +2729,9 @@
 		ppsc->last_sleep_jiffies = jiffies;
 		_rtl8723be_phy_set_rf_sleep(hw);
 		break;
+
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
 			 "switch case not process\n");
 		bresult = false;
 		break;
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.h b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h
index 444ef95..6339738 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/phy.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h
@@ -26,22 +26,28 @@
 #ifndef __RTL8723BE_PHY_H__
 #define __RTL8723BE_PHY_H__
 
-/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/
+/* MAX_TX_COUNT must always set to 4, otherwise read efuse table sequence
+ * will be wrong.
+ */
 #define MAX_TX_COUNT		4
 #define	TX_1S			0
 #define	TX_2S			1
+#define	TX_3S			2
+#define	TX_4S			3
 
 #define	MAX_POWER_INDEX		0x3F
 
 #define MAX_PRECMD_CNT			16
 #define MAX_RFDEPENDCMD_CNT		16
-#define MAX_POSTCMD_CNT		16
+#define MAX_POSTCMD_CNT			16
 
 #define MAX_DOZE_WAITING_TIMES_9x	64
 
 #define RT_CANNOT_IO(hw)		false
 #define HIGHPOWER_RADIOA_ARRAYLEN	22
 
+#define TARGET_CHNL_NUM_2G_5G		59
+
 #define IQK_ADDA_REG_NUM		16
 #define IQK_BB_REG_NUM			9
 #define MAX_TOLERANCE			5
@@ -83,104 +89,19 @@
 
 #define RTL92C_MAX_PATH_NUM			2
 
-enum hw90_block_e {
-	HW90_BLOCK_MAC = 0,
-	HW90_BLOCK_PHY0 = 1,
-	HW90_BLOCK_PHY1 = 2,
-	HW90_BLOCK_RF = 3,
-	HW90_BLOCK_MAXIMUM = 4,
-};
-
 enum baseband_config_type {
 	BASEBAND_CONFIG_PHY_REG = 0,
 	BASEBAND_CONFIG_AGC_TAB = 1,
 };
 
-enum ra_offset_area {
-	RA_OFFSET_LEGACY_OFDM1,
-	RA_OFFSET_LEGACY_OFDM2,
-	RA_OFFSET_HT_OFDM1,
-	RA_OFFSET_HT_OFDM2,
-	RA_OFFSET_HT_OFDM3,
-	RA_OFFSET_HT_OFDM4,
-	RA_OFFSET_HT_CCK,
-};
-
-enum antenna_path {
-	ANTENNA_NONE,
-	ANTENNA_D,
-	ANTENNA_C,
-	ANTENNA_CD,
-	ANTENNA_B,
-	ANTENNA_BD,
-	ANTENNA_BC,
-	ANTENNA_BCD,
-	ANTENNA_A,
-	ANTENNA_AD,
-	ANTENNA_AC,
-	ANTENNA_ACD,
-	ANTENNA_AB,
-	ANTENNA_ABD,
-	ANTENNA_ABC,
-	ANTENNA_ABCD
-};
-
-struct r_antenna_select_ofdm {
-	u32 r_tx_antenna:4;
-	u32 r_ant_l:4;
-	u32 r_ant_non_ht:4;
-	u32 r_ant_ht1:4;
-	u32 r_ant_ht2:4;
-	u32 r_ant_ht_s1:4;
-	u32 r_ant_non_ht_s1:4;
-	u32 ofdm_txsc:2;
-	u32 reserved:2;
-};
-
-struct r_antenna_select_cck {
-	u8 r_cckrx_enable_2:2;
-	u8 r_cckrx_enable:2;
-	u8 r_ccktx_enable:4;
-};
-
-
-struct efuse_contents {
-	u8 mac_addr[ETH_ALEN];
-	u8 cck_tx_power_idx[6];
-	u8 ht40_1s_tx_power_idx[6];
-	u8 ht40_2s_tx_power_idx_diff[3];
-	u8 ht20_tx_power_idx_diff[3];
-	u8 ofdm_tx_power_idx_diff[3];
-	u8 ht40_max_power_offset[3];
-	u8 ht20_max_power_offset[3];
-	u8 channel_plan;
-	u8 thermal_meter;
-	u8 rf_option[5];
-	u8 version;
-	u8 oem_id;
-	u8 regulatory;
-};
-
-struct tx_power_struct {
-	u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 legacy_ht_txpowerdiff;
-	u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
-	u8 pwrgroup_cnt;
-	u32 mcs_original_offset[4][16];
-};
-
-enum _ANT_DIV_TYPE {
-	NO_ANTDIV				= 0xFF,
-	CG_TRX_HW_ANTDIV		= 0x01,
-	CGCS_RX_HW_ANTDIV		= 0x02,
+enum ant_div_type {
+	NO_ANTDIV		= 0xFF,
+	CG_TRX_HW_ANTDIV	= 0x01,
+	CGCS_RX_HW_ANTDIV	= 0x02,
 	FIXED_HW_ANTDIV         = 0x03,
-	CG_TRX_SMART_ANTDIV		= 0x04,
-	CGCS_RX_SW_ANTDIV		= 0x05,
+	CG_TRX_SMART_ANTDIV	= 0x04,
+	CGCS_RX_SW_ANTDIV	= 0x05,
+
 };
 
 u32 rtl8723be_phy_query_rf_reg(struct ieee80211_hw *hw,
@@ -206,7 +127,6 @@
 u8 rtl8723be_phy_sw_chnl(struct ieee80211_hw *hw);
 void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw,
 				bool b_recovery);
-void rtl23b_phy_ap_calibrate(struct ieee80211_hw *hw, char delta);
 void rtl8723be_phy_lc_calibrate(struct ieee80211_hw *hw);
 void rtl8723be_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
 bool rtl8723be_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c
index b5167e7..a1bb1f6 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.c
@@ -23,7 +23,7 @@
  *
  *****************************************************************************/
 
-#include "pwrseqcmd.h"
+#include "../pwrseqcmd.h"
 #include "pwrseq.h"
 
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h
index a62f43e..0fee5e0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseq.h
@@ -26,7 +26,9 @@
 #ifndef __RTL8723BE_PWRSEQ_H__
 #define __RTL8723BE_PWRSEQ_H__
 
-/*	Check document WM-20130425-JackieLau-RTL8723B_Power_Architecture v05.vsd
+#include "../pwrseqcmd.h"
+/**
+ *	Check document WM-20130425-JackieLau-RTL8723B_Power_Architecture v05.vsd
  *	There are 6 HW Power States:
  *	0: POFF--Power Off
  *	1: PDN--Power Down
@@ -35,7 +37,7 @@
  *	4: LPS--Low Power State
  *	5: SUS--Suspend
  *
- *	The transition from different states are defined below
+ *	The transision from different states are defined below
  *	TRANS_CARDEMU_TO_ACT
  *	TRANS_ACT_TO_CARDEMU
  *	TRANS_CARDEMU_TO_SUS
@@ -57,203 +59,320 @@
 #define	RTL8723B_TRANS_END_STEPS		1
 
 #define RTL8723B_TRANS_CARDEMU_TO_ACT					\
+	/* format */							\
+	/* comments here */						\
+	/* {offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value}, */\
+	/*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/  \
 	{0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	 PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK,				\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	/*0x67[0] = 0 to disable BT_GPS_SEL pins*/			\
 	{0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	 PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK,				\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},			\
+	/*Delay 1ms*/							\
 	{0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	 PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK,				\
 	 PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},		\
+	/*0x00[5] = 1b'0 release analog Ips to digital ,1:isolation*/   \
 	{0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	 PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK,				\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), 0},			\
+	/* disable SW LPS 0x04[10]=0 and WLSUS_EN 0x04[11]=0*/		\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT(4)|BIT(3)|BIT(2)), 0},	\
-	{0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
-	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0) , 0},			\
-	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	 PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)},		\
+	/* Disable USB suspend */					\
 	{0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0) , BIT(0)},		\
+	/* wait till 0x04[17] = 1    power ready*/			\
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
+	 PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)},		\
+	/* Enable USB suspend */					\
+	{0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
+	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0) , 0},			\
+	/* release WLON reset  0x04[16]=1*/				\
 	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	/* disable HWPDN 0x04[15]=0*/					\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},			\
+	/* disable WL suspend*/						\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT(4)|BIT(3)), 0},		\
+	/* polling until return 0*/					\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},		\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0},			\
+	/* Enable WL control XTAL setting*/				\
 	{0x0010, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6), BIT(6)},		\
+	/*Enable falling edge triggering interrupt*/			\
 	{0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},		\
+	/*Enable GPIO9 interrupt mode*/					\
 	{0x0063, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},		\
+	/*Enable GPIO9 input mode*/					\
 	{0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},			\
+	/*Enable HSISR GPIO[C:0] interrupt*/				\
 	{0x0058, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	/*Enable HSISR GPIO9 interrupt*/				\
 	{0x005A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},		\
+	/*For GPIO9 internal pull high setting by test chip*/		\
 	{0x0068, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3), BIT(3)},		\
+	/*For GPIO9 internal pull high setting*/			\
 	{0x0069, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6), BIT(6)},
 
 #define RTL8723B_TRANS_ACT_TO_CARDEMU					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+	/*0x1F[7:0] = 0 turn off RF*/					\
 	{0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},			\
+	/*0x4C[24] = 0x4F[0] = 0, */					\
+	/*switch DPDT_SEL_P output from register 0x65[2] */		\
 	{0x004F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},			\
+	/*Enable rising edge triggering interrupt*/			\
 	{0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},			\
+	 /*0x04[9] = 1 turn off MAC by HW state machine*/		\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},		\
+	 /*wait till 0x04[9] = 0 polling until return 0 to disable*/	\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0},			\
+	/* Enable BT control XTAL setting*/				\
 	{0x0010, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6), 0},			\
+	/*0x00[5] = 1b'1 analog Ips to digital ,1:isolation*/		\
 	{0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	 PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC,	\
 	 PWR_CMD_WRITE, BIT(5), BIT(5)},				\
+	/*0x20[0] = 1b'0 disable LDOA12 MACRO block*/			\
 	{0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	 PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC,	\
 	 PWR_CMD_WRITE, BIT(0), 0},
 
 #define RTL8723B_TRANS_CARDEMU_TO_SUS					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+	/*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/		\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4) | BIT(3), (BIT(4) | BIT(3))}, \
+	/*0x04[12:11] = 2b'01 enable WL suspend*/			\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	 PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC,	\
 	 PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)},			\
+	/*0x23[4] = 1b'1 12H LDO enter sleep mode*/			\
 	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)},		\
+	/*0x07[7:0] = 0x20 SDIO SOP option to disable BG/MB/ACK/SWR*/   \
 	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20},			\
+	/*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/		\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3) | BIT(4)},\
+	/*Set SDIO suspend local register*/				\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	/*wait power state to suspend*/					\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0},
 
 #define RTL8723B_TRANS_SUS_TO_CARDEMU					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+	/*clear suspend enable and power down enable*/			\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(7), 0},		\
+	/*Set SDIO suspend local register*/				\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0},			\
+	/*wait power state to suspend*/					\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},		\
+	/*0x23[4] = 1b'0 12H LDO enter normal mode*/			\
 	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},			\
+	/*0x04[12:11] = 2b'01enable WL suspend*/			\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},
 
 #define RTL8723B_TRANS_CARDEMU_TO_CARDDIS				\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+	/*0x07=0x20 , SOP option to disable BG/MB*/			\
 	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20},			\
+	/*0x04[12:11] = 2b'01 enable WL suspend*/			\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	 PWR_INTF_USB_MSK | PWR_INTF_SDIO_MSK,				\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},	\
+	/*0x04[10] = 1, enable SW LPS*/					\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), BIT(2)},		\
+	/*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/			\
 	{0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 1},			\
+	/*0x23[4] = 1b'1 12H LDO enter sleep mode*/			\
 	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)},		\
+	/*Set SDIO suspend local register*/				\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)},		\
+	/*wait power state to suspend*/					\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0},
 
 #define RTL8723B_TRANS_CARDDIS_TO_CARDEMU				\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+	/*clear suspend enable and power down enable*/			\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(7), 0},		\
+	/*Set SDIO suspend local register*/				\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0},			\
+	/*wait power state to suspend*/					\
 	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},		\
+	/*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/			\
 	{0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},			\
+	/*0x04[12:11] = 2b'01enable WL suspend*/			\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},		\
+	/*0x23[4] = 1b'0 12H LDO enter normal mode*/			\
 	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},			\
+	/*PCIe DMA start*/						\
 	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},
 
 #define RTL8723B_TRANS_CARDEMU_TO_PDN					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+	/*0x23[4] = 1b'1 12H LDO enter sleep mode*/			\
 	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)},		\
+	/*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/	\
 	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
 	 PWR_INTF_SDIO_MSK | PWR_INTF_USB_MSK, PWR_BASEADDR_MAC,	\
 	 PWR_CMD_WRITE, 0xFF, 0x20},					\
+	/* 0x04[16] = 0*/						\
 	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},			\
+	/* 0x04[15] = 1*/						\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)},
 
 #define RTL8723B_TRANS_PDN_TO_CARDEMU					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+	/* 0x04[15] = 0*/						\
 	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},
 
 #define RTL8723B_TRANS_ACT_TO_LPS					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+	/*PCIe DMA stop*/						\
 	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},			\
+	/*Tx Pause*/							\
 	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},			\
+	/*Should be zero if no packet is transmitting*/			\
 	{0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},			\
+	/*Should be zero if no packet is transmitting*/			\
 	{0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},			\
+	/*Should be zero if no packet is transmitting*/			\
 	{0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},			\
+	/*Should be zero if no packet is transmitting*/			\
 	{0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},			\
+	/*CCK and OFDM are disabled,and clock are gated*/		\
 	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},			\
+	/*Delay 1us*/							\
 	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},		\
+	/*Whole BB is reset*/						\
 	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},			\
+	/*Reset MAC TRX*/						\
 	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},			\
+	/*check if removed later*/					\
 	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},			\
+	/*When driver enter Sus/ Disable, enable LOP for BT*/		\
 	{0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},			\
+	/*Respond TxOK to scheduler*/					\
 	{0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)},
 
 #define RTL8723B_TRANS_LPS_TO_ACT					\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+	/*SDIO RPWM*/							\
 	{0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,	\
-	 PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84},		\
+	 PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84},			\
+	/*USB RPWM*/							\
 	{0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84},			\
+	/*PCIe RPWM*/							\
 	{0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84},			\
+	/*Delay*/							\
 	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS},		\
+	/*.	0x08[4] = 0		 switch TSF to 40M*/		\
 	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},			\
+	/*Polling 0x109[7]=0  TSF in 40M*/				\
 	{0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
-	 PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0},		\
+	 PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0},			\
+	/*.	0x29[7:6] = 2b'00	 enable BB clock*/		\
 	{0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6)|BIT(7), 0},		\
+	/*.	0x101[1] = 1*/						\
 	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},		\
+	/*.	0x100[7:0] = 0xFF	 enable WMAC TRX*/		\
 	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},			\
+	/*.	0x02[1:0] = 2b'11	 enable BB macro*/		\
 	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1) | BIT(0), BIT(1) | BIT(0)}, \
+	/*.	0x522 = 0*/						\
 	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,	\
 	 PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},
 
 #define RTL8723B_TRANS_END						\
+	/* format */							\
+	/* comments here */						\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
 	{0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0,	\
 	 PWR_CMD_END, 0, 0},
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c
deleted file mode 100644
index 4573310..0000000
--- a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2009-2014  Realtek Corporation.
- *
- * 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.
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * wlanfae <wlanfae@realtek.com>
- * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
- * Hsinchu 300, Taiwan.
- *
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- *****************************************************************************/
-
-#include "pwrseq.h"
-
-/*	Description:
- *		This routine deal with the Power Configuration CMDs
- *		 parsing for RTL8723/RTL8188E Series IC.
- *	Assumption:
- *		We should follow specific format which was released from HW SD.
- *
- *	2011.07.07, added by Roger.
- */
-bool rtlbe_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
-				 u8 fab_version, u8 interface_type,
-				 struct wlan_pwr_cfg pwrcfgcmd[])
-
-{
-	struct wlan_pwr_cfg pwr_cfg_cmd = {0};
-	bool b_polling_bit = false;
-	u32 ary_idx = 0;
-	u8 value = 0;
-	u32 offset = 0;
-	u32 polling_count = 0;
-	u32 max_polling_cnt = 5000;
-
-	do {
-		pwr_cfg_cmd = pwrcfgcmd[ary_idx];
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-			 "rtlbe_hal_pwrseqcmdparsing(): "
-			 "offset(%#x),cut_msk(%#x), fab_msk(%#x),"
-			 "interface_msk(%#x), base(%#x), "
-			 "cmd(%#x), msk(%#x), value(%#x)\n",
-			 GET_PWR_CFG_OFFSET(pwr_cfg_cmd),
-			 GET_PWR_CFG_CUT_MASK(pwr_cfg_cmd),
-			 GET_PWR_CFG_FAB_MASK(pwr_cfg_cmd),
-			 GET_PWR_CFG_INTF_MASK(pwr_cfg_cmd),
-			 GET_PWR_CFG_BASE(pwr_cfg_cmd),
-			 GET_PWR_CFG_CMD(pwr_cfg_cmd),
-			 GET_PWR_CFG_MASK(pwr_cfg_cmd),
-			 GET_PWR_CFG_VALUE(pwr_cfg_cmd));
-
-		if ((GET_PWR_CFG_FAB_MASK(pwr_cfg_cmd)&fab_version) &&
-		    (GET_PWR_CFG_CUT_MASK(pwr_cfg_cmd)&cut_version) &&
-		    (GET_PWR_CFG_INTF_MASK(pwr_cfg_cmd)&interface_type)) {
-			switch (GET_PWR_CFG_CMD(pwr_cfg_cmd)) {
-			case PWR_CMD_READ:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					 "rtlbe_hal_pwrseqcmdparsing(): "
-					  "PWR_CMD_READ\n");
-				break;
-			case PWR_CMD_WRITE:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					 "rtlbe_hal_pwrseqcmdparsing(): "
-					  "PWR_CMD_WRITE\n");
-				offset = GET_PWR_CFG_OFFSET(pwr_cfg_cmd);
-
-				/*Read the value from system register*/
-				value = rtl_read_byte(rtlpriv, offset);
-				value &= (~(GET_PWR_CFG_MASK(pwr_cfg_cmd)));
-				value = value | (GET_PWR_CFG_VALUE(pwr_cfg_cmd)
-					& GET_PWR_CFG_MASK(pwr_cfg_cmd));
-
-				/*Write the value back to sytem register*/
-				rtl_write_byte(rtlpriv, offset, value);
-				break;
-			case PWR_CMD_POLLING:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					 "rtlbe_hal_pwrseqcmdparsing(): "
-					  "PWR_CMD_POLLING\n");
-				b_polling_bit = false;
-				offset = GET_PWR_CFG_OFFSET(pwr_cfg_cmd);
-
-				do {
-					value = rtl_read_byte(rtlpriv, offset);
-
-					value &= GET_PWR_CFG_MASK(pwr_cfg_cmd);
-					if (value ==
-					    (GET_PWR_CFG_VALUE(pwr_cfg_cmd) &
-					     GET_PWR_CFG_MASK(pwr_cfg_cmd)))
-						b_polling_bit = true;
-					else
-						udelay(10);
-
-					if (polling_count++ > max_polling_cnt)
-						return false;
-
-				} while (!b_polling_bit);
-				break;
-			case PWR_CMD_DELAY:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					 "rtlbe_hal_pwrseqcmdparsing(): "
-					 "PWR_CMD_DELAY\n");
-				if (GET_PWR_CFG_VALUE(pwr_cfg_cmd) ==
-				    PWRSEQ_DELAY_US)
-					udelay(GET_PWR_CFG_OFFSET(pwr_cfg_cmd));
-				else
-					mdelay(GET_PWR_CFG_OFFSET(pwr_cfg_cmd));
-				break;
-			case PWR_CMD_END:
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-					 "rtlbe_hal_pwrseqcmdparsing(): "
-					 "PWR_CMD_END\n");
-				return true;
-			default:
-				RT_ASSERT(false,
-					  "rtlbe_hal_pwrseqcmdparsing(): "
-					  "Unknown CMD!!\n");
-				break;
-			}
-		}
-
-		ary_idx++;
-	} while (1);
-
-	return true;
-}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h b/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h
deleted file mode 100644
index ce14a3b..0000000
--- a/drivers/net/wireless/rtlwifi/rtl8723be/pwrseqcmd.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2009-2014  Realtek Corporation.
- *
- * 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.
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * wlanfae <wlanfae@realtek.com>
- * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
- * Hsinchu 300, Taiwan.
- *
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- *****************************************************************************/
-
-#ifndef __RTL8723BE_PWRSEQCMD_H__
-#define __RTL8723BE_PWRSEQCMD_H__
-
-#include "../wifi.h"
-/*---------------------------------------------*/
-/*The value of cmd: 4 bits */
-/*---------------------------------------------*/
-#define PWR_CMD_READ		0x00
-#define PWR_CMD_WRITE		0x01
-#define PWR_CMD_POLLING		0x02
-#define PWR_CMD_DELAY		0x03
-#define PWR_CMD_END		0x04
-
-/* define the base address of each block */
-#define PWR_BASEADDR_MAC	0x00
-#define PWR_BASEADDR_USB	0x01
-#define PWR_BASEADDR_PCIE	0x02
-#define PWR_BASEADDR_SDIO	0x03
-
-#define	PWR_INTF_SDIO_MSK	BIT(0)
-#define	PWR_INTF_USB_MSK	BIT(1)
-#define	PWR_INTF_PCI_MSK	BIT(2)
-#define	PWR_INTF_ALL_MSK	(BIT(0) | BIT(1) | BIT(2) | BIT(3))
-
-#define	PWR_FAB_TSMC_MSK	BIT(0)
-#define	PWR_FAB_UMC_MSK		BIT(1)
-#define	PWR_FAB_ALL_MSK		(BIT(0) | BIT(1) | BIT(2) | BIT(3))
-
-#define	PWR_CUT_TESTCHIP_MSK	BIT(0)
-#define	PWR_CUT_A_MSK		BIT(1)
-#define	PWR_CUT_B_MSK		BIT(2)
-#define	PWR_CUT_C_MSK		BIT(3)
-#define	PWR_CUT_D_MSK		BIT(4)
-#define	PWR_CUT_E_MSK		BIT(5)
-#define	PWR_CUT_F_MSK		BIT(6)
-#define	PWR_CUT_G_MSK		BIT(7)
-#define	PWR_CUT_ALL_MSK		0xFF
-
-
-enum pwrseq_delay_unit {
-	PWRSEQ_DELAY_US,
-	PWRSEQ_DELAY_MS,
-};
-
-struct wlan_pwr_cfg {
-	u16 offset;
-	u8 cut_msk;
-	u8 fab_msk:4;
-	u8 interface_msk:4;
-	u8 base:4;
-	u8 cmd:4;
-	u8 msk;
-	u8 value;
-
-};
-
-#define	GET_PWR_CFG_OFFSET(__PWR_CMD)	__PWR_CMD.offset
-#define	GET_PWR_CFG_CUT_MASK(__PWR_CMD)	__PWR_CMD.cut_msk
-#define	GET_PWR_CFG_FAB_MASK(__PWR_CMD)	__PWR_CMD.fab_msk
-#define	GET_PWR_CFG_INTF_MASK(__PWR_CMD)	__PWR_CMD.interface_msk
-#define	GET_PWR_CFG_BASE(__PWR_CMD)	__PWR_CMD.base
-#define	GET_PWR_CFG_CMD(__PWR_CMD)	__PWR_CMD.cmd
-#define	GET_PWR_CFG_MASK(__PWR_CMD)	__PWR_CMD.msk
-#define	GET_PWR_CFG_VALUE(__PWR_CMD)	__PWR_CMD.value
-
-bool rtlbe_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
-				 u8 fab_version, u8 interface_type,
-				 struct wlan_pwr_cfg pwrcfgcmd[]);
-
-#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/reg.h b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h
index 3006849..03581d2 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/reg.h
@@ -78,11 +78,11 @@
 #define REG_WOL_EVENT				0x0081
 #define REG_MCUTSTCFG				0x0084
 
-
 #define REG_HIMR				0x00B0
 #define REG_HISR				0x00B4
 #define REG_HIMRE				0x00B8
 #define REG_HISRE				0x00BC
+#define REG_PMC_DBG_CTRL2			0x00CC
 
 #define REG_EFUSE_ACCESS			0x00CF
 
@@ -95,7 +95,8 @@
 #define REG_HPON_FSM				0x00EC
 #define REG_SYS_CFG				0x00F0
 #define REG_GPIO_OUTSTS				0x00F4
-#define REG_SYS_CFG1				0x00F0
+#define REG_MAC_PHY_CTRL_NORMAL			0x00F8
+#define REG_SYS_CFG1				0x00FC
 #define REG_ROM_VERSION				0x00FD
 
 #define REG_CR					0x0100
@@ -170,8 +171,14 @@
 #define	REG_BKQ_DESA				0x0338
 #define	REG_RX_DESA				0x0340
 
-#define	REG_DBI					0x0348
-#define	REG_MDIO				0x0354
+#define	REG_DBI_WDATA				0x0348
+#define	REG_DBI_RDATA				0x034C
+#define	REG_DBI_CTRL				0x0350
+#define	REG_DBI_ADDR				0x0350
+#define	REG_DBI_FLAG				0x0352
+#define	REG_MDIO_WDATA				0x0354
+#define	REG_MDIO_RDATA				0x0356
+#define	REG_MDIO_CTL				0x0358
 #define	REG_DBG_SEL				0x0360
 #define	REG_PCIE_HRPWM				0x0361
 #define	REG_PCIE_HCPWM				0x0363
@@ -180,7 +187,6 @@
 #define	REG_UART_TX_DESA			0x0370
 #define	REG_UART_RX_DESA			0x0378
 
-
 #define	REG_HDAQ_DESA_NODEF			0x0000
 #define	REG_CMDQ_DESA_NODEF			0x0000
 
@@ -193,7 +199,6 @@
 #define REG_BCNQ_INFORMATION			0x0418
 #define REG_TXPKT_EMPTY				0x041A
 
-
 #define REG_CPU_MGQ_INFORMATION			0x041C
 #define REG_FWHW_TXQ_CTRL			0x0420
 #define REG_HWSEQ_CTRL				0x0423
@@ -207,9 +212,7 @@
 #define REG_RARFRC				0x0438
 #define REG_RRSR				0x0440
 #define REG_ARFR0				0x0444
-#define REG_ARFR1				0x0448
-#define REG_ARFR2				0x044C
-#define REG_ARFR3				0x0450
+#define REG_ARFR1				0x044C
 #define REG_AMPDU_MAX_TIME			0x0456
 #define REG_AGGLEN_LMT				0x0458
 #define REG_AMPDU_MIN_SPACE			0x045C
@@ -223,7 +226,10 @@
 #define REG_POWER_STAGE2			0x04B8
 #define REG_PKT_LIFE_TIME			0x04C0
 #define REG_STBC_SETTING			0x04C4
+#define REG_HT_SINGLE_AMPDU			0x04C7
+
 #define REG_PROT_MODE_CTRL			0x04C8
+#define REG_MAX_AGGR_NUM			0x04CA
 #define REG_BAR_MODE_CTRL			0x04CC
 #define REG_RA_TRY_RATE_AGG_LMT			0x04CF
 #define REG_EARLY_MODE_CONTROL			0x04D0
@@ -303,6 +309,7 @@
 #define REG_EIFS				0x0642
 
 #define REG_NAV_CTRL				0x0650
+#define	REG_NAV_UPPER				0x0652
 #define REG_BACAMCMD				0x0654
 #define REG_BACAMCONTENT			0x0658
 #define REG_LBDLY				0x0660
@@ -355,43 +362,43 @@
 #define REG_NORMAL_SIE_MAC_ADDR			0xFE70
 #define REG_NORMAL_SIE_STRING			0xFE80
 
-#define	CR9346					REG_9346CR
-#define	MSR					(REG_CR + 2)
-#define	ISR					REG_HISR
-#define	TSFR					REG_TSFTR
+#define	CR9346				REG_9346CR
+#define	MSR				(REG_CR + 2)
+#define	ISR				REG_HISR
+#define	TSFR				REG_TSFTR
 
-#define	MACIDR0					REG_MACID
-#define	MACIDR4					(REG_MACID + 4)
+#define	MACIDR0				REG_MACID
+#define	MACIDR4				(REG_MACID + 4)
 
-#define PBP					REG_PBP
+#define PBP				REG_PBP
 
-#define	IDR0					MACIDR0
-#define	IDR4					MACIDR4
+#define	IDR0				MACIDR0
+#define	IDR4				MACIDR4
 
-#define	UNUSED_REGISTER				0x1BF
-#define	DCAM					UNUSED_REGISTER
-#define	PSR					UNUSED_REGISTER
-#define BBADDR					UNUSED_REGISTER
-#define	PHYDATAR				UNUSED_REGISTER
+#define	UNUSED_REGISTER			0x1BF
+#define	DCAM				UNUSED_REGISTER
+#define	PSR				UNUSED_REGISTER
+#define BBADDR				UNUSED_REGISTER
+#define	PHYDATAR			UNUSED_REGISTER
 
-#define	INVALID_BBRF_VALUE			0x12345678
+#define	INVALID_BBRF_VALUE		0x12345678
 
-#define	MAX_MSS_DENSITY_2T			0x13
-#define	MAX_MSS_DENSITY_1T			0x0A
+#define	MAX_MSS_DENSITY_2T		0x13
+#define	MAX_MSS_DENSITY_1T		0x0A
 
-#define	CMDEEPROM_EN				BIT(5)
-#define	CMDEEPROM_SEL				BIT(4)
-#define	CMD9346CR_9356SEL			BIT(4)
-#define	AUTOLOAD_EEPROM				(CMDEEPROM_EN | CMDEEPROM_SEL)
-#define	AUTOLOAD_EFUSE				CMDEEPROM_EN
+#define	CMDEEPROM_EN			BIT(5)
+#define	CMDEEPROM_SEL			BIT(4)
+#define	CMD9346CR_9356SEL		BIT(4)
+#define	AUTOLOAD_EEPROM			(CMDEEPROM_EN | CMDEEPROM_SEL)
+#define	AUTOLOAD_EFUSE			CMDEEPROM_EN
 
-#define	GPIOSEL_GPIO				0
-#define	GPIOSEL_ENBT				BIT(5)
+#define	GPIOSEL_GPIO			0
+#define	GPIOSEL_ENBT			BIT(5)
 
-#define	GPIO_IN					REG_GPIO_PIN_CTRL
-#define	GPIO_OUT				(REG_GPIO_PIN_CTRL + 1)
-#define	GPIO_IO_SEL				(REG_GPIO_PIN_CTRL + 2)
-#define	GPIO_MOD				(REG_GPIO_PIN_CTRL + 3)
+#define	GPIO_IN				REG_GPIO_PIN_CTRL
+#define	GPIO_OUT			(REG_GPIO_PIN_CTRL + 1)
+#define	GPIO_IO_SEL			(REG_GPIO_PIN_CTRL + 2)
+#define	GPIO_MOD			(REG_GPIO_PIN_CTRL + 3)
 
 /* 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */
 #define	HSIMR_GPIO12_0_INT_EN			BIT(0)
@@ -400,8 +407,7 @@
 #define	HSIMR_PDN_INT_EN			BIT(7)
 #define	HSIMR_GPIO9_INT_EN			BIT(25)
 
-/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */
-
+/*  8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */
 #define	HSISR_GPIO12_0_INT			BIT(0)
 #define	HSISR_SPS_OCP_INT			BIT(5)
 #define	HSISR_RON_INT_EN			BIT(6)
@@ -412,7 +418,6 @@
 #define	MSR_ADHOC				0x01
 #define	MSR_INFRA				0x02
 #define	MSR_AP					0x03
-#define	MSR_MASK				0x03
 
 #define	RRSR_RSC_OFFSET				21
 #define	RRSR_SHORT_OFFSET			23
@@ -542,7 +547,8 @@
 
 /*********************************************
 *       8723BE IMR/ISR bits
-**********************************************/
+*********************************************
+*/
 #define	IMR_DISABLED				0x0
 /* IMR DW0(0x0060-0063) Bit 0-31 */
 #define	IMR_TXCCK		BIT(30)	/* TXRPT interrupt when
@@ -644,7 +650,7 @@
 #define RF_OPTION1				0x79
 #define RF_OPTION2				0x7A
 #define RF_OPTION3				0x7B
-#define RF_OPTION4				0xC3
+#define EEPROM_RF_BT_SETTING_8723B		0xC3
 
 #define EEPROM_DEFAULT_PID			0x1234
 #define EEPROM_DEFAULT_VID			0x5678
@@ -678,14 +684,11 @@
 #define EEPROM_CLK				0x06
 #define EEPROM_TESTR				0x08
 
-
 #define EEPROM_TXPOWERCCK			0x10
 #define	EEPROM_TXPOWERHT40_1S			0x16
 #define EEPROM_TXPOWERHT20DIFF			0x1B
 #define EEPROM_TXPOWER_OFDMDIFF			0x1B
 
-
-
 #define	EEPROM_TX_PWR_INX			0x10
 
 #define	EEPROM_CHANNELPLAN			0xB8
@@ -1198,7 +1201,7 @@
 #define APP_MIC					BIT(30)
 #define APP_FCS					BIT(31)
 
-#define _MIN_SPACE(x)			((x) & 0x7)
+#define _MIN_SPACE(x)				((x) & 0x7)
 #define _SHORT_GI_PADDING(x)		(((x) & 0x1F) << 3)
 
 #define RXERR_TYPE_OFDM_PPDU		0
@@ -1216,105 +1219,105 @@
 #define RXERR_TYPE_HT_MPDU_FAIL		12
 #define RXERR_TYPE_RX_FULL_DROP		15
 
-#define RXERR_COUNTER_MASK		0xFFFFF
-#define RXERR_RPT_RST			BIT(27)
-#define _RXERR_RPT_SEL(type)		((type) << 28)
+#define RXERR_COUNTER_MASK			0xFFFFF
+#define RXERR_RPT_RST				BIT(27)
+#define _RXERR_RPT_SEL(type)			((type) << 28)
 
-#define	SCR_TXUSEDK			BIT(0)
-#define	SCR_RXUSEDK			BIT(1)
-#define	SCR_TXENCENABLE			BIT(2)
-#define	SCR_RXDECENABLE			BIT(3)
-#define	SCR_SKBYA2			BIT(4)
-#define	SCR_NOSKMC			BIT(5)
-#define SCR_TXBCUSEDK			BIT(6)
-#define SCR_RXBCUSEDK			BIT(7)
+#define	SCR_TXUSEDK				BIT(0)
+#define	SCR_RXUSEDK				BIT(1)
+#define	SCR_TXENCENABLE				BIT(2)
+#define	SCR_RXDECENABLE				BIT(3)
+#define	SCR_SKBYA2				BIT(4)
+#define	SCR_NOSKMC				BIT(5)
+#define SCR_TXBCUSEDK				BIT(6)
+#define SCR_RXBCUSEDK				BIT(7)
 
-#define XCLK_VLD			BIT(0)
-#define ACLK_VLD			BIT(1)
-#define UCLK_VLD			BIT(2)
-#define PCLK_VLD			BIT(3)
-#define PCIRSTB				BIT(4)
-#define V15_VLD				BIT(5)
-#define TRP_B15V_EN			BIT(7)
-#define SIC_IDLE			BIT(8)
-#define BD_MAC2				BIT(9)
-#define BD_MAC1				BIT(10)
-#define IC_MACPHY_MODE			BIT(11)
-#define BT_FUNC				BIT(16)
-#define VENDOR_ID			BIT(19)
-#define PAD_HWPD_IDN			BIT(22)
-#define TRP_VAUX_EN			BIT(23)
-#define TRP_BT_EN			BIT(24)
-#define BD_PKG_SEL			BIT(25)
-#define BD_HCI_SEL			BIT(26)
-#define TYPE_ID				BIT(27)
+#define XCLK_VLD				BIT(0)
+#define ACLK_VLD				BIT(1)
+#define UCLK_VLD				BIT(2)
+#define PCLK_VLD				BIT(3)
+#define PCIRSTB					BIT(4)
+#define V15_VLD					BIT(5)
+#define TRP_B15V_EN				BIT(7)
+#define SIC_IDLE				BIT(8)
+#define BD_MAC2					BIT(9)
+#define BD_MAC1					BIT(10)
+#define IC_MACPHY_MODE				BIT(11)
+#define BT_FUNC					BIT(16)
+#define VENDOR_ID				BIT(19)
+#define PAD_HWPD_IDN				BIT(22)
+#define TRP_VAUX_EN				BIT(23)
+#define TRP_BT_EN				BIT(24)
+#define BD_PKG_SEL				BIT(25)
+#define BD_HCI_SEL				BIT(26)
+#define TYPE_ID					BIT(27)
 
-#define USB_IS_HIGH_SPEED		0
-#define USB_IS_FULL_SPEED		1
-#define USB_SPEED_MASK			BIT(5)
+#define USB_IS_HIGH_SPEED			0
+#define USB_IS_FULL_SPEED			1
+#define USB_SPEED_MASK				BIT(5)
 
-#define USB_NORMAL_SIE_EP_MASK		0xF
-#define USB_NORMAL_SIE_EP_SHIFT		4
+#define USB_NORMAL_SIE_EP_MASK			0xF
+#define USB_NORMAL_SIE_EP_SHIFT			4
 
-#define USB_TEST_EP_MASK		0x30
-#define USB_TEST_EP_SHIFT		4
+#define USB_TEST_EP_MASK			0x30
+#define USB_TEST_EP_SHIFT			4
 
-#define USB_AGG_EN			BIT(3)
+#define USB_AGG_EN				BIT(3)
 
-#define MAC_ADDR_LEN			6
-#define LAST_ENTRY_OF_TX_PKT_BUFFER	175/*255    88e*/
+#define MAC_ADDR_LEN				6
+#define LAST_ENTRY_OF_TX_PKT_BUFFER		175/*255    88e*/
 
-#define POLLING_LLT_THRESHOLD		20
-#define POLLING_READY_TIMEOUT_COUNT	3000
+#define POLLING_LLT_THRESHOLD			20
+#define POLLING_READY_TIMEOUT_COUNT		3000
 
-#define	MAX_MSS_DENSITY_2T		0x13
-#define	MAX_MSS_DENSITY_1T		0x0A
+#define	MAX_MSS_DENSITY_2T			0x13
+#define	MAX_MSS_DENSITY_1T			0x0A
 
 #define EPROM_CMD_OPERATING_MODE_MASK	((1<<7)|(1<<6))
-#define EPROM_CMD_CONFIG		0x3
-#define EPROM_CMD_LOAD			1
+#define EPROM_CMD_CONFIG			0x3
+#define EPROM_CMD_LOAD				1
 
-#define	HWSET_MAX_SIZE_92S		HWSET_MAX_SIZE
+#define	HWSET_MAX_SIZE_92S			HWSET_MAX_SIZE
 
-#define	HAL_8192C_HW_GPIO_WPS_BIT	BIT(2)
+#define	HAL_8192C_HW_GPIO_WPS_BIT		BIT(2)
 
-#define	RPMAC_RESET			0x100
-#define	RPMAC_TXSTART			0x104
-#define	RPMAC_TXLEGACYSIG		0x108
-#define	RPMAC_TXHTSIG1			0x10c
-#define	RPMAC_TXHTSIG2			0x110
-#define	RPMAC_PHYDEBUG			0x114
-#define	RPMAC_TXPACKETNUM		0x118
-#define	RPMAC_TXIDLE			0x11c
-#define	RPMAC_TXMACHEADER0		0x120
-#define	RPMAC_TXMACHEADER1		0x124
-#define	RPMAC_TXMACHEADER2		0x128
-#define	RPMAC_TXMACHEADER3		0x12c
-#define	RPMAC_TXMACHEADER4		0x130
-#define	RPMAC_TXMACHEADER5		0x134
-#define	RPMAC_TXDADATYPE		0x138
-#define	RPMAC_TXRANDOMSEED		0x13c
-#define	RPMAC_CCKPLCPPREAMBLE		0x140
-#define	RPMAC_CCKPLCPHEADER		0x144
-#define	RPMAC_CCKCRC16			0x148
-#define	RPMAC_OFDMRXCRC32OK		0x170
-#define	RPMAC_OFDMRXCRC32ER		0x174
-#define	RPMAC_OFDMRXPARITYER		0x178
-#define	RPMAC_OFDMRXCRC8ER		0x17c
-#define	RPMAC_CCKCRXRC16ER		0x180
-#define	RPMAC_CCKCRXRC32ER		0x184
-#define	RPMAC_CCKCRXRC32OK		0x188
-#define	RPMAC_TXSTATUS			0x18c
+#define	RPMAC_RESET				0x100
+#define	RPMAC_TXSTART				0x104
+#define	RPMAC_TXLEGACYSIG			0x108
+#define	RPMAC_TXHTSIG1				0x10c
+#define	RPMAC_TXHTSIG2				0x110
+#define	RPMAC_PHYDEBUG				0x114
+#define	RPMAC_TXPACKETNUM			0x118
+#define	RPMAC_TXIDLE				0x11c
+#define	RPMAC_TXMACHEADER0			0x120
+#define	RPMAC_TXMACHEADER1			0x124
+#define	RPMAC_TXMACHEADER2			0x128
+#define	RPMAC_TXMACHEADER3			0x12c
+#define	RPMAC_TXMACHEADER4			0x130
+#define	RPMAC_TXMACHEADER5			0x134
+#define	RPMAC_TXDADATYPE			0x138
+#define	RPMAC_TXRANDOMSEED			0x13c
+#define	RPMAC_CCKPLCPPREAMBLE			0x140
+#define	RPMAC_CCKPLCPHEADER			0x144
+#define	RPMAC_CCKCRC16				0x148
+#define	RPMAC_OFDMRXCRC32OK			0x170
+#define	RPMAC_OFDMRXCRC32ER			0x174
+#define	RPMAC_OFDMRXPARITYER			0x178
+#define	RPMAC_OFDMRXCRC8ER			0x17c
+#define	RPMAC_CCKCRXRC16ER			0x180
+#define	RPMAC_CCKCRXRC32ER			0x184
+#define	RPMAC_CCKCRXRC32OK			0x188
+#define	RPMAC_TXSTATUS				0x18c
 
-#define	RFPGA0_RFMOD			0x800
+#define	RFPGA0_RFMOD				0x800
 
-#define	RFPGA0_TXINFO			0x804
-#define	RFPGA0_PSDFUNCTION		0x808
+#define	RFPGA0_TXINFO				0x804
+#define	RFPGA0_PSDFUNCTION			0x808
 
-#define	RFPGA0_TXGAINSTAGE		0x80c
+#define	RFPGA0_TXGAINSTAGE			0x80c
 
-#define	RFPGA0_RFTIMING1		0x810
-#define	RFPGA0_RFTIMING2		0x814
+#define	RFPGA0_RFTIMING1			0x810
+#define	RFPGA0_RFTIMING2			0x814
 
 #define	RFPGA0_XA_HSSIPARAMETER1	0x820
 #define	RFPGA0_XA_HSSIPARAMETER2	0x824
@@ -1385,7 +1388,6 @@
 #define	RCCK0_FACOUNTERUPPER		0xa58
 #define	RCCK0_CCA_CNT			0xa60
 
-
 /* PageB(0xB00) */
 #define	RPDP_ANTA			0xb00
 #define	RPDP_ANTA_4			0xb04
@@ -1399,7 +1401,7 @@
 #define	RPDP_ANTA_24			0xb24
 
 #define	RCONFIG_PMPD_ANTA		0xb28
-#define	CONFIG_RAM64X16			0xb2c
+#define	RCONFIG_ram64x16		0xb2c
 
 #define	RBNDA				0xb30
 #define	RHSSIPAR			0xb34
@@ -1494,7 +1496,6 @@
 #define	ROFDM0_FRAMESYNC		0xcf0
 #define	ROFDM0_DFSREPORT		0xcf4
 
-
 #define	ROFDM1_LSTF			0xd00
 #define	ROFDM1_TRXPATHENABLE		0xd04
 
@@ -1593,144 +1594,144 @@
 #define	RSLEEP				0xee0
 #define	RPMPD_ANAEN			0xeec
 
-#define	RZEBRA1_HSSIENABLE		0x0
-#define	RZEBRA1_TRXENABLE1		0x1
-#define	RZEBRA1_TRXENABLE2		0x2
-#define	RZEBRA1_AGC			0x4
-#define	RZEBRA1_CHARGEPUMP		0x5
-#define	RZEBRA1_CHANNEL			0x7
+#define	RZEBRA1_HSSIENABLE			0x0
+#define	RZEBRA1_TRXENABLE1			0x1
+#define	RZEBRA1_TRXENABLE2			0x2
+#define	RZEBRA1_AGC				0x4
+#define	RZEBRA1_CHARGEPUMP			0x5
+#define	RZEBRA1_CHANNEL				0x7
 
-#define	RZEBRA1_TXGAIN			0x8
-#define	RZEBRA1_TXLPF			0x9
-#define	RZEBRA1_RXLPF			0xb
-#define	RZEBRA1_RXHPFCORNER		0xc
+#define	RZEBRA1_TXGAIN				0x8
+#define	RZEBRA1_TXLPF				0x9
+#define	RZEBRA1_RXLPF				0xb
+#define	RZEBRA1_RXHPFCORNER			0xc
 
-#define	RGLOBALCTRL			0
-#define	RRTL8256_TXLPF			19
-#define	RRTL8256_RXLPF			11
-#define	RRTL8258_TXLPF			0x11
-#define	RRTL8258_RXLPF			0x13
-#define	RRTL8258_RSSILPF		0xa
+#define	RGLOBALCTRL				0
+#define	RRTL8256_TXLPF				19
+#define	RRTL8256_RXLPF				11
+#define	RRTL8258_TXLPF				0x11
+#define	RRTL8258_RXLPF				0x13
+#define	RRTL8258_RSSILPF			0xa
 
-#define	RF_AC				0x00
+#define	RF_AC					0x00
 
-#define	RF_IQADJ_G1			0x01
-#define	RF_IQADJ_G2			0x02
-#define	RF_POW_TRSW			0x05
+#define	RF_IQADJ_G1				0x01
+#define	RF_IQADJ_G2				0x02
+#define	RF_POW_TRSW				0x05
 
-#define	RF_GAIN_RX			0x06
-#define	RF_GAIN_TX			0x07
+#define	RF_GAIN_RX				0x06
+#define	RF_GAIN_TX				0x07
 
-#define	RF_TXM_IDAC			0x08
-#define	RF_BS_IQGEN			0x0F
+#define	RF_TXM_IDAC				0x08
+#define	RF_BS_IQGEN				0x0F
 
-#define	RF_MODE1			0x10
-#define	RF_MODE2			0x11
+#define	RF_MODE1				0x10
+#define	RF_MODE2				0x11
 
-#define	RF_RX_AGC_HP			0x12
-#define	RF_TX_AGC			0x13
-#define	RF_BIAS				0x14
-#define	RF_IPA				0x15
-#define	RF_POW_ABILITY			0x17
-#define	RF_MODE_AG			0x18
-#define	RRFCHANNEL			0x18
-#define	RF_CHNLBW			0x18
-#define	RF_TOP				0x19
+#define	RF_RX_AGC_HP				0x12
+#define	RF_TX_AGC				0x13
+#define	RF_BIAS					0x14
+#define	RF_IPA					0x15
+#define	RF_POW_ABILITY				0x17
+#define	RF_MODE_AG				0x18
+#define	RRFCHANNEL				0x18
+#define	RF_CHNLBW				0x18
+#define	RF_TOP					0x19
 
-#define	RF_RX_G1			0x1A
-#define	RF_RX_G2			0x1B
+#define	RF_RX_G1				0x1A
+#define	RF_RX_G2				0x1B
 
-#define	RF_RX_BB2			0x1C
-#define	RF_RX_BB1			0x1D
+#define	RF_RX_BB2				0x1C
+#define	RF_RX_BB1				0x1D
 
-#define	RF_RCK1				0x1E
-#define	RF_RCK2				0x1F
+#define	RF_RCK1					0x1E
+#define	RF_RCK2					0x1F
 
-#define	RF_TX_G1			0x20
-#define	RF_TX_G2			0x21
-#define	RF_TX_G3			0x22
+#define	RF_TX_G1				0x20
+#define	RF_TX_G2				0x21
+#define	RF_TX_G3				0x22
 
-#define	RF_TX_BB1			0x23
-#define	RF_T_METER			0x42
+#define	RF_TX_BB1				0x23
+#define	RF_T_METER				0x42
 
-#define	RF_SYN_G1			0x25
-#define	RF_SYN_G2			0x26
-#define	RF_SYN_G3			0x27
-#define	RF_SYN_G4			0x28
-#define	RF_SYN_G5			0x29
-#define	RF_SYN_G6			0x2A
-#define	RF_SYN_G7			0x2B
-#define	RF_SYN_G8			0x2C
+#define	RF_SYN_G1				0x25
+#define	RF_SYN_G2				0x26
+#define	RF_SYN_G3				0x27
+#define	RF_SYN_G4				0x28
+#define	RF_SYN_G5				0x29
+#define	RF_SYN_G6				0x2A
+#define	RF_SYN_G7				0x2B
+#define	RF_SYN_G8				0x2C
 
-#define	RF_RCK_OS			0x30
-#define	RF_TXPA_G1			0x31
-#define	RF_TXPA_G2			0x32
-#define	RF_TXPA_G3			0x33
+#define	RF_RCK_OS				0x30
+#define	RF_TXPA_G1				0x31
+#define	RF_TXPA_G2				0x32
+#define	RF_TXPA_G3				0x33
 
-#define	RF_TX_BIAS_A			0x35
-#define	RF_TX_BIAS_D			0x36
-#define	RF_LOBF_9			0x38
-#define	RF_RXRF_A3			0x3C
-#define	RF_TRSW				0x3F
+#define	RF_TX_BIAS_A				0x35
+#define	RF_TX_BIAS_D				0x36
+#define	RF_LOBF_9				0x38
+#define	RF_RXRF_A3				0x3C
+#define	RF_TRSW					0x3F
 
-#define	RF_TXRF_A2			0x41
-#define	RF_TXPA_G4			0x46
-#define	RF_TXPA_A4			0x4B
+#define	RF_TXRF_A2				0x41
+#define	RF_TXPA_G4				0x46
+#define	RF_TXPA_A4				0x4B
 
-#define	RF_WE_LUT			0xEF
+#define	RF_WE_LUT				0xEF
 
-#define	BBBRESETB			0x100
-#define	BGLOBALRESETB			0x200
-#define	BOFDMTXSTART			0x4
-#define	BCCKTXSTART			0x8
-#define	BCRC32DEBUG			0x100
-#define	BPMACLOOPBACK			0x10
-#define	BTXLSIG				0xffffff
-#define	BOFDMTXRATE			0xf
-#define	BOFDMTXRESERVED			0x10
-#define	BOFDMTXLENGTH			0x1ffe0
-#define	BOFDMTXPARITY			0x20000
-#define	BTXHTSIG1			0xffffff
-#define	BTXHTMCSRATE			0x7f
-#define	BTXHTBW				0x80
-#define	BTXHTLENGTH			0xffff00
-#define	BTXHTSIG2			0xffffff
-#define	BTXHTSMOOTHING			0x1
-#define	BTXHTSOUNDING			0x2
-#define	BTXHTRESERVED			0x4
-#define	BTXHTAGGREATION			0x8
-#define	BTXHTSTBC			0x30
-#define	BTXHTADVANCECODING		0x40
-#define	BTXHTSHORTGI			0x80
-#define	BTXHTNUMBERHT_LTF		0x300
-#define	BTXHTCRC8			0x3fc00
-#define	BCOUNTERRESET			0x10000
-#define	BNUMOFOFDMTX			0xffff
-#define	BNUMOFCCKTX			0xffff0000
-#define	BTXIDLEINTERVAL			0xffff
-#define	BOFDMSERVICE			0xffff0000
-#define	BTXMACHEADER			0xffffffff
-#define	BTXDATAINIT			0xff
-#define	BTXHTMODE			0x100
-#define	BTXDATATYPE			0x30000
-#define	BTXRANDOMSEED			0xffffffff
-#define	BCCKTXPREAMBLE			0x1
-#define	BCCKTXSFD			0xffff0000
-#define	BCCKTXSIG			0xff
-#define	BCCKTXSERVICE			0xff00
-#define	BCCKLENGTHEXT			0x8000
-#define	BCCKTXLENGHT			0xffff0000
-#define	BCCKTXCRC16			0xffff
-#define	BCCKTXSTATUS			0x1
-#define	BOFDMTXSTATUS			0x2
+#define	BBBRESETB				0x100
+#define	BGLOBALRESETB				0x200
+#define	BOFDMTXSTART				0x4
+#define	BCCKTXSTART				0x8
+#define	BCRC32DEBUG				0x100
+#define	BPMACLOOPBACK				0x10
+#define	BTXLSIG					0xffffff
+#define	BOFDMTXRATE				0xf
+#define	BOFDMTXRESERVED				0x10
+#define	BOFDMTXLENGTH				0x1ffe0
+#define	BOFDMTXPARITY				0x20000
+#define	BTXHTSIG1				0xffffff
+#define	BTXHTMCSRATE				0x7f
+#define	BTXHTBW					0x80
+#define	BTXHTLENGTH				0xffff00
+#define	BTXHTSIG2				0xffffff
+#define	BTXHTSMOOTHING				0x1
+#define	BTXHTSOUNDING				0x2
+#define	BTXHTRESERVED				0x4
+#define	BTXHTAGGREATION				0x8
+#define	BTXHTSTBC				0x30
+#define	BTXHTADVANCECODING			0x40
+#define	BTXHTSHORTGI				0x80
+#define	BTXHTNUMBERHT_LTF			0x300
+#define	BTXHTCRC8				0x3fc00
+#define	BCOUNTERRESET				0x10000
+#define	BNUMOFOFDMTX				0xffff
+#define	BNUMOFCCKTX				0xffff0000
+#define	BTXIDLEINTERVAL				0xffff
+#define	BOFDMSERVICE				0xffff0000
+#define	BTXMACHEADER				0xffffffff
+#define	BTXDATAINIT				0xff
+#define	BTXHTMODE				0x100
+#define	BTXDATATYPE				0x30000
+#define	BTXRANDOMSEED				0xffffffff
+#define	BCCKTXPREAMBLE				0x1
+#define	BCCKTXSFD				0xffff0000
+#define	BCCKTXSIG				0xff
+#define	BCCKTXSERVICE				0xff00
+#define	BCCKLENGTHEXT				0x8000
+#define	BCCKTXLENGHT				0xffff0000
+#define	BCCKTXCRC16				0xffff
+#define	BCCKTXSTATUS				0x1
+#define	BOFDMTXSTATUS				0x2
 #define IS_BB_REG_OFFSET_92S(_offset)	\
 	((_offset >= 0x800) && (_offset <= 0xfff))
 
-#define	BRFMOD				0x1
-#define	BJAPANMODE			0x2
-#define	BCCKTXSC			0x30
-#define	BCCKEN				0x1000000
-#define	BOFDMEN				0x2000000
+#define	BRFMOD					0x1
+#define	BJAPANMODE				0x2
+#define	BCCKTXSC				0x30
+#define	BCCKEN					0x1000000
+#define	BOFDMEN					0x2000000
 
 #define	BOFDMRXADCPHASE			0x10000
 #define	BOFDMTXDACPHASE			0x40000
@@ -1824,13 +1825,13 @@
 #define	BDA6SWING			0x380000
 
 #define	BADCLKPHASE			0x4000000
-#define	B80MCLKDELAY	0x18000000
-#define	BAFEWATCHDOGENABLE	0x20000000
+#define	B80MCLKDELAY			0x18000000
+#define	BAFEWATCHDOGENABLE		0x20000000
 
-#define	BXTALCAP01	0xc0000000
-#define	BXTALCAP23	0x3
+#define	BXTALCAP01			0xc0000000
+#define	BXTALCAP23			0x3
 #define	BXTALCAP92X			0x0f000000
-#define BXTALCAP	0x0f000000
+#define BXTALCAP			0x0f000000
 
 #define	BINTDIFCLKENABLE		0x400
 #define	BEXTSIGCLKENABLE		0x800
@@ -1857,7 +1858,7 @@
 #define	BCCKRX_AGC_FORMAT		0x200
 #define	BPSDFFT_SAMPLE_POINT		0xc000
 #define	BPSD_AVERAGE_NUM		0x3000
-#define	BIQPATH_CONTROL	0xc00
+#define	BIQPATH_CONTROL			0xc00
 #define	BPSD_FREQ			0x3ff
 #define	BPSD_ANTENNA_PATH		0x30
 #define	BPSD_IQ_SWITCH			0x40
@@ -1957,300 +1958,316 @@
 #define	BCCK_DEFAULT_RXPATH		0xc000000
 #define	BCCK_OPTION_RXPATH		0x3000000
 
-#define	BNUM_OFSTF	0x3
-#define	BSHIFT_L	0xc0
-#define	BGI_TH	0xc
-#define	BRXPATH_A	0x1
-#define	BRXPATH_B	0x2
-#define	BRXPATH_C	0x4
-#define	BRXPATH_D	0x8
-#define	BTXPATH_A	0x1
-#define	BTXPATH_B	0x2
-#define	BTXPATH_C	0x4
-#define	BTXPATH_D	0x8
-#define	BTRSSI_FREQ	0x200
-#define	BADC_BACKOFF	0x3000
-#define	BDFIR_BACKOFF	0xc000
-#define	BTRSSI_LATCH_PHASE	0x10000
-#define	BRX_LDC_OFFSET	0xff
-#define	BRX_QDC_OFFSET	0xff00
-#define	BRX_DFIR_MODE	0x1800000
-#define	BRX_DCNF_TYPE	0xe000000
-#define	BRXIQIMB_A	0x3ff
-#define	BRXIQIMB_B	0xfc00
-#define	BRXIQIMB_C	0x3f0000
-#define	BRXIQIMB_D	0xffc00000
-#define	BDC_DC_NOTCH	0x60000
-#define	BRXNB_NOTCH	0x1f000000
-#define	BPD_TH	0xf
-#define	BPD_TH_OPT2	0xc000
-#define	BPWED_TH	0x700
-#define	BIFMF_WIN_L	0x800
-#define	BPD_OPTION	0x1000
-#define	BMF_WIN_L	0xe000
-#define	BBW_SEARCH_L	0x30000
-#define	BWIN_ENH_L	0xc0000
-#define	BBW_TH	0x700000
-#define	BED_TH2	0x3800000
-#define	BBW_OPTION	0x4000000
-#define	BRADIO_TH	0x18000000
-#define	BWINDOW_L	0xe0000000
-#define	BSBD_OPTION	0x1
-#define	BFRAME_TH	0x1c
-#define	BFS_OPTION	0x60
-#define	BDC_SLOPE_CHECK	0x80
-#define	BFGUARD_COUNTER_DC_L	0xe00
-#define	BFRAME_WEIGHT_SHORT	0x7000
-#define	BSUB_TUNE	0xe00000
-#define	BFRAME_DC_LENGTH	0xe000000
-#define	BSBD_START_OFFSET	0x30000000
-#define	BFRAME_TH_2	0x7
-#define	BFRAME_GI2_TH	0x38
-#define	BGI2_SYNC_EN	0x40
-#define	BSARCH_SHORT_EARLY	0x300
-#define	BSARCH_SHORT_LATE	0xc00
-#define	BSARCH_GI2_LATE	0x70000
-#define	BCFOANTSUM	0x1
-#define	BCFOACC	0x2
-#define	BCFOSTARTOFFSET	0xc
-#define	BCFOLOOPBACK	0x70
-#define	BCFOSUMWEIGHT	0x80
-#define	BDAGCENABLE	0x10000
-#define	BTXIQIMB_A	0x3ff
-#define	BTXIQIMB_b	0xfc00
-#define	BTXIQIMB_C	0x3f0000
-#define	BTXIQIMB_D	0xffc00000
-#define	BTXIDCOFFSET	0xff
-#define	BTXIQDCOFFSET	0xff00
-#define	BTXDFIRMODE	0x10000
-#define	BTXPESUDO_NOISEON	0x4000000
-#define	BTXPESUDO_NOISE_A	0xff
-#define	BTXPESUDO_NOISE_B	0xff00
-#define	BTXPESUDO_NOISE_C	0xff0000
-#define	BTXPESUDO_NOISE_D	0xff000000
-#define	BCCA_DROPOPTION	0x20000
-#define	BCCA_DROPTHRES	0xfff00000
-#define	BEDCCA_H	0xf
-#define	BEDCCA_L	0xf0
-#define	BLAMBDA_ED	0x300
-#define	BRX_INITIALGAIN	0x7f
-#define	BRX_ANTDIV_EN	0x80
+#define	BNUM_OFSTF			0x3
+#define	BSHIFT_L			0xc0
+#define	BGI_TH				0xc
+#define	BRXPATH_A			0x1
+#define	BRXPATH_B			0x2
+#define	BRXPATH_C			0x4
+#define	BRXPATH_D			0x8
+#define	BTXPATH_A			0x1
+#define	BTXPATH_B			0x2
+#define	BTXPATH_C			0x4
+#define	BTXPATH_D			0x8
+#define	BTRSSI_FREQ			0x200
+#define	BADC_BACKOFF			0x3000
+#define	BDFIR_BACKOFF			0xc000
+#define	BTRSSI_LATCH_PHASE		0x10000
+#define	BRX_LDC_OFFSET			0xff
+#define	BRX_QDC_OFFSET			0xff00
+#define	BRX_DFIR_MODE			0x1800000
+#define	BRX_DCNF_TYPE			0xe000000
+#define	BRXIQIMB_A			0x3ff
+#define	BRXIQIMB_B			0xfc00
+#define	BRXIQIMB_C			0x3f0000
+#define	BRXIQIMB_D			0xffc00000
+#define	BDC_DC_NOTCH			0x60000
+#define	BRXNB_NOTCH			0x1f000000
+#define	BPD_TH				0xf
+#define	BPD_TH_OPT2			0xc000
+#define	BPWED_TH			0x700
+#define	BIFMF_WIN_L			0x800
+#define	BPD_OPTION			0x1000
+#define	BMF_WIN_L			0xe000
+#define	BBW_SEARCH_L			0x30000
+#define	BWIN_ENH_L			0xc0000
+#define	BBW_TH				0x700000
+#define	BED_TH2				0x3800000
+#define	BBW_OPTION			0x4000000
+#define	BRADIO_TH			0x18000000
+#define	BWINDOW_L			0xe0000000
+#define	BSBD_OPTION			0x1
+#define	BFRAME_TH			0x1c
+#define	BFS_OPTION			0x60
+#define	BDC_SLOPE_CHECK			0x80
+#define	BFGUARD_COUNTER_DC_L		0xe00
+#define	BFRAME_WEIGHT_SHORT		0x7000
+#define	BSUB_TUNE			0xe00000
+#define	BFRAME_DC_LENGTH		0xe000000
+#define	BSBD_START_OFFSET		0x30000000
+#define	BFRAME_TH_2			0x7
+#define	BFRAME_GI2_TH			0x38
+#define	BGI2_SYNC_EN			0x40
+#define	BSARCH_SHORT_EARLY		0x300
+#define	BSARCH_SHORT_LATE		0xc00
+#define	BSARCH_GI2_LATE			0x70000
+#define	BCFOANTSUM			0x1
+#define	BCFOACC				0x2
+#define	BCFOSTARTOFFSET			0xc
+#define	BCFOLOOPBACK			0x70
+#define	BCFOSUMWEIGHT			0x80
+#define	BDAGCENABLE			0x10000
+#define	BTXIQIMB_A			0x3ff
+#define	BTXIQIMB_b			0xfc00
+#define	BTXIQIMB_C			0x3f0000
+#define	BTXIQIMB_D			0xffc00000
+#define	BTXIDCOFFSET			0xff
+#define	BTXIQDCOFFSET			0xff00
+#define	BTXDFIRMODE			0x10000
+#define	BTXPESUDO_NOISEON		0x4000000
+#define	BTXPESUDO_NOISE_A		0xff
+#define	BTXPESUDO_NOISE_B		0xff00
+#define	BTXPESUDO_NOISE_C		0xff0000
+#define	BTXPESUDO_NOISE_D		0xff000000
+#define	BCCA_DROPOPTION			0x20000
+#define	BCCA_DROPTHRES			0xfff00000
+#define	BEDCCA_H			0xf
+#define	BEDCCA_L			0xf0
+#define	BLAMBDA_ED			0x300
+#define	BRX_INITIALGAIN			0x7f
+#define	BRX_ANTDIV_EN			0x80
 #define	BRX_AGC_ADDRESS_FOR_LNA		0x7f00
-#define	BRX_HIGHPOWER_FLOW	0x8000
+#define	BRX_HIGHPOWER_FLOW		0x8000
 #define	BRX_AGC_FREEZE_THRES		0xc0000
-#define	BRX_FREEZESTEP_AGC1	0x300000
-#define	BRX_FREEZESTEP_AGC2	0xc00000
-#define	BRX_FREEZESTEP_AGC3	0x3000000
-#define	BRX_FREEZESTEP_AGC0	0xc000000
-#define	BRXRSSI_CMP_EN	0x10000000
-#define	BRXQUICK_AGCEN	0x20000000
+#define	BRX_FREEZESTEP_AGC1		0x300000
+#define	BRX_FREEZESTEP_AGC2		0xc00000
+#define	BRX_FREEZESTEP_AGC3		0x3000000
+#define	BRX_FREEZESTEP_AGC0		0xc000000
+#define	BRXRSSI_CMP_EN			0x10000000
+#define	BRXQUICK_AGCEN			0x20000000
 #define	BRXAGC_FREEZE_THRES_MODE	0x40000000
-#define	BRX_OVERFLOW_CHECKTYPE	0x80000000
-#define	BRX_AGCSHIFT	0x7f
-#define	BTRSW_TRI_ONLY	0x80
-#define	BPOWER_THRES	0x300
-#define	BRXAGC_EN	0x1
-#define	BRXAGC_TOGETHER_EN	0x2
-#define	BRXAGC_MIN	0x4
-#define	BRXHP_INI	0x7
-#define	BRXHP_TRLNA	0x70
-#define	BRXHP_RSSI	0x700
-#define	BRXHP_BBP1	0x7000
-#define	BRXHP_BBP2	0x70000
-#define	BRXHP_BBP3	0x700000
-#define	BRSSI_H	0x7f0000
-#define	BRSSI_GEN	0x7f000000
-#define	BRXSETTLE_TRSW	0x7
-#define	BRXSETTLE_LNA	0x38
-#define	BRXSETTLE_RSSI	0x1c0
-#define	BRXSETTLE_BBP	0xe00
-#define	BRXSETTLE_RXHP	0x7000
-#define	BRXSETTLE_ANTSW_RSSI	0x38000
-#define	BRXSETTLE_ANTSW	0xc0000
-#define	BRXPROCESS_TIME_DAGC	0x300000
-#define	BRXSETTLE_HSSI	0x400000
-#define	BRXPROCESS_TIME_BBPPW	0x800000
-#define	BRXANTENNA_POWER_SHIFT	0x3000000
-#define	BRSSI_TABLE_SELECT	0xc000000
-#define	BRXHP_FINAL	0x7000000
-#define	BRXHPSETTLE_BBP	0x7
-#define	BRXHTSETTLE_HSSI	0x8
-#define	BRXHTSETTLE_RXHP	0x70
-#define	BRXHTSETTLE_BBPPW	0x80
-#define	BRXHTSETTLE_IDLE	0x300
-#define	BRXHTSETTLE_RESERVED	0x1c00
-#define	BRXHT_RXHP_EN	0x8000
-#define	BRXAGC_FREEZE_THRES	0x30000
-#define	BRXAGC_TOGETHEREN	0x40000
-#define	BRXHTAGC_MIN	0x80000
-#define	BRXHTAGC_EN	0x100000
-#define	BRXHTDAGC_EN	0x200000
-#define	BRXHT_RXHP_BBP	0x1c00000
-#define	BRXHT_RXHP_FINAL	0xe0000000
-#define	BRXPW_RADIO_TH	0x3
-#define	BRXPW_RADIO_EN	0x4
-#define	BRXMF_HOLD	0x3800
-#define	BRXPD_DELAY_TH1	0x38
-#define	BRXPD_DELAY_TH2	0x1c0
-#define	BRXPD_DC_COUNT_MAX	0x600
-#define	BRXPD_DELAY_TH	0x8000
-#define	BRXPROCESS_DELAY	0xf0000
+#define	BRX_OVERFLOW_CHECKTYPE		0x80000000
+#define	BRX_AGCSHIFT			0x7f
+#define	BTRSW_TRI_ONLY			0x80
+#define	BPOWER_THRES			0x300
+#define	BRXAGC_EN			0x1
+#define	BRXAGC_TOGETHER_EN		0x2
+#define	BRXAGC_MIN			0x4
+#define	BRXHP_INI			0x7
+#define	BRXHP_TRLNA			0x70
+#define	BRXHP_RSSI			0x700
+#define	BRXHP_BBP1			0x7000
+#define	BRXHP_BBP2			0x70000
+#define	BRXHP_BBP3			0x700000
+#define	BRSSI_H				0x7f0000
+#define	BRSSI_GEN			0x7f000000
+#define	BRXSETTLE_TRSW			0x7
+#define	BRXSETTLE_LNA			0x38
+#define	BRXSETTLE_RSSI			0x1c0
+#define	BRXSETTLE_BBP			0xe00
+#define	BRXSETTLE_RXHP			0x7000
+#define	BRXSETTLE_ANTSW_RSSI		0x38000
+#define	BRXSETTLE_ANTSW			0xc0000
+#define	BRXPROCESS_TIME_DAGC		0x300000
+#define	BRXSETTLE_HSSI			0x400000
+#define	BRXPROCESS_TIME_BBPPW		0x800000
+#define	BRXANTENNA_POWER_SHIFT		0x3000000
+#define	BRSSI_TABLE_SELECT		0xc000000
+#define	BRXHP_FINAL			0x7000000
+#define	BRXHPSETTLE_BBP			0x7
+#define	BRXHTSETTLE_HSSI		0x8
+#define	BRXHTSETTLE_RXHP		0x70
+#define	BRXHTSETTLE_BBPPW		0x80
+#define	BRXHTSETTLE_IDLE		0x300
+#define	BRXHTSETTLE_RESERVED		0x1c00
+#define	BRXHT_RXHP_EN			0x8000
+#define	BRXAGC_FREEZE_THRES		0x30000
+#define	BRXAGC_TOGETHEREN		0x40000
+#define	BRXHTAGC_MIN			0x80000
+#define	BRXHTAGC_EN			0x100000
+#define	BRXHTDAGC_EN			0x200000
+#define	BRXHT_RXHP_BBP			0x1c00000
+#define	BRXHT_RXHP_FINAL		0xe0000000
+#define	BRXPW_RADIO_TH			0x3
+#define	BRXPW_RADIO_EN			0x4
+#define	BRXMF_HOLD			0x3800
+#define	BRXPD_DELAY_TH1			0x38
+#define	BRXPD_DELAY_TH2			0x1c0
+#define	BRXPD_DC_COUNT_MAX		0x600
+#define	BRXPD_DELAY_TH			0x8000
+#define	BRXPROCESS_DELAY		0xf0000
 #define	BRXSEARCHRANGE_GI2_EARLY	0x700000
 #define	BRXFRAME_FUARD_COUNTER_L	0x3800000
-#define	BRXSGI_GUARD_L	0xc000000
-#define	BRXSGI_SEARCH_L	0x30000000
-#define	BRXSGI_TH	0xc0000000
-#define	BDFSCNT0	0xff
-#define	BDFSCNT1	0xff00
-#define	BDFSFLAG	0xf0000
-#define	BMF_WEIGHT_SUM	0x300000
-#define	BMINIDX_TH	0x7f000000
-#define	BDAFORMAT	0x40000
-#define	BTXCH_EMU_ENABLE	0x01000000
-#define	BTRSW_ISOLATION_A	0x7f
-#define	BTRSW_ISOLATION_B	0x7f00
-#define	BTRSW_ISOLATION_C	0x7f0000
-#define	BTRSW_ISOLATION_D	0x7f000000
-#define	BEXT_LNA_GAIN	0x7c00
+#define	BRXSGI_GUARD_L			0xc000000
+#define	BRXSGI_SEARCH_L			0x30000000
+#define	BRXSGI_TH			0xc0000000
+#define	BDFSCNT0			0xff
+#define	BDFSCNT1			0xff00
+#define	BDFSFLAG			0xf0000
+#define	BMF_WEIGHT_SUM			0x300000
+#define	BMINIDX_TH			0x7f000000
+#define	BDAFORMAT			0x40000
+#define	BTXCH_EMU_ENABLE		0x01000000
+#define	BTRSW_ISOLATION_A		0x7f
+#define	BTRSW_ISOLATION_B		0x7f00
+#define	BTRSW_ISOLATION_C		0x7f0000
+#define	BTRSW_ISOLATION_D		0x7f000000
+#define	BEXT_LNA_GAIN			0x7c00
 
-#define	BSTBC_EN	0x4
-#define	BANTENNA_MAPPING	0x10
-#define	BNSS	0x20
+#define	BSTBC_EN			0x4
+#define	BANTENNA_MAPPING		0x10
+#define	BNSS				0x20
 #define	BCFO_ANTSUM_ID			0x200
-#define	BPHY_COUNTER_RESET	0x8000000
-#define	BCFO_REPORT_GET	0x4000000
-#define	BOFDM_CONTINUE_TX	0x10000000
-#define	BOFDM_SINGLE_CARRIER	0x20000000
-#define	BOFDM_SINGLE_TONE	0x40000000
-#define	BHT_DETECT	0x100
-#define	BCFOEN	0x10000
-#define	BCFOVALUE	0xfff00000
-#define	BSIGTONE_RE	0x3f
-#define	BSIGTONE_IM	0x7f00
-#define	BCOUNTER_CCA	0xffff
-#define	BCOUNTER_PARITYFAIL	0xffff0000
-#define	BCOUNTER_RATEILLEGAL	0xffff
-#define	BCOUNTER_CRC8FAIL	0xffff0000
-#define	BCOUNTER_MCSNOSUPPORT	0xffff
-#define	BCOUNTER_FASTSYNC	0xffff
-#define	BSHORTCFO	0xfff
-#define	BSHORTCFOT_LENGTH	12
-#define	BSHORTCFOF_LENGTH	11
-#define	BLONGCFO	0x7ff
-#define	BLONGCFOT_LENGTH	11
-#define	BLONGCFOF_LENGTH	11
-#define	BTAILCFO	0x1fff
-#define	BTAILCFOT_LENGTH	13
-#define	BTAILCFOF_LENGTH	12
-#define	BNOISE_EN_PWDB	0xffff
-#define	BCC_POWER_DB	0xffff0000
-#define	BMOISE_PWDB	0xffff
-#define	BPOWERMEAST_LENGTH	10
-#define	BPOWERMEASF_LENGTH	3
-#define	BRX_HT_BW	0x1
-#define	BRXSC	0x6
-#define	BRX_HT	0x8
-#define	BNB_INTF_DET_ON	0x1
-#define	BINTF_WIN_LEN_CFG	0x30
-#define	BNB_INTF_TH_CFG	0x1c0
-#define	BRFGAIN	0x3f
-#define	BTABLESEL	0x40
-#define	BTRSW	0x80
-#define	BRXSNR_A	0xff
-#define	BRXSNR_B	0xff00
-#define	BRXSNR_C	0xff0000
-#define	BRXSNR_D	0xff000000
-#define	BSNR_EVMT_LENGTH	8
-#define	BSNR_EVMF_LENGTH	1
-#define	BCSI1ST	0xff
-#define	BCSI2ND	0xff00
-#define	BRXEVM1ST	0xff0000
-#define	BRXEVM2ND	0xff000000
-#define	BSIGEVM	0xff
-#define	BPWDB	0xff00
-#define	BSGIEN	0x10000
+#define	BPHY_COUNTER_RESET		0x8000000
+#define	BCFO_REPORT_GET			0x4000000
+#define	BOFDM_CONTINUE_TX		0x10000000
+#define	BOFDM_SINGLE_CARRIER		0x20000000
+#define	BOFDM_SINGLE_TONE		0x40000000
+#define	BHT_DETECT			0x100
+#define	BCFOEN				0x10000
+#define	BCFOVALUE			0xfff00000
+#define	BSIGTONE_RE			0x3f
+#define	BSIGTONE_IM			0x7f00
+#define	BCOUNTER_CCA			0xffff
+#define	BCOUNTER_PARITYFAIL		0xffff0000
+#define	BCOUNTER_RATEILLEGAL		0xffff
+#define	BCOUNTER_CRC8FAIL		0xffff0000
+#define	BCOUNTER_MCSNOSUPPORT		0xffff
+#define	BCOUNTER_FASTSYNC		0xffff
+#define	BSHORTCFO			0xfff
+#define	BSHORTCFOT_LENGTH		12
+#define	BSHORTCFOF_LENGTH		11
+#define	BLONGCFO			0x7ff
+#define	BLONGCFOT_LENGTH		11
+#define	BLONGCFOF_LENGTH		11
+#define	BTAILCFO			0x1fff
+#define	BTAILCFOT_LENGTH		13
+#define	BTAILCFOF_LENGTH		12
+#define	BNOISE_EN_PWDB			0xffff
+#define	BCC_POWER_DB			0xffff0000
+#define	BMOISE_PWDB			0xffff
+#define	BPOWERMEAST_LENGTH		10
+#define	BPOWERMEASF_LENGTH		3
+#define	BRX_HT_BW			0x1
+#define	BRXSC				0x6
+#define	BRX_HT				0x8
+#define	BNB_INTF_DET_ON			0x1
+#define	BINTF_WIN_LEN_CFG		0x30
+#define	BNB_INTF_TH_CFG			0x1c0
+#define	BRFGAIN				0x3f
+#define	BTABLESEL			0x40
+#define	BTRSW				0x80
+#define	BRXSNR_A			0xff
+#define	BRXSNR_B			0xff00
+#define	BRXSNR_C			0xff0000
+#define	BRXSNR_D			0xff000000
+#define	BSNR_EVMT_LENGTH		8
+#define	BSNR_EVMF_LENGTH		1
+#define	BCSI1ST				0xff
+#define	BCSI2ND				0xff00
+#define	BRXEVM1ST			0xff0000
+#define	BRXEVM2ND			0xff000000
+#define	BSIGEVM				0xff
+#define	BPWDB				0xff00
+#define	BSGIEN				0x10000
 
-#define	BSFACTOR_QMA1	0xf
-#define	BSFACTOR_QMA2	0xf0
-#define	BSFACTOR_QMA3	0xf00
-#define	BSFACTOR_QMA4	0xf000
-#define	BSFACTOR_QMA5	0xf0000
-#define	BSFACTOR_QMA6	0xf0000
-#define	BSFACTOR_QMA7	0xf00000
-#define	BSFACTOR_QMA8	0xf000000
-#define	BSFACTOR_QMA9	0xf0000000
-#define	BCSI_SCHEME	0x100000
+#define	BSFACTOR_QMA1			0xf
+#define	BSFACTOR_QMA2			0xf0
+#define	BSFACTOR_QMA3			0xf00
+#define	BSFACTOR_QMA4			0xf000
+#define	BSFACTOR_QMA5			0xf0000
+#define	BSFACTOR_QMA6			0xf0000
+#define	BSFACTOR_QMA7			0xf00000
+#define	BSFACTOR_QMA8			0xf000000
+#define	BSFACTOR_QMA9			0xf0000000
+#define	BCSI_SCHEME			0x100000
 
 #define	BNOISE_LVL_TOP_SET		0x3
-#define	BCHSMOOTH	0x4
-#define	BCHSMOOTH_CFG1	0x38
-#define	BCHSMOOTH_CFG2	0x1c0
-#define	BCHSMOOTH_CFG3	0xe00
-#define	BCHSMOOTH_CFG4	0x7000
-#define	BMRCMODE	0x800000
-#define	BTHEVMCFG	0x7000000
+#define	BCHSMOOTH			0x4
+#define	BCHSMOOTH_CFG1			0x38
+#define	BCHSMOOTH_CFG2			0x1c0
+#define	BCHSMOOTH_CFG3			0xe00
+#define	BCHSMOOTH_CFG4			0x7000
+#define	BMRCMODE			0x800000
+#define	BTHEVMCFG			0x7000000
 
-#define	BLOOP_FIT_TYPE	0x1
-#define	BUPD_CFO	0x40
-#define	BUPD_CFO_OFFDATA	0x80
-#define	BADV_UPD_CFO	0x100
-#define	BADV_TIME_CTRL	0x800
-#define	BUPD_CLKO	0x1000
-#define	BFC	0x6000
-#define	BTRACKING_MODE	0x8000
-#define	BPHCMP_ENABLE	0x10000
-#define	BUPD_CLKO_LTF	0x20000
-#define	BCOM_CH_CFO	0x40000
-#define	BCSI_ESTI_MODE	0x80000
-#define	BADV_UPD_EQZ	0x100000
-#define	BUCHCFG	0x7000000
-#define	BUPDEQZ	0x8000000
+#define	BLOOP_FIT_TYPE			0x1
+#define	BUPD_CFO			0x40
+#define	BUPD_CFO_OFFDATA		0x80
+#define	BADV_UPD_CFO			0x100
+#define	BADV_TIME_CTRL			0x800
+#define	BUPD_CLKO			0x1000
+#define	BFC				0x6000
+#define	BTRACKING_MODE			0x8000
+#define	BPHCMP_ENABLE			0x10000
+#define	BUPD_CLKO_LTF			0x20000
+#define	BCOM_CH_CFO			0x40000
+#define	BCSI_ESTI_MODE			0x80000
+#define	BADV_UPD_EQZ			0x100000
+#define	BUCHCFG				0x7000000
+#define	BUPDEQZ				0x8000000
 
 #define	BRX_PESUDO_NOISE_ON		0x20000000
-#define	BRX_PESUDO_NOISE_A	0xff
-#define	BRX_PESUDO_NOISE_B	0xff00
-#define	BRX_PESUDO_NOISE_C	0xff0000
-#define	BRX_PESUDO_NOISE_D	0xff000000
+#define	BRX_PESUDO_NOISE_A		0xff
+#define	BRX_PESUDO_NOISE_B		0xff00
+#define	BRX_PESUDO_NOISE_C		0xff0000
+#define	BRX_PESUDO_NOISE_D		0xff000000
 #define	BRX_PESUDO_NOISESTATE_A		0xffff
 #define	BRX_PESUDO_NOISESTATE_B		0xffff0000
 #define	BRX_PESUDO_NOISESTATE_C		0xffff
 #define	BRX_PESUDO_NOISESTATE_D		0xffff0000
 
-#define	BZEBRA1_HSSIENABLE	0x8
-#define	BZEBRA1_TRXCONTROL	0xc00
-#define	BZEBRA1_TRXGAINSETTING	0x07f
-#define	BZEBRA1_RXCOUNTER	0xc00
-#define	BZEBRA1_TXCHANGEPUMP	0x38
-#define	BZEBRA1_RXCHANGEPUMP	0x7
-#define	BZEBRA1_CHANNEL_NUM	0xf80
-#define	BZEBRA1_TXLPFBW	0x400
-#define	BZEBRA1_RXLPFBW	0x600
+#define	BZEBRA1_HSSIENABLE		0x8
+#define	BZEBRA1_TRXCONTROL		0xc00
+#define	BZEBRA1_TRXGAINSETTING		0x07f
+#define	BZEBRA1_RXCOUNTER		0xc00
+#define	BZEBRA1_TXCHANGEPUMP		0x38
+#define	BZEBRA1_RXCHANGEPUMP		0x7
+#define	BZEBRA1_CHANNEL_NUM		0xf80
+#define	BZEBRA1_TXLPFBW			0x400
+#define	BZEBRA1_RXLPFBW			0x600
 
 #define	BRTL8256REG_MODE_CTRL1		0x100
 #define	BRTL8256REG_MODE_CTRL0		0x40
 #define	BRTL8256REG_TXLPFBW		0x18
 #define	BRTL8256REG_RXLPFBW		0x600
 
-#define	BRTL8258_TXLPFBW	0xc
-#define	BRTL8258_RXLPFBW	0xc00
-#define	BRTL8258_RSSILPFBW	0xc0
+#define	BRTL8258_TXLPFBW		0xc
+#define	BRTL8258_RXLPFBW		0xc00
+#define	BRTL8258_RSSILPFBW		0xc0
 
-#define	BBYTE0	0x1
-#define	BBYTE1	0x2
-#define	BBYTE2	0x4
-#define	BBYTE3	0x8
-#define	BWORD0	0x3
-#define	BWORD1	0xc
-#define	BWORD	0xf
+#define	BBYTE0				0x1
+#define	BBYTE1				0x2
+#define	BBYTE2				0x4
+#define	BBYTE3				0x8
+#define	BWORD0				0x3
+#define	BWORD1				0xc
+#define	BWORD				0xf
 
-#define	BENABLE	0x1
-#define	BDISABLE	0x0
+#define	MASKBYTE0			0xff
+#define	MASKBYTE1			0xff00
+#define	MASKBYTE2			0xff0000
+#define	MASKBYTE3			0xff000000
+#define	MASKHWORD			0xffff0000
+#define	MASKLWORD			0x0000ffff
+#define	MASKDWORD			0xffffffff
+#define	MASK12BITS			0xfff
+#define	MASKH4BITS			0xf0000000
+#define MASKOFDM_D			0xffc00000
+#define	MASKCCK				0x3f3f3f3f
 
-#define	LEFT_ANTENNA	0x0
-#define	RIGHT_ANTENNA	0x1
+#define	MASK4BITS			0x0f
+#define	MASK20BITS			0xfffff
+#define RFREG_OFFSET_MASK		0xfffff
 
-#define	TCHECK_TXSTATUS	500
-#define	TUPDATE_RXCOUNTER	100
+#define	BENABLE				0x1
+#define	BDISABLE			0x0
+
+#define	LEFT_ANTENNA			0x0
+#define	RIGHT_ANTENNA			0x1
+
+#define	TCHECK_TXSTATUS			500
+#define	TUPDATE_RXCOUNTER		100
 
 #define	REG_UN_used_register		0x01bf
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/rf.c b/drivers/net/wireless/rtlwifi/rtl8723be/rf.c
index 4862949..5ed4492 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/rf.c
@@ -51,7 +51,7 @@
 			      rtlphy->rfreg_chnlval[0]);
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 "unknown bandwidth: %#X\n", bandwidth);
 		break;
 	}
@@ -93,18 +93,20 @@
 				       (ppowerlevel[idx1] << 16) |
 				       (ppowerlevel[idx1] << 24);
 		}
+
 		if (rtlefuse->eeprom_regulatory == 0) {
 			tmpval =
-			    (rtlphy->mcs_offset[0][6]) +
-			    (rtlphy->mcs_offset[0][7] << 8);
+			    (rtlphy->mcs_txpwrlevel_origoffset[0][6]) +
+			    (rtlphy->mcs_txpwrlevel_origoffset[0][7] << 8);
 			tx_agc[RF90_PATH_A] += tmpval;
 
-			tmpval = (rtlphy->mcs_offset[0][14]) +
-				 (rtlphy->mcs_offset[0][15] <<
+			tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) +
+				 (rtlphy->mcs_txpwrlevel_origoffset[0][15] <<
 				  24);
 			tx_agc[RF90_PATH_B] += tmpval;
 		}
 	}
+
 	for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
 		ptr = (u8 *)(&(tx_agc[idx1]));
 		for (idx2 = 0; idx2 < 4; idx2++) {
@@ -124,30 +126,32 @@
 	tmpval = tx_agc[RF90_PATH_A] & 0xff;
 	rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);
 
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-		 "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+		"CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
 		 RTXAGC_A_CCK1_MCS32);
 
 	tmpval = tx_agc[RF90_PATH_A] >> 8;
 
+	/*tmpval = tmpval & 0xff00ffff;*/
+
 	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
 
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-		 "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+		"CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
 		 RTXAGC_B_CCK11_A_CCK2_11);
 
 	tmpval = tx_agc[RF90_PATH_B] >> 24;
 	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);
 
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-		 "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+		"CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
 		 RTXAGC_B_CCK11_A_CCK2_11);
 
 	tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff;
 	rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval);
 
-	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-		 "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+		"CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
 		 RTXAGC_B_CCK1_55_MCS32);
 }
 
@@ -169,8 +173,8 @@
 		powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) |
 		    (powerbase0 << 8) | powerbase0;
 		*(ofdmbase + i) = powerbase0;
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-			 " [OFDM power base index rf(%c) = 0x%x]\n",
+		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+			" [OFDM power base index rf(%c) = 0x%x]\n",
 			 ((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
 	}
 
@@ -179,27 +183,30 @@
 			powerlevel[i] = ppowerlevel_bw20[i];
 		else
 			powerlevel[i] = ppowerlevel_bw40[i];
+
 		powerbase1 = powerlevel[i];
 		powerbase1 = (powerbase1 << 24) | (powerbase1 << 16) |
 			     (powerbase1 << 8) | powerbase1;
 
 		*(mcsbase + i) = powerbase1;
 
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 			" [MCS power base index rf(%c) = 0x%x]\n",
-			((i == 0) ? 'A' : 'B'), *(mcsbase + i));
+			 ((i == 0) ? 'A' : 'B'), *(mcsbase + i));
 	}
 }
 
-static void txpwr_by_regulatory(struct ieee80211_hw *hw, u8 channel, u8 index,
-				u32 *powerbase0, u32 *powerbase1,
-				u32 *p_outwriteval)
+static void _rtl8723be_get_txpower_writeval_by_regulatory(
+							struct ieee80211_hw *hw,
+							u8 channel, u8 index,
+							u32 *powerbase0,
+							u32 *powerbase1,
+							u32 *p_outwriteval)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
-	u8 i, chnlgroup = 0, pwr_diff_limit[4];
-	u8 pwr_diff = 0, customer_pwr_diff;
+	u8 i, chnlgroup = 0, pwr_diff_limit[4], pwr_diff = 0, customer_pwr_diff;
 	u32 writeval, customer_limit, rf;
 
 	for (rf = 0; rf < 2; rf++) {
@@ -208,13 +215,13 @@
 			chnlgroup = 0;
 
 			writeval =
-			    rtlphy->mcs_offset[chnlgroup][index + (rf ? 8 : 0)]
+			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index +
+								(rf ? 8 : 0)]
 			    + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 
-			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-				 "RTK better performance, "
-				 "writeval(%c) = 0x%x\n",
-				 ((rf == 0) ? 'A' : 'B'), writeval);
+			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+				"RTK better performance, writeval(%c) = 0x%x\n",
+				((rf == 0) ? 'A' : 'B'), writeval);
 			break;
 		case 1:
 			if (rtlphy->pwrgroup_cnt == 1) {
@@ -233,43 +240,41 @@
 				else if (channel == 14)
 					chnlgroup = 5;
 			}
-			writeval = rtlphy->mcs_offset[chnlgroup]
+
+			writeval =
+			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
 			    [index + (rf ? 8 : 0)] + ((index < 2) ?
 						      powerbase0[rf] :
 						      powerbase1[rf]);
 
-			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-				 "Realtek regulatory, 20MHz, "
-				 "writeval(%c) = 0x%x\n",
-				 ((rf == 0) ? 'A' : 'B'), writeval);
+			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+				"Realtek regulatory, 20MHz, writeval(%c) = 0x%x\n",
+				((rf == 0) ? 'A' : 'B'), writeval);
 
 			break;
 		case 2:
 			writeval =
 			    ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 
-			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-				 "Better regulatory, "
-				 "writeval(%c) = 0x%x\n",
-				 ((rf == 0) ? 'A' : 'B'), writeval);
+			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+				"Better regulatory, writeval(%c) = 0x%x\n",
+				((rf == 0) ? 'A' : 'B'), writeval);
 			break;
 		case 3:
 			chnlgroup = 0;
 
 			if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-					 "customer's limit, 40MHz "
-					 "rf(%c) = 0x%x\n",
-					 ((rf == 0) ? 'A' : 'B'),
-					 rtlefuse->pwrgroup_ht40[rf]
-					 [channel-1]);
+				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+					"customer's limit, 40MHz rf(%c) = 0x%x\n",
+					((rf == 0) ? 'A' : 'B'),
+					rtlefuse->pwrgroup_ht40
+					[rf][channel - 1]);
 			} else {
-				RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-					 "customer's limit, 20MHz "
-					 "rf(%c) = 0x%x\n",
-					 ((rf == 0) ? 'A' : 'B'),
-					 rtlefuse->pwrgroup_ht20[rf]
-					 [channel-1]);
+				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+					"customer's limit, 20MHz rf(%c) = 0x%x\n",
+					((rf == 0) ? 'A' : 'B'),
+					rtlefuse->pwrgroup_ht20
+					[rf][channel - 1]);
 			}
 
 			if (index < 2)
@@ -294,9 +299,9 @@
 
 			for (i = 0; i < 4; i++) {
 				pwr_diff_limit[i] =
-				    (u8)((rtlphy->mcs_offset
-					  [chnlgroup][index + (rf ? 8 : 0)] &
-					  (0x7f << (i * 8))) >> (i * 8));
+				    (u8)((rtlphy->mcs_txpwrlevel_origoffset
+					   [chnlgroup][index + (rf ? 8 : 0)] &
+					      (0x7f << (i * 8))) >> (i * 8));
 
 					if (pwr_diff_limit[i] > pwr_diff)
 						pwr_diff_limit[i] = pwr_diff;
@@ -307,29 +312,28 @@
 					 (pwr_diff_limit[1] << 8) |
 					 (pwr_diff_limit[0]);
 
-			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
 				"Customer's limit rf(%c) = 0x%x\n",
-				((rf == 0) ? 'A' : 'B'), customer_limit);
+				 ((rf == 0) ? 'A' : 'B'), customer_limit);
 
 			writeval = customer_limit + ((index < 2) ?
 						      powerbase0[rf] :
 						      powerbase1[rf]);
 
-			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-				 "Customer, writeval rf(%c)= 0x%x\n",
+			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+				"Customer, writeval rf(%c)= 0x%x\n",
 				 ((rf == 0) ? 'A' : 'B'), writeval);
 			break;
 		default:
 			chnlgroup = 0;
 			writeval =
-			    rtlphy->mcs_offset[chnlgroup]
+			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
 			    [index + (rf ? 8 : 0)]
 			    + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
 
-			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-				 "RTK better performance, writeval "
-				 "rf(%c) = 0x%x\n",
-				 ((rf == 0) ? 'A' : 'B'), writeval);
+			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+				"RTK better performance, writeval rf(%c) = 0x%x\n",
+				((rf == 0) ? 'A' : 'B'), writeval);
 			break;
 		}
 
@@ -343,7 +347,7 @@
 }
 
 static void _rtl8723be_write_ofdm_power_reg(struct ieee80211_hw *hw,
-					 u8 index, u32 *value)
+					 u8 index, u32 *pvalue)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u16 regoffset_a[6] = {
@@ -361,9 +365,9 @@
 	u16 regoffset;
 
 	for (rf = 0; rf < 2; rf++) {
-		writeval = value[rf];
+		writeval = pvalue[rf];
 		for (i = 0; i < 4; i++) {
-			pwr_val[i] = (u8) ((writeval & (0x7f <<
+			pwr_val[i] = (u8)((writeval & (0x7f <<
 							(i * 8))) >> (i * 8));
 
 			if (pwr_val[i] > RF6052_MAX_TX_PWR)
@@ -378,8 +382,8 @@
 			regoffset = regoffset_b[index];
 		rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);
 
-		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-			 "Set 0x%x = %08x\n", regoffset, writeval);
+		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+			"Set 0x%x = %08x\n", regoffset, writeval);
 	}
 }
 
@@ -400,8 +404,11 @@
 	rtl8723be_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
 
 	for (index = 0; index < 6; index++) {
-		txpwr_by_regulatory(hw, channel, index, &powerbase0[0],
-				    &powerbase1[0], &writeval[0]);
+		_rtl8723be_get_txpower_writeval_by_regulatory(hw,
+							      channel, index,
+							      &powerbase0[0],
+							      &powerbase1[0],
+							      &writeval[0]);
 		if (direction == 1) {
 			writeval[0] += pwrtrac_value;
 			writeval[1] += pwrtrac_value;
@@ -424,16 +431,17 @@
 		rtlphy->num_total_rfpath = 2;
 
 	return _rtl8723be_phy_rf6052_config_parafile(hw);
+
 }
 
 static bool _rtl8723be_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_phy *rtlphy = &(rtlpriv->phy);
-	struct bb_reg_def *pphyreg;
 	u32 u4_regvalue = 0;
 	u8 rfpath;
 	bool rtstatus = true;
+	struct bb_reg_def *pphyreg;
 
 	for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
 		pphyreg = &rtlphy->phyreg_def[rfpath];
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c
index 532913c..223eb42 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c
@@ -31,6 +31,7 @@
 #include "phy.h"
 #include "../rtl8723com/phy_common.h"
 #include "dm.h"
+#include "../rtl8723com/dm_common.h"
 #include "hw.h"
 #include "fw.h"
 #include "../rtl8723com/fw_common.h"
@@ -101,6 +102,8 @@
 	rtlpriv->dm.thermalvalue = 0;
 	rtlpci->transmit_config = CFENDFORM | BIT(15) | BIT(24) | BIT(25);
 
+	rtlpriv->phy.lck_inprogress = false;
+
 	mac->ht_enable = true;
 
 	/* compatible 5G band 88ce just 2.4G band & smsp */
@@ -137,12 +140,19 @@
 
 	rtlpci->irq_mask[1] = (u32)(IMR_RXFOVW | 0);
 
+	rtlpci->sys_irq_mask = (u32)(HSIMR_PDN_INT_EN	|
+				     HSIMR_RON_INT_EN	|
+				     0);
+
 	/* for debug level */
 	rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
 	/* for LPS & IPS */
 	rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
 	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
 	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
+	if (rtlpriv->cfg->mod_params->disable_watchdog)
+		pr_info("watchdog disabled\n");
 	rtlpriv->psc.reg_fwctrl_lps = 3;
 	rtlpriv->psc.reg_max_lps_awakeintvl = 5;
 	/* for ASPM, you can close aspm through
@@ -157,6 +167,11 @@
 	else if (rtlpriv->psc.reg_fwctrl_lps == 3)
 		rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
 
+	/*low power: Disable 32k */
+	rtlpriv->psc.low_power_enable = false;
+
+	rtlpriv->rtlhal.earlymode_enable = false;
+
 	/* for firmware buf */
 	rtlpriv->rtlhal.pfirmware = vzalloc(0x8000);
 	if (!rtlpriv->rtlhal.pfirmware) {
@@ -182,8 +197,6 @@
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-	if (rtlpriv->cfg->ops->get_btc_status())
-		rtlpriv->btcoexist.btc_ops->btc_halt_notify();
 	if (rtlpriv->rtlhal.pfirmware) {
 		vfree(rtlpriv->rtlhal.pfirmware);
 		rtlpriv->rtlhal.pfirmware = NULL;
@@ -196,7 +209,7 @@
 	return true;
 }
 
-static bool is_fw_header(struct rtl92c_firmware_header *hdr)
+static bool is_fw_header(struct rtl8723e_firmware_header *hdr)
 {
 	return (hdr->signature & 0xfff0) == 0x5300;
 }
@@ -245,6 +258,7 @@
 	.set_rfreg = rtl8723be_phy_set_rf_reg,
 	.fill_h2c_cmd = rtl8723be_fill_h2c_cmd,
 	.get_btc_status = rtl8723be_get_btc_status,
+	.rx_command_packet = rtl8723be_rx_command_packet,
 	.is_fw_header = is_fw_header,
 };
 
@@ -253,8 +267,6 @@
 	.inactiveps = true,
 	.swctrl_lps = false,
 	.fwctrl_lps = true,
-	.msi_support = false,
-	.debug = DBG_EMERG,
 };
 
 static struct rtl_hal_cfg rtl8723be_hal_cfg = {
@@ -272,6 +284,9 @@
 	.maps[MAC_RCR_ACRC32] = ACRC32,
 	.maps[MAC_RCR_ACF] = ACF,
 	.maps[MAC_RCR_AAP] = AAP,
+	.maps[MAC_HIMR] = REG_HIMR,
+	.maps[MAC_HIMRE] = REG_HIMRE,
+	.maps[MAC_HSISR] = REG_HSISR,
 
 	.maps[EFUSE_ACCESS] = REG_EFUSE_ACCESS,
 
@@ -305,6 +320,7 @@
 	.maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3,
 	.maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2,
 	.maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1,
+/*	.maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8,     */   /*need check*/
 	.maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7,
 	.maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6,
 	.maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5,
@@ -312,6 +328,8 @@
 	.maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3,
 	.maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2,
 	.maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1,
+/*	.maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2,*/
+/*	.maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1,*/
 
 	.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
 	.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
@@ -329,6 +347,7 @@
 	.maps[RTL_IMR_VIDOK] = IMR_VIDOK,
 	.maps[RTL_IMR_VODOK] = IMR_VODOK,
 	.maps[RTL_IMR_ROK] = IMR_ROK,
+	.maps[RTL_IMR_HSISR_IND] = IMR_HSISR_IND_ON_INT,
 	.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNDMAINT0 | IMR_TBDOK | IMR_TBDER),
 
 	.maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
@@ -348,12 +367,12 @@
 	.maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
 };
 
-static const struct pci_device_id rtl8723be_pci_id[] = {
-	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xb723, rtl8723be_hal_cfg)},
+static struct pci_device_id rtl8723be_pci_ids[] = {
+	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xB723, rtl8723be_hal_cfg)},
 	{},
 };
 
-MODULE_DEVICE_TABLE(pci, rtl8723be_pci_id);
+MODULE_DEVICE_TABLE(pci, rtl8723be_pci_ids);
 
 MODULE_AUTHOR("PageHe	<page_he@realsil.com.cn>");
 MODULE_AUTHOR("Realtek WlanFAE	<wlanfae@realtek.com>");
@@ -366,21 +385,22 @@
 module_param_named(ips, rtl8723be_mod_params.inactiveps, bool, 0444);
 module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444);
 module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444);
-module_param_named(msi, rtl8723be_mod_params.msi_support, bool, 0444);
+module_param_named(disable_watchdog, rtl8723be_mod_params.disable_watchdog,
+		   bool, 0444);
 MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
 MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
 MODULE_PARM_DESC(fwlps, "using linked fw control power save (default 1 is open)\n");
 MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 0)\n");
 MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n");
 
 static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
 
 static struct pci_driver rtl8723be_driver = {
 	.name = KBUILD_MODNAME,
-	.id_table = rtl8723be_pci_id,
+	.id_table = rtl8723be_pci_ids,
 	.probe = rtl_pci_probe,
 	.remove = rtl_pci_disconnect,
-
 	.driver.pm = &rtlwifi_pm_ops,
 };
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/table.c b/drivers/net/wireless/rtlwifi/rtl8723be/table.c
index 4b283cd..a180761 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/table.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/table.c
@@ -27,200 +27,201 @@
 
 #include "table.h"
 u32 RTL8723BEPHY_REG_1TARRAY[] = {
-	0x800, 0x80040000,
-	0x804, 0x00000003,
-	0x808, 0x0000FC00,
-	0x80C, 0x0000000A,
-	0x810, 0x10001331,
-	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, 0x569A11A9,
-	0x85C, 0x01000014,
-	0x860, 0x66F60110,
-	0x864, 0x061F0649,
-	0x868, 0x00000000,
-	0x86C, 0x27272700,
-	0x870, 0x07000760,
-	0x874, 0x25004000,
-	0x878, 0x00000808,
-	0x87C, 0x00000000,
-	0x880, 0xB0000C1C,
-	0x884, 0x00000001,
-	0x888, 0x00000000,
-	0x88C, 0xCCC000C0,
-	0x890, 0x00000800,
-	0x894, 0xFFFFFFFE,
-	0x898, 0x40302010,
-	0x89C, 0x00706050,
-	0x900, 0x00000000,
-	0x904, 0x00000023,
-	0x908, 0x00000000,
-	0x90C, 0x81121111,
-	0x910, 0x00000002,
-	0x914, 0x00000201,
-	0x948, 0x00000000,
-	0xA00, 0x00D047C8,
-	0xA04, 0x80FF000C,
-	0xA08, 0x8C838300,
-	0xA0C, 0x2E7F120F,
-	0xA10, 0x9500BB78,
-	0xA14, 0x1114D028,
-	0xA18, 0x00881117,
-	0xA1C, 0x89140F00,
-	0xA20, 0x1A1B0000,
-	0xA24, 0x090E1317,
-	0xA28, 0x00000204,
-	0xA2C, 0x00D30000,
-	0xA70, 0x101FBF00,
-	0xA74, 0x00000007,
-	0xA78, 0x00000900,
-	0xA7C, 0x225B0606,
-	0xA80, 0x21806490,
-	0xB2C, 0x00000000,
-	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, 0x69553420,
-	0xC54, 0x43BC0094,
-	0xC58, 0x00023169,
-	0xC5C, 0x00250492,
-	0xC60, 0x00000000,
-	0xC64, 0x7112848B,
-	0xC68, 0x47C00BFF,
-	0xC6C, 0x00000036,
-	0xC70, 0x2C7F000D,
-	0xC74, 0x020610DB,
-	0xC78, 0x0000001F,
-	0xC7C, 0x00B91612,
-	0xC80, 0x390000E4,
-	0xC84, 0x20F60000,
-	0xC88, 0x40000100,
-	0xC8C, 0x20200000,
-	0xC90, 0x00020E1A,
-	0xC94, 0x00000000,
-	0xC98, 0x00020E1A,
-	0xC9C, 0x00007F7F,
-	0xCA0, 0x00000000,
-	0xCA4, 0x000300A0,
-	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, 0x00000740,
-	0xD04, 0x40020401,
-	0xD08, 0x0000907F,
-	0xD0C, 0x20010201,
-	0xD10, 0xA0633333,
-	0xD14, 0x3333BC53,
-	0xD18, 0x7A8F5B6F,
-	0xD2C, 0xCC979975,
-	0xD30, 0x00000000,
-	0xD34, 0x80608000,
-	0xD38, 0x00000000,
-	0xD3C, 0x00127353,
-	0xD40, 0x00000000,
-	0xD44, 0x00000000,
-	0xD48, 0x00000000,
-	0xD4C, 0x00000000,
-	0xD50, 0x6437140A,
-	0xD54, 0x00000000,
-	0xD58, 0x00000282,
-	0xD5C, 0x30032064,
-	0xD60, 0x4653DE68,
-	0xD64, 0x04518A3C,
-	0xD68, 0x00002101,
-	0xD6C, 0x2A201C16,
-	0xD70, 0x1812362E,
-	0xD74, 0x322C2220,
-	0xD78, 0x000E3C24,
-	0xE00, 0x2D2D2D2D,
-	0xE04, 0x2D2D2D2D,
-	0xE08, 0x0390272D,
-	0xE10, 0x2D2D2D2D,
-	0xE14, 0x2D2D2D2D,
-	0xE18, 0x2D2D2D2D,
-	0xE1C, 0x2D2D2D2D,
-	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, 0x001B2556,
-	0xE6C, 0x00C00096,
-	0xE70, 0x00C00096,
-	0xE74, 0x01000056,
-	0xE78, 0x01000014,
-	0xE7C, 0x01000056,
-	0xE80, 0x01000014,
-	0xE84, 0x00C00096,
-	0xE88, 0x01000056,
-	0xE8C, 0x00C00096,
-	0xED0, 0x00C00096,
-	0xED4, 0x00C00096,
-	0xED8, 0x00C00096,
-	0xEDC, 0x000000D6,
-	0xEE0, 0x000000D6,
-	0xEEC, 0x01C00016,
-	0xF14, 0x00000003,
-	0xF4C, 0x00000000,
-	0xF00, 0x00000300,
-	0x820, 0x01000100,
-	0x800, 0x83040000,
+		0x800, 0x80040000,
+		0x804, 0x00000003,
+		0x808, 0x0000FC00,
+		0x80C, 0x0000000A,
+		0x810, 0x10001331,
+		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, 0x569A11A9,
+		0x85C, 0x01000014,
+		0x860, 0x66F60110,
+		0x864, 0x061F0649,
+		0x868, 0x00000000,
+		0x86C, 0x27272700,
+		0x870, 0x07000760,
+		0x874, 0x25004000,
+		0x878, 0x00000808,
+		0x87C, 0x00000000,
+		0x880, 0xB0000C1C,
+		0x884, 0x00000001,
+		0x888, 0x00000000,
+		0x88C, 0xCCC000C0,
+		0x890, 0x00000800,
+		0x894, 0xFFFFFFFE,
+		0x898, 0x40302010,
+		0x89C, 0x00706050,
+		0x900, 0x00000000,
+		0x904, 0x00000023,
+		0x908, 0x00000000,
+		0x90C, 0x81121111,
+		0x910, 0x00000002,
+		0x914, 0x00000201,
+		0x948, 0x00000280,
+		0xA00, 0x00D047C8,
+		0xA04, 0x80FF000C,
+		0xA08, 0x8C838300,
+		0xA0C, 0x2E7F120F,
+		0xA10, 0x9500BB78,
+		0xA14, 0x1114D028,
+		0xA18, 0x00881117,
+		0xA1C, 0x89140F00,
+		0xA20, 0x1A1B0000,
+		0xA24, 0x090E1317,
+		0xA28, 0x00000204,
+		0xA2C, 0x00D30000,
+		0xA70, 0x101FBF00,
+		0xA74, 0x00000007,
+		0xA78, 0x00000900,
+		0xA7C, 0x225B0606,
+		0xA80, 0x21806490,
+		0xB2C, 0x00000000,
+		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, 0x69553420,
+		0xC54, 0x43BC0094,
+		0xC58, 0x00023169,
+		0xC5C, 0x00250492,
+		0xC60, 0x00000000,
+		0xC64, 0x7112848B,
+		0xC68, 0x47C00BFF,
+		0xC6C, 0x00000036,
+		0xC70, 0x2C7F000D,
+		0xC74, 0x020610DB,
+		0xC78, 0x0000001F,
+		0xC7C, 0x00B91612,
+		0xC80, 0x390000E4,
+		0xC84, 0x20F60000,
+		0xC88, 0x40000100,
+		0xC8C, 0x20200000,
+		0xC90, 0x00020E1A,
+		0xC94, 0x00000000,
+		0xC98, 0x00020E1A,
+		0xC9C, 0x00007F7F,
+		0xCA0, 0x00000000,
+		0xCA4, 0x000300A0,
+		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, 0x00000740,
+		0xD04, 0x40020401,
+		0xD08, 0x0000907F,
+		0xD0C, 0x20010201,
+		0xD10, 0xA0633333,
+		0xD14, 0x3333BC53,
+		0xD18, 0x7A8F5B6F,
+		0xD2C, 0xCC979975,
+		0xD30, 0x00000000,
+		0xD34, 0x80608000,
+		0xD38, 0x00000000,
+		0xD3C, 0x00127353,
+		0xD40, 0x00000000,
+		0xD44, 0x00000000,
+		0xD48, 0x00000000,
+		0xD4C, 0x00000000,
+		0xD50, 0x6437140A,
+		0xD54, 0x00000000,
+		0xD58, 0x00000282,
+		0xD5C, 0x30032064,
+		0xD60, 0x4653DE68,
+		0xD64, 0x04518A3C,
+		0xD68, 0x00002101,
+		0xD6C, 0x2A201C16,
+		0xD70, 0x1812362E,
+		0xD74, 0x322C2220,
+		0xD78, 0x000E3C24,
+		0xE00, 0x2D2D2D2D,
+		0xE04, 0x2D2D2D2D,
+		0xE08, 0x0390272D,
+		0xE10, 0x2D2D2D2D,
+		0xE14, 0x2D2D2D2D,
+		0xE18, 0x2D2D2D2D,
+		0xE1C, 0x2D2D2D2D,
+		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, 0x001B2556,
+		0xE6C, 0x00C00096,
+		0xE70, 0x00C00096,
+		0xE74, 0x01000056,
+		0xE78, 0x01000014,
+		0xE7C, 0x01000056,
+		0xE80, 0x01000014,
+		0xE84, 0x00C00096,
+		0xE88, 0x01000056,
+		0xE8C, 0x00C00096,
+		0xED0, 0x00C00096,
+		0xED4, 0x00C00096,
+		0xED8, 0x00C00096,
+		0xEDC, 0x000000D6,
+		0xEE0, 0x000000D6,
+		0xEEC, 0x01C00016,
+		0xF14, 0x00000003,
+		0xF4C, 0x00000000,
+		0xF00, 0x00000300,
+		0x820, 0x01000100,
+		0x800, 0x83040000,
+
 };
 
 u32 RTL8723BEPHY_REG_ARRAY_PG[] = {
@@ -233,340 +234,344 @@
 };
 
 u32 RTL8723BE_RADIOA_1TARRAY[] = {
-	0x000, 0x00010000,
-	0x0B0, 0x000DFFE0,
-	0x0FE, 0x00000000,
-	0x0FE, 0x00000000,
-	0x0FE, 0x00000000,
-	0x0B1, 0x00000018,
-	0x0FE, 0x00000000,
-	0x0FE, 0x00000000,
-	0x0FE, 0x00000000,
-	0x0B2, 0x00084C00,
-	0x0B5, 0x0000D2CC,
-	0x0B6, 0x000925AA,
-	0x0B7, 0x00000010,
-	0x0B8, 0x0000907F,
-	0x05C, 0x00000002,
-	0x07C, 0x00000002,
-	0x07E, 0x00000005,
-	0x08B, 0x0006FC00,
-	0x0B0, 0x000FF9F0,
-	0x01C, 0x000739D2,
-	0x01E, 0x00000000,
-	0x0DF, 0x00000780,
-	0x050, 0x00067435,
-	0x051, 0x0006B04E,
-	0x052, 0x000007D2,
-	0x053, 0x00000000,
-	0x054, 0x00050400,
-	0x055, 0x0004026E,
-	0x0DD, 0x0000004C,
-	0x070, 0x00067435,
-	0x071, 0x0006B04E,
-	0x072, 0x000007D2,
-	0x073, 0x00000000,
-	0x074, 0x00050400,
-	0x075, 0x0004026E,
-	0x0EF, 0x00000100,
-	0x034, 0x0000ADD7,
-	0x035, 0x00005C00,
-	0x034, 0x00009DD4,
-	0x035, 0x00005000,
-	0x034, 0x00008DD1,
-	0x035, 0x00004400,
-	0x034, 0x00007DCE,
-	0x035, 0x00003800,
-	0x034, 0x00006CD1,
-	0x035, 0x00004400,
-	0x034, 0x00005CCE,
-	0x035, 0x00003800,
-	0x034, 0x000048CE,
-	0x035, 0x00004400,
-	0x034, 0x000034CE,
-	0x035, 0x00003800,
-	0x034, 0x00002451,
-	0x035, 0x00004400,
-	0x034, 0x0000144E,
-	0x035, 0x00003800,
-	0x034, 0x00000051,
-	0x035, 0x00004400,
-	0x0EF, 0x00000000,
-	0x0EF, 0x00000100,
-	0x0ED, 0x00000010,
-	0x044, 0x0000ADD7,
-	0x044, 0x00009DD4,
-	0x044, 0x00008DD1,
-	0x044, 0x00007DCE,
-	0x044, 0x00006CC1,
-	0x044, 0x00005CCE,
-	0x044, 0x000044D1,
-	0x044, 0x000034CE,
-	0x044, 0x00002451,
-	0x044, 0x0000144E,
-	0x044, 0x00000051,
-	0x0EF, 0x00000000,
-	0x0ED, 0x00000000,
-	0x0EF, 0x00002000,
-	0x03B, 0x000380EF,
-	0x03B, 0x000302FE,
-	0x03B, 0x00028CE6,
-	0x03B, 0x000200BC,
-	0x03B, 0x000188A5,
-	0x03B, 0x00010FBC,
-	0x03B, 0x00008F71,
-	0x03B, 0x00000900,
-	0x0EF, 0x00000000,
-	0x0ED, 0x00000001,
-	0x040, 0x000380EF,
-	0x040, 0x000302FE,
-	0x040, 0x00028CE6,
-	0x040, 0x000200BC,
-	0x040, 0x000188A5,
-	0x040, 0x00010FBC,
-	0x040, 0x00008F71,
-	0x040, 0x00000900,
-	0x0ED, 0x00000000,
-	0x082, 0x00080000,
-	0x083, 0x00008000,
-	0x084, 0x00048D80,
-	0x085, 0x00068000,
-	0x0A2, 0x00080000,
-	0x0A3, 0x00008000,
-	0x0A4, 0x00048D80,
-	0x0A5, 0x00068000,
-	0x000, 0x00033D80,
+		0x000, 0x00010000,
+		0x0B0, 0x000DFFE0,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x0B1, 0x00000018,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x0B2, 0x00084C00,
+		0x0B5, 0x0000D2CC,
+		0x0B6, 0x000925AA,
+		0x0B7, 0x00000010,
+		0x0B8, 0x0000907F,
+		0x05C, 0x00000002,
+		0x07C, 0x00000002,
+		0x07E, 0x00000005,
+		0x08B, 0x0006FC00,
+		0x0B0, 0x000FF9F0,
+		0x01C, 0x000739D2,
+		0x01E, 0x00000000,
+		0x0DF, 0x00000780,
+		0x050, 0x00067435,
+		0x051, 0x0006B04E,
+		0x052, 0x000007D2,
+		0x053, 0x00000000,
+		0x054, 0x00050400,
+		0x055, 0x0004026E,
+		0x0DD, 0x0000004C,
+		0x070, 0x00067435,
+		0x071, 0x0006B04E,
+		0x072, 0x000007D2,
+		0x073, 0x00000000,
+		0x074, 0x00050400,
+		0x075, 0x0004026E,
+		0x0EF, 0x00000100,
+		0x034, 0x0000ADD7,
+		0x035, 0x00005C00,
+		0x034, 0x00009DD4,
+		0x035, 0x00005000,
+		0x034, 0x00008DD1,
+		0x035, 0x00004400,
+		0x034, 0x00007DCE,
+		0x035, 0x00003800,
+		0x034, 0x00006CD1,
+		0x035, 0x00004400,
+		0x034, 0x00005CCE,
+		0x035, 0x00003800,
+		0x034, 0x000048CE,
+		0x035, 0x00004400,
+		0x034, 0x000034CE,
+		0x035, 0x00003800,
+		0x034, 0x00002451,
+		0x035, 0x00004400,
+		0x034, 0x0000144E,
+		0x035, 0x00003800,
+		0x034, 0x00000051,
+		0x035, 0x00004400,
+		0x0EF, 0x00000000,
+		0x0EF, 0x00000100,
+		0x0ED, 0x00000010,
+		0x044, 0x0000ADD7,
+		0x044, 0x00009DD4,
+		0x044, 0x00008DD1,
+		0x044, 0x00007DCE,
+		0x044, 0x00006CC1,
+		0x044, 0x00005CCE,
+		0x044, 0x000044D1,
+		0x044, 0x000034CE,
+		0x044, 0x00002451,
+		0x044, 0x0000144E,
+		0x044, 0x00000051,
+		0x0EF, 0x00000000,
+		0x0ED, 0x00000000,
+		0x0EF, 0x00002000,
+		0x03B, 0x000380EF,
+		0x03B, 0x000302FE,
+		0x03B, 0x00028CE6,
+		0x03B, 0x000200BC,
+		0x03B, 0x000188A5,
+		0x03B, 0x00010FBC,
+		0x03B, 0x00008F71,
+		0x03B, 0x00000900,
+		0x0EF, 0x00000000,
+		0x0ED, 0x00000001,
+		0x040, 0x000380EF,
+		0x040, 0x000302FE,
+		0x040, 0x00028CE6,
+		0x040, 0x000200BC,
+		0x040, 0x000188A5,
+		0x040, 0x00010FBC,
+		0x040, 0x00008F71,
+		0x040, 0x00000900,
+		0x0ED, 0x00000000,
+		0x082, 0x00080000,
+		0x083, 0x00008000,
+		0x084, 0x00048D80,
+		0x085, 0x00068000,
+		0x0A2, 0x00080000,
+		0x0A3, 0x00008000,
+		0x0A4, 0x00048D80,
+		0x0A5, 0x00068000,
+		0x000, 0x00033D80,
+
 };
 
 u32 RTL8723BEMAC_1T_ARRAY[] = {
-	0x02F, 0x00000030,
-	0x035, 0x00000000,
-	0x428, 0x0000000A,
-	0x429, 0x00000010,
-	0x430, 0x00000000,
-	0x431, 0x00000000,
-	0x432, 0x00000000,
-	0x433, 0x00000001,
-	0x434, 0x00000004,
-	0x435, 0x00000005,
-	0x436, 0x00000007,
-	0x437, 0x00000008,
-	0x43C, 0x00000004,
-	0x43D, 0x00000005,
-	0x43E, 0x00000007,
-	0x43F, 0x00000008,
-	0x440, 0x0000005D,
-	0x441, 0x00000001,
-	0x442, 0x00000000,
-	0x444, 0x00000010,
-	0x445, 0x00000000,
-	0x446, 0x00000000,
-	0x447, 0x00000000,
-	0x448, 0x00000000,
-	0x449, 0x000000F0,
-	0x44A, 0x0000000F,
-	0x44B, 0x0000003E,
-	0x44C, 0x00000010,
-	0x44D, 0x00000000,
-	0x44E, 0x00000000,
-	0x44F, 0x00000000,
-	0x450, 0x00000000,
-	0x451, 0x000000F0,
-	0x452, 0x0000000F,
-	0x453, 0x00000000,
-	0x456, 0x0000005E,
-	0x460, 0x00000066,
-	0x461, 0x00000066,
-	0x4C8, 0x000000FF,
-	0x4C9, 0x00000008,
-	0x4CC, 0x000000FF,
-	0x4CD, 0x000000FF,
-	0x4CE, 0x00000001,
-	0x500, 0x00000026,
-	0x501, 0x000000A2,
-	0x502, 0x0000002F,
-	0x503, 0x00000000,
-	0x504, 0x00000028,
-	0x505, 0x000000A3,
-	0x506, 0x0000005E,
-	0x507, 0x00000000,
-	0x508, 0x0000002B,
-	0x509, 0x000000A4,
-	0x50A, 0x0000005E,
-	0x50B, 0x00000000,
-	0x50C, 0x0000004F,
-	0x50D, 0x000000A4,
-	0x50E, 0x00000000,
-	0x50F, 0x00000000,
-	0x512, 0x0000001C,
-	0x514, 0x0000000A,
-	0x516, 0x0000000A,
-	0x525, 0x0000004F,
-	0x550, 0x00000010,
-	0x551, 0x00000010,
-	0x559, 0x00000002,
-	0x55C, 0x00000050,
-	0x55D, 0x000000FF,
-	0x605, 0x00000030,
-	0x608, 0x0000000E,
-	0x609, 0x0000002A,
-	0x620, 0x000000FF,
-	0x621, 0x000000FF,
-	0x622, 0x000000FF,
-	0x623, 0x000000FF,
-	0x624, 0x000000FF,
-	0x625, 0x000000FF,
-	0x626, 0x000000FF,
-	0x627, 0x000000FF,
-	0x638, 0x00000050,
-	0x63C, 0x0000000A,
-	0x63D, 0x0000000A,
-	0x63E, 0x0000000E,
-	0x63F, 0x0000000E,
-	0x640, 0x00000040,
-	0x642, 0x00000040,
-	0x643, 0x00000000,
-	0x652, 0x000000C8,
-	0x66E, 0x00000005,
-	0x700, 0x00000021,
-	0x701, 0x00000043,
-	0x702, 0x00000065,
-	0x703, 0x00000087,
-	0x708, 0x00000021,
-	0x709, 0x00000043,
-	0x70A, 0x00000065,
-	0x70B, 0x00000087,
+		0x02F, 0x00000030,
+		0x035, 0x00000000,
+		0x067, 0x00000020,
+		0x428, 0x0000000A,
+		0x429, 0x00000010,
+		0x430, 0x00000000,
+		0x431, 0x00000000,
+		0x432, 0x00000000,
+		0x433, 0x00000001,
+		0x434, 0x00000004,
+		0x435, 0x00000005,
+		0x436, 0x00000007,
+		0x437, 0x00000008,
+		0x43C, 0x00000004,
+		0x43D, 0x00000005,
+		0x43E, 0x00000007,
+		0x43F, 0x00000008,
+		0x440, 0x0000005D,
+		0x441, 0x00000001,
+		0x442, 0x00000000,
+		0x444, 0x00000010,
+		0x445, 0x00000000,
+		0x446, 0x00000000,
+		0x447, 0x00000000,
+		0x448, 0x00000000,
+		0x449, 0x000000F0,
+		0x44A, 0x0000000F,
+		0x44B, 0x0000003E,
+		0x44C, 0x00000010,
+		0x44D, 0x00000000,
+		0x44E, 0x00000000,
+		0x44F, 0x00000000,
+		0x450, 0x00000000,
+		0x451, 0x000000F0,
+		0x452, 0x0000000F,
+		0x453, 0x00000000,
+		0x456, 0x0000005E,
+		0x460, 0x00000066,
+		0x461, 0x00000066,
+		0x4C8, 0x000000FF,
+		0x4C9, 0x00000008,
+		0x4CC, 0x000000FF,
+		0x4CD, 0x000000FF,
+		0x4CE, 0x00000001,
+		0x500, 0x00000026,
+		0x501, 0x000000A2,
+		0x502, 0x0000002F,
+		0x503, 0x00000000,
+		0x504, 0x00000028,
+		0x505, 0x000000A3,
+		0x506, 0x0000005E,
+		0x507, 0x00000000,
+		0x508, 0x0000002B,
+		0x509, 0x000000A4,
+		0x50A, 0x0000005E,
+		0x50B, 0x00000000,
+		0x50C, 0x0000004F,
+		0x50D, 0x000000A4,
+		0x50E, 0x00000000,
+		0x50F, 0x00000000,
+		0x512, 0x0000001C,
+		0x514, 0x0000000A,
+		0x516, 0x0000000A,
+		0x525, 0x0000004F,
+		0x550, 0x00000010,
+		0x551, 0x00000010,
+		0x559, 0x00000002,
+		0x55C, 0x00000050,
+		0x55D, 0x000000FF,
+		0x605, 0x00000030,
+		0x608, 0x0000000E,
+		0x609, 0x0000002A,
+		0x620, 0x000000FF,
+		0x621, 0x000000FF,
+		0x622, 0x000000FF,
+		0x623, 0x000000FF,
+		0x624, 0x000000FF,
+		0x625, 0x000000FF,
+		0x626, 0x000000FF,
+		0x627, 0x000000FF,
+		0x638, 0x00000050,
+		0x63C, 0x0000000A,
+		0x63D, 0x0000000A,
+		0x63E, 0x0000000E,
+		0x63F, 0x0000000E,
+		0x640, 0x00000040,
+		0x642, 0x00000040,
+		0x643, 0x00000000,
+		0x652, 0x000000C8,
+		0x66E, 0x00000005,
+		0x700, 0x00000021,
+		0x701, 0x00000043,
+		0x702, 0x00000065,
+		0x703, 0x00000087,
+		0x708, 0x00000021,
+		0x709, 0x00000043,
+		0x70A, 0x00000065,
+		0x70B, 0x00000087,
+
 };
 
 u32 RTL8723BEAGCTAB_1TARRAY[] = {
-	0xC78, 0xFD000001,
-	0xC78, 0xFC010001,
-	0xC78, 0xFB020001,
-	0xC78, 0xFA030001,
-	0xC78, 0xF9040001,
-	0xC78, 0xF8050001,
-	0xC78, 0xF7060001,
-	0xC78, 0xF6070001,
-	0xC78, 0xF5080001,
-	0xC78, 0xF4090001,
-	0xC78, 0xF30A0001,
-	0xC78, 0xF20B0001,
-	0xC78, 0xF10C0001,
-	0xC78, 0xF00D0001,
-	0xC78, 0xEF0E0001,
-	0xC78, 0xEE0F0001,
-	0xC78, 0xED100001,
-	0xC78, 0xEC110001,
-	0xC78, 0xEB120001,
-	0xC78, 0xEA130001,
-	0xC78, 0xE9140001,
-	0xC78, 0xE8150001,
-	0xC78, 0xE7160001,
-	0xC78, 0xAA170001,
-	0xC78, 0xA9180001,
-	0xC78, 0xA8190001,
-	0xC78, 0xA71A0001,
-	0xC78, 0xA61B0001,
-	0xC78, 0xA51C0001,
-	0xC78, 0xA41D0001,
-	0xC78, 0xA31E0001,
-	0xC78, 0x671F0001,
-	0xC78, 0x66200001,
-	0xC78, 0x65210001,
-	0xC78, 0x64220001,
-	0xC78, 0x63230001,
-	0xC78, 0x62240001,
-	0xC78, 0x61250001,
-	0xC78, 0x47260001,
-	0xC78, 0x46270001,
-	0xC78, 0x45280001,
-	0xC78, 0x44290001,
-	0xC78, 0x432A0001,
-	0xC78, 0x422B0001,
-	0xC78, 0x292C0001,
-	0xC78, 0x282D0001,
-	0xC78, 0x272E0001,
-	0xC78, 0x262F0001,
-	0xC78, 0x25300001,
-	0xC78, 0x24310001,
-	0xC78, 0x09320001,
-	0xC78, 0x08330001,
-	0xC78, 0x07340001,
-	0xC78, 0x06350001,
-	0xC78, 0x05360001,
-	0xC78, 0x04370001,
-	0xC78, 0x03380001,
-	0xC78, 0x02390001,
-	0xC78, 0x013A0001,
-	0xC78, 0x003B0001,
-	0xC78, 0x003C0001,
-	0xC78, 0x003D0001,
-	0xC78, 0x003E0001,
-	0xC78, 0x003F0001,
-	0xC78, 0xFC400001,
-	0xC78, 0xFB410001,
-	0xC78, 0xFA420001,
-	0xC78, 0xF9430001,
-	0xC78, 0xF8440001,
-	0xC78, 0xF7450001,
-	0xC78, 0xF6460001,
-	0xC78, 0xF5470001,
-	0xC78, 0xF4480001,
-	0xC78, 0xF3490001,
-	0xC78, 0xF24A0001,
-	0xC78, 0xF14B0001,
-	0xC78, 0xF04C0001,
-	0xC78, 0xEF4D0001,
-	0xC78, 0xEE4E0001,
-	0xC78, 0xED4F0001,
-	0xC78, 0xEC500001,
-	0xC78, 0xEB510001,
-	0xC78, 0xEA520001,
-	0xC78, 0xE9530001,
-	0xC78, 0xE8540001,
-	0xC78, 0xE7550001,
-	0xC78, 0xE6560001,
-	0xC78, 0xE5570001,
-	0xC78, 0xAA580001,
-	0xC78, 0xA9590001,
-	0xC78, 0xA85A0001,
-	0xC78, 0xA75B0001,
-	0xC78, 0xA65C0001,
-	0xC78, 0xA55D0001,
-	0xC78, 0xA45E0001,
-	0xC78, 0x675F0001,
-	0xC78, 0x66600001,
-	0xC78, 0x65610001,
-	0xC78, 0x64620001,
-	0xC78, 0x63630001,
-	0xC78, 0x62640001,
-	0xC78, 0x61650001,
-	0xC78, 0x47660001,
-	0xC78, 0x46670001,
-	0xC78, 0x45680001,
-	0xC78, 0x44690001,
-	0xC78, 0x436A0001,
-	0xC78, 0x426B0001,
-	0xC78, 0x296C0001,
-	0xC78, 0x286D0001,
-	0xC78, 0x276E0001,
-	0xC78, 0x266F0001,
-	0xC78, 0x25700001,
-	0xC78, 0x24710001,
-	0xC78, 0x09720001,
-	0xC78, 0x08730001,
-	0xC78, 0x07740001,
-	0xC78, 0x06750001,
-	0xC78, 0x05760001,
-	0xC78, 0x04770001,
-	0xC78, 0x03780001,
-	0xC78, 0x02790001,
-	0xC78, 0x017A0001,
-	0xC78, 0x007B0001,
-	0xC78, 0x007C0001,
-	0xC78, 0x007D0001,
-	0xC78, 0x007E0001,
-	0xC78, 0x007F0001,
-	0xC50, 0x69553422,
-	0xC50, 0x69553420,
+		0xC78, 0xFD000001,
+		0xC78, 0xFC010001,
+		0xC78, 0xFB020001,
+		0xC78, 0xFA030001,
+		0xC78, 0xF9040001,
+		0xC78, 0xF8050001,
+		0xC78, 0xF7060001,
+		0xC78, 0xF6070001,
+		0xC78, 0xF5080001,
+		0xC78, 0xF4090001,
+		0xC78, 0xF30A0001,
+		0xC78, 0xF20B0001,
+		0xC78, 0xF10C0001,
+		0xC78, 0xF00D0001,
+		0xC78, 0xEF0E0001,
+		0xC78, 0xEE0F0001,
+		0xC78, 0xED100001,
+		0xC78, 0xEC110001,
+		0xC78, 0xEB120001,
+		0xC78, 0xEA130001,
+		0xC78, 0xE9140001,
+		0xC78, 0xE8150001,
+		0xC78, 0xE7160001,
+		0xC78, 0xAA170001,
+		0xC78, 0xA9180001,
+		0xC78, 0xA8190001,
+		0xC78, 0xA71A0001,
+		0xC78, 0xA61B0001,
+		0xC78, 0xA51C0001,
+		0xC78, 0xA41D0001,
+		0xC78, 0xA31E0001,
+		0xC78, 0x671F0001,
+		0xC78, 0x66200001,
+		0xC78, 0x65210001,
+		0xC78, 0x64220001,
+		0xC78, 0x63230001,
+		0xC78, 0x62240001,
+		0xC78, 0x61250001,
+		0xC78, 0x47260001,
+		0xC78, 0x46270001,
+		0xC78, 0x45280001,
+		0xC78, 0x44290001,
+		0xC78, 0x432A0001,
+		0xC78, 0x422B0001,
+		0xC78, 0x292C0001,
+		0xC78, 0x282D0001,
+		0xC78, 0x272E0001,
+		0xC78, 0x262F0001,
+		0xC78, 0x25300001,
+		0xC78, 0x24310001,
+		0xC78, 0x09320001,
+		0xC78, 0x08330001,
+		0xC78, 0x07340001,
+		0xC78, 0x06350001,
+		0xC78, 0x05360001,
+		0xC78, 0x04370001,
+		0xC78, 0x03380001,
+		0xC78, 0x02390001,
+		0xC78, 0x013A0001,
+		0xC78, 0x003B0001,
+		0xC78, 0x003C0001,
+		0xC78, 0x003D0001,
+		0xC78, 0x003E0001,
+		0xC78, 0x003F0001,
+		0xC78, 0xFC400001,
+		0xC78, 0xFB410001,
+		0xC78, 0xFA420001,
+		0xC78, 0xF9430001,
+		0xC78, 0xF8440001,
+		0xC78, 0xF7450001,
+		0xC78, 0xF6460001,
+		0xC78, 0xF5470001,
+		0xC78, 0xF4480001,
+		0xC78, 0xF3490001,
+		0xC78, 0xF24A0001,
+		0xC78, 0xF14B0001,
+		0xC78, 0xF04C0001,
+		0xC78, 0xEF4D0001,
+		0xC78, 0xEE4E0001,
+		0xC78, 0xED4F0001,
+		0xC78, 0xEC500001,
+		0xC78, 0xEB510001,
+		0xC78, 0xEA520001,
+		0xC78, 0xE9530001,
+		0xC78, 0xE8540001,
+		0xC78, 0xE7550001,
+		0xC78, 0xE6560001,
+		0xC78, 0xE5570001,
+		0xC78, 0xAA580001,
+		0xC78, 0xA9590001,
+		0xC78, 0xA85A0001,
+		0xC78, 0xA75B0001,
+		0xC78, 0xA65C0001,
+		0xC78, 0xA55D0001,
+		0xC78, 0xA45E0001,
+		0xC78, 0x675F0001,
+		0xC78, 0x66600001,
+		0xC78, 0x65610001,
+		0xC78, 0x64620001,
+		0xC78, 0x63630001,
+		0xC78, 0x62640001,
+		0xC78, 0x61650001,
+		0xC78, 0x47660001,
+		0xC78, 0x46670001,
+		0xC78, 0x45680001,
+		0xC78, 0x44690001,
+		0xC78, 0x436A0001,
+		0xC78, 0x426B0001,
+		0xC78, 0x296C0001,
+		0xC78, 0x286D0001,
+		0xC78, 0x276E0001,
+		0xC78, 0x266F0001,
+		0xC78, 0x25700001,
+		0xC78, 0x24710001,
+		0xC78, 0x09720001,
+		0xC78, 0x08730001,
+		0xC78, 0x07740001,
+		0xC78, 0x06750001,
+		0xC78, 0x05760001,
+		0xC78, 0x04770001,
+		0xC78, 0x03780001,
+		0xC78, 0x02790001,
+		0xC78, 0x017A0001,
+		0xC78, 0x007B0001,
+		0xC78, 0x007C0001,
+		0xC78, 0x007D0001,
+		0xC78, 0x007E0001,
+		0xC78, 0x007F0001,
+		0xC50, 0x69553422,
+		0xC50, 0x69553420,
+
 };
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/table.h b/drivers/net/wireless/rtlwifi/rtl8723be/table.h
index 932760a..dc17001 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/table.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/table.h
@@ -35,7 +35,7 @@
 extern u32 RTL8723BEPHY_REG_ARRAY_PG[];
 #define	RTL8723BE_RADIOA_1TARRAYLEN	206
 extern u32 RTL8723BE_RADIOA_1TARRAY[];
-#define RTL8723BEMAC_1T_ARRAYLEN	194
+#define RTL8723BEMAC_1T_ARRAYLEN	196
 extern u32 RTL8723BEMAC_1T_ARRAY[];
 #define RTL8723BEAGCTAB_1TARRAYLEN	260
 extern u32 RTL8723BEAGCTAB_1TARRAY[];
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c
index 969eaea..d6a1c70 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c
@@ -33,6 +33,7 @@
 #include "trx.h"
 #include "led.h"
 #include "dm.h"
+#include "fw.h"
 
 static u8 _rtl8723be_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
 {
@@ -207,196 +208,150 @@
 static void _rtl8723be_query_rxphystatus(struct ieee80211_hw *hw,
 					 struct rtl_stats *pstatus, u8 *pdesc,
 					 struct rx_fwinfo_8723be *p_drvinfo,
-					 bool packet_match_bssid,
-					 bool packet_toself,
+					 bool bpacket_match_bssid,
+					 bool bpacket_toself,
 					 bool packet_beacon)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-	struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
-	struct phy_sts_cck_8723e_t *cck_buf;
 	struct phy_status_rpt *p_phystrpt = (struct phy_status_rpt *)p_drvinfo;
-	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
 	char rx_pwr_all = 0, rx_pwr[4];
-	u8 rf_rx_num = 0, evm, pwdb_all;
+	u8 rf_rx_num = 0, evm, pwdb_all, pwdb_all_bt = 0;
 	u8 i, max_spatial_stream;
 	u32 rssi, total_rssi = 0;
 	bool is_cck = pstatus->is_cck;
 	u8 lan_idx, vga_idx;
 
 	/* Record it for next packet processing */
-	pstatus->packet_matchbssid = packet_match_bssid;
-	pstatus->packet_toself = packet_toself;
+	pstatus->packet_matchbssid = bpacket_match_bssid;
+	pstatus->packet_toself = bpacket_toself;
 	pstatus->packet_beacon = packet_beacon;
-	pstatus->rx_mimo_sig_qual[0] = -1;
-	pstatus->rx_mimo_sig_qual[1] = -1;
+	pstatus->rx_mimo_signalquality[0] = -1;
+	pstatus->rx_mimo_signalquality[1] = -1;
 
 	if (is_cck) {
 		u8 cck_highpwr;
 		u8 cck_agc_rpt;
-		/* CCK Driver info Structure is not the same as OFDM packet. */
-		cck_buf = (struct phy_sts_cck_8723e_t *)p_drvinfo;
-		cck_agc_rpt = cck_buf->cck_agc_rpt;
 
-		/* (1)Hardware does not provide RSSI for CCK
-		 * (2)PWDB, Average PWDB cacluated by
+		cck_agc_rpt = p_phystrpt->cck_agc_rpt_ofdm_cfosho_a;
+
+		/* (1)Hardware does not provide RSSI for CCK */
+		/* (2)PWDB, Average PWDB cacluated by
 		 * hardware (for rate adaptive)
 		 */
-		if (ppsc->rfpwr_state == ERFON)
-			cck_highpwr = (u8) rtl_get_bbreg(hw,
-						       RFPGA0_XA_HSSIPARAMETER2,
-						       BIT(9));
-		else
-			cck_highpwr = false;
+		cck_highpwr = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2,
+						 BIT(9));
 
 		lan_idx = ((cck_agc_rpt & 0xE0) >> 5);
 		vga_idx = (cck_agc_rpt & 0x1f);
+
 		switch (lan_idx) {
-		case 7:
-			if (vga_idx <= 27)/*VGA_idx = 27~2*/
-				rx_pwr_all = -100 + 2 * (27 - vga_idx);
-			else
-				rx_pwr_all = -100;
+		/* 46 53 73 95 201301231630 */
+		/* 46 53 77 99 201301241630 */
+		case 6:
+			rx_pwr_all = -34 - (2 * vga_idx);
 			break;
-		case 6:/*VGA_idx = 2~0*/
-			rx_pwr_all = -48 + 2 * (2 - vga_idx);
-			break;
-		case 5:/*VGA_idx = 7~5*/
-			rx_pwr_all = -42 + 2 * (7 - vga_idx);
-			break;
-		case 4:/*VGA_idx = 7~4*/
-			rx_pwr_all = -36 + 2 * (7 - vga_idx);
-			break;
-		case 3:/*VGA_idx = 7~0*/
-			rx_pwr_all = -24 + 2 * (7 - vga_idx);
-			break;
-		case 2:
-			if (cck_highpwr)/*VGA_idx = 5~0*/
-				rx_pwr_all = -12 + 2 * (5 - vga_idx);
-			else
-				rx_pwr_all = -6 + 2 * (5 - vga_idx);
+		case 4:
+			rx_pwr_all = -14 - (2 * vga_idx);
 			break;
 		case 1:
-			rx_pwr_all = 8 - 2 * vga_idx;
+			rx_pwr_all = 6 - (2 * vga_idx);
 			break;
 		case 0:
-			rx_pwr_all = 14 - 2 * vga_idx;
+			rx_pwr_all = 16 - (2 * vga_idx);
 			break;
 		default:
 			break;
 		}
-		rx_pwr_all += 6;
+
 		pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
-		/* CCK gain is smaller than OFDM/MCS gain,  */
-		/* so we add gain diff by experiences,
-		 * the val is 6
-		 */
-		pwdb_all += 6;
 		if (pwdb_all > 100)
 			pwdb_all = 100;
-		/* modify the offset to make the same gain index with OFDM. */
-		if (pwdb_all > 34 && pwdb_all <= 42)
-			pwdb_all -= 2;
-		else if (pwdb_all > 26 && pwdb_all <= 34)
-			pwdb_all -= 6;
-		else if (pwdb_all > 14 && pwdb_all <= 26)
-			pwdb_all -= 8;
-		else if (pwdb_all > 4 && pwdb_all <= 14)
-			pwdb_all -= 4;
-		if (!cck_highpwr) {
-			if (pwdb_all >= 80)
-				pwdb_all = ((pwdb_all - 80) << 1) +
-					   ((pwdb_all - 80) >> 1) + 80;
-			else if ((pwdb_all <= 78) && (pwdb_all >= 20))
-				pwdb_all += 3;
-			if (pwdb_all > 100)
-				pwdb_all = 100;
-		}
 
 		pstatus->rx_pwdb_all = pwdb_all;
+		pstatus->bt_rx_rssi_percentage = pwdb_all;
 		pstatus->recvsignalpower = rx_pwr_all;
 
 		/* (3) Get Signal Quality (EVM) */
-		if (packet_match_bssid) {
-			u8 sq;
-
+		if (bpacket_match_bssid) {
+			u8 sq, sq_rpt;
 			if (pstatus->rx_pwdb_all > 40) {
 				sq = 100;
 			} else {
-				sq = cck_buf->sq_rpt;
-				if (sq > 64)
+				sq_rpt = p_phystrpt->cck_sig_qual_ofdm_pwdb_all;
+				if (sq_rpt > 64)
 					sq = 0;
-				else if (sq < 20)
+				else if (sq_rpt < 20)
 					sq = 100;
 				else
-					sq = ((64 - sq) * 100) / 44;
+					sq = ((64 - sq_rpt) * 100) / 44;
 			}
-
 			pstatus->signalquality = sq;
-			pstatus->rx_mimo_sig_qual[0] = sq;
-			pstatus->rx_mimo_sig_qual[1] = -1;
+			pstatus->rx_mimo_signalquality[0] = sq;
+			pstatus->rx_mimo_signalquality[1] = -1;
 		}
 	} else {
-		rtlpriv->dm.rfpath_rxenable[0] = true;
-		rtlpriv->dm.rfpath_rxenable[1] = true;
-
 		/* (1)Get RSSI for HT rate */
 		for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) {
 			/* we will judge RF RX path now. */
 			if (rtlpriv->dm.rfpath_rxenable[i])
 				rf_rx_num++;
 
-			rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f)*2) - 110;
+			rx_pwr[i] = ((p_phystrpt->path_agc[i].gain & 0x3f) * 2)
+				    - 110;
 
+			pstatus->rx_pwr[i] = rx_pwr[i];
 			/* Translate DBM to percentage. */
 			rssi = rtl_query_rxpwrpercentage(rx_pwr[i]);
 			total_rssi += rssi;
 
-			/* Get Rx snr value in DB */
-			rtlpriv->stats.rx_snr_db[i] =
-					(long)(p_drvinfo->rxsnr[i] / 2);
-
-			/* Record Signal Strength for next packet */
-			if (packet_match_bssid)
-				pstatus->rx_mimo_signalstrength[i] = (u8) rssi;
+			pstatus->rx_mimo_signalstrength[i] = (u8)rssi;
 		}
 
-		/* (2)PWDB, Avg cacluated by hardware (for rate adaptive) */
-		rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
+		/* (2)PWDB, Average PWDB cacluated by
+		 * hardware (for rate adaptive)
+		 */
+		rx_pwr_all = ((p_phystrpt->cck_sig_qual_ofdm_pwdb_all >> 1) &
+			     0x7f) - 110;
 
 		pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+		pwdb_all_bt = pwdb_all;
 		pstatus->rx_pwdb_all = pwdb_all;
+		pstatus->bt_rx_rssi_percentage = pwdb_all_bt;
 		pstatus->rxpower = rx_pwr_all;
 		pstatus->recvsignalpower = rx_pwr_all;
 
 		/* (3)EVM of HT rate */
-		if (pstatus->is_ht && pstatus->rate >= DESC92C_RATEMCS8 &&
+		if (pstatus->rate >= DESC92C_RATEMCS8 &&
 		    pstatus->rate <= DESC92C_RATEMCS15)
 			max_spatial_stream = 2;
 		else
 			max_spatial_stream = 1;
 
 		for (i = 0; i < max_spatial_stream; i++) {
-			evm = rtl_evm_db_to_percentage(p_drvinfo->rxevm[i]);
+			evm = rtl_evm_db_to_percentage(
+						p_phystrpt->stream_rxevm[i]);
 
-			if (packet_match_bssid) {
+			if (bpacket_match_bssid) {
 				/* Fill value in RFD, Get the first
 				 * spatial stream only
 				 */
 				if (i == 0)
 					pstatus->signalquality =
-							(u8) (evm & 0xff);
-				pstatus->rx_mimo_sig_qual[i] =
-							(u8) (evm & 0xff);
+							(u8)(evm & 0xff);
+				pstatus->rx_mimo_signalquality[i] =
+							(u8)(evm & 0xff);
 			}
 		}
-		if (packet_match_bssid) {
+
+		if (bpacket_match_bssid) {
 			for (i = RF90_PATH_A; i <= RF90_PATH_B; i++)
 				rtl_priv(hw)->dm.cfo_tail[i] =
-					(char)p_phystrpt->path_cfotail[i];
+					(int)p_phystrpt->path_cfotail[i];
 
-			rtl_priv(hw)->dm.packet_count++;
 			if (rtl_priv(hw)->dm.packet_count == 0xffffffff)
 				rtl_priv(hw)->dm.packet_count = 0;
+			else
+				rtl_priv(hw)->dm.packet_count++;
 		}
 	}
 
@@ -409,10 +364,6 @@
 	else if (rf_rx_num != 0)
 		pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
 						total_rssi /= rf_rx_num));
-	/*HW antenna diversity*/
-	rtldm->fat_table.antsel_rx_keep_0 = p_phystrpt->ant_sel;
-	rtldm->fat_table.antsel_rx_keep_1 = p_phystrpt->ant_sel_b;
-	rtldm->fat_table.antsel_rx_keep_2 = p_phystrpt->antsel_rx_keep_2;
 }
 
 static void _rtl8723be_translate_rx_signal_stuff(struct ieee80211_hw *hw,
@@ -440,14 +391,14 @@
 	memcpy(pstatus->psaddr, psaddr, ETH_ALEN);
 
 	packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) &&
-	     (!ether_addr_equal(mac->bssid, (fc & IEEE80211_FCTL_TODS) ?
-				hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ?
-				hdr->addr2 : hdr->addr3)) &&
-				(!pstatus->hwerror) &&
-				(!pstatus->crc) && (!pstatus->icv));
+	     (ether_addr_equal(mac->bssid, (fc & IEEE80211_FCTL_TODS) ?
+				  hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ?
+				  hdr->addr2 : hdr->addr3)) &&
+				  (!pstatus->hwerror) &&
+				  (!pstatus->crc) && (!pstatus->icv));
 
 	packet_toself = packet_matchbssid &&
-	    (!ether_addr_equal(praddr, rtlefuse->dev_addr));
+	    (ether_addr_equal(praddr, rtlefuse->dev_addr));
 
 	/* YP: packet_beacon is not initialized,
 	 * this assignment is neccesary,
@@ -531,30 +482,33 @@
 	struct ieee80211_hdr *hdr;
 
 	u32 phystatus = GET_RX_DESC_PHYST(pdesc);
-	status->packet_report_type = (u8)GET_RX_STATUS_DESC_RPT_SEL(pdesc);
-	if (status->packet_report_type == TX_REPORT2)
-		status->length = (u16) GET_RX_RPT2_DESC_PKT_LEN(pdesc);
-	else
-		status->length = (u16) GET_RX_DESC_PKT_LEN(pdesc);
-	status->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
+
+	status->length = (u16)GET_RX_DESC_PKT_LEN(pdesc);
+	status->rx_drvinfo_size = (u8)GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
 				  RX_DRV_INFO_SIZE_UNIT;
-	status->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03);
+	status->rx_bufshift = (u8)(GET_RX_DESC_SHIFT(pdesc) & 0x03);
 	status->icv = (u16) GET_RX_DESC_ICV(pdesc);
 	status->crc = (u16) GET_RX_DESC_CRC32(pdesc);
 	status->hwerror = (status->crc | status->icv);
 	status->decrypted = !GET_RX_DESC_SWDEC(pdesc);
-	status->rate = (u8) GET_RX_DESC_RXMCS(pdesc);
-	status->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
-	status->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
-	status->isfirst_ampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
-	if (status->packet_report_type == NORMAL_RX)
-		status->timestamp_low = GET_RX_DESC_TSFL(pdesc);
-	status->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
+	status->rate = (u8)GET_RX_DESC_RXMCS(pdesc);
+	status->shortpreamble = (u16)GET_RX_DESC_SPLCP(pdesc);
+	status->isampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1);
+	status->isfirst_ampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1);
+	status->timestamp_low = GET_RX_DESC_TSFL(pdesc);
+	status->rx_is40Mhzpacket = (bool)GET_RX_DESC_BW(pdesc);
+	status->bandwidth = (u8)GET_RX_DESC_BW(pdesc);
+	status->macid = GET_RX_DESC_MACID(pdesc);
 	status->is_ht = (bool)GET_RX_DESC_RXHT(pdesc);
 
-	status->is_cck = RTL8723E_RX_HAL_IS_CCK_RATE(status->rate);
+	status->is_cck = RX_HAL_IS_CCK_RATE(status->rate);
 
-	status->macid = GET_RX_DESC_MACID(pdesc);
+	if (GET_RX_STATUS_DESC_RPT_SEL(pdesc))
+		status->packet_report_type = C2H_PACKET;
+	else
+		status->packet_report_type = NORMAL_RX;
+
+
 	if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
 		status->wake_match = BIT(2);
 	else if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
@@ -565,12 +519,11 @@
 		status->wake_match = 0;
 	if (status->wake_match)
 		RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD,
-			 "GGGGGGGGGGGGGet Wakeup Packet!! WakeMatch=%d\n",
-			 status->wake_match);
+		"GGGGGGGGGGGGGet Wakeup Packet!! WakeMatch=%d\n",
+		status->wake_match);
 	rx_status->freq = hw->conf.chandef.chan->center_freq;
 	rx_status->band = hw->conf.chandef.chan->band;
 
-
 	hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size +
 				       status->rx_bufshift);
 
@@ -594,24 +547,16 @@
 	 * to decrypt it
 	 */
 	if (status->decrypted) {
-		if (!hdr) {
-			WARN_ON_ONCE(true);
-			pr_err("decrypted is true but hdr NULL in skb %p\n",
-			       rtl_get_hdr(skb));
-			return false;
-		}
-
-		if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
+		if ((!_ieee80211_is_robust_mgmt_frame(hdr)) &&
 		    (ieee80211_has_protected(hdr->frame_control)))
-			rx_status->flag &= ~RX_FLAG_DECRYPTED;
-		else
 			rx_status->flag |= RX_FLAG_DECRYPTED;
+		else
+			rx_status->flag &= ~RX_FLAG_DECRYPTED;
 	}
 
 	/* rate_idx: index of data rate into band's
 	 * supported rates or MCS index if HT rates
 	 * are use (RX_FLAG_HT)
-	 * Notice: this is diff with windows define
 	 */
 	rx_status->rate_idx = _rtl8723be_rate_mapping(hw, status->is_ht,
 						      status->rate);
@@ -624,21 +569,19 @@
 		_rtl8723be_translate_rx_signal_stuff(hw, skb, status,
 						     pdesc, p_drvinfo);
 	}
-
-	/*rx_status->qual = status->signal; */
 	rx_status->signal = status->recvsignalpower + 10;
 	if (status->packet_report_type == TX_REPORT2) {
 		status->macid_valid_entry[0] =
-			 GET_RX_RPT2_DESC_MACID_VALID_1(pdesc);
+		  GET_RX_RPT2_DESC_MACID_VALID_1(pdesc);
 		status->macid_valid_entry[1] =
-			 GET_RX_RPT2_DESC_MACID_VALID_2(pdesc);
+		  GET_RX_RPT2_DESC_MACID_VALID_2(pdesc);
 	}
 	return true;
 }
 
 void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw,
 			    struct ieee80211_hdr *hdr, u8 *pdesc_tx,
-			    u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
+			    u8 *txbd, struct ieee80211_tx_info *info,
 			    struct ieee80211_sta *sta, struct sk_buff *skb,
 			    u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
 {
@@ -646,16 +589,16 @@
 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
-	u8 *pdesc = pdesc_tx;
+	u8 *pdesc = (u8 *)pdesc_tx;
 	u16 seq_number;
 	__le16 fc = hdr->frame_control;
 	unsigned int buf_len = 0;
 	unsigned int skb_len = skb->len;
 	u8 fw_qsel = _rtl8723be_map_hwqueue_to_fwqueue(skb, hw_queue);
 	bool firstseg = ((hdr->seq_ctrl &
-			  cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
+			    cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
 	bool lastseg = ((hdr->frame_control &
-			 cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
+			   cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
 	dma_addr_t mapping;
 	u8 bw_40 = 0;
 	u8 short_gi = 0;
@@ -732,11 +675,11 @@
 			 (ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
 			 (ptcb_desc->rts_use_shortgi ? 1 : 0)));
 
-		if (ptcb_desc->btx_enable_sw_calc_duration)
+		if (ptcb_desc->tx_enable_sw_calc_duration)
 			SET_TX_DESC_NAV_USE_HDR(pdesc, 1);
 
 		if (bw_40) {
-			if (ptcb_desc->packet_bw) {
+			if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40) {
 				SET_TX_DESC_DATA_BW(pdesc, 1);
 				SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3);
 			} else {
@@ -776,9 +719,12 @@
 		SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
 		SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
 		SET_TX_DESC_DISABLE_FB(pdesc, ptcb_desc->disable_ratefallback ?
-				       1 : 0);
+					      1 : 0);
 		SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0);
 
+		/* Set TxRate and RTSRate in TxDesc  */
+		/* This prevent Tx initial rate of new-coming packets */
+		/* from being overwritten by retried  packet rate.*/
 		if (ieee80211_is_data_qos(fc)) {
 			if (mac->rdg_en) {
 				RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
@@ -793,9 +739,14 @@
 	SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
 	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) buf_len);
 	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
-	SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index);
-	SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
-
+	/* if (rtlpriv->dm.useramask) { */
+	if (1) {
+		SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index);
+		SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+	} else {
+		SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcb_desc->ratr_index);
+		SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+	}
 	if (!ieee80211_is_data_qos(fc))  {
 		SET_TX_DESC_HWSEQ_EN(pdesc, 1);
 		SET_TX_DESC_HWSEQ_SEL(pdesc, 0);
@@ -805,11 +756,12 @@
 	    is_broadcast_ether_addr(ieee80211_get_DA(hdr))) {
 		SET_TX_DESC_BMC(pdesc, 1);
 	}
+
 	RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n");
 }
 
 void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
-			       bool b_firstseg, bool b_lastseg,
+			       bool firstseg, bool lastseg,
 			       struct sk_buff *skb)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -849,16 +801,19 @@
 
 	SET_TX_DESC_OWN(pdesc, 1);
 
-	SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len));
+	SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len));
 
 	SET_TX_DESC_FIRST_SEG(pdesc, 1);
 	SET_TX_DESC_LAST_SEG(pdesc, 1);
 
 	SET_TX_DESC_USE_RATE(pdesc, 1);
+
+	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+		      "H2C Tx Cmd Content\n", pdesc, TX_DESC_SIZE);
 }
 
-void rtl8723be_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
-			u8 desc_name, u8 *val)
+void rtl8723be_set_desc(struct ieee80211_hw *hw, u8 *pdesc,
+			bool istx, u8 desc_name, u8 *val)
 {
 	if (istx) {
 		switch (desc_name) {
@@ -870,7 +825,7 @@
 			break;
 		default:
 			RT_ASSERT(false, "ERR txdesc :%d not process\n",
-				  desc_name);
+					  desc_name);
 			break;
 		}
 	} else {
@@ -889,7 +844,7 @@
 			break;
 		default:
 			RT_ASSERT(false, "ERR rxdesc :%d not process\n",
-				  desc_name);
+					  desc_name);
 			break;
 		}
 	}
@@ -909,7 +864,7 @@
 			break;
 		default:
 			RT_ASSERT(false, "ERR txdesc :%d not process\n",
-				  desc_name);
+					  desc_name);
 			break;
 		}
 	} else {
@@ -920,6 +875,9 @@
 		case HW_DESC_RXPKT_LEN:
 			ret = GET_RX_DESC_PKT_LEN(pdesc);
 			break;
+		case HW_DESC_RXBUFF_ADDR:
+			ret = GET_RX_DESC_BUFF_ADDR(pdesc);
+			break;
 		default:
 			RT_ASSERT(false, "ERR rxdesc :%d not process\n",
 				  desc_name);
@@ -935,16 +893,15 @@
 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
 	u8 *entry = (u8 *)(&ring->desc[ring->idx]);
-	u8 own = (u8) rtl8723be_get_desc(entry, true, HW_DESC_OWN);
+	u8 own = (u8)rtl8723be_get_desc(entry, true, HW_DESC_OWN);
 
 	/*beacon packet will only use the first
-	 *descriptor by default, and the own may not
+	 *descriptor defautly,and the own may not
 	 *be cleared by the hardware
 	 */
 	if (own)
 		return false;
-	else
-		return true;
+	return true;
 }
 
 void rtl8723be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
@@ -957,3 +914,28 @@
 			       BIT(0) << (hw_queue));
 	}
 }
+
+u32 rtl8723be_rx_command_packet(struct ieee80211_hw *hw,
+				struct rtl_stats status,
+				struct sk_buff *skb)
+{
+	u32 result = 0;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	switch (status.packet_report_type) {
+	case NORMAL_RX:
+			result = 0;
+			break;
+	case C2H_PACKET:
+			rtl8723be_c2h_packet_handler(hw, skb->data,
+						     (u8)skb->len);
+			result = 1;
+			break;
+	default:
+			RT_TRACE(rtlpriv, COMP_RECV, DBG_TRACE,
+				 "No this packet type!!\n");
+			break;
+	}
+
+	return result;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.h b/drivers/net/wireless/rtlwifi/rtl8723be/trx.h
index 102f33d..45949ac 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.h
@@ -415,21 +415,25 @@
 } __packed;
 
 struct rx_fwinfo_8723be {
-	u8 gain_trsw[4];
+	u8 gain_trsw[2];
+	u16 chl_num:10;
+	u16 sub_chnl:4;
+	u16 r_rfmod:2;
 	u8 pwdb_all;
 	u8 cfosho[4];
 	u8 cfotail[4];
 	char rxevm[2];
-	char rxsnr[4];
+	char rxsnr[2];
+	u8 pcts_msk_rpt[2];
 	u8 pdsnr[2];
 	u8 csi_current[2];
-	u8 csi_target[2];
+	u8 rx_gain_c;
+	u8 rx_gain_d;
 	u8 sigevm;
-	u8 max_ex_pwr;
-	u8 ex_intf_flag:1;
-	u8 sgi_en:1;
-	u8 rxsc:2;
-	u8 reserve:4;
+	u8 resvd_0;
+	u8 antidx_anta:3;
+	u8 antidx_antb:3;
+	u8 resvd_1:2;
 } __packed;
 
 struct tx_desc_8723be {
@@ -597,21 +601,25 @@
 } __packed;
 
 void rtl8723be_tx_fill_desc(struct ieee80211_hw *hw,
-			    struct ieee80211_hdr *hdr, u8 *pdesc,
-			    u8 *pbd_desc_tx, struct ieee80211_tx_info *info,
+			    struct ieee80211_hdr *hdr,
+			    u8 *pdesc_tx, u8 *txbd,
+			    struct ieee80211_tx_info *info,
 			    struct ieee80211_sta *sta, struct sk_buff *skb,
 			    u8 hw_queue, struct rtl_tcb_desc *ptcb_desc);
 bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw,
 			     struct rtl_stats *status,
 			     struct ieee80211_rx_status *rx_status,
 			     u8 *pdesc, struct sk_buff *skb);
-void rtl8723be_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx,
-			u8 desc_name, u8 *val);
+void rtl8723be_set_desc(struct ieee80211_hw *hw, u8 *pdesc,
+			bool istx, u8 desc_name, u8 *val);
 u32 rtl8723be_get_desc(u8 *pdesc, bool istx, u8 desc_name);
 bool rtl8723be_is_tx_desc_closed(struct ieee80211_hw *hw,
 				 u8 hw_queue, u16 index);
 void rtl8723be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
 void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
-			       bool b_firstseg, bool b_lastseg,
+			       bool firstseg, bool lastseg,
 			       struct sk_buff *skb);
+u32 rtl8723be_rx_command_packet(struct ieee80211_hw *hw,
+				struct rtl_stats status,
+				struct sk_buff *skb);
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c
index 4e254b7..0643406 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723com/dm_common.c
@@ -44,7 +44,6 @@
 void rtl8723_dm_init_edca_turbo(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
-
 	rtlpriv->dm.current_turbo_edca = false;
 	rtlpriv->dm.is_any_nonbepkts = false;
 	rtlpriv->dm.is_cur_rdlstate = false;
@@ -54,12 +53,13 @@
 void rtl8723_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct ps_t *dm_pstable = &rtlpriv->dm_pstable;
 
-	rtlpriv->dm_pstable.pre_ccastate = CCA_MAX;
-	rtlpriv->dm_pstable.cur_ccasate = CCA_MAX;
-	rtlpriv->dm_pstable.pre_rfstate = RF_MAX;
-	rtlpriv->dm_pstable.cur_rfstate = RF_MAX;
-	rtlpriv->dm_pstable.rssi_val_min = 0;
-	rtlpriv->dm_pstable.initialize = 0;
+	dm_pstable->pre_ccastate = CCA_MAX;
+	dm_pstable->cur_ccasate = CCA_MAX;
+	dm_pstable->pre_rfstate = RF_MAX;
+	dm_pstable->cur_rfstate = RF_MAX;
+	dm_pstable->rssi_val_min = 0;
+	dm_pstable->initialize = 0;
 }
 EXPORT_SYMBOL_GPL(rtl8723_dm_init_dynamic_bb_powersaving);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c
index 540278f..dd698e7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.c
@@ -36,7 +36,8 @@
 
 	if (enable) {
 		tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
-		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
+		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
+			       tmp | 0x04);
 
 		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
 		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
@@ -95,7 +96,7 @@
 }
 EXPORT_SYMBOL_GPL(rtl8723_fw_page_write);
 
-static void rtl8723_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
+void rtl8723_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
 {
 	u32 fwlen = *pfwlen;
 	u8 remain = (u8) (fwlen % 4);
@@ -109,60 +110,64 @@
 	}
 	*pfwlen = fwlen;
 }
+EXPORT_SYMBOL(rtl8723_fill_dummy);
 
 void rtl8723_write_fw(struct ieee80211_hw *hw,
 		      enum version_8723e version,
-		      u8 *buffer, u32 size)
+		      u8 *buffer, u32 size, u8 max_page)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	u8 *bufferptr = buffer;
-	u32 pagenums, remainsize;
+	u32 page_nums, remain_size;
 	u32 page, offset;
 
-	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
+	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
 
 	rtl8723_fill_dummy(bufferptr, &size);
 
-	pagenums = size / FW_8192C_PAGE_SIZE;
-	remainsize = size % FW_8192C_PAGE_SIZE;
+	page_nums = size / FW_8192C_PAGE_SIZE;
+	remain_size = size % FW_8192C_PAGE_SIZE;
 
-	if (pagenums > 8) {
+	if (page_nums > max_page) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Page numbers should not greater then 8\n");
+			 "Page numbers should not greater than %d\n", max_page);
 	}
-	for (page = 0; page < pagenums; page++) {
+	for (page = 0; page < page_nums; page++) {
 		offset = page * FW_8192C_PAGE_SIZE;
 		rtl8723_fw_page_write(hw, page, (bufferptr + offset),
 				      FW_8192C_PAGE_SIZE);
 	}
-	if (remainsize) {
-		offset = pagenums * FW_8192C_PAGE_SIZE;
-		page = pagenums;
+
+	if (remain_size) {
+		offset = page_nums * FW_8192C_PAGE_SIZE;
+		page = page_nums;
 		rtl8723_fw_page_write(hw, page, (bufferptr + offset),
-				      remainsize);
+				      remain_size);
 	}
+	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n");
 }
 EXPORT_SYMBOL_GPL(rtl8723_write_fw);
 
 void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)
 {
-	u8 u1tmp;
+	u8 u1b_tmp;
 	u8 delay = 100;
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 
 	rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
-	u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 
-	while (u1tmp & BIT(2)) {
+	while (u1b_tmp & BIT(2)) {
 		delay--;
 		if (delay == 0)
 			break;
 		udelay(50);
-		u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+		u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 	}
 	if (delay == 0) {
-		u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
-		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1tmp&(~BIT(2)));
+		u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
+			       u1b_tmp&(~BIT(2)));
 	}
 }
 EXPORT_SYMBOL_GPL(rtl8723ae_firmware_selfreset);
@@ -190,7 +195,8 @@
 }
 EXPORT_SYMBOL_GPL(rtl8723be_firmware_selfreset);
 
-int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be)
+int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be,
+			  int max_count)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	int err = -EIO;
@@ -199,10 +205,10 @@
 
 	do {
 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
-	} while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
+	} while ((counter++ < max_count) &&
 		 (!(value32 & FWDL_CHKSUM_RPT)));
 
-	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
+	if (counter >= max_count) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 "chksum report fail ! REG_MCUFWDL:0x%08x .\n",
 			 value32);
@@ -223,15 +229,15 @@
 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 		if (value32 & WINTINI_RDY) {
 			RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-				 "Polling FW ready success!! "
-				 "REG_MCUFWDL:0x%08x .\n",
+				 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
 				 value32);
 			err = 0;
 			goto exit;
 		}
-		udelay(FW_8192C_POLLING_DELAY);
 
-	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
+		mdelay(FW_8192C_POLLING_DELAY);
+
+	} while (counter++ < max_count);
 
 	RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 		 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
@@ -243,51 +249,55 @@
 EXPORT_SYMBOL_GPL(rtl8723_fw_free_to_go);
 
 int rtl8723_download_fw(struct ieee80211_hw *hw,
-			bool is_8723be)
+			bool is_8723be, int max_count)
 {
 	struct rtl_priv *rtlpriv = rtl_priv(hw);
 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-	struct rtl92c_firmware_header *pfwheader;
+	struct rtl8723e_firmware_header *pfwheader;
 	u8 *pfwdata;
 	u32 fwsize;
 	int err;
 	enum version_8723e version = rtlhal->version;
+	int max_page;
 
 	if (!rtlhal->pfirmware)
 		return 1;
 
-	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
+	pfwheader = (struct rtl8723e_firmware_header *)rtlhal->pfirmware;
 	pfwdata = rtlhal->pfirmware;
 	fwsize = rtlhal->fwsize;
-	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
-		 "normal Firmware SIZE %d\n", fwsize);
 
+	if (!is_8723be)
+		max_page = 6;
+	else
+		max_page = 8;
 	if (rtlpriv->cfg->ops->is_fw_header(pfwheader)) {
 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
 			 "Firmware Version(%d), Signature(%#x), Size(%d)\n",
 			 pfwheader->version, pfwheader->signature,
-			 (int)sizeof(struct rtl92c_firmware_header));
+			 (int)sizeof(struct rtl8723e_firmware_header));
 
-		pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
-		fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
+		pfwdata = pfwdata + sizeof(struct rtl8723e_firmware_header);
+		fwsize = fwsize - sizeof(struct rtl8723e_firmware_header);
 	}
-	if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
-		rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
+
+	if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) {
 		if (is_8723be)
 			rtl8723be_firmware_selfreset(hw);
 		else
 			rtl8723ae_firmware_selfreset(hw);
+		rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
 	}
 	rtl8723_enable_fw_download(hw, true);
-	rtl8723_write_fw(hw, version, pfwdata, fwsize);
+	rtl8723_write_fw(hw, version, pfwdata, fwsize, max_page);
 	rtl8723_enable_fw_download(hw, false);
 
-	err = rtl8723_fw_free_to_go(hw, is_8723be);
+	err = rtl8723_fw_free_to_go(hw, is_8723be, max_count);
 	if (err) {
 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
 			 "Firmware is not ready to run!\n");
 	} else {
-		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 			 "Firmware is ready to run!\n");
 	}
 	return 0;
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h
index cf1cc58..3ebafc8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723com/fw_common.h
@@ -30,7 +30,8 @@
 #define REG_MCUFWDL				0x0080
 #define FW_8192C_START_ADDRESS			0x1000
 #define FW_8192C_PAGE_SIZE			4096
-#define FW_8192C_POLLING_TIMEOUT_COUNT		6000
+#define FW_8723A_POLLING_TIMEOUT_COUNT		1000
+#define FW_8723B_POLLING_TIMEOUT_COUNT		6000
 #define FW_8192C_POLLING_DELAY			5
 
 #define MCUFWDL_RDY				BIT(1)
@@ -49,16 +50,23 @@
 	VERSION_UNKNOWN = 0xFF,
 };
 
-enum rtl8723ae_h2c_cmd {
-	H2C_AP_OFFLOAD = 0,
-	H2C_SETPWRMODE = 1,
-	H2C_JOINBSSRPT = 2,
-	H2C_RSVDPAGE = 3,
-	H2C_RSSI_REPORT = 4,
-	H2C_P2P_PS_CTW_CMD = 5,
-	H2C_P2P_PS_OFFLOAD = 6,
-	H2C_RA_MASK = 7,
-	MAX_H2CCMD
+struct rtl8723e_firmware_header {
+	u16 signature;
+	u8 category;
+	u8 function;
+	u16 version;
+	u8 subversion;
+	u8 rsvd1;
+	u8 month;
+	u8 date;
+	u8 hour;
+	u8 minute;
+	u16 ramcodesize;
+	u16 rsvd2;
+	u32 svnindex;
+	u32 rsvd3;
+	u32 rsvd4;
+	u32 rsvd5;
 };
 
 enum rtl8723be_cmd {
@@ -92,25 +100,6 @@
 	MAX_8723BE_H2CCMD
 };
 
-struct rtl92c_firmware_header {
-	u16 signature;
-	u8 category;
-	u8 function;
-	u16 version;
-	u8 subversion;
-	u8 rsvd1;
-	u8 month;
-	u8 date;
-	u8 hour;
-	u8 minute;
-	u16 ramcodesize;
-	u16 rsvd2;
-	u32 svnindex;
-	u32 rsvd3;
-	u32 rsvd4;
-	u32 rsvd5;
-};
-
 void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw);
 void rtl8723be_firmware_selfreset(struct ieee80211_hw *hw);
 void rtl8723_enable_fw_download(struct ieee80211_hw *hw, bool enable);
@@ -120,7 +109,11 @@
 			   u32 page, const u8 *buffer, u32 size);
 void rtl8723_write_fw(struct ieee80211_hw *hw,
 		      enum version_8723e version,
-		      u8 *buffer, u32 size);
-int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be);
-int rtl8723_download_fw(struct ieee80211_hw *hw, bool is_8723be);
+		      u8 *buffer, u32 size, u8 max_page);
+int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be, int count);
+int rtl8723_download_fw(struct ieee80211_hw *hw, bool is_8723be, int count);
+bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw,
+			     struct sk_buff *skb);
+void rtl8723_fill_dummy(u8 *pfwbuf, u32 *pfwlen);
+
 #endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c
index d73b659..75cbd15 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723com/phy_common.c
@@ -43,9 +43,8 @@
 	returnvalue = (originalvalue & bitmask) >> bitshift;
 
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
-		 "BBR MASK = 0x%x Addr[0x%x]= 0x%x\n",
-		  bitmask, regaddr, originalvalue);
-
+		 "BBR MASK=0x%x Addr[0x%x]=0x%x\n", bitmask,
+		 regaddr, originalvalue);
 	return returnvalue;
 }
 EXPORT_SYMBOL_GPL(rtl8723_phy_query_bb_reg);
@@ -57,8 +56,8 @@
 	u32 originalvalue, bitshift;
 
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
-		 "regaddr(%#x), bitmask(%#x), data(%#x)\n",
-		  regaddr, bitmask, data);
+		 "regaddr(%#x), bitmask(%#x), data(%#x)\n", regaddr, bitmask,
+		 data);
 
 	if (bitmask != MASKDWORD) {
 		originalvalue = rtl_read_dword(rtlpriv, regaddr);
@@ -70,7 +69,7 @@
 
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
 		 "regaddr(%#x), bitmask(%#x), data(%#x)\n",
-		  regaddr, bitmask, data);
+		 regaddr, bitmask, data);
 }
 EXPORT_SYMBOL_GPL(rtl8723_phy_set_bb_reg);
 
@@ -109,12 +108,15 @@
 	else
 		tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
 	tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
-		   (newoffset << 23) | BLSSIREADEDGE;
+	    (newoffset << 23) | BLSSIREADEDGE;
 	rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
 		      tmplong & (~BLSSIREADEDGE));
 	mdelay(1);
 	rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
-	mdelay(2);
+	mdelay(1);
+	rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+		      tmplong | BLSSIREADEDGE);
+	mdelay(1);
 	if (rfpath == RF90_PATH_A)
 		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
 						 BIT(8));
@@ -128,8 +130,8 @@
 		retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
 					 BLSSIREADBACKDATA);
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
-		 "RFR-%d Addr[0x%x]= 0x%x\n",
-		  rfpath, pphyreg->rf_rb, retvalue);
+		 "RFR-%d Addr[0x%x]=0x%x\n",
+		 rfpath, pphyreg->rf_rb, retvalue);
 	return retvalue;
 }
 EXPORT_SYMBOL_GPL(rtl8723_phy_rf_serial_read);
@@ -153,8 +155,9 @@
 	data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
 	rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
 	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
-		 "RFW-%d Addr[0x%x]= 0x%x\n", rfpath,
-		   pphyreg->rf3wire_offset, data_and_addr);
+		 "RFW-%d Addr[0x%x]=0x%x\n",
+		 rfpath, pphyreg->rf3wire_offset,
+		 data_and_addr);
 }
 EXPORT_SYMBOL_GPL(rtl8723_phy_rf_serial_write);
 
@@ -171,6 +174,8 @@
 		break;
 	case WIRELESS_MODE_G:
 	case WIRELESS_MODE_N_24G:
+		offset = -8;
+		break;
 	default:
 		offset = -8;
 		break;
@@ -202,14 +207,14 @@
 	rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE;
 
 	rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset =
-			    RFPGA0_XA_LSSIPARAMETER;
+	    RFPGA0_XA_LSSIPARAMETER;
 	rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset =
-			    RFPGA0_XB_LSSIPARAMETER;
+	    RFPGA0_XB_LSSIPARAMETER;
 
-	rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = rFPGA0_XAB_RFPARAMETER;
-	rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = rFPGA0_XAB_RFPARAMETER;
-	rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER;
-	rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+	rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = RFPGA0_XAB_RFPARAMETER;
+	rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = RFPGA0_XAB_RFPARAMETER;
+	rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = RFPGA0_XCD_RFPARAMETER;
+	rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = RFPGA0_XCD_RFPARAMETER;
 
 	rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE;
 	rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE;
@@ -264,6 +269,7 @@
 
 	rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK;
 	rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;
+
 }
 EXPORT_SYMBOL_GPL(rtl8723_phy_init_bb_rf_reg_def);
 
@@ -384,14 +390,21 @@
 void rtl8723_phy_path_adda_on(struct ieee80211_hw *hw, u32 *addareg,
 			      bool is_patha_on, bool is2t)
 {
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 	u32 pathon;
 	u32 i;
 
-	pathon = is_patha_on ? 0x04db25a4 : 0x0b1b25a4;
-	if (!is2t) {
-		pathon = 0x0bdb25a0;
-		rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0);
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723AE) {
+		pathon = is_patha_on ? 0x04db25a4 : 0x0b1b25a4;
+		if (!is2t) {
+			pathon = 0x0bdb25a0;
+			rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0);
+		} else {
+			rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathon);
+		}
 	} else {
+		/* rtl8723be */
+		pathon = 0x01c00014;
 		rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathon);
 	}
 
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/Makefile b/drivers/net/wireless/rtlwifi/rtl8821ae/Makefile
new file mode 100644
index 0000000..445930c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/Makefile
@@ -0,0 +1,19 @@
+obj-m := rtl8821ae.o
+
+
+rtl8821ae-objs :=		\
+		dm.o		\
+		fw.o		\
+		hw.o		\
+		led.o		\
+		phy.o		\
+		pwrseq.o	\
+		rf.o		\
+		sw.o		\
+		table.o		\
+		trx.o		\
+
+
+obj-$(CPTCFG_RTL8821AE) += rtl8821ae.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/def.h b/drivers/net/wireless/rtlwifi/rtl8821ae/def.h
new file mode 100644
index 0000000..a730985
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/def.h
@@ -0,0 +1,450 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8821AE_DEF_H__
+#define __RTL8821AE_DEF_H__
+
+/*--------------------------Define -------------------------------------------*/
+#define	USE_SPECIFIC_FW_TO_SUPPORT_WOWLAN	1
+
+/* BIT 7 HT Rate*/
+/*TxHT = 0*/
+#define	MGN_1M				0x02
+#define	MGN_2M				0x04
+#define	MGN_5_5M			0x0b
+#define	MGN_11M				0x16
+
+#define	MGN_6M				0x0c
+#define	MGN_9M				0x12
+#define	MGN_12M				0x18
+#define	MGN_18M				0x24
+#define	MGN_24M				0x30
+#define	MGN_36M				0x48
+#define	MGN_48M				0x60
+#define	MGN_54M				0x6c
+
+/* TxHT = 1 */
+#define	MGN_MCS0			0x80
+#define	MGN_MCS1			0x81
+#define	MGN_MCS2			0x82
+#define	MGN_MCS3			0x83
+#define	MGN_MCS4			0x84
+#define	MGN_MCS5			0x85
+#define	MGN_MCS6			0x86
+#define	MGN_MCS7			0x87
+#define	MGN_MCS8			0x88
+#define	MGN_MCS9			0x89
+#define	MGN_MCS10			0x8a
+#define	MGN_MCS11			0x8b
+#define	MGN_MCS12			0x8c
+#define	MGN_MCS13			0x8d
+#define	MGN_MCS14			0x8e
+#define	MGN_MCS15			0x8f
+/* VHT rate */
+#define	MGN_VHT1SS_MCS0		0x90
+#define	MGN_VHT1SS_MCS1		0x91
+#define	MGN_VHT1SS_MCS2		0x92
+#define	MGN_VHT1SS_MCS3		0x93
+#define	MGN_VHT1SS_MCS4		0x94
+#define	MGN_VHT1SS_MCS5		0x95
+#define	MGN_VHT1SS_MCS6		0x96
+#define	MGN_VHT1SS_MCS7		0x97
+#define	MGN_VHT1SS_MCS8		0x98
+#define	MGN_VHT1SS_MCS9		0x99
+#define	MGN_VHT2SS_MCS0		0x9a
+#define	MGN_VHT2SS_MCS1		0x9b
+#define	MGN_VHT2SS_MCS2		0x9c
+#define	MGN_VHT2SS_MCS3		0x9d
+#define	MGN_VHT2SS_MCS4		0x9e
+#define	MGN_VHT2SS_MCS5		0x9f
+#define	MGN_VHT2SS_MCS6		0xa0
+#define	MGN_VHT2SS_MCS7		0xa1
+#define	MGN_VHT2SS_MCS8		0xa2
+#define	MGN_VHT2SS_MCS9		0xa3
+
+#define	MGN_VHT3SS_MCS0		0xa4
+#define	MGN_VHT3SS_MCS1		0xa5
+#define	MGN_VHT3SS_MCS2		0xa6
+#define	MGN_VHT3SS_MCS3		0xa7
+#define	MGN_VHT3SS_MCS4		0xa8
+#define	MGN_VHT3SS_MCS5		0xa9
+#define	MGN_VHT3SS_MCS6		0xaa
+#define	MGN_VHT3SS_MCS7		0xab
+#define	MGN_VHT3SS_MCS8		0xac
+#define	MGN_VHT3SS_MCS9		0xad
+
+#define	MGN_MCS0_SG			0xc0
+#define	MGN_MCS1_SG			0xc1
+#define	MGN_MCS2_SG			0xc2
+#define	MGN_MCS3_SG			0xc3
+#define	MGN_MCS4_SG			0xc4
+#define	MGN_MCS5_SG			0xc5
+#define	MGN_MCS6_SG			0xc6
+#define	MGN_MCS7_SG			0xc7
+#define	MGN_MCS8_SG			0xc8
+#define	MGN_MCS9_SG			0xc9
+#define	MGN_MCS10_SG		0xca
+#define	MGN_MCS11_SG		0xcb
+#define	MGN_MCS12_SG		0xcc
+#define	MGN_MCS13_SG		0xcd
+#define	MGN_MCS14_SG		0xce
+#define	MGN_MCS15_SG		0xcf
+
+#define	MGN_UNKNOWN			0xff
+
+/* 30 ms */
+#define	WIFI_NAV_UPPER_US				30000
+#define HAL_92C_NAV_UPPER_UNIT			128
+
+#define HAL_RETRY_LIMIT_INFRA				48
+#define HAL_RETRY_LIMIT_AP_ADHOC			7
+
+#define RESET_DELAY_8185					20
+
+#define RT_IBSS_INT_MASKS	(IMR_BCNINT | IMR_TBDOK | IMR_TBDER)
+#define RT_AC_INT_MASKS		(IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK)
+
+#define NUM_OF_FIRMWARE_QUEUE				10
+#define NUM_OF_PAGES_IN_FW					0x100
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK			0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE			0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI			0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO			0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA		0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_CMD			0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT		0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH		0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_BCN			0x2
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB			0xA1
+
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM		0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM		0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM		0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM		0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM		0x00
+
+#define MAX_RX_DMA_BUFFER_SIZE				0x3E80
+
+#define MAX_LINES_HWCONFIG_TXT				1000
+#define MAX_BYTES_LINE_HWCONFIG_TXT			256
+
+#define SW_THREE_WIRE						0
+#define HW_THREE_WIRE						2
+
+#define BT_DEMO_BOARD						0
+#define BT_QA_BOARD							1
+#define BT_FPGA								2
+
+#define HAL_PRIME_CHNL_OFFSET_DONT_CARE		0
+#define HAL_PRIME_CHNL_OFFSET_LOWER			1
+#define HAL_PRIME_CHNL_OFFSET_UPPER			2
+
+#define MAX_H2C_QUEUE_NUM					10
+
+#define RX_MPDU_QUEUE						0
+#define RX_CMD_QUEUE						1
+#define RX_MAX_QUEUE						2
+#define AC2QUEUEID(_AC)						(_AC)
+
+#define MAX_RX_DMA_BUFFER_SIZE_8812	0x3E80
+
+#define	C2H_RX_CMD_HDR_LEN					8
+#define	GET_C2H_CMD_CMD_LEN(__prxhdr)		\
+	LE_BITS_TO_4BYTE((__prxhdr), 0, 16)
+#define	GET_C2H_CMD_ELEMENT_ID(__prxhdr)	\
+	LE_BITS_TO_4BYTE((__prxhdr), 16, 8)
+#define	GET_C2H_CMD_CMD_SEQ(__prxhdr)		\
+	LE_BITS_TO_4BYTE((__prxhdr), 24, 7)
+#define	GET_C2H_CMD_CONTINUE(__prxhdr)		\
+	LE_BITS_TO_4BYTE((__prxhdr), 31, 1)
+#define	GET_C2H_CMD_CONTENT(__prxhdr)		\
+	((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN)
+
+#define	GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr)	\
+	LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8)
+#define	GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr)		\
+	LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8)
+#define	GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr)	\
+	LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16)
+#define	GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr)	\
+	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5)
+#define	GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr)		\
+	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1)
+#define	GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr)	\
+	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5)
+#define	GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr)		\
+	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1)
+#define	GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr)		\
+	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4)
+#define	GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr)		\
+	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12)
+
+#define CHIP_BONDING_IDENTIFIER(_value)	(((_value)>>22)&0x3)
+
+#define CHIP_8812				BIT(2)
+#define CHIP_8821				(BIT(0)|BIT(2))
+
+#define CHIP_8821A				(BIT(0)|BIT(2))
+#define NORMAL_CHIP				BIT(3)
+#define RF_TYPE_1T1R				(~(BIT(4)|BIT(5)|BIT(6)))
+#define RF_TYPE_1T2R				BIT(4)
+#define RF_TYPE_2T2R				BIT(5)
+#define CHIP_VENDOR_UMC				BIT(7)
+#define B_CUT_VERSION				BIT(12)
+#define C_CUT_VERSION				BIT(13)
+#define D_CUT_VERSION				((BIT(12)|BIT(13)))
+#define E_CUT_VERSION				BIT(14)
+#define	RF_RL_ID			(BIT(31)|BIT(30)|BIT(29)|BIT(28))
+
+enum version_8821ae {
+	VERSION_TEST_CHIP_1T1R_8812 = 0x0004,
+	VERSION_TEST_CHIP_2T2R_8812 = 0x0024,
+	VERSION_NORMAL_TSMC_CHIP_1T1R_8812 = 0x100c,
+	VERSION_NORMAL_TSMC_CHIP_2T2R_8812 = 0x102c,
+	VERSION_NORMAL_TSMC_CHIP_1T1R_8812_C_CUT = 0x200c,
+	VERSION_NORMAL_TSMC_CHIP_2T2R_8812_C_CUT = 0x202c,
+	VERSION_TEST_CHIP_8821 = 0x0005,
+	VERSION_NORMAL_TSMC_CHIP_8821 = 0x000d,
+	VERSION_NORMAL_TSMC_CHIP_8821_B_CUT = 0x100d,
+	VERSION_UNKNOWN = 0xFF,
+};
+
+enum vht_data_sc {
+	VHT_DATA_SC_DONOT_CARE = 0,
+	VHT_DATA_SC_20_UPPER_OF_80MHZ = 1,
+	VHT_DATA_SC_20_LOWER_OF_80MHZ = 2,
+	VHT_DATA_SC_20_UPPERST_OF_80MHZ = 3,
+	VHT_DATA_SC_20_LOWEST_OF_80MHZ = 4,
+	VHT_DATA_SC_20_RECV1 = 5,
+	VHT_DATA_SC_20_RECV2 = 6,
+	VHT_DATA_SC_20_RECV3 = 7,
+	VHT_DATA_SC_20_RECV4 = 8,
+	VHT_DATA_SC_40_UPPER_OF_80MHZ = 9,
+	VHT_DATA_SC_40_LOWER_OF_80MHZ = 10,
+};
+
+/* MASK */
+#define IC_TYPE_MASK			(BIT(0)|BIT(1)|BIT(2))
+#define CHIP_TYPE_MASK			BIT(3)
+#define RF_TYPE_MASK			(BIT(4)|BIT(5)|BIT(6))
+#define MANUFACTUER_MASK		BIT(7)
+#define ROM_VERSION_MASK		(BIT(11)|BIT(10)|BIT(9)|BIT(8))
+#define CUT_VERSION_MASK		(BIT(15)|BIT(14)|BIT(13)|BIT(12))
+
+/* Get element */
+#define GET_CVID_IC_TYPE(version)	((version) & IC_TYPE_MASK)
+#define GET_CVID_CHIP_TYPE(version)	((version) & CHIP_TYPE_MASK)
+#define GET_CVID_RF_TYPE(version)	((version) & RF_TYPE_MASK)
+#define GET_CVID_MANUFACTUER(version)	((version) & MANUFACTUER_MASK)
+#define GET_CVID_ROM_VERSION(version)	((version) & ROM_VERSION_MASK)
+#define GET_CVID_CUT_VERSION(version)	((version) & CUT_VERSION_MASK)
+
+#define IS_1T1R(version)	((GET_CVID_RF_TYPE(version)) ? false : true)
+#define IS_1T2R(version)	((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R)\
+							? true : false)
+#define IS_2T2R(version)	((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R)\
+							? true : false)
+
+#define IS_8812_SERIES(version)	((GET_CVID_IC_TYPE(version) == CHIP_8812) ? \
+								true : false)
+#define IS_8821_SERIES(version)	((GET_CVID_IC_TYPE(version) == CHIP_8821) ? \
+								true : false)
+
+#define IS_VENDOR_8812A_TEST_CHIP(version)	((IS_8812_SERIES(version)) ? \
+					((IS_NORMAL_CHIP(version)) ? \
+						false : true) : false)
+#define IS_VENDOR_8812A_MP_CHIP(version)	((IS_8812_SERIES(version)) ? \
+					((IS_NORMAL_CHIP(version)) ? \
+						true : false) : false)
+#define IS_VENDOR_8812A_C_CUT(version)		((IS_8812_SERIES(version)) ? \
+					((GET_CVID_CUT_VERSION(version) == \
+					C_CUT_VERSION) ? \
+					true : false) : false)
+
+#define IS_VENDOR_8821A_TEST_CHIP(version)	((IS_8821_SERIES(version)) ? \
+					((IS_NORMAL_CHIP(version)) ? \
+					false : true) : false)
+#define IS_VENDOR_8821A_MP_CHIP(version)	((IS_8821_SERIES(version)) ? \
+					((IS_NORMAL_CHIP(version)) ? \
+						true : false) : false)
+#define IS_VENDOR_8821A_B_CUT(version)		((IS_8821_SERIES(version)) ? \
+					((GET_CVID_CUT_VERSION(version) == \
+					B_CUT_VERSION) ? \
+					true : false) : false)
+enum board_type {
+	ODM_BOARD_DEFAULT = 0,	  /* The DEFAULT case. */
+	ODM_BOARD_MINICARD = BIT(0), /* 0 = non-mini card, 1 = mini card. */
+	ODM_BOARD_SLIM = BIT(1), /* 0 = non-slim card, 1 = slim card */
+	ODM_BOARD_BT = BIT(2), /* 0 = without BT card, 1 = with BT */
+	ODM_BOARD_EXT_PA = BIT(3), /* 1 = existing 2G ext-PA */
+	ODM_BOARD_EXT_LNA = BIT(4), /* 1 = existing 2G ext-LNA */
+	ODM_BOARD_EXT_TRSW = BIT(5), /* 1 = existing ext-TRSW */
+	ODM_BOARD_EXT_PA_5G = BIT(6), /* 1 = existing 5G ext-PA */
+	ODM_BOARD_EXT_LNA_5G = BIT(7), /* 1 = existing 5G ext-LNA */
+};
+
+enum rf_optype {
+	RF_OP_BY_SW_3WIRE = 0,
+	RF_OP_BY_FW,
+	RF_OP_MAX
+};
+
+enum rf_power_state {
+	RF_ON,
+	RF_OFF,
+	RF_SLEEP,
+	RF_SHUT_DOWN,
+};
+
+enum power_save_mode {
+	POWER_SAVE_MODE_ACTIVE,
+	POWER_SAVE_MODE_SAVE,
+};
+
+enum power_polocy_config {
+	POWERCFG_MAX_POWER_SAVINGS,
+	POWERCFG_GLOBAL_POWER_SAVINGS,
+	POWERCFG_LOCAL_POWER_SAVINGS,
+	POWERCFG_LENOVO,
+};
+
+enum interface_select_pci {
+	INTF_SEL1_MINICARD = 0,
+	INTF_SEL0_PCIE = 1,
+	INTF_SEL2_RSV = 2,
+	INTF_SEL3_RSV = 3,
+};
+
+enum hal_fw_c2h_cmd_id {
+	HAL_FW_C2H_CMD_READ_MACREG = 0,
+	HAL_FW_C2H_CMD_READ_BBREG = 1,
+	HAL_FW_C2H_CMD_READ_RFREG = 2,
+	HAL_FW_C2H_CMD_READ_EEPROM = 3,
+	HAL_FW_C2H_CMD_READ_EFUSE = 4,
+	HAL_FW_C2H_CMD_READ_CAM = 5,
+	HAL_FW_C2H_CMD_GET_BASICRATE = 6,
+	HAL_FW_C2H_CMD_GET_DATARATE = 7,
+	HAL_FW_C2H_CMD_SURVEY = 8,
+	HAL_FW_C2H_CMD_SURVEYDONE = 9,
+	HAL_FW_C2H_CMD_JOINBSS = 10,
+	HAL_FW_C2H_CMD_ADDSTA = 11,
+	HAL_FW_C2H_CMD_DELSTA = 12,
+	HAL_FW_C2H_CMD_ATIMDONE = 13,
+	HAL_FW_C2H_CMD_TX_REPORT = 14,
+	HAL_FW_C2H_CMD_CCX_REPORT = 15,
+	HAL_FW_C2H_CMD_DTM_REPORT = 16,
+	HAL_FW_C2H_CMD_TX_RATE_STATISTICS = 17,
+	HAL_FW_C2H_CMD_C2HLBK = 18,
+	HAL_FW_C2H_CMD_C2HDBG = 19,
+	HAL_FW_C2H_CMD_C2HFEEDBACK = 20,
+	HAL_FW_C2H_CMD_MAX
+};
+
+enum rtl_desc_qsel {
+	QSLT_BK = 0x2,
+	QSLT_BE = 0x0,
+	QSLT_VI = 0x5,
+	QSLT_VO = 0x7,
+	QSLT_BEACON = 0x10,
+	QSLT_HIGH = 0x11,
+	QSLT_MGNT = 0x12,
+	QSLT_CMD = 0x13,
+};
+
+enum rtl_desc8821ae_rate {
+	DESC_RATE1M = 0x00,
+	DESC_RATE2M = 0x01,
+	DESC_RATE5_5M = 0x02,
+	DESC_RATE11M = 0x03,
+
+	DESC_RATE6M = 0x04,
+	DESC_RATE9M = 0x05,
+	DESC_RATE12M = 0x06,
+	DESC_RATE18M = 0x07,
+	DESC_RATE24M = 0x08,
+	DESC_RATE36M = 0x09,
+	DESC_RATE48M = 0x0a,
+	DESC_RATE54M = 0x0b,
+
+	DESC_RATEMCS0 = 0x0c,
+	DESC_RATEMCS1 = 0x0d,
+	DESC_RATEMCS2 = 0x0e,
+	DESC_RATEMCS3 = 0x0f,
+	DESC_RATEMCS4 = 0x10,
+	DESC_RATEMCS5 = 0x11,
+	DESC_RATEMCS6 = 0x12,
+	DESC_RATEMCS7 = 0x13,
+	DESC_RATEMCS8 = 0x14,
+	DESC_RATEMCS9 = 0x15,
+	DESC_RATEMCS10 = 0x16,
+	DESC_RATEMCS11 = 0x17,
+	DESC_RATEMCS12 = 0x18,
+	DESC_RATEMCS13 = 0x19,
+	DESC_RATEMCS14 = 0x1a,
+	DESC_RATEMCS15 = 0x1b,
+
+	DESC_RATEVHT1SS_MCS0 = 0x2c,
+	DESC_RATEVHT1SS_MCS1 = 0x2d,
+	DESC_RATEVHT1SS_MCS2 = 0x2e,
+	DESC_RATEVHT1SS_MCS3 = 0x2f,
+	DESC_RATEVHT1SS_MCS4 = 0x30,
+	DESC_RATEVHT1SS_MCS5 = 0x31,
+	DESC_RATEVHT1SS_MCS6 = 0x32,
+	DESC_RATEVHT1SS_MCS7 = 0x33,
+	DESC_RATEVHT1SS_MCS8 = 0x34,
+	DESC_RATEVHT1SS_MCS9 = 0x35,
+	DESC_RATEVHT2SS_MCS0 = 0x36,
+	DESC_RATEVHT2SS_MCS1 = 0x37,
+	DESC_RATEVHT2SS_MCS2 = 0x38,
+	DESC_RATEVHT2SS_MCS3 = 0x39,
+	DESC_RATEVHT2SS_MCS4 = 0x3a,
+	DESC_RATEVHT2SS_MCS5 = 0x3b,
+	DESC_RATEVHT2SS_MCS6 = 0x3c,
+	DESC_RATEVHT2SS_MCS7 = 0x3d,
+	DESC_RATEVHT2SS_MCS8 = 0x3e,
+	DESC_RATEVHT2SS_MCS9 = 0x3f,
+};
+
+enum rx_packet_type {
+	NORMAL_RX,
+	TX_REPORT1,
+	TX_REPORT2,
+	HIS_REPORT,
+	C2H_PACKET,
+};
+
+struct phy_sts_cck_8821ae_t {
+	u8 adc_pwdb_X[4];
+	u8 sq_rpt;
+	u8 cck_agc_rpt;
+};
+
+struct h2c_cmd_8821ae {
+	u8 element_id;
+	u32 cmd_len;
+	u8 *p_cmdbuffer;
+};
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c
new file mode 100644
index 0000000..9be1061
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c
@@ -0,0 +1,3019 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../base.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "trx.h"
+#include "../btcoexist/rtl_btc.h"
+
+static const u32 txscaling_tbl[TXSCALE_TABLE_SIZE] = {
+	0x081, /* 0, -12.0dB */
+	0x088, /* 1, -11.5dB */
+	0x090, /* 2, -11.0dB */
+	0x099, /* 3, -10.5dB */
+	0x0A2, /* 4, -10.0dB */
+	0x0AC, /* 5, -9.5dB */
+	0x0B6, /* 6, -9.0dB */
+	0x0C0, /* 7, -8.5dB */
+	0x0CC, /* 8, -8.0dB */
+	0x0D8, /* 9, -7.5dB */
+	0x0E5, /* 10, -7.0dB */
+	0x0F2, /* 11, -6.5dB */
+	0x101, /* 12, -6.0dB */
+	0x110, /* 13, -5.5dB */
+	0x120, /* 14, -5.0dB */
+	0x131, /* 15, -4.5dB */
+	0x143, /* 16, -4.0dB */
+	0x156, /* 17, -3.5dB */
+	0x16A, /* 18, -3.0dB */
+	0x180, /* 19, -2.5dB */
+	0x197, /* 20, -2.0dB */
+	0x1AF, /* 21, -1.5dB */
+	0x1C8, /* 22, -1.0dB */
+	0x1E3, /* 23, -0.5dB */
+	0x200, /* 24, +0  dB */
+	0x21E, /* 25, +0.5dB */
+	0x23E, /* 26, +1.0dB */
+	0x261, /* 27, +1.5dB */
+	0x285, /* 28, +2.0dB */
+	0x2AB, /* 29, +2.5dB */
+	0x2D3, /* 30, +3.0dB */
+	0x2FE, /* 31, +3.5dB */
+	0x32B, /* 32, +4.0dB */
+	0x35C, /* 33, +4.5dB */
+	0x38E, /* 34, +5.0dB */
+	0x3C4, /* 35, +5.5dB */
+	0x3FE  /* 36, +6.0dB */
+};
+
+static const u32 rtl8821ae_txscaling_table[TXSCALE_TABLE_SIZE] = {
+	0x081, /* 0, -12.0dB */
+	0x088, /* 1, -11.5dB */
+	0x090, /* 2, -11.0dB */
+	0x099, /* 3, -10.5dB */
+	0x0A2, /* 4, -10.0dB */
+	0x0AC, /* 5, -9.5dB */
+	0x0B6, /* 6, -9.0dB */
+	0x0C0, /* 7, -8.5dB */
+	0x0CC, /* 8, -8.0dB */
+	0x0D8, /* 9, -7.5dB */
+	0x0E5, /* 10, -7.0dB */
+	0x0F2, /* 11, -6.5dB */
+	0x101, /* 12, -6.0dB */
+	0x110, /* 13, -5.5dB */
+	0x120, /* 14, -5.0dB */
+	0x131, /* 15, -4.5dB */
+	0x143, /* 16, -4.0dB */
+	0x156, /* 17, -3.5dB */
+	0x16A, /* 18, -3.0dB */
+	0x180, /* 19, -2.5dB */
+	0x197, /* 20, -2.0dB */
+	0x1AF, /* 21, -1.5dB */
+	0x1C8, /* 22, -1.0dB */
+	0x1E3, /* 23, -0.5dB */
+	0x200, /* 24, +0  dB */
+	0x21E, /* 25, +0.5dB */
+	0x23E, /* 26, +1.0dB */
+	0x261, /* 27, +1.5dB */
+	0x285, /* 28, +2.0dB */
+	0x2AB, /* 29, +2.5dB */
+	0x2D3, /* 30, +3.0dB */
+	0x2FE, /* 31, +3.5dB */
+	0x32B, /* 32, +4.0dB */
+	0x35C, /* 33, +4.5dB */
+	0x38E, /* 34, +5.0dB */
+	0x3C4, /* 35, +5.5dB */
+	0x3FE  /* 36, +6.0dB */
+};
+
+static const u32 ofdmswing_table[] = {
+	0x0b40002d, /* 0, -15.0dB */
+	0x0c000030, /* 1, -14.5dB */
+	0x0cc00033, /* 2, -14.0dB */
+	0x0d800036, /* 3, -13.5dB */
+	0x0e400039, /* 4, -13.0dB */
+	0x0f00003c, /* 5, -12.5dB */
+	0x10000040, /* 6, -12.0dB */
+	0x11000044, /* 7, -11.5dB */
+	0x12000048, /* 8, -11.0dB */
+	0x1300004c, /* 9, -10.5dB */
+	0x14400051, /* 10, -10.0dB */
+	0x15800056, /* 11, -9.5dB */
+	0x16c0005b, /* 12, -9.0dB */
+	0x18000060, /* 13, -8.5dB */
+	0x19800066, /* 14, -8.0dB */
+	0x1b00006c, /* 15, -7.5dB */
+	0x1c800072, /* 16, -7.0dB */
+	0x1e400079, /* 17, -6.5dB */
+	0x20000080, /* 18, -6.0dB */
+	0x22000088, /* 19, -5.5dB */
+	0x24000090, /* 20, -5.0dB */
+	0x26000098, /* 21, -4.5dB */
+	0x288000a2, /* 22, -4.0dB */
+	0x2ac000ab, /* 23, -3.5dB */
+	0x2d4000b5, /* 24, -3.0dB */
+	0x300000c0, /* 25, -2.5dB */
+	0x32c000cb, /* 26, -2.0dB */
+	0x35c000d7, /* 27, -1.5dB */
+	0x390000e4, /* 28, -1.0dB */
+	0x3c8000f2, /* 29, -0.5dB */
+	0x40000100, /* 30, +0dB */
+	0x43c0010f, /* 31, +0.5dB */
+	0x47c0011f, /* 32, +1.0dB */
+	0x4c000130, /* 33, +1.5dB */
+	0x50800142, /* 34, +2.0dB */
+	0x55400155, /* 35, +2.5dB */
+	0x5a400169, /* 36, +3.0dB */
+	0x5fc0017f, /* 37, +3.5dB */
+	0x65400195, /* 38, +4.0dB */
+	0x6b8001ae, /* 39, +4.5dB */
+	0x71c001c7, /* 40, +5.0dB */
+	0x788001e2, /* 41, +5.5dB */
+	0x7f8001fe  /* 42, +6.0dB */
+};
+
+static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = {
+	{0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}, /* 0, -16.0dB */
+	{0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 1, -15.5dB */
+	{0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 2, -15.0dB */
+	{0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 3, -14.5dB */
+	{0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 4, -14.0dB */
+	{0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 5, -13.5dB */
+	{0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 6, -13.0dB */
+	{0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 7, -12.5dB */
+	{0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 8, -12.0dB */
+	{0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 9, -11.5dB */
+	{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 10, -11.0dB */
+	{0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 11, -10.5dB */
+	{0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 12, -10.0dB */
+	{0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 13, -9.5dB */
+	{0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 14, -9.0dB */
+	{0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 15, -8.5dB */
+	{0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */
+	{0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 17, -7.5dB */
+	{0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 18, -7.0dB */
+	{0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 19, -6.5dB */
+	{0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 20, -6.0dB */
+	{0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 21, -5.5dB */
+	{0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 22, -5.0dB */
+	{0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 23, -4.5dB */
+	{0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 24, -4.0dB */
+	{0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 25, -3.5dB */
+	{0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 26, -3.0dB */
+	{0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 27, -2.5dB */
+	{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 28, -2.0dB */
+	{0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 29, -1.5dB */
+	{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 30, -1.0dB */
+	{0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 31, -0.5dB */
+	{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04} /* 32, +0dB */
+};
+
+static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = {
+	{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}, /* 0, -16.0dB */
+	{0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 1, -15.5dB */
+	{0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 2, -15.0dB */
+	{0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 3, -14.5dB */
+	{0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 4, -14.0dB */
+	{0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 5, -13.5dB */
+	{0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 6, -13.0dB */
+	{0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 7, -12.5dB */
+	{0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 8, -12.0dB */
+	{0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 9, -11.5dB */
+	{0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 10, -11.0dB */
+	{0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 11, -10.5dB */
+	{0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 12, -10.0dB */
+	{0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 13, -9.5dB */
+	{0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 14, -9.0dB */
+	{0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 15, -8.5dB */
+	{0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */
+	{0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 17, -7.5dB */
+	{0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 18, -7.0dB */
+	{0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 19, -6.5dB */
+	{0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 20, -6.0dB */
+	{0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 21, -5.5dB */
+	{0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 22, -5.0dB */
+	{0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 23, -4.5dB */
+	{0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 24, -4.0dB */
+	{0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 25, -3.5dB */
+	{0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 26, -3.0dB */
+	{0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 27, -2.5dB */
+	{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 28, -2.0dB */
+	{0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 29, -1.5dB */
+	{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 30, -1.0dB */
+	{0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 31, -0.5dB */
+	{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00} /* 32, +0dB */
+};
+
+static const u32 edca_setting_dl[PEER_MAX] = {
+	0xa44f,		/* 0 UNKNOWN */
+	0x5ea44f,	/* 1 REALTEK_90 */
+	0x5e4322,	/* 2 REALTEK_92SE */
+	0x5ea42b,		/* 3 BROAD	*/
+	0xa44f,		/* 4 RAL */
+	0xa630,		/* 5 ATH */
+	0x5ea630,		/* 6 CISCO */
+	0x5ea42b,		/* 7 MARVELL */
+};
+
+static const u32 edca_setting_ul[PEER_MAX] = {
+	0x5e4322,	/* 0 UNKNOWN */
+	0xa44f,		/* 1 REALTEK_90 */
+	0x5ea44f,	/* 2 REALTEK_92SE */
+	0x5ea32b,	/* 3 BROAD */
+	0x5ea422,	/* 4 RAL */
+	0x5ea322,	/* 5 ATH */
+	0x3ea430,	/* 6 CISCO */
+	0x5ea44f,	/* 7 MARV */
+};
+
+static u8 rtl8818e_delta_swing_table_idx_24gb_p[] = {
+	0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4,
+	4, 4, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9};
+
+static u8 rtl8818e_delta_swing_table_idx_24gb_n[] = {
+	0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6,
+	7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11};
+
+static u8 rtl8812ae_delta_swing_table_idx_24gb_n[]  = {
+	0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6,
+	6, 6, 7, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11};
+
+static u8 rtl8812ae_delta_swing_table_idx_24gb_p[] = {
+	0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6,
+	6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9};
+
+static u8 rtl8812ae_delta_swing_table_idx_24ga_n[] = {
+	0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6,
+	6, 6, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11};
+
+static u8 rtl8812ae_delta_swing_table_idx_24ga_p[] = {
+	0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6,
+	6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9};
+
+static u8 rtl8812ae_delta_swing_table_idx_24gcckb_n[] = {
+	0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6,
+	6, 6, 7, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11};
+
+static u8 rtl8812ae_delta_swing_table_idx_24gcckb_p[] = {
+	0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6,
+	6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9};
+
+static u8 rtl8812ae_delta_swing_table_idx_24gccka_n[] = {
+	0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6,
+	6, 6, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11};
+
+static u8 rtl8812ae_delta_swing_table_idx_24gccka_p[] = {
+	0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6,
+	6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9};
+
+static u8 rtl8812ae_delta_swing_table_idx_5gb_n[][DEL_SW_IDX_SZ] = {
+	{0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7,
+	7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13},
+	{0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
+	7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13},
+	{0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 9, 10, 11,
+	12, 12, 13, 14, 14, 14, 15, 16, 17, 17, 17, 18, 18, 18},
+};
+
+static u8 rtl8812ae_delta_swing_table_idx_5gb_p[][DEL_SW_IDX_SZ] = {
+	{0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8,
+	8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11},
+	{0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8,
+	8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11},
+	{0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8, 9,
+	9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11},
+};
+
+static u8 rtl8812ae_delta_swing_table_idx_5ga_n[][DEL_SW_IDX_SZ] = {
+	{0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8,
+	8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13},
+	{0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9,
+	9, 10, 10, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13},
+	{0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11,
+	12, 13, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 18, 18},
+};
+
+static u8 rtl8812ae_delta_swing_table_idx_5ga_p[][DEL_SW_IDX_SZ] = {
+	{0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 7, 7, 8,
+	8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11},
+	{0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8,
+	9, 9, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11},
+	{0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9,
+	10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11},
+};
+
+static u8 rtl8821ae_delta_swing_table_idx_24gb_n[] = {
+	0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6,
+	6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10};
+
+static u8 rtl8821ae_delta_swing_table_idx_24gb_p[]  = {
+	0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
+	8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12};
+
+static u8 rtl8821ae_delta_swing_table_idx_24ga_n[]  = {
+	0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6,
+	6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10};
+
+static u8 rtl8821ae_delta_swing_table_idx_24ga_p[] = {
+	0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
+	8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12};
+
+static u8 rtl8821ae_delta_swing_table_idx_24gcckb_n[] = {
+	0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6,
+	6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10};
+
+static u8 rtl8821ae_delta_swing_table_idx_24gcckb_p[] = {
+	0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
+	8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12};
+
+static u8 rtl8821ae_delta_swing_table_idx_24gccka_n[] = {
+	0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6,
+	6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10};
+
+static u8 rtl8821ae_delta_swing_table_idx_24gccka_p[] = {
+	0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
+	8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12};
+
+static u8 rtl8821ae_delta_swing_table_idx_5gb_n[][DEL_SW_IDX_SZ] = {
+	{0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+	12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16},
+	{0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+	12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16},
+	{0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+	12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16},
+};
+
+static u8 rtl8821ae_delta_swing_table_idx_5gb_p[][DEL_SW_IDX_SZ] = {
+	{0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+	12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16},
+	{0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+	12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16},
+	{0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+	12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16},
+};
+
+static u8 rtl8821ae_delta_swing_table_idx_5ga_n[][DEL_SW_IDX_SZ] = {
+	{0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+	12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16},
+	{0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+	12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16},
+	{0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+	12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16},
+};
+
+static u8 rtl8821ae_delta_swing_table_idx_5ga_p[][DEL_SW_IDX_SZ] = {
+	{0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+	12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16},
+	{0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+	12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16},
+	{0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11,
+	12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16},
+};
+
+void rtl8821ae_dm_txpower_track_adjust(struct ieee80211_hw *hw,
+				       u8 type, u8 *pdirection,
+				       u32 *poutwrite_val)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+	u8 pwr_val = 0;
+
+	if (type == 0) {
+		if (rtlpriv->dm.swing_idx_ofdm[RF90_PATH_A] <=
+			rtlpriv->dm.swing_idx_ofdm_base[RF90_PATH_A]) {
+			*pdirection = 1;
+			pwr_val = rtldm->swing_idx_ofdm_base[RF90_PATH_A] -
+					rtldm->swing_idx_ofdm[RF90_PATH_A];
+		} else {
+			*pdirection = 2;
+			pwr_val = rtldm->swing_idx_ofdm[RF90_PATH_A] -
+				rtldm->swing_idx_ofdm_base[RF90_PATH_A];
+		}
+	} else if (type == 1) {
+		if (rtldm->swing_idx_cck <= rtldm->swing_idx_cck_base) {
+			*pdirection = 1;
+			pwr_val = rtldm->swing_idx_cck_base -
+					rtldm->swing_idx_cck;
+		} else {
+			*pdirection = 2;
+			pwr_val = rtldm->swing_idx_cck -
+				rtldm->swing_idx_cck_base;
+		}
+	}
+
+	if (pwr_val >= TXPWRTRACK_MAX_IDX && (*pdirection == 1))
+		pwr_val = TXPWRTRACK_MAX_IDX;
+
+	*poutwrite_val = pwr_val | (pwr_val << 8)|
+				(pwr_val << 16)|
+				(pwr_val << 24);
+}
+
+void rtl8821ae_dm_clear_txpower_tracking_state(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_dm *rtldm = rtl_dm(rtlpriv);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
+	u8 p = 0;
+
+	rtldm->swing_idx_cck_base = rtldm->default_cck_index;
+	rtldm->swing_idx_cck = rtldm->default_cck_index;
+	rtldm->cck_index = 0;
+
+	for (p = RF90_PATH_A; p <= RF90_PATH_B; ++p) {
+		rtldm->swing_idx_ofdm_base[p] = rtldm->default_ofdm_index;
+		rtldm->swing_idx_ofdm[p] = rtldm->default_ofdm_index;
+		rtldm->ofdm_index[p] = rtldm->default_ofdm_index;
+
+		rtldm->power_index_offset[p] = 0;
+		rtldm->delta_power_index[p] = 0;
+		rtldm->delta_power_index_last[p] = 0;
+		/*Initial Mix mode power tracking*/
+		rtldm->absolute_ofdm_swing_idx[p] = 0;
+		rtldm->remnant_ofdm_swing_idx[p] = 0;
+	}
+	/*Initial at Modify Tx Scaling Mode*/
+	rtldm->modify_txagc_flag_path_a = false;
+	/*Initial at Modify Tx Scaling Mode*/
+	rtldm->modify_txagc_flag_path_b = false;
+	rtldm->remnant_cck_idx = 0;
+	rtldm->thermalvalue = rtlefuse->eeprom_thermalmeter;
+	rtldm->thermalvalue_iqk = rtlefuse->eeprom_thermalmeter;
+	rtldm->thermalvalue_lck = rtlefuse->eeprom_thermalmeter;
+}
+
+static u8  rtl8821ae_dm_get_swing_index(struct ieee80211_hw *hw)
+{
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 i = 0;
+	u32  bb_swing;
+
+	bb_swing = phy_get_tx_swing_8812A(hw, rtlhal->current_bandtype,
+					  RF90_PATH_A);
+
+	for (i = 0; i < TXSCALE_TABLE_SIZE; ++i)
+		if (bb_swing == rtl8821ae_txscaling_table[i])
+			break;
+
+	return i;
+}
+
+void rtl8821ae_dm_initialize_txpower_tracking_thermalmeter(
+				struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_dm *rtldm = rtl_dm(rtlpriv);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
+	u8 default_swing_index  = 0;
+	u8 p = 0;
+
+	rtlpriv->dm.txpower_track_control = true;
+	rtldm->thermalvalue = rtlefuse->eeprom_thermalmeter;
+	rtldm->thermalvalue_iqk = rtlefuse->eeprom_thermalmeter;
+	rtldm->thermalvalue_lck = rtlefuse->eeprom_thermalmeter;
+	default_swing_index = rtl8821ae_dm_get_swing_index(hw);
+
+	rtldm->default_ofdm_index =
+		(default_swing_index == TXSCALE_TABLE_SIZE) ?
+		24 : default_swing_index;
+	rtldm->default_cck_index = 24;
+
+	rtldm->swing_idx_cck_base = rtldm->default_cck_index;
+	rtldm->cck_index = rtldm->default_cck_index;
+
+	for (p = RF90_PATH_A; p < MAX_RF_PATH; ++p) {
+		rtldm->swing_idx_ofdm_base[p] =
+			rtldm->default_ofdm_index;
+		rtldm->ofdm_index[p] = rtldm->default_ofdm_index;
+		rtldm->delta_power_index[p] = 0;
+		rtldm->power_index_offset[p] = 0;
+		rtldm->delta_power_index_last[p] = 0;
+	}
+}
+
+static void rtl8821ae_dm_diginit(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+	dm_digtable->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f);
+	dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
+	dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
+	dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
+	dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
+	dm_digtable->rx_gain_max = DM_DIG_MAX;
+	dm_digtable->rx_gain_min = DM_DIG_MIN;
+	dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
+	dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
+	dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
+	dm_digtable->pre_cck_cca_thres = 0xff;
+	dm_digtable->cur_cck_cca_thres = 0x83;
+	dm_digtable->forbidden_igi = DM_DIG_MIN;
+	dm_digtable->large_fa_hit = 0;
+	dm_digtable->recover_cnt = 0;
+	dm_digtable->dig_dynamic_min = DM_DIG_MIN;
+	dm_digtable->dig_dynamic_min_1 = DM_DIG_MIN;
+	dm_digtable->media_connect_0 = false;
+	dm_digtable->media_connect_1 = false;
+	rtlpriv->dm.dm_initialgain_enable = true;
+	dm_digtable->bt30_cur_igi = 0x32;
+}
+
+void rtl8821ae_dm_init_edca_turbo(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtlpriv->dm.current_turbo_edca = false;
+	rtlpriv->dm.is_any_nonbepkts = false;
+	rtlpriv->dm.is_cur_rdlstate = false;
+}
+
+void rtl8821ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rate_adaptive *p_ra = &rtlpriv->ra;
+
+	p_ra->ratr_state = DM_RATR_STA_INIT;
+	p_ra->pre_ratr_state = DM_RATR_STA_INIT;
+
+	rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
+	if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
+		rtlpriv->dm.useramask = true;
+	else
+		rtlpriv->dm.useramask = false;
+
+	p_ra->high_rssi_thresh_for_ra = 50;
+	p_ra->low_rssi_thresh_for_ra40m = 20;
+}
+
+static void rtl8821ae_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtlpriv->dm.crystal_cap = rtlpriv->efuse.crystalcap;
+
+	rtlpriv->dm.atc_status = rtl_get_bbreg(hw, ROFDM1_CFOTRACKING, BIT(11));
+	rtlpriv->dm.cfo_threshold = CFO_THRESHOLD_XTAL;
+}
+
+static void rtl8821ae_dm_common_info_self_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 tmp;
+
+	rtlphy->cck_high_power =
+		(bool)rtl_get_bbreg(hw, ODM_REG_CCK_RPT_FORMAT_11AC,
+				    ODM_BIT_CCK_RPT_FORMAT_11AC);
+
+	tmp = (u8)rtl_get_bbreg(hw, ODM_REG_BB_RX_PATH_11AC,
+				ODM_BIT_BB_RX_PATH_11AC);
+	if (tmp & BIT(0))
+		rtlpriv->dm.rfpath_rxenable[0] = true;
+	if (tmp & BIT(1))
+		rtlpriv->dm.rfpath_rxenable[1] = true;
+}
+
+void rtl8821ae_dm_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	spin_lock(&rtlpriv->locks.iqk_lock);
+	rtlphy->lck_inprogress = false;
+	spin_unlock(&rtlpriv->locks.iqk_lock);
+
+	rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
+	rtl8821ae_dm_common_info_self_init(hw);
+	rtl8821ae_dm_diginit(hw);
+	rtl8821ae_dm_init_rate_adaptive_mask(hw);
+	rtl8821ae_dm_init_edca_turbo(hw);
+	rtl8821ae_dm_initialize_txpower_tracking_thermalmeter(hw);
+	rtl8821ae_dm_init_dynamic_atc_switch(hw);
+}
+
+static void rtl8821ae_dm_find_minimum_rssi(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *rtl_dm_dig = &rtlpriv->dm_digtable;
+	struct rtl_mac *mac = rtl_mac(rtlpriv);
+
+	/* Determine the minimum RSSI  */
+	if ((mac->link_state < MAC80211_LINKED) &&
+	    (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
+		rtl_dm_dig->min_undec_pwdb_for_dm = 0;
+		RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+			 "Not connected to any\n");
+	}
+	if (mac->link_state >= MAC80211_LINKED) {
+		if (mac->opmode == NL80211_IFTYPE_AP ||
+		    mac->opmode == NL80211_IFTYPE_ADHOC) {
+			rtl_dm_dig->min_undec_pwdb_for_dm =
+			    rtlpriv->dm.entry_min_undec_sm_pwdb;
+			RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+				 "AP Client PWDB = 0x%lx\n",
+				 rtlpriv->dm.entry_min_undec_sm_pwdb);
+		} else {
+			rtl_dm_dig->min_undec_pwdb_for_dm =
+			    rtlpriv->dm.undec_sm_pwdb;
+			RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+				 "STA Default Port PWDB = 0x%x\n",
+				 rtl_dm_dig->min_undec_pwdb_for_dm);
+		}
+	} else {
+		rtl_dm_dig->min_undec_pwdb_for_dm =
+		    rtlpriv->dm.entry_min_undec_sm_pwdb;
+		RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD,
+			 "AP Ext Port or disconnet PWDB = 0x%x\n",
+			 rtl_dm_dig->min_undec_pwdb_for_dm);
+	}
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+		 "MinUndecoratedPWDBForDM =%d\n",
+		 rtl_dm_dig->min_undec_pwdb_for_dm);
+}
+
+static void  rtl8812ae_dm_rssi_dump_to_register(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtl_write_byte(rtlpriv, RA_RSSI_DUMP,
+		       rtlpriv->stats.rx_rssi_percentage[0]);
+	rtl_write_byte(rtlpriv, RB_RSSI_DUMP,
+		       rtlpriv->stats.rx_rssi_percentage[1]);
+
+	/* Rx EVM*/
+	rtl_write_byte(rtlpriv, RS1_RX_EVM_DUMP,
+		       rtlpriv->stats.rx_evm_dbm[0]);
+	rtl_write_byte(rtlpriv, RS2_RX_EVM_DUMP,
+		       rtlpriv->stats.rx_evm_dbm[1]);
+
+	/*Rx SNR*/
+	rtl_write_byte(rtlpriv, RA_RX_SNR_DUMP,
+		       (u8)(rtlpriv->stats.rx_snr_db[0]));
+	rtl_write_byte(rtlpriv, RB_RX_SNR_DUMP,
+		       (u8)(rtlpriv->stats.rx_snr_db[1]));
+
+	/*Rx Cfo_Short*/
+	rtl_write_word(rtlpriv, RA_CFO_SHORT_DUMP,
+		       rtlpriv->stats.rx_cfo_short[0]);
+	rtl_write_word(rtlpriv, RB_CFO_SHORT_DUMP,
+		       rtlpriv->stats.rx_cfo_short[1]);
+
+	/*Rx Cfo_Tail*/
+	rtl_write_word(rtlpriv, RA_CFO_LONG_DUMP,
+		       rtlpriv->stats.rx_cfo_tail[0]);
+	rtl_write_word(rtlpriv, RB_CFO_LONG_DUMP,
+		       rtlpriv->stats.rx_cfo_tail[1]);
+}
+
+static void rtl8821ae_dm_check_rssi_monitor(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_sta_info *drv_priv;
+	u8 h2c_parameter[4] = { 0 };
+	long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff;
+	u8 stbc_tx = 0;
+	u64 cur_txokcnt = 0, cur_rxokcnt = 0;
+	static u64 last_txokcnt = 0, last_rxokcnt;
+
+	cur_txokcnt = rtlpriv->stats.txbytesunicast - last_txokcnt;
+	cur_rxokcnt = rtlpriv->stats.rxbytesunicast - last_rxokcnt;
+	last_txokcnt = rtlpriv->stats.txbytesunicast;
+	last_rxokcnt = rtlpriv->stats.rxbytesunicast;
+	if (cur_rxokcnt > (last_txokcnt * 6))
+		h2c_parameter[3] = 0x01;
+	else
+		h2c_parameter[3] = 0x00;
+
+	/* AP & ADHOC & MESH */
+	if (mac->opmode == NL80211_IFTYPE_AP ||
+	    mac->opmode == NL80211_IFTYPE_ADHOC ||
+	    mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+		spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+		list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
+			if (drv_priv->rssi_stat.undec_sm_pwdb <
+					tmp_entry_min_pwdb)
+				tmp_entry_min_pwdb =
+					drv_priv->rssi_stat.undec_sm_pwdb;
+			if (drv_priv->rssi_stat.undec_sm_pwdb >
+					tmp_entry_max_pwdb)
+				tmp_entry_max_pwdb =
+					drv_priv->rssi_stat.undec_sm_pwdb;
+		}
+		spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+
+		/* If associated entry is found */
+		if (tmp_entry_max_pwdb != 0) {
+			rtlpriv->dm.entry_max_undec_sm_pwdb =
+				tmp_entry_max_pwdb;
+			RTPRINT(rtlpriv, FDM, DM_PWDB,
+				"EntryMaxPWDB = 0x%lx(%ld)\n",
+				tmp_entry_max_pwdb, tmp_entry_max_pwdb);
+		} else {
+			rtlpriv->dm.entry_max_undec_sm_pwdb = 0;
+		}
+		/* If associated entry is found */
+		if (tmp_entry_min_pwdb != 0xff) {
+			rtlpriv->dm.entry_min_undec_sm_pwdb =
+				tmp_entry_min_pwdb;
+			RTPRINT(rtlpriv, FDM, DM_PWDB,
+				"EntryMinPWDB = 0x%lx(%ld)\n",
+				tmp_entry_min_pwdb, tmp_entry_min_pwdb);
+		} else {
+			rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
+		}
+	}
+	/* Indicate Rx signal strength to FW. */
+	if (rtlpriv->dm.useramask) {
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+			if (mac->mode == WIRELESS_MODE_AC_24G ||
+			    mac->mode == WIRELESS_MODE_AC_5G ||
+			    mac->mode == WIRELESS_MODE_AC_ONLY)
+				stbc_tx = (mac->vht_cur_stbc &
+					   STBC_VHT_ENABLE_TX) ? 1 : 0;
+			else
+				stbc_tx = (mac->ht_cur_stbc &
+					   STBC_HT_ENABLE_TX) ? 1 : 0;
+			h2c_parameter[3] |= stbc_tx << 1;
+		}
+		h2c_parameter[2] =
+			(u8)(rtlpriv->dm.undec_sm_pwdb & 0xFF);
+		h2c_parameter[1] = 0x20;
+		h2c_parameter[0] = 0;
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+			rtl8821ae_fill_h2c_cmd(hw, H2C_RSSI_21AE_REPORT, 4,
+					       h2c_parameter);
+		else
+			rtl8821ae_fill_h2c_cmd(hw, H2C_RSSI_21AE_REPORT, 3,
+					       h2c_parameter);
+	} else {
+		rtl_write_byte(rtlpriv, 0x4fe, rtlpriv->dm.undec_sm_pwdb);
+	}
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+		rtl8812ae_dm_rssi_dump_to_register(hw);
+	rtl8821ae_dm_find_minimum_rssi(hw);
+	dm_digtable->rssi_val_min = rtlpriv->dm_digtable.min_undec_pwdb_for_dm;
+}
+
+void rtl8821ae_dm_write_cck_cca_thres(struct ieee80211_hw *hw, u8 current_cca)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+	if (dm_digtable->cur_cck_cca_thres != current_cca)
+		rtl_write_byte(rtlpriv, DM_REG_CCK_CCA_11AC, current_cca);
+
+	dm_digtable->pre_cck_cca_thres = dm_digtable->cur_cck_cca_thres;
+	dm_digtable->cur_cck_cca_thres = current_cca;
+}
+
+void rtl8821ae_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+	if (dm_digtable->stop_dig)
+		return;
+
+	if (dm_digtable->cur_igvalue != current_igi) {
+		rtl_set_bbreg(hw, DM_REG_IGI_A_11AC,
+			      DM_BIT_IGI_11AC, current_igi);
+		if (rtlpriv->phy.rf_type != RF_1T1R)
+			rtl_set_bbreg(hw, DM_REG_IGI_B_11AC,
+				      DM_BIT_IGI_11AC, current_igi);
+	}
+	dm_digtable->cur_igvalue = current_igi;
+}
+
+static void rtl8821ae_dm_dig(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 dig_dynamic_min;
+	u8 dig_max_of_min;
+	bool first_connect, first_disconnect;
+	u8 dm_dig_max, dm_dig_min, offset;
+	u8 current_igi = dm_digtable->cur_igvalue;
+
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "\n");
+
+	if (mac->act_scanning) {
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+			 "Return: In Scan Progress\n");
+		return;
+	}
+
+	/*add by Neil Chen to avoid PSD is processing*/
+	dig_dynamic_min = dm_digtable->dig_dynamic_min;
+	first_connect = (mac->link_state >= MAC80211_LINKED) &&
+			(!dm_digtable->media_connect_0);
+	first_disconnect = (mac->link_state < MAC80211_LINKED) &&
+			(dm_digtable->media_connect_0);
+
+	/*1 Boundary Decision*/
+
+	dm_dig_max = 0x5A;
+
+	if (rtlhal->hw_type != HARDWARE_TYPE_RTL8821AE)
+		dm_dig_min = DM_DIG_MIN;
+	else
+		dm_dig_min = 0x1C;
+
+	dig_max_of_min = DM_DIG_MAX_AP;
+
+	if (mac->link_state >= MAC80211_LINKED) {
+		if (rtlhal->hw_type != HARDWARE_TYPE_RTL8821AE)
+			offset = 20;
+		else
+			offset = 10;
+
+		if ((dm_digtable->rssi_val_min + offset) > dm_dig_max)
+			dm_digtable->rx_gain_max = dm_dig_max;
+		else if ((dm_digtable->rssi_val_min + offset) < dm_dig_min)
+			dm_digtable->rx_gain_max = dm_dig_min;
+		else
+			dm_digtable->rx_gain_max =
+				dm_digtable->rssi_val_min + offset;
+
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+			 "dm_digtable->rssi_val_min=0x%x,dm_digtable->rx_gain_max = 0x%x",
+			 dm_digtable->rssi_val_min,
+			 dm_digtable->rx_gain_max);
+		if (rtlpriv->dm.one_entry_only) {
+			offset = 0;
+
+			if (dm_digtable->rssi_val_min - offset < dm_dig_min)
+				dig_dynamic_min = dm_dig_min;
+			else if (dm_digtable->rssi_val_min -
+				offset > dig_max_of_min)
+				dig_dynamic_min = dig_max_of_min;
+			else
+				dig_dynamic_min =
+					dm_digtable->rssi_val_min - offset;
+
+			RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+				 "bOneEntryOnly=TRUE, dig_dynamic_min=0x%x\n",
+				 dig_dynamic_min);
+		} else {
+			dig_dynamic_min = dm_dig_min;
+		}
+	} else {
+		dm_digtable->rx_gain_max = dm_dig_max;
+		dig_dynamic_min = dm_dig_min;
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+			 "No Link\n");
+	}
+
+	if (rtlpriv->falsealm_cnt.cnt_all > 10000) {
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+			 "Abnornally false alarm case.\n");
+
+		if (dm_digtable->large_fa_hit != 3)
+			dm_digtable->large_fa_hit++;
+		if (dm_digtable->forbidden_igi < current_igi) {
+			dm_digtable->forbidden_igi = current_igi;
+			dm_digtable->large_fa_hit = 1;
+		}
+
+		if (dm_digtable->large_fa_hit >= 3) {
+			if ((dm_digtable->forbidden_igi + 1) >
+				dm_digtable->rx_gain_max)
+				dm_digtable->rx_gain_min =
+					dm_digtable->rx_gain_max;
+			else
+				dm_digtable->rx_gain_min =
+					(dm_digtable->forbidden_igi + 1);
+			dm_digtable->recover_cnt = 3600;
+		}
+	} else {
+		/*Recovery mechanism for IGI lower bound*/
+		if (dm_digtable->recover_cnt != 0) {
+			dm_digtable->recover_cnt--;
+		} else {
+			if (dm_digtable->large_fa_hit < 3) {
+				if ((dm_digtable->forbidden_igi - 1) <
+				    dig_dynamic_min) {
+					dm_digtable->forbidden_igi =
+						dig_dynamic_min;
+					dm_digtable->rx_gain_min =
+						dig_dynamic_min;
+					RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+						 "Normal Case: At Lower Bound\n");
+				} else {
+					dm_digtable->forbidden_igi--;
+					dm_digtable->rx_gain_min =
+					  (dm_digtable->forbidden_igi + 1);
+					RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+						 "Normal Case: Approach Lower Bound\n");
+				}
+			} else {
+				dm_digtable->large_fa_hit = 0;
+			}
+		}
+	}
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+		 "pDM_DigTable->LargeFAHit=%d\n",
+		 dm_digtable->large_fa_hit);
+
+	if (rtlpriv->dm.dbginfo.num_qry_beacon_pkt < 10)
+		dm_digtable->rx_gain_min = dm_dig_min;
+
+	if (dm_digtable->rx_gain_min > dm_digtable->rx_gain_max)
+		dm_digtable->rx_gain_min = dm_digtable->rx_gain_max;
+
+	/*Adjust initial gain by false alarm*/
+	if (mac->link_state >= MAC80211_LINKED) {
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+			 "DIG AfterLink\n");
+		if (first_connect) {
+			if (dm_digtable->rssi_val_min <= dig_max_of_min)
+				current_igi = dm_digtable->rssi_val_min;
+			else
+				current_igi = dig_max_of_min;
+			RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+				 "First Connect\n");
+		} else {
+			if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH2)
+				current_igi = current_igi + 4;
+			else if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH1)
+				current_igi = current_igi + 2;
+			else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0)
+				current_igi = current_igi - 2;
+
+			if ((rtlpriv->dm.dbginfo.num_qry_beacon_pkt < 10) &&
+			    (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH1)) {
+				current_igi = dm_digtable->rx_gain_min;
+				RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+					 "Beacon is less than 10 and FA is less than 768, IGI GOES TO 0x1E!!!!!!!!!!!!\n");
+			}
+		}
+	} else {
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+			 "DIG BeforeLink\n");
+		if (first_disconnect) {
+			current_igi = dm_digtable->rx_gain_min;
+			RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+				 "First DisConnect\n");
+		} else {
+			/* 2012.03.30 LukeLee: enable DIG before
+			 * link but with very high thresholds
+			 */
+			if (rtlpriv->falsealm_cnt.cnt_all > 2000)
+				current_igi = current_igi + 4;
+			else if (rtlpriv->falsealm_cnt.cnt_all > 600)
+				current_igi = current_igi + 2;
+			else if (rtlpriv->falsealm_cnt.cnt_all < 300)
+				current_igi = current_igi - 2;
+
+			if (current_igi >= 0x3e)
+				current_igi = 0x3e;
+
+			RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "England DIG\n");
+		}
+	}
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+		 "DIG End Adjust IGI\n");
+	/* Check initial gain by upper/lower bound*/
+
+	if (current_igi > dm_digtable->rx_gain_max)
+		current_igi = dm_digtable->rx_gain_max;
+	if (current_igi < dm_digtable->rx_gain_min)
+		current_igi = dm_digtable->rx_gain_min;
+
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+		 "rx_gain_max=0x%x, rx_gain_min=0x%x\n",
+		dm_digtable->rx_gain_max, dm_digtable->rx_gain_min);
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+		 "TotalFA=%d\n", rtlpriv->falsealm_cnt.cnt_all);
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+		 "CurIGValue=0x%x\n", current_igi);
+
+	rtl8821ae_dm_write_dig(hw, current_igi);
+	dm_digtable->media_connect_0 =
+		((mac->link_state >= MAC80211_LINKED) ? true : false);
+	dm_digtable->dig_dynamic_min = dig_dynamic_min;
+}
+
+static void rtl8821ae_dm_common_info_self_update(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 cnt = 0;
+	struct rtl_sta_info *drv_priv;
+
+	rtlpriv->dm.tx_rate = 0xff;
+
+	rtlpriv->dm.one_entry_only = false;
+
+	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_STATION &&
+	    rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
+		rtlpriv->dm.one_entry_only = true;
+		return;
+	}
+
+	if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP ||
+	    rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC ||
+	    rtlpriv->mac80211.opmode == NL80211_IFTYPE_MESH_POINT) {
+		spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+		list_for_each_entry(drv_priv, &rtlpriv->entry_list, list)
+			cnt++;
+		spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+
+		if (cnt == 1)
+			rtlpriv->dm.one_entry_only = true;
+	}
+}
+
+static void rtl8821ae_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct false_alarm_statistics *falsealm_cnt = &rtlpriv->falsealm_cnt;
+	u32 cck_enable = 0;
+
+	/*read OFDM FA counter*/
+	falsealm_cnt->cnt_ofdm_fail =
+		rtl_get_bbreg(hw, ODM_REG_OFDM_FA_11AC, BMASKLWORD);
+	falsealm_cnt->cnt_cck_fail =
+		rtl_get_bbreg(hw, ODM_REG_CCK_FA_11AC, BMASKLWORD);
+
+	cck_enable =  rtl_get_bbreg(hw, ODM_REG_BB_RX_PATH_11AC, BIT(28));
+	if (cck_enable)  /*if(pDM_Odm->pBandType == ODM_BAND_2_4G)*/
+		falsealm_cnt->cnt_all = falsealm_cnt->cnt_ofdm_fail +
+					falsealm_cnt->cnt_cck_fail;
+	else
+		falsealm_cnt->cnt_all = falsealm_cnt->cnt_ofdm_fail;
+
+	/*reset OFDM FA coutner*/
+	rtl_set_bbreg(hw, ODM_REG_OFDM_FA_RST_11AC, BIT(17), 1);
+	rtl_set_bbreg(hw, ODM_REG_OFDM_FA_RST_11AC, BIT(17), 0);
+	/* reset CCK FA counter*/
+	rtl_set_bbreg(hw, ODM_REG_CCK_FA_RST_11AC, BIT(15), 0);
+	rtl_set_bbreg(hw, ODM_REG_CCK_FA_RST_11AC, BIT(15), 1);
+
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "Cnt_Cck_fail=%d\n",
+		 falsealm_cnt->cnt_cck_fail);
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "cnt_ofdm_fail=%d\n",
+		 falsealm_cnt->cnt_ofdm_fail);
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "Total False Alarm=%d\n",
+		 falsealm_cnt->cnt_all);
+}
+
+static void rtl8812ae_dm_check_txpower_tracking_thermalmeter(
+		struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	static u8 tm_trigger;
+
+	if (!tm_trigger) {
+		rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER_88E,
+			      BIT(17) | BIT(16), 0x03);
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "Trigger 8812 Thermal Meter!!\n");
+		tm_trigger = 1;
+		return;
+	}
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "Schedule TxPowerTracking direct call!!\n");
+	rtl8812ae_dm_txpower_tracking_callback_thermalmeter(hw);
+	tm_trigger = 0;
+}
+
+static void rtl8821ae_dm_iq_calibrate(struct ieee80211_hw *hw)
+{
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+	if (mac->link_state >= MAC80211_LINKED) {
+		if (rtldm->linked_interval < 3)
+			rtldm->linked_interval++;
+
+		if (rtldm->linked_interval == 2) {
+			if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+				rtl8812ae_phy_iq_calibrate(hw, false);
+			else
+				rtl8821ae_phy_iq_calibrate(hw, false);
+		}
+	} else {
+		rtldm->linked_interval = 0;
+	}
+}
+
+static void rtl8812ae_get_delta_swing_table(struct ieee80211_hw *hw,
+					    u8 **up_a, u8 **down_a,
+					    u8 **up_b, u8 **down_b)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+	u8 channel = rtlphy->current_channel;
+	u8 rate = rtldm->tx_rate;
+
+	if (1 <= channel && channel <= 14) {
+		if (RTL8821AE_RX_HAL_IS_CCK_RATE(rate)) {
+			*up_a = rtl8812ae_delta_swing_table_idx_24gccka_p;
+			*down_a = rtl8812ae_delta_swing_table_idx_24gccka_n;
+			*up_b = rtl8812ae_delta_swing_table_idx_24gcckb_p;
+			*down_b = rtl8812ae_delta_swing_table_idx_24gcckb_n;
+		} else {
+			*up_a = rtl8812ae_delta_swing_table_idx_24ga_p;
+			*down_a = rtl8812ae_delta_swing_table_idx_24ga_n;
+			*up_b = rtl8812ae_delta_swing_table_idx_24gb_p;
+			*down_b = rtl8812ae_delta_swing_table_idx_24gb_n;
+		}
+	} else if (36 <= channel && channel <= 64) {
+		*up_a = rtl8812ae_delta_swing_table_idx_5ga_p[0];
+		*down_a = rtl8812ae_delta_swing_table_idx_5ga_n[0];
+		*up_b = rtl8812ae_delta_swing_table_idx_5gb_p[0];
+		*down_b = rtl8812ae_delta_swing_table_idx_5gb_n[0];
+	} else if (100 <= channel && channel <= 140) {
+		*up_a = rtl8812ae_delta_swing_table_idx_5ga_p[1];
+		*down_a = rtl8812ae_delta_swing_table_idx_5ga_n[1];
+		*up_b = rtl8812ae_delta_swing_table_idx_5gb_p[1];
+		*down_b = rtl8812ae_delta_swing_table_idx_5gb_n[1];
+	} else if (149 <= channel && channel <= 173) {
+		*up_a = rtl8812ae_delta_swing_table_idx_5ga_p[2];
+		*down_a = rtl8812ae_delta_swing_table_idx_5ga_n[2];
+		*up_b = rtl8812ae_delta_swing_table_idx_5gb_p[2];
+		*down_b = rtl8812ae_delta_swing_table_idx_5gb_n[2];
+	} else {
+	    *up_a = (u8 *)rtl8818e_delta_swing_table_idx_24gb_p;
+	    *down_a = (u8 *)rtl8818e_delta_swing_table_idx_24gb_n;
+	    *up_b = (u8 *)rtl8818e_delta_swing_table_idx_24gb_p;
+	    *down_b = (u8 *)rtl8818e_delta_swing_table_idx_24gb_n;
+	}
+}
+
+void rtl8821ae_dm_update_init_rate(struct ieee80211_hw *hw, u8 rate)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_dm	*rtldm = rtl_dm(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 p = 0;
+
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "Get C2H Command! Rate=0x%x\n", rate);
+
+	rtldm->tx_rate = rate;
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+		rtl8821ae_dm_txpwr_track_set_pwr(hw, MIX_MODE, RF90_PATH_A, 0);
+	} else {
+		for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++)
+			rtl8812ae_dm_txpwr_track_set_pwr(hw, MIX_MODE, p, 0);
+	}
+}
+
+u8 rtl8821ae_hw_rate_to_mrate(struct ieee80211_hw *hw, u8 rate)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 ret_rate = MGN_1M;
+
+	switch (rate) {
+	case DESC_RATE1M:
+		ret_rate = MGN_1M;
+		break;
+	case DESC_RATE2M:
+		ret_rate = MGN_2M;
+		break;
+	case DESC_RATE5_5M:
+		ret_rate = MGN_5_5M;
+		break;
+	case DESC_RATE11M:
+		ret_rate = MGN_11M;
+		break;
+	case DESC_RATE6M:
+		ret_rate = MGN_6M;
+		break;
+	case DESC_RATE9M:
+		ret_rate = MGN_9M;
+		break;
+	case DESC_RATE12M:
+		ret_rate = MGN_12M;
+		break;
+	case DESC_RATE18M:
+		ret_rate = MGN_18M;
+		break;
+	case DESC_RATE24M:
+		ret_rate = MGN_24M;
+		break;
+	case DESC_RATE36M:
+		ret_rate = MGN_36M;
+		break;
+	case DESC_RATE48M:
+		ret_rate = MGN_48M;
+		break;
+	case DESC_RATE54M:
+		ret_rate = MGN_54M;
+		break;
+	case DESC_RATEMCS0:
+		ret_rate = MGN_MCS0;
+		break;
+	case DESC_RATEMCS1:
+		ret_rate = MGN_MCS1;
+		break;
+	case DESC_RATEMCS2:
+		ret_rate = MGN_MCS2;
+		break;
+	case DESC_RATEMCS3:
+		ret_rate = MGN_MCS3;
+		break;
+	case DESC_RATEMCS4:
+		ret_rate = MGN_MCS4;
+		break;
+	case DESC_RATEMCS5:
+		ret_rate = MGN_MCS5;
+		break;
+	case DESC_RATEMCS6:
+		ret_rate = MGN_MCS6;
+		break;
+	case DESC_RATEMCS7:
+		ret_rate = MGN_MCS7;
+		break;
+	case DESC_RATEMCS8:
+		ret_rate = MGN_MCS8;
+		break;
+	case DESC_RATEMCS9:
+		ret_rate = MGN_MCS9;
+		break;
+	case DESC_RATEMCS10:
+		ret_rate = MGN_MCS10;
+		break;
+	case DESC_RATEMCS11:
+		ret_rate = MGN_MCS11;
+		break;
+	case DESC_RATEMCS12:
+		ret_rate = MGN_MCS12;
+		break;
+	case DESC_RATEMCS13:
+		ret_rate = MGN_MCS13;
+		break;
+	case DESC_RATEMCS14:
+		ret_rate = MGN_MCS14;
+		break;
+	case DESC_RATEMCS15:
+		ret_rate = MGN_MCS15;
+		break;
+	case DESC_RATEVHT1SS_MCS0:
+		ret_rate = MGN_VHT1SS_MCS0;
+		break;
+	case DESC_RATEVHT1SS_MCS1:
+		ret_rate = MGN_VHT1SS_MCS1;
+		break;
+	case DESC_RATEVHT1SS_MCS2:
+		ret_rate = MGN_VHT1SS_MCS2;
+		break;
+	case DESC_RATEVHT1SS_MCS3:
+		ret_rate = MGN_VHT1SS_MCS3;
+		break;
+	case DESC_RATEVHT1SS_MCS4:
+		ret_rate = MGN_VHT1SS_MCS4;
+		break;
+	case DESC_RATEVHT1SS_MCS5:
+		ret_rate = MGN_VHT1SS_MCS5;
+		break;
+	case DESC_RATEVHT1SS_MCS6:
+		ret_rate = MGN_VHT1SS_MCS6;
+		break;
+	case DESC_RATEVHT1SS_MCS7:
+		ret_rate = MGN_VHT1SS_MCS7;
+		break;
+	case DESC_RATEVHT1SS_MCS8:
+		ret_rate = MGN_VHT1SS_MCS8;
+		break;
+	case DESC_RATEVHT1SS_MCS9:
+		ret_rate = MGN_VHT1SS_MCS9;
+		break;
+	case DESC_RATEVHT2SS_MCS0:
+		ret_rate = MGN_VHT2SS_MCS0;
+		break;
+	case DESC_RATEVHT2SS_MCS1:
+		ret_rate = MGN_VHT2SS_MCS1;
+		break;
+	case DESC_RATEVHT2SS_MCS2:
+		ret_rate = MGN_VHT2SS_MCS2;
+		break;
+	case DESC_RATEVHT2SS_MCS3:
+		ret_rate = MGN_VHT2SS_MCS3;
+		break;
+	case DESC_RATEVHT2SS_MCS4:
+		ret_rate = MGN_VHT2SS_MCS4;
+		break;
+	case DESC_RATEVHT2SS_MCS5:
+		ret_rate = MGN_VHT2SS_MCS5;
+		break;
+	case DESC_RATEVHT2SS_MCS6:
+		ret_rate = MGN_VHT2SS_MCS6;
+		break;
+	case DESC_RATEVHT2SS_MCS7:
+		ret_rate = MGN_VHT2SS_MCS7;
+		break;
+	case DESC_RATEVHT2SS_MCS8:
+		ret_rate = MGN_VHT2SS_MCS8;
+		break;
+	case DESC_RATEVHT2SS_MCS9:
+		ret_rate = MGN_VHT2SS_MCS9;
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "HwRateToMRate8812(): Non supported Rate [%x]!!!\n",
+			 rate);
+		break;
+	}
+	return ret_rate;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	odm_TxPwrTrackSetPwr88E()
+ *
+ * Overview:	88E change all channel tx power accordign to flag.
+ *				OFDM & CCK are all different.
+ *
+ * Input:		NONE
+ *
+ * Output:		NONE
+ *
+ * Return:		NONE
+ *
+ * Revised History:
+ *	When		Who		Remark
+ *	04/23/2012	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------
+ */
+void rtl8812ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw,
+				      enum pwr_track_control_method method,
+				      u8 rf_path, u8 channel_mapped_index)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_dm	*rtldm = rtl_dm(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u32 final_swing_idx[2];
+	u8 pwr_tracking_limit = 26; /*+1.0dB*/
+	u8 tx_rate = 0xFF;
+	char final_ofdm_swing_index = 0;
+
+	if (rtldm->tx_rate != 0xFF)
+		tx_rate =
+			rtl8821ae_hw_rate_to_mrate(hw, rtldm->tx_rate);
+
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "===>rtl8812ae_dm_txpwr_track_set_pwr\n");
+	/*20130429 Mimic Modify High Rate BBSwing Limit.*/
+	if (tx_rate != 0xFF) {
+		/*CCK*/
+		if ((tx_rate >= MGN_1M) && (tx_rate <= MGN_11M))
+			pwr_tracking_limit = 32; /*+4dB*/
+		/*OFDM*/
+		else if ((tx_rate >= MGN_6M) && (tx_rate <= MGN_48M))
+			pwr_tracking_limit = 30; /*+3dB*/
+		else if (tx_rate == MGN_54M)
+			pwr_tracking_limit = 28; /*+2dB*/
+		/*HT*/
+		 /*QPSK/BPSK*/
+		else if ((tx_rate >= MGN_MCS0) && (tx_rate <= MGN_MCS2))
+			pwr_tracking_limit = 34; /*+5dB*/
+		 /*16QAM*/
+		else if ((tx_rate >= MGN_MCS3) && (tx_rate <= MGN_MCS4))
+			pwr_tracking_limit = 30; /*+3dB*/
+		 /*64QAM*/
+		else if ((tx_rate >= MGN_MCS5) && (tx_rate <= MGN_MCS7))
+			pwr_tracking_limit = 28; /*+2dB*/
+		 /*QPSK/BPSK*/
+		else if ((tx_rate >= MGN_MCS8) && (tx_rate <= MGN_MCS10))
+			pwr_tracking_limit = 34; /*+5dB*/
+		 /*16QAM*/
+		else if ((tx_rate >= MGN_MCS11) && (tx_rate <= MGN_MCS12))
+			pwr_tracking_limit = 30; /*+3dB*/
+		 /*64QAM*/
+		else if ((tx_rate >= MGN_MCS13) && (tx_rate <= MGN_MCS15))
+			pwr_tracking_limit = 28; /*+2dB*/
+
+		/*2 VHT*/
+		 /*QPSK/BPSK*/
+		else if ((tx_rate >= MGN_VHT1SS_MCS0) &&
+			 (tx_rate <= MGN_VHT1SS_MCS2))
+			pwr_tracking_limit = 34; /*+5dB*/
+		 /*16QAM*/
+		else if ((tx_rate >= MGN_VHT1SS_MCS3) &&
+			 (tx_rate <= MGN_VHT1SS_MCS4))
+			pwr_tracking_limit = 30; /*+3dB*/
+		 /*64QAM*/
+		else if ((tx_rate >= MGN_VHT1SS_MCS5) &&
+			 (tx_rate <= MGN_VHT1SS_MCS6))
+			pwr_tracking_limit = 28; /*+2dB*/
+		else if (tx_rate == MGN_VHT1SS_MCS7) /*64QAM*/
+			pwr_tracking_limit = 26; /*+1dB*/
+		else if (tx_rate == MGN_VHT1SS_MCS8) /*256QAM*/
+			pwr_tracking_limit = 24; /*+0dB*/
+		else if (tx_rate == MGN_VHT1SS_MCS9) /*256QAM*/
+			pwr_tracking_limit = 22; /*-1dB*/
+		 /*QPSK/BPSK*/
+		else if ((tx_rate >= MGN_VHT2SS_MCS0) &&
+			 (tx_rate <= MGN_VHT2SS_MCS2))
+			pwr_tracking_limit = 34; /*+5dB*/
+		 /*16QAM*/
+		else if ((tx_rate >= MGN_VHT2SS_MCS3) &&
+			 (tx_rate <= MGN_VHT2SS_MCS4))
+			pwr_tracking_limit = 30; /*+3dB*/
+		 /*64QAM*/
+		else if ((tx_rate >= MGN_VHT2SS_MCS5) &&
+			 (tx_rate <= MGN_VHT2SS_MCS6))
+			pwr_tracking_limit = 28; /*+2dB*/
+		else if (tx_rate == MGN_VHT2SS_MCS7) /*64QAM*/
+			pwr_tracking_limit = 26; /*+1dB*/
+		else if (tx_rate == MGN_VHT2SS_MCS8) /*256QAM*/
+			pwr_tracking_limit = 24; /*+0dB*/
+		else if (tx_rate == MGN_VHT2SS_MCS9) /*256QAM*/
+			pwr_tracking_limit = 22; /*-1dB*/
+		else
+			pwr_tracking_limit = 24;
+	}
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "TxRate=0x%x, PwrTrackingLimit=%d\n",
+		 tx_rate, pwr_tracking_limit);
+
+	if (method == BBSWING) {
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "===>rtl8812ae_dm_txpwr_track_set_pwr\n");
+
+		if (rf_path == RF90_PATH_A) {
+			u32 tmp;
+
+			final_swing_idx[RF90_PATH_A] =
+				(rtldm->ofdm_index[RF90_PATH_A] >
+				pwr_tracking_limit) ?
+				pwr_tracking_limit :
+				rtldm->ofdm_index[RF90_PATH_A];
+			tmp = final_swing_idx[RF90_PATH_A];
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "pDM_Odm->RFCalibrateInfo.OFDM_index[ODM_RF_PATH_A]=%d,pDM_Odm->RealBbSwingIdx[ODM_RF_PATH_A]=%d\n",
+				 rtldm->ofdm_index[RF90_PATH_A],
+				 final_swing_idx[RF90_PATH_A]);
+
+			rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000,
+				      txscaling_tbl[tmp]);
+		} else {
+			u32 tmp;
+
+			final_swing_idx[RF90_PATH_B] =
+				rtldm->ofdm_index[RF90_PATH_B] >
+				pwr_tracking_limit ?
+				pwr_tracking_limit :
+				rtldm->ofdm_index[RF90_PATH_B];
+			tmp = final_swing_idx[RF90_PATH_B];
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "pDM_Odm->RFCalibrateInfo.OFDM_index[ODM_RF_PATH_B]=%d, pDM_Odm->RealBbSwingIdx[ODM_RF_PATH_B]=%d\n",
+				 rtldm->ofdm_index[RF90_PATH_B],
+				 final_swing_idx[RF90_PATH_B]);
+
+			rtl_set_bbreg(hw, RB_TXSCALE, 0xFFE00000,
+				      txscaling_tbl[tmp]);
+		}
+	} else if (method == MIX_MODE) {
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "pDM_Odm->DefaultOfdmIndex=%d, pDM_Odm->Aboslute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n",
+			 rtldm->default_ofdm_index,
+			 rtldm->absolute_ofdm_swing_idx[rf_path],
+			 rf_path);
+
+		final_ofdm_swing_index = rtldm->default_ofdm_index +
+				rtldm->absolute_ofdm_swing_idx[rf_path];
+
+		if (rf_path == RF90_PATH_A) {
+			/*BBSwing higher then Limit*/
+			if (final_ofdm_swing_index > pwr_tracking_limit) {
+				rtldm->remnant_cck_idx =
+					final_ofdm_swing_index -
+					pwr_tracking_limit;
+				/* CCK Follow the same compensation value
+				 * as Path A
+				 */
+				rtldm->remnant_ofdm_swing_idx[rf_path] =
+					final_ofdm_swing_index -
+					pwr_tracking_limit;
+
+				rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000,
+					      txscaling_tbl[pwr_tracking_limit]);
+
+				rtldm->modify_txagc_flag_path_a = true;
+
+				/*Set TxAGC Page C{};*/
+				rtl8821ae_phy_set_txpower_level_by_path(hw,
+					rtlphy->current_channel,
+					RF90_PATH_A);
+
+				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+					 "******Path_A Over BBSwing Limit ,PwrTrackingLimit = %d ,Remnant TxAGC Value = %d\n",
+					 pwr_tracking_limit,
+					 rtldm->remnant_ofdm_swing_idx[rf_path]);
+			} else if (final_ofdm_swing_index < 0) {
+				rtldm->remnant_cck_idx = final_ofdm_swing_index;
+				/* CCK Follow the same compensate value as Path A*/
+				rtldm->remnant_ofdm_swing_idx[rf_path] =
+					final_ofdm_swing_index;
+
+				rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000,
+					txscaling_tbl[0]);
+
+				rtldm->modify_txagc_flag_path_a = true;
+
+				/*Set TxAGC Page C{};*/
+				rtl8821ae_phy_set_txpower_level_by_path(hw,
+					rtlphy->current_channel, RF90_PATH_A);
+
+				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+					 "******Path_A Lower then BBSwing lower bound  0 , Remnant TxAGC Value = %d\n",
+					 rtldm->remnant_ofdm_swing_idx[rf_path]);
+			} else {
+				rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000,
+					txscaling_tbl[(u8)final_ofdm_swing_index]);
+
+				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+					 "******Path_A Compensate with BBSwing, Final_OFDM_Swing_Index = %d\n",
+					final_ofdm_swing_index);
+				/*If TxAGC has changed, reset TxAGC again*/
+				if (rtldm->modify_txagc_flag_path_a) {
+					rtldm->remnant_cck_idx = 0;
+					rtldm->remnant_ofdm_swing_idx[rf_path] = 0;
+
+					/*Set TxAGC Page C{};*/
+					rtl8821ae_phy_set_txpower_level_by_path(hw,
+						rtlphy->current_channel, RF90_PATH_A);
+					rtldm->modify_txagc_flag_path_a = false;
+
+					RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
+						 DBG_LOUD,
+						 "******Path_A pDM_Odm->Modify_TxAGC_Flag = FALSE\n");
+				}
+			}
+		}
+		/*BBSwing higher then Limit*/
+		if (rf_path == RF90_PATH_B) {
+			if (final_ofdm_swing_index > pwr_tracking_limit) {
+				rtldm->remnant_ofdm_swing_idx[rf_path] =
+					final_ofdm_swing_index -
+					pwr_tracking_limit;
+
+				rtl_set_bbreg(hw, RB_TXSCALE,
+					0xFFE00000,
+					txscaling_tbl[pwr_tracking_limit]);
+
+				rtldm->modify_txagc_flag_path_b = true;
+
+				/*Set TxAGC Page E{};*/
+				rtl8821ae_phy_set_txpower_level_by_path(hw,
+					rtlphy->current_channel, RF90_PATH_B);
+
+				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+					 "******Path_B Over BBSwing Limit , PwrTrackingLimit = %d , Remnant TxAGC Value = %d\n",
+					 pwr_tracking_limit,
+					 rtldm->remnant_ofdm_swing_idx[rf_path]);
+			} else if (final_ofdm_swing_index < 0) {
+				rtldm->remnant_ofdm_swing_idx[rf_path] =
+					final_ofdm_swing_index;
+
+				rtl_set_bbreg(hw, RB_TXSCALE, 0xFFE00000,
+					      txscaling_tbl[0]);
+
+				rtldm->modify_txagc_flag_path_b = true;
+
+				/*Set TxAGC Page E{};*/
+				rtl8821ae_phy_set_txpower_level_by_path(hw,
+					rtlphy->current_channel, RF90_PATH_B);
+
+				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+					 "******Path_B Lower then BBSwing lower bound  0 , Remnant TxAGC Value = %d\n",
+					 rtldm->remnant_ofdm_swing_idx[rf_path]);
+			} else {
+				rtl_set_bbreg(hw, RB_TXSCALE, 0xFFE00000,
+					txscaling_tbl[(u8)final_ofdm_swing_index]);
+
+				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+					 "******Path_B Compensate with BBSwing ,Final_OFDM_Swing_Index = %d\n",
+					final_ofdm_swing_index);
+				 /*If TxAGC has changed, reset TxAGC again*/
+				if (rtldm->modify_txagc_flag_path_b) {
+					rtldm->remnant_ofdm_swing_idx[rf_path] = 0;
+
+					/*Set TxAGC Page E{};*/
+					rtl8821ae_phy_set_txpower_level_by_path(hw,
+					rtlphy->current_channel, RF90_PATH_B);
+
+					rtldm->modify_txagc_flag_path_b =
+						false;
+
+					RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+						 "******Path_B pDM_Odm->Modify_TxAGC_Flag = FALSE\n");
+				}
+			}
+		}
+	} else {
+		return;
+	}
+}
+
+void rtl8812ae_dm_txpower_tracking_callback_thermalmeter(
+	struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct rtl_dm	*rtldm = rtl_dm(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 thermal_value = 0, delta, delta_lck, delta_iqk, p = 0, i = 0;
+	u8 thermal_value_avg_count = 0;
+	u32 thermal_value_avg = 0;
+	/* OFDM BB Swing should be less than +3.0dB, */
+	u8 ofdm_min_index = 6;
+	 /* GetRightChnlPlaceforIQK(pHalData->CurrentChannel)*/
+	u8 index_for_channel = 0;
+	/* 1. The following TWO tables decide
+	 * the final index of OFDM/CCK swing table.
+	 */
+	u8 *delta_swing_table_idx_tup_a;
+	u8 *delta_swing_table_idx_tdown_a;
+	u8 *delta_swing_table_idx_tup_b;
+	u8 *delta_swing_table_idx_tdown_b;
+
+	/*2. Initilization ( 7 steps in total )*/
+	rtl8812ae_get_delta_swing_table(hw,
+		(u8 **)&delta_swing_table_idx_tup_a,
+		(u8 **)&delta_swing_table_idx_tdown_a,
+		(u8 **)&delta_swing_table_idx_tup_b,
+		(u8 **)&delta_swing_table_idx_tdown_b);
+
+	rtldm->txpower_trackinginit = true;
+
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "pDM_Odm->BbSwingIdxCckBase: %d, pDM_Odm->BbSwingIdxOfdmBase[A]:%d, pDM_Odm->DefaultOfdmIndex: %d\n",
+		 rtldm->swing_idx_cck_base,
+		 rtldm->swing_idx_ofdm_base[RF90_PATH_A],
+		 rtldm->default_ofdm_index);
+
+	thermal_value = (u8)rtl_get_rfreg(hw, RF90_PATH_A,
+		/*0x42: RF Reg[15:10] 88E*/
+		RF_T_METER_8812A, 0xfc00);
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "Thermal Meter = 0x%X, EFUSE Thermal Base = 0x%X\n",
+		 thermal_value, rtlefuse->eeprom_thermalmeter);
+	if (!rtldm->txpower_track_control ||
+	    rtlefuse->eeprom_thermalmeter == 0 ||
+	    rtlefuse->eeprom_thermalmeter == 0xFF)
+		return;
+
+	/* 3. Initialize ThermalValues of RFCalibrateInfo*/
+
+	if (rtlhal->reloadtxpowerindex)
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "reload ofdm index for band switch\n");
+
+	/*4. Calculate average thermal meter*/
+	rtldm->thermalvalue_avg[rtldm->thermalvalue_avg_index] = thermal_value;
+	rtldm->thermalvalue_avg_index++;
+	if (rtldm->thermalvalue_avg_index == AVG_THERMAL_NUM_8812A)
+		/*Average times =  c.AverageThermalNum*/
+		rtldm->thermalvalue_avg_index = 0;
+
+	for (i = 0; i < AVG_THERMAL_NUM_8812A; i++) {
+		if (rtldm->thermalvalue_avg[i]) {
+			thermal_value_avg += rtldm->thermalvalue_avg[i];
+			thermal_value_avg_count++;
+		}
+	}
+	/*Calculate Average ThermalValue after average enough times*/
+	if (thermal_value_avg_count) {
+		thermal_value = (u8)(thermal_value_avg /
+				thermal_value_avg_count);
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "AVG Thermal Meter = 0x%X, EFUSE Thermal Base = 0x%X\n",
+			 thermal_value, rtlefuse->eeprom_thermalmeter);
+	}
+
+	/*5. Calculate delta, delta_LCK, delta_IQK.
+	 *"delta" here is used to determine whether
+	 *thermal value changes or not.
+	 */
+	delta = (thermal_value > rtldm->thermalvalue) ?
+		(thermal_value - rtldm->thermalvalue) :
+		(rtldm->thermalvalue - thermal_value);
+	delta_lck = (thermal_value > rtldm->thermalvalue_lck) ?
+		(thermal_value - rtldm->thermalvalue_lck) :
+		(rtldm->thermalvalue_lck - thermal_value);
+	delta_iqk = (thermal_value > rtldm->thermalvalue_iqk) ?
+		(thermal_value - rtldm->thermalvalue_iqk) :
+		(rtldm->thermalvalue_iqk - thermal_value);
+
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "(delta, delta_LCK, delta_IQK) = (%d, %d, %d)\n",
+		 delta, delta_lck, delta_iqk);
+
+	/* 6. If necessary, do LCK.
+	 * Delta temperature is equal to or larger than 20 centigrade.
+	 */
+	if (delta_lck >= IQK_THRESHOLD) {
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "delta_LCK(%d) >= Threshold_IQK(%d)\n",
+			 delta_lck, IQK_THRESHOLD);
+		rtldm->thermalvalue_lck = thermal_value;
+		rtl8821ae_phy_lc_calibrate(hw);
+	}
+
+	/*7. If necessary, move the index of swing table to adjust Tx power.*/
+
+	if (delta > 0 && rtldm->txpower_track_control) {
+		/* "delta" here is used to record the
+		 * absolute value of differrence.
+		 */
+		delta = thermal_value > rtlefuse->eeprom_thermalmeter ?
+			(thermal_value - rtlefuse->eeprom_thermalmeter) :
+			(rtlefuse->eeprom_thermalmeter - thermal_value);
+
+		if (delta >= TXPWR_TRACK_TABLE_SIZE)
+			delta = TXPWR_TRACK_TABLE_SIZE - 1;
+
+		/*7.1 The Final Power Index = BaseIndex + PowerIndexOffset*/
+
+		if (thermal_value > rtlefuse->eeprom_thermalmeter) {
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "delta_swing_table_idx_tup_a[%d] = %d\n",
+				 delta, delta_swing_table_idx_tup_a[delta]);
+			rtldm->delta_power_index_last[RF90_PATH_A] =
+				rtldm->delta_power_index[RF90_PATH_A];
+			rtldm->delta_power_index[RF90_PATH_A] =
+				delta_swing_table_idx_tup_a[delta];
+
+			rtldm->absolute_ofdm_swing_idx[RF90_PATH_A] =
+				delta_swing_table_idx_tup_a[delta];
+			/*Record delta swing for mix mode power tracking*/
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "******Temp is higher and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
+			rtldm->absolute_ofdm_swing_idx[RF90_PATH_A]);
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "delta_swing_table_idx_tup_b[%d] = %d\n",
+				 delta, delta_swing_table_idx_tup_b[delta]);
+			rtldm->delta_power_index_last[RF90_PATH_B] =
+				rtldm->delta_power_index[RF90_PATH_B];
+			rtldm->delta_power_index[RF90_PATH_B] =
+				delta_swing_table_idx_tup_b[delta];
+
+			rtldm->absolute_ofdm_swing_idx[RF90_PATH_B] =
+				delta_swing_table_idx_tup_b[delta];
+			/*Record delta swing for mix mode power tracking*/
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "******Temp is higher and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n",
+				 rtldm->absolute_ofdm_swing_idx[RF90_PATH_B]);
+		} else {
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "delta_swing_table_idx_tdown_a[%d] = %d\n",
+				 delta, delta_swing_table_idx_tdown_a[delta]);
+
+			rtldm->delta_power_index_last[RF90_PATH_A] =
+				rtldm->delta_power_index[RF90_PATH_A];
+			rtldm->delta_power_index[RF90_PATH_A] =
+				-1 * delta_swing_table_idx_tdown_a[delta];
+
+			rtldm->absolute_ofdm_swing_idx[RF90_PATH_A] =
+				-1 * delta_swing_table_idx_tdown_a[delta];
+			/* Record delta swing for mix mode power tracking*/
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "******Temp is lower and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
+				 rtldm->absolute_ofdm_swing_idx[RF90_PATH_A]);
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "deltaSwingTableIdx_TDOWN_B[%d] = %d\n",
+				 delta, delta_swing_table_idx_tdown_b[delta]);
+
+			rtldm->delta_power_index_last[RF90_PATH_B] =
+				rtldm->delta_power_index[RF90_PATH_B];
+			rtldm->delta_power_index[RF90_PATH_B] =
+				-1 * delta_swing_table_idx_tdown_b[delta];
+
+			rtldm->absolute_ofdm_swing_idx[RF90_PATH_B] =
+				-1 * delta_swing_table_idx_tdown_b[delta];
+			/*Record delta swing for mix mode power tracking*/
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "******Temp is lower and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n",
+				 rtldm->absolute_ofdm_swing_idx[RF90_PATH_B]);
+		}
+
+		for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++) {
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "============================= [Path-%c]Calculating PowerIndexOffset =============================\n",
+				 (p == RF90_PATH_A ? 'A' : 'B'));
+
+			if (rtldm->delta_power_index[p] ==
+				rtldm->delta_power_index_last[p])
+				/*If Thermal value changes but lookup
+				table value still the same*/
+				rtldm->power_index_offset[p] = 0;
+			else
+				rtldm->power_index_offset[p] =
+					rtldm->delta_power_index[p] -
+					rtldm->delta_power_index_last[p];
+				/* Power Index Diff between 2
+				 * times Power Tracking
+				 */
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "[Path-%c] PowerIndexOffset(%d) =DeltaPowerIndex(%d) -DeltaPowerIndexLast(%d)\n",
+				 (p == RF90_PATH_A ? 'A' : 'B'),
+				 rtldm->power_index_offset[p],
+				 rtldm->delta_power_index[p] ,
+				 rtldm->delta_power_index_last[p]);
+
+			rtldm->ofdm_index[p] =
+					rtldm->swing_idx_ofdm_base[p] +
+					rtldm->power_index_offset[p];
+			rtldm->cck_index =
+					rtldm->swing_idx_cck_base +
+					rtldm->power_index_offset[p];
+
+			rtldm->swing_idx_cck = rtldm->cck_index;
+			rtldm->swing_idx_ofdm[p] = rtldm->ofdm_index[p];
+
+			/****Print BB Swing Base and Index Offset */
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "The 'CCK' final index(%d) = BaseIndex(%d) + PowerIndexOffset(%d)\n",
+				 rtldm->swing_idx_cck,
+				rtldm->swing_idx_cck_base,
+				rtldm->power_index_offset[p]);
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "The 'OFDM' final index(%d) = BaseIndex[%c](%d) + PowerIndexOffset(%d)\n",
+				 rtldm->swing_idx_ofdm[p],
+				 (p == RF90_PATH_A ? 'A' : 'B'),
+				 rtldm->swing_idx_ofdm_base[p],
+				 rtldm->power_index_offset[p]);
+
+			/*7.1 Handle boundary conditions of index.*/
+
+			if (rtldm->ofdm_index[p] > TXSCALE_TABLE_SIZE - 1)
+				rtldm->ofdm_index[p] = TXSCALE_TABLE_SIZE - 1;
+			else if (rtldm->ofdm_index[p] < ofdm_min_index)
+				rtldm->ofdm_index[p] = ofdm_min_index;
+		}
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "\n\n====================================================================================\n");
+		if (rtldm->cck_index > TXSCALE_TABLE_SIZE - 1)
+			rtldm->cck_index = TXSCALE_TABLE_SIZE - 1;
+		else if (rtldm->cck_index < 0)
+			rtldm->cck_index = 0;
+	} else {
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "The thermal meter is unchanged or TxPowerTracking OFF(%d): ThermalValue: %d , pDM_Odm->RFCalibrateInfo.ThermalValue: %d\n",
+			 rtldm->txpower_track_control,
+			 thermal_value,
+			 rtldm->thermalvalue);
+
+		for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++)
+			rtldm->power_index_offset[p] = 0;
+	}
+	/*Print Swing base & current*/
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "TxPowerTracking: [CCK] Swing Current Index: %d,Swing Base Index: %d\n",
+		 rtldm->cck_index, rtldm->swing_idx_cck_base);
+	for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++) {
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "TxPowerTracking: [OFDM] Swing Current Index: %d,Swing Base Index[%c]: %d\n",
+			 rtldm->ofdm_index[p],
+			 (p == RF90_PATH_A ? 'A' : 'B'),
+			 rtldm->swing_idx_ofdm_base[p]);
+	}
+
+	if ((rtldm->power_index_offset[RF90_PATH_A] != 0 ||
+		rtldm->power_index_offset[RF90_PATH_B] != 0) &&
+		rtldm->txpower_track_control) {
+		/*7.2 Configure the Swing Table to adjust Tx Power.
+		 *Always TRUE after Tx Power is adjusted by power tracking.
+		 *
+		 *2012/04/23 MH According to Luke's suggestion,
+		 *we can not write BB digital
+		 *to increase TX power. Otherwise, EVM will be bad.
+		 *
+		 *2012/04/25 MH Add for tx power tracking to set
+		 *tx power in tx agc for 88E.
+		 */
+		if (thermal_value > rtldm->thermalvalue) {
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "Temperature Increasing(A): delta_pi: %d , delta_t: %d, Now_t: %d,EFUSE_t: %d, Last_t: %d\n",
+				 rtldm->power_index_offset[RF90_PATH_A],
+				 delta, thermal_value,
+				 rtlefuse->eeprom_thermalmeter,
+				 rtldm->thermalvalue);
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "Temperature Increasing(B): delta_pi: %d ,delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
+				 rtldm->power_index_offset[RF90_PATH_B],
+				 delta, thermal_value,
+				 rtlefuse->eeprom_thermalmeter,
+				 rtldm->thermalvalue);
+		} else if (thermal_value < rtldm->thermalvalue) { /*Low temperature*/
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "Temperature Decreasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
+				 rtldm->power_index_offset[RF90_PATH_A],
+				 delta, thermal_value,
+				 rtlefuse->eeprom_thermalmeter,
+				 rtldm->thermalvalue);
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "Temperature Decreasing(B): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
+				 rtldm->power_index_offset[RF90_PATH_B],
+				 delta, thermal_value,
+				 rtlefuse->eeprom_thermalmeter,
+				 rtldm->thermalvalue);
+		}
+
+		if (thermal_value > rtlefuse->eeprom_thermalmeter) {
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "Temperature(%d) higher than PG value(%d)\n",
+				 thermal_value, rtlefuse->eeprom_thermalmeter);
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "**********Enter POWER Tracking MIX_MODE**********\n");
+			for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++)
+				rtl8812ae_dm_txpwr_track_set_pwr(hw, MIX_MODE,
+								 p, 0);
+		} else {
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "Temperature(%d) lower than PG value(%d)\n",
+				 thermal_value, rtlefuse->eeprom_thermalmeter);
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "**********Enter POWER Tracking MIX_MODE**********\n");
+			for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++)
+				rtl8812ae_dm_txpwr_track_set_pwr(hw, MIX_MODE,
+								 p, index_for_channel);
+		}
+		/*Record last time Power Tracking result as base.*/
+		rtldm->swing_idx_cck_base = rtldm->swing_idx_cck;
+		for (p = RF90_PATH_A; p < MAX_PATH_NUM_8812A; p++)
+				rtldm->swing_idx_ofdm_base[p] =
+					rtldm->swing_idx_ofdm[p];
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "pDM_Odm->RFCalibrateInfo.ThermalValue =%d ThermalValue= %d\n",
+				 rtldm->thermalvalue, thermal_value);
+		/*Record last Power Tracking Thermal Value*/
+		rtldm->thermalvalue = thermal_value;
+	}
+	/*Delta temperature is equal to or larger than
+	20 centigrade (When threshold is 8).*/
+	if (delta_iqk >= IQK_THRESHOLD)
+		rtl8812ae_do_iqk(hw, delta_iqk, thermal_value, 8);
+
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "<===rtl8812ae_dm_txpower_tracking_callback_thermalmeter\n");
+}
+
+static void rtl8821ae_get_delta_swing_table(struct ieee80211_hw *hw, u8 **up_a,
+					    u8 **down_a, u8 **up_b, u8 **down_b)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+	u8 channel = rtlphy->current_channel;
+	u8 rate = rtldm->tx_rate;
+
+	if (1 <= channel && channel <= 14) {
+		if (RTL8821AE_RX_HAL_IS_CCK_RATE(rate)) {
+			*up_a = rtl8821ae_delta_swing_table_idx_24gccka_p;
+			*down_a = rtl8821ae_delta_swing_table_idx_24gccka_n;
+			*up_b = rtl8821ae_delta_swing_table_idx_24gcckb_p;
+			*down_b = rtl8821ae_delta_swing_table_idx_24gcckb_n;
+		} else {
+			*up_a = rtl8821ae_delta_swing_table_idx_24ga_p;
+			*down_a = rtl8821ae_delta_swing_table_idx_24ga_n;
+			*up_b = rtl8821ae_delta_swing_table_idx_24gb_p;
+			*down_b = rtl8821ae_delta_swing_table_idx_24gb_n;
+		}
+	} else if (36 <= channel && channel <= 64) {
+		*up_a = rtl8821ae_delta_swing_table_idx_5ga_p[0];
+		*down_a = rtl8821ae_delta_swing_table_idx_5ga_n[0];
+		*up_b = rtl8821ae_delta_swing_table_idx_5gb_p[0];
+		*down_b = rtl8821ae_delta_swing_table_idx_5gb_n[0];
+	} else if (100 <= channel && channel <= 140) {
+		*up_a = rtl8821ae_delta_swing_table_idx_5ga_p[1];
+		*down_a = rtl8821ae_delta_swing_table_idx_5ga_n[1];
+		*up_b = rtl8821ae_delta_swing_table_idx_5gb_p[1];
+		*down_b = rtl8821ae_delta_swing_table_idx_5gb_n[1];
+	} else if (149 <= channel && channel <= 173) {
+		*up_a = rtl8821ae_delta_swing_table_idx_5ga_p[2];
+		*down_a = rtl8821ae_delta_swing_table_idx_5ga_n[2];
+		*up_b = rtl8821ae_delta_swing_table_idx_5gb_p[2];
+		*down_b = rtl8821ae_delta_swing_table_idx_5gb_n[2];
+	} else {
+	    *up_a = (u8 *)rtl8818e_delta_swing_table_idx_24gb_p;
+	    *down_a = (u8 *)rtl8818e_delta_swing_table_idx_24gb_n;
+	    *up_b = (u8 *)rtl8818e_delta_swing_table_idx_24gb_p;
+	    *down_b = (u8 *)rtl8818e_delta_swing_table_idx_24gb_n;
+	}
+	return;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	odm_TxPwrTrackSetPwr88E()
+ *
+ * Overview:	88E change all channel tx power accordign to flag.
+ *				OFDM & CCK are all different.
+ *
+ * Input:		NONE
+ *
+ * Output:		NONE
+ *
+ * Return:		NONE
+ *
+ * Revised History:
+ *	When		Who		Remark
+ *	04/23/2012	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------
+ */
+void rtl8821ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw,
+				      enum pwr_track_control_method method,
+				      u8 rf_path, u8 channel_mapped_index)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_dm	*rtldm = rtl_dm(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u32 final_swing_idx[1];
+	u8 pwr_tracking_limit = 26; /*+1.0dB*/
+	u8 tx_rate = 0xFF;
+	char final_ofdm_swing_index = 0;
+
+	if (rtldm->tx_rate != 0xFF)
+		tx_rate = rtl8821ae_hw_rate_to_mrate(hw, rtldm->tx_rate);
+
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "===>rtl8812ae_dm_txpwr_track_set_pwr\n");
+
+	if (tx_rate != 0xFF) { /* Mimic Modify High Rate BBSwing Limit.*/
+		/*CCK*/
+		if ((tx_rate >= MGN_1M) && (tx_rate <= MGN_11M))
+			pwr_tracking_limit = 32; /*+4dB*/
+		/*OFDM*/
+		else if ((tx_rate >= MGN_6M) && (tx_rate <= MGN_48M))
+			pwr_tracking_limit = 30; /*+3dB*/
+		else if (tx_rate == MGN_54M)
+			pwr_tracking_limit = 28; /*+2dB*/
+		/*HT*/
+		/*QPSK/BPSK*/
+		else if ((tx_rate >= MGN_MCS0) && (tx_rate <= MGN_MCS2))
+			pwr_tracking_limit = 34; /*+5dB*/
+		/*16QAM*/
+		else if ((tx_rate >= MGN_MCS3) && (tx_rate <= MGN_MCS4))
+			pwr_tracking_limit = 30; /*+3dB*/
+		/*64QAM*/
+		else if ((tx_rate >= MGN_MCS5) && (tx_rate <= MGN_MCS7))
+			pwr_tracking_limit = 28; /*+2dB*/
+		/*2 VHT*/
+		/*QPSK/BPSK*/
+		else if ((tx_rate >= MGN_VHT1SS_MCS0) &&
+			(tx_rate <= MGN_VHT1SS_MCS2))
+			pwr_tracking_limit = 34; /*+5dB*/
+		/*16QAM*/
+		else if ((tx_rate >= MGN_VHT1SS_MCS3) &&
+			(tx_rate <= MGN_VHT1SS_MCS4))
+			pwr_tracking_limit = 30; /*+3dB*/
+		/*64QAM*/
+		else if ((tx_rate >= MGN_VHT1SS_MCS5) &&
+			(tx_rate <= MGN_VHT1SS_MCS6))
+			pwr_tracking_limit = 28; /*+2dB*/
+		else if (tx_rate == MGN_VHT1SS_MCS7) /*64QAM*/
+			pwr_tracking_limit = 26; /*+1dB*/
+		else if (tx_rate == MGN_VHT1SS_MCS8) /*256QAM*/
+			pwr_tracking_limit = 24; /*+0dB*/
+		else if (tx_rate == MGN_VHT1SS_MCS9) /*256QAM*/
+			pwr_tracking_limit = 22; /*-1dB*/
+		else
+			pwr_tracking_limit = 24;
+	}
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "TxRate=0x%x, PwrTrackingLimit=%d\n",
+		 tx_rate, pwr_tracking_limit);
+
+	if (method == BBSWING) {
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "===>rtl8812ae_dm_txpwr_track_set_pwr\n");
+		if (rf_path == RF90_PATH_A) {
+			final_swing_idx[RF90_PATH_A] =
+				(rtldm->ofdm_index[RF90_PATH_A] >
+				pwr_tracking_limit) ?
+				pwr_tracking_limit :
+				rtldm->ofdm_index[RF90_PATH_A];
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "pDM_Odm->RFCalibrateInfo.OFDM_index[ODM_RF_PATH_A]=%d,pDM_Odm->RealBbSwingIdx[ODM_RF_PATH_A]=%d\n",
+				 rtldm->ofdm_index[RF90_PATH_A],
+				 final_swing_idx[RF90_PATH_A]);
+
+			rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000,
+				txscaling_tbl[final_swing_idx[RF90_PATH_A]]);
+		}
+	} else if (method == MIX_MODE) {
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "pDM_Odm->DefaultOfdmIndex=%d,pDM_Odm->Aboslute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n",
+			 rtldm->default_ofdm_index,
+			 rtldm->absolute_ofdm_swing_idx[rf_path],
+			 rf_path);
+
+		final_ofdm_swing_index =
+			rtldm->default_ofdm_index +
+			rtldm->absolute_ofdm_swing_idx[rf_path];
+		/*BBSwing higher then Limit*/
+		if (rf_path == RF90_PATH_A) {
+			if (final_ofdm_swing_index > pwr_tracking_limit) {
+				rtldm->remnant_cck_idx =
+					final_ofdm_swing_index -
+					pwr_tracking_limit;
+				/* CCK Follow the same compensate value as Path A*/
+				rtldm->remnant_ofdm_swing_idx[rf_path] =
+					final_ofdm_swing_index -
+					pwr_tracking_limit;
+
+				rtl_set_bbreg(hw, RA_TXSCALE,
+					0xFFE00000,
+					txscaling_tbl[pwr_tracking_limit]);
+
+				rtldm->modify_txagc_flag_path_a = true;
+
+				/*Set TxAGC Page C{};*/
+				rtl8821ae_phy_set_txpower_level_by_path(hw,
+					rtlphy->current_channel,
+					RF90_PATH_A);
+
+				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+					" ******Path_A Over BBSwing Limit , PwrTrackingLimit = %d , Remnant TxAGC Value = %d\n",
+					 pwr_tracking_limit,
+					 rtldm->remnant_ofdm_swing_idx[rf_path]);
+			} else if (final_ofdm_swing_index < 0) {
+				rtldm->remnant_cck_idx = final_ofdm_swing_index;
+				/* CCK Follow the same compensate value as Path A*/
+				rtldm->remnant_ofdm_swing_idx[rf_path] =
+					final_ofdm_swing_index;
+
+				rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000,
+					txscaling_tbl[0]);
+
+				rtldm->modify_txagc_flag_path_a = true;
+
+				/*Set TxAGC Page C{};*/
+				rtl8821ae_phy_set_txpower_level_by_path(hw,
+					rtlphy->current_channel, RF90_PATH_A);
+
+				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+					 "******Path_A Lower then BBSwing lower bound  0 , Remnant TxAGC Value = %d\n",
+					 rtldm->remnant_ofdm_swing_idx[rf_path]);
+			} else {
+				rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000,
+					txscaling_tbl[(u8)final_ofdm_swing_index]);
+
+				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+					 "******Path_A Compensate with BBSwing ,Final_OFDM_Swing_Index = %d\n",
+					 final_ofdm_swing_index);
+				/*If TxAGC has changed, reset TxAGC again*/
+				if (rtldm->modify_txagc_flag_path_a) {
+					rtldm->remnant_cck_idx = 0;
+					rtldm->remnant_ofdm_swing_idx[rf_path] = 0;
+
+					/*Set TxAGC Page C{};*/
+					rtl8821ae_phy_set_txpower_level_by_path(hw,
+						rtlphy->current_channel, RF90_PATH_A);
+
+					rtldm->modify_txagc_flag_path_a = false;
+
+					RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
+						 DBG_LOUD,
+						 "******Path_A pDM_Odm->Modify_TxAGC_Flag= FALSE\n");
+				}
+			}
+		}
+	} else {
+		return;
+	}
+}
+
+void rtl8821ae_dm_txpower_tracking_callback_thermalmeter(
+	struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct rtl_dm	*rtldm = rtl_dm(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	u8 thermal_value = 0, delta, delta_lck, delta_iqk, p = 0, i = 0;
+	u8 thermal_value_avg_count = 0;
+	u32 thermal_value_avg = 0;
+
+	u8 ofdm_min_index = 6;  /*OFDM BB Swing should be less than +3.0dB */
+	/* GetRightChnlPlaceforIQK(pHalData->CurrentChannel)*/
+	u8 index_for_channel = 0;
+
+	/* 1. The following TWO tables decide the final
+	 * index of OFDM/CCK swing table.
+	 */
+	u8 *delta_swing_table_idx_tup_a;
+	u8 *delta_swing_table_idx_tdown_a;
+	u8 *delta_swing_table_idx_tup_b;
+	u8 *delta_swing_table_idx_tdown_b;
+
+	/*2. Initilization ( 7 steps in total )*/
+	rtl8821ae_get_delta_swing_table(hw, (u8 **)&delta_swing_table_idx_tup_a,
+					(u8 **)&delta_swing_table_idx_tdown_a,
+					(u8 **)&delta_swing_table_idx_tup_b,
+					(u8 **)&delta_swing_table_idx_tdown_b);
+
+	rtldm->txpower_trackinginit = true;
+
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "===>rtl8812ae_dm_txpower_tracking_callback_thermalmeter,\n pDM_Odm->BbSwingIdxCckBase: %d,pDM_Odm->BbSwingIdxOfdmBase[A]:%d, pDM_Odm->DefaultOfdmIndex: %d\n",
+		 rtldm->swing_idx_cck_base,
+		 rtldm->swing_idx_ofdm_base[RF90_PATH_A],
+		 rtldm->default_ofdm_index);
+	/*0x42: RF Reg[15:10] 88E*/
+	thermal_value = (u8)rtl_get_rfreg(hw,
+		RF90_PATH_A, RF_T_METER_8812A, 0xfc00);
+	if (!rtldm->txpower_track_control ||
+		rtlefuse->eeprom_thermalmeter == 0 ||
+		rtlefuse->eeprom_thermalmeter == 0xFF)
+		return;
+
+	/* 3. Initialize ThermalValues of RFCalibrateInfo*/
+
+	if (rtlhal->reloadtxpowerindex) {
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "reload ofdm index for band switch\n");
+	}
+
+	/*4. Calculate average thermal meter*/
+	rtldm->thermalvalue_avg[rtldm->thermalvalue_avg_index] = thermal_value;
+	rtldm->thermalvalue_avg_index++;
+	if (rtldm->thermalvalue_avg_index == AVG_THERMAL_NUM_8812A)
+		/*Average times =  c.AverageThermalNum*/
+		rtldm->thermalvalue_avg_index = 0;
+
+	for (i = 0; i < AVG_THERMAL_NUM_8812A; i++) {
+		if (rtldm->thermalvalue_avg[i]) {
+			thermal_value_avg += rtldm->thermalvalue_avg[i];
+			thermal_value_avg_count++;
+		}
+	}
+	/*Calculate Average ThermalValue after average enough times*/
+	if (thermal_value_avg_count) {
+		thermal_value = (u8)(thermal_value_avg /
+				thermal_value_avg_count);
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "AVG Thermal Meter = 0x%X, EFUSE Thermal Base = 0x%X\n",
+			 thermal_value, rtlefuse->eeprom_thermalmeter);
+	}
+
+	/*5. Calculate delta, delta_LCK, delta_IQK.
+	 *"delta" here is used to determine whether
+	 * thermal value changes or not.
+	 */
+	delta = (thermal_value > rtldm->thermalvalue) ?
+		(thermal_value - rtldm->thermalvalue) :
+		(rtldm->thermalvalue - thermal_value);
+	delta_lck = (thermal_value > rtldm->thermalvalue_lck) ?
+		(thermal_value - rtldm->thermalvalue_lck) :
+		(rtldm->thermalvalue_lck - thermal_value);
+	delta_iqk = (thermal_value > rtldm->thermalvalue_iqk) ?
+		(thermal_value - rtldm->thermalvalue_iqk) :
+		(rtldm->thermalvalue_iqk - thermal_value);
+
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "(delta, delta_LCK, delta_IQK) = (%d, %d, %d)\n",
+		 delta, delta_lck, delta_iqk);
+
+	/* 6. If necessary, do LCK.	*/
+	/*Delta temperature is equal to or larger than 20 centigrade.*/
+	if (delta_lck >= IQK_THRESHOLD) {
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "delta_LCK(%d) >= Threshold_IQK(%d)\n",
+			 delta_lck, IQK_THRESHOLD);
+		rtldm->thermalvalue_lck = thermal_value;
+		rtl8821ae_phy_lc_calibrate(hw);
+	}
+
+	/*7. If necessary, move the index of swing table to adjust Tx power.*/
+
+	if (delta > 0 && rtldm->txpower_track_control) {
+		/*"delta" here is used to record the
+		 * absolute value of differrence.
+		 */
+		delta = thermal_value > rtlefuse->eeprom_thermalmeter ?
+			(thermal_value - rtlefuse->eeprom_thermalmeter) :
+			(rtlefuse->eeprom_thermalmeter - thermal_value);
+
+		if (delta >= TXSCALE_TABLE_SIZE)
+			delta = TXSCALE_TABLE_SIZE - 1;
+
+		/*7.1 The Final Power Index = BaseIndex + PowerIndexOffset*/
+
+		if (thermal_value > rtlefuse->eeprom_thermalmeter) {
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "delta_swing_table_idx_tup_a[%d] = %d\n",
+				 delta, delta_swing_table_idx_tup_a[delta]);
+			rtldm->delta_power_index_last[RF90_PATH_A] =
+				rtldm->delta_power_index[RF90_PATH_A];
+			rtldm->delta_power_index[RF90_PATH_A] =
+				delta_swing_table_idx_tup_a[delta];
+
+			rtldm->absolute_ofdm_swing_idx[RF90_PATH_A] =
+				delta_swing_table_idx_tup_a[delta];
+			/*Record delta swing for mix mode power tracking*/
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "******Temp is higher and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
+				 rtldm->absolute_ofdm_swing_idx[RF90_PATH_A]);
+		} else {
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "delta_swing_table_idx_tdown_a[%d] = %d\n",
+				 delta, delta_swing_table_idx_tdown_a[delta]);
+
+			rtldm->delta_power_index_last[RF90_PATH_A] =
+				rtldm->delta_power_index[RF90_PATH_A];
+			rtldm->delta_power_index[RF90_PATH_A] =
+				-1 * delta_swing_table_idx_tdown_a[delta];
+
+			rtldm->absolute_ofdm_swing_idx[RF90_PATH_A] =
+				-1 * delta_swing_table_idx_tdown_a[delta];
+			/* Record delta swing for mix mode power tracking*/
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "******Temp is lower and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n",
+				 rtldm->absolute_ofdm_swing_idx[RF90_PATH_A]);
+		}
+
+		for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++) {
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "\n\n================================ [Path-%c]Calculating PowerIndexOffset ================================\n",
+				 (p == RF90_PATH_A ? 'A' : 'B'));
+			/*If Thermal value changes but lookup table value
+			 * still the same
+			 */
+			if (rtldm->delta_power_index[p] ==
+				rtldm->delta_power_index_last[p])
+
+				rtldm->power_index_offset[p] = 0;
+			else
+				rtldm->power_index_offset[p] =
+					rtldm->delta_power_index[p] -
+					rtldm->delta_power_index_last[p];
+			/*Power Index Diff between 2 times Power Tracking*/
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "[Path-%c] PowerIndexOffset(%d) = DeltaPowerIndex(%d) - DeltaPowerIndexLast(%d)\n",
+				 (p == RF90_PATH_A ? 'A' : 'B'),
+				rtldm->power_index_offset[p],
+				rtldm->delta_power_index[p] ,
+				rtldm->delta_power_index_last[p]);
+
+			rtldm->ofdm_index[p] =
+					rtldm->swing_idx_ofdm_base[p] +
+					rtldm->power_index_offset[p];
+			rtldm->cck_index =
+					rtldm->swing_idx_cck_base +
+					rtldm->power_index_offset[p];
+
+			rtldm->swing_idx_cck = rtldm->cck_index;
+			rtldm->swing_idx_ofdm[p] = rtldm->ofdm_index[p];
+
+			/*********Print BB Swing Base and Index Offset********/
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "The 'CCK' final index(%d) = BaseIndex(%d) + PowerIndexOffset(%d)\n",
+				 rtldm->swing_idx_cck,
+				 rtldm->swing_idx_cck_base,
+				 rtldm->power_index_offset[p]);
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "The 'OFDM' final index(%d) = BaseIndex[%c](%d) + PowerIndexOffset(%d)\n",
+				 rtldm->swing_idx_ofdm[p],
+				 (p == RF90_PATH_A ? 'A' : 'B'),
+				 rtldm->swing_idx_ofdm_base[p],
+				 rtldm->power_index_offset[p]);
+
+			/*7.1 Handle boundary conditions of index.*/
+
+			if (rtldm->ofdm_index[p] > TXSCALE_TABLE_SIZE - 1)
+				rtldm->ofdm_index[p] = TXSCALE_TABLE_SIZE - 1;
+			else if (rtldm->ofdm_index[p] < ofdm_min_index)
+				rtldm->ofdm_index[p] = ofdm_min_index;
+		}
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "\n\n========================================================================================================\n");
+		if (rtldm->cck_index > TXSCALE_TABLE_SIZE - 1)
+			rtldm->cck_index = TXSCALE_TABLE_SIZE - 1;
+		else if (rtldm->cck_index < 0)
+			rtldm->cck_index = 0;
+	} else {
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "The thermal meter is unchanged or TxPowerTracking OFF(%d):ThermalValue: %d , pDM_Odm->RFCalibrateInfo.ThermalValue: %d\n",
+			 rtldm->txpower_track_control,
+			 thermal_value,
+			 rtldm->thermalvalue);
+
+		for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++)
+			rtldm->power_index_offset[p] = 0;
+	}
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "TxPowerTracking: [CCK] Swing Current Index: %d, Swing Base Index: %d\n",
+		 /*Print Swing base & current*/
+		rtldm->cck_index, rtldm->swing_idx_cck_base);
+	for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++) {
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "TxPowerTracking: [OFDM] Swing Current Index: %d, Swing Base Index[%c]: %d\n",
+			 rtldm->ofdm_index[p],
+			 (p == RF90_PATH_A ? 'A' : 'B'),
+			 rtldm->swing_idx_ofdm_base[p]);
+	}
+
+	if ((rtldm->power_index_offset[RF90_PATH_A] != 0 ||
+		rtldm->power_index_offset[RF90_PATH_B] != 0) &&
+		rtldm->txpower_track_control) {
+		/*7.2 Configure the Swing Table to adjust Tx Power.*/
+		/*Always TRUE after Tx Power is adjusted by power tracking.*/
+		/*
+		 *  2012/04/23 MH According to Luke's suggestion,
+		 *  we can not write BB digital
+		 *  to increase TX power. Otherwise, EVM will be bad.
+		 *
+		 *  2012/04/25 MH Add for tx power tracking to
+		 *  set tx power in tx agc for 88E.
+		 */
+		if (thermal_value > rtldm->thermalvalue) {
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "Temperature Increasing(A): delta_pi: %d , delta_t: %d,Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
+				 rtldm->power_index_offset[RF90_PATH_A],
+				 delta, thermal_value,
+				 rtlefuse->eeprom_thermalmeter,
+				 rtldm->thermalvalue);
+		} else if (thermal_value < rtldm->thermalvalue) { /*Low temperature*/
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "Temperature Decreasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n",
+				 rtldm->power_index_offset[RF90_PATH_A],
+				 delta, thermal_value,
+				 rtlefuse->eeprom_thermalmeter,
+				 rtldm->thermalvalue);
+		}
+
+		if (thermal_value > rtlefuse->eeprom_thermalmeter) {
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "Temperature(%d) higher than PG value(%d)\n",
+				 thermal_value, rtlefuse->eeprom_thermalmeter);
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "****Enter POWER Tracking MIX_MODE****\n");
+			for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++)
+					rtl8821ae_dm_txpwr_track_set_pwr(hw,
+						MIX_MODE, p, index_for_channel);
+		} else {
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "Temperature(%d) lower than PG value(%d)\n",
+				 thermal_value, rtlefuse->eeprom_thermalmeter);
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "*****Enter POWER Tracking MIX_MODE*****\n");
+			for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++)
+				rtl8812ae_dm_txpwr_track_set_pwr(hw,
+					MIX_MODE, p, index_for_channel);
+		}
+		/*Record last time Power Tracking result as base.*/
+		rtldm->swing_idx_cck_base = rtldm->swing_idx_cck;
+		for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++)
+			rtldm->swing_idx_ofdm_base[p] = rtldm->swing_idx_ofdm[p];
+
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+				 "pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue= %d\n",
+				 rtldm->thermalvalue, thermal_value);
+		/*Record last Power Tracking Thermal Value*/
+		rtldm->thermalvalue = thermal_value;
+	}
+	/* Delta temperature is equal to or larger than
+	 * 20 centigrade (When threshold is 8).
+	 */
+	if (delta_iqk >= IQK_THRESHOLD) {
+		if (!rtlphy->lck_inprogress) {
+			spin_lock(&rtlpriv->locks.iqk_lock);
+			rtlphy->lck_inprogress = true;
+			spin_unlock(&rtlpriv->locks.iqk_lock);
+
+			rtl8821ae_do_iqk(hw, delta_iqk, thermal_value, 8);
+
+			spin_lock(&rtlpriv->locks.iqk_lock);
+			rtlphy->lck_inprogress = false;
+			spin_unlock(&rtlpriv->locks.iqk_lock);
+		}
+	}
+
+	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+		 "<===rtl8812ae_dm_txpower_tracking_callback_thermalmeter\n");
+}
+
+void rtl8821ae_dm_check_txpower_tracking_thermalmeter(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	static u8 tm_trigger;
+
+	if (!tm_trigger) {
+		rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER_88E, BIT(17)|BIT(16),
+			      0x03);
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "Trigger 8821ae Thermal Meter!!\n");
+		tm_trigger = 1;
+		return;
+	} else {
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			 "Schedule TxPowerTracking !!\n");
+
+		rtl8821ae_dm_txpower_tracking_callback_thermalmeter(hw);
+		tm_trigger = 0;
+	}
+}
+
+static void rtl8821ae_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rate_adaptive *p_ra = &rtlpriv->ra;
+	u32 low_rssithresh_for_ra = p_ra->low2high_rssi_thresh_for_ra40m;
+	u32 high_rssithresh_for_ra = p_ra->high_rssi_thresh_for_ra;
+	u8 go_up_gap = 5;
+	struct ieee80211_sta *sta = NULL;
+
+	if (is_hal_stop(rtlhal)) {
+		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+			 "driver is going to unload\n");
+		return;
+	}
+
+	if (!rtlpriv->dm.useramask) {
+		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+			 "driver does not control rate adaptive mask\n");
+		return;
+	}
+
+	if (mac->link_state == MAC80211_LINKED &&
+		mac->opmode == NL80211_IFTYPE_STATION) {
+		switch (p_ra->pre_ratr_state) {
+		case DM_RATR_STA_MIDDLE:
+			high_rssithresh_for_ra += go_up_gap;
+			break;
+		case DM_RATR_STA_LOW:
+			high_rssithresh_for_ra += go_up_gap;
+			low_rssithresh_for_ra += go_up_gap;
+			break;
+		default:
+			break;
+		}
+
+		if (rtlpriv->dm.undec_sm_pwdb >
+		    (long)high_rssithresh_for_ra)
+			p_ra->ratr_state = DM_RATR_STA_HIGH;
+		else if (rtlpriv->dm.undec_sm_pwdb >
+			 (long)low_rssithresh_for_ra)
+			p_ra->ratr_state = DM_RATR_STA_MIDDLE;
+		else
+			p_ra->ratr_state = DM_RATR_STA_LOW;
+
+		if (p_ra->pre_ratr_state != p_ra->ratr_state) {
+			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+				 "RSSI = %ld\n",
+				  rtlpriv->dm.undec_sm_pwdb);
+			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+				 "RSSI_LEVEL = %d\n", p_ra->ratr_state);
+			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+				 "PreState = %d, CurState = %d\n",
+				  p_ra->pre_ratr_state, p_ra->ratr_state);
+
+			rcu_read_lock();
+			sta = rtl_find_sta(hw, mac->bssid);
+			if (sta)
+				rtlpriv->cfg->ops->update_rate_tbl(hw,
+						sta, p_ra->ratr_state);
+			rcu_read_unlock();
+
+			p_ra->pre_ratr_state = p_ra->ratr_state;
+		}
+	}
+}
+
+static void rtl8821ae_dm_refresh_basic_rate_mask(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+	struct rtl_mac *mac = &rtlpriv->mac80211;
+	static u8 stage;
+	u8 cur_stage = 0;
+	u16 basic_rate = RRSR_1M | RRSR_2M | RRSR_5_5M | RRSR_11M | RRSR_6M;
+
+	if (mac->link_state < MAC80211_LINKED)
+		cur_stage = 0;
+	else if (dm_digtable->rssi_val_min < 25)
+		cur_stage = 1;
+	else if (dm_digtable->rssi_val_min > 30)
+		cur_stage = 3;
+	else
+		cur_stage = 2;
+
+	if (cur_stage != stage) {
+		if (cur_stage == 1) {
+			basic_rate &= (!(basic_rate ^ mac->basic_rates));
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+				HW_VAR_BASIC_RATE, (u8 *)&basic_rate);
+		} else if (cur_stage == 3 && (stage == 1 || stage == 2)) {
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+				HW_VAR_BASIC_RATE, (u8 *)&mac->basic_rates);
+		}
+	}
+	stage = cur_stage;
+}
+
+static void rtl8821ae_dm_edca_choose_traffic_idx(
+	struct ieee80211_hw *hw, u64 cur_tx_bytes,
+	u64 cur_rx_bytes, bool b_bias_on_rx,
+	bool *pb_is_cur_rdl_state)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (b_bias_on_rx) {
+		if (cur_tx_bytes > (cur_rx_bytes*4)) {
+			*pb_is_cur_rdl_state = false;
+			RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD,
+				 "Uplink Traffic\n ");
+		} else {
+			*pb_is_cur_rdl_state = true;
+			RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD,
+				 "Balance Traffic\n");
+		}
+	} else {
+		if (cur_rx_bytes > (cur_tx_bytes*4)) {
+			*pb_is_cur_rdl_state = true;
+			RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD,
+				 "Downlink	Traffic\n");
+		} else {
+			*pb_is_cur_rdl_state = false;
+			RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD,
+				 "Balance Traffic\n");
+		}
+	}
+	return;
+}
+
+static void rtl8821ae_dm_check_edca_turbo(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_dm *rtldm =  rtl_dm(rtl_priv(hw));
+
+	/*Keep past Tx/Rx packet count for RT-to-RT EDCA turbo.*/
+	u64 cur_tx_ok_cnt = 0;
+	u64 cur_rx_ok_cnt = 0;
+	u32 edca_be_ul = 0x5ea42b;
+	u32 edca_be_dl = 0x5ea42b;
+	u32 edca_be = 0x5ea42b;
+	u8 iot_peer = 0;
+	bool *pb_is_cur_rdl_state = NULL;
+	bool b_last_is_cur_rdl_state = false;
+	bool b_bias_on_rx = false;
+	bool b_edca_turbo_on = false;
+
+	RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD,
+		 "rtl8821ae_dm_check_edca_turbo=====>");
+	RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD,
+		 "Orginial BE PARAM: 0x%x\n",
+		 rtl_read_dword(rtlpriv, DM_REG_EDCA_BE_11N));
+
+	if (rtlpriv->dm.dbginfo.num_non_be_pkt > 0x100)
+		rtlpriv->dm.is_any_nonbepkts = true;
+	rtlpriv->dm.dbginfo.num_non_be_pkt = 0;
+
+	/*===============================
+	 * list paramter for different platform
+	 *===============================
+	 */
+	b_last_is_cur_rdl_state = rtlpriv->dm.is_cur_rdlstate;
+	pb_is_cur_rdl_state = &rtlpriv->dm.is_cur_rdlstate;
+
+	cur_tx_ok_cnt = rtlpriv->stats.txbytesunicast - rtldm->last_tx_ok_cnt;
+	cur_rx_ok_cnt = rtlpriv->stats.rxbytesunicast - rtldm->last_rx_ok_cnt;
+
+	rtldm->last_tx_ok_cnt = rtlpriv->stats.txbytesunicast;
+	rtldm->last_rx_ok_cnt = rtlpriv->stats.rxbytesunicast;
+
+	iot_peer = rtlpriv->mac80211.vendor;
+	b_bias_on_rx = false;
+	b_edca_turbo_on = ((!rtlpriv->dm.is_any_nonbepkts) &&
+			   (!rtlpriv->dm.disable_framebursting)) ?
+			   true : false;
+
+	if (rtlpriv->rtlhal.hw_type != HARDWARE_TYPE_RTL8812AE) {
+		if ((iot_peer == PEER_CISCO) &&
+			(mac->mode == WIRELESS_MODE_N_24G)) {
+			edca_be_dl = edca_setting_dl[iot_peer];
+			edca_be_ul = edca_setting_ul[iot_peer];
+		}
+	}
+
+	RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD,
+		 "bIsAnyNonBEPkts : 0x%x  bDisableFrameBursting : 0x%x\n",
+		 rtlpriv->dm.is_any_nonbepkts,
+		 rtlpriv->dm.disable_framebursting);
+
+	RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD,
+		 "bEdcaTurboOn : 0x%x bBiasOnRx : 0x%x\n",
+		 b_edca_turbo_on, b_bias_on_rx);
+
+	if (b_edca_turbo_on) {
+		RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD,
+			 "curTxOkCnt : 0x%llx\n", cur_tx_ok_cnt);
+		RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD,
+			 "curRxOkCnt : 0x%llx\n", cur_rx_ok_cnt);
+		if (b_bias_on_rx)
+			rtl8821ae_dm_edca_choose_traffic_idx(hw, cur_tx_ok_cnt,
+				cur_rx_ok_cnt, true, pb_is_cur_rdl_state);
+		else
+			rtl8821ae_dm_edca_choose_traffic_idx(hw, cur_tx_ok_cnt,
+				cur_rx_ok_cnt, false, pb_is_cur_rdl_state);
+
+		edca_be = (*pb_is_cur_rdl_state) ?  edca_be_dl : edca_be_ul;
+
+		rtl_write_dword(rtlpriv, DM_REG_EDCA_BE_11N, edca_be);
+
+		RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD,
+			 "EDCA Turbo on: EDCA_BE:0x%x\n", edca_be);
+
+		rtlpriv->dm.current_turbo_edca = true;
+
+		RT_TRACE(rtlpriv, COMP_TURBO, DBG_LOUD,
+			 "EDCA_BE_DL : 0x%x  EDCA_BE_UL : 0x%x  EDCA_BE : 0x%x\n",
+			 edca_be_dl, edca_be_ul, edca_be);
+	} else {
+		if (rtlpriv->dm.current_turbo_edca) {
+			u8 tmp = AC0_BE;
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+						      (u8 *)(&tmp));
+		}
+		rtlpriv->dm.current_turbo_edca = false;
+	}
+
+	rtlpriv->dm.is_any_nonbepkts = false;
+	rtldm->last_tx_ok_cnt = rtlpriv->stats.txbytesunicast;
+	rtldm->last_rx_ok_cnt = rtlpriv->stats.rxbytesunicast;
+}
+
+static void rtl8821ae_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+	u8 cur_cck_cca_thresh;
+
+	if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) {
+		if (dm_digtable->rssi_val_min > 25) {
+			cur_cck_cca_thresh = 0xcd;
+		} else if ((dm_digtable->rssi_val_min <= 25) &&
+			   (dm_digtable->rssi_val_min > 10)) {
+			cur_cck_cca_thresh = 0x83;
+		} else {
+			if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
+				cur_cck_cca_thresh = 0x83;
+			else
+				cur_cck_cca_thresh = 0x40;
+		}
+	} else {
+		if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
+			cur_cck_cca_thresh = 0x83;
+		else
+			cur_cck_cca_thresh = 0x40;
+	}
+
+	if (dm_digtable->cur_cck_cca_thres != cur_cck_cca_thresh)
+		rtl_write_byte(rtlpriv, ODM_REG_CCK_CCA_11AC,
+			       cur_cck_cca_thresh);
+
+	dm_digtable->pre_cck_cca_thres = dm_digtable->cur_cck_cca_thres;
+	dm_digtable->cur_cck_cca_thres = cur_cck_cca_thresh;
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+		 "CCK cca thresh hold =%x\n", dm_digtable->cur_cck_cca_thres);
+}
+
+static void rtl8821ae_dm_dynamic_atc_switch(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+	u8 crystal_cap;
+	u32 packet_count;
+	int cfo_khz_a, cfo_khz_b, cfo_ave = 0, adjust_xtal = 0;
+	int cfo_ave_diff;
+
+	if (rtlpriv->mac80211.link_state < MAC80211_LINKED) {
+		/*1.Enable ATC*/
+		if (rtldm->atc_status == ATC_STATUS_OFF) {
+			rtl_set_bbreg(hw, RFC_AREA, BIT(14), ATC_STATUS_ON);
+			rtldm->atc_status = ATC_STATUS_ON;
+		}
+
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "No link!!\n");
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+			 "atc_status = %d\n", rtldm->atc_status);
+
+		if (rtldm->crystal_cap != rtlpriv->efuse.crystalcap) {
+			rtldm->crystal_cap = rtlpriv->efuse.crystalcap;
+			crystal_cap = rtldm->crystal_cap & 0x3f;
+			crystal_cap = crystal_cap & 0x3f;
+			if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE)
+				rtl_set_bbreg(hw, REG_MAC_PHY_CTRL,
+					      0x7ff80000, (crystal_cap |
+					      (crystal_cap << 6)));
+			else
+				rtl_set_bbreg(hw, REG_MAC_PHY_CTRL,
+					      0xfff000, (crystal_cap |
+					      (crystal_cap << 6)));
+		}
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "crystal_cap = 0x%x\n",
+			 rtldm->crystal_cap);
+	} else{
+		/*1. Calculate CFO for path-A & path-B*/
+		cfo_khz_a = (int)(rtldm->cfo_tail[0] * 3125) / 1280;
+		cfo_khz_b = (int)(rtldm->cfo_tail[1] * 3125) / 1280;
+		packet_count = rtldm->packet_count;
+
+		/*2.No new packet*/
+		if (packet_count == rtldm->packet_count_pre) {
+			RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+				 "packet counter doesn't change\n");
+			return;
+		}
+
+		rtldm->packet_count_pre = packet_count;
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+			 "packet counter = %d\n",
+			 rtldm->packet_count);
+
+		/*3.Average CFO*/
+		if (rtlpriv->phy.rf_type == RF_1T1R)
+			cfo_ave = cfo_khz_a;
+		else
+			cfo_ave = (cfo_khz_a + cfo_khz_b) >> 1;
+
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+			 "cfo_khz_a = %dkHz, cfo_khz_b = %dkHz, cfo_ave = %dkHz\n",
+			 cfo_khz_a, cfo_khz_b, cfo_ave);
+
+		/*4.Avoid abnormal large CFO*/
+		cfo_ave_diff = (rtldm->cfo_ave_pre >= cfo_ave) ?
+						(rtldm->cfo_ave_pre - cfo_ave) :
+						(cfo_ave - rtldm->cfo_ave_pre);
+
+		if (cfo_ave_diff > 20 && rtldm->large_cfo_hit == 0) {
+			RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+				 "first large CFO hit\n");
+			rtldm->large_cfo_hit = 1;
+			return;
+		} else
+			rtldm->large_cfo_hit = 0;
+
+		rtldm->cfo_ave_pre = cfo_ave;
+
+		/*CFO tracking by adjusting Xtal cap.*/
+
+		/*1.Dynamic Xtal threshold*/
+		if (cfo_ave >= -rtldm->cfo_threshold &&
+			cfo_ave <= rtldm->cfo_threshold &&
+			rtldm->is_freeze == 0) {
+			if (rtldm->cfo_threshold == CFO_THRESHOLD_XTAL) {
+				rtldm->cfo_threshold = CFO_THRESHOLD_XTAL + 10;
+				rtldm->is_freeze = 1;
+			} else {
+				rtldm->cfo_threshold = CFO_THRESHOLD_XTAL;
+			}
+		}
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+			 "Dynamic threshold = %d\n",
+			 rtldm->cfo_threshold);
+
+		/* 2.Calculate Xtal offset*/
+		if (cfo_ave > rtldm->cfo_threshold && rtldm->crystal_cap < 0x3f)
+			adjust_xtal = ((cfo_ave - CFO_THRESHOLD_XTAL) >> 2) + 1;
+		else if ((cfo_ave < -rtlpriv->dm.cfo_threshold) &&
+			 rtlpriv->dm.crystal_cap > 0)
+			adjust_xtal = ((cfo_ave + CFO_THRESHOLD_XTAL) >> 2) - 1;
+		RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+			 "Crystal cap = 0x%x, Crystal cap offset = %d\n",
+			 rtldm->crystal_cap, adjust_xtal);
+
+		/*3.Adjudt Crystal Cap.*/
+		if (adjust_xtal != 0) {
+			rtldm->is_freeze = 0;
+			rtldm->crystal_cap += adjust_xtal;
+
+			if (rtldm->crystal_cap > 0x3f)
+				rtldm->crystal_cap = 0x3f;
+			else if (rtldm->crystal_cap < 0)
+				rtldm->crystal_cap = 0;
+
+			crystal_cap = rtldm->crystal_cap & 0x3f;
+			crystal_cap = crystal_cap & 0x3f;
+			if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE)
+				rtl_set_bbreg(hw, REG_MAC_PHY_CTRL,
+					      0x7ff80000, (crystal_cap |
+					      (crystal_cap << 6)));
+			else
+				rtl_set_bbreg(hw, REG_MAC_PHY_CTRL,
+					      0xfff000, (crystal_cap |
+					      (crystal_cap << 6)));
+			RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+				 "New crystal cap = 0x%x\n",
+				 rtldm->crystal_cap);
+		}
+	}
+}
+
+void rtl8821ae_dm_watchdog(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	bool fw_current_inpsmode = false;
+	bool fw_ps_awake = true;
+
+	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+				      (u8 *)(&fw_current_inpsmode));
+
+	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
+				      (u8 *)(&fw_ps_awake));
+
+	if (ppsc->p2p_ps_info.p2p_ps_mode)
+		fw_ps_awake = false;
+
+	if ((ppsc->rfpwr_state == ERFON) &&
+	    ((!fw_current_inpsmode) && fw_ps_awake) &&
+	    (!ppsc->rfchange_inprogress)) {
+		rtl8821ae_dm_common_info_self_update(hw);
+		rtl8821ae_dm_false_alarm_counter_statistics(hw);
+		rtl8821ae_dm_check_rssi_monitor(hw);
+		rtl8821ae_dm_dig(hw);
+		rtl8821ae_dm_cck_packet_detection_thresh(hw);
+		rtl8821ae_dm_refresh_rate_adaptive_mask(hw);
+		rtl8821ae_dm_refresh_basic_rate_mask(hw);
+		rtl8821ae_dm_check_edca_turbo(hw);
+		rtl8821ae_dm_dynamic_atc_switch(hw);
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+			rtl8812ae_dm_check_txpower_tracking_thermalmeter(hw);
+		else
+			rtl8821ae_dm_check_txpower_tracking_thermalmeter(hw);
+		rtl8821ae_dm_iq_calibrate(hw);
+	}
+
+	rtlpriv->dm.dbginfo.num_qry_beacon_pkt = 0;
+	RT_TRACE(rtlpriv, COMP_DIG, DBG_DMESG, "\n");
+}
+
+void rtl8821ae_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw,
+					u8 *pdesc, u32 mac_id)
+{
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+	struct fast_ant_training *pfat_table = &rtldm->fat_table;
+
+	if (rtlhal->hw_type != HARDWARE_TYPE_RTL8812AE)
+		return;
+
+	if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
+		SET_TX_DESC_TX_ANT(pdesc, pfat_table->antsel_a[mac_id]);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h
new file mode 100644
index 0000000..9dd40dd
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h
@@ -0,0 +1,356 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef	__RTL8821AE_DM_H__
+#define __RTL8821AE_DM_H__
+
+#define	MAIN_ANT	0
+#define	AUX_ANT	1
+#define	MAIN_ANT_CG_TRX	1
+#define	AUX_ANT_CG_TRX	0
+#define	MAIN_ANT_CGCS_RX	0
+#define	AUX_ANT_CGCS_RX	1
+
+#define	TXSCALE_TABLE_SIZE 37
+
+/*RF REG LIST*/
+#define	DM_REG_RF_MODE_11N				0x00
+#define	DM_REG_RF_0B_11N				0x0B
+#define	DM_REG_CHNBW_11N				0x18
+#define	DM_REG_T_METER_11N				0x24
+#define	DM_REG_RF_25_11N				0x25
+#define	DM_REG_RF_26_11N				0x26
+#define	DM_REG_RF_27_11N				0x27
+#define	DM_REG_RF_2B_11N				0x2B
+#define	DM_REG_RF_2C_11N				0x2C
+#define	DM_REG_RXRF_A3_11N				0x3C
+#define	DM_REG_T_METER_92D_11N			0x42
+#define	DM_REG_T_METER_88E_11N			0x42
+
+/*BB REG LIST*/
+/*PAGE 8 */
+#define	DM_REG_BB_CTRL_11N				0x800
+#define	DM_REG_RF_PIN_11N				0x804
+#define	DM_REG_PSD_CTRL_11N				0x808
+#define	DM_REG_TX_ANT_CTRL_11N			0x80C
+#define	DM_REG_BB_PWR_SAV5_11N			0x818
+#define	DM_REG_CCK_RPT_FORMAT_11N		0x824
+#define	DM_REG_RX_DEFUALT_A_11N		0x858
+#define	DM_REG_RX_DEFUALT_B_11N		0x85A
+#define	DM_REG_BB_PWR_SAV3_11N			0x85C
+#define	DM_REG_ANTSEL_CTRL_11N			0x860
+#define	DM_REG_RX_ANT_CTRL_11N			0x864
+#define	DM_REG_PIN_CTRL_11N				0x870
+#define	DM_REG_BB_PWR_SAV1_11N			0x874
+#define	DM_REG_ANTSEL_PATH_11N			0x878
+#define	DM_REG_BB_3WIRE_11N			0x88C
+#define	DM_REG_SC_CNT_11N				0x8C4
+#define	DM_REG_PSD_DATA_11N			0x8B4
+/*PAGE 9*/
+#define	DM_REG_ANT_MAPPING1_11N		0x914
+#define	DM_REG_ANT_MAPPING2_11N		0x918
+/*PAGE A*/
+#define	DM_REG_CCK_ANTDIV_PARA1_11N	0xA00
+#define	DM_REG_CCK_CCA_11N			0xA0A
+#define	DM_REG_CCK_CCA_11AC			0xA0A
+#define	DM_REG_CCK_ANTDIV_PARA2_11N	0xA0C
+#define	DM_REG_CCK_ANTDIV_PARA3_11N	0xA10
+#define	DM_REG_CCK_ANTDIV_PARA4_11N	0xA14
+#define	DM_REG_CCK_FILTER_PARA1_11N	0xA22
+#define	DM_REG_CCK_FILTER_PARA2_11N	0xA23
+#define	DM_REG_CCK_FILTER_PARA3_11N	0xA24
+#define	DM_REG_CCK_FILTER_PARA4_11N	0xA25
+#define	DM_REG_CCK_FILTER_PARA5_11N	0xA26
+#define	DM_REG_CCK_FILTER_PARA6_11N	0xA27
+#define	DM_REG_CCK_FILTER_PARA7_11N	0xA28
+#define	DM_REG_CCK_FILTER_PARA8_11N	0xA29
+#define	DM_REG_CCK_FA_RST_11N			0xA2C
+#define	DM_REG_CCK_FA_MSB_11N			0xA58
+#define	DM_REG_CCK_FA_LSB_11N			0xA5C
+#define	DM_REG_CCK_CCA_CNT_11N			0xA60
+#define	DM_REG_BB_PWR_SAV4_11N			0xA74
+/*PAGE B */
+#define	DM_REG_LNA_SWITCH_11N			0xB2C
+#define	DM_REG_PATH_SWITCH_11N			0xB30
+#define	DM_REG_RSSI_CTRL_11N			0xB38
+#define	DM_REG_CONFIG_ANTA_11N			0xB68
+#define	DM_REG_RSSI_BT_11N				0xB9C
+/*PAGE C */
+#define	DM_REG_OFDM_FA_HOLDC_11N		0xC00
+#define	DM_REG_RX_PATH_11N				0xC04
+#define	DM_REG_TRMUX_11N				0xC08
+#define	DM_REG_OFDM_FA_RSTC_11N		0xC0C
+#define	DM_REG_RXIQI_MATRIX_11N		0xC14
+#define	DM_REG_TXIQK_MATRIX_LSB1_11N	0xC4C
+#define	DM_REG_IGI_A_11N				0xC50
+#define	DM_REG_IGI_A_11AC				0xC50
+#define	DM_REG_ANTDIV_PARA2_11N		0xC54
+#define	DM_REG_IGI_B_11N					0xC58
+#define	DM_REG_IGI_B_11AC					0xE50
+#define	DM_REG_ANTDIV_PARA3_11N		0xC5C
+#define	DM_REG_BB_PWR_SAV2_11N			0xC70
+#define	DM_REG_RX_OFF_11N				0xC7C
+#define	DM_REG_TXIQK_MATRIXA_11N		0xC80
+#define	DM_REG_TXIQK_MATRIXB_11N		0xC88
+#define	DM_REG_TXIQK_MATRIXA_LSB2_11N	0xC94
+#define	DM_REG_TXIQK_MATRIXB_LSB2_11N	0xC9C
+#define	DM_REG_RXIQK_MATRIX_LSB_11N	0xCA0
+#define	DM_REG_ANTDIV_PARA1_11N		0xCA4
+#define	DM_REG_OFDM_FA_TYPE1_11N		0xCF0
+/*PAGE D */
+#define	DM_REG_OFDM_FA_RSTD_11N		0xD00
+#define	DM_REG_OFDM_FA_TYPE2_11N		0xDA0
+#define	DM_REG_OFDM_FA_TYPE3_11N		0xDA4
+#define	DM_REG_OFDM_FA_TYPE4_11N		0xDA8
+/*PAGE E */
+#define	DM_REG_TXAGC_A_6_18_11N		0xE00
+#define	DM_REG_TXAGC_A_24_54_11N		0xE04
+#define	DM_REG_TXAGC_A_1_MCS32_11N	0xE08
+#define	DM_REG_TXAGC_A_MCS0_3_11N		0xE10
+#define	DM_REG_TXAGC_A_MCS4_7_11N		0xE14
+#define	DM_REG_TXAGC_A_MCS8_11_11N	0xE18
+#define	DM_REG_TXAGC_A_MCS12_15_11N	0xE1C
+#define	DM_REG_FPGA0_IQK_11N			0xE28
+#define	DM_REG_TXIQK_TONE_A_11N		0xE30
+#define	DM_REG_RXIQK_TONE_A_11N		0xE34
+#define	DM_REG_TXIQK_PI_A_11N			0xE38
+#define	DM_REG_RXIQK_PI_A_11N			0xE3C
+#define	DM_REG_TXIQK_11N				0xE40
+#define	DM_REG_RXIQK_11N				0xE44
+#define	DM_REG_IQK_AGC_PTS_11N			0xE48
+#define	DM_REG_IQK_AGC_RSP_11N			0xE4C
+#define	DM_REG_BLUETOOTH_11N			0xE6C
+#define	DM_REG_RX_WAIT_CCA_11N			0xE70
+#define	DM_REG_TX_CCK_RFON_11N			0xE74
+#define	DM_REG_TX_CCK_BBON_11N			0xE78
+#define	DM_REG_OFDM_RFON_11N			0xE7C
+#define	DM_REG_OFDM_BBON_11N			0xE80
+#define DM_REG_TX2RX_11N				0xE84
+#define	DM_REG_TX2TX_11N				0xE88
+#define	DM_REG_RX_CCK_11N				0xE8C
+#define	DM_REG_RX_OFDM_11N				0xED0
+#define	DM_REG_RX_WAIT_RIFS_11N		0xED4
+#define	DM_REG_RX2RX_11N				0xED8
+#define	DM_REG_STANDBY_11N				0xEDC
+#define	DM_REG_SLEEP_11N				0xEE0
+#define	DM_REG_PMPD_ANAEN_11N			0xEEC
+
+/*MAC REG LIST*/
+#define	DM_REG_BB_RST_11N				0x02
+#define	DM_REG_ANTSEL_PIN_11N			0x4C
+#define	DM_REG_EARLY_MODE_11N			0x4D0
+#define	DM_REG_RSSI_MONITOR_11N		0x4FE
+#define	DM_REG_EDCA_VO_11N				0x500
+#define	DM_REG_EDCA_VI_11N				0x504
+#define	DM_REG_EDCA_BE_11N				0x508
+#define	DM_REG_EDCA_BK_11N				0x50C
+#define	DM_REG_TXPAUSE_11N				0x522
+#define	DM_REG_RESP_TX_11N				0x6D8
+#define	DM_REG_ANT_TRAIN_PARA1_11N	0x7b0
+#define	DM_REG_ANT_TRAIN_PARA2_11N	0x7b4
+
+/*DIG Related*/
+#define	DM_BIT_IGI_11N					0x0000007F
+#define	DM_BIT_IGI_11AC					0xFFFFFFFF
+
+#define HAL_DM_DIG_DISABLE			BIT(0)
+#define HAL_DM_HIPWR_DISABLE		BIT(1)
+
+#define OFDM_TABLE_LENGTH			43
+#define CCK_TABLE_LENGTH			33
+
+#define OFDM_TABLE_SIZE				37
+#define CCK_TABLE_SIZE				33
+
+#define BW_AUTO_SWITCH_HIGH_LOW		25
+#define BW_AUTO_SWITCH_LOW_HIGH		30
+
+#define DM_DIG_THRESH_HIGH			40
+#define DM_DIG_THRESH_LOW			35
+
+#define DM_FALSEALARM_THRESH_LOW	400
+#define DM_FALSEALARM_THRESH_HIGH	1000
+
+#define DM_DIG_MAX					0x3e
+#define DM_DIG_MIN					0x1e
+
+#define DM_DIG_MAX_AP				0x32
+#define DM_DIG_MIN_AP				0x20
+
+#define DM_DIG_FA_UPPER				0x3e
+#define DM_DIG_FA_LOWER				0x1e
+#define DM_DIG_FA_TH0				200
+#define DM_DIG_FA_TH1				0x300
+#define DM_DIG_FA_TH2				0x400
+
+#define DM_DIG_BACKOFF_MAX			12
+#define DM_DIG_BACKOFF_MIN			-4
+#define DM_DIG_BACKOFF_DEFAULT		10
+
+#define RXPATHSELECTION_SS_TH_LOW	30
+#define RXPATHSELECTION_DIFF_TH		18
+
+#define DM_RATR_STA_INIT			0
+#define DM_RATR_STA_HIGH			1
+#define DM_RATR_STA_MIDDLE			2
+#define DM_RATR_STA_LOW				3
+
+#define CTS2SELF_THVAL				30
+#define REGC38_TH					20
+
+#define WAIOTTHVAL					25
+
+#define TXHIGHPWRLEVEL_NORMAL		0
+#define TXHIGHPWRLEVEL_LEVEL1		1
+#define TXHIGHPWRLEVEL_LEVEL2		2
+#define TXHIGHPWRLEVEL_BT1			3
+#define TXHIGHPWRLEVEL_BT2			4
+
+#define DM_TYPE_BYFW				0
+#define DM_TYPE_BYDRIVER			1
+
+#define TX_POWER_NEAR_FIELD_THRESH_LVL2	74
+#define TX_POWER_NEAR_FIELD_THRESH_LVL1	67
+#define TXPWRTRACK_MAX_IDX 6
+
+/* Dynamic ATC switch */
+#define ATC_STATUS_OFF				0x0	/* enable */
+#define	ATC_STATUS_ON				0x1	/* disable */
+#define	CFO_THRESHOLD_XTAL			10	/* kHz */
+#define	CFO_THRESHOLD_ATC			80	/* kHz */
+
+#define AVG_THERMAL_NUM_8812A	4
+#define TXPWR_TRACK_TABLE_SIZE	30
+#define MAX_PATH_NUM_8812A		2
+#define MAX_PATH_NUM_8821A		1
+
+enum FAT_STATE {
+	FAT_NORMAL_STATE	= 0,
+	FAT_TRAINING_STATE = 1,
+};
+
+enum tag_dynamic_init_gain_operation_type_definition {
+	DIG_TYPE_THRESH_HIGH = 0,
+	DIG_TYPE_THRESH_LOW = 1,
+	DIG_TYPE_BACKOFF = 2,
+	DIG_TYPE_RX_GAIN_MIN = 3,
+	DIG_TYPE_RX_GAIN_MAX = 4,
+	DIG_TYPE_ENABLE = 5,
+	DIG_TYPE_DISABLE = 6,
+	DIG_OP_TYPE_MAX
+};
+
+enum tag_cck_packet_detection_threshold_type_definition {
+	CCK_PD_STAGE_LOWRSSI = 0,
+	CCK_PD_STAGE_HIGHRSSI = 1,
+	CCK_FA_STAGE_LOW = 2,
+	CCK_FA_STAGE_HIGH = 3,
+	CCK_PD_STAGE_MAX = 4,
+};
+
+enum dm_1r_cca_e {
+	CCA_1R = 0,
+	CCA_2R = 1,
+	CCA_MAX = 2,
+};
+
+enum dm_rf_e {
+	RF_SAVE = 0,
+	RF_NORMAL = 1,
+	RF_MAX = 2,
+};
+
+enum dm_sw_ant_switch_e {
+	ANS_ANTENNA_B = 1,
+	ANS_ANTENNA_A = 2,
+	ANS_ANTENNA_MAX = 3,
+};
+
+enum dm_dig_ext_port_alg_e {
+	DIG_EXT_PORT_STAGE_0 = 0,
+	DIG_EXT_PORT_STAGE_1 = 1,
+	DIG_EXT_PORT_STAGE_2 = 2,
+	DIG_EXT_PORT_STAGE_3 = 3,
+	DIG_EXT_PORT_STAGE_MAX = 4,
+};
+
+enum dm_dig_connect_e {
+	DIG_STA_DISCONNECT = 0,
+	DIG_STA_CONNECT = 1,
+	DIG_STA_BEFORE_CONNECT = 2,
+	DIG_MULTISTA_DISCONNECT = 3,
+	DIG_MULTISTA_CONNECT = 4,
+	DIG_CONNECT_MAX
+};
+
+enum pwr_track_control_method {
+	BBSWING,
+	TXAGC,
+	MIX_MODE
+};
+
+#define BT_RSSI_STATE_NORMAL_POWER      BIT_OFFSET_LEN_MASK_32(0, 1)
+#define BT_RSSI_STATE_AMDPU_OFF         BIT_OFFSET_LEN_MASK_32(1, 1)
+#define BT_RSSI_STATE_SPECIAL_LOW       BIT_OFFSET_LEN_MASK_32(2, 1)
+#define BT_RSSI_STATE_BG_EDCA_LOW       BIT_OFFSET_LEN_MASK_32(3, 1)
+#define BT_RSSI_STATE_TXPOWER_LOW       BIT_OFFSET_LEN_MASK_32(4, 1)
+#define GET_UNDECORATED_AVERAGE_RSSI(_priv)     \
+	((((struct rtl_priv *)(_priv))->mac80211.opmode ==	\
+			      NL80211_IFTYPE_ADHOC) ? \
+	(((struct rtl_priv *)(_priv))->dm.entry_min_undec_sm_pwdb) : \
+	(((struct rtl_priv *)(_priv))->dm.undec_sm_pwdb))
+
+void rtl8821ae_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw,
+					u8 *pdesc, u32 mac_id);
+void rtl8821ae_dm_ant_sel_statistics(struct ieee80211_hw *hw,
+				     u8 antsel_tr_mux, u32 mac_id,
+				     u32 rx_pwdb_all);
+void rtl8821ae_dm_fast_antenna_training_callback(unsigned long data);
+void rtl8821ae_dm_init(struct ieee80211_hw *hw);
+void rtl8821ae_dm_watchdog(struct ieee80211_hw *hw);
+void rtl8821ae_dm_write_dig(struct ieee80211_hw *hw, u8 current_igi);
+void rtl8821ae_dm_init_edca_turbo(struct ieee80211_hw *hw);
+void rtl8821ae_dm_check_txpower_tracking_thermalmeter(struct ieee80211_hw *hw);
+void rtl8821ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
+void rtl8821ae_dm_txpower_track_adjust(struct ieee80211_hw *hw,
+				       u8 type, u8 *pdirection,
+				       u32 *poutwrite_val);
+void rtl8821ae_dm_clear_txpower_tracking_state(struct ieee80211_hw *hw);
+void rtl8821ae_dm_write_cck_cca_thres(struct ieee80211_hw *hw, u8 current_cca);
+void rtl8821ae_dm_initialize_txpower_tracking_thermalmeter(struct ieee80211_hw *hw);
+void rtl8812ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw,
+				      enum pwr_track_control_method method,
+				      u8 rf_path,
+				      u8 channel_mapped_index);
+void rtl8821ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw,
+				      enum pwr_track_control_method method,
+				      u8 rf_path, u8 channel_mapped_index);
+
+void rtl8821ae_dm_update_init_rate(struct ieee80211_hw *hw, u8 rate);
+u8 rtl8821ae_hw_rate_to_mrate(struct ieee80211_hw *hw, u8 rate);
+void rtl8812ae_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw *hw);
+void rtl8821ae_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/fw.c
new file mode 100644
index 0000000..95e9562
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/fw.c
@@ -0,0 +1,1857 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "../core.h"
+#include "reg.h"
+#include "def.h"
+#include "fw.h"
+#include "dm.h"
+
+static void _rtl8821ae_enable_fw_download(struct ieee80211_hw *hw, bool enable)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 tmp;
+
+	if (enable) {
+		rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x05);
+
+		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
+		rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
+
+		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+	} else {
+		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
+		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+	}
+}
+
+static void _rtl8821ae_fw_block_write(struct ieee80211_hw *hw,
+				      const u8 *buffer, u32 size)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 blocksize = sizeof(u32);
+	u8 *bufferptr = (u8 *)buffer;
+	u32 *pu4byteptr = (u32 *)buffer;
+	u32 i, offset, blockcount, remainsize;
+
+	blockcount = size / blocksize;
+	remainsize = size % blocksize;
+
+	for (i = 0; i < blockcount; i++) {
+		offset = i * blocksize;
+		rtl_write_dword(rtlpriv, (FW_8821AE_START_ADDRESS + offset),
+				*(pu4byteptr + i));
+	}
+
+	if (remainsize) {
+		offset = blockcount * blocksize;
+		bufferptr += offset;
+		for (i = 0; i < remainsize; i++) {
+			rtl_write_byte(rtlpriv, (FW_8821AE_START_ADDRESS +
+					offset + i), *(bufferptr + i));
+		}
+	}
+}
+
+static void _rtl8821ae_fw_page_write(struct ieee80211_hw *hw,
+				     u32 page, const u8 *buffer, u32 size)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 value8;
+	u8 u8page = (u8)(page & 0x07);
+
+	value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
+
+	rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
+	_rtl8821ae_fw_block_write(hw, buffer, size);
+}
+
+static void _rtl8821ae_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
+{
+	u32 fwlen = *pfwlen;
+	u8 remain = (u8)(fwlen % 4);
+
+	remain = (remain == 0) ? 0 : (4 - remain);
+
+	while (remain > 0) {
+		pfwbuf[fwlen] = 0;
+		fwlen++;
+		remain--;
+	}
+
+	*pfwlen = fwlen;
+}
+
+static void _rtl8821ae_write_fw(struct ieee80211_hw *hw,
+				enum version_8821ae version,
+				u8 *buffer, u32 size)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 *bufferptr = (u8 *)buffer;
+	u32 pagenums, remainsize;
+	u32 page, offset;
+
+	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
+
+	_rtl8821ae_fill_dummy(bufferptr, &size);
+
+	pagenums = size / FW_8821AE_PAGE_SIZE;
+	remainsize = size % FW_8821AE_PAGE_SIZE;
+
+	if (pagenums > 8) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Page numbers should not greater then 8\n");
+	}
+
+	for (page = 0; page < pagenums; page++) {
+		offset = page * FW_8821AE_PAGE_SIZE;
+		_rtl8821ae_fw_page_write(hw, page, (bufferptr + offset),
+					 FW_8821AE_PAGE_SIZE);
+	}
+
+	if (remainsize) {
+		offset = pagenums * FW_8821AE_PAGE_SIZE;
+		page = pagenums;
+		_rtl8821ae_fw_page_write(hw, page, (bufferptr + offset),
+					 remainsize);
+	}
+}
+
+static int _rtl8821ae_fw_free_to_go(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	int err = -EIO;
+	u32 counter = 0;
+	u32 value32;
+
+	do {
+		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+	} while ((counter++ < FW_8821AE_POLLING_TIMEOUT_COUNT) &&
+		 (!(value32 & FWDL_CHKSUM_RPT)));
+
+	if (counter >= FW_8821AE_POLLING_TIMEOUT_COUNT) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
+			  value32);
+		goto exit;
+	}
+
+	RT_TRACE(rtlpriv, COMP_FW, DBG_EMERG,
+		 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
+
+	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+	value32 |= MCUFWDL_RDY;
+	value32 &= ~WINTINI_RDY;
+	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
+
+	rtl8821ae_firmware_selfreset(hw);
+
+	counter = 0;
+	do {
+		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+		if (value32 & WINTINI_RDY) {
+			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+				 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
+				  value32);
+			err = 0;
+			goto exit;
+		}
+
+		udelay(FW_8821AE_POLLING_DELAY);
+	} while (counter++ < FW_8821AE_POLLING_TIMEOUT_COUNT);
+
+	RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+		 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
+		 value32);
+
+exit:
+	return err;
+}
+
+static void _rtl8821ae_wait_for_h2c_cmd_finish(struct rtl_priv *rtlpriv)
+{
+	u8 val;
+	u16 count = 0;
+
+	do {
+		val = rtl_read_byte(rtlpriv, REG_HMETFR);
+		mdelay(1);
+		count++;
+	} while ((val & 0x0F) && (count < 1000));
+}
+
+int rtl8821ae_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl8821a_firmware_header *pfwheader;
+	u8 *pfwdata;
+	u32 fwsize;
+	int err;
+	bool support_remote_wakeup;
+	enum version_8821ae version = rtlhal->version;
+
+	rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+				      (u8 *)(&support_remote_wakeup));
+
+	if (support_remote_wakeup)
+		_rtl8821ae_wait_for_h2c_cmd_finish(rtlpriv);
+
+	if (buse_wake_on_wlan_fw) {
+		if (!rtlhal->wowlan_firmware)
+			return 1;
+
+		pfwheader =
+		  (struct rtl8821a_firmware_header *)rtlhal->wowlan_firmware;
+		rtlhal->fw_version = pfwheader->version;
+		rtlhal->fw_subversion = pfwheader->subversion;
+		pfwdata = (u8 *)rtlhal->wowlan_firmware;
+		fwsize = rtlhal->wowlan_fwsize;
+	} else {
+		if (!rtlhal->pfirmware)
+			return 1;
+
+		pfwheader =
+		  (struct rtl8821a_firmware_header *)rtlhal->pfirmware;
+		rtlhal->fw_version = pfwheader->version;
+		rtlhal->fw_subversion = pfwheader->subversion;
+		pfwdata = (u8 *)rtlhal->pfirmware;
+		fwsize = rtlhal->fwsize;
+	}
+
+	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+		 "%s Firmware SIZE %d\n",
+		 buse_wake_on_wlan_fw ? "Wowlan" : "Normal", fwsize);
+
+	if (IS_FW_HEADER_EXIST_8812(pfwheader) ||
+	    IS_FW_HEADER_EXIST_8821(pfwheader)) {
+		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+			 "Firmware Version(%d), Signature(%#x)\n",
+			 pfwheader->version, pfwheader->signature);
+
+		pfwdata = pfwdata + sizeof(struct rtl8821a_firmware_header);
+		fwsize = fwsize - sizeof(struct rtl8821a_firmware_header);
+	}
+
+	if (rtlhal->mac_func_enable) {
+		if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
+			rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
+			rtl8821ae_firmware_selfreset(hw);
+		}
+	}
+	_rtl8821ae_enable_fw_download(hw, true);
+	_rtl8821ae_write_fw(hw, version, pfwdata, fwsize);
+	_rtl8821ae_enable_fw_download(hw, false);
+
+	err = _rtl8821ae_fw_free_to_go(hw);
+	if (err) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Firmware is not ready to run!\n");
+	} else {
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+			 "Firmware is ready to run!\n");
+	}
+
+	return 0;
+}
+
+#if (USE_SPECIFIC_FW_TO_SUPPORT_WOWLAN == 1)
+void rtl8821ae_set_fw_related_for_wowlan(struct ieee80211_hw *hw,
+					 bool used_wowlan_fw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	/* 1. Before WoWLAN or After WOWLAN we need to re-download Fw. */
+	if (rtl8821ae_download_fw(hw, used_wowlan_fw)) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+			 "Re-Download Firmware failed!!\n");
+		rtlhal->fw_ready = false;
+		return;
+	}
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		 "Re-Download Firmware Success !!\n");
+	rtlhal->fw_ready = true;
+
+	/* 2. Re-Init the variables about Fw related setting. */
+	ppsc->fw_current_inpsmode = false;
+	rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_8821AE;
+	rtlhal->fw_clk_change_in_progress = false;
+	rtlhal->allow_sw_to_change_hwclc = false;
+	rtlhal->last_hmeboxnum = 0;
+}
+#endif
+
+static bool _rtl8821ae_check_fw_read_last_h2c(struct ieee80211_hw *hw,
+					      u8 boxnum)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 val_hmetfr;
+	bool result = false;
+
+	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
+	if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
+		result = true;
+	return result;
+}
+
+static void _rtl8821ae_fill_h2c_command(struct ieee80211_hw *hw,
+					u8 element_id, u32 cmd_len,
+					u8 *cmdbuffer)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 boxnum = 0;
+	u16 box_reg = 0, box_extreg = 0;
+	u8 u1b_tmp = 0;
+	bool isfw_read = false;
+	u8 buf_index = 0;
+	bool bwrite_sucess = false;
+	u8 wait_h2c_limmit = 100;
+	/*u8 wait_writeh2c_limmit = 100;*/
+	u8 boxcontent[4], boxextcontent[4];
+	u32 h2c_waitcounter = 0;
+	unsigned long flag = 0;
+	u8 idx = 0;
+
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
+
+	while (true) {
+		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+		if (rtlhal->h2c_setinprogress) {
+			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+				 "H2C set in progress! Wait to set..element_id(%d).\n",
+				 element_id);
+
+			while (rtlhal->h2c_setinprogress) {
+				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
+						       flag);
+				h2c_waitcounter++;
+				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+					 "Wait 100 us (%d times)...\n",
+					  h2c_waitcounter);
+				udelay(100);
+
+				if (h2c_waitcounter > 1000)
+					return;
+				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
+						  flag);
+			}
+			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+		} else {
+			rtlhal->h2c_setinprogress = true;
+			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+			break;
+		}
+	}
+
+	while (!bwrite_sucess) {
+		boxnum = rtlhal->last_hmeboxnum;
+		switch (boxnum) {
+		case 0:
+			box_reg = REG_HMEBOX_0;
+			box_extreg = REG_HMEBOX_EXT_0;
+			break;
+		case 1:
+			box_reg = REG_HMEBOX_1;
+			box_extreg = REG_HMEBOX_EXT_1;
+			break;
+		case 2:
+			box_reg = REG_HMEBOX_2;
+			box_extreg = REG_HMEBOX_EXT_2;
+			break;
+		case 3:
+			box_reg = REG_HMEBOX_3;
+			box_extreg = REG_HMEBOX_EXT_3;
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
+			break;
+		}
+
+		isfw_read = false;
+		u1b_tmp = rtl_read_byte(rtlpriv, REG_CR);
+
+		if (u1b_tmp != 0xEA) {
+			isfw_read = true;
+		} else {
+			if (rtl_read_byte(rtlpriv, REG_TXDMA_STATUS) == 0xEA ||
+			    rtl_read_byte(rtlpriv, REG_TXPKT_EMPTY) == 0xEA)
+				rtl_write_byte(rtlpriv, REG_SYS_CFG1 + 3, 0xFF);
+		}
+
+		if (isfw_read) {
+			wait_h2c_limmit = 100;
+			isfw_read =
+			  _rtl8821ae_check_fw_read_last_h2c(hw, boxnum);
+			while (!isfw_read) {
+				/*wait until Fw read*/
+				wait_h2c_limmit--;
+				if (wait_h2c_limmit == 0) {
+					RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+						 "Waiting too long for FW read clear HMEBox(%d)!\n",
+						 boxnum);
+					break;
+				}
+
+				udelay(10);
+
+				isfw_read =
+				  _rtl8821ae_check_fw_read_last_h2c(hw, boxnum);
+				u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
+				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+					 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
+					 boxnum, u1b_tmp);
+			}
+		}
+
+		if (!isfw_read) {
+			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
+				 boxnum);
+			break;
+		}
+
+		memset(boxcontent, 0, sizeof(boxcontent));
+		memset(boxextcontent, 0, sizeof(boxextcontent));
+		boxcontent[0] = element_id;
+		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+			 "Write element_id box_reg(%4x) = %2x\n",
+			 box_reg, element_id);
+
+		switch (cmd_len) {
+		case 1:
+		case 2:
+		case 3:
+			/*boxcontent[0] &= ~(BIT(7));*/
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index, cmd_len);
+
+			for (idx = 0; idx < 4; idx++) {
+				rtl_write_byte(rtlpriv, box_reg + idx,
+					       boxcontent[idx]);
+			}
+			break;
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+			/*boxcontent[0] |= (BIT(7));*/
+			memcpy((u8 *)(boxextcontent),
+			       cmdbuffer + buf_index+3, cmd_len-3);
+			memcpy((u8 *)(boxcontent) + 1,
+			       cmdbuffer + buf_index, 3);
+
+			for (idx = 0; idx < 4; idx++) {
+				rtl_write_byte(rtlpriv, box_extreg + idx,
+					       boxextcontent[idx]);
+			}
+
+			for (idx = 0; idx < 4; idx++) {
+				rtl_write_byte(rtlpriv, box_reg + idx,
+					       boxcontent[idx]);
+			}
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
+			break;
+		}
+
+		bwrite_sucess = true;
+
+		rtlhal->last_hmeboxnum = boxnum + 1;
+		if (rtlhal->last_hmeboxnum == 4)
+			rtlhal->last_hmeboxnum = 0;
+
+		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+			 "pHalData->last_hmeboxnum  = %d\n",
+			  rtlhal->last_hmeboxnum);
+	}
+
+	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+	rtlhal->h2c_setinprogress = false;
+	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
+}
+
+void rtl8821ae_fill_h2c_cmd(struct ieee80211_hw *hw,
+			    u8 element_id, u32 cmd_len, u8 *cmdbuffer)
+{
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u32 tmp_cmdbuf[2];
+
+	if (!rtlhal->fw_ready) {
+		RT_ASSERT(false,
+			  "return H2C cmd because of Fw download fail!!!\n");
+		return;
+	}
+
+	memset(tmp_cmdbuf, 0, 8);
+	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
+	_rtl8821ae_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
+}
+
+void rtl8821ae_firmware_selfreset(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 u1b_tmp;
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+		u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1);
+		rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp & (~BIT(3))));
+	} else {
+		u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1);
+		rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp & (~BIT(0))));
+	}
+
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
+	udelay(50);
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+		u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1);
+		rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp | BIT(3)));
+	} else {
+		u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1);
+		rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp | BIT(0)));
+	}
+
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "_8051Reset8812ae(): 8051 reset success .\n");
+}
+
+void rtl8821ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 u1_h2c_set_pwrmode[H2C_8821AE_PWEMODE_LENGTH] = { 0 };
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	u8 rlbm, power_state = 0;
+
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
+
+	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
+	rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/
+	SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
+	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
+					 (rtlpriv->mac80211.p2p) ?
+					 ppsc->smart_ps : 1);
+	SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
+					       ppsc->reg_max_lps_awakeintvl);
+	SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
+	if (mode == FW_PS_ACTIVE_MODE)
+		power_state |= FW_PWR_STATE_ACTIVE;
+	else
+		power_state |= FW_PWR_STATE_RF_OFF;
+
+	SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
+
+	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+		      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
+		      u1_h2c_set_pwrmode, H2C_8821AE_PWEMODE_LENGTH);
+	rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_SETPWRMODE,
+			       H2C_8821AE_PWEMODE_LENGTH,
+			       u1_h2c_set_pwrmode);
+}
+
+void rtl8821ae_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw,
+					   u8 mstatus)
+{
+	u8 parm[3] = { 0, 0, 0 };
+	/* parm[0]: bit0=0-->Disconnect, bit0=1-->Connect
+	 *          bit1=0-->update Media Status to MACID
+	 *          bit1=1-->update Media Status from MACID to MACID_End
+	 * parm[1]: MACID, if this is INFRA_STA, MacID = 0
+	 * parm[2]: MACID_End
+	 */
+
+	SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, mstatus);
+	SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0);
+
+	rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_MSRRPT, 3, parm);
+}
+
+void rtl8821ae_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
+				      u8 ap_offload_enable)
+{
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	u8 u1_apoffload_parm[H2C_8821AE_AP_OFFLOAD_LENGTH] = { 0 };
+
+	SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
+	SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
+	SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
+
+	rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_AP_OFFLOAD,
+			       H2C_8821AE_AP_OFFLOAD_LENGTH,
+			       u1_apoffload_parm);
+}
+
+void rtl8821ae_set_fw_wowlan_mode(struct ieee80211_hw *hw, bool func_en)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	u8 fw_wowlan_info[H2C_8821AE_WOWLAN_LENGTH] = {0};
+
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "enable(%d)\n", func_en);
+
+	SET_8812_H2CCMD_WOWLAN_FUNC_ENABLE(fw_wowlan_info,
+					   (func_en ? true : false));
+
+	SET_8812_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(fw_wowlan_info,
+		((ppsc->wo_wlan_mode & WAKE_ON_PATTERN_MATCH) ? 1 : 0));
+	SET_8812_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(fw_wowlan_info,
+		((ppsc->wo_wlan_mode & WAKE_ON_MAGIC_PACKET) ? 1 : 0));
+
+	SET_8812_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(fw_wowlan_info, 0);
+	SET_8812_H2CCMD_WOWLAN_ALL_PKT_DROP(fw_wowlan_info, false);
+	SET_8812_H2CCMD_WOWLAN_GPIO_ACTIVE(fw_wowlan_info, 0);
+	SET_8812_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(fw_wowlan_info, 1);
+	SET_8812_H2CCMD_WOWLAN_GPIONUM(fw_wowlan_info, 0);
+	SET_8812_H2CCMD_WOWLAN_GPIO_DURATION(fw_wowlan_info, 0);
+
+	RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_DMESG,
+		      "wowlan mode: cmd 0x80: Content:\n",
+		      fw_wowlan_info, H2C_8821AE_WOWLAN_LENGTH);
+
+	rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_WO_WLAN,
+			       H2C_8821AE_WOWLAN_LENGTH,
+			       fw_wowlan_info);
+}
+
+void rtl8821ae_set_fw_remote_wake_ctrl_cmd(struct ieee80211_hw *hw,
+					   u8 enable)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 remote_wake_ctrl_parm[H2C_8821AE_REMOTE_WAKE_CTRL_LEN] = {0};
+
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+		 "enable=%d, ARP offload=%d, GTK offload=%d\n",
+		 enable, ppsc->arp_offload_enable, ppsc->gtk_offload_enable);
+
+	SET_8812_H2CCMD_REMOTE_WAKECTRL_ENABLE(remote_wake_ctrl_parm, enable);
+	SET_8812_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN(remote_wake_ctrl_parm,
+					(ppsc->arp_offload_enable ? 1 : 0));
+	SET_8812_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(remote_wake_ctrl_parm,
+					(ppsc->gtk_offload_enable ? 1 : 0));
+	SET_8812_H2CCMD_REMOTE_WAKE_CTRL_REALWOWV2_EN(remote_wake_ctrl_parm,
+					(rtlhal->real_wow_v2_enable ? 1 : 0));
+
+	RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+		      "remote_wake_ctrl: cmd 0x4: Content:\n",
+		      remote_wake_ctrl_parm, H2C_8821AE_REMOTE_WAKE_CTRL_LEN);
+
+	rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_REMOTE_WAKE_CTRL,
+			       H2C_8821AE_REMOTE_WAKE_CTRL_LEN,
+			       remote_wake_ctrl_parm);
+}
+
+void rtl8821ae_set_fw_keep_alive_cmd(struct ieee80211_hw *hw,
+				     bool func_en)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 keep_alive_info[H2C_8821AE_KEEP_ALIVE_CTRL_LENGTH] = {0};
+
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Enable(%d)\n", func_en);
+
+	SET_8812_H2CCMD_KEEP_ALIVE_ENABLE(keep_alive_info, func_en);
+	/* 1: the period is controled by driver, 0: by Fw default */
+	SET_8812_H2CCMD_KEEP_ALIVE_ACCPEPT_USER_DEFINED(keep_alive_info, 1);
+	SET_8812_H2CCMD_KEEP_ALIVE_PERIOD(keep_alive_info, 10); /* 10 sec */
+
+	RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+		      "keep alive: cmd 0x3: Content:\n",
+		      keep_alive_info, H2C_8821AE_KEEP_ALIVE_CTRL);
+	rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_KEEP_ALIVE_CTRL,
+			       H2C_8821AE_KEEP_ALIVE_CTRL_LENGTH,
+			       keep_alive_info);
+}
+
+void rtl8821ae_set_fw_disconnect_decision_ctrl_cmd(struct ieee80211_hw *hw,
+						   bool enabled)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 parm[H2C_8821AE_DISCONNECT_DECISION_CTRL_LEN] = {0};
+
+	SET_8812_H2CCMD_DISCONNECT_DECISION_CTRL_ENABLE(parm, enabled);
+	SET_8812_H2CCMD_DISCONNECT_DECISION_CTRL_USER_SETTING(parm, 1);
+	SET_8812_H2CCMD_DISCONNECT_DECISION_CTRL_CHECK_PERIOD(parm, 30);
+	SET_8812_H2CCMD_DISCONNECT_DECISION_CTRL_TRYPKT_NUM(parm, 3);
+
+	RT_PRINT_DATA(rtlpriv, COMP_POWER, DBG_TRACE,
+		      "disconnect_decision_ctrl: cmd 0x4: Content:\n",
+		      parm, H2C_8821AE_DISCONNECT_DECISION_CTRL_LEN);
+	rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_DISCONNECT_DECISION,
+			       H2C_8821AE_DISCONNECT_DECISION_CTRL_LEN, parm);
+}
+
+void rtl8821ae_set_fw_global_info_cmd(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_security *sec = &rtlpriv->sec;
+	u8 remote_wakeup_sec_info[H2C_8821AE_AOAC_GLOBAL_INFO_LEN] = {0};
+
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+		 "PairwiseEncAlgorithm=%d, GroupEncAlgorithm=%d\n",
+		 sec->pairwise_enc_algorithm, sec->group_enc_algorithm);
+
+	SET_8812_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(
+						remote_wakeup_sec_info,
+						sec->pairwise_enc_algorithm);
+	SET_8812_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(remote_wakeup_sec_info,
+						      sec->group_enc_algorithm);
+
+	rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_AOAC_GLOBAL_INFO,
+			       H2C_8821AE_AOAC_GLOBAL_INFO_LEN,
+			       remote_wakeup_sec_info);
+
+	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_TRACE,
+		      "rtl8821ae_set_global_info: cmd 0x82:\n",
+		      remote_wakeup_sec_info, H2C_8821AE_AOAC_GLOBAL_INFO_LEN);
+}
+
+#define BEACON_PG		0
+#define PSPOLL_PG		1
+#define NULL_PG			2
+#define QOSNULL_PG		3
+#define ARPRESP_PG		4
+#define REMOTE_PG		5
+#define GTKEXT_PG		6
+
+#define TOTAL_RESERVED_PKT_LEN_8812	3584
+#define TOTAL_RESERVED_PKT_LEN_8821	1792
+
+static u8 reserved_page_packet_8821[TOTAL_RESERVED_PKT_LEN_8821] = {
+	/* page 0: beacon */
+	0x80, 0x00, 0x00, 0x00,  0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0x00, 0xe0,  0x4c, 0x02, 0xe2, 0x64,
+	0x40, 0x16, 0x9f, 0x23,  0xd4, 0x46, 0x20, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x64, 0x00, 0x20, 0x04,  0x00, 0x06, 0x64, 0x6c,
+	0x69, 0x6e, 0x6b, 0x31,  0x01, 0x08, 0x82, 0x84,
+	0x8b, 0x96, 0x0c, 0x18,  0x30, 0x48, 0x03, 0x01,
+	0x0b, 0x06, 0x02, 0x00,  0x00, 0x2a, 0x01, 0x8b,
+	0x32, 0x04, 0x12, 0x24,  0x60, 0x6c, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x10, 0x00, 0x28, 0x8c,  0x00, 0x12, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x81, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	/* page 1: ps-poll */
+	0xa4, 0x10, 0x01, 0xc0,  0x40, 0x16, 0x9f, 0x23,
+	0xd4, 0x46, 0x00, 0xe0,  0x4c, 0x02, 0xe2, 0x64,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x18, 0x00, 0x28, 0x8c,  0x00, 0x12, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x01, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x80, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	/* page 2: null data */
+	0x48, 0x01, 0x00, 0x00,  0x40, 0x16, 0x9f, 0x23,
+	0xd4, 0x46, 0x00, 0xe0,  0x4c, 0x02, 0xe2, 0x64,
+	0x40, 0x16, 0x9f, 0x23,  0xd4, 0x46, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x1A, 0x00, 0x28, 0x8C,  0x00, 0x12, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x01, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x80, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	/* page 3: qos null data */
+	0xC8, 0x01, 0x00, 0x00,  0x84, 0xC9, 0xB2, 0xA7,
+	0xB3, 0x6E, 0x00, 0xE0,  0x4C, 0x02, 0x51, 0x02,
+	0x84, 0xC9, 0xB2, 0xA7,  0xB3, 0x6E, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x3C, 0x00, 0x28, 0x8C,  0x00, 0x12, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x01, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x80, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	/* page 4~6 is for wowlan */
+	/* page 4: ARP resp */
+	0x08, 0x01, 0x00, 0x00,  0x84, 0xC9, 0xB2, 0xA7,
+	0xB3, 0x6E, 0x00, 0xE0,  0x4C, 0x02, 0x51, 0x02,
+	0x84, 0xC9, 0xB2, 0xA7,  0xB3, 0x6E, 0x00, 0x00,
+	0xAA, 0xAA, 0x03, 0x00,  0x00, 0x00, 0x08, 0x06,
+	0x00, 0x01, 0x08, 0x00,  0x06, 0x04, 0x00, 0x02,
+	0x00, 0xE0, 0x4C, 0x02,  0x51, 0x02, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xE0,  0x4C, 0x02, 0x51, 0x02,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	/* page 5: H2C_REMOTE_WAKE_CTRL_INFO */
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	/* page 6: Rsvd GTK extend memory (zero memory) */
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+};
+
+static u8 reserved_page_packet_8812[TOTAL_RESERVED_PKT_LEN_8812] = {
+	/* page 0: beacon */
+	0x80, 0x00, 0x00, 0x00,  0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0x00, 0xE0,  0x4C, 0x02, 0x51, 0x02,
+	0x84, 0xC9, 0xB2, 0xA7,  0xB3, 0x6E, 0x60, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x64, 0x00, 0x20, 0x04,  0x00, 0x03, 0x32, 0x31,
+	0x35, 0x01, 0x08, 0x82,  0x84, 0x8B, 0x96, 0x0C,
+	0x12, 0x18, 0x24, 0x03,  0x01, 0x01, 0x06, 0x02,
+	0x00, 0x00, 0x2A, 0x01,  0x02, 0x32, 0x04, 0x30,
+	0x48, 0x60, 0x6C, 0x2D,  0x1A, 0xED, 0x09, 0x03,
+	0xFF, 0xFF, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x3D,
+	0x00, 0xDD, 0x07, 0x00,  0xE0, 0x4C, 0x02, 0x02,
+	0x08, 0x04, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x10, 0x00, 0x28, 0x8C,  0x00, 0x12, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x81, 0x00, 0x00,
+	0x04, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	/* page 1: ps-poll */
+	0xA4, 0x10, 0x09, 0xC0,  0x84, 0xC9, 0xB2, 0xA7,
+	0xB3, 0x6E, 0x00, 0xE0,  0x4C, 0x02, 0x51, 0x02,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x18, 0x00, 0x28, 0x8C,  0x00, 0x12, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x01, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x80, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	/* page 2: null data */
+	0x48, 0x01, 0x00, 0x00,  0x84, 0xC9, 0xB2, 0xA7,
+	0xB3, 0x6E, 0x00, 0xE0,  0x4C, 0x02, 0x51, 0x02,
+	0x84, 0xC9, 0xB2, 0xA7,  0xB3, 0x6E, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x1A, 0x00, 0x28, 0x8C,  0x00, 0x12, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x01, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x80, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	/* page 3: Qos null data */
+	0xC8, 0x01, 0x00, 0x00,  0x84, 0xC9, 0xB2, 0xA7,
+	0xB3, 0x6E, 0x00, 0xE0,  0x4C, 0x02, 0x51, 0x02,
+	0x84, 0xC9, 0xB2, 0xA7,  0xB3, 0x6E, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x3C, 0x00, 0x28, 0x8C,  0x00, 0x12, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x01, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x80, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	/* page 4~6 is for wowlan */
+	/* page 4: ARP resp */
+	0x08, 0x01, 0x00, 0x00,  0x84, 0xC9, 0xB2, 0xA7,
+	0xB3, 0x6E, 0x00, 0xE0,  0x4C, 0x02, 0x51, 0x02,
+	0x84, 0xC9, 0xB2, 0xA7,  0xB3, 0x6E, 0x00, 0x00,
+	0xAA, 0xAA, 0x03, 0x00,  0x00, 0x00, 0x08, 0x06,
+	0x00, 0x01, 0x08, 0x00,  0x06, 0x04, 0x00, 0x02,
+	0x00, 0xE0, 0x4C, 0x02,  0x51, 0x02, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xE0,  0x4C, 0x02, 0x51, 0x02,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	/* page 5: H2C_REMOTE_WAKE_CTRL_INFO */
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	/* page 6: Rsvd GTK extend memory (zero memory) */
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+};
+
+void rtl8812ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
+				  bool b_dl_finished, bool dl_whole_packets)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtlpriv);
+	struct sk_buff *skb = NULL;
+	u32 totalpacketlen;
+	bool rtstatus;
+	u8 u1RsvdPageLoc[5] = { 0 };
+	u8 u1RsvdPageLoc2[7] = { 0 };
+	bool b_dlok = false;
+	u8 *beacon;
+	u8 *p_pspoll;
+	u8 *nullfunc;
+	u8 *qosnull;
+	u8 *arpresp;
+
+	/*---------------------------------------------------------
+	 *			(1) beacon
+	 *---------------------------------------------------------
+	 */
+	beacon = &reserved_page_packet_8812[BEACON_PG * 512];
+	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
+
+	if (b_dl_finished) {
+		totalpacketlen = 512 - 40;
+		goto out;
+	}
+	/*-------------------------------------------------------
+	 *			(2) ps-poll
+	 *--------------------------------------------------------
+	 */
+	p_pspoll = &reserved_page_packet_8812[PSPOLL_PG * 512];
+	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
+	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
+	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
+
+	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
+
+	/*--------------------------------------------------------
+	 *			(3) null data
+	 *---------------------------------------------------------
+	 */
+	nullfunc = &reserved_page_packet_8812[NULL_PG * 512];
+	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
+	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
+
+	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
+
+	/*---------------------------------------------------------
+	 *			(4) Qos null data
+	 *----------------------------------------------------------
+	 */
+	qosnull = &reserved_page_packet_8812[QOSNULL_PG * 512];
+	SET_80211_HDR_ADDRESS1(qosnull, mac->bssid);
+	SET_80211_HDR_ADDRESS2(qosnull, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(qosnull, mac->bssid);
+
+	SET_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1RsvdPageLoc, QOSNULL_PG);
+
+	if (!dl_whole_packets) {
+		totalpacketlen = 512 * (QOSNULL_PG + 1) - 40;
+		goto out;
+	}
+	/*---------------------------------------------------------
+	 *			(5) ARP Resp
+	 *----------------------------------------------------------
+	 */
+	arpresp = &reserved_page_packet_8812[ARPRESP_PG * 512];
+	SET_80211_HDR_ADDRESS1(arpresp, mac->bssid);
+	SET_80211_HDR_ADDRESS2(arpresp, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(arpresp, mac->bssid);
+
+	SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(u1RsvdPageLoc2, ARPRESP_PG);
+
+	/*---------------------------------------------------------
+	 *			(6) Remote Wake Ctrl
+	 *----------------------------------------------------------
+	 */
+	SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_REMOTE_WAKE_CTRL_INFO(u1RsvdPageLoc2,
+								REMOTE_PG);
+
+	/*---------------------------------------------------------
+	 *			(7) GTK Ext Memory
+	 *----------------------------------------------------------
+	 */
+	SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_EXT_MEM(u1RsvdPageLoc2, GTKEXT_PG);
+
+	totalpacketlen = TOTAL_RESERVED_PKT_LEN_8812 - 40;
+
+out:
+	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+		      "rtl8812ae_set_fw_rsvdpagepkt(): packet data\n",
+		      &reserved_page_packet_8812[0], totalpacketlen);
+
+	skb = dev_alloc_skb(totalpacketlen);
+	memcpy((u8 *)skb_put(skb, totalpacketlen),
+	       &reserved_page_packet_8812, totalpacketlen);
+
+	rtstatus = rtl_cmd_send_packet(hw, skb);
+
+	if (rtstatus)
+		b_dlok = true;
+
+	if (!b_dl_finished && b_dlok) {
+		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+			      "H2C_RSVDPAGE:\n", u1RsvdPageLoc, 5);
+		rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_RSVDPAGE,
+				       sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
+		if (dl_whole_packets) {
+			RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+				      "wowlan H2C_RSVDPAGE:\n", u1RsvdPageLoc2, 7);
+			rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_AOAC_RSVDPAGE,
+					       sizeof(u1RsvdPageLoc2), u1RsvdPageLoc2);
+		}
+	}
+
+	if (!b_dlok)
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
+}
+
+void rtl8821ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
+				  bool b_dl_finished, bool dl_whole_packets)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct sk_buff *skb = NULL;
+	u32 totalpacketlen;
+	bool rtstatus;
+	u8 u1RsvdPageLoc[5] = { 0 };
+	u8 u1RsvdPageLoc2[7] = { 0 };
+	bool b_dlok = false;
+	u8 *beacon;
+	u8 *p_pspoll;
+	u8 *nullfunc;
+	u8 *qosnull;
+	u8 *arpresp;
+
+	/*---------------------------------------------------------
+	 *			(1) beacon
+	 *---------------------------------------------------------
+	 */
+	beacon = &reserved_page_packet_8821[BEACON_PG * 256];
+	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
+
+	if (b_dl_finished) {
+		totalpacketlen = 256 - 40;
+		goto out;
+	}
+	/*-------------------------------------------------------
+	 *			(2) ps-poll
+	 *--------------------------------------------------------
+	 */
+	p_pspoll = &reserved_page_packet_8821[PSPOLL_PG * 256];
+	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
+	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
+	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
+
+	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
+
+	/*--------------------------------------------------------
+	 *			(3) null data
+	 *---------------------------------------------------------i
+	 */
+	nullfunc = &reserved_page_packet_8821[NULL_PG * 256];
+	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
+	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
+
+	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
+
+	/*---------------------------------------------------------
+	 *			(4) Qos null data
+	 *----------------------------------------------------------
+	 */
+	qosnull = &reserved_page_packet_8821[QOSNULL_PG * 256];
+	SET_80211_HDR_ADDRESS1(qosnull, mac->bssid);
+	SET_80211_HDR_ADDRESS2(qosnull, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(qosnull, mac->bssid);
+
+	SET_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1RsvdPageLoc, QOSNULL_PG);
+
+	if (!dl_whole_packets) {
+		totalpacketlen = 256 * (QOSNULL_PG + 1) - 40;
+		goto out;
+	}
+	/*---------------------------------------------------------
+	 *			(5) ARP Resp
+	 *----------------------------------------------------------
+	 */
+	arpresp = &reserved_page_packet_8821[ARPRESP_PG * 256];
+	SET_80211_HDR_ADDRESS1(arpresp, mac->bssid);
+	SET_80211_HDR_ADDRESS2(arpresp, mac->mac_addr);
+	SET_80211_HDR_ADDRESS3(arpresp, mac->bssid);
+
+	SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(u1RsvdPageLoc2, ARPRESP_PG);
+
+	/*---------------------------------------------------------
+	 *			(6) Remote Wake Ctrl
+	 *----------------------------------------------------------
+	 */
+	SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_REMOTE_WAKE_CTRL_INFO(u1RsvdPageLoc2,
+									REMOTE_PG);
+
+	/*---------------------------------------------------------
+	 *			(7) GTK Ext Memory
+	 *----------------------------------------------------------
+	 */
+	SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_EXT_MEM(u1RsvdPageLoc2, GTKEXT_PG);
+
+	totalpacketlen = TOTAL_RESERVED_PKT_LEN_8821 - 40;
+
+out:
+
+	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+		      "rtl8821ae_set_fw_rsvdpagepkt(): packet data\n",
+		      &reserved_page_packet_8821[0], totalpacketlen);
+
+	skb = dev_alloc_skb(totalpacketlen);
+	memcpy((u8 *)skb_put(skb, totalpacketlen),
+	       &reserved_page_packet_8821, totalpacketlen);
+
+	rtstatus = rtl_cmd_send_packet(hw, skb);
+
+	if (rtstatus)
+		b_dlok = true;
+
+	if (!b_dl_finished && b_dlok) {
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+			 "Set RSVD page location to Fw.\n");
+		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+				"H2C_RSVDPAGE:\n", u1RsvdPageLoc, 5);
+		rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_RSVDPAGE,
+				       sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
+		if (dl_whole_packets) {
+			RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+				      "wowlan H2C_RSVDPAGE:\n",
+				      u1RsvdPageLoc2, 7);
+			rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_AOAC_RSVDPAGE,
+					       sizeof(u1RsvdPageLoc2),
+					       u1RsvdPageLoc2);
+		}
+	}
+
+	if (!b_dlok) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
+	}
+}
+
+/*Should check FW support p2p or not.*/
+static void rtl8821ae_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
+{
+	u8 u1_ctwindow_period[1] = { ctwindow};
+
+	rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_P2P_PS_CTW_CMD, 1,
+			       u1_ctwindow_period);
+}
+
+void rtl8821ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_p2p_ps_info *p2pinfo = &rtlps->p2p_ps_info;
+	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
+	u8	i;
+	u16	ctwindow;
+	u32	start_time, tsf_low;
+
+	switch (p2p_ps_state) {
+	case P2P_PS_DISABLE:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
+		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
+		break;
+	case P2P_PS_ENABLE:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
+		/* update CTWindow value. */
+		if (p2pinfo->ctwindow > 0) {
+			p2p_ps_offload->ctwindow_en = 1;
+			ctwindow = p2pinfo->ctwindow;
+			rtl8821ae_set_p2p_ctw_period_cmd(hw, ctwindow);
+		}
+
+		/* hw only support 2 set of NoA */
+		for (i = 0 ; i < p2pinfo->noa_num ; i++) {
+			/* To control the register setting for which NOA*/
+			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
+			if (i == 0)
+				p2p_ps_offload->noa0_en = 1;
+			else
+				p2p_ps_offload->noa1_en = 1;
+
+			/* config P2P NoA Descriptor Register */
+			rtl_write_dword(rtlpriv, 0x5E0, p2pinfo->noa_duration[i]);
+			rtl_write_dword(rtlpriv, 0x5E4, p2pinfo->noa_interval[i]);
+
+			/*Get Current TSF value */
+			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+			start_time = p2pinfo->noa_start_time[i];
+			if (p2pinfo->noa_count_type[i] != 1) {
+				while (start_time <= (tsf_low+(50*1024))) {
+					start_time += p2pinfo->noa_interval[i];
+					if (p2pinfo->noa_count_type[i] != 255)
+						p2pinfo->noa_count_type[i]--;
+				}
+			}
+			rtl_write_dword(rtlpriv, 0x5E8, start_time);
+			rtl_write_dword(rtlpriv, 0x5EC,
+					p2pinfo->noa_count_type[i]);
+		}
+
+		if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
+			/* rst p2p circuit */
+			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
+
+			p2p_ps_offload->offload_en = 1;
+
+			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
+				p2p_ps_offload->role = 1;
+				p2p_ps_offload->allstasleep = 0;
+			} else {
+				p2p_ps_offload->role = 0;
+			}
+
+			p2p_ps_offload->discovery = 0;
+		}
+		break;
+	case P2P_PS_SCAN:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
+		p2p_ps_offload->discovery = 1;
+		break;
+	case P2P_PS_SCAN_DONE:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
+		p2p_ps_offload->discovery = 0;
+		p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
+		break;
+	default:
+		break;
+	}
+
+	rtl8821ae_fill_h2c_cmd(hw,
+			H2C_8821AE_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
+}
+
+static void rtl8821ae_c2h_ra_report_handler(struct ieee80211_hw *hw,
+				     u8 *cmd_buf, u8 cmd_len)
+{
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 rate = cmd_buf[0] & 0x3F;
+
+	rtlhal->current_ra_rate = rtl8821ae_hw_rate_to_mrate(hw, rate);
+
+	rtl8821ae_dm_update_init_rate(hw, rate);
+}
+
+static void _rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw,
+					   u8 c2h_cmd_id, u8 c2h_cmd_len,
+					   u8 *tmp_buf)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	switch (c2h_cmd_id) {
+	case C2H_8812_DBG:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "[C2H], C2H_8812_DBG!!\n");
+		break;
+	case C2H_8812_RA_RPT:
+		rtl8821ae_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len);
+		break;
+	case C2H_8812_BT_INFO:
+		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+			 "[C2H], C2H_8812_BT_INFO!!\n");
+		if (rtlpriv->cfg->ops->get_btc_status())
+			rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv,
+								      tmp_buf,
+								      c2h_cmd_len);
+		break;
+	default:
+		break;
+	}
+}
+
+void rtl8821ae_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer,
+				  u8 length)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0;
+	u8 *tmp_buf = NULL;
+
+	c2h_cmd_id = buffer[0];
+	c2h_cmd_seq = buffer[1];
+	c2h_cmd_len = length - 2;
+	tmp_buf = buffer + 2;
+
+	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+		 "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n",
+		 c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len);
+
+	RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD,
+		      "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
+	_rtl8821ae_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/fw.h b/drivers/net/wireless/rtlwifi/rtl8821ae/fw.h
new file mode 100644
index 0000000..591c14c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/fw.h
@@ -0,0 +1,351 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8821AE__FW__H__
+#define __RTL8821AE__FW__H__
+#include "def.h"
+
+#define FW_8821AE_SIZE					0x8000
+#define FW_8821AE_START_ADDRESS			0x1000
+#define FW_8821AE_END_ADDRESS			0x5FFF
+#define FW_8821AE_PAGE_SIZE				4096
+#define FW_8821AE_POLLING_DELAY			5
+#define FW_8821AE_POLLING_TIMEOUT_COUNT	6000
+
+#define IS_FW_HEADER_EXIST_8812(_pfwhdr)	\
+	((_pfwhdr->signature&0xFFF0) == 0x9500)
+
+#define IS_FW_HEADER_EXIST_8821(_pfwhdr)	\
+	((_pfwhdr->signature&0xFFF0) == 0x2100)
+
+#define USE_OLD_WOWLAN_DEBUG_FW 0
+
+#define H2C_8821AE_RSVDPAGE_LOC_LEN		5
+#define H2C_8821AE_PWEMODE_LENGTH			5
+#define H2C_8821AE_JOINBSSRPT_LENGTH		1
+#define H2C_8821AE_AP_OFFLOAD_LENGTH		3
+#define H2C_8821AE_WOWLAN_LENGTH			3
+#define H2C_8821AE_KEEP_ALIVE_CTRL_LENGTH	3
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+#define H2C_8821AE_REMOTE_WAKE_CTRL_LEN	1
+#else
+#define H2C_8821AE_REMOTE_WAKE_CTRL_LEN	3
+#endif
+#define H2C_8821AE_AOAC_GLOBAL_INFO_LEN	2
+#define H2C_8821AE_AOAC_RSVDPAGE_LOC_LEN	7
+#define H2C_8821AE_DISCONNECT_DECISION_CTRL_LEN	3
+
+/* Fw PS state for RPWM.
+*BIT[2:0] = HW state
+
+*BIT[3] = Protocol PS state,
+1: register active state ,
+0: register sleep state
+
+*BIT[4] = sub-state
+*/
+#define	FW_PS_GO_ON			BIT(0)
+#define	FW_PS_TX_NULL			BIT(1)
+#define	FW_PS_RF_ON			BIT(2)
+#define	FW_PS_REGISTER_ACTIVE	BIT(3)
+
+#define	FW_PS_DPS		BIT(0)
+#define	FW_PS_LCLK		(FW_PS_DPS)
+#define	FW_PS_RF_OFF		BIT(1)
+#define	FW_PS_ALL_ON		BIT(2)
+#define	FW_PS_ST_ACTIVE		BIT(3)
+#define	FW_PS_ISR_ENABLE	BIT(4)
+#define	FW_PS_IMR_ENABLE	BIT(5)
+
+#define	FW_PS_ACK		BIT(6)
+#define	FW_PS_TOGGLE		BIT(7)
+
+ /* 8821AE RPWM value*/
+ /* BIT[0] = 1: 32k, 0: 40M*/
+ /* 32k*/
+#define	FW_PS_CLOCK_OFF		BIT(0)
+/*40M*/
+#define	FW_PS_CLOCK_ON		0
+
+#define	FW_PS_STATE_MASK		(0x0F)
+#define	FW_PS_STATE_HW_MASK	(0x07)
+/*ISR_ENABLE, IMR_ENABLE, and PS mode should be inherited.*/
+#define	FW_PS_STATE_INT_MASK	(0x3F)
+
+#define	FW_PS_STATE(x)			(FW_PS_STATE_MASK & (x))
+#define	FW_PS_STATE_HW(x)		(FW_PS_STATE_HW_MASK & (x))
+#define	FW_PS_STATE_INT(x)	(FW_PS_STATE_INT_MASK & (x))
+#define	FW_PS_ISR_VAL(x)		((x) & 0x70)
+#define	FW_PS_IMR_MASK(x)	((x) & 0xDF)
+#define	FW_PS_KEEP_IMR(x)		((x) & 0x20)
+
+#define	FW_PS_STATE_S0		(FW_PS_DPS)
+#define	FW_PS_STATE_S1		(FW_PS_LCLK)
+#define	FW_PS_STATE_S2		(FW_PS_RF_OFF)
+#define	FW_PS_STATE_S3		(FW_PS_ALL_ON)
+#define	FW_PS_STATE_S4		((FW_PS_ST_ACTIVE) | (FW_PS_ALL_ON))
+ /* ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))*/
+#define	FW_PS_STATE_ALL_ON_8821AE	(FW_PS_CLOCK_ON)
+ /* (FW_PS_RF_ON)*/
+#define	FW_PS_STATE_RF_ON_8821AE	(FW_PS_CLOCK_ON)
+ /* 0x0*/
+#define	FW_PS_STATE_RF_OFF_8821AE	(FW_PS_CLOCK_ON)
+ /* (FW_PS_STATE_RF_OFF)*/
+#define	FW_PS_STATE_RF_OFF_LOW_PWR_8821AE	(FW_PS_CLOCK_OFF)
+
+#define	FW_PS_STATE_ALL_ON_92C	(FW_PS_STATE_S4)
+#define	FW_PS_STATE_RF_ON_92C		(FW_PS_STATE_S3)
+#define	FW_PS_STATE_RF_OFF_92C	(FW_PS_STATE_S2)
+#define	FW_PS_STATE_RF_OFF_LOW_PWR_92C	(FW_PS_STATE_S1)
+
+/* For 8821AE H2C PwrMode Cmd ID 5.*/
+#define	FW_PWR_STATE_ACTIVE	((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
+#define	FW_PWR_STATE_RF_OFF	0
+
+#define	FW_PS_IS_ACK(x)		((x) & FW_PS_ACK)
+#define	FW_PS_IS_CLK_ON(x)	((x) & (FW_PS_RF_OFF | FW_PS_ALL_ON))
+#define	FW_PS_IS_RF_ON(x)	((x) & (FW_PS_ALL_ON))
+#define	FW_PS_IS_ACTIVE(x)	((x) & (FW_PS_ST_ACTIVE))
+#define	FW_PS_IS_CPWM_INT(x)	((x) & 0x40)
+
+#define	FW_CLR_PS_STATE(x)	((x) = ((x) & (0xF0)))
+
+#define	IS_IN_LOW_POWER_STATE_8821AE(__state)		\
+			(FW_PS_STATE(__state) == FW_PS_CLOCK_OFF)
+
+#define	FW_PWR_STATE_ACTIVE	((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
+#define	FW_PWR_STATE_RF_OFF	0
+
+struct rtl8821a_firmware_header {
+	u16 signature;
+	u8 category;
+	u8 function;
+	u16 version;
+	u8 subversion;
+	u8 rsvd1;
+	u8 month;
+	u8 date;
+	u8 hour;
+	u8 minute;
+	u16 ramcodeSize;
+	u16 rsvd2;
+	u32 svnindex;
+	u32 rsvd3;
+	u32 rsvd4;
+	u32 rsvd5;
+};
+
+enum rtl8812_c2h_evt {
+	C2H_8812_DBG = 0,
+	C2H_8812_LB = 1,
+	C2H_8812_TXBF = 2,
+	C2H_8812_TX_REPORT = 3,
+	C2H_8812_BT_INFO = 9,
+	C2H_8812_BT_MP = 11,
+	C2H_8812_RA_RPT = 12,
+
+	C2H_8812_FW_SWCHNL = 0x10,
+	C2H_8812_IQK_FINISH = 0x11,
+	MAX_8812_C2HEVENT
+};
+
+enum rtl8821a_h2c_cmd {
+	H2C_8821AE_RSVDPAGE = 0,
+	H2C_8821AE_MSRRPT = 1,
+	H2C_8821AE_SCAN = 2,
+	H2C_8821AE_KEEP_ALIVE_CTRL = 3,
+	H2C_8821AE_DISCONNECT_DECISION = 4,
+	H2C_8821AE_INIT_OFFLOAD = 6,
+	H2C_8821AE_AP_OFFLOAD = 8,
+	H2C_8821AE_BCN_RSVDPAGE = 9,
+	H2C_8821AE_PROBERSP_RSVDPAGE = 10,
+
+	H2C_8821AE_SETPWRMODE = 0x20,
+	H2C_8821AE_PS_TUNING_PARA = 0x21,
+	H2C_8821AE_PS_TUNING_PARA2 = 0x22,
+	H2C_8821AE_PS_LPS_PARA = 0x23,
+	H2C_8821AE_P2P_PS_OFFLOAD = 024,
+
+	H2C_8821AE_WO_WLAN = 0x80,
+	H2C_8821AE_REMOTE_WAKE_CTRL = 0x81,
+	H2C_8821AE_AOAC_GLOBAL_INFO = 0x82,
+	H2C_8821AE_AOAC_RSVDPAGE = 0x83,
+
+	H2C_RSSI_21AE_REPORT = 0x42,
+	H2C_8821AE_RA_MASK = 0x40,
+	H2C_8821AE_SELECTIVE_SUSPEND_ROF_CMD,
+	H2C_8821AE_P2P_PS_MODE,
+	H2C_8821AE_PSD_RESULT,
+	/*Not defined CTW CMD for P2P yet*/
+	H2C_8821AE_P2P_PS_CTW_CMD,
+	MAX_8821AE_H2CCMD
+};
+
+#define pagenum_128(_len)	(u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0))
+
+#define SET_8812_H2CCMD_WOWLAN_FUNC_ENABLE(__cmd, __value)		\
+	SET_BITS_TO_LE_1BYTE(__cmd, 0, 1, __value)
+#define SET_8812_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd, 1, 1, __value)
+#define SET_8812_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd, 2, 1, __value)
+#define SET_8812_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd, 3, 1, __value)
+#define SET_8812_H2CCMD_WOWLAN_ALL_PKT_DROP(__cmd, __value)		\
+	SET_BITS_TO_LE_1BYTE(__cmd, 4, 1, __value)
+#define SET_8812_H2CCMD_WOWLAN_GPIO_ACTIVE(__cmd, __value)		\
+	SET_BITS_TO_LE_1BYTE(__cmd, 5, 1, __value)
+#define SET_8812_H2CCMD_WOWLAN_REKEY_WAKE_UP(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd, 6, 1, __value)
+#define SET_8812_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd, 7, 1, __value)
+#define SET_8812_H2CCMD_WOWLAN_GPIONUM(__cmd, __value)		\
+	SET_BITS_TO_LE_1BYTE((__cmd) + 1, 0, 8, __value)
+#define SET_8812_H2CCMD_WOWLAN_GPIO_DURATION(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd) + 2, 0, 8, __value)
+
+#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val)			\
+	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_RLBM(__cmd, __value)		\
+	SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 4, __value)
+#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+1, 4, 4, __value)
+#define SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+#define SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(__cmd, __value)		\
+	SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __value)
+#define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+4, 0, 8, __value)
+#define GET_8821AE_H2CCMD_PWRMODE_PARM_MODE(__cmd)		\
+	LE_BITS_TO_1BYTE(__cmd, 0, 8)
+
+#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val)		\
+	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val)		\
+	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val)		\
+	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(__ph2ccmd, __val)		\
+	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+3, 0, 8, __val)
+
+/* _MEDIA_STATUS_RPT_PARM_CMD1 */
+#define SET_H2CCMD_MSRRPT_PARM_OPMODE(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd, 0, 1, __value)
+#define SET_H2CCMD_MSRRPT_PARM_MACID_IND(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd, 1, 1, __value)
+#define SET_H2CCMD_MSRRPT_PARM_MACID(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd+1, 0, 8, __value)
+#define SET_H2CCMD_MSRRPT_PARM_MACID_END(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd+2, 0, 8, __value)
+
+/* AP_OFFLOAD */
+#define SET_H2CCMD_AP_OFFLOAD_ON(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd, 0, 8, __value)
+#define SET_H2CCMD_AP_OFFLOAD_HIDDEN(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+#define SET_H2CCMD_AP_OFFLOAD_DENYANY(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+#define SET_H2CCMD_AP_OFFLOAD_WAKEUP_EVT_RPT(__cmd, __value) \
+	SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __value)
+
+/* Keep Alive Control*/
+#define SET_8812_H2CCMD_KEEP_ALIVE_ENABLE(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd, 0, 1, __value)
+#define SET_8812_H2CCMD_KEEP_ALIVE_ACCPEPT_USER_DEFINED(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd, 1, 1, __value)
+#define SET_8812_H2CCMD_KEEP_ALIVE_PERIOD(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+
+/*REMOTE_WAKE_CTRL */
+#define SET_8812_H2CCMD_REMOTE_WAKECTRL_ENABLE(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd, 0, 1, __value)
+#define SET_8812_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN(__cmd, __value)\
+	SET_BITS_TO_LE_1BYTE(__cmd, 1, 1, __value)
+#define SET_8812_H2CCMD_REMOTE_WAKE_CTRL_NDP_OFFLOAD_EN(__cmd, __value)\
+	SET_BITS_TO_LE_1BYTE(__cmd, 2, 1, __value)
+#define SET_8812_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(__cmd, __value)\
+	SET_BITS_TO_LE_1BYTE(__cmd, 3, 1, __value)
+#define SET_8812_H2CCMD_REMOTE_WAKE_CTRL_REALWOWV2_EN(__cmd, __value)\
+	SET_BITS_TO_LE_1BYTE(__cmd, 6, 1, __value)
+
+/* GTK_OFFLOAD */
+#define SET_8812_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(__cmd, __value)\
+	SET_BITS_TO_LE_1BYTE(__cmd, 0, 8, __value)
+#define SET_8812_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+
+/* AOAC_RSVDPAGE_LOC */
+#define SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_REMOTE_WAKE_CTRL_INFO(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd), 0, 8, __value)
+#define SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+#define SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(__cmd, __value)\
+	SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+#define SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __value)
+#define SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+4, 0, 8, __value)
+#define SET_8821AE_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_EXT_MEM(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE((__cmd)+5, 0, 8, __value)
+
+/* Disconnect_Decision_Control */
+#define SET_8812_H2CCMD_DISCONNECT_DECISION_CTRL_ENABLE(__cmd, __value)	\
+	SET_BITS_TO_LE_1BYTE(__cmd, 0, 1, __value)
+#define SET_8812_H2CCMD_DISCONNECT_DECISION_CTRL_USER_SETTING(__cmd, __value)\
+	SET_BITS_TO_LE_1BYTE(__cmd, 1, 1, __value)
+#define SET_8812_H2CCMD_DISCONNECT_DECISION_CTRL_CHECK_PERIOD(__cmd, __value)\
+	SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value) /* unit: beacon period */
+#define SET_8812_H2CCMD_DISCONNECT_DECISION_CTRL_TRYPKT_NUM(__cmd, __value)\
+	SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+
+int rtl8821ae_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw);
+#if (USE_SPECIFIC_FW_TO_SUPPORT_WOWLAN == 1)
+void rtl8821ae_set_fw_related_for_wowlan(struct ieee80211_hw *hw,
+					 bool used_wowlan_fw);
+
+#endif
+void rtl8821ae_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
+			    u32 cmd_len, u8 *cmdbuffer);
+void rtl8821ae_firmware_selfreset(struct ieee80211_hw *hw);
+void rtl8821ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
+void rtl8821ae_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw,
+					   u8 mstatus);
+void rtl8821ae_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
+				      u8 ap_offload_enable);
+void rtl8821ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
+				  bool b_dl_finished, bool dl_whole_packet);
+void rtl8812ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
+				  bool b_dl_finished, bool dl_whole_packet);
+void rtl8821ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw,
+				      u8 p2p_ps_state);
+void rtl8821ae_set_fw_wowlan_mode(struct ieee80211_hw *hw, bool func_en);
+void rtl8821ae_set_fw_remote_wake_ctrl_cmd(struct ieee80211_hw *hw,
+					   u8 enable);
+void rtl8821ae_set_fw_keep_alive_cmd(struct ieee80211_hw *hw, bool func_en);
+void rtl8821ae_set_fw_disconnect_decision_ctrl_cmd(struct ieee80211_hw *hw,
+						   bool enabled);
+void rtl8821ae_set_fw_global_info_cmd(struct ieee80211_hw *hw);
+void rtl8821ae_c2h_packet_handler(struct ieee80211_hw *hw,
+				  u8 *buffer, u8 length);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c
new file mode 100644
index 0000000..310d316
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c
@@ -0,0 +1,4218 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../efuse.h"
+#include "../base.h"
+#include "../regd.h"
+#include "../cam.h"
+#include "../ps.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "led.h"
+#include "hw.h"
+#include "../pwrseqcmd.h"
+#include "pwrseq.h"
+#include "../btcoexist/rtl_btc.h"
+
+#define LLT_CONFIG	5
+
+static void _rtl8821ae_return_beacon_queue_skb(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
+	unsigned long flags;
+
+	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+	while (skb_queue_len(&ring->queue)) {
+		struct rtl_tx_desc *entry = &ring->desc[ring->idx];
+		struct sk_buff *skb = __skb_dequeue(&ring->queue);
+
+		pci_unmap_single(rtlpci->pdev,
+				 rtlpriv->cfg->ops->get_desc(
+				 (u8 *)entry, true, HW_DESC_TXBUFF_ADDR),
+				 skb->len, PCI_DMA_TODEVICE);
+		kfree_skb(skb);
+		ring->idx = (ring->idx + 1) % ring->entries;
+	}
+	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+}
+
+static void _rtl8821ae_set_bcn_ctrl_reg(struct ieee80211_hw *hw,
+					u8 set_bits, u8 clear_bits)
+{
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtlpci->reg_bcn_ctrl_val |= set_bits;
+	rtlpci->reg_bcn_ctrl_val &= ~clear_bits;
+
+	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8)rtlpci->reg_bcn_ctrl_val);
+}
+
+void _rtl8821ae_stop_tx_beacon(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 tmp1byte;
+
+	tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6)));
+	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64);
+	tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+	tmp1byte &= ~(BIT(0));
+	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+void _rtl8821ae_resume_tx_beacon(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 tmp1byte;
+
+	tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6));
+	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+	tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+	tmp1byte |= BIT(0);
+	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl8821ae_enable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+	_rtl8821ae_set_bcn_ctrl_reg(hw, 0, BIT(1));
+}
+
+static void _rtl8821ae_disable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+	_rtl8821ae_set_bcn_ctrl_reg(hw, BIT(1), 0);
+}
+
+static void _rtl8821ae_set_fw_clock_on(struct ieee80211_hw *hw,
+				       u8 rpwm_val, bool b_need_turn_off_ckk)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	bool b_support_remote_wake_up;
+	u32 count = 0, isr_regaddr, content;
+	bool b_schedule_timer = b_need_turn_off_ckk;
+
+	rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+					(u8 *)(&b_support_remote_wake_up));
+
+	if (!rtlhal->fw_ready)
+		return;
+	if (!rtlpriv->psc.fw_current_inpsmode)
+		return;
+
+	while (1) {
+		spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+		if (rtlhal->fw_clk_change_in_progress) {
+			while (rtlhal->fw_clk_change_in_progress) {
+				spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+				count++;
+				udelay(100);
+				if (count > 1000)
+					goto change_done;
+				spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+			}
+			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+		} else {
+			rtlhal->fw_clk_change_in_progress = false;
+			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+			goto change_done;
+		}
+	}
+change_done:
+	if (IS_IN_LOW_POWER_STATE_8821AE(rtlhal->fw_ps_state)) {
+		rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM,
+					(u8 *)(&rpwm_val));
+		if (FW_PS_IS_ACK(rpwm_val)) {
+			isr_regaddr = REG_HISR;
+			content = rtl_read_dword(rtlpriv, isr_regaddr);
+			while (!(content & IMR_CPWM) && (count < 500)) {
+				udelay(50);
+				count++;
+				content = rtl_read_dword(rtlpriv, isr_regaddr);
+			}
+
+			if (content & IMR_CPWM) {
+				rtl_write_word(rtlpriv, isr_regaddr, 0x0100);
+				rtlhal->fw_ps_state = FW_PS_STATE_RF_ON_8821AE;
+				RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+					 "Receive CPWM INT!!! Set rtlhal->FwPSState = %X\n",
+					 rtlhal->fw_ps_state);
+			}
+		}
+
+		spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+		rtlhal->fw_clk_change_in_progress = false;
+		spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+		if (b_schedule_timer)
+			mod_timer(&rtlpriv->works.fw_clockoff_timer,
+				  jiffies + MSECS(10));
+	} else  {
+		spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+		rtlhal->fw_clk_change_in_progress = false;
+		spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+	}
+}
+
+static void _rtl8821ae_set_fw_clock_off(struct ieee80211_hw *hw,
+					u8 rpwm_val)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl8192_tx_ring *ring;
+	enum rf_pwrstate rtstate;
+	bool b_schedule_timer = false;
+	u8 queue;
+
+	if (!rtlhal->fw_ready)
+		return;
+	if (!rtlpriv->psc.fw_current_inpsmode)
+		return;
+	if (!rtlhal->allow_sw_to_change_hwclc)
+		return;
+	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE, (u8 *)(&rtstate));
+	if (rtstate == ERFOFF || rtlpriv->psc.inactive_pwrstate == ERFOFF)
+		return;
+
+	for (queue = 0; queue < RTL_PCI_MAX_TX_QUEUE_COUNT; queue++) {
+		ring = &rtlpci->tx_ring[queue];
+		if (skb_queue_len(&ring->queue)) {
+			b_schedule_timer = true;
+			break;
+		}
+	}
+
+	if (b_schedule_timer) {
+		mod_timer(&rtlpriv->works.fw_clockoff_timer,
+			  jiffies + MSECS(10));
+		return;
+	}
+
+	if (FW_PS_STATE(rtlhal->fw_ps_state) !=
+		FW_PS_STATE_RF_OFF_LOW_PWR_8821AE) {
+		spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+		if (!rtlhal->fw_clk_change_in_progress) {
+			rtlhal->fw_clk_change_in_progress = true;
+			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+			rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val);
+			rtl_write_word(rtlpriv, REG_HISR, 0x0100);
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+						      (u8 *)(&rpwm_val));
+			spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+			rtlhal->fw_clk_change_in_progress = false;
+			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+		} else {
+			spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+			mod_timer(&rtlpriv->works.fw_clockoff_timer,
+				  jiffies + MSECS(10));
+		}
+	}
+}
+
+static void _rtl8821ae_set_fw_ps_rf_on(struct ieee80211_hw *hw)
+{
+	u8 rpwm_val = 0;
+
+	rpwm_val |= (FW_PS_STATE_RF_OFF_8821AE | FW_PS_ACK);
+	_rtl8821ae_set_fw_clock_on(hw, rpwm_val, true);
+}
+
+static void _rtl8821ae_fwlps_leave(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	bool fw_current_inps = false;
+	u8 rpwm_val = 0, fw_pwrmode = FW_PS_ACTIVE_MODE;
+
+	if (ppsc->low_power_enable) {
+		rpwm_val = (FW_PS_STATE_ALL_ON_8821AE|FW_PS_ACK);/* RF on */
+		_rtl8821ae_set_fw_clock_on(hw, rpwm_val, false);
+		rtlhal->allow_sw_to_change_hwclc = false;
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+				(u8 *)(&fw_pwrmode));
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+				(u8 *)(&fw_current_inps));
+	} else {
+		rpwm_val = FW_PS_STATE_ALL_ON_8821AE;	/* RF on */
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+				(u8 *)(&rpwm_val));
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+				(u8 *)(&fw_pwrmode));
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+				(u8 *)(&fw_current_inps));
+	}
+}
+
+static void _rtl8821ae_fwlps_enter(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	bool fw_current_inps = true;
+	u8 rpwm_val;
+
+	if (ppsc->low_power_enable) {
+		rpwm_val = FW_PS_STATE_RF_OFF_LOW_PWR_8821AE;	/* RF off */
+		rtlpriv->cfg->ops->set_hw_reg(hw,
+				HW_VAR_FW_PSMODE_STATUS,
+				(u8 *)(&fw_current_inps));
+		rtlpriv->cfg->ops->set_hw_reg(hw,
+				HW_VAR_H2C_FW_PWRMODE,
+				(u8 *)(&ppsc->fwctrl_psmode));
+		rtlhal->allow_sw_to_change_hwclc = true;
+		_rtl8821ae_set_fw_clock_off(hw, rpwm_val);
+	} else {
+		rpwm_val = FW_PS_STATE_RF_OFF_8821AE;	/* RF off */
+		rtlpriv->cfg->ops->set_hw_reg(hw,
+				HW_VAR_FW_PSMODE_STATUS,
+				(u8 *)(&fw_current_inps));
+		rtlpriv->cfg->ops->set_hw_reg(hw,
+				HW_VAR_H2C_FW_PWRMODE,
+				(u8 *)(&ppsc->fwctrl_psmode));
+		rtlpriv->cfg->ops->set_hw_reg(hw,
+				HW_VAR_SET_RPWM,
+				(u8 *)(&rpwm_val));
+	}
+}
+
+static void _rtl8821ae_download_rsvd_page(struct ieee80211_hw *hw,
+					  bool dl_whole_packets)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	u8 tmp_regcr, tmp_reg422, bcnvalid_reg;
+	u8 count = 0, dlbcn_count = 0;
+	bool send_beacon = false;
+
+	tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
+	rtl_write_byte(rtlpriv, REG_CR + 1, (tmp_regcr | BIT(0)));
+
+	_rtl8821ae_set_bcn_ctrl_reg(hw, 0, BIT(3));
+	_rtl8821ae_set_bcn_ctrl_reg(hw, BIT(4), 0);
+
+	tmp_reg422 = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+		       tmp_reg422 & (~BIT(6)));
+	if (tmp_reg422 & BIT(6))
+		send_beacon = true;
+
+	do {
+		bcnvalid_reg = rtl_read_byte(rtlpriv, REG_TDECTRL + 2);
+		rtl_write_byte(rtlpriv, REG_TDECTRL + 2,
+			       (bcnvalid_reg | BIT(0)));
+		_rtl8821ae_return_beacon_queue_skb(hw);
+
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+			rtl8812ae_set_fw_rsvdpagepkt(hw, false,
+						     dl_whole_packets);
+		else
+			rtl8821ae_set_fw_rsvdpagepkt(hw, false,
+						     dl_whole_packets);
+
+		bcnvalid_reg = rtl_read_byte(rtlpriv, REG_TDECTRL + 2);
+		count = 0;
+		while (!(bcnvalid_reg & BIT(0)) && count < 20) {
+			count++;
+			udelay(10);
+			bcnvalid_reg = rtl_read_byte(rtlpriv, REG_TDECTRL + 2);
+		}
+		dlbcn_count++;
+	} while (!(bcnvalid_reg & BIT(0)) && dlbcn_count < 5);
+
+	if (!(bcnvalid_reg & BIT(0)))
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Download RSVD page failed!\n");
+	if (bcnvalid_reg & BIT(0) && rtlhal->enter_pnp_sleep) {
+		rtl_write_byte(rtlpriv, REG_TDECTRL + 2, bcnvalid_reg | BIT(0));
+		_rtl8821ae_return_beacon_queue_skb(hw);
+		if (send_beacon) {
+			dlbcn_count = 0;
+			do {
+				rtl_write_byte(rtlpriv, REG_TDECTRL + 2,
+					       bcnvalid_reg | BIT(0));
+
+				_rtl8821ae_return_beacon_queue_skb(hw);
+
+				if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+					rtl8812ae_set_fw_rsvdpagepkt(hw, true,
+								     false);
+				else
+					rtl8821ae_set_fw_rsvdpagepkt(hw, true,
+								     false);
+
+				/* check rsvd page download OK. */
+				bcnvalid_reg = rtl_read_byte(rtlpriv,
+							     REG_TDECTRL + 2);
+				count = 0;
+				while (!(bcnvalid_reg & BIT(0)) && count < 20) {
+					count++;
+					udelay(10);
+					bcnvalid_reg =
+					  rtl_read_byte(rtlpriv,
+							REG_TDECTRL + 2);
+				}
+				dlbcn_count++;
+			} while (!(bcnvalid_reg & BIT(0)) && dlbcn_count < 5);
+
+			if (!(bcnvalid_reg & BIT(0)))
+				RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+					 "2 Download RSVD page failed!\n");
+		}
+	}
+
+	if (bcnvalid_reg & BIT(0))
+		rtl_write_byte(rtlpriv, REG_TDECTRL + 2, BIT(0));
+
+	_rtl8821ae_set_bcn_ctrl_reg(hw, BIT(3), 0);
+	_rtl8821ae_set_bcn_ctrl_reg(hw, 0, BIT(4));
+
+	if (send_beacon)
+		rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp_reg422);
+
+	if (!rtlhal->enter_pnp_sleep) {
+		tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
+		rtl_write_byte(rtlpriv, REG_CR + 1, (tmp_regcr & ~(BIT(0))));
+	}
+}
+
+void rtl8821ae_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+	switch (variable) {
+	case HW_VAR_ETHER_ADDR:
+		*((u32 *)(val)) = rtl_read_dword(rtlpriv, REG_MACID);
+		*((u16 *)(val+4)) = rtl_read_word(rtlpriv, REG_MACID + 4);
+		break;
+	case HW_VAR_BSSID:
+		*((u32 *)(val)) = rtl_read_dword(rtlpriv, REG_BSSID);
+		*((u16 *)(val+4)) = rtl_read_word(rtlpriv, REG_BSSID+4);
+		break;
+	case HW_VAR_MEDIA_STATUS:
+		val[0] = rtl_read_byte(rtlpriv, REG_CR+2) & 0x3;
+		break;
+	case HW_VAR_SLOT_TIME:
+		*((u8 *)(val)) = mac->slot_time;
+		break;
+	case HW_VAR_BEACON_INTERVAL:
+		*((u16 *)(val)) = rtl_read_word(rtlpriv, REG_BCN_INTERVAL);
+		break;
+	case HW_VAR_ATIM_WINDOW:
+		*((u16 *)(val)) =  rtl_read_word(rtlpriv, REG_ATIMWND);
+		break;
+	case HW_VAR_RCR:
+		*((u32 *)(val)) = rtlpci->receive_config;
+		break;
+	case HW_VAR_RF_STATE:
+		*((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
+		break;
+	case HW_VAR_FWLPS_RF_ON:{
+		enum rf_pwrstate rfstate;
+		u32 val_rcr;
+
+		rtlpriv->cfg->ops->get_hw_reg(hw,
+					      HW_VAR_RF_STATE,
+					      (u8 *)(&rfstate));
+		if (rfstate == ERFOFF) {
+			*((bool *)(val)) = true;
+		} else {
+			val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+			val_rcr &= 0x00070000;
+			if (val_rcr)
+				*((bool *)(val)) = false;
+			else
+				*((bool *)(val)) = true;
+		}
+		break; }
+	case HW_VAR_FW_PSMODE_STATUS:
+		*((bool *)(val)) = ppsc->fw_current_inpsmode;
+		break;
+	case HW_VAR_CORRECT_TSF:{
+		u64 tsf;
+		u32 *ptsf_low = (u32 *)&tsf;
+		u32 *ptsf_high = ((u32 *)&tsf) + 1;
+
+		*ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4));
+		*ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+		*((u64 *)(val)) = tsf;
+
+		break; }
+	case HAL_DEF_WOWLAN:
+		if (ppsc->wo_wlan_mode)
+			*((bool *)(val)) = true;
+		else
+			*((bool *)(val)) = false;
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process %x\n", variable);
+		break;
+	}
+}
+
+void rtl8821ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 idx;
+
+	switch (variable) {
+	case HW_VAR_ETHER_ADDR:{
+			for (idx = 0; idx < ETH_ALEN; idx++) {
+				rtl_write_byte(rtlpriv, (REG_MACID + idx),
+					       val[idx]);
+			}
+			break;
+		}
+	case HW_VAR_BASIC_RATE:{
+			u16 b_rate_cfg = ((u16 *)val)[0];
+			b_rate_cfg = b_rate_cfg & 0x15f;
+			rtl_write_word(rtlpriv, REG_RRSR, b_rate_cfg);
+			break;
+		}
+	case HW_VAR_BSSID:{
+			for (idx = 0; idx < ETH_ALEN; idx++) {
+				rtl_write_byte(rtlpriv, (REG_BSSID + idx),
+					       val[idx]);
+			}
+			break;
+		}
+	case HW_VAR_SIFS:
+		rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]);
+		rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[0]);
+
+		rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]);
+		rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]);
+
+		rtl_write_byte(rtlpriv, REG_RESP_SIFS_OFDM + 1, val[0]);
+		rtl_write_byte(rtlpriv, REG_RESP_SIFS_OFDM, val[0]);
+		break;
+	case HW_VAR_R2T_SIFS:
+		rtl_write_byte(rtlpriv, REG_RESP_SIFS_OFDM + 1, val[0]);
+		break;
+	case HW_VAR_SLOT_TIME:{
+		u8 e_aci;
+
+		RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+			 "HW_VAR_SLOT_TIME %x\n", val[0]);
+
+		rtl_write_byte(rtlpriv, REG_SLOT, val[0]);
+
+		for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_AC_PARAM,
+						      (u8 *)(&e_aci));
+		}
+		break; }
+	case HW_VAR_ACK_PREAMBLE:{
+		u8 reg_tmp;
+		u8 short_preamble = (bool)(*(u8 *)val);
+
+		reg_tmp = rtl_read_byte(rtlpriv, REG_TRXPTCL_CTL+2);
+		if (short_preamble) {
+			reg_tmp |= BIT(1);
+			rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2,
+				       reg_tmp);
+		} else {
+			reg_tmp &= (~BIT(1));
+			rtl_write_byte(rtlpriv,
+				REG_TRXPTCL_CTL + 2,
+				reg_tmp);
+		}
+		break; }
+	case HW_VAR_WPA_CONFIG:
+		rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *)val));
+		break;
+	case HW_VAR_AMPDU_MIN_SPACE:{
+		u8 min_spacing_to_set;
+		u8 sec_min_space;
+
+		min_spacing_to_set = *((u8 *)val);
+		if (min_spacing_to_set <= 7) {
+			sec_min_space = 0;
+
+			if (min_spacing_to_set < sec_min_space)
+				min_spacing_to_set = sec_min_space;
+
+			mac->min_space_cfg = ((mac->min_space_cfg &
+					       0xf8) |
+					      min_spacing_to_set);
+
+			*val = min_spacing_to_set;
+
+			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+				 "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
+				  mac->min_space_cfg);
+
+			rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+				       mac->min_space_cfg);
+		}
+		break; }
+	case HW_VAR_SHORTGI_DENSITY:{
+		u8 density_to_set;
+
+		density_to_set = *((u8 *)val);
+		mac->min_space_cfg |= (density_to_set << 3);
+
+		RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+			 "Set HW_VAR_SHORTGI_DENSITY: %#x\n",
+			  mac->min_space_cfg);
+
+		rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+			       mac->min_space_cfg);
+
+		break; }
+	case HW_VAR_AMPDU_FACTOR:{
+		u32	ampdu_len =  (*((u8 *)val));
+
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+			if (ampdu_len < VHT_AGG_SIZE_128K)
+				ampdu_len =
+					(0x2000 << (*((u8 *)val))) - 1;
+			else
+				ampdu_len = 0x1ffff;
+		} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+			if (ampdu_len < HT_AGG_SIZE_64K)
+				ampdu_len =
+					(0x2000 << (*((u8 *)val))) - 1;
+			else
+				ampdu_len = 0xffff;
+		}
+		ampdu_len |= BIT(31);
+
+		rtl_write_dword(rtlpriv,
+			REG_AMPDU_MAX_LENGTH_8812, ampdu_len);
+		break; }
+	case HW_VAR_AC_PARAM:{
+		u8 e_aci = *((u8 *)val);
+
+		rtl8821ae_dm_init_edca_turbo(hw);
+		if (rtlpci->acm_method != EACMWAY2_SW)
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_ACM_CTRL,
+						      (u8 *)(&e_aci));
+		break; }
+	case HW_VAR_ACM_CTRL:{
+		u8 e_aci = *((u8 *)val);
+		union aci_aifsn *p_aci_aifsn =
+		    (union aci_aifsn *)(&mac->ac[0].aifs);
+		u8 acm = p_aci_aifsn->f.acm;
+		u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL);
+
+		acm_ctrl =
+		    acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1);
+
+		if (acm) {
+			switch (e_aci) {
+			case AC0_BE:
+				acm_ctrl |= ACMHW_BEQEN;
+				break;
+			case AC2_VI:
+				acm_ctrl |= ACMHW_VIQEN;
+				break;
+			case AC3_VO:
+				acm_ctrl |= ACMHW_VOQEN;
+				break;
+			default:
+				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+					 "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n",
+					 acm);
+				break;
+			}
+		} else {
+			switch (e_aci) {
+			case AC0_BE:
+				acm_ctrl &= (~ACMHW_BEQEN);
+				break;
+			case AC2_VI:
+				acm_ctrl &= (~ACMHW_VIQEN);
+				break;
+			case AC3_VO:
+				acm_ctrl &= (~ACMHW_BEQEN);
+				break;
+			default:
+				RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+					 "switch case not process\n");
+				break;
+			}
+		}
+
+		RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
+			 "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n",
+			 acm_ctrl);
+		rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl);
+		break; }
+	case HW_VAR_RCR:
+		rtl_write_dword(rtlpriv, REG_RCR, ((u32 *)(val))[0]);
+		rtlpci->receive_config = ((u32 *)(val))[0];
+		break;
+	case HW_VAR_RETRY_LIMIT:{
+		u8 retry_limit = ((u8 *)(val))[0];
+
+		rtl_write_word(rtlpriv, REG_RL,
+			       retry_limit << RETRY_LIMIT_SHORT_SHIFT |
+			       retry_limit << RETRY_LIMIT_LONG_SHIFT);
+		break; }
+	case HW_VAR_DUAL_TSF_RST:
+		rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1)));
+		break;
+	case HW_VAR_EFUSE_BYTES:
+		rtlefuse->efuse_usedbytes = *((u16 *)val);
+		break;
+	case HW_VAR_EFUSE_USAGE:
+		rtlefuse->efuse_usedpercentage = *((u8 *)val);
+		break;
+	case HW_VAR_IO_CMD:
+		rtl8821ae_phy_set_io_cmd(hw, (*(enum io_type *)val));
+		break;
+	case HW_VAR_SET_RPWM:{
+		u8 rpwm_val;
+
+		rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM);
+		udelay(1);
+
+		if (rpwm_val & BIT(7)) {
+			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+				       (*(u8 *)val));
+		} else {
+			rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+				       ((*(u8 *)val) | BIT(7)));
+		}
+
+		break; }
+	case HW_VAR_H2C_FW_PWRMODE:
+		rtl8821ae_set_fw_pwrmode_cmd(hw, (*(u8 *)val));
+		break;
+	case HW_VAR_FW_PSMODE_STATUS:
+		ppsc->fw_current_inpsmode = *((bool *)val);
+		break;
+	case HW_VAR_INIT_RTS_RATE:
+		break;
+	case HW_VAR_RESUME_CLK_ON:
+		_rtl8821ae_set_fw_ps_rf_on(hw);
+		break;
+	case HW_VAR_FW_LPS_ACTION:{
+		bool b_enter_fwlps = *((bool *)val);
+
+		if (b_enter_fwlps)
+			_rtl8821ae_fwlps_enter(hw);
+		 else
+			_rtl8821ae_fwlps_leave(hw);
+		 break; }
+	case HW_VAR_H2C_FW_JOINBSSRPT:{
+		u8 mstatus = (*(u8 *)val);
+
+		if (mstatus == RT_MEDIA_CONNECT) {
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID,
+						      NULL);
+			_rtl8821ae_download_rsvd_page(hw, false);
+		}
+		rtl8821ae_set_fw_media_status_rpt_cmd(hw, mstatus);
+
+		break; }
+	case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+		rtl8821ae_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+		break;
+	case HW_VAR_AID:{
+		u16 u2btmp;
+		u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
+		u2btmp &= 0xC000;
+		rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, (u2btmp |
+			       mac->assoc_id));
+		break; }
+	case HW_VAR_CORRECT_TSF:{
+		u8 btype_ibss = ((u8 *)(val))[0];
+
+		if (btype_ibss)
+			_rtl8821ae_stop_tx_beacon(hw);
+
+		_rtl8821ae_set_bcn_ctrl_reg(hw, 0, BIT(3));
+
+		rtl_write_dword(rtlpriv, REG_TSFTR,
+				(u32)(mac->tsf & 0xffffffff));
+		rtl_write_dword(rtlpriv, REG_TSFTR + 4,
+				(u32)((mac->tsf >> 32) & 0xffffffff));
+
+		_rtl8821ae_set_bcn_ctrl_reg(hw, BIT(3), 0);
+
+		if (btype_ibss)
+			_rtl8821ae_resume_tx_beacon(hw);
+		break; }
+	case HW_VAR_NAV_UPPER: {
+		u32	us_nav_upper = ((u32)*val);
+
+		if (us_nav_upper > HAL_92C_NAV_UPPER_UNIT * 0xFF) {
+			RT_TRACE(rtlpriv, COMP_INIT , DBG_WARNING,
+				 "The setting value (0x%08X us) of NAV_UPPER is larger than (%d * 0xFF)!!!\n",
+				 us_nav_upper, HAL_92C_NAV_UPPER_UNIT);
+			break;
+		}
+		rtl_write_byte(rtlpriv, REG_NAV_UPPER,
+			       ((u8)((us_nav_upper +
+				HAL_92C_NAV_UPPER_UNIT - 1) /
+				HAL_92C_NAV_UPPER_UNIT)));
+		break; }
+	case HW_VAR_KEEP_ALIVE: {
+		u8 array[2];
+		array[0] = 0xff;
+		array[1] = *((u8 *)val);
+		rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_KEEP_ALIVE_CTRL, 2,
+				       array);
+		break; }
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process %x\n", variable);
+		break;
+	}
+}
+
+static bool _rtl8821ae_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	bool status = true;
+	long count = 0;
+	u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) |
+		    _LLT_OP(_LLT_WRITE_ACCESS);
+
+	rtl_write_dword(rtlpriv, REG_LLT_INIT, value);
+
+	do {
+		value = rtl_read_dword(rtlpriv, REG_LLT_INIT);
+		if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value))
+			break;
+
+		if (count > POLLING_LLT_THRESHOLD) {
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "Failed to polling write LLT done at address %d!\n",
+				 address);
+			status = false;
+			break;
+		}
+	} while (++count);
+
+	return status;
+}
+
+static bool _rtl8821ae_llt_table_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	unsigned short i;
+	u8 txpktbuf_bndy;
+	u32 rqpn;
+	u8 maxpage;
+	bool status;
+
+	maxpage = 255;
+	txpktbuf_bndy = 0xF8;
+	rqpn = 0x80e70808;
+	if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE) {
+		txpktbuf_bndy = 0xFA;
+		rqpn = 0x80e90808;
+	}
+
+	rtl_write_byte(rtlpriv, REG_TRXFF_BNDY, txpktbuf_bndy);
+	rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, MAX_RX_DMA_BUFFER_SIZE - 1);
+
+	rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy);
+
+	rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy);
+	rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy);
+
+	rtl_write_byte(rtlpriv, REG_PBP, 0x31);
+	rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4);
+
+	for (i = 0; i < (txpktbuf_bndy - 1); i++) {
+		status = _rtl8821ae_llt_write(hw, i, i + 1);
+		if (!status)
+			return status;
+	}
+
+	status = _rtl8821ae_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
+	if (!status)
+		return status;
+
+	for (i = txpktbuf_bndy; i < maxpage; i++) {
+		status = _rtl8821ae_llt_write(hw, i, (i + 1));
+		if (!status)
+			return status;
+	}
+
+	status = _rtl8821ae_llt_write(hw, maxpage, txpktbuf_bndy);
+	if (!status)
+		return status;
+
+	rtl_write_dword(rtlpriv, REG_RQPN, rqpn);
+
+	rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x00);
+
+	return true;
+}
+
+static void _rtl8821ae_gen_refresh_led_state(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_led *pled0 = &pcipriv->ledctl.sw_led0;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+	if (rtlpriv->rtlhal.up_first_time)
+		return;
+
+	if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS)
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+			rtl8812ae_sw_led_on(hw, pled0);
+		else
+			rtl8821ae_sw_led_on(hw, pled0);
+	else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT)
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+			rtl8812ae_sw_led_on(hw, pled0);
+		else
+			rtl8821ae_sw_led_on(hw, pled0);
+	else
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+			rtl8812ae_sw_led_off(hw, pled0);
+		else
+			rtl8821ae_sw_led_off(hw, pled0);
+}
+
+static bool _rtl8821ae_init_mac(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+	u8 bytetmp = 0;
+	u16 wordtmp = 0;
+	bool mac_func_enable = rtlhal->mac_func_enable;
+
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00);
+
+	/*Auto Power Down to CHIP-off State*/
+	bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) & (~BIT(7));
+	rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp);
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+		/* HW Power on sequence*/
+		if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK,
+					      PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,
+					      RTL8812_NIC_ENABLE_FLOW)) {
+				RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+					 "init 8812 MAC Fail as power on failure\n");
+				return false;
+		}
+	} else {
+		/* HW Power on sequence */
+		if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_A_MSK,
+					      PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,
+					      RTL8821A_NIC_ENABLE_FLOW)){
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				"init 8821 MAC Fail as power on failure\n");
+			return false;
+		}
+	}
+
+	bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO) | BIT(4);
+	rtl_write_byte(rtlpriv, REG_APS_FSMCO, bytetmp);
+
+	bytetmp = rtl_read_byte(rtlpriv, REG_CR);
+	bytetmp = 0xff;
+	rtl_write_byte(rtlpriv, REG_CR, bytetmp);
+	mdelay(2);
+
+	bytetmp = 0xff;
+	rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, bytetmp);
+	mdelay(2);
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+		bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CFG + 3);
+		if (bytetmp & BIT(0)) {
+			bytetmp = rtl_read_byte(rtlpriv, 0x7c);
+			bytetmp |= BIT(6);
+			rtl_write_byte(rtlpriv, 0x7c, bytetmp);
+		}
+	}
+
+	bytetmp = rtl_read_byte(rtlpriv, REG_GPIO_MUXCFG + 1);
+	bytetmp &= ~BIT(4);
+	rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG + 1, bytetmp);
+
+	rtl_write_word(rtlpriv, REG_CR, 0x2ff);
+
+	if (!mac_func_enable) {
+		if (!_rtl8821ae_llt_table_init(hw))
+			return false;
+	}
+
+	rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff);
+	rtl_write_dword(rtlpriv, REG_HISRE, 0xffffffff);
+
+	/* Enable FW Beamformer Interrupt */
+	bytetmp = rtl_read_byte(rtlpriv, REG_FWIMR + 3);
+	rtl_write_byte(rtlpriv, REG_FWIMR + 3, bytetmp | BIT(6));
+
+	wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL);
+	wordtmp &= 0xf;
+	wordtmp |= 0xF5B1;
+	rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp);
+
+	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F);
+	rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+	rtl_write_word(rtlpriv, REG_RXFLTMAP2, 0xFFFF);
+	/*low address*/
+	rtl_write_dword(rtlpriv, REG_BCNQ_DESA,
+			rtlpci->tx_ring[BEACON_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_MGQ_DESA,
+			rtlpci->tx_ring[MGNT_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_VOQ_DESA,
+			rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_VIQ_DESA,
+			rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_BEQ_DESA,
+			rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_BKQ_DESA,
+			rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_HQ_DESA,
+			rtlpci->tx_ring[HIGH_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_RX_DESA,
+			rtlpci->rx_ring[RX_MPDU_QUEUE].dma & DMA_BIT_MASK(32));
+
+	rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, 0x77);
+
+	rtl_write_dword(rtlpriv, REG_INT_MIG, 0);
+
+	rtl_write_dword(rtlpriv, REG_MCUTST_1, 0);
+
+	rtl_write_byte(rtlpriv, REG_SECONDARY_CCA_CTRL, 0x3);
+	_rtl8821ae_gen_refresh_led_state(hw);
+
+	return true;
+}
+
+static void _rtl8821ae_hw_configure(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u32 reg_rrsr;
+
+	reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
+
+	rtl_write_dword(rtlpriv, REG_RRSR, reg_rrsr);
+	/* ARFB table 9 for 11ac 5G 2SS */
+	rtl_write_dword(rtlpriv, REG_ARFR0 + 4, 0xfffff000);
+	/* ARFB table 10 for 11ac 5G 1SS */
+	rtl_write_dword(rtlpriv, REG_ARFR1 + 4, 0x003ff000);
+	/* ARFB table 11 for 11ac 24G 1SS */
+	rtl_write_dword(rtlpriv, REG_ARFR2, 0x00000015);
+	rtl_write_dword(rtlpriv, REG_ARFR2 + 4, 0x003ff000);
+	/* ARFB table 12 for 11ac 24G 1SS */
+	rtl_write_dword(rtlpriv, REG_ARFR3, 0x00000015);
+	rtl_write_dword(rtlpriv, REG_ARFR3 + 4, 0xffcff000);
+	/* 0x420[7] = 0 , enable retry AMPDU in new AMPD not singal MPDU. */
+	rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F00);
+	rtl_write_byte(rtlpriv, REG_AMPDU_MAX_TIME, 0x70);
+
+	/*Set retry limit*/
+	rtl_write_word(rtlpriv, REG_RL, 0x0707);
+
+	/* Set Data / Response auto rate fallack retry count*/
+	rtl_write_dword(rtlpriv, REG_DARFRC, 0x01000000);
+	rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x07060504);
+	rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000);
+	rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504);
+
+	rtlpci->reg_bcn_ctrl_val = 0x1d;
+	rtl_write_byte(rtlpriv, REG_BCN_CTRL, rtlpci->reg_bcn_ctrl_val);
+
+	/* TBTT prohibit hold time. Suggested by designer TimChen. */
+	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+
+	/* AGGR_BK_TIME Reg51A 0x16 */
+	rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0040);
+
+	/*For Rx TP. Suggested by SD1 Richard. Added by tynli. 2010.04.12.*/
+	rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666);
+
+	rtl_write_byte(rtlpriv, REG_HT_SINGLE_AMPDU, 0x80);
+	rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x20);
+	rtl_write_word(rtlpriv, REG_MAX_AGGR_NUM, 0x1F1F);
+}
+
+static u16 _rtl8821ae_mdio_read(struct rtl_priv *rtlpriv, u8 addr)
+{
+	u16 ret = 0;
+	u8 tmp = 0, count = 0;
+
+	rtl_write_byte(rtlpriv, REG_MDIO_CTL, addr | BIT(6));
+	tmp = rtl_read_byte(rtlpriv, REG_MDIO_CTL) & BIT(6);
+	count = 0;
+	while (tmp && count < 20) {
+		udelay(10);
+		tmp = rtl_read_byte(rtlpriv, REG_MDIO_CTL) & BIT(6);
+		count++;
+	}
+	if (0 == tmp)
+		ret = rtl_read_word(rtlpriv, REG_MDIO_RDATA);
+
+	return ret;
+}
+
+static void _rtl8821ae_mdio_write(struct rtl_priv *rtlpriv, u8 addr, u16 data)
+{
+	u8 tmp = 0, count = 0;
+
+	rtl_write_word(rtlpriv, REG_MDIO_WDATA, data);
+	rtl_write_byte(rtlpriv, REG_MDIO_CTL, addr | BIT(5));
+	tmp = rtl_read_byte(rtlpriv, REG_MDIO_CTL) & BIT(5);
+	count = 0;
+	while (tmp && count < 20) {
+		udelay(10);
+		tmp = rtl_read_byte(rtlpriv, REG_MDIO_CTL) & BIT(5);
+		count++;
+	}
+}
+
+static u8 _rtl8821ae_dbi_read(struct rtl_priv *rtlpriv, u16 addr)
+{
+	u16 read_addr = addr & 0xfffc;
+	u8 tmp = 0, count = 0, ret = 0;
+
+	rtl_write_word(rtlpriv, REG_DBI_ADDR, read_addr);
+	rtl_write_byte(rtlpriv, REG_DBI_FLAG, 0x2);
+	tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG);
+	count = 0;
+	while (tmp && count < 20) {
+		udelay(10);
+		tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG);
+		count++;
+	}
+	if (0 == tmp) {
+		read_addr = REG_DBI_RDATA + addr % 4;
+		ret = rtl_read_word(rtlpriv, read_addr);
+	}
+	return ret;
+}
+
+static void _rtl8821ae_dbi_write(struct rtl_priv *rtlpriv, u16 addr, u8 data)
+{
+	u8 tmp = 0, count = 0;
+	u16 wrtie_addr, remainder = addr % 4;
+
+	wrtie_addr = REG_DBI_WDATA + remainder;
+	rtl_write_byte(rtlpriv, wrtie_addr, data);
+
+	wrtie_addr = (addr & 0xfffc) | (BIT(0) << (remainder + 12));
+	rtl_write_word(rtlpriv, REG_DBI_ADDR, wrtie_addr);
+
+	rtl_write_byte(rtlpriv, REG_DBI_FLAG, 0x1);
+
+	tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG);
+	count = 0;
+	while (tmp && count < 20) {
+		udelay(10);
+		tmp = rtl_read_byte(rtlpriv, REG_DBI_FLAG);
+		count++;
+	}
+}
+
+static void _rtl8821ae_enable_aspm_back_door(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 tmp;
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+		if (_rtl8821ae_mdio_read(rtlpriv, 0x04) != 0x8544)
+			_rtl8821ae_mdio_write(rtlpriv, 0x04, 0x8544);
+
+		if (_rtl8821ae_mdio_read(rtlpriv, 0x0b) != 0x0070)
+			_rtl8821ae_mdio_write(rtlpriv, 0x0b, 0x0070);
+	}
+
+	tmp = _rtl8821ae_dbi_read(rtlpriv, 0x70f);
+	_rtl8821ae_dbi_write(rtlpriv, 0x70f, tmp | BIT(7));
+
+	tmp = _rtl8821ae_dbi_read(rtlpriv, 0x719);
+	_rtl8821ae_dbi_write(rtlpriv, 0x719, tmp | BIT(3) | BIT(4));
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+		tmp  = _rtl8821ae_dbi_read(rtlpriv, 0x718);
+		_rtl8821ae_dbi_write(rtlpriv, 0x718, tmp|BIT(4));
+	}
+}
+
+void rtl8821ae_enable_hw_security_config(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 sec_reg_value;
+	u8 tmp;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		 "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n",
+		  rtlpriv->sec.pairwise_enc_algorithm,
+		  rtlpriv->sec.group_enc_algorithm);
+
+	if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
+		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+			 "not open hw encryption\n");
+		return;
+	}
+
+	sec_reg_value = SCR_TXENCENABLE | SCR_RXDECENABLE;
+
+	if (rtlpriv->sec.use_defaultkey) {
+		sec_reg_value |= SCR_TXUSEDK;
+		sec_reg_value |= SCR_RXUSEDK;
+	}
+
+	sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK);
+
+	tmp = rtl_read_byte(rtlpriv, REG_CR + 1);
+	rtl_write_byte(rtlpriv, REG_CR + 1, tmp | BIT(1));
+
+	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+		 "The SECR-value %x\n", sec_reg_value);
+
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
+}
+
+/* Static MacID Mapping (cf. Used in MacIdDoStaticMapping) ---------- */
+#define MAC_ID_STATIC_FOR_DEFAULT_PORT				0
+#define MAC_ID_STATIC_FOR_BROADCAST_MULTICAST		1
+#define MAC_ID_STATIC_FOR_BT_CLIENT_START				2
+#define MAC_ID_STATIC_FOR_BT_CLIENT_END				3
+/* ----------------------------------------------------------- */
+
+static void rtl8821ae_macid_initialize_mediastatus(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8	media_rpt[4] = {RT_MEDIA_CONNECT, 1,
+		MAC_ID_STATIC_FOR_BROADCAST_MULTICAST,
+		MAC_ID_STATIC_FOR_BT_CLIENT_END};
+
+	rtlpriv->cfg->ops->set_hw_reg(hw,
+		HW_VAR_H2C_FW_MEDIASTATUSRPT, media_rpt);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "Initialize MacId media status: from %d to %d\n",
+		 MAC_ID_STATIC_FOR_BROADCAST_MULTICAST,
+		 MAC_ID_STATIC_FOR_BT_CLIENT_END);
+}
+
+static bool _rtl8821ae_check_pcie_dma_hang(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 tmp;
+
+	/* write reg 0x350 Bit[26]=1. Enable debug port. */
+	tmp = rtl_read_byte(rtlpriv, REG_DBI_CTRL + 3);
+	if (!(tmp & BIT(2))) {
+		rtl_write_byte(rtlpriv, REG_DBI_CTRL + 3, (tmp | BIT(2)));
+		mdelay(100);
+	}
+
+	/* read reg 0x350 Bit[25] if 1 : RX hang */
+	/* read reg 0x350 Bit[24] if 1 : TX hang */
+	tmp = rtl_read_byte(rtlpriv, REG_DBI_CTRL + 3);
+	if ((tmp & BIT(0)) || (tmp & BIT(1))) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "CheckPcieDMAHang8821AE(): true! Reset PCIE DMA!\n");
+		return true;
+	} else {
+		return false;
+	}
+}
+
+static bool _rtl8821ae_reset_pcie_interface_dma(struct ieee80211_hw *hw,
+					 bool mac_power_on,
+					 bool in_watchdog)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 tmp;
+	bool release_mac_rx_pause;
+	u8 backup_pcie_dma_pause;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+
+	/* 1. Disable register write lock. 0x1c[1] = 0 */
+	tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL);
+	tmp &= ~(BIT(1));
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL, tmp);
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+		/* write 0xCC bit[2] = 1'b1 */
+		tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2);
+		tmp |= BIT(2);
+		rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp);
+	}
+
+	/* 2. Check and pause TRX DMA */
+	/* write 0x284 bit[18] = 1'b1 */
+	/* write 0x301 = 0xFF */
+	tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+	if (tmp & BIT(2)) {
+		/* Already pause before the function for another purpose. */
+		release_mac_rx_pause = false;
+	} else {
+		rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, (tmp | BIT(2)));
+		release_mac_rx_pause = true;
+	}
+	backup_pcie_dma_pause = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 1);
+	if (backup_pcie_dma_pause != 0xFF)
+		rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xFF);
+
+	if (mac_power_on) {
+		/* 3. reset TRX function */
+		/* write 0x100 = 0x00 */
+		rtl_write_byte(rtlpriv, REG_CR, 0);
+	}
+
+	/* 4. Reset PCIe DMA. 0x3[0] = 0 */
+	tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+	tmp &= ~(BIT(0));
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp);
+
+	/* 5. Enable PCIe DMA. 0x3[0] = 1 */
+	tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+	tmp |= BIT(0);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp);
+
+	if (mac_power_on) {
+		/* 6. enable TRX function */
+		/* write 0x100 = 0xFF */
+		rtl_write_byte(rtlpriv, REG_CR, 0xFF);
+
+		/* We should init LLT & RQPN and
+		 * prepare Tx/Rx descrptor address later
+		 * because MAC function is reset.*/
+	}
+
+	/* 7. Restore PCIe autoload down bit */
+	/* 8812AE does not has the defination. */
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+		/* write 0xF8 bit[17] = 1'b1 */
+		tmp = rtl_read_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2);
+		tmp |= BIT(1);
+		rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2, tmp);
+	}
+
+	/* In MAC power on state, BB and RF maybe in ON state,
+	 * if we release TRx DMA here.
+	 * it will cause packets to be started to Tx/Rx,
+	 * so we release Tx/Rx DMA later.*/
+	if (!mac_power_on/* || in_watchdog*/) {
+		/* 8. release TRX DMA */
+		/* write 0x284 bit[18] = 1'b0 */
+		/* write 0x301 = 0x00 */
+		if (release_mac_rx_pause) {
+			tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+			rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL,
+				       tmp & (~BIT(2)));
+		}
+		rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1,
+			       backup_pcie_dma_pause);
+	}
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+		/* 9. lock system register */
+		/* write 0xCC bit[2] = 1'b0 */
+		tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2);
+		tmp &= ~(BIT(2));
+		rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp);
+	}
+	return true;
+}
+
+static void _rtl8821ae_get_wakeup_reason(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
+	u8 fw_reason = 0;
+	struct timeval ts;
+
+	fw_reason = rtl_read_byte(rtlpriv, REG_MCUTST_WOWLAN);
+
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "WOL Read 0x1c7 = %02X\n",
+		 fw_reason);
+
+	ppsc->wakeup_reason = 0;
+
+	rtlhal->last_suspend_sec = ts.tv_sec;
+
+	switch (fw_reason) {
+	case FW_WOW_V2_PTK_UPDATE_EVENT:
+		ppsc->wakeup_reason = WOL_REASON_PTK_UPDATE;
+		do_gettimeofday(&ts);
+		ppsc->last_wakeup_time = ts.tv_sec*1000 + ts.tv_usec/1000;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+			 "It's a WOL PTK Key update event!\n");
+		break;
+	case FW_WOW_V2_GTK_UPDATE_EVENT:
+		ppsc->wakeup_reason = WOL_REASON_GTK_UPDATE;
+		do_gettimeofday(&ts);
+		ppsc->last_wakeup_time = ts.tv_sec*1000 + ts.tv_usec/1000;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+			 "It's a WOL GTK Key update event!\n");
+		break;
+	case FW_WOW_V2_DISASSOC_EVENT:
+		ppsc->wakeup_reason = WOL_REASON_DISASSOC;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+			 "It's a disassociation event!\n");
+		break;
+	case FW_WOW_V2_DEAUTH_EVENT:
+		ppsc->wakeup_reason = WOL_REASON_DEAUTH;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+			 "It's a deauth event!\n");
+		break;
+	case FW_WOW_V2_FW_DISCONNECT_EVENT:
+		ppsc->wakeup_reason = WOL_REASON_AP_LOST;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+			 "It's a Fw disconnect decision (AP lost) event!\n");
+	break;
+	case FW_WOW_V2_MAGIC_PKT_EVENT:
+		ppsc->wakeup_reason = WOL_REASON_MAGIC_PKT;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+			 "It's a magic packet event!\n");
+		break;
+	case FW_WOW_V2_UNICAST_PKT_EVENT:
+		ppsc->wakeup_reason = WOL_REASON_UNICAST_PKT;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+			 "It's an unicast packet event!\n");
+		break;
+	case FW_WOW_V2_PATTERN_PKT_EVENT:
+		ppsc->wakeup_reason = WOL_REASON_PATTERN_PKT;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+			 "It's a pattern match event!\n");
+		break;
+	case FW_WOW_V2_RTD3_SSID_MATCH_EVENT:
+		ppsc->wakeup_reason = WOL_REASON_RTD3_SSID_MATCH;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+			 "It's an RTD3 Ssid match event!\n");
+		break;
+	case FW_WOW_V2_REALWOW_V2_WAKEUPPKT:
+		ppsc->wakeup_reason = WOL_REASON_REALWOW_V2_WAKEUPPKT;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+			 "It's an RealWoW wake packet event!\n");
+		break;
+	case FW_WOW_V2_REALWOW_V2_ACKLOST:
+		ppsc->wakeup_reason = WOL_REASON_REALWOW_V2_ACKLOST;
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+			 "It's an RealWoW ack lost event!\n");
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+			 "WOL Read 0x1c7 = %02X, Unknown reason!\n",
+			  fw_reason);
+		break;
+	}
+}
+
+static void _rtl8821ae_init_trx_desc_hw_address(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	/*low address*/
+	rtl_write_dword(rtlpriv, REG_BCNQ_DESA,
+			rtlpci->tx_ring[BEACON_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_MGQ_DESA,
+			rtlpci->tx_ring[MGNT_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_VOQ_DESA,
+			rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_VIQ_DESA,
+			rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_BEQ_DESA,
+			rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_BKQ_DESA,
+			rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_HQ_DESA,
+			rtlpci->tx_ring[HIGH_QUEUE].dma & DMA_BIT_MASK(32));
+	rtl_write_dword(rtlpriv, REG_RX_DESA,
+			rtlpci->rx_ring[RX_MPDU_QUEUE].dma & DMA_BIT_MASK(32));
+}
+
+static bool _rtl8821ae_init_llt_table(struct ieee80211_hw *hw, u32 boundary)
+{
+	bool status = true;
+	u32 i;
+	u32 txpktbuf_bndy = boundary;
+	u32 last_entry_of_txpktbuf = LAST_ENTRY_OF_TX_PKT_BUFFER;
+
+	for (i = 0 ; i < (txpktbuf_bndy - 1) ; i++) {
+		status = _rtl8821ae_llt_write(hw, i , i + 1);
+		if (!status)
+			return status;
+	}
+
+	status = _rtl8821ae_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
+	if (!status)
+		return status;
+
+	for (i = txpktbuf_bndy ; i < last_entry_of_txpktbuf ; i++) {
+		status = _rtl8821ae_llt_write(hw, i, (i + 1));
+		if (!status)
+			return status;
+	}
+
+	status = _rtl8821ae_llt_write(hw, last_entry_of_txpktbuf,
+				      txpktbuf_bndy);
+	if (!status)
+		return status;
+
+	return status;
+}
+
+static bool _rtl8821ae_dynamic_rqpn(struct ieee80211_hw *hw, u32 boundary,
+			     u16 npq_rqpn_value, u32 rqpn_val)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 tmp;
+	bool ret = true;
+	u16 count = 0, tmp16;
+	bool support_remote_wakeup;
+
+	rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+				      (u8 *)(&support_remote_wakeup));
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "boundary=0x%#X, NPQ_RQPNValue=0x%#X, RQPNValue=0x%#X\n",
+		  boundary, npq_rqpn_value, rqpn_val);
+
+	/* stop PCIe DMA
+	 * 1. 0x301[7:0] = 0xFE */
+	rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xFE);
+
+	/* wait TXFF empty
+	 * 2. polling till 0x41A[15:0]=0x07FF */
+	tmp16 = rtl_read_word(rtlpriv, REG_TXPKT_EMPTY);
+	while ((tmp16 & 0x07FF) != 0x07FF) {
+		udelay(100);
+		tmp16 = rtl_read_word(rtlpriv, REG_TXPKT_EMPTY);
+		count++;
+		if ((count % 200) == 0) {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "Tx queue is not empty for 20ms!\n");
+		}
+		if (count >= 1000) {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "Wait for Tx FIFO empty timeout!\n");
+			break;
+		}
+	}
+
+	/* TX pause
+	 * 3. reg 0x522=0xFF */
+	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+
+	/* Wait TX State Machine OK
+	 * 4. polling till reg 0x5FB~0x5F8 = 0x00000000 for 50ms */
+	count = 0;
+	while (rtl_read_byte(rtlpriv, REG_SCH_TXCMD) != 0) {
+		udelay(100);
+		count++;
+		if (count >= 500) {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "Wait for TX State Machine ready timeout !!\n");
+			break;
+		}
+	}
+
+	/* stop RX DMA path
+	 * 5.	0x284[18] = 1
+	 * 6.	wait till 0x284[17] == 1
+	 * wait RX DMA idle */
+	count = 0;
+	tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+	rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, (tmp | BIT(2)));
+	do {
+		tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+		udelay(10);
+		count++;
+	} while (!(tmp & BIT(1)) && count < 100);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "Wait until Rx DMA Idle. count=%d REG[0x286]=0x%x\n",
+		  count, tmp);
+
+	/* reset BB
+	 * 7.	0x02 [0] = 0 */
+	tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN);
+	tmp &= ~(BIT(0));
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, tmp);
+
+	/* Reset TRX MAC
+	 * 8.	 0x100 = 0x00
+	 * Delay (1ms) */
+	rtl_write_byte(rtlpriv, REG_CR, 0x00);
+	udelay(1000);
+
+	/* Disable MAC Security Engine
+	 * 9.	0x100 bit[9]=0 */
+	tmp = rtl_read_byte(rtlpriv, REG_CR + 1);
+	tmp &= ~(BIT(1));
+	rtl_write_byte(rtlpriv, REG_CR + 1, tmp);
+
+	/* To avoid DD-Tim Circuit hang
+	 * 10.	0x553 bit[5]=1 */
+	tmp = rtl_read_byte(rtlpriv, REG_DUAL_TSF_RST);
+	rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (tmp | BIT(5)));
+
+	/* Enable MAC Security Engine
+	 * 11.	0x100 bit[9]=1 */
+	tmp = rtl_read_byte(rtlpriv, REG_CR + 1);
+	rtl_write_byte(rtlpriv, REG_CR + 1, (tmp | BIT(1)));
+
+	/* Enable TRX MAC
+	 * 12.	 0x100 = 0xFF
+	 *	Delay (1ms) */
+	rtl_write_byte(rtlpriv, REG_CR, 0xFF);
+	udelay(1000);
+
+	/* Enable BB
+	 * 13.	0x02 [0] = 1 */
+	tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, (tmp | BIT(0)));
+
+	/* beacon setting
+	 * 14,15. set beacon head page (reg 0x209 and 0x424) */
+	rtl_write_byte(rtlpriv, REG_TDECTRL + 1, (u8)boundary);
+	rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, (u8)boundary);
+	rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, (u8)boundary);
+
+	/* 16.	WMAC_LBK_BF_HD 0x45D[7:0]
+	 * WMAC_LBK_BF_HD */
+	rtl_write_byte(rtlpriv, REG_TXPKTBUF_WMAC_LBK_BF_HD,
+		       (u8)boundary);
+
+	rtl_write_word(rtlpriv, REG_TRXFF_BNDY, boundary);
+
+	/* init LLT
+	 * 17. init LLT */
+	if (!_rtl8821ae_init_llt_table(hw, boundary)) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING,
+			 "Failed to init LLT table!\n");
+		return false;
+	}
+
+	/* reallocate RQPN
+	 * 18. reallocate RQPN and init LLT */
+	rtl_write_word(rtlpriv, REG_RQPN_NPQ, npq_rqpn_value);
+	rtl_write_dword(rtlpriv, REG_RQPN, rqpn_val);
+
+	/* release Tx pause
+	 * 19. 0x522=0x00 */
+	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+
+	/* enable PCIE DMA
+	 * 20. 0x301[7:0] = 0x00
+	 * 21. 0x284[18] = 0 */
+	rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0x00);
+	tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+	rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, (tmp&~BIT(2)));
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "End.\n");
+	return ret;
+}
+
+static void _rtl8821ae_simple_initialize_adapter(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
+
+#if (USE_SPECIFIC_FW_TO_SUPPORT_WOWLAN == 1)
+	/* Re-download normal Fw. */
+	rtl8821ae_set_fw_related_for_wowlan(hw, false);
+#endif
+
+	/* Re-Initialize LLT table. */
+	if (rtlhal->re_init_llt_table) {
+		u32 rqpn = 0x80e70808;
+		u8 rqpn_npq = 0, boundary = 0xF8;
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+			rqpn = 0x80e90808;
+			boundary = 0xFA;
+		}
+		if (_rtl8821ae_dynamic_rqpn(hw, boundary, rqpn_npq, rqpn))
+			rtlhal->re_init_llt_table = false;
+	}
+
+	ppsc->rfpwr_state = ERFON;
+}
+
+static void _rtl8821ae_enable_l1off(struct ieee80211_hw *hw)
+{
+	u8 tmp  = 0;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "--->\n");
+
+	tmp = _rtl8821ae_dbi_read(rtlpriv, 0x160);
+	if (!(tmp & (BIT(2) | BIT(3)))) {
+		RT_TRACE(rtlpriv, COMP_POWER | COMP_INIT, DBG_LOUD,
+			 "0x160(%#x)return!!\n", tmp);
+		return;
+	}
+
+	tmp = _rtl8821ae_mdio_read(rtlpriv, 0x1b);
+	_rtl8821ae_mdio_write(rtlpriv, 0x1b, (tmp | BIT(4)));
+
+	tmp = _rtl8821ae_dbi_read(rtlpriv, 0x718);
+	_rtl8821ae_dbi_write(rtlpriv, 0x718, tmp | BIT(5));
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "<---\n");
+}
+
+static void _rtl8821ae_enable_ltr(struct ieee80211_hw *hw)
+{
+	u8 tmp  = 0;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "--->\n");
+
+	/* Check 0x98[10] */
+	tmp = _rtl8821ae_dbi_read(rtlpriv, 0x99);
+	if (!(tmp & BIT(2))) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "<---0x99(%#x) return!!\n", tmp);
+		return;
+	}
+
+	/* LTR idle latency, 0x90 for 144us */
+	rtl_write_dword(rtlpriv, 0x798, 0x88908890);
+
+	/* LTR active latency, 0x3c for 60us */
+	rtl_write_dword(rtlpriv, 0x79c, 0x883c883c);
+
+	tmp = rtl_read_byte(rtlpriv, 0x7a4);
+	rtl_write_byte(rtlpriv, 0x7a4, (tmp | BIT(4)));
+
+	tmp = rtl_read_byte(rtlpriv, 0x7a4);
+	rtl_write_byte(rtlpriv, 0x7a4, (tmp & (~BIT(0))));
+	rtl_write_byte(rtlpriv, 0x7a4, (tmp | BIT(0)));
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "<---\n");
+}
+
+static bool _rtl8821ae_wowlan_initialize_adapter(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	bool init_finished = true;
+	u8 tmp = 0;
+
+	/* Get Fw wake up reason. */
+	_rtl8821ae_get_wakeup_reason(hw);
+
+	/* Patch Pcie Rx DMA hang after S3/S4 several times.
+	 * The root cause has not be found. */
+	if (_rtl8821ae_check_pcie_dma_hang(hw))
+		_rtl8821ae_reset_pcie_interface_dma(hw, true, false);
+
+	/* Prepare Tx/Rx Desc Hw address. */
+	_rtl8821ae_init_trx_desc_hw_address(hw);
+
+	/* Release Pcie Interface Rx DMA to allow wake packet DMA. */
+	rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xFE);
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Enable PCIE Rx DMA.\n");
+
+	/* Check wake up event.
+	 * We should check wake packet bit before disable wowlan by H2C or
+	 * Fw will clear the bit. */
+	tmp = rtl_read_byte(rtlpriv, REG_FTISR + 3);
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+		 "Read REG_FTISR 0x13f = %#X\n", tmp);
+
+	/* Set the WoWLAN related function control disable. */
+	rtl8821ae_set_fw_wowlan_mode(hw, false);
+	rtl8821ae_set_fw_remote_wake_ctrl_cmd(hw, 0);
+
+	if (rtlhal->hw_rof_enable) {
+		tmp = rtl_read_byte(rtlpriv, REG_HSISR + 3);
+		if (tmp & BIT(1)) {
+			/* Clear GPIO9 ISR */
+			rtl_write_byte(rtlpriv, REG_HSISR + 3, tmp | BIT(1));
+			init_finished = false;
+		} else {
+			init_finished = true;
+		}
+	}
+
+	if (init_finished) {
+		_rtl8821ae_simple_initialize_adapter(hw);
+
+		/* Release Pcie Interface Tx DMA. */
+		rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0x00);
+		/* Release Pcie RX DMA */
+		rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, 0x02);
+
+		tmp = rtl_read_byte(rtlpriv, REG_CR + 1);
+		rtl_write_byte(rtlpriv, REG_CR + 1, (tmp & (~BIT(0))));
+
+		_rtl8821ae_enable_l1off(hw);
+		_rtl8821ae_enable_ltr(hw);
+	}
+
+	return init_finished;
+}
+
+static void _rtl8812ae_bb8812_config_1t(struct ieee80211_hw *hw)
+{
+	/* BB OFDM RX Path_A */
+	rtl_set_bbreg(hw, 0x808, 0xff, 0x11);
+	/* BB OFDM TX Path_A */
+	rtl_set_bbreg(hw, 0x80c, MASKLWORD, 0x1111);
+	/* BB CCK R/Rx Path_A */
+	rtl_set_bbreg(hw, 0xa04, 0x0c000000, 0x0);
+	/* MCS support */
+	rtl_set_bbreg(hw, 0x8bc, 0xc0000060, 0x4);
+	/* RF Path_B HSSI OFF */
+	rtl_set_bbreg(hw, 0xe00, 0xf, 0x4);
+	/* RF Path_B Power Down */
+	rtl_set_bbreg(hw, 0xe90, MASKDWORD, 0);
+	/* ADDA Path_B OFF */
+	rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0);
+	rtl_set_bbreg(hw, 0xe64, MASKDWORD, 0);
+}
+
+static void _rtl8821ae_poweroff_adapter(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 u1b_tmp;
+
+	rtlhal->mac_func_enable = false;
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+		/* Combo (PCIe + USB) Card and PCIe-MF Card */
+		/* 1. Run LPS WL RFOFF flow */
+		/* RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		"=====>CardDisableRTL8812E,RTL8821A_NIC_LPS_ENTER_FLOW\n");
+		*/
+		rtl_hal_pwrseqcmdparsing(rtlpriv,
+			PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+			PWR_INTF_PCI_MSK, RTL8821A_NIC_LPS_ENTER_FLOW);
+	}
+	/* 2. 0x1F[7:0] = 0 */
+	/* turn off RF */
+	/* rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00); */
+	if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) &&
+		rtlhal->fw_ready) {
+		rtl8821ae_firmware_selfreset(hw);
+	}
+
+	/* Reset MCU. Suggested by Filen. */
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
+
+	/* g.	MCUFWDL 0x80[1:0]=0	 */
+	/* reset MCU ready status */
+	rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+		/* HW card disable configuration. */
+		rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+			PWR_INTF_PCI_MSK, RTL8821A_NIC_DISABLE_FLOW);
+	} else {
+		/* HW card disable configuration. */
+		rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+			PWR_INTF_PCI_MSK, RTL8812_NIC_DISABLE_FLOW);
+	}
+
+	/* Reset MCU IO Wrapper */
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
+	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, u1b_tmp | BIT(0));
+
+	/* 7. RSV_CTRL 0x1C[7:0] = 0x0E */
+	/* lock ISO/CLK/Power control register */
+	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e);
+}
+
+int rtl8821ae_hw_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	bool rtstatus = true;
+	int err;
+	u8 tmp_u1b;
+	bool support_remote_wakeup;
+	u32 nav_upper = WIFI_NAV_UPPER_US;
+
+	rtlhal->being_init_adapter = true;
+	rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+				      (u8 *)(&support_remote_wakeup));
+	rtlpriv->intf_ops->disable_aspm(hw);
+
+	/*YP wowlan not considered*/
+
+	tmp_u1b = rtl_read_byte(rtlpriv, REG_CR);
+	if (tmp_u1b != 0 && tmp_u1b != 0xEA) {
+		rtlhal->mac_func_enable = true;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "MAC has already power on.\n");
+	} else {
+		rtlhal->mac_func_enable = false;
+		rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_8821AE;
+	}
+
+	if (support_remote_wakeup &&
+		rtlhal->wake_from_pnp_sleep &&
+		rtlhal->mac_func_enable) {
+		if (_rtl8821ae_wowlan_initialize_adapter(hw)) {
+			rtlhal->being_init_adapter = false;
+			return 0;
+		}
+	}
+
+	if (_rtl8821ae_check_pcie_dma_hang(hw)) {
+		_rtl8821ae_reset_pcie_interface_dma(hw,
+						    rtlhal->mac_func_enable,
+						    false);
+		rtlhal->mac_func_enable = false;
+	}
+
+	/* Reset MAC/BB/RF status if it is not powered off
+	 * before calling initialize Hw flow to prevent
+	 * from interface and MAC status mismatch.
+	 * 2013.06.21, by tynli. Suggested by SD1 JackieLau. */
+	if (rtlhal->mac_func_enable) {
+		_rtl8821ae_poweroff_adapter(hw);
+		rtlhal->mac_func_enable = false;
+	}
+
+	rtstatus = _rtl8821ae_init_mac(hw);
+	if (rtstatus != true) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
+		err = 1;
+		return err;
+	}
+
+	tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CFG);
+	tmp_u1b &= 0x7F;
+	rtl_write_byte(rtlpriv, REG_SYS_CFG, tmp_u1b);
+
+	err = rtl8821ae_download_fw(hw, false);
+	if (err) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "Failed to download FW. Init HW without FW now\n");
+		err = 1;
+		rtlhal->fw_ready = false;
+		return err;
+	} else {
+		rtlhal->fw_ready = true;
+	}
+	ppsc->fw_current_inpsmode = false;
+	rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_8821AE;
+	rtlhal->fw_clk_change_in_progress = false;
+	rtlhal->allow_sw_to_change_hwclc = false;
+	rtlhal->last_hmeboxnum = 0;
+
+	/*SIC_Init(Adapter);
+	if(rtlhal->AMPDUBurstMode)
+		rtl_write_byte(rtlpriv,REG_AMPDU_BURST_MODE_8812,  0x7F);*/
+
+	rtl8821ae_phy_mac_config(hw);
+	/* because last function modify RCR, so we update
+	 * rcr var here, or TP will unstable for receive_config
+	 * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx
+	 * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252
+	rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR);
+	rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV);
+	rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);*/
+	rtl8821ae_phy_bb_config(hw);
+
+	rtl8821ae_phy_rf_config(hw);
+
+	if (rtlpriv->phy.rf_type == RF_1T1R &&
+		rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+		_rtl8812ae_bb8812_config_1t(hw);
+
+	_rtl8821ae_hw_configure(hw);
+
+	rtl8821ae_phy_switch_wirelessband(hw, BAND_ON_2_4G);
+
+	/*set wireless mode*/
+
+	rtlhal->mac_func_enable = true;
+
+	rtl_cam_reset_all_entry(hw);
+
+	rtl8821ae_enable_hw_security_config(hw);
+
+	ppsc->rfpwr_state = ERFON;
+
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
+	_rtl8821ae_enable_aspm_back_door(hw);
+	rtlpriv->intf_ops->enable_aspm(hw);
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE &&
+	    (rtlhal->rfe_type == 1 || rtlhal->rfe_type == 5))
+		rtl_set_bbreg(hw, 0x900, 0x00000303, 0x0302);
+
+	rtl8821ae_bt_hw_init(hw);
+	rtlpriv->rtlhal.being_init_adapter = false;
+
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_NAV_UPPER, (u8 *)&nav_upper);
+
+	/* rtl8821ae_dm_check_txpower_tracking(hw); */
+	/* rtl8821ae_phy_lc_calibrate(hw); */
+	if (support_remote_wakeup)
+		rtl_write_byte(rtlpriv, REG_WOW_CTRL, 0);
+
+	/* Release Rx DMA*/
+	tmp_u1b = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+	if (tmp_u1b & BIT(2)) {
+		/* Release Rx DMA if needed*/
+		tmp_u1b &= ~BIT(2);
+		rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, tmp_u1b);
+	}
+
+	/* Release Tx/Rx PCIE DMA if*/
+	rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0);
+
+	rtl8821ae_dm_init(hw);
+	rtl8821ae_macid_initialize_mediastatus(hw);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "rtl8821ae_hw_init() <====\n");
+	return err;
+}
+
+static enum version_8821ae _rtl8821ae_read_chip_version(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	enum version_8821ae version = VERSION_UNKNOWN;
+	u32 value32;
+
+	value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "ReadChipVersion8812A 0xF0 = 0x%x\n", value32);
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+		rtlphy->rf_type = RF_2T2R;
+	else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE)
+		rtlphy->rf_type = RF_1T1R;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "RF_Type is %x!!\n", rtlphy->rf_type);
+
+	if (value32 & TRP_VAUX_EN) {
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+			if (rtlphy->rf_type == RF_2T2R)
+				version = VERSION_TEST_CHIP_2T2R_8812;
+			else
+				version = VERSION_TEST_CHIP_1T1R_8812;
+		} else
+			version = VERSION_TEST_CHIP_8821;
+	} else {
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+			u32 rtl_id = ((value32 & CHIP_VER_RTL_MASK) >> 12) + 1;
+
+			if (rtlphy->rf_type == RF_2T2R)
+				version =
+					(enum version_8821ae)(CHIP_8812
+					| NORMAL_CHIP |
+					RF_TYPE_2T2R);
+			else
+				version = (enum version_8821ae)(CHIP_8812
+					| NORMAL_CHIP);
+
+			version = (enum version_8821ae)(version | (rtl_id << 12));
+		} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+			u32 rtl_id = value32 & CHIP_VER_RTL_MASK;
+
+			version = (enum version_8821ae)(CHIP_8821
+				| NORMAL_CHIP | rtl_id);
+		}
+	}
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+		/*WL_HWROF_EN.*/
+		value32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL);
+		rtlhal->hw_rof_enable = ((value32 & WL_HWROF_EN) ? 1 : 0);
+	}
+
+	switch (version) {
+	case VERSION_TEST_CHIP_1T1R_8812:
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Chip Version ID: VERSION_TEST_CHIP_1T1R_8812\n");
+		break;
+	case VERSION_TEST_CHIP_2T2R_8812:
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Chip Version ID: VERSION_TEST_CHIP_2T2R_8812\n");
+		break;
+	case VERSION_NORMAL_TSMC_CHIP_1T1R_8812:
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Chip Version ID:VERSION_NORMAL_TSMC_CHIP_1T1R_8812\n");
+		break;
+	case VERSION_NORMAL_TSMC_CHIP_2T2R_8812:
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Chip Version ID: VERSION_NORMAL_TSMC_CHIP_2T2R_8812\n");
+		break;
+	case VERSION_NORMAL_TSMC_CHIP_1T1R_8812_C_CUT:
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Chip Version ID: VERSION_NORMAL_TSMC_CHIP_1T1R_8812 C CUT\n");
+		break;
+	case VERSION_NORMAL_TSMC_CHIP_2T2R_8812_C_CUT:
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Chip Version ID: VERSION_NORMAL_TSMC_CHIP_2T2R_8812 C CUT\n");
+		break;
+	case VERSION_TEST_CHIP_8821:
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Chip Version ID: VERSION_TEST_CHIP_8821\n");
+		break;
+	case VERSION_NORMAL_TSMC_CHIP_8821:
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Chip Version ID: VERSION_NORMAL_TSMC_CHIP_8821 A CUT\n");
+		break;
+	case VERSION_NORMAL_TSMC_CHIP_8821_B_CUT:
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Chip Version ID: VERSION_NORMAL_TSMC_CHIP_8821 B CUT\n");
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Chip Version ID: Unknow (0x%X)\n", version);
+		break;
+	}
+
+	return version;
+}
+
+static int _rtl8821ae_set_media_status(struct ieee80211_hw *hw,
+				     enum nl80211_iftype type)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 bt_msr = rtl_read_byte(rtlpriv, MSR);
+	enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
+	bt_msr &= 0xfc;
+
+	rtl_write_dword(rtlpriv, REG_BCN_CTRL, 0);
+	RT_TRACE(rtlpriv, COMP_BEACON, DBG_LOUD,
+		"clear 0x550 when set HW_VAR_MEDIA_STATUS\n");
+
+	if (type == NL80211_IFTYPE_UNSPECIFIED ||
+	    type == NL80211_IFTYPE_STATION) {
+		_rtl8821ae_stop_tx_beacon(hw);
+		_rtl8821ae_enable_bcn_sub_func(hw);
+	} else if (type == NL80211_IFTYPE_ADHOC ||
+		type == NL80211_IFTYPE_AP) {
+		_rtl8821ae_resume_tx_beacon(hw);
+		_rtl8821ae_disable_bcn_sub_func(hw);
+	} else {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n",
+			 type);
+	}
+
+	switch (type) {
+	case NL80211_IFTYPE_UNSPECIFIED:
+		bt_msr |= MSR_NOLINK;
+		ledaction = LED_CTL_LINK;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "Set Network type to NO LINK!\n");
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		bt_msr |= MSR_ADHOC;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "Set Network type to Ad Hoc!\n");
+		break;
+	case NL80211_IFTYPE_STATION:
+		bt_msr |= MSR_INFRA;
+		ledaction = LED_CTL_LINK;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "Set Network type to STA!\n");
+		break;
+	case NL80211_IFTYPE_AP:
+		bt_msr |= MSR_AP;
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "Set Network type to AP!\n");
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Network type %d not support!\n", type);
+		return 1;
+	}
+
+	rtl_write_byte(rtlpriv, (MSR), bt_msr);
+	rtlpriv->cfg->ops->led_control(hw, ledaction);
+	if ((bt_msr & 0xfc) == MSR_AP)
+		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
+	else
+		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
+
+	return 0;
+}
+
+void rtl8821ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u32 reg_rcr = rtlpci->receive_config;
+
+	if (rtlpriv->psc.rfpwr_state != ERFON)
+		return;
+
+	if (check_bssid) {
+		reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
+		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
+					      (u8 *)(&reg_rcr));
+		_rtl8821ae_set_bcn_ctrl_reg(hw, 0, BIT(4));
+	} else if (!check_bssid) {
+		reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN));
+		_rtl8821ae_set_bcn_ctrl_reg(hw, BIT(4), 0);
+		rtlpriv->cfg->ops->set_hw_reg(hw,
+			HW_VAR_RCR, (u8 *)(&reg_rcr));
+	}
+}
+
+int rtl8821ae_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "rtl8821ae_set_network_type!\n");
+
+	if (_rtl8821ae_set_media_status(hw, type))
+		return -EOPNOTSUPP;
+
+	if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+		if (type != NL80211_IFTYPE_AP)
+			rtl8821ae_set_check_bssid(hw, true);
+	} else {
+		rtl8821ae_set_check_bssid(hw, false);
+	}
+
+	return 0;
+}
+
+/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */
+void rtl8821ae_set_qos(struct ieee80211_hw *hw, int aci)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	rtl8821ae_dm_init_edca_turbo(hw);
+	switch (aci) {
+	case AC1_BK:
+		rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
+		break;
+	case AC0_BE:
+		/* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); */
+		break;
+	case AC2_VI:
+		rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322);
+		break;
+	case AC3_VO:
+		rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222);
+		break;
+	default:
+		RT_ASSERT(false, "invalid aci: %d !\n", aci);
+		break;
+	}
+}
+
+static void rtl8821ae_clear_interrupt(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 tmp;
+	tmp = rtl_read_dword(rtlpriv, REG_HISR);
+	/*printk("clear interrupt first:\n");
+	printk("0x%x = 0x%08x\n",REG_HISR, tmp);*/
+	rtl_write_dword(rtlpriv, REG_HISR, tmp);
+
+	tmp = rtl_read_dword(rtlpriv, REG_HISRE);
+	/*printk("0x%x = 0x%08x\n",REG_HISRE, tmp);*/
+	rtl_write_dword(rtlpriv, REG_HISRE, tmp);
+
+	tmp = rtl_read_dword(rtlpriv, REG_HSISR);
+	/*printk("0x%x = 0x%08x\n",REG_HSISR, tmp);*/
+	rtl_write_dword(rtlpriv, REG_HSISR, tmp);
+}
+
+void rtl8821ae_enable_interrupt(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	rtl8821ae_clear_interrupt(hw);/*clear it here first*/
+
+	rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
+	rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
+	rtlpci->irq_enabled = true;
+	/* there are some C2H CMDs have been sent before
+	system interrupt is enabled, e.g., C2H, CPWM.
+	*So we need to clear all C2H events that FW has
+	notified, otherwise FW won't schedule any commands anymore.
+	*/
+	/* rtl_write_byte(rtlpriv, REG_C2HEVT_CLEAR, 0); */
+	/*enable system interrupt*/
+	rtl_write_dword(rtlpriv, REG_HSIMR, rtlpci->sys_irq_mask & 0xFFFFFFFF);
+}
+
+void rtl8821ae_disable_interrupt(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	rtl_write_dword(rtlpriv, REG_HIMR, IMR_DISABLED);
+	rtl_write_dword(rtlpriv, REG_HIMRE, IMR_DISABLED);
+	rtlpci->irq_enabled = false;
+	/*synchronize_irq(rtlpci->pdev->irq);*/
+}
+
+static void _rtl8821ae_clear_pci_pme_status(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u16 cap_hdr;
+	u8 cap_pointer;
+	u8 cap_id = 0xff;
+	u8 pmcs_reg;
+	u8 cnt = 0;
+
+	/* Get the Capability pointer first,
+	 * the Capability Pointer is located at
+	 * offset 0x34 from the Function Header */
+
+	pci_read_config_byte(rtlpci->pdev, 0x34, &cap_pointer);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "PCI configration 0x34 = 0x%2x\n", cap_pointer);
+
+	do {
+		pci_read_config_word(rtlpci->pdev, cap_pointer, &cap_hdr);
+		cap_id = cap_hdr & 0xFF;
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "in pci configration, cap_pointer%x = %x\n",
+			  cap_pointer, cap_id);
+
+		if (cap_id == 0x01) {
+			break;
+		} else {
+			/* point to next Capability */
+			cap_pointer = (cap_hdr >> 8) & 0xFF;
+			/* 0: end of pci capability, 0xff: invalid value */
+			if (cap_pointer == 0x00 || cap_pointer == 0xff) {
+				cap_id = 0xff;
+				break;
+			}
+		}
+	} while (cnt++ < 200);
+
+	if (cap_id == 0x01) {
+		/* Get the PM CSR (Control/Status Register),
+		 * The PME_Status is located at PM Capatibility offset 5, bit 7
+		 */
+		pci_read_config_byte(rtlpci->pdev, cap_pointer + 5, &pmcs_reg);
+
+		if (pmcs_reg & BIT(7)) {
+			/* PME event occured, clear the PM_Status by write 1 */
+			pmcs_reg = pmcs_reg | BIT(7);
+
+			pci_write_config_byte(rtlpci->pdev, cap_pointer + 5,
+					      pmcs_reg);
+			/* Read it back to check */
+			pci_read_config_byte(rtlpci->pdev, cap_pointer + 5,
+					     &pmcs_reg);
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+				 "Clear PME status 0x%2x to 0x%2x\n",
+				  cap_pointer + 5, pmcs_reg);
+		} else {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+				 "PME status(0x%2x) = 0x%2x\n",
+				  cap_pointer + 5, pmcs_reg);
+		}
+	} else {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING,
+			 "Cannot find PME Capability\n");
+	}
+}
+
+void rtl8821ae_card_disable(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
+	struct rtl_mac *mac = rtl_mac(rtlpriv);
+	enum nl80211_iftype opmode;
+	bool support_remote_wakeup;
+	u8 tmp;
+	u32 count = 0;
+
+	rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+				      (u8 *)(&support_remote_wakeup));
+
+	RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+	if (!(support_remote_wakeup && mac->opmode == NL80211_IFTYPE_STATION)
+	    || !rtlhal->enter_pnp_sleep) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Normal Power off\n");
+		mac->link_state = MAC80211_NOLINK;
+		opmode = NL80211_IFTYPE_UNSPECIFIED;
+		_rtl8821ae_set_media_status(hw, opmode);
+		_rtl8821ae_poweroff_adapter(hw);
+	} else {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Wowlan Supported.\n");
+		/* 3 <1> Prepare for configuring wowlan related infomations */
+		/* Clear Fw WoWLAN event. */
+		rtl_write_byte(rtlpriv, REG_MCUTST_WOWLAN, 0x0);
+
+#if (USE_SPECIFIC_FW_TO_SUPPORT_WOWLAN == 1)
+		rtl8821ae_set_fw_related_for_wowlan(hw, true);
+#endif
+		/* Dynamically adjust Tx packet boundary
+		 * for download reserved page packet.
+		 * reserve 30 pages for rsvd page */
+		if (_rtl8821ae_dynamic_rqpn(hw, 0xE0, 0x3, 0x80c20d0d))
+			rtlhal->re_init_llt_table = true;
+
+		/* 3 <2> Set Fw releted H2C cmd. */
+
+		/* Set WoWLAN related security information. */
+		rtl8821ae_set_fw_global_info_cmd(hw);
+
+		_rtl8821ae_download_rsvd_page(hw, true);
+
+		/* Just enable AOAC related functions when we connect to AP. */
+		printk("mac->link_state = %d\n", mac->link_state);
+		if (mac->link_state >= MAC80211_LINKED &&
+		    mac->opmode == NL80211_IFTYPE_STATION) {
+			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL);
+			rtl8821ae_set_fw_media_status_rpt_cmd(hw,
+							      RT_MEDIA_CONNECT);
+
+			rtl8821ae_set_fw_wowlan_mode(hw, true);
+			/* Enable Fw Keep alive mechanism. */
+			rtl8821ae_set_fw_keep_alive_cmd(hw, true);
+
+			/* Enable disconnect decision control. */
+			rtl8821ae_set_fw_disconnect_decision_ctrl_cmd(hw, true);
+		}
+
+		/* 3 <3> Hw Configutations */
+
+		/* Wait untill Rx DMA Finished before host sleep.
+		 * FW Pause Rx DMA may happens when received packet doing dma.
+		 */
+		rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, BIT(2));
+
+		tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+		count = 0;
+		while (!(tmp & BIT(1)) && (count++ < 100)) {
+			udelay(10);
+			tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+		}
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Wait Rx DMA Finished before host sleep. count=%d\n",
+			  count);
+
+		/* reset trx ring */
+		rtlpriv->intf_ops->reset_trx_ring(hw);
+
+		rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, 0x0);
+
+		_rtl8821ae_clear_pci_pme_status(hw);
+		tmp = rtl_read_byte(rtlpriv, REG_SYS_CLKR);
+		rtl_write_byte(rtlpriv, REG_SYS_CLKR, tmp | BIT(3));
+		/* prevent 8051 to be reset by PERST */
+		rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x20);
+		rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x60);
+	}
+
+	if (rtlpriv->rtlhal.driver_is_goingto_unload ||
+	    ppsc->rfoff_reason > RF_CHANGE_BY_PS)
+		rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
+	/* For wowlan+LPS+32k. */
+	if (support_remote_wakeup && rtlhal->enter_pnp_sleep) {
+		/* Set the WoWLAN related function control enable.
+		 * It should be the last H2C cmd in the WoWLAN flow. */
+		rtl8821ae_set_fw_remote_wake_ctrl_cmd(hw, 1);
+
+		/* Stop Pcie Interface Tx DMA. */
+		rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xff);
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Stop PCIE Tx DMA.\n");
+
+		/* Wait for TxDMA idle. */
+		count = 0;
+		do {
+			tmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG);
+			udelay(10);
+			count++;
+		} while ((tmp != 0) && (count < 100));
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Wait Tx DMA Finished before host sleep. count=%d\n",
+			  count);
+
+		if (rtlhal->hw_rof_enable) {
+			printk("hw_rof_enable\n");
+			tmp = rtl_read_byte(rtlpriv, REG_HSISR + 3);
+			rtl_write_byte(rtlpriv, REG_HSISR + 3, tmp | BIT(1));
+		}
+	}
+	/* after power off we should do iqk again */
+	rtlpriv->phy.iqk_initialized = false;
+}
+
+void rtl8821ae_interrupt_recognized(struct ieee80211_hw *hw,
+				  u32 *p_inta, u32 *p_intb)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	*p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0];
+	rtl_write_dword(rtlpriv, ISR, *p_inta);
+
+	*p_intb = rtl_read_dword(rtlpriv, REG_HISRE) & rtlpci->irq_mask[1];
+	rtl_write_dword(rtlpriv, REG_HISRE, *p_intb);
+}
+
+void rtl8821ae_set_beacon_related_registers(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u16 bcn_interval, atim_window;
+
+	bcn_interval = mac->beacon_interval;
+	atim_window = 2;	/*FIX MERGE */
+	rtl8821ae_disable_interrupt(hw);
+	rtl_write_word(rtlpriv, REG_ATIMWND, atim_window);
+	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+	rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f);
+	rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18);
+	rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18);
+	rtl_write_byte(rtlpriv, 0x606, 0x30);
+	rtlpci->reg_bcn_ctrl_val |= BIT(3);
+	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8)rtlpci->reg_bcn_ctrl_val);
+	rtl8821ae_enable_interrupt(hw);
+}
+
+void rtl8821ae_set_beacon_interval(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	u16 bcn_interval = mac->beacon_interval;
+
+	RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
+		 "beacon_interval:%d\n", bcn_interval);
+	rtl8821ae_disable_interrupt(hw);
+	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+	rtl8821ae_enable_interrupt(hw);
+}
+
+void rtl8821ae_update_interrupt_mask(struct ieee80211_hw *hw,
+				   u32 add_msr, u32 rm_msr)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
+		 "add_msr:%x, rm_msr:%x\n", add_msr, rm_msr);
+
+	if (add_msr)
+		rtlpci->irq_mask[0] |= add_msr;
+	if (rm_msr)
+		rtlpci->irq_mask[0] &= (~rm_msr);
+	rtl8821ae_disable_interrupt(hw);
+	rtl8821ae_enable_interrupt(hw);
+}
+
+static u8 _rtl8821ae_get_chnl_group(u8 chnl)
+{
+	u8 group = 0;
+
+	if (chnl <= 14) {
+		if (1 <= chnl && chnl <= 2)
+			group = 0;
+	else if (3 <= chnl && chnl <= 5)
+			group = 1;
+	else if (6 <= chnl && chnl <= 8)
+			group = 2;
+	else if (9 <= chnl && chnl <= 11)
+			group = 3;
+	else /*if (12 <= chnl && chnl <= 14)*/
+			group = 4;
+	} else {
+		if (36 <= chnl && chnl <= 42)
+			group = 0;
+	else if (44 <= chnl && chnl <= 48)
+			group = 1;
+	else if (50 <= chnl && chnl <= 58)
+			group = 2;
+	else if (60 <= chnl && chnl <= 64)
+			group = 3;
+	else if (100 <= chnl && chnl <= 106)
+			group = 4;
+	else if (108 <= chnl && chnl <= 114)
+			group = 5;
+	else if (116 <= chnl && chnl <= 122)
+			group = 6;
+	else if (124 <= chnl && chnl <= 130)
+			group = 7;
+	else if (132 <= chnl && chnl <= 138)
+			group = 8;
+	else if (140 <= chnl && chnl <= 144)
+			group = 9;
+	else if (149 <= chnl && chnl <= 155)
+			group = 10;
+	else if (157 <= chnl && chnl <= 161)
+			group = 11;
+	else if (165 <= chnl && chnl <= 171)
+			group = 12;
+	else if (173 <= chnl && chnl <= 177)
+			group = 13;
+		else
+			/*RT_TRACE(rtlpriv, COMP_EFUSE,DBG_LOUD,
+				"5G, Channel %d in Group not found\n",chnl);*/
+			RT_ASSERT(!COMP_EFUSE,
+				"5G, Channel %d in Group not found\n", chnl);
+	}
+	return group;
+}
+
+static void _rtl8821ae_read_power_value_fromprom(struct ieee80211_hw *hw,
+	struct txpower_info_2g *pwrinfo24g,
+	struct txpower_info_5g *pwrinfo5g,
+	bool autoload_fail,
+	u8 *hwinfo)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 rfPath, eeAddr = EEPROM_TX_PWR_INX, group, TxCount = 0;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "hal_ReadPowerValueFromPROM8821ae(): hwinfo[0x%x]=0x%x\n",
+		 (eeAddr+1), hwinfo[eeAddr+1]);
+	if (0xFF == hwinfo[eeAddr+1])  /*YJ,add,120316*/
+		autoload_fail = true;
+
+	if (autoload_fail) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "auto load fail : Use Default value!\n");
+		for (rfPath = 0 ; rfPath < MAX_RF_PATH ; rfPath++) {
+			/*2.4G default value*/
+			for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) {
+				pwrinfo24g->index_cck_base[rfPath][group] =	0x2D;
+				pwrinfo24g->index_bw40_base[rfPath][group] = 0x2D;
+			}
+			for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
+				if (TxCount == 0) {
+					pwrinfo24g->bw20_diff[rfPath][0] = 0x02;
+					pwrinfo24g->ofdm_diff[rfPath][0] = 0x04;
+				} else {
+					pwrinfo24g->bw20_diff[rfPath][TxCount] = 0xFE;
+					pwrinfo24g->bw40_diff[rfPath][TxCount] = 0xFE;
+					pwrinfo24g->cck_diff[rfPath][TxCount] =	0xFE;
+					pwrinfo24g->ofdm_diff[rfPath][TxCount] = 0xFE;
+				}
+			}
+			/*5G default value*/
+			for (group = 0 ; group < MAX_CHNL_GROUP_5G; group++)
+				pwrinfo5g->index_bw40_base[rfPath][group] = 0x2A;
+
+			for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
+				if (TxCount == 0) {
+					pwrinfo5g->ofdm_diff[rfPath][0] = 0x04;
+					pwrinfo5g->bw20_diff[rfPath][0] = 0x00;
+					pwrinfo5g->bw80_diff[rfPath][0] = 0xFE;
+					pwrinfo5g->bw160_diff[rfPath][0] = 0xFE;
+				} else {
+					pwrinfo5g->ofdm_diff[rfPath][0] = 0xFE;
+					pwrinfo5g->bw20_diff[rfPath][0] = 0xFE;
+					pwrinfo5g->bw40_diff[rfPath][0] = 0xFE;
+					pwrinfo5g->bw80_diff[rfPath][0] = 0xFE;
+					pwrinfo5g->bw160_diff[rfPath][0] = 0xFE;
+				}
+			}
+		}
+		return;
+	}
+
+	rtl_priv(hw)->efuse.txpwr_fromeprom = true;
+
+	for (rfPath = 0 ; rfPath < MAX_RF_PATH ; rfPath++) {
+		/*2.4G default value*/
+		for (group = 0 ; group < MAX_CHNL_GROUP_24G; group++) {
+			pwrinfo24g->index_cck_base[rfPath][group] = hwinfo[eeAddr++];
+			if (pwrinfo24g->index_cck_base[rfPath][group] == 0xFF)
+				pwrinfo24g->index_cck_base[rfPath][group] = 0x2D;
+		}
+		for (group = 0 ; group < MAX_CHNL_GROUP_24G - 1; group++) {
+			pwrinfo24g->index_bw40_base[rfPath][group] = hwinfo[eeAddr++];
+			if (pwrinfo24g->index_bw40_base[rfPath][group] == 0xFF)
+				pwrinfo24g->index_bw40_base[rfPath][group] = 0x2D;
+		}
+		for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
+			if (TxCount == 0) {
+				pwrinfo24g->bw40_diff[rfPath][TxCount] = 0;
+				/*bit sign number to 8 bit sign number*/
+				pwrinfo24g->bw20_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0xf0) >> 4;
+				if (pwrinfo24g->bw20_diff[rfPath][TxCount] & BIT(3))
+					pwrinfo24g->bw20_diff[rfPath][TxCount] |= 0xF0;
+				/*bit sign number to 8 bit sign number*/
+				pwrinfo24g->ofdm_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0x0f);
+				if (pwrinfo24g->ofdm_diff[rfPath][TxCount] & BIT(3))
+					pwrinfo24g->ofdm_diff[rfPath][TxCount] |= 0xF0;
+
+				pwrinfo24g->cck_diff[rfPath][TxCount] = 0;
+				eeAddr++;
+			} else {
+				pwrinfo24g->bw40_diff[rfPath][TxCount] = (hwinfo[eeAddr]&0xf0) >> 4;
+				if (pwrinfo24g->bw40_diff[rfPath][TxCount] & BIT(3))
+					pwrinfo24g->bw40_diff[rfPath][TxCount] |= 0xF0;
+
+				pwrinfo24g->bw20_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0x0f);
+				if (pwrinfo24g->bw20_diff[rfPath][TxCount] & BIT(3))
+					pwrinfo24g->bw20_diff[rfPath][TxCount] |= 0xF0;
+
+				eeAddr++;
+
+				pwrinfo24g->ofdm_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0xf0) >> 4;
+				if (pwrinfo24g->ofdm_diff[rfPath][TxCount] & BIT(3))
+					pwrinfo24g->ofdm_diff[rfPath][TxCount] |= 0xF0;
+
+				pwrinfo24g->cck_diff[rfPath][TxCount] =	(hwinfo[eeAddr] & 0x0f);
+				if (pwrinfo24g->cck_diff[rfPath][TxCount] & BIT(3))
+					pwrinfo24g->cck_diff[rfPath][TxCount] |= 0xF0;
+
+				eeAddr++;
+			}
+		}
+
+		/*5G default value*/
+		for (group = 0 ; group < MAX_CHNL_GROUP_5G; group++) {
+			pwrinfo5g->index_bw40_base[rfPath][group] = hwinfo[eeAddr++];
+			if (pwrinfo5g->index_bw40_base[rfPath][group] == 0xFF)
+				pwrinfo5g->index_bw40_base[rfPath][group] = 0xFE;
+		}
+
+		for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
+			if (TxCount == 0) {
+				pwrinfo5g->bw40_diff[rfPath][TxCount] = 0;
+
+				pwrinfo5g->bw20_diff[rfPath][0] = (hwinfo[eeAddr] & 0xf0) >> 4;
+				if (pwrinfo5g->bw20_diff[rfPath][TxCount] & BIT(3))
+					pwrinfo5g->bw20_diff[rfPath][TxCount] |= 0xF0;
+
+				pwrinfo5g->ofdm_diff[rfPath][0] = (hwinfo[eeAddr] & 0x0f);
+				if (pwrinfo5g->ofdm_diff[rfPath][TxCount] & BIT(3))
+					pwrinfo5g->ofdm_diff[rfPath][TxCount] |= 0xF0;
+
+				eeAddr++;
+			} else {
+				pwrinfo5g->bw40_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0xf0) >> 4;
+				if (pwrinfo5g->bw40_diff[rfPath][TxCount] & BIT(3))
+					pwrinfo5g->bw40_diff[rfPath][TxCount] |= 0xF0;
+
+				pwrinfo5g->bw20_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0x0f);
+				if (pwrinfo5g->bw20_diff[rfPath][TxCount] & BIT(3))
+					pwrinfo5g->bw20_diff[rfPath][TxCount] |= 0xF0;
+
+				eeAddr++;
+			}
+		}
+
+		pwrinfo5g->ofdm_diff[rfPath][1] =	(hwinfo[eeAddr] & 0xf0) >> 4;
+		pwrinfo5g->ofdm_diff[rfPath][2] =	(hwinfo[eeAddr] & 0x0f);
+
+		eeAddr++;
+
+		pwrinfo5g->ofdm_diff[rfPath][3] = (hwinfo[eeAddr] & 0x0f);
+
+		eeAddr++;
+
+		for (TxCount = 1; TxCount < MAX_TX_COUNT; TxCount++) {
+			if (pwrinfo5g->ofdm_diff[rfPath][TxCount] & BIT(3))
+				pwrinfo5g->ofdm_diff[rfPath][TxCount] |= 0xF0;
+		}
+		for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
+			pwrinfo5g->bw80_diff[rfPath][TxCount] =	(hwinfo[eeAddr] & 0xf0) >> 4;
+			/* 4bit sign number to 8 bit sign number */
+			if (pwrinfo5g->bw80_diff[rfPath][TxCount] & BIT(3))
+				pwrinfo5g->bw80_diff[rfPath][TxCount] |= 0xF0;
+			/* 4bit sign number to 8 bit sign number */
+			pwrinfo5g->bw160_diff[rfPath][TxCount] = (hwinfo[eeAddr] & 0x0f);
+			if (pwrinfo5g->bw160_diff[rfPath][TxCount] & BIT(3))
+				pwrinfo5g->bw160_diff[rfPath][TxCount] |= 0xF0;
+
+			eeAddr++;
+		}
+	}
+}
+#if 0
+static void _rtl8812ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
+						 bool autoload_fail,
+						 u8 *hwinfo)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct txpower_info_2g pwrinfo24g;
+	struct txpower_info_5g pwrinfo5g;
+	u8 channel5g[CHANNEL_MAX_NUMBER_5G] = {
+		36, 38, 40, 42, 44, 46, 48, 50, 52, 54,
+		56, 58, 60, 62, 64, 100, 102, 104, 106,
+		108, 110, 112, 114, 116, 118, 120, 122,
+		124, 126, 128, 130, 132, 134, 136, 138,
+		140, 142, 144, 149, 151, 153, 155, 157,
+		159, 161, 163, 165, 167, 168, 169, 171, 173, 175, 177};
+	u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {42, 58, 106, 122, 138, 155, 171};
+	u8 rf_path, index;
+	u8 i;
+
+	_rtl8821ae_read_power_value_fromprom(hw, &pwrinfo24g,
+					&pwrinfo5g, autoload_fail, hwinfo);
+
+	for (rf_path = 0; rf_path < 2; rf_path++) {
+		for (i = 0; i < CHANNEL_MAX_NUMBER_2G; i++) {
+			index = _rtl8821ae_get_chnl_group(i + 1);
+
+			if (i == CHANNEL_MAX_NUMBER_2G - 1) {
+				rtlefuse->txpwrlevel_cck[rf_path][i] =
+					pwrinfo24g.index_cck_base[rf_path][5];
+				rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+					pwrinfo24g.index_bw40_base[rf_path][index];
+			} else {
+				rtlefuse->txpwrlevel_cck[rf_path][i] =
+					pwrinfo24g.index_cck_base[rf_path][index];
+				rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+					pwrinfo24g.index_bw40_base[rf_path][index];
+			}
+		}
+
+		for (i = 0; i < CHANNEL_MAX_NUMBER_5G; i++) {
+			index = _rtl8821ae_get_chnl_group(channel5g[i]);
+			rtlefuse->txpwr_5g_bw40base[rf_path][i] =
+					pwrinfo5g.index_bw40_base[rf_path][index];
+		}
+		for (i = 0; i < CHANNEL_MAX_NUMBER_5G_80M; i++) {
+			u8 upper, lower;
+			index = _rtl8821ae_get_chnl_group(channel5g_80m[i]);
+			upper = pwrinfo5g.index_bw40_base[rf_path][index];
+			lower = pwrinfo5g.index_bw40_base[rf_path][index + 1];
+
+			rtlefuse->txpwr_5g_bw80base[rf_path][i] = (upper + lower) / 2;
+		}
+		for (i = 0; i < MAX_TX_COUNT; i++) {
+			rtlefuse->txpwr_cckdiff[rf_path][i] =
+				pwrinfo24g.cck_diff[rf_path][i];
+			rtlefuse->txpwr_legacyhtdiff[rf_path][i] =
+				pwrinfo24g.ofdm_diff[rf_path][i];
+			rtlefuse->txpwr_ht20diff[rf_path][i] =
+				pwrinfo24g.bw20_diff[rf_path][i];
+			rtlefuse->txpwr_ht40diff[rf_path][i] =
+				pwrinfo24g.bw40_diff[rf_path][i];
+
+			rtlefuse->txpwr_5g_ofdmdiff[rf_path][i] =
+				pwrinfo5g.ofdm_diff[rf_path][i];
+			rtlefuse->txpwr_5g_bw20diff[rf_path][i] =
+				pwrinfo5g.bw20_diff[rf_path][i];
+			rtlefuse->txpwr_5g_bw40diff[rf_path][i] =
+				pwrinfo5g.bw40_diff[rf_path][i];
+			rtlefuse->txpwr_5g_bw80diff[rf_path][i] =
+				pwrinfo5g.bw80_diff[rf_path][i];
+		}
+	}
+
+	if (!autoload_fail) {
+		rtlefuse->eeprom_regulatory =
+			hwinfo[EEPROM_RF_BOARD_OPTION] & 0x07;/*bit0~2*/
+		if (hwinfo[EEPROM_RF_BOARD_OPTION] == 0xFF)
+			rtlefuse->eeprom_regulatory = 0;
+	} else {
+		rtlefuse->eeprom_regulatory = 0;
+	}
+
+	RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
+	"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
+}
+#endif
+static void _rtl8821ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
+						 bool autoload_fail,
+						 u8 *hwinfo)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct txpower_info_2g pwrinfo24g;
+	struct txpower_info_5g pwrinfo5g;
+	u8 channel5g[CHANNEL_MAX_NUMBER_5G] = {
+		36, 38, 40, 42, 44, 46, 48, 50, 52, 54,
+		56, 58, 60, 62, 64, 100, 102, 104, 106,
+		108, 110, 112, 114, 116, 118, 120, 122,
+		124, 126, 128, 130, 132, 134, 136, 138,
+		140, 142, 144, 149, 151, 153, 155, 157,
+		159, 161, 163, 165, 167, 168, 169, 171,
+		173, 175, 177};
+	u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {
+		42, 58, 106, 122, 138, 155, 171};
+	u8 rf_path, index;
+	u8 i;
+
+	_rtl8821ae_read_power_value_fromprom(hw, &pwrinfo24g,
+		&pwrinfo5g, autoload_fail, hwinfo);
+
+	for (rf_path = 0; rf_path < 2; rf_path++) {
+		for (i = 0; i < CHANNEL_MAX_NUMBER_2G; i++) {
+			index = _rtl8821ae_get_chnl_group(i + 1);
+
+			if (i == CHANNEL_MAX_NUMBER_2G - 1) {
+				rtlefuse->txpwrlevel_cck[rf_path][i] =
+					pwrinfo24g.index_cck_base[rf_path][5];
+				rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+					pwrinfo24g.index_bw40_base[rf_path][index];
+			} else {
+				rtlefuse->txpwrlevel_cck[rf_path][i] =
+					pwrinfo24g.index_cck_base[rf_path][index];
+				rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+					pwrinfo24g.index_bw40_base[rf_path][index];
+			}
+		}
+
+		for (i = 0; i < CHANNEL_MAX_NUMBER_5G; i++) {
+			index = _rtl8821ae_get_chnl_group(channel5g[i]);
+			rtlefuse->txpwr_5g_bw40base[rf_path][i] =
+				pwrinfo5g.index_bw40_base[rf_path][index];
+		}
+		for (i = 0; i < CHANNEL_MAX_NUMBER_5G_80M; i++) {
+			u8 upper, lower;
+			index = _rtl8821ae_get_chnl_group(channel5g_80m[i]);
+			upper = pwrinfo5g.index_bw40_base[rf_path][index];
+			lower = pwrinfo5g.index_bw40_base[rf_path][index + 1];
+
+			rtlefuse->txpwr_5g_bw80base[rf_path][i] = (upper + lower) / 2;
+		}
+		for (i = 0; i < MAX_TX_COUNT; i++) {
+			rtlefuse->txpwr_cckdiff[rf_path][i] =
+				pwrinfo24g.cck_diff[rf_path][i];
+			rtlefuse->txpwr_legacyhtdiff[rf_path][i] =
+				pwrinfo24g.ofdm_diff[rf_path][i];
+			rtlefuse->txpwr_ht20diff[rf_path][i] =
+				pwrinfo24g.bw20_diff[rf_path][i];
+			rtlefuse->txpwr_ht40diff[rf_path][i] =
+				pwrinfo24g.bw40_diff[rf_path][i];
+
+			rtlefuse->txpwr_5g_ofdmdiff[rf_path][i] =
+				pwrinfo5g.ofdm_diff[rf_path][i];
+			rtlefuse->txpwr_5g_bw20diff[rf_path][i] =
+				pwrinfo5g.bw20_diff[rf_path][i];
+			rtlefuse->txpwr_5g_bw40diff[rf_path][i] =
+				pwrinfo5g.bw40_diff[rf_path][i];
+			rtlefuse->txpwr_5g_bw80diff[rf_path][i] =
+				pwrinfo5g.bw80_diff[rf_path][i];
+		}
+	}
+	/*bit0~2*/
+	if (!autoload_fail) {
+		rtlefuse->eeprom_regulatory = hwinfo[EEPROM_RF_BOARD_OPTION] & 0x07;
+		if (hwinfo[EEPROM_RF_BOARD_OPTION] == 0xFF)
+			rtlefuse->eeprom_regulatory = 0;
+	} else {
+		rtlefuse->eeprom_regulatory = 0;
+	}
+
+	RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
+	"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
+}
+
+static void _rtl8812ae_read_pa_type(struct ieee80211_hw *hw, u8 *hwinfo,
+				    bool autoload_fail)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+
+	if (!autoload_fail) {
+		rtlhal->pa_type_2g = hwinfo[0xBC];
+		rtlhal->lna_type_2g = hwinfo[0xBD];
+		if (rtlhal->pa_type_2g == 0xFF && rtlhal->lna_type_2g == 0xFF) {
+			rtlhal->pa_type_2g = 0;
+			rtlhal->lna_type_2g = 0;
+		}
+		rtlhal->external_pa_2g = ((rtlhal->pa_type_2g & BIT(5)) &&
+					  (rtlhal->pa_type_2g & BIT(4))) ?
+					 1 : 0;
+		rtlhal->external_lna_2g = ((rtlhal->lna_type_2g & BIT(7)) &&
+					   (rtlhal->lna_type_2g & BIT(3))) ?
+					  1 : 0;
+
+		rtlhal->pa_type_5g = hwinfo[0xBC];
+		rtlhal->lna_type_5g = hwinfo[0xBF];
+		if (rtlhal->pa_type_5g == 0xFF && rtlhal->lna_type_5g == 0xFF) {
+			rtlhal->pa_type_5g = 0;
+			rtlhal->lna_type_5g = 0;
+		}
+		rtlhal->external_pa_5g = ((rtlhal->pa_type_5g & BIT(1)) &&
+					  (rtlhal->pa_type_5g & BIT(0))) ?
+					 1 : 0;
+		rtlhal->external_lna_5g = ((rtlhal->lna_type_5g & BIT(7)) &&
+					   (rtlhal->lna_type_5g & BIT(3))) ?
+					  1 : 0;
+	} else {
+		rtlhal->external_pa_2g  = 0;
+		rtlhal->external_lna_2g = 0;
+		rtlhal->external_pa_5g  = 0;
+		rtlhal->external_lna_5g = 0;
+	}
+}
+
+static void _rtl8821ae_read_pa_type(struct ieee80211_hw *hw, u8 *hwinfo,
+				    bool autoload_fail)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+
+	if (!autoload_fail) {
+		rtlhal->pa_type_2g = hwinfo[0xBC];
+		rtlhal->lna_type_2g = hwinfo[0xBD];
+		if (rtlhal->pa_type_2g == 0xFF && rtlhal->lna_type_2g == 0xFF) {
+			rtlhal->pa_type_2g = 0;
+			rtlhal->lna_type_2g = 0;
+		}
+		rtlhal->external_pa_2g = (rtlhal->pa_type_2g & BIT(5)) ? 1 : 0;
+		rtlhal->external_lna_2g = (rtlhal->lna_type_2g & BIT(7)) ? 1 : 0;
+
+		rtlhal->pa_type_5g = hwinfo[0xBC];
+		rtlhal->lna_type_5g = hwinfo[0xBF];
+		if (rtlhal->pa_type_5g == 0xFF && rtlhal->lna_type_5g == 0xFF) {
+			rtlhal->pa_type_5g = 0;
+			rtlhal->lna_type_5g = 0;
+		}
+		rtlhal->external_pa_5g = (rtlhal->pa_type_5g & BIT(1)) ? 1 : 0;
+		rtlhal->external_lna_5g = (rtlhal->lna_type_5g & BIT(7)) ? 1 : 0;
+	} else {
+		rtlhal->external_pa_2g  = 0;
+		rtlhal->external_lna_2g = 0;
+		rtlhal->external_pa_5g  = 0;
+		rtlhal->external_lna_5g = 0;
+	}
+}
+
+static void _rtl8821ae_read_rfe_type(struct ieee80211_hw *hw, u8 *hwinfo,
+			      bool autoload_fail)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+
+	if (!autoload_fail) {
+		if (hwinfo[EEPROM_RFE_OPTION] & BIT(7)) {
+			if (rtlhal->external_lna_5g) {
+				if (rtlhal->external_pa_5g) {
+					if (rtlhal->external_lna_2g &&
+					    rtlhal->external_pa_2g)
+						rtlhal->rfe_type = 3;
+					else
+						rtlhal->rfe_type = 0;
+				} else {
+					rtlhal->rfe_type = 2;
+				}
+			} else {
+				rtlhal->rfe_type = 4;
+			}
+		} else {
+			rtlhal->rfe_type = hwinfo[EEPROM_RFE_OPTION] & 0x3F;
+
+			if (rtlhal->rfe_type == 4 &&
+			    (rtlhal->external_pa_5g ||
+			     rtlhal->external_pa_2g ||
+			     rtlhal->external_lna_5g ||
+			     rtlhal->external_lna_2g)) {
+				if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+					rtlhal->rfe_type = 2;
+			}
+		}
+	} else {
+		rtlhal->rfe_type = 0x04;
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "RFE Type: 0x%2x\n", rtlhal->rfe_type);
+}
+
+static void _rtl8812ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+					      bool auto_load_fail, u8 *hwinfo)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 value;
+
+	if (!auto_load_fail) {
+		value = *(u8 *)&hwinfo[EEPROM_RF_BOARD_OPTION];
+		if (((value & 0xe0) >> 5) == 0x1)
+			rtlpriv->btcoexist.btc_info.btcoexist = 1;
+		else
+			rtlpriv->btcoexist.btc_info.btcoexist = 0;
+		rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8812A;
+
+		value = hwinfo[EEPROM_RF_BT_SETTING];
+		rtlpriv->btcoexist.btc_info.ant_num = (value & 0x1);
+	} else {
+		rtlpriv->btcoexist.btc_info.btcoexist = 0;
+		rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8812A;
+		rtlpriv->btcoexist.btc_info.ant_num = ANT_X2;
+	}
+	/*move BT_InitHalVars() to init_sw_vars*/
+}
+
+static void _rtl8821ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+					      bool auto_load_fail, u8 *hwinfo)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 value;
+	u32 tmpu_32;
+
+	if (!auto_load_fail) {
+		tmpu_32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL);
+		if (tmpu_32 & BIT(18))
+			rtlpriv->btcoexist.btc_info.btcoexist = 1;
+		else
+			rtlpriv->btcoexist.btc_info.btcoexist = 0;
+		rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8821A;
+
+		value = hwinfo[EEPROM_RF_BT_SETTING];
+		rtlpriv->btcoexist.btc_info.ant_num = (value & 0x1);
+	} else {
+		rtlpriv->btcoexist.btc_info.btcoexist = 0;
+		rtlpriv->btcoexist.btc_info.bt_type = BT_RTL8821A;
+		rtlpriv->btcoexist.btc_info.ant_num = ANT_X2;
+	}
+	/*move BT_InitHalVars() to init_sw_vars*/
+}
+
+static void _rtl8821ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_test)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	u16 i, usvalue;
+	u8 hwinfo[HWSET_MAX_SIZE];
+	u16 eeprom_id;
+
+	if (b_pseudo_test) {
+		;/* need add */
+	}
+
+	if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
+		rtl_efuse_shadow_map_update(hw);
+		memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+		       HWSET_MAX_SIZE);
+	} else if (rtlefuse->epromtype == EEPROM_93C46) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "RTL819X Not boot from eeprom, check it !!");
+	}
+
+	RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP\n",
+		      hwinfo, HWSET_MAX_SIZE);
+
+	eeprom_id = *((u16 *)&hwinfo[0]);
+	if (eeprom_id != RTL_EEPROM_ID) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "EEPROM ID(%#x) is invalid!!\n", eeprom_id);
+		rtlefuse->autoload_failflag = true;
+	} else {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+		rtlefuse->autoload_failflag = false;
+	}
+
+	if (rtlefuse->autoload_failflag) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "RTL8812AE autoload_failflag, check it !!");
+		return;
+	}
+
+	rtlefuse->eeprom_version = *(u8 *)&hwinfo[EEPROM_VERSION];
+	if (rtlefuse->eeprom_version == 0xff)
+			rtlefuse->eeprom_version = 0;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "EEPROM version: 0x%2x\n", rtlefuse->eeprom_version);
+
+	rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID];
+	rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID];
+	rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID];
+	rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID];
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "EEPROMId = 0x%4x\n", eeprom_id);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);
+
+	/*customer ID*/
+	rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+	if (rtlefuse->eeprom_oemid == 0xFF)
+		rtlefuse->eeprom_oemid = 0;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
+
+	for (i = 0; i < 6; i += 2) {
+		usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
+		*((u16 *)(&rtlefuse->dev_addr[i])) = usvalue;
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		 "dev_addr: %pM\n", rtlefuse->dev_addr);
+
+	_rtl8821ae_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag,
+					       hwinfo);
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+		_rtl8812ae_read_pa_type(hw, hwinfo, rtlefuse->autoload_failflag);
+		_rtl8812ae_read_bt_coexist_info_from_hwpg(hw,
+				rtlefuse->autoload_failflag, hwinfo);
+	} else {
+		_rtl8821ae_read_pa_type(hw, hwinfo, rtlefuse->autoload_failflag);
+		_rtl8821ae_read_bt_coexist_info_from_hwpg(hw,
+				rtlefuse->autoload_failflag, hwinfo);
+	}
+
+	_rtl8821ae_read_rfe_type(hw, hwinfo, rtlefuse->autoload_failflag);
+	/*board type*/
+	rtlefuse->board_type = ODM_BOARD_DEFAULT;
+	if (rtlhal->external_lna_2g != 0)
+		rtlefuse->board_type |= ODM_BOARD_EXT_LNA;
+	if (rtlhal->external_lna_5g != 0)
+		rtlefuse->board_type |= ODM_BOARD_EXT_LNA_5G;
+	if (rtlhal->external_pa_2g != 0)
+		rtlefuse->board_type |= ODM_BOARD_EXT_PA;
+	if (rtlhal->external_pa_5g != 0)
+		rtlefuse->board_type |= ODM_BOARD_EXT_PA_5G;
+
+	if (rtlpriv->btcoexist.btc_info.btcoexist == 1)
+		rtlefuse->board_type |= ODM_BOARD_BT;
+
+	rtlhal->board_type = rtlefuse->board_type;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "board_type = 0x%x\n", rtlefuse->board_type);
+
+	rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+	if (rtlefuse->eeprom_channelplan == 0xff)
+		rtlefuse->eeprom_channelplan = 0x7F;
+
+	/* set channel paln to world wide 13 */
+	/* rtlefuse->channel_plan = (u8)rtlefuse->eeprom_channelplan; */
+
+	/*parse xtal*/
+	rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_8821AE];
+	if (rtlefuse->crystalcap == 0xFF)
+		rtlefuse->crystalcap = 0x20;
+
+	rtlefuse->eeprom_thermalmeter = *(u8 *)&hwinfo[EEPROM_THERMAL_METER];
+	if ((rtlefuse->eeprom_thermalmeter == 0xff) ||
+	    rtlefuse->autoload_failflag) {
+		rtlefuse->apk_thermalmeterignore = true;
+		rtlefuse->eeprom_thermalmeter = 0xff;
+	}
+
+	rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
+
+	if (!rtlefuse->autoload_failflag) {
+		rtlefuse->antenna_div_cfg =
+		  (hwinfo[EEPROM_RF_BOARD_OPTION] & 0x18) >> 3;
+		if (hwinfo[EEPROM_RF_BOARD_OPTION] == 0xff)
+			rtlefuse->antenna_div_cfg = 0;
+
+		if (rtlpriv->btcoexist.btc_info.btcoexist == 1 &&
+		    rtlpriv->btcoexist.btc_info.ant_num == ANT_X1)
+			rtlefuse->antenna_div_cfg = 0;
+
+		rtlefuse->antenna_div_type = hwinfo[EEPROM_RF_ANTENNA_OPT_88E];
+		if (rtlefuse->antenna_div_type == 0xff)
+			rtlefuse->antenna_div_type = FIXED_HW_ANTDIV;
+	} else {
+		rtlefuse->antenna_div_cfg = 0;
+		rtlefuse->antenna_div_type = 0;
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		"SWAS: bHwAntDiv = %x, TRxAntDivType = %x\n",
+		rtlefuse->antenna_div_cfg, rtlefuse->antenna_div_type);
+
+	pcipriv->ledctl.led_opendrain = true;
+
+	if (rtlhal->oem_id == RT_CID_DEFAULT) {
+		switch (rtlefuse->eeprom_oemid) {
+		case RT_CID_DEFAULT:
+			break;
+		case EEPROM_CID_TOSHIBA:
+			rtlhal->oem_id = RT_CID_TOSHIBA;
+			break;
+		case EEPROM_CID_CCX:
+			rtlhal->oem_id = RT_CID_CCX;
+			break;
+		case EEPROM_CID_QMI:
+			rtlhal->oem_id = RT_CID_819X_QMI;
+			break;
+		case EEPROM_CID_WHQL:
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/*static void _rtl8821ae_hal_customized_behavior(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+	pcipriv->ledctl.led_opendrain = true;
+	switch (rtlhal->oem_id) {
+	case RT_CID_819X_HP:
+		pcipriv->ledctl.led_opendrain = true;
+		break;
+	case RT_CID_819X_LENOVO:
+	case RT_CID_DEFAULT:
+	case RT_CID_TOSHIBA:
+	case RT_CID_CCX:
+	case RT_CID_819X_ACER:
+	case RT_CID_WHQL:
+	default:
+		break;
+	}
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+		 "RT Customized ID: 0x%02X\n", rtlhal->oem_id);
+}*/
+
+void rtl8821ae_read_eeprom_info(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 tmp_u1b;
+
+	rtlhal->version = _rtl8821ae_read_chip_version(hw);
+	if (get_rf_type(rtlphy) == RF_1T1R)
+		rtlpriv->dm.rfpath_rxenable[0] = true;
+	else
+		rtlpriv->dm.rfpath_rxenable[0] =
+		    rtlpriv->dm.rfpath_rxenable[1] = true;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n",
+						rtlhal->version);
+
+	tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR);
+	if (tmp_u1b & BIT(4)) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n");
+		rtlefuse->epromtype = EEPROM_93C46;
+	} else {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n");
+		rtlefuse->epromtype = EEPROM_BOOT_EFUSE;
+	}
+
+	if (tmp_u1b & BIT(5)) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+		rtlefuse->autoload_failflag = false;
+		_rtl8821ae_read_adapter_info(hw, false);
+	} else {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n");
+	}
+	/*hal_ReadRFType_8812A()*/
+	/* _rtl8821ae_hal_customized_behavior(hw); */
+}
+
+static void rtl8821ae_update_hal_rate_table(struct ieee80211_hw *hw,
+		struct ieee80211_sta *sta)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u32 ratr_value;
+	u8 ratr_index = 0;
+	u8 b_nmode = mac->ht_enable;
+	u8 mimo_ps = IEEE80211_SMPS_OFF;
+	u16 shortgi_rate;
+	u32 tmp_ratr_value;
+	u8 curtxbw_40mhz = mac->bw_40;
+	u8 b_curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+				1 : 0;
+	u8 b_curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+				1 : 0;
+	enum wireless_mode wirelessmode = mac->mode;
+
+	if (rtlhal->current_bandtype == BAND_ON_5G)
+		ratr_value = sta->supp_rates[1] << 4;
+	else
+		ratr_value = sta->supp_rates[0];
+	if (mac->opmode == NL80211_IFTYPE_ADHOC)
+		ratr_value = 0xfff;
+	ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+			sta->ht_cap.mcs.rx_mask[0] << 12);
+	switch (wirelessmode) {
+	case WIRELESS_MODE_B:
+		if (ratr_value & 0x0000000c)
+			ratr_value &= 0x0000000d;
+		else
+			ratr_value &= 0x0000000f;
+		break;
+	case WIRELESS_MODE_G:
+		ratr_value &= 0x00000FF5;
+		break;
+	case WIRELESS_MODE_N_24G:
+	case WIRELESS_MODE_N_5G:
+		b_nmode = 1;
+		if (mimo_ps == IEEE80211_SMPS_STATIC) {
+			ratr_value &= 0x0007F005;
+		} else {
+			u32 ratr_mask;
+
+			if (get_rf_type(rtlphy) == RF_1T2R ||
+			    get_rf_type(rtlphy) == RF_1T1R)
+				ratr_mask = 0x000ff005;
+			else
+				ratr_mask = 0x0f0ff005;
+
+			ratr_value &= ratr_mask;
+		}
+		break;
+	default:
+		if (rtlphy->rf_type == RF_1T2R)
+			ratr_value &= 0x000ff0ff;
+		else
+			ratr_value &= 0x0f0ff0ff;
+
+		break;
+	}
+
+	if ((rtlpriv->btcoexist.bt_coexistence) &&
+	     (rtlpriv->btcoexist.bt_coexist_type == BT_CSR_BC4) &&
+	     (rtlpriv->btcoexist.bt_cur_state) &&
+	     (rtlpriv->btcoexist.bt_ant_isolation) &&
+	     ((rtlpriv->btcoexist.bt_service == BT_SCO) ||
+	     (rtlpriv->btcoexist.bt_service == BT_BUSY)))
+		ratr_value &= 0x0fffcfc0;
+	else
+		ratr_value &= 0x0FFFFFFF;
+
+	if (b_nmode && ((curtxbw_40mhz &&
+			 b_curshortgi_40mhz) || (!curtxbw_40mhz &&
+						 b_curshortgi_20mhz))) {
+		ratr_value |= 0x10000000;
+		tmp_ratr_value = (ratr_value >> 12);
+
+		for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
+			if ((1 << shortgi_rate) & tmp_ratr_value)
+				break;
+		}
+
+		shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
+		    (shortgi_rate << 4) | (shortgi_rate);
+	}
+
+	rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
+
+	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+		 "%x\n", rtl_read_dword(rtlpriv, REG_ARFR0));
+}
+
+static u8 _rtl8821ae_mrate_idx_to_arfr_id(
+	struct ieee80211_hw *hw, u8 rate_index,
+	enum wireless_mode wirelessmode)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 ret = 0;
+	switch (rate_index) {
+	case RATR_INX_WIRELESS_NGB:
+		if (rtlphy->rf_type == RF_1T1R)
+			ret = 1;
+		else
+			ret = 0;
+		; break;
+	case RATR_INX_WIRELESS_N:
+	case RATR_INX_WIRELESS_NG:
+		if (rtlphy->rf_type == RF_1T1R)
+			ret = 5;
+		else
+			ret = 4;
+		; break;
+	case RATR_INX_WIRELESS_NB:
+		if (rtlphy->rf_type == RF_1T1R)
+			ret = 3;
+		else
+			ret = 2;
+		; break;
+	case RATR_INX_WIRELESS_GB:
+		ret = 6;
+		break;
+	case RATR_INX_WIRELESS_G:
+		ret = 7;
+		break;
+	case RATR_INX_WIRELESS_B:
+		ret = 8;
+		break;
+	case RATR_INX_WIRELESS_MC:
+		if ((wirelessmode == WIRELESS_MODE_B)
+			|| (wirelessmode == WIRELESS_MODE_G)
+			|| (wirelessmode == WIRELESS_MODE_N_24G)
+			|| (wirelessmode == WIRELESS_MODE_AC_24G))
+			ret = 6;
+		else
+			ret = 7;
+	case RATR_INX_WIRELESS_AC_5N:
+		if (rtlphy->rf_type == RF_1T1R)
+			ret = 10;
+		else
+			ret = 9;
+		break;
+	case RATR_INX_WIRELESS_AC_24N:
+		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) {
+			if (rtlphy->rf_type == RF_1T1R)
+				ret = 10;
+			else
+				ret = 9;
+		} else {
+			if (rtlphy->rf_type == RF_1T1R)
+				ret = 11;
+			else
+				ret = 12;
+		}
+		break;
+	default:
+		ret = 0; break;
+	}
+	return ret;
+}
+
+static u32 _rtl8821ae_rate_to_bitmap_2ssvht(__le16 vht_rate)
+{
+	u8 i, j, tmp_rate;
+	u32 rate_bitmap = 0;
+
+	for (i = j = 0; i < 4; i += 2, j += 10) {
+		tmp_rate = (le16_to_cpu(vht_rate) >> i) & 3;
+
+		switch (tmp_rate) {
+		case 2:
+			rate_bitmap = rate_bitmap | (0x03ff << j);
+			break;
+		case 1:
+			rate_bitmap = rate_bitmap | (0x01ff << j);
+			break;
+		case 0:
+			rate_bitmap = rate_bitmap | (0x00ff << j);
+			break;
+		default:
+			break;
+		}
+	}
+
+	return rate_bitmap;
+}
+
+static u32 _rtl8821ae_set_ra_vht_ratr_bitmap(struct ieee80211_hw *hw,
+					     enum wireless_mode wirelessmode,
+					     u32 ratr_bitmap)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u32 ret_bitmap = ratr_bitmap;
+
+	if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40
+		|| rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80)
+		ret_bitmap = ratr_bitmap;
+	else if (wirelessmode == WIRELESS_MODE_AC_5G
+		|| wirelessmode == WIRELESS_MODE_AC_24G) {
+		if (rtlphy->rf_type == RF_1T1R)
+			ret_bitmap = ratr_bitmap & (~BIT21);
+		else
+			ret_bitmap = ratr_bitmap & (~(BIT31|BIT21));
+	}
+
+	return ret_bitmap;
+}
+
+static u8 _rtl8821ae_get_vht_eni(enum wireless_mode wirelessmode,
+			u32 ratr_bitmap)
+{
+	u8 ret = 0;
+	if (wirelessmode < WIRELESS_MODE_N_24G)
+		ret =  0;
+	else if (wirelessmode == WIRELESS_MODE_AC_24G) {
+		if (ratr_bitmap & 0xfff00000)	/* Mix , 2SS */
+			ret = 3;
+		else					/* Mix, 1SS */
+			ret = 2;
+	} else if (wirelessmode == WIRELESS_MODE_AC_5G) {
+			ret = 1;
+	} /* VHT */
+
+	return ret << 4;
+}
+
+static u8 _rtl8821ae_get_ra_ldpc(struct ieee80211_hw *hw,
+			     u8 mac_id, struct rtl_sta_info *sta_entry,
+			     enum wireless_mode wirelessmode)
+{
+	u8 b_ldpc = 0;
+	/*not support ldpc, do not open*/
+	return b_ldpc << 2;
+}
+
+static u8 _rtl8821ae_get_ra_rftype(struct ieee80211_hw *hw,
+			  enum wireless_mode wirelessmode,
+			  u32 ratr_bitmap)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 rf_type = RF_1T1R;
+
+	if (rtlphy->rf_type == RF_1T1R)
+		rf_type = RF_1T1R;
+	else if (wirelessmode == WIRELESS_MODE_AC_5G
+		|| wirelessmode == WIRELESS_MODE_AC_24G
+		|| wirelessmode == WIRELESS_MODE_AC_ONLY) {
+		if (ratr_bitmap & 0xffc00000)
+			rf_type = RF_2T2R;
+	} else if (wirelessmode == WIRELESS_MODE_N_5G
+		|| wirelessmode == WIRELESS_MODE_N_24G) {
+		if (ratr_bitmap & 0xfff00000)
+			rf_type = RF_2T2R;
+	}
+
+	return rf_type;
+}
+
+static bool _rtl8821ae_get_ra_shortgi(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+			      u8 mac_id)
+{
+	bool b_short_gi = false;
+	u8 b_curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+				1 : 0;
+	u8 b_curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+				1 : 0;
+	u8 b_curshortgi_80mhz = 0;
+	b_curshortgi_80mhz = (sta->vht_cap.cap &
+			      IEEE80211_VHT_CAP_SHORT_GI_80) ? 1 : 0;
+
+	if (mac_id == MAC_ID_STATIC_FOR_BROADCAST_MULTICAST)
+			b_short_gi = false;
+
+	if (b_curshortgi_40mhz || b_curshortgi_80mhz
+		|| b_curshortgi_20mhz)
+		b_short_gi = true;
+
+	return b_short_gi;
+}
+
+static void rtl8821ae_update_hal_rate_mask(struct ieee80211_hw *hw,
+		struct ieee80211_sta *sta, u8 rssi_level)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_sta_info *sta_entry = NULL;
+	u32 ratr_bitmap;
+	u8 ratr_index;
+	enum wireless_mode wirelessmode = 0;
+	u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+				? 1 : 0;
+	bool b_shortgi = false;
+	u8 rate_mask[7];
+	u8 macid = 0;
+	u8 mimo_ps = IEEE80211_SMPS_OFF;
+	u8 rf_type;
+
+	sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+	wirelessmode = sta_entry->wireless_mode;
+
+	RT_TRACE(rtlpriv, COMP_RATR, DBG_LOUD,
+		 "wireless mode = 0x%x\n", wirelessmode);
+	if (mac->opmode == NL80211_IFTYPE_STATION ||
+		mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+		curtxbw_40mhz = mac->bw_40;
+	} else if (mac->opmode == NL80211_IFTYPE_AP ||
+		mac->opmode == NL80211_IFTYPE_ADHOC)
+		macid = sta->aid + 1;
+	if (wirelessmode == WIRELESS_MODE_N_5G ||
+	    wirelessmode == WIRELESS_MODE_AC_5G)
+		ratr_bitmap = sta->supp_rates[NL80211_BAND_5GHZ];
+	else
+		ratr_bitmap = sta->supp_rates[NL80211_BAND_2GHZ];
+
+	if (mac->opmode == NL80211_IFTYPE_ADHOC)
+		ratr_bitmap = 0xfff;
+
+	if (wirelessmode == WIRELESS_MODE_N_24G
+		|| wirelessmode == WIRELESS_MODE_N_5G)
+		ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+				sta->ht_cap.mcs.rx_mask[0] << 12);
+	else if (wirelessmode == WIRELESS_MODE_AC_24G
+		|| wirelessmode == WIRELESS_MODE_AC_5G
+		|| wirelessmode == WIRELESS_MODE_AC_ONLY)
+		ratr_bitmap |= _rtl8821ae_rate_to_bitmap_2ssvht(
+				sta->vht_cap.vht_mcs.rx_mcs_map) << 12;
+
+	b_shortgi = _rtl8821ae_get_ra_shortgi(hw, sta, macid);
+	rf_type = _rtl8821ae_get_ra_rftype(hw, wirelessmode, ratr_bitmap);
+
+/*mac id owner*/
+	switch (wirelessmode) {
+	case WIRELESS_MODE_B:
+		ratr_index = RATR_INX_WIRELESS_B;
+		if (ratr_bitmap & 0x0000000c)
+			ratr_bitmap &= 0x0000000d;
+		else
+			ratr_bitmap &= 0x0000000f;
+		break;
+	case WIRELESS_MODE_G:
+		ratr_index = RATR_INX_WIRELESS_GB;
+
+		if (rssi_level == 1)
+			ratr_bitmap &= 0x00000f00;
+		else if (rssi_level == 2)
+			ratr_bitmap &= 0x00000ff0;
+		else
+			ratr_bitmap &= 0x00000ff5;
+		break;
+	case WIRELESS_MODE_A:
+		ratr_index = RATR_INX_WIRELESS_G;
+		ratr_bitmap &= 0x00000ff0;
+		break;
+	case WIRELESS_MODE_N_24G:
+	case WIRELESS_MODE_N_5G:
+		if (wirelessmode == WIRELESS_MODE_N_24G)
+			ratr_index = RATR_INX_WIRELESS_NGB;
+		else
+			ratr_index = RATR_INX_WIRELESS_NG;
+
+		if (mimo_ps == IEEE80211_SMPS_STATIC
+			|| mimo_ps == IEEE80211_SMPS_DYNAMIC) {
+			if (rssi_level == 1)
+				ratr_bitmap &= 0x000f0000;
+			else if (rssi_level == 2)
+				ratr_bitmap &= 0x000ff000;
+			else
+				ratr_bitmap &= 0x000ff005;
+		} else {
+			if (rf_type == RF_1T1R) {
+				if (curtxbw_40mhz) {
+					if (rssi_level == 1)
+						ratr_bitmap &= 0x000f0000;
+					else if (rssi_level == 2)
+						ratr_bitmap &= 0x000ff000;
+					else
+						ratr_bitmap &= 0x000ff015;
+				} else {
+					if (rssi_level == 1)
+						ratr_bitmap &= 0x000f0000;
+					else if (rssi_level == 2)
+						ratr_bitmap &= 0x000ff000;
+					else
+						ratr_bitmap &= 0x000ff005;
+				}
+			} else {
+				if (curtxbw_40mhz) {
+					if (rssi_level == 1)
+						ratr_bitmap &= 0x0fff0000;
+					else if (rssi_level == 2)
+						ratr_bitmap &= 0x0ffff000;
+					else
+						ratr_bitmap &= 0x0ffff015;
+				} else {
+					if (rssi_level == 1)
+						ratr_bitmap &= 0x0fff0000;
+					else if (rssi_level == 2)
+						ratr_bitmap &= 0x0ffff000;
+					else
+						ratr_bitmap &= 0x0ffff005;
+				}
+			}
+		}
+		break;
+
+	case WIRELESS_MODE_AC_24G:
+		ratr_index = RATR_INX_WIRELESS_AC_24N;
+		if (rssi_level == 1)
+			ratr_bitmap &= 0xfc3f0000;
+		else if (rssi_level == 2)
+			ratr_bitmap &= 0xfffff000;
+		else
+			ratr_bitmap &= 0xffffffff;
+		break;
+
+	case WIRELESS_MODE_AC_5G:
+		ratr_index = RATR_INX_WIRELESS_AC_5N;
+
+		if (rf_type == RF_1T1R) {
+			if (rssi_level == 1)	/*add by Gary for ac-series*/
+				ratr_bitmap &= 0x003f8000;
+			else if (rssi_level == 2)
+				ratr_bitmap &= 0x003ff000;
+			else
+				ratr_bitmap &= 0x003ff010;
+		} else {
+			if (rssi_level == 1)
+				ratr_bitmap &= 0xfe3f8000;
+			else if (rssi_level == 2)
+				ratr_bitmap &= 0xfffff000;
+			else
+				ratr_bitmap &= 0xfffff010;
+		}
+		break;
+
+	default:
+		ratr_index = RATR_INX_WIRELESS_NGB;
+
+		if (rf_type == RF_1T2R)
+			ratr_bitmap &= 0x000ff0ff;
+		else
+			ratr_bitmap &= 0x0f8ff0ff;
+		break;
+	}
+
+	ratr_index = _rtl8821ae_mrate_idx_to_arfr_id(hw, ratr_index, wirelessmode);
+	sta_entry->ratr_index = ratr_index;
+	ratr_bitmap = _rtl8821ae_set_ra_vht_ratr_bitmap(hw, wirelessmode,
+							ratr_bitmap);
+
+	RT_TRACE(rtlpriv, COMP_RATR, DBG_LOUD,
+		 "ratr_bitmap :%x\n", ratr_bitmap);
+
+	/* *(u32 *)& rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) |
+				       (ratr_index << 28)); */
+
+	rate_mask[0] = macid;
+	rate_mask[1] = ratr_index | (b_shortgi ? 0x80 : 0x00);
+	rate_mask[2] = rtlphy->current_chan_bw
+			   | _rtl8821ae_get_vht_eni(wirelessmode, ratr_bitmap)
+			   | _rtl8821ae_get_ra_ldpc(hw, macid, sta_entry, wirelessmode);
+
+	rate_mask[3] = (u8)(ratr_bitmap & 0x000000ff);
+	rate_mask[4] = (u8)((ratr_bitmap & 0x0000ff00) >> 8);
+	rate_mask[5] = (u8)((ratr_bitmap & 0x00ff0000) >> 16);
+	rate_mask[6] = (u8)((ratr_bitmap & 0xff000000) >> 24);
+
+	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+		 "Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x:%x:%x\n",
+		 ratr_index, ratr_bitmap,
+		 rate_mask[0], rate_mask[1],
+		 rate_mask[2], rate_mask[3],
+		 rate_mask[4], rate_mask[5],
+		 rate_mask[6]);
+	rtl8821ae_fill_h2c_cmd(hw, H2C_8821AE_RA_MASK, 7, rate_mask);
+	_rtl8821ae_set_bcn_ctrl_reg(hw, BIT(3), 0);
+}
+
+void rtl8821ae_update_hal_rate_tbl(struct ieee80211_hw *hw,
+		struct ieee80211_sta *sta, u8 rssi_level)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	if (rtlpriv->dm.useramask)
+		rtl8821ae_update_hal_rate_mask(hw, sta, rssi_level);
+	else
+		/*RT_TRACE(rtlpriv, COMP_RATR,DBG_LOUD,
+			   "rtl8821ae_update_hal_rate_tbl() Error! 8821ae FW RA Only");*/
+		rtl8821ae_update_hal_rate_table(hw, sta);
+}
+
+void rtl8821ae_update_channel_access_setting(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	u8 wireless_mode = mac->mode;
+	u8 sifs_timer, r2t_sifs;
+
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
+				      (u8 *)&mac->slot_time);
+	if (wireless_mode == WIRELESS_MODE_G)
+		sifs_timer = 0x0a;
+	else
+		sifs_timer = 0x0e;
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
+
+	r2t_sifs = 0xa;
+
+	if (wireless_mode == WIRELESS_MODE_AC_5G &&
+	    (mac->vht_ldpc_cap & LDPC_VHT_ENABLE_RX) &&
+	    (mac->vht_stbc_cap & STBC_VHT_ENABLE_RX)) {
+		if (mac->vendor == PEER_ATH)
+			r2t_sifs = 0x8;
+		else
+			r2t_sifs = 0xa;
+	} else if (wireless_mode == WIRELESS_MODE_AC_5G) {
+		r2t_sifs = 0xa;
+	}
+
+	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_R2T_SIFS, (u8 *)&r2t_sifs);
+}
+
+bool rtl8821ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;
+	u8 u1tmp = 0;
+	bool b_actuallyset = false;
+
+	if (rtlpriv->rtlhal.being_init_adapter)
+		return false;
+
+	if (ppsc->swrf_processing)
+		return false;
+
+	spin_lock(&rtlpriv->locks.rf_ps_lock);
+	if (ppsc->rfchange_inprogress) {
+		spin_unlock(&rtlpriv->locks.rf_ps_lock);
+		return false;
+	} else {
+		ppsc->rfchange_inprogress = true;
+		spin_unlock(&rtlpriv->locks.rf_ps_lock);
+	}
+
+	cur_rfstate = ppsc->rfpwr_state;
+
+	rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2,
+			rtl_read_byte(rtlpriv,
+					REG_GPIO_IO_SEL_2) & ~(BIT(1)));
+
+	u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL_2);
+
+	if (rtlphy->polarity_ctl)
+		e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFOFF : ERFON;
+	else
+		e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFON : ERFOFF;
+
+	if ((ppsc->hwradiooff) && (e_rfpowerstate_toset == ERFON)) {
+		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+			 "GPIOChangeRF  - HW Radio ON, RF ON\n");
+
+		e_rfpowerstate_toset = ERFON;
+		ppsc->hwradiooff = false;
+		b_actuallyset = true;
+	} else if ((!ppsc->hwradiooff)
+		   && (e_rfpowerstate_toset == ERFOFF)) {
+		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+			 "GPIOChangeRF  - HW Radio OFF, RF OFF\n");
+
+		e_rfpowerstate_toset = ERFOFF;
+		ppsc->hwradiooff = true;
+		b_actuallyset = true;
+	}
+
+	if (b_actuallyset) {
+		spin_lock(&rtlpriv->locks.rf_ps_lock);
+		ppsc->rfchange_inprogress = false;
+		spin_unlock(&rtlpriv->locks.rf_ps_lock);
+	} else {
+		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC)
+			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+		spin_lock(&rtlpriv->locks.rf_ps_lock);
+		ppsc->rfchange_inprogress = false;
+		spin_unlock(&rtlpriv->locks.rf_ps_lock);
+	}
+
+	*valid = 1;
+	return !ppsc->hwradiooff;
+}
+
+void rtl8821ae_set_key(struct ieee80211_hw *hw, u32 key_index,
+		     u8 *p_macaddr, bool is_group, u8 enc_algo,
+		     bool is_wepkey, bool clear_all)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	u8 *macaddr = p_macaddr;
+	u32 entry_id = 0;
+	bool is_pairwise = false;
+
+	static u8 cam_const_addr[4][6] = {
+		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+		{0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+		{0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+		{0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+	};
+	static u8 cam_const_broad[] = {
+		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+	};
+
+	if (clear_all) {
+		u8 idx = 0;
+		u8 cam_offset = 0;
+		u8 clear_number = 5;
+
+		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n");
+
+		for (idx = 0; idx < clear_number; idx++) {
+			rtl_cam_mark_invalid(hw, cam_offset + idx);
+			rtl_cam_empty_entry(hw, cam_offset + idx);
+
+			if (idx < 5) {
+				memset(rtlpriv->sec.key_buf[idx], 0,
+				       MAX_KEY_LEN);
+				rtlpriv->sec.key_len[idx] = 0;
+			}
+		}
+	} else {
+		switch (enc_algo) {
+		case WEP40_ENCRYPTION:
+			enc_algo = CAM_WEP40;
+			break;
+		case WEP104_ENCRYPTION:
+			enc_algo = CAM_WEP104;
+			break;
+		case TKIP_ENCRYPTION:
+			enc_algo = CAM_TKIP;
+			break;
+		case AESCCMP_ENCRYPTION:
+			enc_algo = CAM_AES;
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+				 "switch case not process\n");
+			enc_algo = CAM_TKIP;
+			break;
+		}
+
+		if (is_wepkey || rtlpriv->sec.use_defaultkey) {
+			macaddr = cam_const_addr[key_index];
+			entry_id = key_index;
+		} else {
+			if (is_group) {
+				macaddr = cam_const_broad;
+				entry_id = key_index;
+			} else {
+				if (mac->opmode == NL80211_IFTYPE_AP) {
+					entry_id = rtl_cam_get_free_entry(hw, p_macaddr);
+					if (entry_id >=  TOTAL_CAM_ENTRY) {
+						RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG,
+							 "Can not find free hwsecurity cam entry\n");
+						return;
+					}
+				} else {
+					entry_id = CAM_PAIRWISE_KEY_POSITION;
+				}
+
+				key_index = PAIRWISE_KEYIDX;
+				is_pairwise = true;
+			}
+		}
+
+		if (rtlpriv->sec.key_len[key_index] == 0) {
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+				 "delete one entry, entry_id is %d\n",
+				 entry_id);
+			if (mac->opmode == NL80211_IFTYPE_AP)
+				rtl_cam_del_entry(hw, p_macaddr);
+			rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
+		} else {
+			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+				 "add one entry\n");
+			if (is_pairwise) {
+				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+					 "set Pairwise key\n");
+
+				rtl_cam_add_one_entry(hw, macaddr, key_index,
+						      entry_id, enc_algo,
+						      CAM_CONFIG_NO_USEDK,
+						      rtlpriv->sec.key_buf[key_index]);
+			} else {
+				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+					 "set group key\n");
+
+				if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+					rtl_cam_add_one_entry(hw,
+							rtlefuse->dev_addr,
+							PAIRWISE_KEYIDX,
+							CAM_PAIRWISE_KEY_POSITION,
+							enc_algo,
+							CAM_CONFIG_NO_USEDK,
+							rtlpriv->sec.key_buf
+							[entry_id]);
+				}
+
+				rtl_cam_add_one_entry(hw, macaddr, key_index,
+						entry_id, enc_algo,
+						CAM_CONFIG_NO_USEDK,
+						rtlpriv->sec.key_buf[entry_id]);
+			}
+		}
+	}
+}
+
+void rtl8821ae_bt_reg_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	/* 0:Low, 1:High, 2:From Efuse. */
+	rtlpriv->btcoexist.reg_bt_iso = 2;
+	/* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */
+	rtlpriv->btcoexist.reg_bt_sco = 3;
+	/* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
+	rtlpriv->btcoexist.reg_bt_sco = 0;
+}
+
+void rtl8821ae_bt_hw_init(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (rtlpriv->cfg->ops->get_btc_status())
+		rtlpriv->btcoexist.btc_ops->btc_init_hw_config(rtlpriv);
+}
+
+void rtl8821ae_suspend(struct ieee80211_hw *hw)
+{
+}
+
+void rtl8821ae_resume(struct ieee80211_hw *hw)
+{
+}
+
+/* Turn on AAP (RCR:bit 0) for promicuous mode. */
+void rtl8821ae_allow_all_destaddr(struct ieee80211_hw *hw,
+	bool allow_all_da, bool write_into_reg)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	if (allow_all_da) /* Set BIT0 */
+		rtlpci->receive_config |= RCR_AAP;
+	else /* Clear BIT0 */
+		rtlpci->receive_config &= ~RCR_AAP;
+
+	if (write_into_reg)
+		rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+	RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD,
+		"receive_config=0x%08X, write_into_reg=%d\n",
+		rtlpci->receive_config, write_into_reg);
+}
+
+/* WKFMCAMAddAllEntry8812 */
+void rtl8821ae_add_wowlan_pattern(struct ieee80211_hw *hw,
+				  struct rtl_wow_pattern *rtl_pattern,
+				  u8 index)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 cam = 0;
+	u8 addr = 0;
+	u16 rxbuf_addr;
+	u8 tmp, count = 0;
+	u16 cam_start;
+	u16 offset;
+
+	/* Count the WFCAM entry start offset. */
+
+	/* RX page size = 128 byte */
+	offset = MAX_RX_DMA_BUFFER_SIZE_8812 / 128;
+	/* We should start from the boundry */
+	cam_start = offset * 128;
+
+	/* Enable Rx packet buffer access. */
+	rtl_write_byte(rtlpriv, REG_PKT_BUFF_ACCESS_CTRL, RXPKT_BUF_SELECT);
+	for (addr = 0; addr < WKFMCAM_ADDR_NUM; addr++) {
+		/* Set Rx packet buffer offset.
+		 * RxBufer pointer increases 1,
+		 * we can access 8 bytes in Rx packet buffer.
+		 * CAM start offset (unit: 1 byte) =  index*WKFMCAM_SIZE
+		 * RxBufer addr = (CAM start offset +
+		 *                 per entry offset of a WKFM CAM)/8
+		 *	* index: The index of the wake up frame mask
+		 *	* WKFMCAM_SIZE: the total size of one WKFM CAM
+		 *	* per entry offset of a WKFM CAM: Addr*4 bytes
+		 */
+		rxbuf_addr = (cam_start + index * WKFMCAM_SIZE + addr * 4) >> 3;
+		/* Set R/W start offset */
+		rtl_write_word(rtlpriv, REG_PKTBUF_DBG_CTRL, rxbuf_addr);
+
+		if (addr == 0) {
+			cam = BIT(31) | rtl_pattern->crc;
+
+			if (rtl_pattern->type == UNICAST_PATTERN)
+				cam |= BIT(24);
+			else if (rtl_pattern->type == MULTICAST_PATTERN)
+				cam |= BIT(25);
+			else if (rtl_pattern->type == BROADCAST_PATTERN)
+				cam |= BIT(26);
+
+			rtl_write_dword(rtlpriv, REG_PKTBUF_DBG_DATA_L, cam);
+			RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+				 "WRITE entry[%d] 0x%x: %x\n", addr,
+				  REG_PKTBUF_DBG_DATA_L, cam);
+
+			/* Write to Rx packet buffer. */
+			rtl_write_word(rtlpriv, REG_RXPKTBUF_CTRL, 0x0f01);
+		} else if (addr == 2 || addr == 4) {/* WKFM[127:0] */
+			cam = rtl_pattern->mask[addr - 2];
+
+			rtl_write_dword(rtlpriv, REG_PKTBUF_DBG_DATA_L, cam);
+			RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+				 "WRITE entry[%d] 0x%x: %x\n", addr,
+				  REG_PKTBUF_DBG_DATA_L, cam);
+
+			rtl_write_word(rtlpriv, REG_RXPKTBUF_CTRL, 0x0f01);
+		} else if (addr == 3 || addr == 5) {/* WKFM[127:0] */
+			cam = rtl_pattern->mask[addr - 2];
+
+			rtl_write_dword(rtlpriv, REG_PKTBUF_DBG_DATA_H, cam);
+			RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+				 "WRITE entry[%d] 0x%x: %x\n", addr,
+				  REG_PKTBUF_DBG_DATA_H, cam);
+
+			rtl_write_word(rtlpriv, REG_RXPKTBUF_CTRL, 0xf001);
+		}
+
+		count = 0;
+		do {
+			tmp = rtl_read_byte(rtlpriv, REG_RXPKTBUF_CTRL);
+			udelay(2);
+			count++;
+		} while (tmp && count < 100);
+
+		RT_ASSERT((count < 100),
+			  "Write wake up frame mask FAIL %d value!\n", tmp);
+	}
+	/* Disable Rx packet buffer access. */
+	rtl_write_byte(rtlpriv, REG_PKT_BUFF_ACCESS_CTRL,
+		       DISABLE_TRXPKT_BUF_ACCESS);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.h b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.h
new file mode 100644
index 0000000..a3553e3
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.h
@@ -0,0 +1,70 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8821AE_HW_H__
+#define __RTL8821AE_HW_H__
+
+void rtl8821ae_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl8821ae_read_eeprom_info(struct ieee80211_hw *hw);
+
+void rtl8821ae_interrupt_recognized(struct ieee80211_hw *hw,
+				    u32 *p_inta, u32 *p_intb);
+int rtl8821ae_hw_init(struct ieee80211_hw *hw);
+void rtl8821ae_card_disable(struct ieee80211_hw *hw);
+void rtl8821ae_enable_interrupt(struct ieee80211_hw *hw);
+void rtl8821ae_disable_interrupt(struct ieee80211_hw *hw);
+int rtl8821ae_set_network_type(struct ieee80211_hw *hw,
+			       enum nl80211_iftype type);
+void rtl8821ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
+void rtl8821ae_set_qos(struct ieee80211_hw *hw, int aci);
+void rtl8821ae_set_beacon_related_registers(struct ieee80211_hw *hw);
+void rtl8821ae_set_beacon_interval(struct ieee80211_hw *hw);
+void rtl8821ae_update_interrupt_mask(struct ieee80211_hw *hw,
+				     u32 add_msr, u32 rm_msr);
+void rtl8821ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl8821ae_update_hal_rate_tbl(struct ieee80211_hw *hw,
+				   struct ieee80211_sta *sta,
+				   u8 rssi_level);
+void rtl8821ae_update_channel_access_setting(struct ieee80211_hw *hw);
+bool rtl8821ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
+void rtl8821ae_enable_hw_security_config(struct ieee80211_hw *hw);
+void rtl8821ae_set_key(struct ieee80211_hw *hw, u32 key_index,
+		       u8 *p_macaddr, bool is_group, u8 enc_algo,
+		       bool is_wepkey, bool clear_all);
+
+void rtl8821ae_bt_reg_init(struct ieee80211_hw *hw);
+void rtl8821ae_bt_hw_init(struct ieee80211_hw *hw);
+void rtl8821ae_suspend(struct ieee80211_hw *hw);
+void rtl8821ae_resume(struct ieee80211_hw *hw);
+void rtl8821ae_allow_all_destaddr(struct ieee80211_hw *hw,
+				  bool allow_all_da,
+				  bool write_into_reg);
+void _rtl8821ae_stop_tx_beacon(struct ieee80211_hw *hw);
+void _rtl8821ae_resume_tx_beacon(struct ieee80211_hw *hw);
+void rtl8821ae_add_wowlan_pattern(struct ieee80211_hw *hw,
+				  struct rtl_wow_pattern *rtl_pattern,
+				  u8 index);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/led.c b/drivers/net/wireless/rtlwifi/rtl8821ae/led.c
new file mode 100644
index 0000000..ba1946a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/led.c
@@ -0,0 +1,237 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "reg.h"
+#include "led.h"
+
+static void _rtl8821ae_init_led(struct ieee80211_hw *hw,
+				struct rtl_led *pled,
+				enum rtl_led_pin ledpin)
+{
+	pled->hw = hw;
+	pled->ledpin = ledpin;
+	pled->ledon = false;
+}
+
+void rtl8821ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+	u8 ledcfg;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
+
+	switch (pled->ledpin) {
+	case LED_PIN_GPIO0:
+		break;
+	case LED_PIN_LED0:
+		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+		ledcfg &= ~BIT(6);
+		rtl_write_byte(rtlpriv,
+			       REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5));
+		break;
+	case LED_PIN_LED1:
+		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
+		rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg & 0x10);
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
+		break;
+	}
+	pled->ledon = true;
+}
+
+void rtl8812ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+	u16	ledreg = REG_LEDCFG1;
+	u8	ledcfg = 0;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	switch (pled->ledpin) {
+	case LED_PIN_LED0:
+		ledreg = REG_LEDCFG1;
+		break;
+
+	case LED_PIN_LED1:
+		ledreg = REG_LEDCFG2;
+		break;
+
+	case LED_PIN_GPIO0:
+	default:
+		break;
+	}
+
+	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+		 "In SwLedOn, LedAddr:%X LEDPIN=%d\n",
+		 ledreg, pled->ledpin);
+
+	ledcfg =  rtl_read_byte(rtlpriv, ledreg);
+	ledcfg |= BIT(5); /*Set 0x4c[21]*/
+	ledcfg &= ~(BIT(7) | BIT(6) | BIT(3) | BIT(2) | BIT(1) | BIT(0));
+		/*Clear 0x4c[23:22] and 0x4c[19:16]*/
+	rtl_write_byte(rtlpriv, ledreg, ledcfg); /*SW control led0 on.*/
+	pled->ledon = true;
+}
+
+void rtl8821ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	u8 ledcfg;
+
+	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
+
+	ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+
+	switch (pled->ledpin) {
+	case LED_PIN_GPIO0:
+		break;
+	case LED_PIN_LED0:
+		ledcfg &= 0xf0;
+		if (pcipriv->ledctl.led_opendrain) {
+			ledcfg &= 0x90; /* Set to software control. */
+			rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg|BIT(3)));
+			ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG);
+			ledcfg &= 0xFE;
+			rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg);
+		} else {
+			ledcfg &= ~BIT(6);
+			rtl_write_byte(rtlpriv, REG_LEDCFG2,
+				       (ledcfg | BIT(3) | BIT(5)));
+		}
+		break;
+	case LED_PIN_LED1:
+		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
+		ledcfg &= 0x10; /* Set to software control. */
+		rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg|BIT(3));
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+			 "switch case not process\n");
+		break;
+	}
+	pled->ledon = false;
+}
+
+void rtl8812ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+	u16 ledreg = REG_LEDCFG1;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+
+	switch (pled->ledpin) {
+	case LED_PIN_LED0:
+		ledreg = REG_LEDCFG1;
+		break;
+
+	case LED_PIN_LED1:
+		ledreg = REG_LEDCFG2;
+		break;
+
+	case LED_PIN_GPIO0:
+	default:
+		break;
+	}
+
+	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+		 "In SwLedOff,LedAddr:%X LEDPIN=%d\n",
+		 ledreg, pled->ledpin);
+	/*Open-drain arrangement for controlling the LED*/
+	if (pcipriv->ledctl.led_opendrain) {
+		u8 ledcfg = rtl_read_byte(rtlpriv, ledreg);
+
+		ledreg &= 0xd0; /* Set to software control.*/
+		rtl_write_byte(rtlpriv, ledreg, (ledcfg | BIT(3)));
+
+		/*Open-drain arrangement*/
+		ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG);
+		ledcfg &= 0xFE;/*Set GPIO[8] to input mode*/
+		rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg);
+	} else {
+		rtl_write_byte(rtlpriv, ledreg, 0x28);
+	}
+
+	pled->ledon = false;
+}
+
+void rtl8821ae_init_sw_leds(struct ieee80211_hw *hw)
+{
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+
+	_rtl8821ae_init_led(hw, &pcipriv->ledctl.sw_led0, LED_PIN_LED0);
+	_rtl8821ae_init_led(hw, &pcipriv->ledctl.sw_led1, LED_PIN_LED1);
+}
+
+static void _rtl8821ae_sw_led_control(struct ieee80211_hw *hw,
+				      enum led_ctl_mode ledaction)
+{
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	struct rtl_led *pLed0 = &pcipriv->ledctl.sw_led0;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+	switch (ledaction) {
+	case LED_CTL_POWER_ON:
+	case LED_CTL_LINK:
+	case LED_CTL_NO_LINK:
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+			rtl8812ae_sw_led_on(hw, pLed0);
+		else
+			rtl8821ae_sw_led_on(hw, pLed0);
+		break;
+	case LED_CTL_POWER_OFF:
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+			rtl8812ae_sw_led_off(hw, pLed0);
+		else
+			rtl8821ae_sw_led_off(hw, pLed0);
+		break;
+	default:
+		break;
+	}
+}
+
+void rtl8821ae_led_control(struct ieee80211_hw *hw,
+			   enum led_ctl_mode ledaction)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+	if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) &&
+	    (ledaction == LED_CTL_TX ||
+	     ledaction == LED_CTL_RX ||
+	     ledaction == LED_CTL_SITE_SURVEY ||
+	     ledaction == LED_CTL_LINK ||
+	     ledaction == LED_CTL_NO_LINK ||
+	     ledaction == LED_CTL_START_TO_LINK ||
+	     ledaction == LED_CTL_POWER_ON)) {
+		return;
+	}
+	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d,\n",
+		 ledaction);
+	_rtl8821ae_sw_led_control(hw, ledaction);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/led.h b/drivers/net/wireless/rtlwifi/rtl8821ae/led.h
new file mode 100644
index 0000000..038e64e
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/led.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8821AE_LED_H__
+#define __RTL8821AE_LED_H__
+
+void rtl8821ae_init_sw_leds(struct ieee80211_hw *hw);
+void rtl8821ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl8812ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl8821ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl8812ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl8821ae_led_control(struct ieee80211_hw *hw,
+			   enum led_ctl_mode ledaction);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8821ae/phy.c
new file mode 100644
index 0000000..9786313
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/phy.c
@@ -0,0 +1,4855 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../ps.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+#include "table.h"
+#include "trx.h"
+#include "../btcoexist/halbt_precomp.h"
+#include "hw.h"
+#include "../efuse.h"
+
+#define READ_NEXT_PAIR(array_table, v1, v2, i) \
+	do { \
+		i += 2; \
+		v1 = array_table[i]; \
+		v2 = array_table[i+1]; \
+	} while (0)
+
+static u32 _rtl8821ae_phy_rf_serial_read(struct ieee80211_hw *hw,
+					 enum radio_path rfpath, u32 offset);
+static void _rtl8821ae_phy_rf_serial_write(struct ieee80211_hw *hw,
+					   enum radio_path rfpath, u32 offset,
+					   u32 data);
+static u32 _rtl8821ae_phy_calculate_bit_shift(u32 bitmask);
+static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw);
+/*static bool _rtl8812ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);*/
+static bool _rtl8821ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
+static bool _rtl8821ae_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+						     u8 configtype);
+static bool _rtl8821ae_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+						       u8 configtype);
+static void phy_init_bb_rf_register_definition(struct ieee80211_hw *hw);
+
+static long _rtl8821ae_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+					    enum wireless_mode wirelessmode,
+					    u8 txpwridx);
+static void rtl8821ae_phy_set_rf_on(struct ieee80211_hw *hw);
+static void rtl8821ae_phy_set_io(struct ieee80211_hw *hw);
+
+static void rtl8812ae_fixspur(struct ieee80211_hw *hw,
+			      enum ht_channel_width band_width, u8 channel)
+{
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+	/*C cut Item12 ADC FIFO CLOCK*/
+	if (IS_VENDOR_8812A_C_CUT(rtlhal->version)) {
+		if (band_width == HT_CHANNEL_WIDTH_20_40 && channel == 11)
+			rtl_set_bbreg(hw, RRFMOD, 0xC00, 0x3);
+			/* 0x8AC[11:10] = 2'b11*/
+		else
+			rtl_set_bbreg(hw, RRFMOD, 0xC00, 0x2);
+			/* 0x8AC[11:10] = 2'b10*/
+
+		/* <20120914, Kordan> A workarould to resolve
+		 * 2480Mhz spur by setting ADC clock as 160M. (Asked by Binson)
+		 */
+		if (band_width == HT_CHANNEL_WIDTH_20 &&
+		    (channel == 13 || channel == 14)) {
+			rtl_set_bbreg(hw, RRFMOD, 0x300, 0x3);
+			/*0x8AC[9:8] = 2'b11*/
+			rtl_set_bbreg(hw, RADC_BUF_CLK, BIT(30), 1);
+			/* 0x8C4[30] = 1*/
+		} else if (band_width == HT_CHANNEL_WIDTH_20_40 &&
+			   channel == 11) {
+			rtl_set_bbreg(hw, RADC_BUF_CLK, BIT(30), 1);
+			/*0x8C4[30] = 1*/
+		} else if (band_width != HT_CHANNEL_WIDTH_80) {
+			rtl_set_bbreg(hw, RRFMOD, 0x300, 0x2);
+			/*0x8AC[9:8] = 2'b10*/
+			rtl_set_bbreg(hw, RADC_BUF_CLK, BIT(30), 0);
+			/*0x8C4[30] = 0*/
+		}
+	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+		/* <20120914, Kordan> A workarould to resolve
+		 * 2480Mhz spur by setting ADC clock as 160M.
+		 */
+		if (band_width == HT_CHANNEL_WIDTH_20 &&
+		    (channel == 13 || channel == 14))
+			rtl_set_bbreg(hw, RRFMOD, 0x300, 0x3);
+			/*0x8AC[9:8] = 11*/
+		else if (channel  <= 14) /*2.4G only*/
+			rtl_set_bbreg(hw, RRFMOD, 0x300, 0x2);
+			/*0x8AC[9:8] = 10*/
+	}
+}
+
+u32 rtl8821ae_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
+			       u32 bitmask)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 returnvalue, originalvalue, bitshift;
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), bitmask(%#x)\n",
+		 regaddr, bitmask);
+	originalvalue = rtl_read_dword(rtlpriv, regaddr);
+	bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask);
+	returnvalue = (originalvalue & bitmask) >> bitshift;
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "BBR MASK=0x%x Addr[0x%x]=0x%x\n",
+		 bitmask, regaddr, originalvalue);
+	return returnvalue;
+}
+
+void rtl8821ae_phy_set_bb_reg(struct ieee80211_hw *hw,
+			      u32 regaddr, u32 bitmask, u32 data)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 originalvalue, bitshift;
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), bitmask(%#x), data(%#x)\n",
+		 regaddr, bitmask, data);
+
+	if (bitmask != MASKDWORD) {
+		originalvalue = rtl_read_dword(rtlpriv, regaddr);
+		bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask);
+		data = ((originalvalue & (~bitmask)) |
+			((data << bitshift) & bitmask));
+	}
+
+	rtl_write_dword(rtlpriv, regaddr, data);
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), bitmask(%#x), data(%#x)\n",
+		 regaddr, bitmask, data);
+}
+
+u32 rtl8821ae_phy_query_rf_reg(struct ieee80211_hw *hw,
+			       enum radio_path rfpath, u32 regaddr,
+			       u32 bitmask)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 original_value, readback_value, bitshift;
+	unsigned long flags;
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
+		 regaddr, rfpath, bitmask);
+
+	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+	original_value = _rtl8821ae_phy_rf_serial_read(hw, rfpath, regaddr);
+	bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask);
+	readback_value = (original_value & bitmask) >> bitshift;
+
+	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
+		 regaddr, rfpath, bitmask, original_value);
+
+	return readback_value;
+}
+
+void rtl8821ae_phy_set_rf_reg(struct ieee80211_hw *hw,
+			   enum radio_path rfpath,
+			   u32 regaddr, u32 bitmask, u32 data)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 original_value, bitshift;
+	unsigned long flags;
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+		  regaddr, bitmask, data, rfpath);
+
+	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+	if (bitmask != RFREG_OFFSET_MASK) {
+		original_value =
+		   _rtl8821ae_phy_rf_serial_read(hw, rfpath, regaddr);
+		bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask);
+		data = ((original_value & (~bitmask)) | (data << bitshift));
+	}
+
+	_rtl8821ae_phy_rf_serial_write(hw, rfpath, regaddr, data);
+
+	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+		 regaddr, bitmask, data, rfpath);
+}
+
+static u32 _rtl8821ae_phy_rf_serial_read(struct ieee80211_hw *hw,
+					 enum radio_path rfpath, u32 offset)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	bool is_pi_mode = false;
+	u32 retvalue = 0;
+
+	/* 2009/06/17 MH We can not execute IO for power
+	save or other accident mode.*/
+	if (RT_CANNOT_IO(hw)) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
+		return 0xFFFFFFFF;
+	}
+	/* <20120809, Kordan> CCA OFF(when entering),
+		asked by James to avoid reading the wrong value.
+	    <20120828, Kordan> Toggling CCA would affect RF 0x0, skip it!*/
+	if (offset != 0x0 &&
+	    !((rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) ||
+	    (IS_VENDOR_8812A_C_CUT(rtlhal->version))))
+		rtl_set_bbreg(hw, RCCAONSEC, 0x8, 1);
+	offset &= 0xff;
+
+	if (rfpath == RF90_PATH_A)
+		is_pi_mode = (bool)rtl_get_bbreg(hw, 0xC00, 0x4);
+	else if (rfpath == RF90_PATH_B)
+		is_pi_mode = (bool)rtl_get_bbreg(hw, 0xE00, 0x4);
+
+	rtl_set_bbreg(hw, RHSSIREAD_8821AE, 0xff, offset);
+
+	if ((rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) ||
+	    (IS_VENDOR_8812A_C_CUT(rtlhal->version)))
+		udelay(20);
+
+	if (is_pi_mode) {
+		if (rfpath == RF90_PATH_A)
+			retvalue =
+			  rtl_get_bbreg(hw, RA_PIREAD_8821A, BLSSIREADBACKDATA);
+		else if (rfpath == RF90_PATH_B)
+			retvalue =
+			  rtl_get_bbreg(hw, RB_PIREAD_8821A, BLSSIREADBACKDATA);
+	} else {
+		if (rfpath == RF90_PATH_A)
+			retvalue =
+			  rtl_get_bbreg(hw, RA_SIREAD_8821A, BLSSIREADBACKDATA);
+		else if (rfpath == RF90_PATH_B)
+			retvalue =
+			  rtl_get_bbreg(hw, RB_SIREAD_8821A, BLSSIREADBACKDATA);
+	}
+
+	/*<20120809, Kordan> CCA ON(when exiting),
+	 * asked by James to avoid reading the wrong value.
+	 *   <20120828, Kordan> Toggling CCA would affect RF 0x0, skip it!
+	 */
+	if (offset != 0x0 &&
+	    !((rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) ||
+	    (IS_VENDOR_8812A_C_CUT(rtlhal->version))))
+		rtl_set_bbreg(hw, RCCAONSEC, 0x8, 0);
+	return retvalue;
+}
+
+static void _rtl8821ae_phy_rf_serial_write(struct ieee80211_hw *hw,
+					   enum radio_path rfpath, u32 offset,
+					   u32 data)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+	u32 data_and_addr;
+	u32 newoffset;
+
+	if (RT_CANNOT_IO(hw)) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
+		return;
+	}
+	offset &= 0xff;
+	newoffset = offset;
+	data_and_addr = ((newoffset << 20) |
+			 (data & 0x000fffff)) & 0x0fffffff;
+	rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
+	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+		 "RFW-%d Addr[0x%x]=0x%x\n",
+		 rfpath, pphyreg->rf3wire_offset, data_and_addr);
+}
+
+static u32 _rtl8821ae_phy_calculate_bit_shift(u32 bitmask)
+{
+	u32 i;
+
+	for (i = 0; i <= 31; i++) {
+		if (((bitmask >> i) & 0x1) == 1)
+			break;
+	}
+	return i;
+}
+
+bool rtl8821ae_phy_mac_config(struct ieee80211_hw *hw)
+{
+	bool rtstatus = 0;
+
+	rtstatus = _rtl8821ae_phy_config_mac_with_headerfile(hw);
+
+	return rtstatus;
+}
+
+bool rtl8821ae_phy_bb_config(struct ieee80211_hw *hw)
+{
+	bool rtstatus = true;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 regval;
+	u8 crystal_cap;
+
+	phy_init_bb_rf_register_definition(hw);
+
+	regval = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN);
+	regval |= FEN_PCIEA;
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, regval);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN,
+		       regval | FEN_BB_GLB_RSTN | FEN_BBRSTB);
+
+	rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x7);
+	rtl_write_byte(rtlpriv, REG_OPT_CTRL + 2, 0x7);
+
+	rtstatus = _rtl8821ae_phy_bb8821a_config_parafile(hw);
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+		crystal_cap = rtlefuse->crystalcap & 0x3F;
+		rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0x7FF80000,
+			      (crystal_cap | (crystal_cap << 6)));
+	} else {
+		crystal_cap = rtlefuse->crystalcap & 0x3F;
+		rtl_set_bbreg(hw, REG_MAC_PHY_CTRL, 0xFFF000,
+			      (crystal_cap | (crystal_cap << 6)));
+	}
+	rtlphy->reg_837 = rtl_read_byte(rtlpriv, 0x837);
+
+	return rtstatus;
+}
+
+bool rtl8821ae_phy_rf_config(struct ieee80211_hw *hw)
+{
+	return rtl8821ae_phy_rf6052_config(hw);
+}
+
+u32 phy_get_tx_swing_8812A(struct ieee80211_hw *hw, u8	band,
+			   u8 rf_path)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_dm *rtldm = rtl_dm(rtlpriv);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	char reg_swing_2g = -1;/* 0xff; */
+	char reg_swing_5g = -1;/* 0xff; */
+	char swing_2g = -1 * reg_swing_2g;
+	char swing_5g = -1 * reg_swing_5g;
+	u32  out = 0x200;
+	const char auto_temp = -1;
+
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD,
+		 "===> PHY_GetTxBBSwing_8812A, bbSwing_2G: %d, bbSwing_5G: %d,autoload_failflag=%d.\n",
+		 (int)swing_2g, (int)swing_5g,
+		 (int)rtlefuse->autoload_failflag);
+
+	if (rtlefuse->autoload_failflag) {
+		if (band == BAND_ON_2_4G) {
+			rtldm->swing_diff_2g = swing_2g;
+			if (swing_2g == 0) {
+				out = 0x200; /* 0 dB */
+			} else if (swing_2g == -3) {
+				out = 0x16A; /* -3 dB */
+			} else if (swing_2g == -6) {
+				out = 0x101; /* -6 dB */
+			} else if (swing_2g == -9) {
+				out = 0x0B6; /* -9 dB */
+			} else {
+				rtldm->swing_diff_2g = 0;
+				out = 0x200;
+			}
+		} else if (band == BAND_ON_5G) {
+			rtldm->swing_diff_5g = swing_5g;
+			if (swing_5g == 0) {
+				out = 0x200; /* 0 dB */
+			} else if (swing_5g == -3) {
+				out = 0x16A; /* -3 dB */
+			} else if (swing_5g == -6) {
+				out = 0x101; /* -6 dB */
+			} else if (swing_5g == -9) {
+				out = 0x0B6; /* -9 dB */
+			} else {
+				if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+					rtldm->swing_diff_5g = -3;
+					out = 0x16A;
+				} else {
+					rtldm->swing_diff_5g = 0;
+					out = 0x200;
+				}
+			}
+		} else {
+			rtldm->swing_diff_2g = -3;
+			rtldm->swing_diff_5g = -3;
+			out = 0x16A; /* -3 dB */
+		}
+	} else {
+	    u32 swing = 0, swing_a = 0, swing_b = 0;
+
+	    if (band == BAND_ON_2_4G) {
+			if (reg_swing_2g == auto_temp) {
+				efuse_shadow_read(hw, 1, 0xC6, (u32 *)&swing);
+				swing = (swing == 0xFF) ? 0x00 : swing;
+			} else if (swing_2g ==  0) {
+				swing = 0x00; /* 0 dB */
+			} else if (swing_2g == -3) {
+				swing = 0x05; /* -3 dB */
+			} else if (swing_2g == -6) {
+				swing = 0x0A; /* -6 dB */
+			} else if (swing_2g == -9) {
+				swing = 0xFF; /* -9 dB */
+			} else {
+				swing = 0x00;
+			}
+		} else {
+			if (reg_swing_5g == auto_temp) {
+				efuse_shadow_read(hw, 1, 0xC7, (u32 *)&swing);
+				swing = (swing == 0xFF) ? 0x00 : swing;
+			} else if (swing_5g ==  0) {
+				swing = 0x00; /* 0 dB */
+			} else if (swing_5g == -3) {
+				swing = 0x05; /* -3 dB */
+			} else if (swing_5g == -6) {
+				swing = 0x0A; /* -6 dB */
+			} else if (swing_5g == -9) {
+				swing = 0xFF; /* -9 dB */
+			} else {
+				swing = 0x00;
+			}
+		}
+
+		swing_a = (swing & 0x3) >> 0; /* 0xC6/C7[1:0] */
+		swing_b = (swing & 0xC) >> 2; /* 0xC6/C7[3:2] */
+		RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD,
+			 "===> PHY_GetTxBBSwing_8812A, swingA: 0x%X, swingB: 0x%X\n",
+			 swing_a, swing_b);
+
+		/* 3 Path-A */
+		if (swing_a == 0x0) {
+			if (band == BAND_ON_2_4G)
+				rtldm->swing_diff_2g = 0;
+			else
+				rtldm->swing_diff_5g = 0;
+			out = 0x200; /* 0 dB */
+		} else if (swing_a == 0x1) {
+			if (band == BAND_ON_2_4G)
+				rtldm->swing_diff_2g = -3;
+			else
+				rtldm->swing_diff_5g = -3;
+			out = 0x16A; /* -3 dB */
+		} else if (swing_a == 0x2) {
+			if (band == BAND_ON_2_4G)
+				rtldm->swing_diff_2g = -6;
+			else
+				rtldm->swing_diff_5g = -6;
+			out = 0x101; /* -6 dB */
+		} else if (swing_a == 0x3) {
+			if (band == BAND_ON_2_4G)
+				rtldm->swing_diff_2g = -9;
+			else
+				rtldm->swing_diff_5g = -9;
+			out = 0x0B6; /* -9 dB */
+		}
+		/* 3 Path-B */
+		if (swing_b == 0x0) {
+			if (band == BAND_ON_2_4G)
+				rtldm->swing_diff_2g = 0;
+			else
+				rtldm->swing_diff_5g = 0;
+			out = 0x200; /* 0 dB */
+		} else if (swing_b == 0x1) {
+			if (band == BAND_ON_2_4G)
+				rtldm->swing_diff_2g = -3;
+			else
+				rtldm->swing_diff_5g = -3;
+			out = 0x16A; /* -3 dB */
+		} else if (swing_b == 0x2) {
+			if (band == BAND_ON_2_4G)
+				rtldm->swing_diff_2g = -6;
+			else
+				rtldm->swing_diff_5g = -6;
+			out = 0x101; /* -6 dB */
+		} else if (swing_b == 0x3) {
+			if (band == BAND_ON_2_4G)
+				rtldm->swing_diff_2g = -9;
+			else
+				rtldm->swing_diff_5g = -9;
+			out = 0x0B6; /* -9 dB */
+		}
+	}
+
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD,
+		 "<=== PHY_GetTxBBSwing_8812A, out = 0x%X\n", out);
+	 return out;
+}
+
+void rtl8821ae_phy_switch_wirelessband(struct ieee80211_hw *hw, u8 band)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_dm *rtldm = rtl_dm(rtlpriv);
+	u8 current_band = rtlhal->current_bandtype;
+	u32 txpath, rxpath;
+	char bb_diff_between_band;
+
+	txpath = rtl8821ae_phy_query_bb_reg(hw, RTXPATH, 0xf0);
+	rxpath = rtl8821ae_phy_query_bb_reg(hw, RCCK_RX, 0x0f000000);
+	rtlhal->current_bandtype = (enum band_type) band;
+	/* reconfig BB/RF according to wireless mode */
+	if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+		/* BB & RF Config */
+		rtl_set_bbreg(hw, ROFDMCCKEN, BOFDMEN|BCCKEN, 0x03);
+
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+			/* 0xCB0[15:12] = 0x7 (LNA_On)*/
+			rtl_set_bbreg(hw, RA_RFE_PINMUX, 0xF000, 0x7);
+			/* 0xCB0[7:4] = 0x7 (PAPE_A)*/
+			rtl_set_bbreg(hw, RA_RFE_PINMUX, 0xF0, 0x7);
+		}
+
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+			/*0x834[1:0] = 0x1*/
+			rtl_set_bbreg(hw, 0x834, 0x3, 0x1);
+		}
+
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+			/* 0xC1C[11:8] = 0 */
+			rtl_set_bbreg(hw, RA_TXSCALE, 0xF00, 0);
+		} else {
+			/* 0x82C[1:0] = 2b'00 */
+			rtl_set_bbreg(hw, 0x82c, 0x3, 0);
+		}
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+			rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD,
+				      0x77777777);
+			rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD,
+				      0x77777777);
+			rtl_set_bbreg(hw, RA_RFE_INV, 0x3ff00000, 0x000);
+			rtl_set_bbreg(hw, RB_RFE_INV, 0x3ff00000, 0x000);
+		}
+
+		rtl_set_bbreg(hw, RTXPATH, 0xf0, 0x1);
+		rtl_set_bbreg(hw, RCCK_RX, 0x0f000000, 0x1);
+
+		rtl_write_byte(rtlpriv, REG_CCK_CHECK, 0x0);
+	} else {/* 5G band */
+		u16 count, reg_41a;
+
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+			/*0xCB0[15:12] = 0x5 (LNA_On)*/
+			rtl_set_bbreg(hw, RA_RFE_PINMUX, 0xF000, 0x5);
+			/*0xCB0[7:4] = 0x4 (PAPE_A)*/
+			rtl_set_bbreg(hw, RA_RFE_PINMUX, 0xF0, 0x4);
+		}
+		/*CCK_CHECK_en*/
+		rtl_write_byte(rtlpriv, REG_CCK_CHECK, 0x80);
+
+		count = 0;
+		reg_41a = rtl_read_word(rtlpriv, REG_TXPKT_EMPTY);
+		RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD,
+			 "Reg41A value %d", reg_41a);
+		reg_41a &= 0x30;
+		while ((reg_41a != 0x30) && (count < 50)) {
+			udelay(50);
+			RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, "Delay 50us\n");
+
+			reg_41a = rtl_read_word(rtlpriv, REG_TXPKT_EMPTY);
+			reg_41a &= 0x30;
+			count++;
+			RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD,
+				 "Reg41A value %d", reg_41a);
+		}
+		if (count != 0)
+			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+				 "PHY_SwitchWirelessBand8812(): Switch to 5G Band. Count = %d reg41A=0x%x\n",
+				 count, reg_41a);
+
+		/* 2012/02/01, Sinda add registry to switch workaround
+		without long-run verification for scan issue. */
+		rtl_set_bbreg(hw, ROFDMCCKEN, BOFDMEN|BCCKEN, 0x03);
+
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+			/*0x834[1:0] = 0x2*/
+			rtl_set_bbreg(hw, 0x834, 0x3, 0x2);
+		}
+
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+			/* AGC table select */
+			/* 0xC1C[11:8] = 1*/
+			rtl_set_bbreg(hw, RA_TXSCALE, 0xF00, 1);
+		} else
+			/* 0x82C[1:0] = 2'b00 */
+			rtl_set_bbreg(hw, 0x82c, 0x3, 1);
+
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+			rtl_set_bbreg(hw, RA_RFE_PINMUX, BMASKDWORD,
+				      0x77337777);
+			rtl_set_bbreg(hw, RB_RFE_PINMUX, BMASKDWORD,
+				      0x77337777);
+			rtl_set_bbreg(hw, RA_RFE_INV, 0x3ff00000, 0x010);
+			rtl_set_bbreg(hw, RB_RFE_INV, 0x3ff00000, 0x010);
+		}
+
+		rtl_set_bbreg(hw, RTXPATH, 0xf0, 0);
+		rtl_set_bbreg(hw, RCCK_RX, 0x0f000000, 0xf);
+
+		RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD,
+			 "==>PHY_SwitchWirelessBand8812() BAND_ON_5G settings OFDM index 0x%x\n",
+			 rtlpriv->dm.ofdm_index[RF90_PATH_A]);
+	}
+
+	if ((rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) ||
+	    (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)) {
+		/* 0xC1C[31:21] */
+		rtl_set_bbreg(hw, RA_TXSCALE, 0xFFE00000,
+			      phy_get_tx_swing_8812A(hw, band, RF90_PATH_A));
+		/* 0xE1C[31:21] */
+		rtl_set_bbreg(hw, RB_TXSCALE, 0xFFE00000,
+			      phy_get_tx_swing_8812A(hw, band, RF90_PATH_B));
+
+		/* <20121005, Kordan> When TxPowerTrack is ON,
+		 *	we should take care of the change of BB swing.
+		 *   That is, reset all info to trigger Tx power tracking.
+		 */
+		if (band != current_band) {
+			bb_diff_between_band =
+				(rtldm->swing_diff_2g - rtldm->swing_diff_5g);
+			bb_diff_between_band = (band == BAND_ON_2_4G) ?
+						bb_diff_between_band :
+						(-1 * bb_diff_between_band);
+			rtldm->default_ofdm_index += bb_diff_between_band * 2;
+		}
+		rtl8821ae_dm_clear_txpower_tracking_state(hw);
+	}
+
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+		 "<==rtl8821ae_phy_switch_wirelessband():Switch Band OK.\n");
+	return;
+}
+
+static bool _rtl8821ae_check_condition(struct ieee80211_hw *hw,
+				       const u32 condition)
+{
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	u32 _board = rtlefuse->board_type; /*need efuse define*/
+	u32 _interface = 0x01; /* ODM_ITRF_PCIE */
+	u32 _platform = 0x08;/* ODM_WIN */
+	u32 cond = condition;
+
+	if (condition == 0xCDCDCDCD)
+		return true;
+
+	cond = condition & 0xFF;
+	if ((_board != cond) && cond != 0xFF)
+		return false;
+
+	cond = condition & 0xFF00;
+	cond = cond >> 8;
+	if ((_interface & cond) == 0 && cond != 0x07)
+		return false;
+
+	cond = condition & 0xFF0000;
+	cond = cond >> 16;
+	if ((_platform & cond) == 0 && cond != 0x0F)
+		return false;
+	return true;
+}
+
+static void _rtl8821ae_config_rf_reg(struct ieee80211_hw *hw,
+				     u32 addr, u32 data,
+				     enum radio_path rfpath, u32 regaddr)
+{
+	if (addr == 0xfe || addr == 0xffe) {
+		/* In order not to disturb BT music when
+		 * wifi init.(1ant NIC only)
+		 */
+		mdelay(50);
+	} else {
+		rtl_set_rfreg(hw, rfpath, regaddr, RFREG_OFFSET_MASK, data);
+		udelay(1);
+	}
+}
+
+static void _rtl8821ae_config_rf_radio_a(struct ieee80211_hw *hw,
+					 u32 addr, u32 data)
+{
+	u32 content = 0x1000; /*RF Content: radio_a_txt*/
+	u32 maskforphyset = (u32)(content & 0xE000);
+
+	_rtl8821ae_config_rf_reg(hw, addr, data,
+				 RF90_PATH_A, addr | maskforphyset);
+}
+
+static void _rtl8821ae_config_rf_radio_b(struct ieee80211_hw *hw,
+					 u32 addr, u32 data)
+{
+	u32 content = 0x1001; /*RF Content: radio_b_txt*/
+	u32 maskforphyset = (u32)(content & 0xE000);
+
+	_rtl8821ae_config_rf_reg(hw, addr, data,
+				 RF90_PATH_B, addr | maskforphyset);
+}
+
+static void _rtl8821ae_config_bb_reg(struct ieee80211_hw *hw,
+				     u32 addr, u32 data)
+{
+	if (addr == 0xfe)
+		mdelay(50);
+	else if (addr == 0xfd)
+		mdelay(5);
+	else if (addr == 0xfc)
+		mdelay(1);
+	else if (addr == 0xfb)
+		udelay(50);
+	else if (addr == 0xfa)
+		udelay(5);
+	else if (addr == 0xf9)
+		udelay(1);
+	else
+		rtl_set_bbreg(hw, addr, MASKDWORD, data);
+
+	udelay(1);
+}
+
+static void _rtl8821ae_phy_init_tx_power_by_rate(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 band, rfpath, txnum, rate_section;
+
+	for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band)
+		for (rfpath = 0; rfpath < TX_PWR_BY_RATE_NUM_RF; ++rfpath)
+			for (txnum = 0; txnum < TX_PWR_BY_RATE_NUM_RF; ++txnum)
+				for (rate_section = 0;
+				     rate_section < TX_PWR_BY_RATE_NUM_SECTION;
+				     ++rate_section)
+					rtlphy->tx_power_by_rate_offset[band]
+					    [rfpath][txnum][rate_section] = 0;
+}
+
+static void _rtl8821ae_phy_set_txpower_by_rate_base(struct ieee80211_hw *hw,
+					  u8 band, u8 path,
+					  u8 rate_section,
+					  u8 txnum, u8 value)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	if (path > RF90_PATH_D) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			"Invalid Rf Path %d in phy_SetTxPowerByRatBase()\n", path);
+		return;
+	}
+
+	if (band == BAND_ON_2_4G) {
+		switch (rate_section) {
+		case CCK:
+			rtlphy->txpwr_by_rate_base_24g[path][txnum][0] = value;
+			break;
+		case OFDM:
+			rtlphy->txpwr_by_rate_base_24g[path][txnum][1] = value;
+			break;
+		case HT_MCS0_MCS7:
+			rtlphy->txpwr_by_rate_base_24g[path][txnum][2] = value;
+			break;
+		case HT_MCS8_MCS15:
+			rtlphy->txpwr_by_rate_base_24g[path][txnum][3] = value;
+			break;
+		case VHT_1SSMCS0_1SSMCS9:
+			rtlphy->txpwr_by_rate_base_24g[path][txnum][4] = value;
+			break;
+		case VHT_2SSMCS0_2SSMCS9:
+			rtlphy->txpwr_by_rate_base_24g[path][txnum][5] = value;
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "Invalid RateSection %d in Band 2.4G,Rf Path %d, %dTx in PHY_SetTxPowerByRateBase()\n",
+				 rate_section, path, txnum);
+			break;
+		};
+	} else if (band == BAND_ON_5G) {
+		switch (rate_section) {
+		case OFDM:
+			rtlphy->txpwr_by_rate_base_5g[path][txnum][0] = value;
+			break;
+		case HT_MCS0_MCS7:
+			rtlphy->txpwr_by_rate_base_5g[path][txnum][1] = value;
+			break;
+		case HT_MCS8_MCS15:
+			rtlphy->txpwr_by_rate_base_5g[path][txnum][2] = value;
+			break;
+		case VHT_1SSMCS0_1SSMCS9:
+			rtlphy->txpwr_by_rate_base_5g[path][txnum][3] = value;
+			break;
+		case VHT_2SSMCS0_2SSMCS9:
+			rtlphy->txpwr_by_rate_base_5g[path][txnum][4] = value;
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				"Invalid RateSection %d in Band 5G, Rf Path %d, %dTx in PHY_SetTxPowerByRateBase()\n",
+				rate_section, path, txnum);
+			break;
+		};
+	} else {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			"Invalid Band %d in PHY_SetTxPowerByRateBase()\n", band);
+	}
+}
+
+static u8 _rtl8821ae_phy_get_txpower_by_rate_base(struct ieee80211_hw *hw,
+						  u8 band, u8 path,
+						  u8 txnum, u8 rate_section)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 value = 0;
+
+	if (path > RF90_PATH_D) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Invalid Rf Path %d in PHY_GetTxPowerByRateBase()\n",
+			 path);
+		return 0;
+	}
+
+	if (band == BAND_ON_2_4G) {
+		switch (rate_section) {
+		case CCK:
+			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][0];
+			break;
+		case OFDM:
+			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][1];
+			break;
+		case HT_MCS0_MCS7:
+			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][2];
+			break;
+		case HT_MCS8_MCS15:
+			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][3];
+			break;
+		case VHT_1SSMCS0_1SSMCS9:
+			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][4];
+			break;
+		case VHT_2SSMCS0_2SSMCS9:
+			value = rtlphy->txpwr_by_rate_base_24g[path][txnum][5];
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "Invalid RateSection %d in Band 2.4G, Rf Path %d, %dTx in PHY_GetTxPowerByRateBase()\n",
+				 rate_section, path, txnum);
+			break;
+		};
+	} else if (band == BAND_ON_5G) {
+		switch (rate_section) {
+		case OFDM:
+			value = rtlphy->txpwr_by_rate_base_5g[path][txnum][0];
+			break;
+		case HT_MCS0_MCS7:
+			value = rtlphy->txpwr_by_rate_base_5g[path][txnum][1];
+			break;
+		case HT_MCS8_MCS15:
+			value = rtlphy->txpwr_by_rate_base_5g[path][txnum][2];
+			break;
+		case VHT_1SSMCS0_1SSMCS9:
+			value = rtlphy->txpwr_by_rate_base_5g[path][txnum][3];
+			break;
+		case VHT_2SSMCS0_2SSMCS9:
+			value = rtlphy->txpwr_by_rate_base_5g[path][txnum][4];
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				 "Invalid RateSection %d in Band 5G, Rf Path %d, %dTx in PHY_GetTxPowerByRateBase()\n",
+				 rate_section, path, txnum);
+			break;
+		};
+	} else {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "Invalid Band %d in PHY_GetTxPowerByRateBase()\n", band);
+	}
+
+	return value;
+}
+
+static void _rtl8821ae_phy_store_txpower_by_rate_base(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u16 rawValue = 0;
+	u8 base = 0, path = 0;
+
+	for (path = RF90_PATH_A; path <= RF90_PATH_B; ++path) {
+		rawValue = (u16)(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_1TX][0] >> 24) & 0xFF;
+		base = (rawValue >> 4) * 10 + (rawValue & 0xF);
+		_rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, CCK, RF_1TX, base);
+
+		rawValue = (u16)(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_1TX][2] >> 24) & 0xFF;
+		base = (rawValue >> 4) * 10 + (rawValue & 0xF);
+		_rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, OFDM, RF_1TX, base);
+
+		rawValue = (u16)(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_1TX][4] >> 24) & 0xFF;
+		base = (rawValue >> 4) * 10 + (rawValue & 0xF);
+		_rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, HT_MCS0_MCS7, RF_1TX, base);
+
+		rawValue = (u16)(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_2TX][6] >> 24) & 0xFF;
+		base = (rawValue >> 4) * 10 + (rawValue & 0xF);
+		_rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, HT_MCS8_MCS15, RF_2TX, base);
+
+		rawValue = (u16)(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_1TX][8] >> 24) & 0xFF;
+		base = (rawValue >> 4) * 10 + (rawValue & 0xF);
+		_rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, VHT_1SSMCS0_1SSMCS9, RF_1TX, base);
+
+		rawValue = (u16)(rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][path][RF_2TX][11] >> 8) & 0xFF;
+		base = (rawValue >> 4) * 10 + (rawValue & 0xF);
+		_rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_2_4G, path, VHT_2SSMCS0_2SSMCS9, RF_2TX, base);
+
+		rawValue = (u16)(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][path][RF_1TX][2] >> 24) & 0xFF;
+		base = (rawValue >> 4) * 10 + (rawValue & 0xF);
+		_rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_5G, path, OFDM, RF_1TX, base);
+
+		rawValue = (u16)(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][path][RF_1TX][4] >> 24) & 0xFF;
+		base = (rawValue >> 4) * 10 + (rawValue & 0xF);
+		_rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_5G, path, HT_MCS0_MCS7, RF_1TX, base);
+
+		rawValue = (u16)(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][path][RF_2TX][6] >> 24) & 0xFF;
+		base = (rawValue >> 4) * 10 + (rawValue & 0xF);
+		_rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_5G, path, HT_MCS8_MCS15, RF_2TX, base);
+
+		rawValue = (u16)(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][path][RF_1TX][8] >> 24) & 0xFF;
+		base = (rawValue >> 4) * 10 + (rawValue & 0xF);
+		_rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_5G, path, VHT_1SSMCS0_1SSMCS9, RF_1TX, base);
+
+		rawValue = (u16)(rtlphy->tx_power_by_rate_offset[BAND_ON_5G][path][RF_2TX][11] >> 8) & 0xFF;
+		base = (rawValue >> 4) * 10 + (rawValue & 0xF);
+		_rtl8821ae_phy_set_txpower_by_rate_base(hw, BAND_ON_5G, path, VHT_2SSMCS0_2SSMCS9, RF_2TX, base);
+	}
+}
+
+static void _phy_convert_txpower_dbm_to_relative_value(u32 *data, u8 start,
+						u8 end, u8 base_val)
+{
+	char i = 0;
+	u8 temp_value = 0;
+	u32 temp_data = 0;
+
+	for (i = 3; i >= 0; --i) {
+		if (i >= start && i <= end) {
+			/* Get the exact value */
+			temp_value = (u8)(*data >> (i * 8)) & 0xF;
+			temp_value += ((u8)((*data >> (i * 8 + 4)) & 0xF)) * 10;
+
+			/* Change the value to a relative value */
+			temp_value = (temp_value > base_val) ? temp_value -
+					base_val : base_val - temp_value;
+		} else {
+			temp_value = (u8)(*data >> (i * 8)) & 0xFF;
+		}
+		temp_data <<= 8;
+		temp_data |= temp_value;
+	}
+	*data = temp_data;
+}
+
+static void _rtl8812ae_phy_cross_reference_ht_and_vht_txpower_limit(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 regulation, bw, channel, rate_section;
+	char temp_pwrlmt = 0;
+
+	for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) {
+		for (bw = 0; bw < MAX_5G_BANDWITH_NUM; ++bw) {
+			for (channel = 0; channel < CHANNEL_MAX_NUMBER_5G; ++channel) {
+				for (rate_section = 0; rate_section < MAX_RATE_SECTION_NUM; ++rate_section) {
+					temp_pwrlmt = rtlphy->txpwr_limit_5g[regulation]
+						[bw][rate_section][channel][RF90_PATH_A];
+					if (temp_pwrlmt == MAX_POWER_INDEX) {
+						if (bw == 0 || bw == 1) { /*5G 20M 40M VHT and HT can cross reference*/
+							RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+								"No power limit table of the specified band %d, bandwidth %d, ratesection %d, channel %d, rf path %d\n",
+								1, bw, rate_section, channel, RF90_PATH_A);
+							if (rate_section == 2) {
+								rtlphy->txpwr_limit_5g[regulation][bw][2][channel][RF90_PATH_A] =
+									rtlphy->txpwr_limit_5g[regulation][bw][4][channel][RF90_PATH_A];
+							} else if (rate_section == 4) {
+								rtlphy->txpwr_limit_5g[regulation][bw][4][channel][RF90_PATH_A] =
+									rtlphy->txpwr_limit_5g[regulation][bw][2][channel][RF90_PATH_A];
+							} else if (rate_section == 3) {
+								rtlphy->txpwr_limit_5g[regulation][bw][3][channel][RF90_PATH_A] =
+									rtlphy->txpwr_limit_5g[regulation][bw][5][channel][RF90_PATH_A];
+							} else if (rate_section == 5) {
+								rtlphy->txpwr_limit_5g[regulation][bw][5][channel][RF90_PATH_A] =
+									rtlphy->txpwr_limit_5g[regulation][bw][3][channel][RF90_PATH_A];
+							}
+
+							RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "use other value %d", temp_pwrlmt);
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+static u8 _rtl8812ae_phy_get_txpower_by_rate_base_index(struct ieee80211_hw *hw,
+						   enum band_type band, u8 rate)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 index = 0;
+	if (band == BAND_ON_2_4G) {
+		switch (rate) {
+		case MGN_1M:
+		case MGN_2M:
+		case MGN_5_5M:
+		case MGN_11M:
+			index = 0;
+			break;
+
+		case MGN_6M:
+		case MGN_9M:
+		case MGN_12M:
+		case MGN_18M:
+		case MGN_24M:
+		case MGN_36M:
+		case MGN_48M:
+		case MGN_54M:
+			index = 1;
+			break;
+
+		case MGN_MCS0:
+		case MGN_MCS1:
+		case MGN_MCS2:
+		case MGN_MCS3:
+		case MGN_MCS4:
+		case MGN_MCS5:
+		case MGN_MCS6:
+		case MGN_MCS7:
+			index = 2;
+			break;
+
+		case MGN_MCS8:
+		case MGN_MCS9:
+		case MGN_MCS10:
+		case MGN_MCS11:
+		case MGN_MCS12:
+		case MGN_MCS13:
+		case MGN_MCS14:
+		case MGN_MCS15:
+			index = 3;
+			break;
+
+		default:
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				"Wrong rate 0x%x to obtain index in 2.4G in PHY_GetTxPowerByRateBaseIndex()\n",
+				rate);
+			break;
+		}
+	} else if (band == BAND_ON_5G) {
+		switch (rate) {
+		case MGN_6M:
+		case MGN_9M:
+		case MGN_12M:
+		case MGN_18M:
+		case MGN_24M:
+		case MGN_36M:
+		case MGN_48M:
+		case MGN_54M:
+			index = 0;
+			break;
+
+		case MGN_MCS0:
+		case MGN_MCS1:
+		case MGN_MCS2:
+		case MGN_MCS3:
+		case MGN_MCS4:
+		case MGN_MCS5:
+		case MGN_MCS6:
+		case MGN_MCS7:
+			index = 1;
+			break;
+
+		case MGN_MCS8:
+		case MGN_MCS9:
+		case MGN_MCS10:
+		case MGN_MCS11:
+		case MGN_MCS12:
+		case MGN_MCS13:
+		case MGN_MCS14:
+		case MGN_MCS15:
+			index = 2;
+			break;
+
+		case MGN_VHT1SS_MCS0:
+		case MGN_VHT1SS_MCS1:
+		case MGN_VHT1SS_MCS2:
+		case MGN_VHT1SS_MCS3:
+		case MGN_VHT1SS_MCS4:
+		case MGN_VHT1SS_MCS5:
+		case MGN_VHT1SS_MCS6:
+		case MGN_VHT1SS_MCS7:
+		case MGN_VHT1SS_MCS8:
+		case MGN_VHT1SS_MCS9:
+			index = 3;
+			break;
+
+		case MGN_VHT2SS_MCS0:
+		case MGN_VHT2SS_MCS1:
+		case MGN_VHT2SS_MCS2:
+		case MGN_VHT2SS_MCS3:
+		case MGN_VHT2SS_MCS4:
+		case MGN_VHT2SS_MCS5:
+		case MGN_VHT2SS_MCS6:
+		case MGN_VHT2SS_MCS7:
+		case MGN_VHT2SS_MCS8:
+		case MGN_VHT2SS_MCS9:
+			index = 4;
+			break;
+
+		default:
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+				"Wrong rate 0x%x to obtain index in 5G in PHY_GetTxPowerByRateBaseIndex()\n",
+				rate);
+			break;
+		}
+	}
+
+	return index;
+}
+
+static void _rtl8812ae_phy_convert_txpower_limit_to_power_index(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 bw40_pwr_base_dbm2_4G, bw40_pwr_base_dbm5G;
+	u8 regulation, bw, channel, rate_section;
+	u8 base_index2_4G = 0;
+	u8 base_index5G = 0;
+	char temp_value = 0, temp_pwrlmt = 0;
+	u8 rf_path = 0;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+		"=====> _rtl8812ae_phy_convert_txpower_limit_to_power_index()\n");
+
+	_rtl8812ae_phy_cross_reference_ht_and_vht_txpower_limit(hw);
+
+	for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) {
+		for (bw = 0; bw < MAX_2_4G_BANDWITH_NUM; ++bw) {
+			for (channel = 0; channel < CHANNEL_MAX_NUMBER_2G; ++channel) {
+				for (rate_section = 0; rate_section < MAX_RATE_SECTION_NUM; ++rate_section) {
+					/* obtain the base dBm values in 2.4G band
+					 CCK => 11M, OFDM => 54M, HT 1T => MCS7, HT 2T => MCS15*/
+					if (rate_section == 0) { /*CCK*/
+						base_index2_4G =
+							_rtl8812ae_phy_get_txpower_by_rate_base_index(hw,
+							BAND_ON_2_4G, MGN_11M);
+					} else if (rate_section == 1) { /*OFDM*/
+						base_index2_4G =
+							_rtl8812ae_phy_get_txpower_by_rate_base_index(hw,
+							BAND_ON_2_4G, MGN_54M);
+					} else if (rate_section == 2) { /*HT IT*/
+						base_index2_4G =
+							_rtl8812ae_phy_get_txpower_by_rate_base_index(hw,
+							BAND_ON_2_4G, MGN_MCS7);
+					} else if (rate_section == 3) { /*HT 2T*/
+						base_index2_4G =
+							_rtl8812ae_phy_get_txpower_by_rate_base_index(hw,
+							BAND_ON_2_4G, MGN_MCS15);
+					}
+
+					temp_pwrlmt = rtlphy->txpwr_limit_2_4g[regulation]
+						[bw][rate_section][channel][RF90_PATH_A];
+
+					for (rf_path = RF90_PATH_A;
+						rf_path < MAX_RF_PATH_NUM;
+						++rf_path) {
+						if (rate_section == 3)
+							bw40_pwr_base_dbm2_4G =
+							rtlphy->txpwr_by_rate_base_24g[rf_path][RF_2TX][base_index2_4G];
+						else
+							bw40_pwr_base_dbm2_4G =
+							rtlphy->txpwr_by_rate_base_24g[rf_path][RF_1TX][base_index2_4G];
+
+						if (temp_pwrlmt != MAX_POWER_INDEX) {
+							temp_value = temp_pwrlmt - bw40_pwr_base_dbm2_4G;
+							rtlphy->txpwr_limit_2_4g[regulation]
+								[bw][rate_section][channel][rf_path] =
+								temp_value;
+						}
+
+						RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+							"TxPwrLimit_2_4G[regulation %d][bw %d][rateSection %d][channel %d] = %d\n(TxPwrLimit in dBm %d - BW40PwrLmt2_4G[channel %d][rfPath %d] %d)\n",
+							regulation, bw, rate_section, channel,
+							rtlphy->txpwr_limit_2_4g[regulation][bw]
+							[rate_section][channel][rf_path], (temp_pwrlmt == 63)
+							? 0 : temp_pwrlmt/2, channel, rf_path,
+							bw40_pwr_base_dbm2_4G);
+					}
+				}
+			}
+		}
+	}
+	for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) {
+		for (bw = 0; bw < MAX_5G_BANDWITH_NUM; ++bw) {
+			for (channel = 0; channel < CHANNEL_MAX_NUMBER_5G; ++channel) {
+				for (rate_section = 0; rate_section < MAX_RATE_SECTION_NUM; ++rate_section) {
+					/* obtain the base dBm values in 5G band
+					 OFDM => 54M, HT 1T => MCS7, HT 2T => MCS15,
+					VHT => 1SSMCS7, VHT 2T => 2SSMCS7*/
+					if (rate_section == 1) { /*OFDM*/
+						base_index5G =
+							_rtl8812ae_phy_get_txpower_by_rate_base_index(hw,
+							BAND_ON_5G, MGN_54M);
+					} else if (rate_section == 2) { /*HT 1T*/
+						base_index5G =
+							_rtl8812ae_phy_get_txpower_by_rate_base_index(hw,
+							BAND_ON_5G, MGN_MCS7);
+					} else if (rate_section == 3) { /*HT 2T*/
+						base_index5G =
+							_rtl8812ae_phy_get_txpower_by_rate_base_index(hw,
+							BAND_ON_5G, MGN_MCS15);
+					} else if (rate_section == 4) { /*VHT 1T*/
+						base_index5G =
+							_rtl8812ae_phy_get_txpower_by_rate_base_index(hw,
+							BAND_ON_5G, MGN_VHT1SS_MCS7);
+					} else if (rate_section == 5) { /*VHT 2T*/
+						base_index5G =
+							_rtl8812ae_phy_get_txpower_by_rate_base_index(hw,
+							BAND_ON_5G, MGN_VHT2SS_MCS7);
+					}
+
+					temp_pwrlmt = rtlphy->txpwr_limit_5g[regulation]
+						[bw][rate_section][channel]
+						[RF90_PATH_A];
+
+					for (rf_path = RF90_PATH_A;
+					     rf_path < MAX_RF_PATH_NUM;
+					     ++rf_path) {
+						if (rate_section == 3 || rate_section == 5)
+							bw40_pwr_base_dbm5G =
+							rtlphy->txpwr_by_rate_base_5g[rf_path]
+							[RF_2TX][base_index5G];
+						else
+							bw40_pwr_base_dbm5G =
+							rtlphy->txpwr_by_rate_base_5g[rf_path]
+							[RF_1TX][base_index5G];
+
+						if (temp_pwrlmt != MAX_POWER_INDEX) {
+							temp_value =
+								temp_pwrlmt - bw40_pwr_base_dbm5G;
+							rtlphy->txpwr_limit_5g[regulation]
+								[bw][rate_section][channel]
+								[rf_path] = temp_value;
+						}
+
+						RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+							"TxPwrLimit_5G[regulation %d][bw %d][rateSection %d][channel %d] =%d\n(TxPwrLimit in dBm %d - BW40PwrLmt5G[chnl group %d][rfPath %d] %d)\n",
+							regulation, bw, rate_section,
+							channel, rtlphy->txpwr_limit_5g[regulation]
+							[bw][rate_section][channel][rf_path],
+							temp_pwrlmt, channel, rf_path, bw40_pwr_base_dbm5G);
+					}
+				}
+			}
+		}
+	}
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+		 "<===== _rtl8812ae_phy_convert_txpower_limit_to_power_index()\n");
+}
+
+static void _rtl8821ae_phy_init_txpower_limit(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 i, j, k, l, m;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "=====> _rtl8821ae_phy_init_txpower_limit()!\n");
+
+	for (i = 0; i < MAX_REGULATION_NUM; ++i) {
+		for (j = 0; j < MAX_2_4G_BANDWITH_NUM; ++j)
+			for (k = 0; k < MAX_RATE_SECTION_NUM; ++k)
+				for (m = 0; m < CHANNEL_MAX_NUMBER_2G; ++m)
+					for (l = 0; l < MAX_RF_PATH_NUM; ++l)
+						rtlphy->txpwr_limit_2_4g
+								[i][j][k][m][l]
+							= MAX_POWER_INDEX;
+	}
+	for (i = 0; i < MAX_REGULATION_NUM; ++i) {
+		for (j = 0; j < MAX_5G_BANDWITH_NUM; ++j)
+			for (k = 0; k < MAX_RATE_SECTION_NUM; ++k)
+				for (m = 0; m < CHANNEL_MAX_NUMBER_5G; ++m)
+					for (l = 0; l < MAX_RF_PATH_NUM; ++l)
+						rtlphy->txpwr_limit_5g
+								[i][j][k][m][l]
+							= MAX_POWER_INDEX;
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "<===== _rtl8821ae_phy_init_txpower_limit()!\n");
+}
+
+static void _rtl8821ae_phy_convert_txpower_dbm_to_relative_value(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 base = 0, rfPath = 0;
+
+	for (rfPath = RF90_PATH_A; rfPath <= RF90_PATH_B; ++rfPath) {
+		base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfPath, RF_1TX, CCK);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][0],
+			0, 3, base);
+
+		base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfPath, RF_1TX, OFDM);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][1],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][2],
+			0, 3, base);
+
+		base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfPath, RF_1TX, HT_MCS0_MCS7);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][3],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][4],
+			0, 3, base);
+
+		base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfPath, RF_2TX, HT_MCS8_MCS15);
+
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_2TX][5],
+			0, 3, base);
+
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_2TX][6],
+			0, 3, base);
+
+		base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfPath, RF_1TX, VHT_1SSMCS0_1SSMCS9);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][7],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][8],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][9],
+			0, 1, base);
+
+		base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_2_4G, rfPath, RF_2TX, VHT_2SSMCS0_2SSMCS9);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_1TX][9],
+			2, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_2TX][10],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_2_4G][rfPath][RF_2TX][11],
+			0, 3, base);
+
+		base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_5G, rfPath, RF_1TX, OFDM);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][1],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][2],
+			0, 3, base);
+
+		base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_5G, rfPath, RF_1TX, HT_MCS0_MCS7);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][3],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][4],
+			0, 3, base);
+
+		base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_5G, rfPath, RF_2TX, HT_MCS8_MCS15);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_2TX][5],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_2TX][6],
+			0, 3, base);
+
+		base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_5G, rfPath, RF_1TX, VHT_1SSMCS0_1SSMCS9);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][7],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][8],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][9],
+			0, 1, base);
+
+		base = _rtl8821ae_phy_get_txpower_by_rate_base(hw, BAND_ON_5G, rfPath, RF_2TX, VHT_2SSMCS0_2SSMCS9);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_1TX][9],
+			2, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_2TX][10],
+			0, 3, base);
+		_phy_convert_txpower_dbm_to_relative_value(
+			&rtlphy->tx_power_by_rate_offset[BAND_ON_5G][rfPath][RF_2TX][11],
+			0, 3, base);
+	}
+
+	RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+		"<===_rtl8821ae_phy_convert_txpower_dbm_to_relative_value()\n");
+}
+
+static void _rtl8821ae_phy_txpower_by_rate_configuration(struct ieee80211_hw *hw)
+{
+	_rtl8821ae_phy_store_txpower_by_rate_base(hw);
+	_rtl8821ae_phy_convert_txpower_dbm_to_relative_value(hw);
+}
+
+/* string is in decimal */
+static bool _rtl8812ae_get_integer_from_string(char *str, u8 *pint)
+{
+	u16 i = 0;
+	*pint = 0;
+
+	while (str[i] != '\0') {
+		if (str[i] >= '0' && str[i] <= '9') {
+			*pint *= 10;
+			*pint += (str[i] - '0');
+		} else {
+			return false;
+		}
+		++i;
+	}
+
+	return true;
+}
+
+static bool _rtl8812ae_eq_n_byte(u8 *str1, u8 *str2, u32 num)
+{
+	if (num == 0)
+		return false;
+	while (num > 0) {
+		num--;
+		if (str1[num] != str2[num])
+			return false;
+	}
+	return true;
+}
+
+static char _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(struct ieee80211_hw *hw,
+					      u8 band, u8 channel)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	char channel_index = -1;
+	u8 channel_5g[CHANNEL_MAX_NUMBER_5G] = {
+		36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64,
+		100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122,
+		124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 149,
+		151, 153, 155, 157, 159, 161, 163, 165, 167, 168, 169, 171,
+		173, 175, 177};
+	u8  i = 0;
+	if (band == BAND_ON_2_4G)
+		channel_index = channel - 1;
+	else if (band == BAND_ON_5G) {
+		for (i = 0; i < sizeof(channel_5g)/sizeof(u8); ++i) {
+			if (channel_5g[i] == channel)
+				channel_index = i;
+		}
+	} else
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "Invalid Band %d in %s",
+			 band,  __func__);
+
+	if (channel_index == -1)
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+			 "Invalid Channel %d of Band %d in %s", channel,
+			 band, __func__);
+
+	return channel_index;
+}
+
+static void _rtl8812ae_phy_set_txpower_limit(struct ieee80211_hw *hw, u8 *pregulation,
+				      u8 *pband, u8 *pbandwidth,
+				      u8 *prate_section, u8 *prf_path,
+				      u8 *pchannel, u8 *ppower_limit)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 regulation = 0, bandwidth = 0, rate_section = 0, channel;
+	u8 channel_index;
+	char power_limit = 0, prev_power_limit, ret;
+
+	if (!_rtl8812ae_get_integer_from_string((char *)pchannel, &channel) ||
+	    !_rtl8812ae_get_integer_from_string((char *)ppower_limit,
+						&power_limit)) {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "Illegal index of pwr_lmt table [chnl %d][val %d]\n",
+			  channel, power_limit);
+	}
+
+	power_limit = power_limit > MAX_POWER_INDEX ?
+		      MAX_POWER_INDEX : power_limit;
+
+	if (_rtl8812ae_eq_n_byte(pregulation, (u8 *)("FCC"), 3))
+		regulation = 0;
+	else if (_rtl8812ae_eq_n_byte(pregulation, (u8 *)("MKK"), 3))
+		regulation = 1;
+	else if (_rtl8812ae_eq_n_byte(pregulation, (u8 *)("ETSI"), 4))
+		regulation = 2;
+	else if (_rtl8812ae_eq_n_byte(pregulation, (u8 *)("WW13"), 4))
+		regulation = 3;
+
+	if (_rtl8812ae_eq_n_byte(prate_section, (u8 *)("CCK"), 3))
+		rate_section = 0;
+	else if (_rtl8812ae_eq_n_byte(prate_section, (u8 *)("OFDM"), 4))
+		rate_section = 1;
+	else if (_rtl8812ae_eq_n_byte(prate_section, (u8 *)("HT"), 2) &&
+		 _rtl8812ae_eq_n_byte(prf_path, (u8 *)("1T"), 2))
+		rate_section = 2;
+	else if (_rtl8812ae_eq_n_byte(prate_section, (u8 *)("HT"), 2) &&
+		 _rtl8812ae_eq_n_byte(prf_path, (u8 *)("2T"), 2))
+		rate_section = 3;
+	else if (_rtl8812ae_eq_n_byte(prate_section, (u8 *)("VHT"), 3) &&
+		 _rtl8812ae_eq_n_byte(prf_path, (u8 *)("1T"), 2))
+		rate_section = 4;
+	else if (_rtl8812ae_eq_n_byte(prate_section, (u8 *)("VHT"), 3) &&
+		 _rtl8812ae_eq_n_byte(prf_path, (u8 *)("2T"), 2))
+		rate_section = 5;
+
+	if (_rtl8812ae_eq_n_byte(pbandwidth, (u8 *)("20M"), 3))
+		bandwidth = 0;
+	else if (_rtl8812ae_eq_n_byte(pbandwidth, (u8 *)("40M"), 3))
+		bandwidth = 1;
+	else if (_rtl8812ae_eq_n_byte(pbandwidth, (u8 *)("80M"), 3))
+		bandwidth = 2;
+	else if (_rtl8812ae_eq_n_byte(pbandwidth, (u8 *)("160M"), 4))
+		bandwidth = 3;
+
+	if (_rtl8812ae_eq_n_byte(pband, (u8 *)("2.4G"), 4)) {
+		ret = _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(hw,
+							       BAND_ON_2_4G,
+							       channel);
+
+		if (ret == -1)
+			return;
+
+		channel_index = ret;
+
+		prev_power_limit = rtlphy->txpwr_limit_2_4g[regulation]
+						[bandwidth][rate_section]
+						[channel_index][RF90_PATH_A];
+
+		if (power_limit < prev_power_limit)
+			rtlphy->txpwr_limit_2_4g[regulation][bandwidth]
+				[rate_section][channel_index][RF90_PATH_A] =
+								   power_limit;
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "2.4G [regula %d][bw %d][sec %d][chnl %d][val %d]\n",
+			  regulation, bandwidth, rate_section, channel_index,
+			  rtlphy->txpwr_limit_2_4g[regulation][bandwidth]
+				[rate_section][channel_index][RF90_PATH_A]);
+	} else if (_rtl8812ae_eq_n_byte(pband, (u8 *)("5G"), 2)) {
+		ret = _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(hw,
+							       BAND_ON_5G,
+							       channel);
+
+		if (ret == -1)
+			return;
+
+		channel_index = ret;
+
+		prev_power_limit = rtlphy->txpwr_limit_5g[regulation][bandwidth]
+						[rate_section][channel_index]
+						[RF90_PATH_A];
+
+		if (power_limit < prev_power_limit)
+			rtlphy->txpwr_limit_5g[regulation][bandwidth]
+			[rate_section][channel_index][RF90_PATH_A] = power_limit;
+
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "5G: [regul %d][bw %d][sec %d][chnl %d][val %d]\n",
+			  regulation, bandwidth, rate_section, channel,
+			  rtlphy->txpwr_limit_5g[regulation][bandwidth]
+				[rate_section][channel_index][RF90_PATH_A]);
+	} else {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+			 "Cannot recognize the band info in %s\n", pband);
+		return;
+	}
+}
+
+static void _rtl8812ae_phy_config_bb_txpwr_lmt(struct ieee80211_hw *hw,
+					  u8 *regulation, u8 *band,
+					  u8 *bandwidth, u8 *rate_section,
+					  u8 *rf_path, u8 *channel,
+					  u8 *power_limit)
+{
+	_rtl8812ae_phy_set_txpower_limit(hw, regulation, band, bandwidth,
+					 rate_section, rf_path, channel,
+					 power_limit);
+}
+
+static void _rtl8821ae_phy_read_and_config_txpwr_lmt(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	u32 i = 0;
+	u32 array_len;
+	u8 **array;
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+		array_len = RTL8812AE_TXPWR_LMT_ARRAY_LEN;
+		array = RTL8812AE_TXPWR_LMT;
+	} else {
+		array_len = RTL8821AE_TXPWR_LMT_ARRAY_LEN;
+		array = RTL8821AE_TXPWR_LMT;
+	}
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+		 "\n");
+
+	for (i = 0; i < array_len; i += 7) {
+		u8 *regulation = array[i];
+		u8 *band = array[i+1];
+		u8 *bandwidth = array[i+2];
+		u8 *rate = array[i+3];
+		u8 *rf_path = array[i+4];
+		u8 *chnl = array[i+5];
+		u8 *val = array[i+6];
+
+		_rtl8812ae_phy_config_bb_txpwr_lmt(hw, regulation, band,
+						   bandwidth, rate, rf_path,
+						   chnl, val);
+	}
+}
+
+static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	bool rtstatus;
+
+	_rtl8821ae_phy_init_txpower_limit(hw);
+
+	/* RegEnableTxPowerLimit == 1 for 8812a & 8821a */
+	if (rtlefuse->eeprom_regulatory != 2)
+		_rtl8821ae_phy_read_and_config_txpwr_lmt(hw);
+
+	rtstatus = _rtl8821ae_phy_config_bb_with_headerfile(hw,
+						       BASEBAND_CONFIG_PHY_REG);
+	if (rtstatus != true) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!");
+		return false;
+	}
+	_rtl8821ae_phy_init_tx_power_by_rate(hw);
+	if (rtlefuse->autoload_failflag == false) {
+		rtstatus = _rtl8821ae_phy_config_bb_with_pgheaderfile(hw,
+						    BASEBAND_CONFIG_PHY_REG);
+	}
+	if (rtstatus != true) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!");
+		return false;
+	}
+
+	_rtl8821ae_phy_txpower_by_rate_configuration(hw);
+
+	/* RegEnableTxPowerLimit == 1 for 8812a & 8821a */
+	if (rtlefuse->eeprom_regulatory != 2)
+		_rtl8812ae_phy_convert_txpower_limit_to_power_index(hw);
+
+	rtstatus = _rtl8821ae_phy_config_bb_with_headerfile(hw,
+						BASEBAND_CONFIG_AGC_TAB);
+
+	if (rtstatus != true) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
+		return false;
+	}
+	rtlphy->cck_high_power = (bool)(rtl_get_bbreg(hw,
+			RFPGA0_XA_HSSIPARAMETER2, 0x200));
+	return true;
+}
+
+static bool _rtl8821ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	u32 i, v1, v2;
+	u32 arraylength;
+	u32 *ptrarray;
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read MAC_REG_Array\n");
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+		arraylength = RTL8821AEMAC_1T_ARRAYLEN;
+		ptrarray = RTL8821AE_MAC_REG_ARRAY;
+	} else {
+		arraylength = RTL8812AEMAC_1T_ARRAYLEN;
+		ptrarray = RTL8812AE_MAC_REG_ARRAY;
+	}
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "Img: MAC_REG_ARRAY LEN %d\n", arraylength);
+	for (i = 0; i < arraylength; i += 2) {
+		v1 = ptrarray[i];
+		v2 = (u8)ptrarray[i + 1];
+		if (v1 < 0xCDCDCDCD) {
+			rtl_write_byte(rtlpriv, v1, (u8)v2);
+			continue;
+		} else {
+			if (!_rtl8821ae_check_condition(hw, v1)) {
+				/*Discard the following (offset, data) pairs*/
+				READ_NEXT_PAIR(ptrarray, v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < arraylength - 2) {
+					READ_NEXT_PAIR(ptrarray, v1, v2, i);
+				}
+				i -= 2; /* prevent from for-loop += 2*/
+			} else {/*Configure matched pairs and skip to end of if-else.*/
+				READ_NEXT_PAIR(ptrarray, v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < arraylength - 2) {
+					rtl_write_byte(rtlpriv, v1, v2);
+					READ_NEXT_PAIR(ptrarray, v1, v2, i);
+				}
+
+				while (v2 != 0xDEAD && i < arraylength - 2)
+					READ_NEXT_PAIR(ptrarray, v1, v2, i);
+			}
+		}
+	}
+	return true;
+}
+
+static bool _rtl8821ae_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+						     u8 configtype)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	int i;
+	u32 *array_table;
+	u16 arraylen;
+	u32 v1 = 0, v2 = 0;
+
+	if (configtype == BASEBAND_CONFIG_PHY_REG) {
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+			arraylen = RTL8812AEPHY_REG_1TARRAYLEN;
+			array_table = RTL8812AE_PHY_REG_ARRAY;
+		} else {
+			arraylen = RTL8821AEPHY_REG_1TARRAYLEN;
+			array_table = RTL8821AE_PHY_REG_ARRAY;
+		}
+
+		for (i = 0; i < arraylen; i += 2) {
+			v1 = array_table[i];
+			v2 = array_table[i + 1];
+			if (v1 < 0xCDCDCDCD) {
+				_rtl8821ae_config_bb_reg(hw, v1, v2);
+				continue;
+			} else {/*This line is the start line of branch.*/
+				if (!_rtl8821ae_check_condition(hw, v1)) {
+					/*Discard the following (offset, data) pairs*/
+					READ_NEXT_PAIR(array_table, v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD &&
+					       i < arraylen - 2) {
+						READ_NEXT_PAIR(array_table, v1,
+								v2, i);
+					}
+
+					i -= 2; /* prevent from for-loop += 2*/
+				} else {/*Configure matched pairs and skip to end of if-else.*/
+					READ_NEXT_PAIR(array_table, v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD &&
+					       i < arraylen - 2) {
+						_rtl8821ae_config_bb_reg(hw, v1,
+									 v2);
+						READ_NEXT_PAIR(array_table, v1,
+							       v2, i);
+					}
+
+					while (v2 != 0xDEAD &&
+					       i < arraylen - 2) {
+						READ_NEXT_PAIR(array_table, v1,
+							       v2, i);
+					}
+				}
+			}
+		}
+	} else if (configtype == BASEBAND_CONFIG_AGC_TAB) {
+		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+			arraylen = RTL8812AEAGCTAB_1TARRAYLEN;
+			array_table = RTL8812AE_AGC_TAB_ARRAY;
+		} else {
+			arraylen = RTL8821AEAGCTAB_1TARRAYLEN;
+			array_table = RTL8821AE_AGC_TAB_ARRAY;
+		}
+
+		for (i = 0; i < arraylen; i = i + 2) {
+			v1 = array_table[i];
+			v2 = array_table[i+1];
+			if (v1 < 0xCDCDCDCD) {
+				rtl_set_bbreg(hw, v1, MASKDWORD, v2);
+				udelay(1);
+				continue;
+			} else {/*This line is the start line of branch.*/
+				if (!_rtl8821ae_check_condition(hw, v1)) {
+					/*Discard the following (offset, data) pairs*/
+					READ_NEXT_PAIR(array_table, v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD &&
+					       i < arraylen - 2) {
+						READ_NEXT_PAIR(array_table, v1,
+								v2, i);
+					}
+					i -= 2; /* prevent from for-loop += 2*/
+				} else {/*Configure matched pairs and skip to end of if-else.*/
+					READ_NEXT_PAIR(array_table, v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD &&
+					       i < arraylen - 2) {
+						rtl_set_bbreg(hw, v1, MASKDWORD,
+							      v2);
+						udelay(1);
+						READ_NEXT_PAIR(array_table, v1,
+							       v2, i);
+					}
+
+					while (v2 != 0xDEAD &&
+						i < arraylen - 2) {
+						READ_NEXT_PAIR(array_table, v1,
+								v2, i);
+					}
+				}
+				RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+					 "The agctab_array_table[0] is %x Rtl818EEPHY_REGArray[1] is %x\n",
+					  array_table[i],  array_table[i + 1]);
+			}
+		}
+	}
+	return true;
+}
+
+static u8 _rtl8821ae_get_rate_section_index(u32 regaddr)
+{
+	u8 index = 0;
+	regaddr &= 0xFFF;
+	if (regaddr >= 0xC20 && regaddr <= 0xC4C)
+		index = (u8)((regaddr - 0xC20) / 4);
+	else if (regaddr >= 0xE20 && regaddr <= 0xE4C)
+		index = (u8)((regaddr - 0xE20) / 4);
+	else
+		RT_ASSERT(!COMP_INIT,
+			  "Invalid RegAddr 0x%x\n", regaddr);
+	return index;
+}
+
+static void _rtl8821ae_store_tx_power_by_rate(struct ieee80211_hw *hw,
+					      u32 band, u32 rfpath,
+					      u32 txnum, u32 regaddr,
+					      u32 bitmask, u32 data)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 rate_section = _rtl8821ae_get_rate_section_index(regaddr);
+
+	if (band != BAND_ON_2_4G && band != BAND_ON_5G)
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid Band %d\n", band);
+
+	if (rfpath >= MAX_RF_PATH)
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid RfPath %d\n", rfpath);
+
+	if (txnum >= MAX_RF_PATH)
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_WARNING, "Invalid TxNum %d\n", txnum);
+
+	rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section] = data;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "TxPwrByRateOffset[Band %d][RfPath %d][TxNum %d][RateSection %d] = 0x%x\n",
+		 band, rfpath, txnum, rate_section,
+		 rtlphy->tx_power_by_rate_offset[band][rfpath][txnum][rate_section]);
+}
+
+static bool _rtl8821ae_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+							u8 configtype)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	int i;
+	u32 *array;
+	u16 arraylen;
+	u32 v1, v2, v3, v4, v5, v6;
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
+		arraylen = RTL8812AEPHY_REG_ARRAY_PGLEN;
+		array = RTL8812AE_PHY_REG_ARRAY_PG;
+	} else {
+		arraylen = RTL8821AEPHY_REG_ARRAY_PGLEN;
+		array = RTL8821AE_PHY_REG_ARRAY_PG;
+	}
+
+	if (configtype != BASEBAND_CONFIG_PHY_REG) {
+		RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+			 "configtype != BaseBand_Config_PHY_REG\n");
+		return true;
+	}
+	for (i = 0; i < arraylen; i += 6) {
+		v1 = array[i];
+		v2 = array[i+1];
+		v3 = array[i+2];
+		v4 = array[i+3];
+		v5 = array[i+4];
+		v6 = array[i+5];
+
+		if (v1 < 0xCDCDCDCD) {
+			if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE &&
+				(v4 == 0xfe || v4 == 0xffe)) {
+				msleep(50);
+				continue;
+			}
+
+			if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+				if (v4 == 0xfe)
+					msleep(50);
+				else if (v4 == 0xfd)
+					mdelay(5);
+				else if (v4 == 0xfc)
+					mdelay(1);
+				else if (v4 == 0xfb)
+					udelay(50);
+				else if (v4 == 0xfa)
+					udelay(5);
+				else if (v4 == 0xf9)
+					udelay(1);
+			}
+			_rtl8821ae_store_tx_power_by_rate(hw, v1, v2, v3,
+							  v4, v5, v6);
+			continue;
+		} else {
+			 /*don't need the hw_body*/
+			if (!_rtl8821ae_check_condition(hw, v1)) {
+				i += 2; /* skip the pair of expression*/
+				v1 = array[i];
+				v2 = array[i+1];
+				v3 = array[i+2];
+				while (v2 != 0xDEAD) {
+					i += 3;
+					v1 = array[i];
+					v2 = array[i+1];
+					v3 = array[i+2];
+				}
+			}
+		}
+	}
+
+	return true;
+}
+
+bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+					     enum radio_path rfpath)
+{
+	int i;
+	bool rtstatus = true;
+	u32 *radioa_array_table_a, *radioa_array_table_b;
+	u16 radioa_arraylen_a, radioa_arraylen_b;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 v1 = 0, v2 = 0;
+
+	radioa_arraylen_a = RTL8812AE_RADIOA_1TARRAYLEN;
+	radioa_array_table_a = RTL8812AE_RADIOA_ARRAY;
+	radioa_arraylen_b = RTL8812AE_RADIOB_1TARRAYLEN;
+	radioa_array_table_b = RTL8812AE_RADIOB_ARRAY;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "Radio_A:RTL8821AE_RADIOA_ARRAY %d\n", radioa_arraylen_a);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath);
+	rtstatus = true;
+	switch (rfpath) {
+	case RF90_PATH_A:
+		for (i = 0; i < radioa_arraylen_a; i = i + 2) {
+			v1 = radioa_array_table_a[i];
+			v2 = radioa_array_table_a[i+1];
+			if (v1 < 0xcdcdcdcd) {
+				_rtl8821ae_config_rf_radio_a(hw, v1, v2);
+				continue;
+			} else{/*This line is the start line of branch.*/
+				if (!_rtl8821ae_check_condition(hw, v1)) {
+					/*Discard the following (offset, data) pairs*/
+					READ_NEXT_PAIR(radioa_array_table_a, v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD && i < radioa_arraylen_a-2)
+						READ_NEXT_PAIR(radioa_array_table_a, v1, v2, i);
+
+					i -= 2; /* prevent from for-loop += 2*/
+				} else {/*Configure matched pairs and skip to end of if-else.*/
+					READ_NEXT_PAIR(radioa_array_table_a, v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD && i < radioa_arraylen_a - 2) {
+						_rtl8821ae_config_rf_radio_a(hw, v1, v2);
+						READ_NEXT_PAIR(radioa_array_table_a, v1, v2, i);
+					}
+
+					while (v2 != 0xDEAD && i < radioa_arraylen_a-2)
+						READ_NEXT_PAIR(radioa_array_table_a, v1, v2, i);
+
+				}
+			}
+		}
+		break;
+	case RF90_PATH_B:
+		for (i = 0; i < radioa_arraylen_b; i = i + 2) {
+			v1 = radioa_array_table_b[i];
+			v2 = radioa_array_table_b[i+1];
+			if (v1 < 0xcdcdcdcd) {
+				_rtl8821ae_config_rf_radio_b(hw, v1, v2);
+				continue;
+			} else{/*This line is the start line of branch.*/
+				if (!_rtl8821ae_check_condition(hw, v1)) {
+					/*Discard the following (offset, data) pairs*/
+					READ_NEXT_PAIR(radioa_array_table_b, v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD && i < radioa_arraylen_b-2)
+						READ_NEXT_PAIR(radioa_array_table_b, v1, v2, i);
+
+					i -= 2; /* prevent from for-loop += 2*/
+				} else {/*Configure matched pairs and skip to end of if-else.*/
+					READ_NEXT_PAIR(radioa_array_table_b, v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD && i < radioa_arraylen_b-2) {
+						_rtl8821ae_config_rf_radio_b(hw, v1, v2);
+						READ_NEXT_PAIR(radioa_array_table_b, v1, v2, i);
+					}
+
+					while (v2 != 0xDEAD && i < radioa_arraylen_b-2)
+						READ_NEXT_PAIR(radioa_array_table_b, v1, v2, i);
+				}
+			}
+		}
+		break;
+	case RF90_PATH_C:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "switch case not process\n");
+		break;
+	case RF90_PATH_D:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "switch case not process\n");
+		break;
+	}
+	return true;
+}
+
+bool rtl8821ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+						enum radio_path rfpath)
+{
+	#define READ_NEXT_RF_PAIR(v1, v2, i) \
+	do { \
+		i += 2; \
+		v1 = radioa_array_table[i]; \
+		v2 = radioa_array_table[i+1]; \
+	} \
+	while (0)
+
+	int i;
+	bool rtstatus = true;
+	u32 *radioa_array_table;
+	u16 radioa_arraylen;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	/* struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); */
+	u32 v1 = 0, v2 = 0;
+
+	radioa_arraylen = RTL8821AE_RADIOA_1TARRAYLEN;
+	radioa_array_table = RTL8821AE_RADIOA_ARRAY;
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+		 "Radio_A:RTL8821AE_RADIOA_ARRAY %d\n", radioa_arraylen);
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath);
+	rtstatus = true;
+	switch (rfpath) {
+	case RF90_PATH_A:
+		for (i = 0; i < radioa_arraylen; i = i + 2) {
+			v1 = radioa_array_table[i];
+			v2 = radioa_array_table[i+1];
+			if (v1 < 0xcdcdcdcd)
+				_rtl8821ae_config_rf_radio_a(hw, v1, v2);
+			else{/*This line is the start line of branch.*/
+				if (!_rtl8821ae_check_condition(hw, v1)) {
+					/*Discard the following (offset, data) pairs*/
+					READ_NEXT_RF_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+						v2 != 0xCDEF &&
+						v2 != 0xCDCD && i < radioa_arraylen - 2)
+						READ_NEXT_RF_PAIR(v1, v2, i);
+
+					i -= 2; /* prevent from for-loop += 2*/
+				} else {/*Configure matched pairs and skip to end of if-else.*/
+					READ_NEXT_RF_PAIR(v1, v2, i);
+					while (v2 != 0xDEAD &&
+					       v2 != 0xCDEF &&
+					       v2 != 0xCDCD && i < radioa_arraylen - 2) {
+						_rtl8821ae_config_rf_radio_a(hw, v1, v2);
+						READ_NEXT_RF_PAIR(v1, v2, i);
+					}
+
+					while (v2 != 0xDEAD && i < radioa_arraylen - 2)
+						READ_NEXT_RF_PAIR(v1, v2, i);
+				}
+			}
+		}
+		break;
+
+	case RF90_PATH_B:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "switch case not process\n");
+		break;
+	case RF90_PATH_C:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "switch case not process\n");
+		break;
+	case RF90_PATH_D:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "switch case not process\n");
+		break;
+	}
+	return true;
+}
+
+void rtl8821ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	rtlphy->default_initialgain[0] =
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
+	rtlphy->default_initialgain[1] =
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
+	rtlphy->default_initialgain[2] =
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
+	rtlphy->default_initialgain[3] =
+	    (u8)rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+		 "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x\n",
+		  rtlphy->default_initialgain[0],
+		  rtlphy->default_initialgain[1],
+		  rtlphy->default_initialgain[2],
+		  rtlphy->default_initialgain[3]);
+
+	rtlphy->framesync = (u8)rtl_get_bbreg(hw,
+					       ROFDM0_RXDETECTOR3, MASKBYTE0);
+	rtlphy->framesync_c34 = rtl_get_bbreg(hw,
+					      ROFDM0_RXDETECTOR2, MASKDWORD);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+		 "Default framesync (0x%x) = 0x%x\n",
+		  ROFDM0_RXDETECTOR3, rtlphy->framesync);
+}
+
+static void phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+	rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE;
+	rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE;
+	rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = RA_LSSIWRITE_8821A;
+	rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = RB_LSSIWRITE_8821A;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RHSSIREAD_8821AE;
+	rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RHSSIREAD_8821AE;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RA_SIREAD_8821A;
+	rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RB_SIREAD_8821A;
+
+	rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = RA_PIREAD_8821A;
+	rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = RB_PIREAD_8821A;
+}
+
+void rtl8821ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 txpwr_level;
+	long txpwr_dbm;
+
+	txpwr_level = rtlphy->cur_cck_txpwridx;
+	txpwr_dbm = _rtl8821ae_phy_txpwr_idx_to_dbm(hw,
+						 WIRELESS_MODE_B, txpwr_level);
+	txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
+	if (_rtl8821ae_phy_txpwr_idx_to_dbm(hw,
+					 WIRELESS_MODE_G,
+					 txpwr_level) > txpwr_dbm)
+		txpwr_dbm =
+		    _rtl8821ae_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
+						 txpwr_level);
+	txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
+	if (_rtl8821ae_phy_txpwr_idx_to_dbm(hw,
+					 WIRELESS_MODE_N_24G,
+					 txpwr_level) > txpwr_dbm)
+		txpwr_dbm =
+		    _rtl8821ae_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
+						 txpwr_level);
+	*powerlevel = txpwr_dbm;
+}
+
+static bool _rtl8821ae_phy_get_chnl_index(u8 channel, u8 *chnl_index)
+{
+	u8 channel_5g[CHANNEL_MAX_NUMBER_5G] = {
+		36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
+		64, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118,
+		120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140,
+		142, 144, 149, 151, 153, 155, 157, 159, 161, 163, 165,
+		167, 168, 169, 171, 173, 175, 177
+	};
+	u8 i = 0;
+	bool in_24g = true;
+
+	if (channel <= 14) {
+		in_24g = true;
+		*chnl_index = channel - 1;
+	} else {
+		in_24g = false;
+
+		for (i = 0; i < CHANNEL_MAX_NUMBER_5G; ++i) {
+			if (channel_5g[i] == channel) {
+				*chnl_index = i;
+				return in_24g;
+			}
+		}
+	}
+	return in_24g;
+}
+
+static char _rtl8821ae_phy_get_ratesection_intxpower_byrate(u8 path, u8 rate)
+{
+	char rate_section = 0;
+	switch (rate) {
+	case DESC_RATE1M:
+	case DESC_RATE2M:
+	case DESC_RATE5_5M:
+	case DESC_RATE11M:
+		rate_section = 0;
+		break;
+	case DESC_RATE6M:
+	case DESC_RATE9M:
+	case DESC_RATE12M:
+	case DESC_RATE18M:
+		rate_section = 1;
+		break;
+	case DESC_RATE24M:
+	case DESC_RATE36M:
+	case DESC_RATE48M:
+	case DESC_RATE54M:
+		rate_section = 2;
+		break;
+	case DESC_RATEMCS0:
+	case DESC_RATEMCS1:
+	case DESC_RATEMCS2:
+	case DESC_RATEMCS3:
+		rate_section = 3;
+		break;
+	case DESC_RATEMCS4:
+	case DESC_RATEMCS5:
+	case DESC_RATEMCS6:
+	case DESC_RATEMCS7:
+		rate_section = 4;
+		break;
+	case DESC_RATEMCS8:
+	case DESC_RATEMCS9:
+	case DESC_RATEMCS10:
+	case DESC_RATEMCS11:
+		rate_section = 5;
+		break;
+	case DESC_RATEMCS12:
+	case DESC_RATEMCS13:
+	case DESC_RATEMCS14:
+	case DESC_RATEMCS15:
+		rate_section = 6;
+		break;
+	case DESC_RATEVHT1SS_MCS0:
+	case DESC_RATEVHT1SS_MCS1:
+	case DESC_RATEVHT1SS_MCS2:
+	case DESC_RATEVHT1SS_MCS3:
+		rate_section = 7;
+		break;
+	case DESC_RATEVHT1SS_MCS4:
+	case DESC_RATEVHT1SS_MCS5:
+	case DESC_RATEVHT1SS_MCS6:
+	case DESC_RATEVHT1SS_MCS7:
+		rate_section = 8;
+		break;
+	case DESC_RATEVHT1SS_MCS8:
+	case DESC_RATEVHT1SS_MCS9:
+	case DESC_RATEVHT2SS_MCS0:
+	case DESC_RATEVHT2SS_MCS1:
+		rate_section = 9;
+		break;
+	case DESC_RATEVHT2SS_MCS2:
+	case DESC_RATEVHT2SS_MCS3:
+	case DESC_RATEVHT2SS_MCS4:
+	case DESC_RATEVHT2SS_MCS5:
+		rate_section = 10;
+		break;
+	case DESC_RATEVHT2SS_MCS6:
+	case DESC_RATEVHT2SS_MCS7:
+	case DESC_RATEVHT2SS_MCS8:
+	case DESC_RATEVHT2SS_MCS9:
+		rate_section = 11;
+		break;
+	default:
+		RT_ASSERT(true, "Rate_Section is Illegal\n");
+		break;
+	}
+
+	return rate_section;
+}
+
+static char _rtl8812ae_phy_get_world_wide_limit(char  *limit_table)
+{
+	char min = limit_table[0];
+	u8 i = 0;
+
+	for (i = 0; i < MAX_REGULATION_NUM; ++i) {
+		if (limit_table[i] < min)
+			min = limit_table[i];
+	}
+	return min;
+}
+
+static char _rtl8812ae_phy_get_txpower_limit(struct ieee80211_hw *hw,
+					     u8 band,
+					     enum ht_channel_width bandwidth,
+					     enum radio_path rf_path,
+					     u8 rate, u8 channel)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtlpriv);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	short band_temp = -1, regulation = -1, bandwidth_temp = -1,
+		 rate_section = -1, channel_temp = -1;
+	u16 bd, regu, bdwidth, sec, chnl;
+	char power_limit = MAX_POWER_INDEX;
+
+	if (rtlefuse->eeprom_regulatory == 2)
+		return MAX_POWER_INDEX;
+
+	regulation = TXPWR_LMT_WW;
+
+	if (band == BAND_ON_2_4G)
+		band_temp = 0;
+	else if (band == BAND_ON_5G)
+		band_temp = 1;
+
+	if (bandwidth == HT_CHANNEL_WIDTH_20)
+		bandwidth_temp = 0;
+	else if (bandwidth == HT_CHANNEL_WIDTH_20_40)
+		bandwidth_temp = 1;
+	else if (bandwidth == HT_CHANNEL_WIDTH_80)
+		bandwidth_temp = 2;
+
+	switch (rate) {
+	case DESC_RATE1M:
+	case DESC_RATE2M:
+	case DESC_RATE5_5M:
+	case DESC_RATE11M:
+		rate_section = 0;
+		break;
+	case DESC_RATE6M:
+	case DESC_RATE9M:
+	case DESC_RATE12M:
+	case DESC_RATE18M:
+	case DESC_RATE24M:
+	case DESC_RATE36M:
+	case DESC_RATE48M:
+	case DESC_RATE54M:
+		rate_section = 1;
+		break;
+	case DESC_RATEMCS0:
+	case DESC_RATEMCS1:
+	case DESC_RATEMCS2:
+	case DESC_RATEMCS3:
+	case DESC_RATEMCS4:
+	case DESC_RATEMCS5:
+	case DESC_RATEMCS6:
+	case DESC_RATEMCS7:
+		rate_section = 2;
+		break;
+	case DESC_RATEMCS8:
+	case DESC_RATEMCS9:
+	case DESC_RATEMCS10:
+	case DESC_RATEMCS11:
+	case DESC_RATEMCS12:
+	case DESC_RATEMCS13:
+	case DESC_RATEMCS14:
+	case DESC_RATEMCS15:
+		rate_section = 3;
+		break;
+	case DESC_RATEVHT1SS_MCS0:
+	case DESC_RATEVHT1SS_MCS1:
+	case DESC_RATEVHT1SS_MCS2:
+	case DESC_RATEVHT1SS_MCS3:
+	case DESC_RATEVHT1SS_MCS4:
+	case DESC_RATEVHT1SS_MCS5:
+	case DESC_RATEVHT1SS_MCS6:
+	case DESC_RATEVHT1SS_MCS7:
+	case DESC_RATEVHT1SS_MCS8:
+	case DESC_RATEVHT1SS_MCS9:
+		rate_section = 4;
+		break;
+	case DESC_RATEVHT2SS_MCS0:
+	case DESC_RATEVHT2SS_MCS1:
+	case DESC_RATEVHT2SS_MCS2:
+	case DESC_RATEVHT2SS_MCS3:
+	case DESC_RATEVHT2SS_MCS4:
+	case DESC_RATEVHT2SS_MCS5:
+	case DESC_RATEVHT2SS_MCS6:
+	case DESC_RATEVHT2SS_MCS7:
+	case DESC_RATEVHT2SS_MCS8:
+	case DESC_RATEVHT2SS_MCS9:
+		rate_section = 5;
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+			"Wrong rate 0x%x\n", rate);
+		break;
+	}
+
+	if (band_temp == BAND_ON_5G  && rate_section == 0)
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+			 "Wrong rate 0x%x: No CCK in 5G Band\n", rate);
+
+	/*workaround for wrong index combination to obtain tx power limit,
+	  OFDM only exists in BW 20M*/
+	if (rate_section == 1)
+		bandwidth_temp = 0;
+
+	/*workaround for wrong index combination to obtain tx power limit,
+	 *HT on 80M will reference to HT on 40M
+	 */
+	if ((rate_section == 2 || rate_section == 3) && band == BAND_ON_5G &&
+	    bandwidth_temp == 2)
+		bandwidth_temp = 1;
+
+	if (band == BAND_ON_2_4G)
+		channel_temp = _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(hw,
+		BAND_ON_2_4G, channel);
+	else if (band == BAND_ON_5G)
+		channel_temp = _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(hw,
+		BAND_ON_5G, channel);
+	else if (band == BAND_ON_BOTH)
+		;/* BAND_ON_BOTH don't care temporarily */
+
+	if (band_temp == -1 || regulation == -1 || bandwidth_temp == -1 ||
+		rate_section == -1 || channel_temp == -1) {
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+			 "Wrong index value to access power limit table [band %d][regulation %d][bandwidth %d][rf_path %d][rate_section %d][chnl %d]\n",
+			 band_temp, regulation, bandwidth_temp, rf_path,
+			 rate_section, channel_temp);
+		return MAX_POWER_INDEX;
+	}
+
+	bd = band_temp;
+	regu = regulation;
+	bdwidth = bandwidth_temp;
+	sec = rate_section;
+	chnl = channel_temp;
+
+	if (band == BAND_ON_2_4G) {
+		char limits[10] = {0};
+		u8 i;
+
+		for (i = 0; i < 4; ++i)
+			limits[i] = rtlphy->txpwr_limit_2_4g[i][bdwidth]
+			[sec][chnl][rf_path];
+
+		power_limit = (regulation == TXPWR_LMT_WW) ?
+			_rtl8812ae_phy_get_world_wide_limit(limits) :
+			rtlphy->txpwr_limit_2_4g[regu][bdwidth]
+					[sec][chnl][rf_path];
+	} else if (band == BAND_ON_5G) {
+		char limits[10] = {0};
+		u8 i;
+
+		for (i = 0; i < MAX_REGULATION_NUM; ++i)
+			limits[i] = rtlphy->txpwr_limit_5g[i][bdwidth]
+			[sec][chnl][rf_path];
+
+		power_limit = (regulation == TXPWR_LMT_WW) ?
+			_rtl8812ae_phy_get_world_wide_limit(limits) :
+			rtlphy->txpwr_limit_5g[regu][chnl]
+			[sec][chnl][rf_path];
+	} else {
+		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+			 "No power limit table of the specified band\n");
+	}
+	return power_limit;
+}
+
+static char _rtl8821ae_phy_get_txpower_by_rate(struct ieee80211_hw *hw,
+					u8 band, u8 path, u8 rate)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 shift = 0, rate_section, tx_num;
+	char tx_pwr_diff = 0;
+	char limit = 0;
+
+	rate_section = _rtl8821ae_phy_get_ratesection_intxpower_byrate(path, rate);
+	tx_num = RF_TX_NUM_NONIMPLEMENT;
+
+	if (tx_num == RF_TX_NUM_NONIMPLEMENT) {
+		if ((rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS15) ||
+			(rate >= DESC_RATEVHT2SS_MCS2 && rate <= DESC_RATEVHT2SS_MCS9))
+			tx_num = RF_2TX;
+		else
+			tx_num = RF_1TX;
+	}
+
+	switch (rate) {
+	case DESC_RATE1M:
+	case DESC_RATE6M:
+	case DESC_RATE24M:
+	case DESC_RATEMCS0:
+	case DESC_RATEMCS4:
+	case DESC_RATEMCS8:
+	case DESC_RATEMCS12:
+	case DESC_RATEVHT1SS_MCS0:
+	case DESC_RATEVHT1SS_MCS4:
+	case DESC_RATEVHT1SS_MCS8:
+	case DESC_RATEVHT2SS_MCS2:
+	case DESC_RATEVHT2SS_MCS6:
+		shift = 0;
+		break;
+	case DESC_RATE2M:
+	case DESC_RATE9M:
+	case DESC_RATE36M:
+	case DESC_RATEMCS1:
+	case DESC_RATEMCS5:
+	case DESC_RATEMCS9:
+	case DESC_RATEMCS13:
+	case DESC_RATEVHT1SS_MCS1:
+	case DESC_RATEVHT1SS_MCS5:
+	case DESC_RATEVHT1SS_MCS9:
+	case DESC_RATEVHT2SS_MCS3:
+	case DESC_RATEVHT2SS_MCS7:
+		shift = 8;
+		break;
+	case DESC_RATE5_5M:
+	case DESC_RATE12M:
+	case DESC_RATE48M:
+	case DESC_RATEMCS2:
+	case DESC_RATEMCS6:
+	case DESC_RATEMCS10:
+	case DESC_RATEMCS14:
+	case DESC_RATEVHT1SS_MCS2:
+	case DESC_RATEVHT1SS_MCS6:
+	case DESC_RATEVHT2SS_MCS0:
+	case DESC_RATEVHT2SS_MCS4:
+	case DESC_RATEVHT2SS_MCS8:
+		shift = 16;
+		break;
+	case DESC_RATE11M:
+	case DESC_RATE18M:
+	case DESC_RATE54M:
+	case DESC_RATEMCS3:
+	case DESC_RATEMCS7:
+	case DESC_RATEMCS11:
+	case DESC_RATEMCS15:
+	case DESC_RATEVHT1SS_MCS3:
+	case DESC_RATEVHT1SS_MCS7:
+	case DESC_RATEVHT2SS_MCS1:
+	case DESC_RATEVHT2SS_MCS5:
+	case DESC_RATEVHT2SS_MCS9:
+		shift = 24;
+		break;
+	default:
+		RT_ASSERT(true, "Rate_Section is Illegal\n");
+		break;
+	}
+
+	tx_pwr_diff = (u8)(rtlphy->tx_power_by_rate_offset[band][path]
+		[tx_num][rate_section] >> shift) & 0xff;
+
+	/* RegEnableTxPowerLimit == 1 for 8812a & 8821a */
+	if (rtlpriv->efuse.eeprom_regulatory != 2) {
+		limit = _rtl8812ae_phy_get_txpower_limit(hw, band,
+			rtlphy->current_chan_bw, path, rate,
+			rtlphy->current_channel);
+
+		if (rate == DESC_RATEVHT1SS_MCS8 || rate == DESC_RATEVHT1SS_MCS9  ||
+			 rate == DESC_RATEVHT2SS_MCS8 || rate == DESC_RATEVHT2SS_MCS9) {
+			if (limit < 0) {
+				if (tx_pwr_diff < (-limit))
+					tx_pwr_diff = -limit;
+			}
+		} else {
+			if (limit < 0)
+				tx_pwr_diff = limit;
+			else
+				tx_pwr_diff = tx_pwr_diff > limit ? limit : tx_pwr_diff;
+		}
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			"Maximum power by rate %d, final power by rate %d\n",
+			limit, tx_pwr_diff);
+	}
+
+	return	tx_pwr_diff;
+}
+
+static u8 _rtl8821ae_get_txpower_index(struct ieee80211_hw *hw, u8 path,
+					u8 rate, u8 bandwidth, u8 channel)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	u8 index = (channel - 1);
+	u8 txpower = 0;
+	bool in_24g = false;
+	char powerdiff_byrate = 0;
+
+	if (((rtlhal->current_bandtype == BAND_ON_2_4G) &&
+	    (channel > 14 || channel < 1)) ||
+	    ((rtlhal->current_bandtype == BAND_ON_5G) && (channel <= 14))) {
+		index = 0;
+		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+			"Illegal channel!!\n");
+	}
+
+	in_24g = _rtl8821ae_phy_get_chnl_index(channel, &index);
+	if (in_24g) {
+		if (RTL8821AE_RX_HAL_IS_CCK_RATE(rate))
+			txpower = rtlefuse->txpwrlevel_cck[path][index];
+		else if (DESC_RATE6M <= rate)
+			txpower = rtlefuse->txpwrlevel_ht40_1s[path][index];
+		else
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "invalid rate\n");
+
+		if (DESC_RATE6M <= rate && rate <= DESC_RATE54M &&
+		    !RTL8821AE_RX_HAL_IS_CCK_RATE(rate))
+			txpower += rtlefuse->txpwr_legacyhtdiff[path][TX_1S];
+
+		if (bandwidth == HT_CHANNEL_WIDTH_20) {
+			if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) ||
+				(DESC_RATEVHT1SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9))
+				txpower += rtlefuse->txpwr_ht20diff[path][TX_1S];
+			if ((DESC_RATEMCS8 <= rate && rate <= DESC_RATEMCS15) ||
+				(DESC_RATEVHT2SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9))
+				txpower += rtlefuse->txpwr_ht20diff[path][TX_2S];
+		} else if (bandwidth == HT_CHANNEL_WIDTH_20_40) {
+			if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) ||
+				(DESC_RATEVHT1SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9))
+				txpower += rtlefuse->txpwr_ht40diff[path][TX_1S];
+			if ((DESC_RATEMCS8 <= rate && rate <= DESC_RATEMCS15) ||
+				(DESC_RATEVHT2SS_MCS0 <= rate && rate <= DESC_RATEVHT2SS_MCS9))
+				txpower += rtlefuse->txpwr_ht40diff[path][TX_2S];
+		} else if (bandwidth == HT_CHANNEL_WIDTH_80) {
+			if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) ||
+			    (DESC_RATEVHT1SS_MCS0 <= rate &&
+			     rate <= DESC_RATEVHT2SS_MCS9))
+				txpower += rtlefuse->txpwr_ht40diff[path][TX_1S];
+			if ((DESC_RATEMCS8 <= rate && rate <= DESC_RATEMCS15) ||
+			    (DESC_RATEVHT2SS_MCS0 <= rate &&
+			     rate <= DESC_RATEVHT2SS_MCS9))
+				txpower += rtlefuse->txpwr_ht40diff[path][TX_2S];
+		}
+	} else {
+		if (DESC_RATE6M <= rate)
+			txpower = rtlefuse->txpwr_5g_bw40base[path][index];
+		else
+			RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_WARNING,
+				 "INVALID Rate.\n");
+
+		if (DESC_RATE6M <= rate && rate <= DESC_RATE54M &&
+		    !RTL8821AE_RX_HAL_IS_CCK_RATE(rate))
+			txpower += rtlefuse->txpwr_5g_ofdmdiff[path][TX_1S];
+
+		if (bandwidth == HT_CHANNEL_WIDTH_20) {
+			if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) ||
+			    (DESC_RATEVHT1SS_MCS0 <= rate &&
+			     rate <= DESC_RATEVHT2SS_MCS9))
+				txpower += rtlefuse->txpwr_5g_bw20diff[path][TX_1S];
+			if ((DESC_RATEMCS8 <= rate && rate <= DESC_RATEMCS15) ||
+			    (DESC_RATEVHT2SS_MCS0 <= rate &&
+			     rate <= DESC_RATEVHT2SS_MCS9))
+				txpower += rtlefuse->txpwr_5g_bw20diff[path][TX_2S];
+		} else if (bandwidth == HT_CHANNEL_WIDTH_20_40) {
+			if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) ||
+			    (DESC_RATEVHT1SS_MCS0 <= rate &&
+			     rate <= DESC_RATEVHT2SS_MCS9))
+				txpower += rtlefuse->txpwr_5g_bw40diff[path][TX_1S];
+			if ((DESC_RATEMCS8 <= rate && rate <= DESC_RATEMCS15) ||
+			    (DESC_RATEVHT2SS_MCS0 <= rate &&
+			     rate <= DESC_RATEVHT2SS_MCS9))
+				txpower += rtlefuse->txpwr_5g_bw40diff[path][TX_2S];
+		} else if (bandwidth == HT_CHANNEL_WIDTH_80) {
+			u8 channel_5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {
+				42, 58, 106, 122, 138, 155, 171
+			};
+			u8 i;
+
+			for (i = 0; i < sizeof(channel_5g_80m) / sizeof(u8); ++i)
+				if (channel_5g_80m[i] == channel)
+					index = i;
+
+			if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) ||
+			    (DESC_RATEVHT1SS_MCS0 <= rate &&
+			     rate <= DESC_RATEVHT2SS_MCS9))
+				txpower = rtlefuse->txpwr_5g_bw80base[path][index]
+					+ rtlefuse->txpwr_5g_bw80diff[path][TX_1S];
+			if ((DESC_RATEMCS8 <= rate && rate <= DESC_RATEMCS15) ||
+			    (DESC_RATEVHT2SS_MCS0 <= rate &&
+			     rate <= DESC_RATEVHT2SS_MCS9))
+				txpower = rtlefuse->txpwr_5g_bw80base[path][index]
+					+ rtlefuse->txpwr_5g_bw80diff[path][TX_1S]
+					+ rtlefuse->txpwr_5g_bw80diff[path][TX_2S];
+		    }
+	}
+	if (rtlefuse->eeprom_regulatory != 2)
+		powerdiff_byrate =
+		  _rtl8821ae_phy_get_txpower_by_rate(hw, (u8)(!in_24g),
+						     path, rate);
+
+	if (rate == DESC_RATEVHT1SS_MCS8 || rate == DESC_RATEVHT1SS_MCS9 ||
+	    rate == DESC_RATEVHT2SS_MCS8 || rate == DESC_RATEVHT2SS_MCS9)
+		txpower -= powerdiff_byrate;
+	else
+		txpower += powerdiff_byrate;
+
+	if (rate > DESC_RATE11M)
+		txpower += rtlpriv->dm.remnant_ofdm_swing_idx[path];
+	else
+		txpower += rtlpriv->dm.remnant_cck_idx;
+
+	if (txpower > MAX_POWER_INDEX)
+		txpower = MAX_POWER_INDEX;
+
+	return txpower;
+}
+
+static void _rtl8821ae_phy_set_txpower_index(struct ieee80211_hw *hw,
+					     u8 power_index, u8 path, u8 rate)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (path == RF90_PATH_A) {
+		switch (rate) {
+		case DESC_RATE1M:
+			rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATE2M:
+			rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATE5_5M:
+			rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATE11M:
+			rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATE6M:
+			rtl_set_bbreg(hw, RTXAGC_A_OFDM18_OFDM6,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATE9M:
+			rtl_set_bbreg(hw, RTXAGC_A_OFDM18_OFDM6,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATE12M:
+			rtl_set_bbreg(hw, RTXAGC_A_OFDM18_OFDM6,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATE18M:
+			rtl_set_bbreg(hw, RTXAGC_A_OFDM18_OFDM6,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATE24M:
+			rtl_set_bbreg(hw, RTXAGC_A_OFDM54_OFDM24,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATE36M:
+			rtl_set_bbreg(hw, RTXAGC_A_OFDM54_OFDM24,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATE48M:
+			rtl_set_bbreg(hw, RTXAGC_A_OFDM54_OFDM24,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATE54M:
+			rtl_set_bbreg(hw, RTXAGC_A_OFDM54_OFDM24,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEMCS0:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEMCS1:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEMCS2:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEMCS3:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS03_MCS00,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEMCS4:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEMCS5:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEMCS6:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEMCS7:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS07_MCS04,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEMCS8:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEMCS9:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEMCS10:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEMCS11:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS11_MCS08,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEMCS12:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEMCS13:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEMCS14:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEMCS15:
+			rtl_set_bbreg(hw, RTXAGC_A_MCS15_MCS12,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS0:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX3_NSS1INDEX0,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS1:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX3_NSS1INDEX0,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS2:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX3_NSS1INDEX0,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS3:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX3_NSS1INDEX0,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS4:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX7_NSS1INDEX4,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS5:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX7_NSS1INDEX4,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS6:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX7_NSS1INDEX4,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS7:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS1INDEX7_NSS1INDEX4,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS8:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX1_NSS1INDEX8,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS9:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX1_NSS1INDEX8,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS0:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX1_NSS1INDEX8,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS1:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX1_NSS1INDEX8,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS2:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX5_NSS2INDEX2,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS3:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX5_NSS2INDEX2,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS4:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX5_NSS2INDEX2,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS5:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX5_NSS2INDEX2,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS6:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX9_NSS2INDEX6,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS7:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX9_NSS2INDEX6,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS8:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX9_NSS2INDEX6,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS9:
+			rtl_set_bbreg(hw, RTXAGC_A_NSS2INDEX9_NSS2INDEX6,
+				      MASKBYTE3, power_index);
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+				"Invalid Rate!!\n");
+			break;
+		}
+	} else if (path == RF90_PATH_B) {
+		switch (rate) {
+		case DESC_RATE1M:
+			rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATE2M:
+			rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATE5_5M:
+			rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATE11M:
+			rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATE6M:
+			rtl_set_bbreg(hw, RTXAGC_B_OFDM18_OFDM6,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATE9M:
+			rtl_set_bbreg(hw, RTXAGC_B_OFDM18_OFDM6,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATE12M:
+			rtl_set_bbreg(hw, RTXAGC_B_OFDM18_OFDM6,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATE18M:
+			rtl_set_bbreg(hw, RTXAGC_B_OFDM18_OFDM6,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATE24M:
+			rtl_set_bbreg(hw, RTXAGC_B_OFDM54_OFDM24,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATE36M:
+			rtl_set_bbreg(hw, RTXAGC_B_OFDM54_OFDM24,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATE48M:
+			rtl_set_bbreg(hw, RTXAGC_B_OFDM54_OFDM24,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATE54M:
+			rtl_set_bbreg(hw, RTXAGC_B_OFDM54_OFDM24,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEMCS0:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEMCS1:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEMCS2:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEMCS3:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS03_MCS00,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEMCS4:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEMCS5:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEMCS6:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEMCS7:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS07_MCS04,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEMCS8:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEMCS9:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEMCS10:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEMCS11:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS11_MCS08,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEMCS12:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEMCS13:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEMCS14:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEMCS15:
+			rtl_set_bbreg(hw, RTXAGC_B_MCS15_MCS12,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS0:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX3_NSS1INDEX0,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS1:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX3_NSS1INDEX0,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS2:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX3_NSS1INDEX0,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS3:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX3_NSS1INDEX0,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS4:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX7_NSS1INDEX4,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS5:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX7_NSS1INDEX4,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS6:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX7_NSS1INDEX4,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS7:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS1INDEX7_NSS1INDEX4,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS8:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX1_NSS1INDEX8,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEVHT1SS_MCS9:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX1_NSS1INDEX8,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS0:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX1_NSS1INDEX8,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS1:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX1_NSS1INDEX8,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS2:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX5_NSS2INDEX2,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS3:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX5_NSS2INDEX2,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS4:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX5_NSS2INDEX2,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS5:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX5_NSS2INDEX2,
+				      MASKBYTE3, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS6:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX9_NSS2INDEX6,
+				      MASKBYTE0, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS7:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX9_NSS2INDEX6,
+				      MASKBYTE1, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS8:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX9_NSS2INDEX6,
+				      MASKBYTE2, power_index);
+			break;
+		case DESC_RATEVHT2SS_MCS9:
+			rtl_set_bbreg(hw, RTXAGC_B_NSS2INDEX9_NSS2INDEX6,
+				      MASKBYTE3, power_index);
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+				 "Invalid Rate!!\n");
+			break;
+		}
+	} else {
+		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+			 "Invalid RFPath!!\n");
+	}
+}
+
+static void _rtl8821ae_phy_set_txpower_level_by_path(struct ieee80211_hw *hw,
+						     u8 *array, u8 path,
+						     u8 channel, u8 size)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 i;
+	u8 power_index;
+
+	for (i = 0; i < size; i++) {
+		power_index =
+		  _rtl8821ae_get_txpower_index(hw, path, array[i],
+					       rtlphy->current_chan_bw,
+					       channel);
+		_rtl8821ae_phy_set_txpower_index(hw, power_index, path,
+						 array[i]);
+	}
+}
+
+static void _rtl8821ae_phy_txpower_training_by_path(struct ieee80211_hw *hw,
+						    u8 bw, u8 channel, u8 path)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	u8 i;
+	u32 power_level, data, offset;
+
+	if (path >= rtlphy->num_total_rfpath)
+		return;
+
+	data = 0;
+	if (path == RF90_PATH_A) {
+		power_level =
+			_rtl8821ae_get_txpower_index(hw, RF90_PATH_A,
+			DESC_RATEMCS7, bw, channel);
+		offset =  RA_TXPWRTRAING;
+	} else {
+		power_level =
+			_rtl8821ae_get_txpower_index(hw, RF90_PATH_B,
+			DESC_RATEMCS7, bw, channel);
+		offset =  RB_TXPWRTRAING;
+	}
+
+	for (i = 0; i < 3; i++) {
+		if (i == 0)
+			power_level = power_level - 10;
+		else if (i == 1)
+			power_level = power_level - 8;
+		else
+			power_level = power_level - 6;
+
+		data |= (((power_level > 2) ? (power_level) : 2) << (i * 8));
+	}
+	rtl_set_bbreg(hw, offset, 0xffffff, data);
+}
+
+void rtl8821ae_phy_set_txpower_level_by_path(struct ieee80211_hw *hw,
+					     u8 channel, u8 path)
+{
+	/* struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); */
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 cck_rates[]  = {DESC_RATE1M, DESC_RATE2M, DESC_RATE5_5M,
+			      DESC_RATE11M};
+	u8 sizes_of_cck_retes = 4;
+	u8 ofdm_rates[]  = {DESC_RATE6M, DESC_RATE9M, DESC_RATE12M,
+				DESC_RATE18M, DESC_RATE24M, DESC_RATE36M,
+				DESC_RATE48M, DESC_RATE54M};
+	u8 sizes_of_ofdm_retes = 8;
+	u8 ht_rates_1t[]  = {DESC_RATEMCS0, DESC_RATEMCS1, DESC_RATEMCS2,
+				DESC_RATEMCS3, DESC_RATEMCS4, DESC_RATEMCS5,
+				DESC_RATEMCS6, DESC_RATEMCS7};
+	u8 sizes_of_ht_retes_1t = 8;
+	u8 ht_rates_2t[]  = {DESC_RATEMCS8, DESC_RATEMCS9,
+				DESC_RATEMCS10, DESC_RATEMCS11,
+				DESC_RATEMCS12, DESC_RATEMCS13,
+				DESC_RATEMCS14, DESC_RATEMCS15};
+	u8 sizes_of_ht_retes_2t = 8;
+	u8 vht_rates_1t[]  = {DESC_RATEVHT1SS_MCS0, DESC_RATEVHT1SS_MCS1,
+				DESC_RATEVHT1SS_MCS2, DESC_RATEVHT1SS_MCS3,
+				DESC_RATEVHT1SS_MCS4, DESC_RATEVHT1SS_MCS5,
+				DESC_RATEVHT1SS_MCS6, DESC_RATEVHT1SS_MCS7,
+			     DESC_RATEVHT1SS_MCS8, DESC_RATEVHT1SS_MCS9};
+	u8 vht_rates_2t[]  = {DESC_RATEVHT2SS_MCS0, DESC_RATEVHT2SS_MCS1,
+				DESC_RATEVHT2SS_MCS2, DESC_RATEVHT2SS_MCS3,
+				DESC_RATEVHT2SS_MCS4, DESC_RATEVHT2SS_MCS5,
+				DESC_RATEVHT2SS_MCS6, DESC_RATEVHT2SS_MCS7,
+				DESC_RATEVHT2SS_MCS8, DESC_RATEVHT2SS_MCS9};
+	u8 sizes_of_vht_retes = 10;
+
+	if (rtlhal->current_bandtype == BAND_ON_2_4G)
+		_rtl8821ae_phy_set_txpower_level_by_path(hw, cck_rates, path, channel,
+							 sizes_of_cck_retes);
+
+	_rtl8821ae_phy_set_txpower_level_by_path(hw, ofdm_rates, path, channel,
+						 sizes_of_ofdm_retes);
+	_rtl8821ae_phy_set_txpower_level_by_path(hw, ht_rates_1t, path, channel,
+						 sizes_of_ht_retes_1t);
+	_rtl8821ae_phy_set_txpower_level_by_path(hw, vht_rates_1t, path, channel,
+						 sizes_of_vht_retes);
+
+	if (rtlphy->num_total_rfpath >= 2) {
+		_rtl8821ae_phy_set_txpower_level_by_path(hw, ht_rates_2t, path,
+							 channel,
+							 sizes_of_ht_retes_2t);
+		_rtl8821ae_phy_set_txpower_level_by_path(hw, vht_rates_2t, path,
+							 channel,
+							 sizes_of_vht_retes);
+	}
+
+	_rtl8821ae_phy_txpower_training_by_path(hw, rtlphy->current_chan_bw,
+						channel, path);
+}
+
+/*just in case, write txpower in DW, to reduce time*/
+void rtl8821ae_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 path = 0;
+
+	for (path = RF90_PATH_A; path < rtlphy->num_total_rfpath; ++path)
+		rtl8821ae_phy_set_txpower_level_by_path(hw, channel, path);
+}
+
+static long _rtl8821ae_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+					    enum wireless_mode wirelessmode,
+					    u8 txpwridx)
+{
+	long offset;
+	long pwrout_dbm;
+
+	switch (wirelessmode) {
+	case WIRELESS_MODE_B:
+		offset = -7;
+		break;
+	case WIRELESS_MODE_G:
+	case WIRELESS_MODE_N_24G:
+		offset = -8;
+		break;
+	default:
+		offset = -8;
+		break;
+	}
+	pwrout_dbm = txpwridx / 2 + offset;
+	return pwrout_dbm;
+}
+
+void rtl8821ae_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	enum io_type iotype = IO_CMD_PAUSE_BAND0_DM_BY_SCAN;
+
+	if (!is_hal_stop(rtlhal)) {
+		switch (operation) {
+		case SCAN_OPT_BACKUP_BAND0:
+			iotype = IO_CMD_PAUSE_BAND0_DM_BY_SCAN;
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_IO_CMD,
+						      (u8 *)&iotype);
+
+			break;
+		case SCAN_OPT_BACKUP_BAND1:
+			iotype = IO_CMD_PAUSE_BAND1_DM_BY_SCAN;
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_IO_CMD,
+						      (u8 *)&iotype);
+
+			break;
+		case SCAN_OPT_RESTORE:
+			iotype = IO_CMD_RESUME_DM_BY_SCAN;
+			rtlpriv->cfg->ops->set_hw_reg(hw,
+						      HW_VAR_IO_CMD,
+						      (u8 *)&iotype);
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "Unknown Scan Backup operation.\n");
+			break;
+		}
+	}
+}
+
+static void _rtl8821ae_phy_set_reg_bw(struct rtl_priv *rtlpriv, u8 bw)
+{
+	u16 reg_rf_mode_bw, tmp = 0;
+
+	reg_rf_mode_bw = rtl_read_word(rtlpriv, REG_TRXPTCL_CTL);
+	switch (bw) {
+	case HT_CHANNEL_WIDTH_20:
+		rtl_write_word(rtlpriv, REG_TRXPTCL_CTL, reg_rf_mode_bw & 0xFE7F);
+		break;
+	case HT_CHANNEL_WIDTH_20_40:
+		tmp = reg_rf_mode_bw | BIT(7);
+		rtl_write_word(rtlpriv, REG_TRXPTCL_CTL, tmp & 0xFEFF);
+		break;
+	case HT_CHANNEL_WIDTH_80:
+		tmp = reg_rf_mode_bw | BIT(8);
+		rtl_write_word(rtlpriv, REG_TRXPTCL_CTL, tmp & 0xFF7F);
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "unknown Bandwidth: 0x%x\n", bw);
+		break;
+	}
+}
+
+static u8 _rtl8821ae_phy_get_secondary_chnl(struct rtl_priv *rtlpriv)
+{
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_mac *mac = rtl_mac(rtlpriv);
+	u8 sc_set_40 = 0, sc_set_20 = 0;
+
+	if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) {
+		if (mac->cur_80_prime_sc == PRIME_CHNL_OFFSET_LOWER)
+			sc_set_40 = VHT_DATA_SC_40_LOWER_OF_80MHZ;
+		else if (mac->cur_80_prime_sc == PRIME_CHNL_OFFSET_UPPER)
+			sc_set_40 = VHT_DATA_SC_40_UPPER_OF_80MHZ;
+		else
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				"SCMapping: Not Correct Primary40MHz Setting\n");
+
+		if ((mac->cur_40_prime_sc == PRIME_CHNL_OFFSET_LOWER) &&
+			(mac->cur_80_prime_sc == HAL_PRIME_CHNL_OFFSET_LOWER))
+			sc_set_20 = VHT_DATA_SC_20_LOWEST_OF_80MHZ;
+		else if ((mac->cur_40_prime_sc == PRIME_CHNL_OFFSET_UPPER) &&
+			(mac->cur_80_prime_sc == HAL_PRIME_CHNL_OFFSET_LOWER))
+			sc_set_20 = VHT_DATA_SC_20_LOWER_OF_80MHZ;
+		else if ((mac->cur_40_prime_sc == PRIME_CHNL_OFFSET_LOWER) &&
+			(mac->cur_80_prime_sc == HAL_PRIME_CHNL_OFFSET_UPPER))
+			sc_set_20 = VHT_DATA_SC_20_UPPER_OF_80MHZ;
+		else if ((mac->cur_40_prime_sc == PRIME_CHNL_OFFSET_UPPER) &&
+			(mac->cur_80_prime_sc == HAL_PRIME_CHNL_OFFSET_UPPER))
+			sc_set_20 = VHT_DATA_SC_20_UPPERST_OF_80MHZ;
+		else
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				"SCMapping: Not Correct Primary40MHz Setting\n");
+	} else if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+		if (mac->cur_40_prime_sc == PRIME_CHNL_OFFSET_UPPER)
+			sc_set_20 = VHT_DATA_SC_20_UPPER_OF_80MHZ;
+		else if (mac->cur_40_prime_sc == PRIME_CHNL_OFFSET_LOWER)
+			sc_set_20 = VHT_DATA_SC_20_LOWER_OF_80MHZ;
+		else
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "SCMapping: Not Correct Primary40MHz Setting\n");
+	}
+	return (sc_set_40 << 4) | sc_set_20;
+}
+
+void rtl8821ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 sub_chnl = 0;
+	u8 l1pk_val = 0;
+
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+		 "Switch to %s bandwidth\n",
+		  (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+		  "20MHz" :
+		  (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40 ?
+		  "40MHz" : "80MHz")));
+
+	_rtl8821ae_phy_set_reg_bw(rtlpriv, rtlphy->current_chan_bw);
+	sub_chnl = _rtl8821ae_phy_get_secondary_chnl(rtlpriv);
+	rtl_write_byte(rtlpriv, 0x0483, sub_chnl);
+
+	switch (rtlphy->current_chan_bw) {
+	case HT_CHANNEL_WIDTH_20:
+		rtl_set_bbreg(hw, RRFMOD, 0x003003C3, 0x00300200);
+		rtl_set_bbreg(hw, RADC_BUF_CLK, BIT(30), 0);
+
+		if (rtlphy->rf_type == RF_2T2R)
+			rtl_set_bbreg(hw, RL1PEAKTH, 0x03C00000, 7);
+		else
+			rtl_set_bbreg(hw, RL1PEAKTH, 0x03C00000, 8);
+		break;
+	case HT_CHANNEL_WIDTH_20_40:
+		rtl_set_bbreg(hw, RRFMOD, 0x003003C3, 0x00300201);
+		rtl_set_bbreg(hw, RADC_BUF_CLK, BIT(30), 0);
+		rtl_set_bbreg(hw, RRFMOD, 0x3C, sub_chnl);
+		rtl_set_bbreg(hw, RCCAONSEC, 0xf0000000, sub_chnl);
+
+		if (rtlphy->reg_837 & BIT(2))
+			l1pk_val = 6;
+		else {
+			if (rtlphy->rf_type == RF_2T2R)
+				l1pk_val = 7;
+			else
+				l1pk_val = 8;
+		}
+		/* 0x848[25:22] = 0x6 */
+		rtl_set_bbreg(hw, RL1PEAKTH, 0x03C00000, l1pk_val);
+
+		if (sub_chnl == VHT_DATA_SC_20_UPPER_OF_80MHZ)
+			rtl_set_bbreg(hw, RCCK_SYSTEM, BCCK_SYSTEM, 1);
+		else
+			rtl_set_bbreg(hw, RCCK_SYSTEM, BCCK_SYSTEM, 0);
+		break;
+
+	case HT_CHANNEL_WIDTH_80:
+		 /* 0x8ac[21,20,9:6,1,0]=8'b11100010 */
+		rtl_set_bbreg(hw, RRFMOD, 0x003003C3, 0x00300202);
+		/* 0x8c4[30] = 1 */
+		rtl_set_bbreg(hw, RADC_BUF_CLK, BIT(30), 1);
+		rtl_set_bbreg(hw, RRFMOD, 0x3C, sub_chnl);
+		rtl_set_bbreg(hw, RCCAONSEC, 0xf0000000, sub_chnl);
+
+		if (rtlphy->reg_837 & BIT(2))
+			l1pk_val = 5;
+		else {
+			if (rtlphy->rf_type == RF_2T2R)
+				l1pk_val = 6;
+			else
+				l1pk_val = 7;
+		}
+		rtl_set_bbreg(hw, RL1PEAKTH, 0x03C00000, l1pk_val);
+
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+		break;
+	}
+
+	rtl8812ae_fixspur(hw, rtlphy->current_chan_bw, rtlphy->current_channel);
+
+	rtl8821ae_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+	rtlphy->set_bwmode_inprogress = false;
+
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, "\n");
+}
+
+void rtl8821ae_phy_set_bw_mode(struct ieee80211_hw *hw,
+			    enum nl80211_channel_type ch_type)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 tmp_bw = rtlphy->current_chan_bw;
+
+	if (rtlphy->set_bwmode_inprogress)
+		return;
+	rtlphy->set_bwmode_inprogress = true;
+	if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw)))
+		rtl8821ae_phy_set_bw_mode_callback(hw);
+	else {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+			 "FALSE driver sleep or unload\n");
+		rtlphy->set_bwmode_inprogress = false;
+		rtlphy->current_chan_bw = tmp_bw;
+	}
+}
+
+void rtl8821ae_phy_sw_chnl_callback(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 channel = rtlphy->current_channel;
+	u8 path;
+	u32 data;
+
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+		 "switch to channel%d\n", rtlphy->current_channel);
+	if (is_hal_stop(rtlhal))
+		return;
+
+	if (36 <= channel && channel <= 48)
+		data = 0x494;
+	else if (50 <= channel && channel <= 64)
+		data = 0x453;
+	else if (100 <= channel && channel <= 116)
+		data = 0x452;
+	else if (118 <= channel)
+		data = 0x412;
+	else
+		data = 0x96a;
+	rtl_set_bbreg(hw, RFC_AREA, 0x1ffe0000, data);
+
+	for (path = RF90_PATH_A; path < rtlphy->num_total_rfpath; path++) {
+		if (36 <= channel && channel <= 64)
+			data = 0x101;
+		else if (100 <= channel && channel <= 140)
+			data = 0x301;
+		else if (140 < channel)
+			data = 0x501;
+		else
+			data = 0x000;
+		rtl8821ae_phy_set_rf_reg(hw, path, RF_CHNLBW,
+			BIT(18)|BIT(17)|BIT(16)|BIT(9)|BIT(8), data);
+
+		rtl8821ae_phy_set_rf_reg(hw, path, RF_CHNLBW,
+			BMASKBYTE0, channel);
+
+		if (channel > 14) {
+			if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
+				if (36 <= channel && channel <= 64)
+					data = 0x114E9;
+				else if (100 <= channel && channel <= 140)
+					data = 0x110E9;
+				else
+					data = 0x110E9;
+				rtl8821ae_phy_set_rf_reg(hw, path, RF_APK,
+					BRFREGOFFSETMASK, data);
+			}
+		}
+	}
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "\n");
+}
+
+u8 rtl8821ae_phy_sw_chnl(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u32 timeout = 1000, timecount = 0;
+	u8 channel = rtlphy->current_channel;
+
+	if (rtlphy->sw_chnl_inprogress)
+		return 0;
+	if (rtlphy->set_bwmode_inprogress)
+		return 0;
+
+	if ((is_hal_stop(rtlhal)) || (RT_CANNOT_IO(hw))) {
+		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+			 "sw_chnl_inprogress false driver sleep or unload\n");
+		return 0;
+	}
+	while (rtlphy->lck_inprogress && timecount < timeout) {
+		mdelay(50);
+		timecount += 50;
+	}
+
+	if (rtlphy->current_channel > 14 && rtlhal->current_bandtype != BAND_ON_5G)
+		rtl8821ae_phy_switch_wirelessband(hw, BAND_ON_5G);
+	else if (rtlphy->current_channel <= 14 && rtlhal->current_bandtype != BAND_ON_2_4G)
+		rtl8821ae_phy_switch_wirelessband(hw, BAND_ON_2_4G);
+
+	rtlphy->sw_chnl_inprogress = true;
+	if (channel == 0)
+		channel = 1;
+
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+		 "switch to channel%d, band type is %d\n",
+		 rtlphy->current_channel, rtlhal->current_bandtype);
+
+	rtl8821ae_phy_sw_chnl_callback(hw);
+
+	rtl8821ae_dm_clear_txpower_tracking_state(hw);
+	rtl8821ae_phy_set_txpower_level(hw, rtlphy->current_channel);
+
+	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "\n");
+	rtlphy->sw_chnl_inprogress = false;
+	return 1;
+}
+
+u8 _rtl8812ae_get_right_chnl_place_for_iqk(u8 chnl)
+{
+	u8 channel_all[TARGET_CHNL_NUM_2G_5G_8812] = {
+		1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+		14, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54,
+		56, 58, 60, 62, 64, 100, 102, 104, 106, 108,
+		110, 112, 114, 116, 118, 120, 122, 124, 126,
+		128, 130, 132, 134, 136, 138, 140, 149, 151,
+		153, 155, 157, 159, 161, 163, 165};
+	u8 place = chnl;
+
+	if (chnl > 14) {
+		for (place = 14; place < sizeof(channel_all); place++)
+			if (channel_all[place] == chnl)
+				return place-13;
+	}
+
+	return 0;
+}
+
+#define MACBB_REG_NUM 10
+#define AFE_REG_NUM 14
+#define RF_REG_NUM 3
+
+static void _rtl8821ae_iqk_backup_macbb(struct ieee80211_hw *hw,
+					u32 *macbb_backup,
+					u32 *backup_macbb_reg, u32 mac_bb_num)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 i;
+
+	rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/
+	/*save MACBB default value*/
+	for (i = 0; i < mac_bb_num; i++)
+		macbb_backup[i] = rtl_read_dword(rtlpriv, backup_macbb_reg[i]);
+
+	RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD, "BackupMacBB Success!!!!\n");
+}
+
+static void _rtl8821ae_iqk_backup_afe(struct ieee80211_hw *hw, u32 *afe_backup,
+				      u32 *backup_afe_REG, u32 afe_num)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 i;
+
+	rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/
+	/*Save AFE Parameters */
+	for (i = 0; i < afe_num; i++)
+		afe_backup[i] = rtl_read_dword(rtlpriv, backup_afe_REG[i]);
+	RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD, "BackupAFE Success!!!!\n");
+}
+
+static void _rtl8821ae_iqk_backup_rf(struct ieee80211_hw *hw, u32 *rfa_backup,
+				     u32 *rfb_backup, u32 *backup_rf_reg,
+				     u32 rf_num)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 i;
+
+	rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/
+	/*Save RF Parameters*/
+	for (i = 0; i < rf_num; i++) {
+		rfa_backup[i] = rtl_get_rfreg(hw, RF90_PATH_A, backup_rf_reg[i],
+					      BMASKDWORD);
+		rfb_backup[i] = rtl_get_rfreg(hw, RF90_PATH_B, backup_rf_reg[i],
+					      BMASKDWORD);
+	}
+	RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD, "BackupRF Success!!!!\n");
+}
+
+static void _rtl8821ae_iqk_configure_mac(
+		struct ieee80211_hw *hw
+		)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	/* ========MAC register setting========*/
+	rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/
+	rtl_write_byte(rtlpriv, 0x522, 0x3f);
+	rtl_set_bbreg(hw, 0x550, BIT(11) | BIT(3), 0x0);
+	rtl_write_byte(rtlpriv, 0x808, 0x00);		/*RX ante off*/
+	rtl_set_bbreg(hw, 0x838, 0xf, 0xc);		/*CCA off*/
+}
+
+static void _rtl8821ae_iqk_tx_fill_iqc(struct ieee80211_hw *hw,
+				       enum radio_path path, u32 tx_x, u32 tx_y)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	switch (path) {
+	case RF90_PATH_A:
+		/* [31] = 1 --> Page C1 */
+		rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1);
+		rtl_write_dword(rtlpriv, 0xc90, 0x00000080);
+		rtl_write_dword(rtlpriv, 0xcc4, 0x20040000);
+		rtl_write_dword(rtlpriv, 0xcc8, 0x20000000);
+		rtl_set_bbreg(hw, 0xccc, 0x000007ff, tx_y);
+		rtl_set_bbreg(hw, 0xcd4, 0x000007ff, tx_x);
+		RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+			 "TX_X = %x;;TX_Y = %x =====> fill to IQC\n",
+			 tx_x, tx_y);
+		RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+			 "0xcd4 = %x;;0xccc = %x ====>fill to IQC\n",
+			 rtl_get_bbreg(hw, 0xcd4, 0x000007ff),
+			 rtl_get_bbreg(hw, 0xccc, 0x000007ff));
+		break;
+	default:
+		break;
+	};
+}
+
+static void _rtl8821ae_iqk_rx_fill_iqc(struct ieee80211_hw *hw,
+				       enum radio_path path, u32 rx_x, u32 rx_y)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	switch (path) {
+	case RF90_PATH_A:
+		rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C */
+		rtl_set_bbreg(hw, 0xc10, 0x000003ff, rx_x>>1);
+		rtl_set_bbreg(hw, 0xc10, 0x03ff0000, rx_y>>1);
+		RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+			 "rx_x = %x;;rx_y = %x ====>fill to IQC\n",
+			 rx_x>>1, rx_y>>1);
+		RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+			 "0xc10 = %x ====>fill to IQC\n",
+			 rtl_read_dword(rtlpriv, 0xc10));
+		break;
+	default:
+		break;
+	};
+}
+
+#define cal_num 10
+
+static void _rtl8821ae_iqk_tx(struct ieee80211_hw *hw, enum radio_path path)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+	u32	tx_fail, rx_fail, delay_count, iqk_ready, cal_retry, cal = 0, temp_reg65;
+	int	tx_x = 0, tx_y = 0, rx_x = 0, rx_y = 0, tx_average = 0, rx_average = 0;
+	int	tx_x0[cal_num], tx_y0[cal_num], tx_x0_rxk[cal_num],
+		tx_y0_rxk[cal_num], rx_x0[cal_num], rx_y0[cal_num];
+	bool	tx0iqkok = false, rx0iqkok = false;
+	bool	vdf_enable = false;
+	int	i, k, vdf_y[3], vdf_x[3], tx_dt[3], rx_dt[3],
+		ii, dx = 0, dy = 0, tx_finish = 0, rx_finish = 0;
+
+	RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+			"BandWidth = %d.\n",
+			 rtlphy->current_chan_bw);
+	if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80)
+		vdf_enable = true;
+
+	while (cal < cal_num) {
+		switch (path) {
+		case RF90_PATH_A:
+			temp_reg65 = rtl_get_rfreg(hw, path, 0x65, 0xffffffff);
+			/* Path-A LOK */
+			rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /*[31] = 0 --> Page C*/
+			/*========Path-A AFE all on========*/
+			/*Port 0 DAC/ADC on*/
+			rtl_write_dword(rtlpriv, 0xc60, 0x77777777);
+			rtl_write_dword(rtlpriv, 0xc64, 0x77777777);
+			rtl_write_dword(rtlpriv, 0xc68, 0x19791979);
+			rtl_write_dword(rtlpriv, 0xc6c, 0x19791979);
+			rtl_write_dword(rtlpriv, 0xc70, 0x19791979);
+			rtl_write_dword(rtlpriv, 0xc74, 0x19791979);
+			rtl_write_dword(rtlpriv, 0xc78, 0x19791979);
+			rtl_write_dword(rtlpriv, 0xc7c, 0x19791979);
+			rtl_write_dword(rtlpriv, 0xc80, 0x19791979);
+			rtl_write_dword(rtlpriv, 0xc84, 0x19791979);
+
+			rtl_set_bbreg(hw, 0xc00, 0xf, 0x4); /*hardware 3-wire off*/
+
+			/* LOK Setting */
+			/* ====== LOK ====== */
+			/*DAC/ADC sampling rate (160 MHz)*/
+			rtl_set_bbreg(hw, 0xc5c, BIT(26) | BIT(25) | BIT(24), 0x7);
+
+			/* 2. LoK RF Setting (at BW = 20M) */
+			rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x80002);
+			rtl_set_rfreg(hw, path, 0x18, 0x00c00, 0x3);     /* BW 20M */
+			rtl_set_rfreg(hw, path, 0x30, RFREG_OFFSET_MASK, 0x20000);
+			rtl_set_rfreg(hw, path, 0x31, RFREG_OFFSET_MASK, 0x0003f);
+			rtl_set_rfreg(hw, path, 0x32, RFREG_OFFSET_MASK, 0xf3fc3);
+			rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, 0x931d5);
+			rtl_set_rfreg(hw, path, 0x8f, RFREG_OFFSET_MASK, 0x8a001);
+			rtl_set_bbreg(hw, 0xcb8, 0xf, 0xd);
+			rtl_write_dword(rtlpriv, 0x90c, 0x00008000);
+			rtl_write_dword(rtlpriv, 0xb00, 0x03000100);
+			rtl_set_bbreg(hw, 0xc94, BIT(0), 0x1);
+			rtl_write_dword(rtlpriv, 0x978, 0x29002000);/* TX (X,Y) */
+			rtl_write_dword(rtlpriv, 0x97c, 0xa9002000);/* RX (X,Y) */
+			rtl_write_dword(rtlpriv, 0x984, 0x00462910);/* [0]:AGC_en, [15]:idac_K_Mask */
+
+			rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 1 --> Page C1 */
+			rtl_write_dword(rtlpriv, 0xc88, 0x821403f4);
+
+			if (rtlhal->current_bandtype)
+				rtl_write_dword(rtlpriv, 0xc8c, 0x68163e96);
+			else
+				rtl_write_dword(rtlpriv, 0xc8c, 0x28163e96);
+
+			rtl_write_dword(rtlpriv, 0xc80, 0x18008c10);/* TX_TONE_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+			rtl_write_dword(rtlpriv, 0xc84, 0x38008c10);/* RX_TONE_idx[9:0], RxK_Mask[29] */
+			rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);/* cb8[20] \B1N SI/PI \A8Ï¥\CE\C5v\A4\C1\B5\B9 iqk_dpk module */
+			rtl_write_dword(rtlpriv, 0x980, 0xfa000000);
+			rtl_write_dword(rtlpriv, 0x980, 0xf8000000);
+
+			mdelay(10); /* Delay 10ms */
+			rtl_write_dword(rtlpriv, 0xcb8, 0x00000000);
+
+			rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C */
+			rtl_set_rfreg(hw, path, 0x58, 0x7fe00, rtl_get_rfreg(hw, path, 0x8, 0xffc00)); /* Load LOK */
+
+			switch (rtlphy->current_chan_bw) {
+			case 1:
+				rtl_set_rfreg(hw, path, 0x18, 0x00c00, 0x1);
+				break;
+			case 2:
+				rtl_set_rfreg(hw, path, 0x18, 0x00c00, 0x0);
+				break;
+			default:
+				break;
+			}
+
+			rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 1 --> Page C1 */
+
+			/* 3. TX RF Setting */
+			rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C */
+			rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x80000);
+			rtl_set_rfreg(hw, path, 0x30, RFREG_OFFSET_MASK, 0x20000);
+			rtl_set_rfreg(hw, path, 0x31, RFREG_OFFSET_MASK, 0x0003f);
+			rtl_set_rfreg(hw, path, 0x32, RFREG_OFFSET_MASK, 0xf3fc3);
+			rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, 0x931d5);
+			rtl_set_rfreg(hw, path, 0x8f, RFREG_OFFSET_MASK, 0x8a001);
+			rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x00000);
+			/* ODM_SetBBReg(pDM_Odm, 0xcb8, 0xf, 0xd); */
+			rtl_write_dword(rtlpriv, 0x90c, 0x00008000);
+			rtl_write_dword(rtlpriv, 0xb00, 0x03000100);
+			rtl_set_bbreg(hw, 0xc94, BIT(0), 0x1);
+			rtl_write_dword(rtlpriv, 0x978, 0x29002000);/* TX (X,Y) */
+			rtl_write_dword(rtlpriv, 0x97c, 0xa9002000);/* RX (X,Y) */
+			rtl_write_dword(rtlpriv, 0x984, 0x0046a910);/* [0]:AGC_en, [15]:idac_K_Mask */
+
+			rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 1 --> Page C1 */
+			rtl_write_dword(rtlpriv, 0xc88, 0x821403f1);
+			if (rtlhal->current_bandtype)
+				rtl_write_dword(rtlpriv, 0xc8c, 0x40163e96);
+			else
+				rtl_write_dword(rtlpriv, 0xc8c, 0x00163e96);
+
+			if (vdf_enable == 1) {
+				RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD, "VDF_enable\n");
+				for (k = 0; k <= 2; k++) {
+					switch (k) {
+					case 0:
+						rtl_write_dword(rtlpriv, 0xc80, 0x18008c38);/* TX_TONE_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+						rtl_write_dword(rtlpriv, 0xc84, 0x38008c38);/* RX_TONE_idx[9:0], RxK_Mask[29] */
+						rtl_set_bbreg(hw, 0xce8, BIT(31), 0x0);
+						break;
+					case 1:
+						rtl_set_bbreg(hw, 0xc80, BIT(28), 0x0);
+						rtl_set_bbreg(hw, 0xc84, BIT(28), 0x0);
+						rtl_set_bbreg(hw, 0xce8, BIT(31), 0x0);
+						break;
+					case 2:
+						RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+							"vdf_y[1] = %x;;;vdf_y[0] = %x\n", vdf_y[1]>>21 & 0x00007ff, vdf_y[0]>>21 & 0x00007ff);
+						RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+							"vdf_x[1] = %x;;;vdf_x[0] = %x\n", vdf_x[1]>>21 & 0x00007ff, vdf_x[0]>>21 & 0x00007ff);
+						tx_dt[cal] = (vdf_y[1]>>20)-(vdf_y[0]>>20);
+						tx_dt[cal] = ((16*tx_dt[cal])*10000/15708);
+						tx_dt[cal] = (tx_dt[cal] >> 1)+(tx_dt[cal] & BIT(0));
+						rtl_write_dword(rtlpriv, 0xc80, 0x18008c20);/* TX_TONE_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+						rtl_write_dword(rtlpriv, 0xc84, 0x38008c20);/* RX_TONE_idx[9:0], RxK_Mask[29] */
+						rtl_set_bbreg(hw, 0xce8, BIT(31), 0x1);
+						rtl_set_bbreg(hw, 0xce8, 0x3fff0000, tx_dt[cal] & 0x00003fff);
+						break;
+					default:
+						break;
+					}
+					rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);/* cb8[20] \B1N SI/PI \A8Ï¥\CE\C5v\A4\C1\B5\B9 iqk_dpk module */
+					cal_retry = 0;
+					while (1) {
+						/* one shot */
+						rtl_write_dword(rtlpriv, 0x980, 0xfa000000);
+						rtl_write_dword(rtlpriv, 0x980, 0xf8000000);
+
+						mdelay(10); /* Delay 10ms */
+						rtl_write_dword(rtlpriv, 0xcb8, 0x00000000);
+						delay_count = 0;
+						while (1) {
+							iqk_ready = rtl_get_bbreg(hw, 0xd00, BIT(10));
+							if ((~iqk_ready) || (delay_count > 20))
+								break;
+							else{
+								mdelay(1);
+								delay_count++;
+							}
+						}
+
+						if (delay_count < 20) {							/* If 20ms No Result, then cal_retry++ */
+							/* ============TXIQK Check============== */
+							tx_fail = rtl_get_bbreg(hw, 0xd00, BIT(12));
+
+							if (~tx_fail) {
+								rtl_write_dword(rtlpriv, 0xcb8, 0x02000000);
+								vdf_x[k] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21;
+								rtl_write_dword(rtlpriv, 0xcb8, 0x04000000);
+								vdf_y[k] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21;
+								tx0iqkok = true;
+								break;
+							} else {
+								rtl_set_bbreg(hw, 0xccc, 0x000007ff, 0x0);
+								rtl_set_bbreg(hw, 0xcd4, 0x000007ff, 0x200);
+								tx0iqkok = false;
+								cal_retry++;
+								if (cal_retry == 10)
+									break;
+							}
+						} else {
+							tx0iqkok = false;
+							cal_retry++;
+							if (cal_retry == 10)
+								break;
+						}
+					}
+				}
+				if (k == 3) {
+					tx_x0[cal] = vdf_x[k-1];
+					tx_y0[cal] = vdf_y[k-1];
+				}
+			} else {
+				rtl_write_dword(rtlpriv, 0xc80, 0x18008c10);/* TX_TONE_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+				rtl_write_dword(rtlpriv, 0xc84, 0x38008c10);/* RX_TONE_idx[9:0], RxK_Mask[29] */
+				rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);/* cb8[20] \B1N SI/PI \A8Ï¥\CE\C5v\A4\C1\B5\B9 iqk_dpk module */
+				cal_retry = 0;
+				while (1) {
+					/* one shot */
+					rtl_write_dword(rtlpriv, 0x980, 0xfa000000);
+					rtl_write_dword(rtlpriv, 0x980, 0xf8000000);
+
+					mdelay(10); /* Delay 10ms */
+					rtl_write_dword(rtlpriv, 0xcb8, 0x00000000);
+					delay_count = 0;
+					while (1) {
+						iqk_ready = rtl_get_bbreg(hw, 0xd00, BIT(10));
+						if ((~iqk_ready) || (delay_count > 20))
+							break;
+						else{
+							mdelay(1);
+							delay_count++;
+						}
+					}
+
+					if (delay_count < 20) {							/* If 20ms No Result, then cal_retry++ */
+						/* ============TXIQK Check============== */
+						tx_fail = rtl_get_bbreg(hw, 0xd00, BIT(12));
+
+						if (~tx_fail) {
+							rtl_write_dword(rtlpriv, 0xcb8, 0x02000000);
+							tx_x0[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21;
+							rtl_write_dword(rtlpriv, 0xcb8, 0x04000000);
+							tx_y0[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21;
+							tx0iqkok = true;
+							break;
+						} else {
+							rtl_set_bbreg(hw, 0xccc, 0x000007ff, 0x0);
+							rtl_set_bbreg(hw, 0xcd4, 0x000007ff, 0x200);
+							tx0iqkok = false;
+							cal_retry++;
+							if (cal_retry == 10)
+								break;
+						}
+					} else {
+						tx0iqkok = false;
+						cal_retry++;
+						if (cal_retry == 10)
+							break;
+					}
+				}
+			}
+
+			if (tx0iqkok == false)
+				break;				/* TXK fail, Don't do RXK */
+
+			if (vdf_enable == 1) {
+				rtl_set_bbreg(hw, 0xce8, BIT(31), 0x0);    /* TX VDF Disable */
+				RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD, "RXVDF Start\n");
+				for (k = 0; k <= 2; k++) {
+					/* ====== RX mode TXK (RXK Step 1) ====== */
+					rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C */
+					/* 1. TX RF Setting */
+					rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x80000);
+					rtl_set_rfreg(hw, path, 0x30, RFREG_OFFSET_MASK, 0x30000);
+					rtl_set_rfreg(hw, path, 0x31, RFREG_OFFSET_MASK, 0x00029);
+					rtl_set_rfreg(hw, path, 0x32, RFREG_OFFSET_MASK, 0xd7ffb);
+					rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, temp_reg65);
+					rtl_set_rfreg(hw, path, 0x8f, RFREG_OFFSET_MASK, 0x8a001);
+					rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x00000);
+
+					rtl_set_bbreg(hw, 0xcb8, 0xf, 0xd);
+					rtl_write_dword(rtlpriv, 0x978, 0x29002000);/* TX (X,Y) */
+					rtl_write_dword(rtlpriv, 0x97c, 0xa9002000);/* RX (X,Y) */
+					rtl_write_dword(rtlpriv, 0x984, 0x0046a910);/* [0]:AGC_en, [15]:idac_K_Mask */
+					rtl_write_dword(rtlpriv, 0x90c, 0x00008000);
+					rtl_write_dword(rtlpriv, 0xb00, 0x03000100);
+					rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 1 --> Page C1 */
+					switch (k) {
+					case 0:
+						{
+							rtl_write_dword(rtlpriv, 0xc80, 0x18008c38);/* TX_TONE_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+							rtl_write_dword(rtlpriv, 0xc84, 0x38008c38);/* RX_TONE_idx[9:0], RxK_Mask[29] */
+							rtl_set_bbreg(hw, 0xce8, BIT(30), 0x0);
+						}
+						break;
+					case 1:
+						{
+							rtl_write_dword(rtlpriv, 0xc80, 0x08008c38);/* TX_TONE_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+							rtl_write_dword(rtlpriv, 0xc84, 0x28008c38);/* RX_TONE_idx[9:0], RxK_Mask[29] */
+							rtl_set_bbreg(hw, 0xce8, BIT(30), 0x0);
+						}
+						break;
+					case 2:
+						{
+							RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+							"VDF_Y[1] = %x;;;VDF_Y[0] = %x\n",
+							vdf_y[1]>>21 & 0x00007ff, vdf_y[0]>>21 & 0x00007ff);
+							RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+							"VDF_X[1] = %x;;;VDF_X[0] = %x\n",
+							vdf_x[1]>>21 & 0x00007ff, vdf_x[0]>>21 & 0x00007ff);
+							rx_dt[cal] = (vdf_y[1]>>20)-(vdf_y[0]>>20);
+							RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD, "Rx_dt = %d\n", rx_dt[cal]);
+							rx_dt[cal] = ((16*rx_dt[cal])*10000/13823);
+							rx_dt[cal] = (rx_dt[cal] >> 1)+(rx_dt[cal] & BIT(0));
+							rtl_write_dword(rtlpriv, 0xc80, 0x18008c20);/* TX_TONE_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+							rtl_write_dword(rtlpriv, 0xc84, 0x38008c20);/* RX_TONE_idx[9:0], RxK_Mask[29] */
+							rtl_set_bbreg(hw, 0xce8, 0x00003fff, rx_dt[cal] & 0x00003fff);
+						}
+						break;
+					default:
+						break;
+					}
+					rtl_write_dword(rtlpriv, 0xc88, 0x821603e0);
+					rtl_write_dword(rtlpriv, 0xc8c, 0x68163e96);
+					rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);/* cb8[20] \B1N SI/PI \A8Ï¥\CE\C5v\A4\C1\B5\B9 iqk_dpk module */
+					cal_retry = 0;
+					while (1) {
+						/* one shot */
+						rtl_write_dword(rtlpriv, 0x980, 0xfa000000);
+						rtl_write_dword(rtlpriv, 0x980, 0xf8000000);
+
+						mdelay(10); /* Delay 10ms */
+						rtl_write_dword(rtlpriv, 0xcb8, 0x00000000);
+						delay_count = 0;
+						while (1) {
+							iqk_ready = rtl_get_bbreg(hw, 0xd00, BIT(10));
+							if ((~iqk_ready) || (delay_count > 20))
+								break;
+							else{
+								mdelay(1);
+								delay_count++;
+							}
+						}
+
+						if (delay_count < 20) {							/* If 20ms No Result, then cal_retry++ */
+							/* ============TXIQK Check============== */
+							tx_fail = rtl_get_bbreg(hw, 0xd00, BIT(12));
+
+							if (~tx_fail) {
+								rtl_write_dword(rtlpriv, 0xcb8, 0x02000000);
+								tx_x0_rxk[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21;
+								rtl_write_dword(rtlpriv, 0xcb8, 0x04000000);
+								tx_y0_rxk[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21;
+								tx0iqkok = true;
+								break;
+							} else{
+								tx0iqkok = false;
+								cal_retry++;
+								if (cal_retry == 10)
+									break;
+							}
+						} else {
+							tx0iqkok = false;
+							cal_retry++;
+							if (cal_retry == 10)
+								break;
+						}
+					}
+
+					if (tx0iqkok == false) {   /* If RX mode TXK fail, then take TXK Result */
+						tx_x0_rxk[cal] = tx_x0[cal];
+						tx_y0_rxk[cal] = tx_y0[cal];
+						tx0iqkok = true;
+						RT_TRACE(rtlpriv,
+							 COMP_IQK,
+							 DBG_LOUD,
+							 "RXK Step 1 fail\n");
+					}
+
+					/* ====== RX IQK ====== */
+					rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C */
+					/* 1. RX RF Setting */
+					rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x80000);
+					rtl_set_rfreg(hw, path, 0x30, RFREG_OFFSET_MASK, 0x30000);
+					rtl_set_rfreg(hw, path, 0x31, RFREG_OFFSET_MASK, 0x0002f);
+					rtl_set_rfreg(hw, path, 0x32, RFREG_OFFSET_MASK, 0xfffbb);
+					rtl_set_rfreg(hw, path, 0x8f, RFREG_OFFSET_MASK, 0x88001);
+					rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, 0x931d8);
+					rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x00000);
+
+					rtl_set_bbreg(hw, 0x978, 0x03FF8000, (tx_x0_rxk[cal])>>21&0x000007ff);
+					rtl_set_bbreg(hw, 0x978, 0x000007FF, (tx_y0_rxk[cal])>>21&0x000007ff);
+					rtl_set_bbreg(hw, 0x978, BIT(31), 0x1);
+					rtl_set_bbreg(hw, 0x97c, BIT(31), 0x0);
+					rtl_set_bbreg(hw, 0xcb8, 0xF, 0xe);
+					rtl_write_dword(rtlpriv, 0x90c, 0x00008000);
+					rtl_write_dword(rtlpriv, 0x984, 0x0046a911);
+
+					rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 1 --> Page C1 */
+					rtl_set_bbreg(hw, 0xc80, BIT(29), 0x1);
+					rtl_set_bbreg(hw, 0xc84, BIT(29), 0x0);
+					rtl_write_dword(rtlpriv, 0xc88, 0x02140119);
+
+					rtl_write_dword(rtlpriv, 0xc8c, 0x28160d00); /* pDM_Odm->SupportInterface == 1 */
+
+					if (k == 2)
+						rtl_set_bbreg(hw, 0xce8, BIT(30), 0x1);  /* RX VDF Enable */
+					rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);/* cb8[20] \B1N SI/PI \A8Ï¥\CE\C5v\A4\C1\B5\B9 iqk_dpk module */
+
+					cal_retry = 0;
+					while (1) {
+						/* one shot */
+						rtl_write_dword(rtlpriv, 0x980, 0xfa000000);
+						rtl_write_dword(rtlpriv, 0x980, 0xf8000000);
+
+						mdelay(10); /* Delay 10ms */
+						rtl_write_dword(rtlpriv, 0xcb8, 0x00000000);
+						delay_count = 0;
+						while (1) {
+							iqk_ready = rtl_get_bbreg(hw, 0xd00, BIT(10));
+							if ((~iqk_ready) || (delay_count > 20))
+								break;
+							else{
+								mdelay(1);
+								delay_count++;
+							}
+						}
+
+						if (delay_count < 20) {	/* If 20ms No Result, then cal_retry++ */
+							/* ============RXIQK Check============== */
+							rx_fail = rtl_get_bbreg(hw, 0xd00, BIT(11));
+							if (rx_fail == 0) {
+								rtl_write_dword(rtlpriv, 0xcb8, 0x06000000);
+								vdf_x[k] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21;
+								rtl_write_dword(rtlpriv, 0xcb8, 0x08000000);
+								vdf_y[k] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21;
+								rx0iqkok = true;
+								break;
+							} else {
+								rtl_set_bbreg(hw, 0xc10, 0x000003ff, 0x200>>1);
+								rtl_set_bbreg(hw, 0xc10, 0x03ff0000, 0x0>>1);
+								rx0iqkok = false;
+								cal_retry++;
+								if (cal_retry == 10)
+									break;
+
+							}
+						} else{
+							rx0iqkok = false;
+							cal_retry++;
+							if (cal_retry == 10)
+								break;
+						}
+					}
+
+				}
+				if (k == 3) {
+					rx_x0[cal] = vdf_x[k-1];
+					rx_y0[cal] = vdf_y[k-1];
+				}
+				rtl_set_bbreg(hw, 0xce8, BIT(31), 0x1);    /* TX VDF Enable */
+			}
+
+			else{
+				/* ====== RX mode TXK (RXK Step 1) ====== */
+				rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C */
+				/* 1. TX RF Setting */
+				rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x80000);
+				rtl_set_rfreg(hw, path, 0x30, RFREG_OFFSET_MASK, 0x30000);
+				rtl_set_rfreg(hw, path, 0x31, RFREG_OFFSET_MASK, 0x00029);
+				rtl_set_rfreg(hw, path, 0x32, RFREG_OFFSET_MASK, 0xd7ffb);
+				rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, temp_reg65);
+				rtl_set_rfreg(hw, path, 0x8f, RFREG_OFFSET_MASK, 0x8a001);
+				rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x00000);
+				rtl_write_dword(rtlpriv, 0x90c, 0x00008000);
+				rtl_write_dword(rtlpriv, 0xb00, 0x03000100);
+				rtl_write_dword(rtlpriv, 0x984, 0x0046a910);/* [0]:AGC_en, [15]:idac_K_Mask */
+
+				rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 1 --> Page C1 */
+				rtl_write_dword(rtlpriv, 0xc80, 0x18008c10);/* TX_TONE_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+				rtl_write_dword(rtlpriv, 0xc84, 0x38008c10);/* RX_TONE_idx[9:0], RxK_Mask[29] */
+				rtl_write_dword(rtlpriv, 0xc88, 0x821603e0);
+				/* ODM_Write4Byte(pDM_Odm, 0xc8c, 0x68163e96); */
+				rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);/* cb8[20] \B1N SI/PI \A8Ï¥\CE\C5v\A4\C1\B5\B9 iqk_dpk module */
+				cal_retry = 0;
+				while (1) {
+					/* one shot */
+					rtl_write_dword(rtlpriv, 0x980, 0xfa000000);
+					rtl_write_dword(rtlpriv, 0x980, 0xf8000000);
+
+					mdelay(10); /* Delay 10ms */
+					rtl_write_dword(rtlpriv, 0xcb8, 0x00000000);
+					delay_count = 0;
+					while (1) {
+						iqk_ready = rtl_get_bbreg(hw, 0xd00, BIT(10));
+						if ((~iqk_ready) || (delay_count > 20))
+							break;
+						else{
+							mdelay(1);
+							delay_count++;
+						}
+					}
+
+					if (delay_count < 20) {							/* If 20ms No Result, then cal_retry++ */
+						/* ============TXIQK Check============== */
+						tx_fail = rtl_get_bbreg(hw, 0xd00, BIT(12));
+
+						if (~tx_fail) {
+							rtl_write_dword(rtlpriv, 0xcb8, 0x02000000);
+							tx_x0_rxk[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21;
+							rtl_write_dword(rtlpriv, 0xcb8, 0x04000000);
+							tx_y0_rxk[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21;
+							tx0iqkok = true;
+							break;
+						} else {
+							tx0iqkok = false;
+							cal_retry++;
+							if (cal_retry == 10)
+								break;
+						}
+					} else{
+						tx0iqkok = false;
+						cal_retry++;
+						if (cal_retry == 10)
+							break;
+					}
+				}
+
+				if (tx0iqkok == false) {   /* If RX mode TXK fail, then take TXK Result */
+					tx_x0_rxk[cal] = tx_x0[cal];
+					tx_y0_rxk[cal] = tx_y0[cal];
+					tx0iqkok = true;
+					RT_TRACE(rtlpriv, COMP_IQK,
+						 DBG_LOUD, "1");
+				}
+
+				/* ====== RX IQK ====== */
+				rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C */
+				/* 1. RX RF Setting */
+				rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x80000);
+				rtl_set_rfreg(hw, path, 0x30, RFREG_OFFSET_MASK, 0x30000);
+				rtl_set_rfreg(hw, path, 0x31, RFREG_OFFSET_MASK, 0x0002f);
+				rtl_set_rfreg(hw, path, 0x32, RFREG_OFFSET_MASK, 0xfffbb);
+				rtl_set_rfreg(hw, path, 0x8f, RFREG_OFFSET_MASK, 0x88001);
+				rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, 0x931d8);
+				rtl_set_rfreg(hw, path, 0xef, RFREG_OFFSET_MASK, 0x00000);
+
+				rtl_set_bbreg(hw, 0x978, 0x03FF8000, (tx_x0_rxk[cal])>>21&0x000007ff);
+				rtl_set_bbreg(hw, 0x978, 0x000007FF, (tx_y0_rxk[cal])>>21&0x000007ff);
+				rtl_set_bbreg(hw, 0x978, BIT(31), 0x1);
+				rtl_set_bbreg(hw, 0x97c, BIT(31), 0x0);
+				/* ODM_SetBBReg(pDM_Odm, 0xcb8, 0xF, 0xe); */
+				rtl_write_dword(rtlpriv, 0x90c, 0x00008000);
+				rtl_write_dword(rtlpriv, 0x984, 0x0046a911);
+
+				rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 1 --> Page C1 */
+				rtl_write_dword(rtlpriv, 0xc80, 0x38008c10);/* TX_TONE_idx[9:0], TxK_Mask[29] TX_Tone = 16 */
+				rtl_write_dword(rtlpriv, 0xc84, 0x18008c10);/* RX_TONE_idx[9:0], RxK_Mask[29] */
+				rtl_write_dword(rtlpriv, 0xc88, 0x02140119);
+
+				rtl_write_dword(rtlpriv, 0xc8c, 0x28160d00); /*pDM_Odm->SupportInterface == 1*/
+
+				rtl_write_dword(rtlpriv, 0xcb8, 0x00100000);/* cb8[20] \B1N SI/PI \A8Ï¥\CE\C5v\A4\C1\B5\B9 iqk_dpk module */
+
+				cal_retry = 0;
+				while (1) {
+					/* one shot */
+					rtl_write_dword(rtlpriv, 0x980, 0xfa000000);
+					rtl_write_dword(rtlpriv, 0x980, 0xf8000000);
+
+					mdelay(10); /* Delay 10ms */
+					rtl_write_dword(rtlpriv, 0xcb8, 0x00000000);
+					delay_count = 0;
+					while (1) {
+						iqk_ready = rtl_get_bbreg(hw, 0xd00, BIT(10));
+						if ((~iqk_ready) || (delay_count > 20))
+							break;
+						else{
+							mdelay(1);
+							delay_count++;
+						}
+					}
+
+					if (delay_count < 20) {	/* If 20ms No Result, then cal_retry++ */
+						/* ============RXIQK Check============== */
+						rx_fail = rtl_get_bbreg(hw, 0xd00, BIT(11));
+						if (rx_fail == 0) {
+							rtl_write_dword(rtlpriv, 0xcb8, 0x06000000);
+							rx_x0[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21;
+							rtl_write_dword(rtlpriv, 0xcb8, 0x08000000);
+							rx_y0[cal] = rtl_get_bbreg(hw, 0xd00, 0x07ff0000)<<21;
+							rx0iqkok = true;
+							break;
+						} else{
+							rtl_set_bbreg(hw, 0xc10, 0x000003ff, 0x200>>1);
+							rtl_set_bbreg(hw, 0xc10, 0x03ff0000, 0x0>>1);
+							rx0iqkok = false;
+							cal_retry++;
+							if (cal_retry == 10)
+								break;
+
+						}
+					} else{
+						rx0iqkok = false;
+						cal_retry++;
+						if (cal_retry == 10)
+							break;
+					}
+				}
+			}
+
+			if (tx0iqkok)
+				tx_average++;
+			if (rx0iqkok)
+				rx_average++;
+			rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C */
+			rtl_set_rfreg(hw, path, 0x65, RFREG_OFFSET_MASK, temp_reg65);
+			break;
+		default:
+			break;
+		}
+		cal++;
+	}
+
+	/* FillIQK Result */
+	switch (path) {
+	case RF90_PATH_A:
+		RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+			 "========Path_A =======\n");
+		if (tx_average == 0)
+			break;
+
+		for (i = 0; i < tx_average; i++) {
+			RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+				 "TX_X0_RXK[%d] = %x ;; TX_Y0_RXK[%d] = %x\n", i,
+				 (tx_x0_rxk[i])>>21&0x000007ff, i,
+				 (tx_y0_rxk[i])>>21&0x000007ff);
+			RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+				 "TX_X0[%d] = %x ;; TX_Y0[%d] = %x\n", i,
+				 (tx_x0[i])>>21&0x000007ff, i,
+				 (tx_y0[i])>>21&0x000007ff);
+		}
+		for (i = 0; i < tx_average; i++) {
+			for (ii = i+1; ii < tx_average; ii++) {
+				dx = (tx_x0[i]>>21) - (tx_x0[ii]>>21);
+				if (dx < 3 && dx > -3) {
+					dy = (tx_y0[i]>>21) - (tx_y0[ii]>>21);
+					if (dy < 3 && dy > -3) {
+						tx_x = ((tx_x0[i]>>21) + (tx_x0[ii]>>21))/2;
+						tx_y = ((tx_y0[i]>>21) + (tx_y0[ii]>>21))/2;
+						tx_finish = 1;
+						break;
+					}
+				}
+			}
+			if (tx_finish == 1)
+				break;
+		}
+
+		if (tx_finish == 1)
+			_rtl8821ae_iqk_tx_fill_iqc(hw, path, tx_x, tx_y); /* ? */
+		else
+			_rtl8821ae_iqk_tx_fill_iqc(hw, path, 0x200, 0x0);
+
+		if (rx_average == 0)
+			break;
+
+		for (i = 0; i < rx_average; i++)
+			RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+				"RX_X0[%d] = %x ;; RX_Y0[%d] = %x\n", i,
+				(rx_x0[i])>>21&0x000007ff, i,
+				(rx_y0[i])>>21&0x000007ff);
+		for (i = 0; i < rx_average; i++) {
+			for (ii = i+1; ii < rx_average; ii++) {
+				dx = (rx_x0[i]>>21) - (rx_x0[ii]>>21);
+				if (dx < 4 && dx > -4) {
+					dy = (rx_y0[i]>>21) - (rx_y0[ii]>>21);
+					if (dy < 4 && dy > -4) {
+						rx_x = ((rx_x0[i]>>21) + (rx_x0[ii]>>21))/2;
+						rx_y = ((rx_y0[i]>>21) + (rx_y0[ii]>>21))/2;
+						rx_finish = 1;
+						break;
+					}
+				}
+			}
+			if (rx_finish == 1)
+				break;
+		}
+
+		if (rx_finish == 1)
+			_rtl8821ae_iqk_rx_fill_iqc(hw, path, rx_x, rx_y);
+		else
+			_rtl8821ae_iqk_rx_fill_iqc(hw, path, 0x200, 0x0);
+		break;
+	default:
+		break;
+	}
+}
+
+static void _rtl8821ae_iqk_restore_rf(struct ieee80211_hw *hw,
+				      enum radio_path path,
+				      u32 *backup_rf_reg,
+				      u32 *rf_backup, u32 rf_reg_num)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u32 i;
+
+	rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C */
+	for (i = 0; i < RF_REG_NUM; i++)
+		rtl_set_rfreg(hw, path, backup_rf_reg[i], RFREG_OFFSET_MASK,
+			      rf_backup[i]);
+
+	switch (path) {
+	case RF90_PATH_A:
+		RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+			 "RestoreRF Path A Success!!!!\n");
+		break;
+	default:
+			break;
+	}
+}
+
+static void _rtl8821ae_iqk_restore_afe(struct ieee80211_hw *hw,
+				       u32 *afe_backup, u32 *backup_afe_reg,
+				       u32 afe_num)
+{
+	u32 i;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C */
+	/* Reload AFE Parameters */
+	for (i = 0; i < afe_num; i++)
+		rtl_write_dword(rtlpriv, backup_afe_reg[i], afe_backup[i]);
+	rtl_set_bbreg(hw, 0x82c, BIT(31), 0x1); /* [31] = 1 --> Page C1 */
+	rtl_write_dword(rtlpriv, 0xc80, 0x0);
+	rtl_write_dword(rtlpriv, 0xc84, 0x0);
+	rtl_write_dword(rtlpriv, 0xc88, 0x0);
+	rtl_write_dword(rtlpriv, 0xc8c, 0x3c000000);
+	rtl_write_dword(rtlpriv, 0xc90, 0x00000080);
+	rtl_write_dword(rtlpriv, 0xc94, 0x00000000);
+	rtl_write_dword(rtlpriv, 0xcc4, 0x20040000);
+	rtl_write_dword(rtlpriv, 0xcc8, 0x20000000);
+	rtl_write_dword(rtlpriv, 0xcb8, 0x0);
+	RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD, "RestoreAFE Success!!!!\n");
+}
+
+static void _rtl8821ae_iqk_restore_macbb(struct ieee80211_hw *hw,
+					 u32 *macbb_backup,
+					 u32 *backup_macbb_reg,
+					 u32 macbb_num)
+{
+	u32 i;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtl_set_bbreg(hw, 0x82c, BIT(31), 0x0); /* [31] = 0 --> Page C */
+	/* Reload MacBB Parameters */
+	for (i = 0; i < macbb_num; i++)
+		rtl_write_dword(rtlpriv, backup_macbb_reg[i], macbb_backup[i]);
+	RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD, "RestoreMacBB Success!!!!\n");
+}
+
+#undef MACBB_REG_NUM
+#undef AFE_REG_NUM
+#undef RF_REG_NUM
+
+#define MACBB_REG_NUM 11
+#define AFE_REG_NUM 12
+#define RF_REG_NUM 3
+
+static void _rtl8821ae_phy_iq_calibrate(struct ieee80211_hw *hw)
+{
+	u32	macbb_backup[MACBB_REG_NUM];
+	u32 afe_backup[AFE_REG_NUM];
+	u32 rfa_backup[RF_REG_NUM];
+	u32 rfb_backup[RF_REG_NUM];
+	u32 backup_macbb_reg[MACBB_REG_NUM] = {
+		0xb00, 0x520, 0x550, 0x808, 0x90c, 0xc00, 0xc50,
+		0xe00, 0xe50, 0x838, 0x82c
+	};
+	u32 backup_afe_reg[AFE_REG_NUM] = {
+		0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74,
+		0xc78, 0xc7c, 0xc80, 0xc84, 0xcb8
+	};
+	u32	backup_rf_reg[RF_REG_NUM] = {0x65, 0x8f, 0x0};
+
+	_rtl8821ae_iqk_backup_macbb(hw, macbb_backup, backup_macbb_reg,
+				    MACBB_REG_NUM);
+	_rtl8821ae_iqk_backup_afe(hw, afe_backup, backup_afe_reg, AFE_REG_NUM);
+	_rtl8821ae_iqk_backup_rf(hw, rfa_backup, rfb_backup, backup_rf_reg,
+				 RF_REG_NUM);
+
+	_rtl8821ae_iqk_configure_mac(hw);
+	_rtl8821ae_iqk_tx(hw, RF90_PATH_A);
+	_rtl8821ae_iqk_restore_rf(hw, RF90_PATH_A, backup_rf_reg, rfa_backup,
+				  RF_REG_NUM);
+
+	_rtl8821ae_iqk_restore_afe(hw, afe_backup, backup_afe_reg, AFE_REG_NUM);
+	_rtl8821ae_iqk_restore_macbb(hw, macbb_backup, backup_macbb_reg,
+				     MACBB_REG_NUM);
+}
+
+static void _rtl8821ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool main)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	/* struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); */
+	/* struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); */
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+
+	if (main)
+		rtl_set_bbreg(hw, RA_RFE_PINMUX + 4, BIT(29) | BIT(28), 0x1);
+	else
+		rtl_set_bbreg(hw, RA_RFE_PINMUX + 4, BIT(29) | BIT(28), 0x2);
+}
+
+#undef IQK_ADDA_REG_NUM
+#undef IQK_DELAY_TIME
+
+void rtl8812ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery)
+{
+}
+
+void rtl8812ae_do_iqk(struct ieee80211_hw *hw, u8 delta_thermal_index,
+		      u8 thermal_value, u8 threshold)
+{
+	struct rtl_dm	*rtldm = rtl_dm(rtl_priv(hw));
+
+	rtldm->thermalvalue_iqk = thermal_value;
+	rtl8812ae_phy_iq_calibrate(hw, false);
+}
+
+void rtl8821ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	if (!rtlphy->lck_inprogress) {
+		spin_lock(&rtlpriv->locks.iqk_lock);
+		rtlphy->lck_inprogress = true;
+		spin_unlock(&rtlpriv->locks.iqk_lock);
+
+		_rtl8821ae_phy_iq_calibrate(hw);
+
+		spin_lock(&rtlpriv->locks.iqk_lock);
+		rtlphy->lck_inprogress = false;
+		spin_unlock(&rtlpriv->locks.iqk_lock);
+	}
+}
+
+void rtl8821ae_reset_iqk_result(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 i;
+
+	RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD,
+		 "rtl8812ae_dm_reset_iqk_result:: settings regs %d default regs %d\n",
+		 (int)(sizeof(rtlphy->iqk_matrix) /
+		 sizeof(struct iqk_matrix_regs)),
+		 IQK_MATRIX_SETTINGS_NUM);
+
+	for (i = 0; i < IQK_MATRIX_SETTINGS_NUM; i++) {
+		rtlphy->iqk_matrix[i].value[0][0] = 0x100;
+		rtlphy->iqk_matrix[i].value[0][2] = 0x100;
+		rtlphy->iqk_matrix[i].value[0][4] = 0x100;
+		rtlphy->iqk_matrix[i].value[0][6] = 0x100;
+
+		rtlphy->iqk_matrix[i].value[0][1] = 0x0;
+		rtlphy->iqk_matrix[i].value[0][3] = 0x0;
+		rtlphy->iqk_matrix[i].value[0][5] = 0x0;
+		rtlphy->iqk_matrix[i].value[0][7] = 0x0;
+
+		rtlphy->iqk_matrix[i].iqk_done = false;
+	}
+}
+
+void rtl8821ae_do_iqk(struct ieee80211_hw *hw, u8 delta_thermal_index,
+		      u8 thermal_value, u8 threshold)
+{
+	struct rtl_dm	*rtldm = rtl_dm(rtl_priv(hw));
+
+	rtl8821ae_reset_iqk_result(hw);
+
+	rtldm->thermalvalue_iqk = thermal_value;
+	rtl8821ae_phy_iq_calibrate(hw, false);
+}
+
+void rtl8821ae_phy_lc_calibrate(struct ieee80211_hw *hw)
+{
+}
+
+void rtl8821ae_phy_ap_calibrate(struct ieee80211_hw *hw, char delta)
+{
+}
+
+void rtl8821ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
+{
+	_rtl8821ae_phy_set_rfpath_switch(hw, bmain);
+}
+
+bool rtl8821ae_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	bool postprocessing = false;
+
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+		 "-->IO Cmd(%#x), set_io_inprogress(%d)\n",
+		  iotype, rtlphy->set_io_inprogress);
+	do {
+		switch (iotype) {
+		case IO_CMD_RESUME_DM_BY_SCAN:
+			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+				 "[IO CMD] Resume DM after scan.\n");
+			postprocessing = true;
+			break;
+		case IO_CMD_PAUSE_BAND0_DM_BY_SCAN:
+		case IO_CMD_PAUSE_BAND1_DM_BY_SCAN:
+			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+				 "[IO CMD] Pause DM before scan.\n");
+			postprocessing = true;
+			break;
+		default:
+			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+				 "switch case not process\n");
+			break;
+		}
+	} while (false);
+	if (postprocessing && !rtlphy->set_io_inprogress) {
+		rtlphy->set_io_inprogress = true;
+		rtlphy->current_io_type = iotype;
+	} else {
+		return false;
+	}
+	rtl8821ae_phy_set_io(hw);
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "IO Type(%#x)\n", iotype);
+	return true;
+}
+
+static void rtl8821ae_phy_set_io(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+		 "--->Cmd(%#x), set_io_inprogress(%d)\n",
+		  rtlphy->current_io_type, rtlphy->set_io_inprogress);
+	switch (rtlphy->current_io_type) {
+	case IO_CMD_RESUME_DM_BY_SCAN:
+		if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
+			_rtl8821ae_resume_tx_beacon(hw);
+		rtl8821ae_dm_write_dig(hw, rtlphy->initgain_backup.xaagccore1);
+		rtl8821ae_dm_write_cck_cca_thres(hw,
+						 rtlphy->initgain_backup.cca);
+		break;
+	case IO_CMD_PAUSE_BAND0_DM_BY_SCAN:
+		if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
+			_rtl8821ae_stop_tx_beacon(hw);
+		rtlphy->initgain_backup.xaagccore1 = dm_digtable->cur_igvalue;
+		rtl8821ae_dm_write_dig(hw, 0x17);
+		rtlphy->initgain_backup.cca = dm_digtable->cur_cck_cca_thres;
+		rtl8821ae_dm_write_cck_cca_thres(hw, 0x40);
+		break;
+	case IO_CMD_PAUSE_BAND1_DM_BY_SCAN:
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "switch case not process\n");
+		break;
+	}
+	rtlphy->set_io_inprogress = false;
+	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+		 "(%#x)\n", rtlphy->current_io_type);
+}
+
+static void rtl8821ae_phy_set_rf_on(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+}
+
+static bool _rtl8821ae_phy_set_rf_power_state(struct ieee80211_hw *hw,
+					      enum rf_pwrstate rfpwr_state)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+	bool bresult = true;
+	u8 i, queue_id;
+	struct rtl8192_tx_ring *ring = NULL;
+
+	switch (rfpwr_state) {
+	case ERFON:
+		if ((ppsc->rfpwr_state == ERFOFF) &&
+		    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+			bool rtstatus = false;
+			u32 initializecount = 0;
+
+			do {
+				initializecount++;
+				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+					 "IPS Set eRf nic enable\n");
+				rtstatus = rtl_ps_enable_nic(hw);
+			} while (!rtstatus && (initializecount < 10));
+			RT_CLEAR_PS_LEVEL(ppsc,
+					  RT_RF_OFF_LEVL_HALT_NIC);
+		} else {
+			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+				 "Set ERFON sleeped:%d ms\n",
+				  jiffies_to_msecs(jiffies -
+						   ppsc->
+						   last_sleep_jiffies));
+			ppsc->last_awake_jiffies = jiffies;
+			rtl8821ae_phy_set_rf_on(hw);
+		}
+		if (mac->link_state == MAC80211_LINKED) {
+			rtlpriv->cfg->ops->led_control(hw,
+						       LED_CTL_LINK);
+		} else {
+			rtlpriv->cfg->ops->led_control(hw,
+						       LED_CTL_NO_LINK);
+		}
+		break;
+	case ERFOFF:
+		for (queue_id = 0, i = 0;
+		     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+			ring = &pcipriv->dev.tx_ring[queue_id];
+			if (queue_id == BEACON_QUEUE ||
+			    skb_queue_len(&ring->queue) == 0) {
+				queue_id++;
+				continue;
+			} else {
+				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+					 "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n",
+					 (i + 1), queue_id,
+					 skb_queue_len(&ring->queue));
+
+				udelay(10);
+				i++;
+			}
+			if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+				RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+					 "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
+					  MAX_DOZE_WAITING_TIMES_9x,
+					  queue_id,
+					  skb_queue_len(&ring->queue));
+				break;
+			}
+		}
+
+		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
+			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+				 "IPS Set eRf nic disable\n");
+			rtl_ps_disable_nic(hw);
+			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+		} else {
+			if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) {
+				rtlpriv->cfg->ops->led_control(hw,
+							       LED_CTL_NO_LINK);
+			} else {
+				rtlpriv->cfg->ops->led_control(hw,
+							       LED_CTL_POWER_OFF);
+			}
+		}
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "switch case not process\n");
+		bresult = false;
+		break;
+	}
+	if (bresult)
+		ppsc->rfpwr_state = rfpwr_state;
+	return bresult;
+}
+
+bool rtl8821ae_phy_set_rf_power_state(struct ieee80211_hw *hw,
+				      enum rf_pwrstate rfpwr_state)
+{
+	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+	bool bresult = false;
+
+	if (rfpwr_state == ppsc->rfpwr_state)
+		return bresult;
+	bresult = _rtl8821ae_phy_set_rf_power_state(hw, rfpwr_state);
+	return bresult;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/phy.h b/drivers/net/wireless/rtlwifi/rtl8821ae/phy.h
new file mode 100644
index 0000000..c411f0a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/phy.h
@@ -0,0 +1,259 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8821AE_PHY_H__
+#define __RTL8821AE_PHY_H__
+
+/* MAX_TX_COUNT must always be set to 4, otherwise read
+ * efuse table sequence will be wrong.
+ */
+#define MAX_TX_COUNT				4
+#define	TX_1S					0
+#define	TX_2S					1
+#define	TX_3S					2
+#define	TX_4S					3
+
+#define	MAX_POWER_INDEX				0x3F
+
+#define MAX_PRECMD_CNT				16
+#define MAX_RFDEPENDCMD_CNT			16
+#define MAX_POSTCMD_CNT				16
+
+#define MAX_DOZE_WAITING_TIMES_9x		64
+
+#define RT_CANNOT_IO(hw)			false
+#define HIGHPOWER_RADIOA_ARRAYLEN		22
+
+#define IQK_ADDA_REG_NUM			16
+#define IQK_BB_REG_NUM				9
+#define MAX_TOLERANCE				5
+#define	IQK_DELAY_TIME				10
+#define	index_mapping_NUM			15
+
+#define	APK_BB_REG_NUM				5
+#define	APK_AFE_REG_NUM				16
+#define	APK_CURVE_REG_NUM			4
+#define	PATH_NUM				2
+
+#define LOOP_LIMIT				5
+#define MAX_STALL_TIME				50
+#define AntennaDiversityValue			0x80
+#define MAX_TXPWR_IDX_NMODE_92S			63
+#define Reset_Cnt_Limit				3
+
+#define IQK_ADDA_REG_NUM			16
+#define IQK_MAC_REG_NUM				4
+
+#define RF6052_MAX_PATH				2
+
+#define CT_OFFSET_MAC_ADDR			0X16
+
+#define CT_OFFSET_CCK_TX_PWR_IDX		0x5A
+#define CT_OFFSET_HT401S_TX_PWR_IDX		0x60
+#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF	0x66
+#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF		0x69
+#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF		0x6C
+
+#define CT_OFFSET_HT40_MAX_PWR_OFFSET		0x6F
+#define CT_OFFSET_HT20_MAX_PWR_OFFSET		0x72
+
+#define CT_OFFSET_CHANNEL_PLAH			0x75
+#define CT_OFFSET_THERMAL_METER			0x78
+#define CT_OFFSET_RF_OPTION			0x79
+#define CT_OFFSET_VERSION			0x7E
+#define CT_OFFSET_CUSTOMER_ID			0x7F
+
+#define RTL8821AE_MAX_PATH_NUM			2
+
+#define TARGET_CHNL_NUM_2G_5G_8812		59
+
+enum swchnlcmd_id {
+	CMDID_END,
+	CMDID_SET_TXPOWEROWER_LEVEL,
+	CMDID_BBREGWRITE10,
+	CMDID_WRITEPORT_ULONG,
+	CMDID_WRITEPORT_USHORT,
+	CMDID_WRITEPORT_UCHAR,
+	CMDID_RF_WRITEREG,
+};
+
+struct swchnlcmd {
+	enum swchnlcmd_id cmdid;
+	u32 para1;
+	u32 para2;
+	u32 msdelay;
+};
+
+enum hw90_block_e {
+	HW90_BLOCK_MAC = 0,
+	HW90_BLOCK_PHY0 = 1,
+	HW90_BLOCK_PHY1 = 2,
+	HW90_BLOCK_RF = 3,
+	HW90_BLOCK_MAXIMUM = 4,
+};
+
+enum baseband_config_type {
+	BASEBAND_CONFIG_PHY_REG = 0,
+	BASEBAND_CONFIG_AGC_TAB = 1,
+};
+
+enum ra_offset_area {
+	RA_OFFSET_LEGACY_OFDM1,
+	RA_OFFSET_LEGACY_OFDM2,
+	RA_OFFSET_HT_OFDM1,
+	RA_OFFSET_HT_OFDM2,
+	RA_OFFSET_HT_OFDM3,
+	RA_OFFSET_HT_OFDM4,
+	RA_OFFSET_HT_CCK,
+};
+
+enum antenna_path {
+	ANTENNA_NONE,
+	ANTENNA_D,
+	ANTENNA_C,
+	ANTENNA_CD,
+	ANTENNA_B,
+	ANTENNA_BD,
+	ANTENNA_BC,
+	ANTENNA_BCD,
+	ANTENNA_A,
+	ANTENNA_AD,
+	ANTENNA_AC,
+	ANTENNA_ACD,
+	ANTENNA_AB,
+	ANTENNA_ABD,
+	ANTENNA_ABC,
+	ANTENNA_ABCD
+};
+
+struct r_antenna_select_ofdm {
+	u32 r_tx_antenna:4;
+	u32 r_ant_l:4;
+	u32 r_ant_non_ht:4;
+	u32 r_ant_ht1:4;
+	u32 r_ant_ht2:4;
+	u32 r_ant_ht_s1:4;
+	u32 r_ant_non_ht_s1:4;
+	u32 ofdm_txsc:2;
+	u32 reserved:2;
+};
+
+struct r_antenna_select_cck {
+	u8 r_cckrx_enable_2:2;
+	u8 r_cckrx_enable:2;
+	u8 r_ccktx_enable:4;
+};
+
+struct efuse_contents {
+	u8 mac_addr[ETH_ALEN];
+	u8 cck_tx_power_idx[6];
+	u8 ht40_1s_tx_power_idx[6];
+	u8 ht40_2s_tx_power_idx_diff[3];
+	u8 ht20_tx_power_idx_diff[3];
+	u8 ofdm_tx_power_idx_diff[3];
+	u8 ht40_max_power_offset[3];
+	u8 ht20_max_power_offset[3];
+	u8 channel_plan;
+	u8 thermal_meter;
+	u8 rf_option[5];
+	u8 version;
+	u8 oem_id;
+	u8 regulatory;
+};
+
+struct tx_power_struct {
+	u8 cck[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+	u8 ht40_1s[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+	u8 ht40_2s[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+	u8 ht20_diff[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+	u8 legacy_ht_diff[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+	u8 legacy_ht_txpowerdiff;
+	u8 groupht20[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+	u8 groupht40[RTL8821AE_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+	u8 pwrgroup_cnt;
+	u32 mcs_original_offset[4][16];
+};
+enum _ANT_DIV_TYPE {
+	NO_ANTDIV			= 0xFF,
+	CG_TRX_HW_ANTDIV		= 0x01,
+	CGCS_RX_HW_ANTDIV		= 0x02,
+	FIXED_HW_ANTDIV     		= 0x03,
+	CG_TRX_SMART_ANTDIV		= 0x04,
+	CGCS_RX_SW_ANTDIV		= 0x05,
+
+};
+
+u32 rtl8821ae_phy_query_bb_reg(struct ieee80211_hw *hw,
+			       u32 regaddr, u32 bitmask);
+void rtl8821ae_phy_set_bb_reg(struct ieee80211_hw *hw,
+			      u32 regaddr, u32 bitmask, u32 data);
+u32 rtl8821ae_phy_query_rf_reg(struct ieee80211_hw *hw,
+			       enum radio_path rfpath, u32 regaddr,
+			       u32 bitmask);
+void rtl8821ae_phy_set_rf_reg(struct ieee80211_hw *hw,
+			      enum radio_path rfpath, u32 regaddr,
+			      u32 bitmask, u32 data);
+bool rtl8821ae_phy_mac_config(struct ieee80211_hw *hw);
+bool rtl8821ae_phy_bb_config(struct ieee80211_hw *hw);
+bool rtl8821ae_phy_rf_config(struct ieee80211_hw *hw);
+void rtl8821ae_phy_switch_wirelessband(struct ieee80211_hw *hw,
+				       u8 band);
+void rtl8821ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+void rtl8821ae_phy_get_txpower_level(struct ieee80211_hw *hw,
+				     long *powerlevel);
+void rtl8821ae_phy_set_txpower_level(struct ieee80211_hw *hw,
+				     u8 channel);
+void rtl8821ae_phy_scan_operation_backup(struct ieee80211_hw *hw,
+					 u8 operation);
+void rtl8821ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+void rtl8821ae_phy_set_bw_mode(struct ieee80211_hw *hw,
+			       enum nl80211_channel_type ch_type);
+void rtl8821ae_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+u8 rtl8821ae_phy_sw_chnl(struct ieee80211_hw *hw);
+void rtl8821ae_phy_iq_calibrate(struct ieee80211_hw *hw,
+				bool b_recovery);
+void rtl8812ae_phy_iq_calibrate(struct ieee80211_hw *hw,
+				bool b_recovery);
+void rtl8821ae_phy_ap_calibrate(struct ieee80211_hw *hw, char delta);
+void rtl8821ae_phy_lc_calibrate(struct ieee80211_hw *hw);
+void rtl8821ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
+bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+					     enum radio_path rfpath);
+bool rtl8821ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+					     enum radio_path rfpath);
+bool rtl8821ae_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
+bool rtl8821ae_phy_set_rf_power_state(struct ieee80211_hw *hw,
+				      enum rf_pwrstate rfpwr_state);
+u8 _rtl8812ae_get_right_chnl_place_for_iqk(u8 chnl);
+void rtl8821ae_phy_set_txpower_level_by_path(struct ieee80211_hw *hw,
+					     u8 channel, u8 path);
+void rtl8812ae_do_iqk(struct ieee80211_hw *hw, u8 delta_thermal_index,
+	u8 thermal_value, u8 threshold);
+void rtl8821ae_do_iqk(struct ieee80211_hw *hw, u8 delta_thermal_index,
+		      u8 thermal_value, u8 threshold);
+void rtl8821ae_reset_iqk_result(struct ieee80211_hw *hw);
+u32 phy_get_tx_swing_8812A(struct ieee80211_hw *hw, u8 band, u8 rf_path);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.c
new file mode 100644
index 0000000..9ddf78a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.c
@@ -0,0 +1,182 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../pwrseqcmd.h"
+#include "pwrseq.h"
+
+/* drivers should parse below arrays and do the corresponding actions */
+/* 3 Power on  Array */
+struct wlan_pwr_cfg rtl8812_power_on_flow[RTL8812_TRANS_CARDEMU_TO_ACT_STEPS +
+					RTL8812_TRANS_END_STEPS] = {
+	RTL8812_TRANS_CARDEMU_TO_ACT
+	RTL8812_TRANS_END
+};
+
+/* 3Radio off GPIO Array */
+struct wlan_pwr_cfg rtl8812_radio_off_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS +
+						RTL8812_TRANS_END_STEPS] = {
+	RTL8812_TRANS_ACT_TO_CARDEMU
+	RTL8812_TRANS_END
+};
+
+/* 3Card Disable Array */
+struct wlan_pwr_cfg rtl8812_card_disable_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS
+	+ RTL8812_TRANS_CARDEMU_TO_PDN_STEPS
+	+ RTL8812_TRANS_END_STEPS] = {
+	RTL8812_TRANS_ACT_TO_CARDEMU
+	RTL8812_TRANS_CARDEMU_TO_CARDDIS
+	RTL8812_TRANS_END
+};
+
+/* 3 Card Enable Array */
+struct wlan_pwr_cfg rtl8812_card_enable_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS
+	+ RTL8812_TRANS_CARDEMU_TO_PDN_STEPS
+	+ RTL8812_TRANS_END_STEPS] = {
+	RTL8812_TRANS_CARDDIS_TO_CARDEMU
+	RTL8812_TRANS_CARDEMU_TO_ACT
+	RTL8812_TRANS_END
+};
+
+/* 3Suspend Array */
+struct wlan_pwr_cfg rtl8812_suspend_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS +
+					RTL8812_TRANS_CARDEMU_TO_SUS_STEPS +
+					RTL8812_TRANS_END_STEPS] = {
+	RTL8812_TRANS_ACT_TO_CARDEMU
+	RTL8812_TRANS_CARDEMU_TO_SUS
+	RTL8812_TRANS_END
+};
+
+/* 3 Resume Array */
+struct wlan_pwr_cfg rtl8812_resume_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS +
+					RTL8812_TRANS_CARDEMU_TO_SUS_STEPS +
+					RTL8812_TRANS_END_STEPS] = {
+	RTL8812_TRANS_SUS_TO_CARDEMU
+	RTL8812_TRANS_CARDEMU_TO_ACT
+	RTL8812_TRANS_END
+};
+
+/* 3HWPDN Array */
+struct wlan_pwr_cfg rtl8812_hwpdn_flow[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS +
+					RTL8812_TRANS_CARDEMU_TO_PDN_STEPS +
+					RTL8812_TRANS_END_STEPS] = {
+	RTL8812_TRANS_ACT_TO_CARDEMU
+	RTL8812_TRANS_CARDEMU_TO_PDN
+	RTL8812_TRANS_END
+};
+
+/* 3 Enter LPS */
+struct wlan_pwr_cfg rtl8812_enter_lps_flow[RTL8812_TRANS_ACT_TO_LPS_STEPS +
+						RTL8812_TRANS_END_STEPS] = {
+	/* FW behavior */
+	RTL8812_TRANS_ACT_TO_LPS
+	RTL8812_TRANS_END
+};
+
+/* 3 Leave LPS */
+struct wlan_pwr_cfg rtl8812_leave_lps_flow[RTL8812_TRANS_LPS_TO_ACT_STEPS +
+						RTL8812_TRANS_END_STEPS] = {
+	/* FW behavior */
+	RTL8812_TRANS_LPS_TO_ACT
+	RTL8812_TRANS_END
+};
+
+/* drivers should parse below arrays and do the corresponding actions */
+/*3 Power on  Array*/
+struct wlan_pwr_cfg rtl8821A_power_on_flow[RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS
+					+ RTL8821A_TRANS_END_STEPS] = {
+	RTL8821A_TRANS_CARDEMU_TO_ACT
+	RTL8821A_TRANS_END
+};
+
+/*3Radio off GPIO Array */
+struct wlan_pwr_cfg rtl8821A_radio_off_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS
+					+ RTL8821A_TRANS_END_STEPS] = {
+	RTL8821A_TRANS_ACT_TO_CARDEMU
+	RTL8821A_TRANS_END
+};
+
+/*3Card Disable Array*/
+struct wlan_pwr_cfg rtl8821A_card_disable_flow
+					[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS
+					+ RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS
+					+ RTL8821A_TRANS_END_STEPS] = {
+	RTL8821A_TRANS_ACT_TO_CARDEMU
+	RTL8821A_TRANS_CARDEMU_TO_CARDDIS
+	RTL8821A_TRANS_END
+};
+
+/*3 Card Enable Array*/
+/*RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS*/
+struct wlan_pwr_cfg rtl8821A_card_enable_flow
+					[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS
+					+ RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS
+					+ RTL8821A_TRANS_END_STEPS] = {
+	RTL8821A_TRANS_CARDDIS_TO_CARDEMU
+	RTL8821A_TRANS_CARDEMU_TO_ACT
+	RTL8821A_TRANS_END
+};
+
+/*3Suspend Array*/
+struct wlan_pwr_cfg rtl8821A_suspend_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS
+					+ RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS
+					+ RTL8821A_TRANS_END_STEPS] = {
+	RTL8821A_TRANS_ACT_TO_CARDEMU
+	RTL8821A_TRANS_CARDEMU_TO_SUS
+	RTL8821A_TRANS_END
+};
+
+/*3 Resume Array*/
+struct wlan_pwr_cfg rtl8821A_resume_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS
+					+ RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS
+					+ RTL8821A_TRANS_END_STEPS] = {
+	RTL8821A_TRANS_SUS_TO_CARDEMU
+	RTL8821A_TRANS_CARDEMU_TO_ACT
+	RTL8821A_TRANS_END
+};
+
+/*3HWPDN Array*/
+struct wlan_pwr_cfg rtl8821A_hwpdn_flow[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS
+				+ RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS
+				+ RTL8821A_TRANS_END_STEPS] = {
+	RTL8821A_TRANS_ACT_TO_CARDEMU
+	RTL8821A_TRANS_CARDEMU_TO_PDN
+	RTL8821A_TRANS_END
+};
+
+/*3 Enter LPS */
+struct wlan_pwr_cfg rtl8821A_enter_lps_flow[RTL8821A_TRANS_ACT_TO_LPS_STEPS
+					+ RTL8821A_TRANS_END_STEPS] = {
+	/*FW behavior*/
+	RTL8821A_TRANS_ACT_TO_LPS
+	RTL8821A_TRANS_END
+};
+
+/*3 Leave LPS */
+struct wlan_pwr_cfg rtl8821A_leave_lps_flow[RTL8821A_TRANS_LPS_TO_ACT_STEPS
+					+ RTL8821A_TRANS_END_STEPS] = {
+	/*FW behavior*/
+	RTL8821A_TRANS_LPS_TO_ACT
+	RTL8821A_TRANS_END
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h
new file mode 100644
index 0000000..bf0b0ce
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h
@@ -0,0 +1,738 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8821AE_PWRSEQ_H__
+#define __RTL8821AE_PWRSEQ_H__
+
+#include "../pwrseqcmd.h"
+#include "../btcoexist/halbt_precomp.h"
+
+#define	RTL8812_TRANS_CARDEMU_TO_ACT_STEPS	15
+#define	RTL8812_TRANS_ACT_TO_CARDEMU_STEPS	15
+#define	RTL8812_TRANS_CARDEMU_TO_SUS_STEPS	15
+#define	RTL8812_TRANS_SUS_TO_CARDEMU_STEPS	15
+#define	RTL8812_TRANS_CARDEMU_TO_PDN_STEPS	25
+#define	RTL8812_TRANS_PDN_TO_CARDEMU_STEPS	15
+#define	RTL8812_TRANS_ACT_TO_LPS_STEPS		15
+#define	RTL8812_TRANS_LPS_TO_ACT_STEPS		15
+#define	RTL8812_TRANS_END_STEPS			1
+
+/* The following macros have the following format:
+ * { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value
+ *   comments },
+ */
+#define RTL8812_TRANS_CARDEMU_TO_ACT					\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0 \
+	/* disable SW LPS 0x04[10]=0*/},	\
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1 \
+	/* wait till 0x04[17] = 1    power ready*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0 \
+	/* disable HWPDN 0x04[15]=0*/}, \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0 \
+	/* disable WL suspend*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0 \
+	/* polling until return 0*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0},
+
+#define RTL8812_TRANS_ACT_TO_CARDEMU													\
+	{0x0c00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04 \
+	 /* 0xc00[7:0] = 4	turn off 3-wire */},	\
+	{0x0e00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04 \
+	 /* 0xe00[7:0] = 4	turn off 3-wire */},	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0 \
+	 /* 0x2[0] = 0	 RESET BB, CLOSE RF */},	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US \
+	/*Delay 1us*/},	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0 \
+	  /* Whole BB is reset*/},			\
+	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x2A \
+	 /* 0x07[7:0] = 0x28 sps pwm mode 0x2a for BT coex*/},	\
+	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x02, 0 \
+	/*0x8[1] = 0 ANA clk =500k */},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1 \
+	 /*0x04[9] = 1 turn off MAC by HW state machine*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0 \
+	 /*wait till 0x04[9] = 0 polling until return 0 to disable*/},
+
+#define RTL8812_TRANS_CARDEMU_TO_SUS					\
+	{0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xcc}, \
+	{0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xEC}, \
+	{0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x07 \
+	/* gpio11 input mode, gpio10~8 output mode */},	\
+	{0x0045, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00 \
+	/* gpio 0~7 output same value as input ?? */},	\
+	{0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xff \
+	/* gpio0~7 output mode */},	\
+	{0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0 \
+	/* 0x47[7:0] = 00 gpio mode */},	\
+	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0 \
+	/* suspend option all off */},	\
+	{0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x80, BIT7 \
+	/*0x14[7] = 1 turn on ZCD */},	\
+	{0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, BIT0 \
+	/* 0x15[0] =1 trun on ZCD */},	\
+	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, BIT4 \
+	/*0x23[4] = 1 hpon LDO sleep mode */},	\
+	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x02, 0 \
+	/*0x8[1] = 0 ANA clk =500k */},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3 \
+	/*0x04[11] = 2b'11 enable WL suspend for PCIe*/},
+
+#define RTL8812_TRANS_SUS_TO_CARDEMU					\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0 \
+	/*0x04[11] = 2b'01enable WL suspend*/},   \
+	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, 0 \
+	/*0x23[4] = 0 hpon LDO sleep mode leave */},	\
+	{0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, 0 \
+	/* 0x15[0] =0 trun off ZCD */},	\
+	{0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x80, 0 \
+	/*0x14[7] = 0 turn off ZCD */},	\
+	{0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00 \
+	/* gpio0~7 input mode */},	\
+	{0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00 \
+	/* gpio11 input mode, gpio10~8 input mode */},
+
+#define RTL8812_TRANS_CARDEMU_TO_CARDDIS				\
+	{0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0 \
+	/*0x03[2] = 0, reset 8051*/},	\
+	{0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x05 \
+	/*0x80=05h if reload fw, fill the default value of host_CPU handshake field*/},	\
+	{0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xcc}, \
+	{0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xEC}, \
+	{0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x07 \
+	/* gpio11 input mode, gpio10~8 output mode */},	\
+	{0x0045, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00 \
+	/* gpio 0~7 output same value as input ?? */},	\
+	{0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xff \
+	/* gpio0~7 output mode */},	\
+	{0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0 \
+	/* 0x47[7:0] = 00 gpio mode */},	\
+	{0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x80, BIT7 \
+	/*0x14[7] = 1 turn on ZCD */},	\
+	{0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, BIT0 \
+	/* 0x15[0] =1 trun on ZCD */},	\
+	{0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, 0 \
+	/*0x12[0] = 0 force PFM mode */},	\
+	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, BIT4 \
+	/*0x23[4] = 1 hpon LDO sleep mode */},	\
+	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x02, 0 \
+	/*0x8[1] = 0 ANA clk =500k */},	\
+	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20 \
+	 /*0x07=0x20 , SOP option to disable BG/MB*/},	\
+	{0x001f, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0 \
+	 /*0x01f[1]=0 , disable RFC_0  control  REG_RF_CTRL_8812 */},	\
+	{0x0076, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0 \
+	 /*0x076[1]=0 , disable RFC_1  control REG_OPT_CTRL_8812 +2 */},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, BIT3 \
+	 /*0x04[11] = 2b'01 enable WL suspend*/},
+
+#define RTL8812_TRANS_CARDDIS_TO_CARDEMU				\
+	{0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0 \
+	/*0x12[0] = 1 force PWM mode */},	\
+	{0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x80, 0 \
+	/*0x14[7] = 0 turn off ZCD */},	\
+	{0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x01, 0 \
+	/* 0x15[0] =0 trun off ZCD */},	\
+	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0x10, 0 \
+	/*0x23[4] = 0 hpon LDO leave sleep mode */},	\
+	{0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00 \
+	/* gpio0~7 input mode */},	\
+	{0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00 \
+	/* gpio11 input mode, gpio10~8 input mode */}, \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0 \
+	 /*0x04[10] = 0, enable SW LPS PCIE only*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3, 0 \
+	 /*0x04[11] = 2b'01enable WL suspend*/},	\
+	{0x0003, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, BIT2 \
+	 /*0x03[2] = 1, enable 8051*/},	\
+	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0 \
+	/*PCIe DMA start*/},
+
+#define RTL8812_TRANS_CARDEMU_TO_PDN		\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7 \
+	/* 0x04[15] = 1*/},
+
+#define RTL8812_TRANS_PDN_TO_CARDEMU			\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0 \
+	/* 0x04[15] = 0*/},
+
+#define RTL8812_TRANS_ACT_TO_LPS		\
+	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF \
+	/*PCIe DMA stop*/},	\
+	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F \
+	/*Tx Pause*/},		\
+	{0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0 \
+	/*Should be zero if no packet is transmitting*/},	\
+	{0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0 \
+	/*Should be zero if no packet is transmitting*/},	\
+	{0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0 \
+	/*Should be zero if no packet is transmitting*/},	\
+	{0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0 \
+	/*Should be zero if no packet is transmitting*/},	\
+	{0x0c00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04 \
+	 /* 0xc00[7:0] = 4	turn off 3-wire */},	\
+	{0x0e00, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x04 \
+	 /* 0xe00[7:0] = 4	turn off 3-wire */},	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0 \
+	/*CCK and OFDM are disabled,and clock are gated,and RF closed*/},	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US \
+	/*Delay 1us*/},	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0 \
+	  /* Whole BB is reset*/},			\
+	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03 \
+	/*Reset MAC TRX*/},			\
+	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0 \
+	/*check if removed later*/},		\
+	{0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5 \
+	/*Respond TxOK to scheduler*/},
+
+#define RTL8812_TRANS_LPS_TO_ACT					\
+	{0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84 \
+	 /*SDIO RPWM*/},	\
+	{0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84 \
+	 /*USB RPWM*/},	\
+	{0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84 \
+	 /*PCIe RPWM*/},	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS \
+	 /*Delay*/},	\
+	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0 \
+	 /*.	0x08[4] = 0		 switch TSF to 40M*/},	\
+	{0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0 \
+	 /*Polling 0x109[7]=0  TSF in 40M*/},			\
+	{0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6|BIT7, 0 \
+	 /*.	0x29[7:6] = 2b'00	 enable BB clock*/},	\
+	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1 \
+	 /*.	0x101[1] = 1*/},					\
+	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF \
+	 /*.	0x100[7:0] = 0xFF	 enable WMAC TRX*/},	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1|BIT0, BIT1|BIT0 \
+	 /*.	0x02[1:0] = 2b'11	 enable BB macro*/},	\
+	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0 \
+	 /*.	0x522 = 0*/},
+
+#define RTL8812_TRANS_END					\
+	{0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+	0, PWR_CMD_END, 0, 0},
+
+extern struct wlan_pwr_cfg  rtl8812_power_on_flow
+		[RTL8812_TRANS_CARDEMU_TO_ACT_STEPS +
+		 RTL8812_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg  rtl8812_radio_off_flow
+		[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8812_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg  rtl8812_card_disable_flow
+		[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8812_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8812_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg  rtl8812_card_enable_flow
+		[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8812_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8812_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg  rtl8812_suspend_flow
+		[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8812_TRANS_CARDEMU_TO_SUS_STEPS +
+		 RTL8812_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg  rtl8812_resume_flow
+		[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8812_TRANS_CARDEMU_TO_SUS_STEPS +
+		 RTL8812_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg  rtl8812_hwpdn_flow
+		[RTL8812_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8812_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8812_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg  rtl8812_enter_lps_flow
+		[RTL8812_TRANS_ACT_TO_LPS_STEPS +
+		 RTL8812_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg  rtl8812_leave_lps_flow
+		[RTL8812_TRANS_LPS_TO_ACT_STEPS +
+		 RTL8812_TRANS_END_STEPS];
+
+/* Check document WM-20130516-JackieLau-RTL8821A_Power_Architecture-R10.vsd
+ *	There are 6 HW Power States:
+ *	0: POFF--Power Off
+ *	1: PDN--Power Down
+ *	2: CARDEMU--Card Emulation
+ *	3: ACT--Active Mode
+ *	4: LPS--Low Power State
+ *	5: SUS--Suspend
+ *
+ *	The transision from different states are defined below
+ *	TRANS_CARDEMU_TO_ACT
+ *	TRANS_ACT_TO_CARDEMU
+ *	TRANS_CARDEMU_TO_SUS
+ *	TRANS_SUS_TO_CARDEMU
+ *	TRANS_CARDEMU_TO_PDN
+ *	TRANS_ACT_TO_LPS
+ *	TRANS_LPS_TO_ACT
+ *
+ *	TRANS_END
+ */
+#define	RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS	25
+#define	RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS	15
+#define	RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS	15
+#define	RTL8821A_TRANS_SUS_TO_CARDEMU_STEPS	15
+#define RTL8821A_TRANS_CARDDIS_TO_CARDEMU_STEPS	15
+#define	RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS	15
+#define	RTL8821A_TRANS_PDN_TO_CARDEMU_STEPS	15
+#define	RTL8821A_TRANS_ACT_TO_LPS_STEPS		15
+#define	RTL8821A_TRANS_LPS_TO_ACT_STEPS		15
+#define	RTL8821A_TRANS_END_STEPS		1
+
+#define RTL8821A_TRANS_CARDEMU_TO_ACT					\
+	{0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
+	 PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0 \
+	 /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/},   \
+	{0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,		\
+	 PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0 \
+	 /*0x67[0] = 0 to disable BT_GPS_SEL pins*/},	\
+	{0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
+	 PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS \
+	/*Delay 1ms*/},   \
+	{0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
+	 PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, 0 \
+	 /*0x00[5] = 1b'0 release analog Ips to digital ,1:isolation*/},   \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT4|BIT3|BIT2), 0 \
+	/* disable SW LPS 0x04[10]=0 and WLSUS_EN 0x04[12:11]=0*/},	\
+	{0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 , BIT0 \
+	/* Disable USB suspend */},	\
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1 \
+	/* wait till 0x04[17] = 1    power ready*/},	\
+	{0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 , 0 \
+	/* Enable USB suspend */},	\
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0 \
+	/* release WLON reset  0x04[16]=1*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0 \
+	/* disable HWPDN 0x04[15]=0*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT4|BIT3), 0 \
+	/* disable WL suspend*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0 \
+	/* polling until return 0*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0 \
+	/**/},	\
+	{0x004F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0 \
+	/*0x4C[24] = 0x4F[0] = 1, switch DPDT_SEL_P output from WL BB */},\
+	{0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT5|BIT4), (BIT5|BIT4) \
+	/*0x66[13] = 0x67[5] = 1, switch for PAPE_G/PAPE_A 	\
+	 from WL BB ; 0x66[12] = 0x67[4] = 1, switch LNAON from WL BB */},\
+	{0x0025, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6, 0 \
+	/*anapar_mac<118> , 0x25[6]=0 by wlan single function*/},\
+	{0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1 \
+	/*Enable falling edge triggering interrupt*/},\
+	{0x0063, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1 \
+	/*Enable GPIO9 interrupt mode*/},\
+	{0x0062, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0 \
+	/*Enable GPIO9 input mode*/},\
+	{0x0058, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0 \
+	/*Enable HSISR GPIO[C:0] interrupt*/},\
+	{0x005A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1 \
+	/*Enable HSISR GPIO9 interrupt*/},\
+	{0x007A, PWR_CUT_TESTCHIP_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3A \
+	/*0x7A = 0x3A start BT*/},\
+	{0x002E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF , 0x82  \
+	/* 0x2C[23:12]=0x820 ; XTAL trim */}, \
+	{0x0010, PWR_CUT_A_MSK , PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6 , BIT6  \
+	/* 0x10[6]=1  */},
+
+#define RTL8821A_TRANS_ACT_TO_CARDEMU					\
+	{0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0 \
+	/*0x1F[7:0] = 0 turn off RF*/},	\
+	{0x004F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0 \
+	/*0x4C[24] = 0x4F[0] = 0, switch DPDT_SEL_P output from		\
+	 register 0x65[2] */},\
+	{0x0049, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0 \
+	/*Enable rising edge triggering interrupt*/}, \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1 \
+	 /*0x04[9] = 1 turn off MAC by HW state machine*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0 \
+	 /*wait till 0x04[9] = 0 polling until return 0 to disable*/},	\
+	{0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,			\
+	 PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5 \
+	 /*0x00[5] = 1b'1 analog Ips to digital ,1:isolation*/},   \
+	{0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,		\
+	 PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0 \
+	 /*0x20[0] = 1b'0 disable LDOA12 MACRO block*/},
+
+#define RTL8821A_TRANS_CARDEMU_TO_SUS					\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4|BIT3, (BIT4|BIT3) \
+	 /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,		\
+	 PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3 \
+	 /*0x04[12:11] = 2b'01 enable WL suspend*/},	\
+	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4 \
+	 /*0x23[4] = 1b'1 12H LDO enter sleep mode*/},   \
+	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20 \
+	 /*0x07[7:0] = 0x20 SDIO SOP option to disable BG/MB/ACK/SWR*/},   \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3|BIT4 \
+	 /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/},	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0 \
+	 /*Set SDIO suspend local register*/},	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0 \
+	 /*wait power state to suspend*/},
+
+#define RTL8821A_TRANS_SUS_TO_CARDEMU					\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT7, 0 \
+	 /*clear suspend enable and power down enable*/},	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0 \
+	 /*Set SDIO suspend local register*/},	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1 \
+	 /*wait power state to suspend*/},\
+	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0 \
+	 /*0x23[4] = 1b'0 12H LDO enter normal mode*/},   \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0 \
+	 /*0x04[12:11] = 2b'01enable WL suspend*/},
+
+#define RTL8821A_TRANS_CARDEMU_TO_CARDDIS				\
+	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20 \
+	 /*0x07=0x20 , SOP option to disable BG/MB*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,		\
+	 PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3 \
+	 /*0x04[12:11] = 2b'01 enable WL suspend*/},	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, BIT2 \
+	 /*0x04[10] = 1, enable SW LPS*/},	\
+        {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 1 \
+	 /*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/},   \
+	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4 \
+	 /*0x23[4] = 1b'1 12H LDO enter sleep mode*/},   \
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0 \
+	 /*Set SDIO suspend local register*/},	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0 \
+	 /*wait power state to suspend*/},
+
+#define RTL8821A_TRANS_CARDDIS_TO_CARDEMU				\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT7, 0 \
+	 /*clear suspend enable and power down enable*/},	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0 \
+	 /*Set SDIO suspend local register*/},	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1 \
+	 /*wait power state to suspend*/},\
+	{0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0 \
+	 /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/},   \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0 \
+	 /*0x04[12:11] = 2b'01enable WL suspend*/},\
+	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0 \
+	 /*0x23[4] = 1b'0 12H LDO enter normal mode*/},   \
+	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0 \
+	/*PCIe DMA start*/},
+
+#define RTL8821A_TRANS_CARDEMU_TO_PDN					\
+	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4 \
+	 /*0x23[4] = 1b'1 12H LDO enter sleep mode*/},   \
+	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,		\
+	 PWR_INTF_SDIO_MSK|PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20 \
+	 /*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/},   \
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0 \
+	/* 0x04[16] = 0*/},\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7 \
+	/* 0x04[15] = 1*/},
+
+#define RTL8821A_TRANS_PDN_TO_CARDEMU				\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0 \
+	/* 0x04[15] = 0*/},
+
+#define RTL8821A_TRANS_ACT_TO_LPS					\
+	{0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF \
+	/*PCIe DMA stop*/},	\
+	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF \
+	/*Tx Pause*/},	\
+	{0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0 \
+	/*Should be zero if no packet is transmitting*/},	\
+	{0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0 \
+	/*Should be zero if no packet is transmitting*/},	\
+	{0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0 \
+	/*Should be zero if no packet is transmitting*/},	\
+	{0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0 \
+	/*Should be zero if no packet is transmitting*/},	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0 \
+	/*CCK and OFDM are disabled,and clock are gated*/},	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US \
+	/*Delay 1us*/},	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0 \
+	/*Whole BB is reset*/},	\
+	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03 \
+	/*Reset MAC TRX*/},	\
+	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0 \
+	/*check if removed later*/},	\
+	{0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00 \
+	/*When driver enter Sus/ Disable, enable LOP for BT*/},	\
+	{0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5 \
+	/*Respond TxOK to scheduler*/},
+
+#define RTL8821A_TRANS_LPS_TO_ACT					\
+	{0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\
+	PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84 \
+	 /*SDIO RPWM*/},\
+	{0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84 \
+	 /*USB RPWM*/},\
+	{0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84 \
+	 /*PCIe RPWM*/},\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS \
+	 /*Delay*/},\
+	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0 \
+	 /*.	0x08[4] = 0		 switch TSF to 40M*/},\
+	{0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0 \
+	 /*Polling 0x109[7]=0  TSF in 40M*/},\
+	{0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6|BIT7, 0 \
+	 /*.	0x29[7:6] = 2b'00	 enable BB clock*/},\
+	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1 \
+	 /*.	0x101[1] = 1*/},\
+	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF \
+	 /*.	0x100[7:0] = 0xFF	 enable WMAC TRX*/},\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1|BIT0, BIT1|BIT0 \
+	 /*.	0x02[1:0] = 2b'11	 enable BB macro*/},\
+	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0 \
+	 /*.	0x522 = 0*/},
+
+#define RTL8821A_TRANS_END					\
+	{0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+	0, PWR_CMD_END, 0, 0},
+
+extern struct wlan_pwr_cfg rtl8821A_power_on_flow
+		[RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS +
+		 RTL8821A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8821A_radio_off_flow
+		[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8821A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8821A_card_disable_flow
+		[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8821A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8821A_card_enable_flow
+		[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8821A_TRANS_CARDEMU_TO_ACT_STEPS +
+		 RTL8821A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8821A_suspend_flow
+		[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS +
+		 RTL8821A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8821A_resume_flow
+		[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8821A_TRANS_CARDEMU_TO_SUS_STEPS +
+		 RTL8821A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8821A_hwpdn_flow
+		[RTL8821A_TRANS_ACT_TO_CARDEMU_STEPS +
+		 RTL8821A_TRANS_CARDEMU_TO_PDN_STEPS +
+		 RTL8821A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8821A_enter_lps_flow
+		[RTL8821A_TRANS_ACT_TO_LPS_STEPS +
+		 RTL8821A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8821A_leave_lps_flow
+		[RTL8821A_TRANS_LPS_TO_ACT_STEPS +
+		 RTL8821A_TRANS_END_STEPS];
+
+/*RTL8812 Power Configuration CMDs for PCIe interface*/
+#define RTL8812_NIC_PWR_ON_FLOW			rtl8812_power_on_flow
+#define RTL8812_NIC_RF_OFF_FLOW			rtl8812_radio_off_flow
+#define RTL8812_NIC_DISABLE_FLOW		rtl8812_card_disable_flow
+#define RTL8812_NIC_ENABLE_FLOW			rtl8812_card_enable_flow
+#define RTL8812_NIC_SUSPEND_FLOW		rtl8812_suspend_flow
+#define RTL8812_NIC_RESUME_FLOW			rtl8812_resume_flow
+#define RTL8812_NIC_PDN_FLOW			rtl8812_hwpdn_flow
+#define RTL8812_NIC_LPS_ENTER_FLOW		rtl8812_enter_lps_flow
+#define RTL8812_NIC_LPS_LEAVE_FLOW		rtl8812_leave_lps_flow
+
+/* RTL8821 Power Configuration CMDs for PCIe interface */
+#define RTL8821A_NIC_PWR_ON_FLOW		rtl8821A_power_on_flow
+#define RTL8821A_NIC_RF_OFF_FLOW		rtl8821A_radio_off_flow
+#define RTL8821A_NIC_DISABLE_FLOW		rtl8821A_card_disable_flow
+#define RTL8821A_NIC_ENABLE_FLOW		rtl8821A_card_enable_flow
+#define RTL8821A_NIC_SUSPEND_FLOW		rtl8821A_suspend_flow
+#define RTL8821A_NIC_RESUME_FLOW		rtl8821A_resume_flow
+#define RTL8821A_NIC_PDN_FLOW			rtl8821A_hwpdn_flow
+#define RTL8821A_NIC_LPS_ENTER_FLOW		rtl8821A_enter_lps_flow
+#define RTL8821A_NIC_LPS_LEAVE_FLOW		rtl8821A_leave_lps_flow
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h b/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h
new file mode 100644
index 0000000..53668fc
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h
@@ -0,0 +1,2464 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8821AE_REG_H__
+#define __RTL8821AE_REG_H__
+
+#define TXPKT_BUF_SELECT			0x69
+#define RXPKT_BUF_SELECT			0xA5
+#define DISABLE_TRXPKT_BUF_ACCESS		0x0
+
+#define REG_SYS_ISO_CTRL			0x0000
+#define REG_SYS_FUNC_EN				0x0002
+#define REG_APS_FSMCO				0x0004
+#define REG_SYS_CLKR				0x0008
+#define REG_9346CR				0x000A
+#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 REG_LDOA15_CTRL				0x0020
+#define REG_LDOV12D_CTRL			0x0021
+#define REG_LDOHCI12_CTRL			0x0022
+#define REG_LPLDO_CTRL				0x0023
+#define REG_AFE_XTAL_CTRL			0x0024
+ /* 1.5v for 8188EE test chip, 1.4v for MP chip */
+#define REG_AFE_LDO_CTRL			0x0027
+#define REG_AFE_PLL_CTRL			0x0028
+#define REG_MAC_PHY_CTRL			0x002c
+#define REG_EFUSE_CTRL				0x0030
+#define REG_EFUSE_TEST				0x0034
+#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 REG_LEDCFG3				0x004F
+#define REG_FSIMR				0x0050
+#define REG_FSISR				0x0054
+#define REG_HSIMR				0x0058
+#define REG_HSISR				0x005c
+#define REG_GPIO_PIN_CTRL_2			0x0060
+#define REG_GPIO_IO_SEL_2			0x0062
+#define REG_MULTI_FUNC_CTRL			0x0068
+#define REG_GPIO_OUTPUT				0x006c
+#define REG_OPT_CTRL				0x0074
+#define REG_AFE_XTAL_CTRL_EXT			0x0078
+#define REG_XCK_OUT_CTRL			0x007c
+#define REG_MCUFWDL				0x0080
+#define REG_WOL_EVENT				0x0081
+#define REG_MCUTSTCFG				0x0084
+
+#define REG_HIMR				0x00B0
+#define REG_HISR				0x00B4
+#define REG_HIMRE				0x00B8
+#define REG_HISRE				0x00BC
+
+#define REG_PMC_DBG_CTRL2			0x00CC
+
+#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 REG_SYS_CFG				0x00F0
+#define REG_GPIO_OUTSTS				0x00F4
+#define REG_MAC_PHY_CTRL_NORMAL			0x00F8
+#define REG_SYS_CFG1				0x00FC
+#define REG_ROM_VERSION				0x00FD
+
+#define REG_CR					0x0100
+#define REG_PBP					0x0104
+#define REG_PKT_BUFF_ACCESS_CTRL		0x0106
+#define REG_TRXDMA_CTRL				0x010C
+#define REG_TRXFF_BNDY				0x0114
+#define REG_TRXFF_STATUS			0x0118
+#define REG_RXFF_PTR				0x011C
+
+#define REG_CPWM				0x012F
+#define REG_FWIMR				0x0130
+#define REG_FWISR				0x0134
+#define REG_FTISR				0x013C
+#define REG_PKTBUF_DBG_CTRL			0x0140
+#define REG_PKTBUF_DBG_DATA_L			0x0144
+#define REG_PKTBUF_DBG_DATA_H			0x0148
+#define REG_RXPKTBUF_CTRL			(REG_PKTBUF_DBG_CTRL+2)
+
+#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_32K_CTRL				0x0194
+#define REG_C2HEVT_MSG_NORMAL			0x01A0
+#define REG_C2HEVT_CLEAR			0x01AF
+#define REG_C2HEVT_MSG_TEST			0x01B8
+#define REG_MCUTST_1				0x01c0
+#define REG_MCUTST_WOWLAN			0x01C7
+#define REG_FMETHR				0x01C8
+#define REG_HMETFR				0x01CC
+#define REG_HMEBOX_0				0x01D0
+#define REG_HMEBOX_1				0x01D4
+#define REG_HMEBOX_2				0x01D8
+#define REG_HMEBOX_3				0x01DC
+
+#define REG_LLT_INIT				0x01E0
+#define REG_BB_ACCEESS_CTRL			0x01E8
+#define REG_BB_ACCESS_DATA			0x01EC
+
+#define REG_HMEBOX_EXT_0			0x01F0
+#define REG_HMEBOX_EXT_1			0x01F4
+#define REG_HMEBOX_EXT_2			0x01F8
+#define REG_HMEBOX_EXT_3			0x01FC
+
+#define REG_RQPN				0x0200
+#define REG_FIFOPAGE				0x0204
+#define REG_TDECTRL				0x0208
+#define REG_TXDMA_OFFSET_CHK			0x020C
+#define REG_TXDMA_STATUS			0x0210
+#define REG_RQPN_NPQ				0x0214
+
+#define REG_RXDMA_AGG_PG_TH			0x0280
+ /* FW shall update this register before FW write RXPKT_RELEASE_POLL to 1 */
+#define REG_FW_UPD_RDPTR			0x0284
+ /* Control the RX DMA.*/
+#define REG_RXDMA_CONTROL			0x0286
+/* The number of packets in RXPKTBUF.	*/
+#define REG_RXPKT_NUM				0x0287
+
+#define	REG_PCIE_CTRL_REG			0x0300
+#define	REG_INT_MIG				0x0304
+#define	REG_BCNQ_DESA				0x0308
+#define	REG_HQ_DESA				0x0310
+#define	REG_MGQ_DESA				0x0318
+#define	REG_VOQ_DESA				0x0320
+#define	REG_VIQ_DESA				0x0328
+#define	REG_BEQ_DESA				0x0330
+#define	REG_BKQ_DESA				0x0338
+#define	REG_RX_DESA				0x0340
+
+#define	REG_DBI_WDATA				0x0348
+#define	REG_DBI_RDATA				0x034C
+#define	REG_DBI_CTRL				0x0350
+#define	REG_DBI_ADDR				0x0350
+#define	REG_DBI_FLAG				0x0352
+#define	REG_MDIO_WDATA				0x0354
+#define	REG_MDIO_RDATA				0x0356
+#define	REG_MDIO_CTL				0x0358
+#define	REG_DBG_SEL				0x0360
+#define	REG_PCIE_HRPWM				0x0361
+#define	REG_PCIE_HCPWM				0x0363
+#define	REG_UART_CTRL				0x0364
+#define	REG_WATCH_DOG				0x0368
+#define	REG_UART_TX_DESA			0x0370
+#define	REG_UART_RX_DESA			0x0378
+
+#define	REG_HDAQ_DESA_NODEF			0x0000
+#define	REG_CMDQ_DESA_NODEF			0x0000
+
+#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_TXPKT_EMPTY				0x041A
+
+#define REG_CPU_MGQ_INFORMATION			0x041C
+#define REG_FWHW_TXQ_CTRL			0x0420
+#define REG_HWSEQ_CTRL				0x0423
+#define REG_TXPKTBUF_BCNQ_BDNY			0x0424
+#define REG_TXPKTBUF_MGQ_BDNY			0x0425
+#define REG_MULTI_BCNQ_EN			0x0426
+#define REG_MULTI_BCNQ_OFFSET			0x0427
+#define REG_SPEC_SIFS				0x0428
+#define REG_RL					0x042A
+#define REG_DARFRC				0x0430
+#define REG_RARFRC				0x0438
+#define REG_RRSR				0x0440
+#define REG_ARFR0				0x0444
+#define REG_ARFR1				0x044C
+#define REG_CCK_CHECK				0x0454
+#define REG_AMPDU_MAX_TIME			0x0456
+#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_ARFR2				0x048C
+#define REG_ARFR3				0x0494
+#define REG_POWER_STATUS			0x04A4
+#define REG_POWER_STAGE1			0x04B4
+#define REG_POWER_STAGE2			0x04B8
+#define REG_PKT_LIFE_TIME			0x04C0
+#define REG_STBC_SETTING			0x04C4
+#define REG_HT_SINGLE_AMPDU			0x04C7
+#define REG_PROT_MODE_CTRL			0x04C8
+#define REG_MAX_AGGR_NUM			0x04CA
+#define REG_BAR_MODE_CTRL			0x04CC
+#define REG_RA_TRY_RATE_AGG_LMT			0x04CF
+#define REG_EARLY_MODE_CONTROL			0x04D0
+#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_TX_RPT_CTRL				0x04EC
+#define REG_TX_RPT_TIME				0x04F0
+#define REG_DUMMY				0x04FC
+
+#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 REG_BCNTCFG				0x0510
+#define REG_PIFS				0x0512
+#define REG_RDG_PIFS				0x0513
+#define REG_SIFS_CTX				0x0514
+#define REG_SIFS_TRX				0x0516
+#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_BCN_CTRL				0x0550
+#define REG_USTIME_TSF				0x0551
+#define REG_MBID_NUM				0x0552
+#define REG_DUAL_TSF_RST			0x0553
+#define REG_BCN_INTERVAL			0x0554
+#define REG_MBSSID_BCN_SPACE			0x0554
+#define REG_DRVERLYINT				0x0558
+#define REG_BCNDMATIM				0x0559
+#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_INIT_TSFTR				0x0564
+#define REG_SECONDARY_CCA_CTRL			0x0577
+#define REG_PSTIMER				0x0580
+#define REG_TIMER0				0x0584
+#define REG_TIMER1				0x0588
+#define REG_ACMHWCTRL				0x05C0
+#define REG_ACMRSTCTRL				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_NOA_DESC_SEL			0x05CF
+#define REG_NOA_DESC_DURATION			0x05E0
+#define REG_NOA_DESC_INTERVAL			0x05E4
+#define REG_NOA_DESC_START			0x05E8
+#define REG_NOA_DESC_COUNT			0x05EC
+#define REG_SCH_TXCMD				0x05F8
+
+#define REG_APSD_CTRL				0x0600
+#define REG_BWOPMODE				0x0603
+#define REG_TCR					0x0604
+#define REG_RCR					0x0608
+#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
+#define REG_RESP_SIFS_CCK			0x063C
+#define REG_RESP_SIFS_OFDM			0x063E
+#define REG_ACKTO				0x0640
+#define REG_CTS2TO				0x0641
+#define REG_EIFS				0x0642
+
+#define REG_NAV_CTRL				0x0650
+#define REG_NAV_UPPER				0x0652
+#define REG_BACAMCMD				0x0654
+#define REG_BACAMCONTENT			0x0658
+#define REG_LBDLY				0x0660
+#define REG_FWDLY				0x0661
+#define REG_RXERR_RPT				0x0664
+#define REG_TRXPTCL_CTL				0x0668
+
+#define REG_CAMCMD				0x0670
+#define REG_CAMWRITE				0x0674
+#define REG_CAMREAD				0x0678
+#define REG_CAMDBG				0x067C
+#define REG_SECCFG				0x0680
+
+#define REG_WOW_CTRL				0x0690
+#define REG_PSSTATUS				0x0691
+#define REG_PS_RX_INFO				0x0692
+#define REG_UAPSD_TID				0x0693
+#define REG_LPNAV_CTRL				0x0694
+#define REG_WKFMCAM_NUM				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_USB_INFO				0xFE17
+#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_TEST_USB_TXQS			0xFE48
+#define REG_TEST_SIE_VID			0xFE60
+#define REG_TEST_SIE_PID			0xFE62
+#define REG_TEST_SIE_OPTIONAL			0xFE64
+#define REG_TEST_SIE_CHIRP_K			0xFE65
+#define REG_TEST_SIE_PHY			0xFE66
+#define REG_TEST_SIE_MAC_ADDR			0xFE70
+#define REG_TEST_SIE_STRING			0xFE80
+
+#define REG_NORMAL_SIE_VID			0xFE60
+#define REG_NORMAL_SIE_PID			0xFE62
+#define REG_NORMAL_SIE_OPTIONAL			0xFE64
+#define REG_NORMAL_SIE_EP			0xFE65
+#define REG_NORMAL_SIE_PHY			0xFE68
+#define REG_NORMAL_SIE_MAC_ADDR			0xFE70
+#define REG_NORMAL_SIE_STRING			0xFE80
+
+#define	CR9346					REG_9346CR
+#define	MSR					(REG_CR + 2)
+#define	ISR					REG_HISR
+#define	TSFR					REG_TSFTR
+
+#define	MACIDR0					REG_MACID
+#define	MACIDR4					(REG_MACID + 4)
+
+#define PBP					REG_PBP
+
+#define	IDR0					MACIDR0
+#define	IDR4					MACIDR4
+
+#define	UNUSED_REGISTER				0x1BF
+#define	DCAM					UNUSED_REGISTER
+#define	PSR					UNUSED_REGISTER
+#define BBADDR					UNUSED_REGISTER
+#define	PHYDATAR				UNUSED_REGISTER
+
+#define	INVALID_BBRF_VALUE			0x12345678
+
+#define	MAX_MSS_DENSITY_2T			0x13
+#define	MAX_MSS_DENSITY_1T			0x0A
+
+#define	CMDEEPROM_EN				BIT(5)
+#define	CMDEEPROM_SEL				BIT(4)
+#define	CMD9346CR_9356SEL			BIT(4)
+#define	AUTOLOAD_EEPROM			(CMDEEPROM_EN|CMDEEPROM_SEL)
+#define	AUTOLOAD_EFUSE			CMDEEPROM_EN
+
+#define	GPIOSEL_GPIO				0
+#define	GPIOSEL_ENBT				BIT(5)
+
+#define	GPIO_IN				REG_GPIO_PIN_CTRL
+#define	GPIO_OUT			(REG_GPIO_PIN_CTRL+1)
+#define	GPIO_IO_SEL			(REG_GPIO_PIN_CTRL+2)
+#define	GPIO_MOD			(REG_GPIO_PIN_CTRL+3)
+
+/*    8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */
+#define	HSIMR_GPIO12_0_INT_EN			BIT(0)
+#define	HSIMR_SPS_OCP_INT_EN			BIT(5)
+#define	HSIMR_RON_INT_EN			BIT(6)
+#define	HSIMR_PDN_INT_EN			BIT(7)
+#define	HSIMR_GPIO9_INT_EN			BIT(25)
+
+/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */
+#define	HSISR_GPIO12_0_INT			BIT(0)
+#define	HSISR_SPS_OCP_INT			BIT(5)
+#define	HSISR_RON_INT_EN			BIT(6)
+#define	HSISR_PDNINT				BIT(7)
+#define	HSISR_GPIO9_INT				BIT(25)
+
+#define	MSR_NOLINK				0x00
+#define	MSR_ADHOC				0x01
+#define	MSR_INFRA				0x02
+#define	MSR_AP					0x03
+
+#define	RRSR_RSC_OFFSET				21
+#define	RRSR_SHORT_OFFSET			23
+#define	RRSR_RSC_BW_40M				0x600000
+#define	RRSR_RSC_UPSUBCHNL			0x400000
+#define	RRSR_RSC_LOWSUBCHNL			0x200000
+#define	RRSR_SHORT				0x800000
+#define	RRSR_1M					BIT(0)
+#define	RRSR_2M					BIT(1)
+#define	RRSR_5_5M				BIT(2)
+#define	RRSR_11M				BIT(3)
+#define	RRSR_6M					BIT(4)
+#define	RRSR_9M					BIT(5)
+#define	RRSR_12M				BIT(6)
+#define	RRSR_18M				BIT(7)
+#define	RRSR_24M				BIT(8)
+#define	RRSR_36M				BIT(9)
+#define	RRSR_48M				BIT(10)
+#define	RRSR_54M				BIT(11)
+#define	RRSR_MCS0				BIT(12)
+#define	RRSR_MCS1				BIT(13)
+#define	RRSR_MCS2				BIT(14)
+#define	RRSR_MCS3				BIT(15)
+#define	RRSR_MCS4				BIT(16)
+#define	RRSR_MCS5				BIT(17)
+#define	RRSR_MCS6				BIT(18)
+#define	RRSR_MCS7				BIT(19)
+#define	BRSR_ACKSHORTPMB			BIT(23)
+
+#define	RATR_1M					0x00000001
+#define	RATR_2M					0x00000002
+#define	RATR_55M				0x00000004
+#define	RATR_11M				0x00000008
+#define	RATR_6M					0x00000010
+#define	RATR_9M					0x00000020
+#define	RATR_12M				0x00000040
+#define	RATR_18M				0x00000080
+#define	RATR_24M				0x00000100
+#define	RATR_36M				0x00000200
+#define	RATR_48M				0x00000400
+#define	RATR_54M				0x00000800
+#define	RATR_MCS0				0x00001000
+#define	RATR_MCS1				0x00002000
+#define	RATR_MCS2				0x00004000
+#define	RATR_MCS3				0x00008000
+#define	RATR_MCS4				0x00010000
+#define	RATR_MCS5				0x00020000
+#define	RATR_MCS6				0x00040000
+#define	RATR_MCS7				0x00080000
+#define	RATR_MCS8				0x00100000
+#define	RATR_MCS9				0x00200000
+#define	RATR_MCS10				0x00400000
+#define	RATR_MCS11				0x00800000
+#define	RATR_MCS12				0x01000000
+#define	RATR_MCS13				0x02000000
+#define	RATR_MCS14				0x04000000
+#define	RATR_MCS15				0x08000000
+
+#define RATE_1M					BIT(0)
+#define RATE_2M					BIT(1)
+#define RATE_5_5M				BIT(2)
+#define RATE_11M				BIT(3)
+#define RATE_6M					BIT(4)
+#define RATE_9M					BIT(5)
+#define RATE_12M				BIT(6)
+#define RATE_18M				BIT(7)
+#define RATE_24M				BIT(8)
+#define RATE_36M				BIT(9)
+#define RATE_48M				BIT(10)
+#define RATE_54M				BIT(11)
+#define RATE_MCS0				BIT(12)
+#define RATE_MCS1				BIT(13)
+#define RATE_MCS2				BIT(14)
+#define RATE_MCS3				BIT(15)
+#define RATE_MCS4				BIT(16)
+#define RATE_MCS5				BIT(17)
+#define RATE_MCS6				BIT(18)
+#define RATE_MCS7				BIT(19)
+#define RATE_MCS8				BIT(20)
+#define RATE_MCS9				BIT(21)
+#define RATE_MCS10				BIT(22)
+#define RATE_MCS11				BIT(23)
+#define RATE_MCS12				BIT(24)
+#define RATE_MCS13				BIT(25)
+#define RATE_MCS14				BIT(26)
+#define RATE_MCS15				BIT(27)
+
+#define	RATE_ALL_CCK		(RATR_1M | RATR_2M | RATR_55M | RATR_11M)
+#define	RATE_ALL_OFDM_AG	(RATR_6M | RATR_9M | RATR_12M | RATR_18M |\
+				RATR_24M | RATR_36M | RATR_48M | RATR_54M)
+#define	RATE_ALL_OFDM_1SS	(RATR_MCS0 | RATR_MCS1 | RATR_MCS2 |\
+				RATR_MCS3 | RATR_MCS4 | RATR_MCS5 |\
+				RATR_MCS6 | RATR_MCS7)
+#define	RATE_ALL_OFDM_2SS	(RATR_MCS8 | RATR_MCS9 | RATR_MCS10 |\
+				RATR_MCS11 | RATR_MCS12 | RATR_MCS13 |\
+				RATR_MCS14 | RATR_MCS15)
+
+#define	BW_OPMODE_20MHZ				BIT(2)
+#define	BW_OPMODE_5G				BIT(1)
+#define	BW_OPMODE_11J				BIT(0)
+
+#define	CAM_VALID				BIT(15)
+#define	CAM_NOTVALID				0x0000
+#define	CAM_USEDK				BIT(5)
+
+#define	CAM_NONE				0x0
+#define	CAM_WEP40				0x01
+#define	CAM_TKIP				0x02
+#define	CAM_AES					0x04
+#define	CAM_WEP104				0x05
+
+#define	TOTAL_CAM_ENTRY				32
+#define	HALF_CAM_ENTRY				16
+
+#define	CAM_WRITE				BIT(16)
+#define	CAM_READ				0x00000000
+#define	CAM_POLLINIG				BIT(31)
+
+#define	SCR_USEDK				0x01
+#define	SCR_TXSEC_ENABLE			0x02
+#define	SCR_RXSEC_ENABLE			0x04
+
+#define	WOW_PMEN				BIT(0)
+#define	WOW_WOMEN				BIT(1)
+#define	WOW_MAGIC				BIT(2)
+#define	WOW_UWF					BIT(3)
+
+/*********************************************
+*       8188 IMR/ISR bits
+**********************************************/
+#define	IMR_DISABLED				0x0
+/* IMR DW0(0x0060-0063) Bit 0-31 */
+/* TXRPT interrupt when CCX bit of the packet is set	*/
+#define	IMR_TXCCK				BIT(30)
+/* Power Save Time Out Interrupt */
+#define	IMR_PSTIMEOUT				BIT(29)
+/* When GTIMER4 expires, this bit is set to 1	*/
+#define	IMR_GTINT4				BIT(28)
+/* When GTIMER3 expires, this bit is set to 1	*/
+#define	IMR_GTINT3				BIT(27)
+/* Transmit Beacon0 Error			*/
+#define	IMR_TBDER				BIT(26)
+/* Transmit Beacon0 OK			*/
+#define	IMR_TBDOK				BIT(25)
+/* TSF Timer BIT32 toggle indication interrupt		*/
+#define	IMR_TSF_BIT32_TOGGLE			BIT(24)
+/* Beacon DMA Interrupt 0			*/
+#define	IMR_BCNDMAINT0				BIT(20)
+/* Beacon Queue DMA OK0			*/
+#define	IMR_BCNDOK0				BIT(16)
+/* HSISR Indicator (HSIMR & HSISR is true, this bit is set to 1) */
+#define	IMR_HSISR_IND_ON_INT			BIT(15)
+/* Beacon DMA Interrupt Extension for Win7			*/
+#define	IMR_BCNDMAINT_E				BIT(14)
+/* CTWidnow End or ATIM Window End */
+#define	IMR_ATIMEND				BIT(12)
+/* HISR1 Indicator (HISR1 & HIMR1 is true, this bit is set to 1)*/
+#define	IMR_HISR1_IND_INT			BIT(11)
+/* CPU to Host Command INT Status, Write 1 clear	*/
+#define	IMR_C2HCMD				BIT(10)
+/* CPU power Mode exchange INT Status, Write 1 clear	*/
+#define	IMR_CPWM2				BIT(9)
+/* CPU power Mode exchange INT Status, Write 1 clear	*/
+#define	IMR_CPWM				BIT(8)
+/* High Queue DMA OK	*/
+#define	IMR_HIGHDOK				BIT(7)
+/* Management Queue DMA OK	*/
+#define	IMR_MGNTDOK				BIT(6)
+/* AC_BK DMA OK		*/
+#define	IMR_BKDOK				BIT(5)
+/* AC_BE DMA OK	*/
+#define	IMR_BEDOK				BIT(4)
+/* AC_VI DMA OK	*/
+#define	IMR_VIDOK				BIT(3)
+/* AC_VO DMA OK	*/
+#define	IMR_VODOK				BIT(2)
+/* Rx Descriptor Unavailable	*/
+#define	IMR_RDU					BIT(1)
+#define	IMR_ROK					BIT(0)	/* Receive DMA OK */
+
+/* IMR DW1(0x00B4-00B7) Bit 0-31 */
+/* Beacon DMA Interrupt 7	*/
+#define	IMR_BCNDMAINT7				BIT(27)
+/* Beacon DMA Interrupt 6		*/
+#define	IMR_BCNDMAINT6				BIT(26)
+/* Beacon DMA Interrupt 5		*/
+#define	IMR_BCNDMAINT5				BIT(25)
+/* Beacon DMA Interrupt 4		*/
+#define	IMR_BCNDMAINT4				BIT(24)
+/* Beacon DMA Interrupt 3		*/
+#define	IMR_BCNDMAINT3				BIT(23)
+/* Beacon DMA Interrupt 2		*/
+#define	IMR_BCNDMAINT2				BIT(22)
+/* Beacon DMA Interrupt 1		*/
+#define	IMR_BCNDMAINT1				BIT(21)
+/* Beacon Queue DMA OK Interrup 7 */
+#define	IMR_BCNDOK7				BIT(20)
+/* Beacon Queue DMA OK Interrup 6 */
+#define	IMR_BCNDOK6				BIT(19)
+/* Beacon Queue DMA OK Interrup 5 */
+#define	IMR_BCNDOK5				BIT(18)
+/* Beacon Queue DMA OK Interrup 4 */
+#define	IMR_BCNDOK4				BIT(17)
+/* Beacon Queue DMA OK Interrup 3 */
+#define	IMR_BCNDOK3				BIT(16)
+/* Beacon Queue DMA OK Interrup 2 */
+#define	IMR_BCNDOK2				BIT(15)
+/* Beacon Queue DMA OK Interrup 1 */
+#define	IMR_BCNDOK1				BIT(14)
+/* ATIM Window End Extension for Win7 */
+#define	IMR_ATIMEND_E				BIT(13)
+/* Tx Error Flag Interrupt Status, write 1 clear. */
+#define	IMR_TXERR				BIT(11)
+/* Rx Error Flag INT Status, Write 1 clear */
+#define	IMR_RXERR				BIT(10)
+/* Transmit FIFO Overflow */
+#define	IMR_TXFOVW				BIT(9)
+/* Receive FIFO Overflow */
+#define	IMR_RXFOVW				BIT(8)
+
+#define	HWSET_MAX_SIZE				512
+#define   EFUSE_MAX_SECTION			64
+#define   EFUSE_REAL_CONTENT_LEN		256
+/* PG data exclude header, dummy 7 bytes frome CP test and reserved 1byte.*/
+#define		EFUSE_OOB_PROTECT_BYTES		18
+
+#define	EEPROM_DEFAULT_TSSI			0x0
+#define EEPROM_DEFAULT_TXPOWERDIFF		0x0
+#define EEPROM_DEFAULT_CRYSTALCAP		0x5
+#define EEPROM_DEFAULT_BOARDTYPE		0x02
+#define EEPROM_DEFAULT_TXPOWER			0x1010
+#define	EEPROM_DEFAULT_HT2T_TXPWR		0x10
+
+#define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3
+#define	EEPROM_DEFAULT_THERMALMETER		0x18
+#define	EEPROM_DEFAULT_ANTTXPOWERDIFF		0x0
+#define	EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP	0x5
+#define	EEPROM_DEFAULT_TXPOWERLEVEL		0x22
+#define	EEPROM_DEFAULT_HT40_2SDIFF		0x0
+#define EEPROM_DEFAULT_HT20_DIFF		2
+#define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3
+#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET	0
+#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET	0
+
+#define RF_OPTION1				0x79
+#define RF_OPTION2				0x7A
+#define RF_OPTION3				0x7B
+#define RF_OPTION4				0xC3
+
+#define EEPROM_DEFAULT_PID			0x1234
+#define EEPROM_DEFAULT_VID			0x5678
+#define EEPROM_DEFAULT_CUSTOMERID		0xAB
+#define EEPROM_DEFAULT_SUBCUSTOMERID		0xCD
+#define EEPROM_DEFAULT_VERSION			0
+
+#define	EEPROM_CHANNEL_PLAN_FCC			0x0
+#define	EEPROM_CHANNEL_PLAN_IC			0x1
+#define	EEPROM_CHANNEL_PLAN_ETSI		0x2
+#define	EEPROM_CHANNEL_PLAN_SPAIN		0x3
+#define	EEPROM_CHANNEL_PLAN_FRANCE		0x4
+#define	EEPROM_CHANNEL_PLAN_MKK			0x5
+#define	EEPROM_CHANNEL_PLAN_MKK1		0x6
+#define	EEPROM_CHANNEL_PLAN_ISRAEL		0x7
+#define	EEPROM_CHANNEL_PLAN_TELEC		0x8
+#define	EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN	0x9
+#define	EEPROM_CHANNEL_PLAN_WORLD_WIDE_13	0xA
+#define	EEPROM_CHANNEL_PLAN_NCC			0xB
+#define	EEPROM_CHANNEL_PLAN_BY_HW_MASK		0x80
+
+#define EEPROM_CID_DEFAULT			0x0
+#define EEPROM_CID_TOSHIBA			0x4
+#define	EEPROM_CID_CCX				0x10
+#define	EEPROM_CID_QMI				0x0D
+#define EEPROM_CID_WHQL				0xFE
+
+#define	RTL_EEPROM_ID				0x8129
+
+#define EEPROM_HPON				0x02
+#define EEPROM_CLK				0x06
+#define EEPROM_TESTR				0x08
+
+#define EEPROM_TXPOWERCCK			0x10
+#define	EEPROM_TXPOWERHT40_1S			0x16
+#define EEPROM_TXPOWERHT20DIFF			0x1B
+#define EEPROM_TXPOWER_OFDMDIFF			0x1B
+
+#define	EEPROM_TX_PWR_INX			0x10
+
+#define	EEPROM_CHANNELPLAN			0xB8
+#define	EEPROM_XTAL_8821AE			0xB9
+#define	EEPROM_THERMAL_METER			0xBA
+#define	EEPROM_IQK_LCK_88E			0xBB
+
+#define	EEPROM_RF_BOARD_OPTION			0xC1
+#define	EEPROM_RF_FEATURE_OPTION_88E		0xC2
+#define	EEPROM_RF_BT_SETTING			0xC3
+#define	EEPROM_VERSION				0xC4
+#define	EEPROM_CUSTOMER_ID			0xC5
+#define	EEPROM_RF_ANTENNA_OPT_88E		0xC9
+#define	EEPROM_RFE_OPTION			0xCA
+
+#define	EEPROM_MAC_ADDR				0xD0
+#define EEPROM_VID				0xD6
+#define EEPROM_DID				0xD8
+#define EEPROM_SVID				0xDA
+#define EEPROM_SMID				0xDC
+
+#define	STOPBECON				BIT(6)
+#define	STOPHIGHT				BIT(5)
+#define	STOPMGT					BIT(4)
+#define	STOPVO					BIT(3)
+#define	STOPVI					BIT(2)
+#define	STOPBE					BIT(1)
+#define	STOPBK					BIT(0)
+
+#define	RCR_APPFCS				BIT(31)
+#define	RCR_APP_MIC				BIT(30)
+#define	RCR_APP_ICV				BIT(29)
+#define	RCR_APP_PHYST_RXFF			BIT(28)
+#define	RCR_APP_BA_SSN				BIT(27)
+#define	RCR_NONQOS_VHT				BIT(26)
+#define	RCR_ENMBID				BIT(24)
+#define	RCR_LSIGEN				BIT(23)
+#define	RCR_MFBEN				BIT(22)
+#define	RCR_HTC_LOC_CTRL			BIT(14)
+#define	RCR_AMF					BIT(13)
+#define	RCR_ACF					BIT(12)
+#define	RCR_ADF					BIT(11)
+#define	RCR_AICV				BIT(9)
+#define	RCR_ACRC32				BIT(8)
+#define	RCR_CBSSID_BCN				BIT(7)
+#define	RCR_CBSSID_DATA				BIT(6)
+#define	RCR_CBSSID				RCR_CBSSID_DATA
+#define	RCR_APWRMGT				BIT(5)
+#define	RCR_ADD3				BIT(4)
+#define	RCR_AB					BIT(3)
+#define	RCR_AM					BIT(2)
+#define	RCR_APM					BIT(1)
+#define	RCR_AAP					BIT(0)
+#define	RCR_MXDMA_OFFSET			8
+#define	RCR_FIFO_OFFSET				13
+
+#define RSV_CTRL				0x001C
+#define RD_CTRL					0x0524
+
+#define REG_USB_INFO				0xFE17
+#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_USB_VID				0xFE60
+#define REG_USB_PID				0xFE62
+#define REG_USB_OPTIONAL			0xFE64
+#define REG_USB_CHIRP_K				0xFE65
+#define REG_USB_PHY				0xFE66
+#define REG_USB_MAC_ADDR			0xFE70
+#define REG_USB_HRPWM				0xFE58
+#define REG_USB_HCPWM				0xFE57
+
+#define SW18_FPWM				BIT(3)
+
+#define ISO_MD2PP				BIT(0)
+#define ISO_UA2USB				BIT(1)
+#define ISO_UD2CORE				BIT(2)
+#define ISO_PA2PCIE				BIT(3)
+#define ISO_PD2CORE				BIT(4)
+#define ISO_IP2MAC				BIT(5)
+#define ISO_DIOP				BIT(6)
+#define ISO_DIOE				BIT(7)
+#define ISO_EB2CORE				BIT(8)
+#define ISO_DIOR				BIT(9)
+
+#define PWC_EV25V				BIT(14)
+#define PWC_EV12V				BIT(15)
+
+#define FEN_BBRSTB				BIT(0)
+#define FEN_BB_GLB_RSTN				BIT(1)
+#define FEN_USBA				BIT(2)
+#define FEN_UPLL				BIT(3)
+#define FEN_USBD				BIT(4)
+#define FEN_DIO_PCIE				BIT(5)
+#define FEN_PCIEA				BIT(6)
+#define FEN_PPLL				BIT(7)
+#define FEN_PCIED				BIT(8)
+#define FEN_DIOE				BIT(9)
+#define FEN_CPUEN				BIT(10)
+#define FEN_DCORE				BIT(11)
+#define FEN_ELDR				BIT(12)
+#define FEN_DIO_RF				BIT(13)
+#define FEN_HWPDN				BIT(14)
+#define FEN_MREGEN				BIT(15)
+
+#define PFM_LDALL				BIT(0)
+#define PFM_ALDN				BIT(1)
+#define PFM_LDKP				BIT(2)
+#define PFM_WOWL				BIT(3)
+#define ENPDN					BIT(4)
+#define PDN_PL					BIT(5)
+#define APFM_ONMAC				BIT(8)
+#define APFM_OFF				BIT(9)
+#define APFM_RSM				BIT(10)
+#define AFSM_HSUS				BIT(11)
+#define AFSM_PCIE				BIT(12)
+#define APDM_MAC				BIT(13)
+#define APDM_HOST				BIT(14)
+#define APDM_HPDN				BIT(15)
+#define RDY_MACON				BIT(16)
+#define SUS_HOST				BIT(17)
+#define ROP_ALD					BIT(20)
+#define ROP_PWR					BIT(21)
+#define ROP_SPS					BIT(22)
+#define SOP_MRST				BIT(25)
+#define SOP_FUSE				BIT(26)
+#define SOP_ABG					BIT(27)
+#define SOP_AMB					BIT(28)
+#define SOP_RCK					BIT(29)
+#define SOP_A8M					BIT(30)
+#define XOP_BTCK				BIT(31)
+
+#define ANAD16V_EN				BIT(0)
+#define ANA8M					BIT(1)
+#define MACSLP					BIT(4)
+#define LOADER_CLK_EN				BIT(5)
+#define _80M_SSC_DIS				BIT(7)
+#define _80M_SSC_EN_HO				BIT(8)
+#define PHY_SSC_RSTB				BIT(9)
+#define SEC_CLK_EN				BIT(10)
+#define MAC_CLK_EN				BIT(11)
+#define SYS_CLK_EN				BIT(12)
+#define RING_CLK_EN				BIT(13)
+
+#define	BOOT_FROM_EEPROM			BIT(4)
+#define	EEPROM_EN				BIT(5)
+
+#define AFE_BGEN				BIT(0)
+#define AFE_MBEN				BIT(1)
+#define MAC_ID_EN				BIT(7)
+
+#define WLOCK_ALL				BIT(0)
+#define WLOCK_00				BIT(1)
+#define WLOCK_04				BIT(2)
+#define WLOCK_08				BIT(3)
+#define WLOCK_40				BIT(4)
+#define R_DIS_PRST_0				BIT(5)
+#define R_DIS_PRST_1				BIT(6)
+#define LOCK_ALL_EN				BIT(7)
+
+#define RF_EN					BIT(0)
+#define RF_RSTB					BIT(1)
+#define RF_SDMRSTB				BIT(2)
+
+#define LDA15_EN				BIT(0)
+#define LDA15_STBY				BIT(1)
+#define LDA15_OBUF				BIT(2)
+#define LDA15_REG_VOS				BIT(3)
+#define _LDA15_VOADJ(x)				(((x) & 0x7) << 4)
+
+#define LDV12_EN				BIT(0)
+#define LDV12_SDBY				BIT(1)
+#define LPLDO_HSM				BIT(2)
+#define LPLDO_LSM_DIS				BIT(3)
+#define _LDV12_VADJ(x)				(((x) & 0xF) << 4)
+
+#define XTAL_EN					BIT(0)
+#define XTAL_BSEL				BIT(1)
+#define _XTAL_BOSC(x)				(((x) & 0x3) << 2)
+#define _XTAL_CADJ(x)				(((x) & 0xF) << 4)
+#define XTAL_GATE_USB				BIT(8)
+#define _XTAL_USB_DRV(x)			(((x) & 0x3) << 9)
+#define XTAL_GATE_AFE				BIT(11)
+#define _XTAL_AFE_DRV(x)			(((x) & 0x3) << 12)
+#define XTAL_RF_GATE				BIT(14)
+#define _XTAL_RF_DRV(x)				(((x) & 0x3) << 15)
+#define XTAL_GATE_DIG				BIT(17)
+#define _XTAL_DIG_DRV(x)			(((x) & 0x3) << 18)
+#define XTAL_BT_GATE				BIT(20)
+#define _XTAL_BT_DRV(x)				(((x) & 0x3) << 21)
+#define _XTAL_GPIO(x)				(((x) & 0x7) << 23)
+
+#define CKDLY_AFE				BIT(26)
+#define CKDLY_USB				BIT(27)
+#define CKDLY_DIG				BIT(28)
+#define CKDLY_BT				BIT(29)
+
+#define APLL_EN					BIT(0)
+#define APLL_320_EN				BIT(1)
+#define APLL_FREF_SEL				BIT(2)
+#define APLL_EDGE_SEL				BIT(3)
+#define APLL_WDOGB				BIT(4)
+#define APLL_LPFEN				BIT(5)
+
+#define APLL_REF_CLK_13MHZ			0x1
+#define APLL_REF_CLK_19_2MHZ			0x2
+#define APLL_REF_CLK_20MHZ			0x3
+#define APLL_REF_CLK_25MHZ			0x4
+#define APLL_REF_CLK_26MHZ			0x5
+#define APLL_REF_CLK_38_4MHZ			0x6
+#define APLL_REF_CLK_40MHZ			0x7
+
+#define APLL_320EN				BIT(14)
+#define APLL_80EN				BIT(15)
+#define APLL_1MEN				BIT(24)
+
+#define ALD_EN					BIT(18)
+#define EF_PD					BIT(19)
+#define EF_FLAG					BIT(31)
+
+#define EF_TRPT					BIT(7)
+#define LDOE25_EN				BIT(31)
+
+#define RSM_EN					BIT(0)
+#define TIMER_EN				BIT(4)
+
+#define TRSW0EN					BIT(2)
+#define TRSW1EN					BIT(3)
+#define EROM_EN					BIT(4)
+#define ENBT					BIT(5)
+#define ENUART					BIT(8)
+#define UART_910				BIT(9)
+#define ENPMAC					BIT(10)
+#define SIC_SWRST				BIT(11)
+#define ENSIC					BIT(12)
+#define SIC_23					BIT(13)
+#define ENHDP					BIT(14)
+#define SIC_LBK					BIT(15)
+
+#define LED0PL					BIT(4)
+#define LED1PL					BIT(12)
+#define LED0DIS					BIT(7)
+
+#define MCUFWDL_EN				BIT(0)
+#define MCUFWDL_RDY				BIT(1)
+#define FWDL_CHKSUM_RPT				BIT(2)
+#define MACINI_RDY				BIT(3)
+#define BBINI_RDY				BIT(4)
+#define RFINI_RDY				BIT(5)
+#define WINTINI_RDY				BIT(6)
+#define CPRST					BIT(23)
+
+#define XCLK_VLD				BIT(0)
+#define ACLK_VLD				BIT(1)
+#define UCLK_VLD				BIT(2)
+#define PCLK_VLD				BIT(3)
+#define PCIRSTB					BIT(4)
+#define V15_VLD					BIT(5)
+#define TRP_B15V_EN				BIT(7)
+#define SIC_IDLE				BIT(8)
+#define BD_MAC2					BIT(9)
+#define BD_MAC1					BIT(10)
+#define IC_MACPHY_MODE				BIT(11)
+#define VENDOR_ID				BIT(19)
+#define PAD_HWPD_IDN				BIT(22)
+#define TRP_VAUX_EN				BIT(23)
+#define TRP_BT_EN				BIT(24)
+#define BD_PKG_SEL				BIT(25)
+#define BD_HCI_SEL				BIT(26)
+#define TYPE_ID					BIT(27)
+
+#define CHIP_VER_RTL_MASK			0xF000
+#define CHIP_VER_RTL_SHIFT			12
+
+#define REG_LBMODE				(REG_CR + 3)
+
+#define HCI_TXDMA_EN				BIT(0)
+#define HCI_RXDMA_EN				BIT(1)
+#define TXDMA_EN				BIT(2)
+#define RXDMA_EN				BIT(3)
+#define PROTOCOL_EN				BIT(4)
+#define SCHEDULE_EN				BIT(5)
+#define MACTXEN					BIT(6)
+#define MACRXEN					BIT(7)
+#define ENSWBCN					BIT(8)
+#define ENSEC					BIT(9)
+
+#define _NETTYPE(x)				(((x) & 0x3) << 16)
+#define MASK_NETTYPE				0x30000
+#define NT_NO_LINK				0x0
+#define NT_LINK_AD_HOC				0x1
+#define NT_LINK_AP				0x2
+#define NT_AS_AP				0x3
+
+#define _LBMODE(x)				(((x) & 0xF) << 24)
+#define MASK_LBMODE				0xF000000
+#define LOOPBACK_NORMAL				0x0
+#define LOOPBACK_IMMEDIATELY			0xB
+#define LOOPBACK_MAC_DELAY			0x3
+#define LOOPBACK_PHY				0x1
+#define LOOPBACK_DMA				0x7
+
+#define GET_RX_PAGE_SIZE(value)		((value) & 0xF)
+#define GET_TX_PAGE_SIZE(value)		(((value) & 0xF0) >> 4)
+#define _PSRX_MASK				0xF
+#define _PSTX_MASK				0xF0
+#define _PSRX(x)				(x)
+#define _PSTX(x)				((x) << 4)
+
+#define PBP_64					0x0
+#define PBP_128					0x1
+#define PBP_256					0x2
+#define PBP_512					0x3
+#define PBP_1024				0x4
+
+#define RXDMA_ARBBW_EN				BIT(0)
+#define RXSHFT_EN				BIT(1)
+#define RXDMA_AGG_EN				BIT(2)
+#define QS_VO_QUEUE				BIT(8)
+#define QS_VI_QUEUE				BIT(9)
+#define QS_BE_QUEUE				BIT(10)
+#define QS_BK_QUEUE				BIT(11)
+#define QS_MANAGER_QUEUE			BIT(12)
+#define QS_HIGH_QUEUE				BIT(13)
+
+#define HQSEL_VOQ				BIT(0)
+#define HQSEL_VIQ				BIT(1)
+#define HQSEL_BEQ				BIT(2)
+#define HQSEL_BKQ				BIT(3)
+#define HQSEL_MGTQ				BIT(4)
+#define HQSEL_HIQ				BIT(5)
+
+#define _TXDMA_HIQ_MAP(x)			(((x)&0x3) << 14)
+#define _TXDMA_MGQ_MAP(x)			(((x)&0x3) << 12)
+#define _TXDMA_BKQ_MAP(x)			(((x)&0x3) << 10)
+#define _TXDMA_BEQ_MAP(x)			(((x)&0x3) << 8)
+#define _TXDMA_VIQ_MAP(x)			(((x)&0x3) << 6)
+#define _TXDMA_VOQ_MAP(x)			(((x)&0x3) << 4)
+
+#define QUEUE_LOW				1
+#define QUEUE_NORMAL				2
+#define QUEUE_HIGH				3
+
+#define _LLT_NO_ACTIVE				0x0
+#define _LLT_WRITE_ACCESS			0x1
+#define _LLT_READ_ACCESS			0x2
+
+#define _LLT_INIT_DATA(x)			((x) & 0xFF)
+#define _LLT_INIT_ADDR(x)			(((x) & 0xFF) << 8)
+#define _LLT_OP(x)				(((x) & 0x3) << 30)
+#define _LLT_OP_VALUE(x)			(((x) >> 30) & 0x3)
+
+#define BB_WRITE_READ_MASK			(BIT(31) | BIT(30))
+#define BB_WRITE_EN				BIT(30)
+#define BB_READ_EN				BIT(31)
+
+#define _HPQ(x)				((x) & 0xFF)
+#define _LPQ(x)				(((x) & 0xFF) << 8)
+#define _PUBQ(x)			(((x) & 0xFF) << 16)
+#define _NPQ(x)				((x) & 0xFF)
+
+#define HPQ_PUBLIC_DIS				BIT(24)
+#define LPQ_PUBLIC_DIS				BIT(25)
+#define LD_RQPN					BIT(31)
+
+#define BCN_VALID				BIT(16)
+#define BCN_HEAD(x)			(((x) & 0xFF) << 8)
+#define	BCN_HEAD_MASK				0xFF00
+
+#define BLK_DESC_NUM_SHIFT			4
+#define BLK_DESC_NUM_MASK			0xF
+
+#define DROP_DATA_EN				BIT(9)
+
+#define EN_AMPDU_RTY_NEW			BIT(7)
+
+#define _INIRTSMCS_SEL(x)			((x) & 0x3F)
+
+#define _SPEC_SIFS_CCK(x)			((x) & 0xFF)
+#define _SPEC_SIFS_OFDM(x)			(((x) & 0xFF) << 8)
+
+#define RATE_REG_BITMAP_ALL			0xFFFFF
+
+#define _RRSC_BITMAP(x)				((x) & 0xFFFFF)
+
+#define _RRSR_RSC(x)				(((x) & 0x3) << 21)
+#define RRSR_RSC_RESERVED			0x0
+#define RRSR_RSC_UPPER_SUBCHANNEL		0x1
+#define RRSR_RSC_LOWER_SUBCHANNEL		0x2
+#define RRSR_RSC_DUPLICATE_MODE			0x3
+
+#define USE_SHORT_G1				BIT(20)
+
+#define _AGGLMT_MCS0(x)				((x) & 0xF)
+#define _AGGLMT_MCS1(x)				(((x) & 0xF) << 4)
+#define _AGGLMT_MCS2(x)				(((x) & 0xF) << 8)
+#define _AGGLMT_MCS3(x)				(((x) & 0xF) << 12)
+#define _AGGLMT_MCS4(x)				(((x) & 0xF) << 16)
+#define _AGGLMT_MCS5(x)				(((x) & 0xF) << 20)
+#define _AGGLMT_MCS6(x)				(((x) & 0xF) << 24)
+#define _AGGLMT_MCS7(x)				(((x) & 0xF) << 28)
+
+#define	RETRY_LIMIT_SHORT_SHIFT		8
+#define	RETRY_LIMIT_LONG_SHIFT		0
+
+#define _DARF_RC1(x)			((x) & 0x1F)
+#define _DARF_RC2(x)			(((x) & 0x1F) << 8)
+#define _DARF_RC3(x)			(((x) & 0x1F) << 16)
+#define _DARF_RC4(x)			(((x) & 0x1F) << 24)
+#define _DARF_RC5(x)			((x) & 0x1F)
+#define _DARF_RC6(x)			(((x) & 0x1F) << 8)
+#define _DARF_RC7(x)			(((x) & 0x1F) << 16)
+#define _DARF_RC8(x)			(((x) & 0x1F) << 24)
+
+#define _RARF_RC1(x)			((x) & 0x1F)
+#define _RARF_RC2(x)			(((x) & 0x1F) << 8)
+#define _RARF_RC3(x)			(((x) & 0x1F) << 16)
+#define _RARF_RC4(x)			(((x) & 0x1F) << 24)
+#define _RARF_RC5(x)			((x) & 0x1F)
+#define _RARF_RC6(x)			(((x) & 0x1F) << 8)
+#define _RARF_RC7(x)			(((x) & 0x1F) << 16)
+#define _RARF_RC8(x)			(((x) & 0x1F) << 24)
+
+#define AC_PARAM_TXOP_LIMIT_OFFSET	16
+#define AC_PARAM_ECW_MAX_OFFSET		12
+#define AC_PARAM_ECW_MIN_OFFSET		8
+#define AC_PARAM_AIFS_OFFSET		0
+
+#define _AIFS(x)			(x)
+#define _ECW_MAX_MIN(x)			((x) << 8)
+#define _TXOP_LIMIT(x)			((x) << 16)
+
+#define _BCNIFS(x)			((x) & 0xFF)
+#define _BCNECW(x)			((((x) & 0xF)) << 8)
+
+#define _LRL(x)				((x) & 0x3F)
+#define _SRL(x)				(((x) & 0x3F) << 8)
+
+#define _SIFS_CCK_CTX(x)		((x) & 0xFF)
+#define _SIFS_CCK_TRX(x)		(((x) & 0xFF) << 8)
+
+#define _SIFS_OFDM_CTX(x)		((x) & 0xFF)
+#define _SIFS_OFDM_TRX(x)		(((x) & 0xFF) << 8)
+
+#define _TBTT_PROHIBIT_HOLD(x)		(((x) & 0xFF) << 8)
+
+#define DIS_EDCA_CNT_DWN		BIT(11)
+
+#define EN_MBSSID			BIT(1)
+#define EN_TXBCN_RPT			BIT(2)
+#define	EN_BCN_FUNCTION			BIT(3)
+
+#define TSFTR_RST			BIT(0)
+#define TSFTR1_RST			BIT(1)
+
+#define STOP_BCNQ			BIT(6)
+
+#define	DIS_TSF_UDT0_NORMAL_CHIP	BIT(4)
+#define	DIS_TSF_UDT0_TEST_CHIP		BIT(5)
+
+#define	ACMHW_HWEN			BIT(0)
+#define	ACMHW_BEQEN			BIT(1)
+#define	ACMHW_VIQEN			BIT(2)
+#define	ACMHW_VOQEN			BIT(3)
+#define	ACMHW_BEQSTATUS			BIT(4)
+#define	ACMHW_VIQSTATUS			BIT(5)
+#define	ACMHW_VOQSTATUS			BIT(6)
+
+#define APSDOFF				BIT(6)
+#define APSDOFF_STATUS			BIT(7)
+
+#define BW_20MHZ			BIT(2)
+
+#define RATE_BITMAP_ALL			0xFFFFF
+
+#define RATE_RRSR_CCK_ONLY_1M		0xFFFF1
+
+#define TSFRST				BIT(0)
+#define DIS_GCLK			BIT(1)
+#define PAD_SEL				BIT(2)
+#define PWR_ST				BIT(6)
+#define PWRBIT_OW_EN			BIT(7)
+#define ACRC				BIT(8)
+#define CFENDFORM			BIT(9)
+#define ICV				BIT(10)
+
+#define AAP				BIT(0)
+#define APM				BIT(1)
+#define AM				BIT(2)
+#define AB				BIT(3)
+#define ADD3				BIT(4)
+#define APWRMGT				BIT(5)
+#define CBSSID				BIT(6)
+#define CBSSID_DATA			BIT(6)
+#define CBSSID_BCN			BIT(7)
+#define ACRC32				BIT(8)
+#define AICV				BIT(9)
+#define ADF				BIT(11)
+#define ACF				BIT(12)
+#define AMF				BIT(13)
+#define HTC_LOC_CTRL			BIT(14)
+#define UC_DATA_EN			BIT(16)
+#define BM_DATA_EN			BIT(17)
+#define MFBEN				BIT(22)
+#define LSIGEN				BIT(23)
+#define ENMBID				BIT(24)
+#define APP_BASSN			BIT(27)
+#define APP_PHYSTS			BIT(28)
+#define APP_ICV				BIT(29)
+#define APP_MIC				BIT(30)
+#define APP_FCS				BIT(31)
+
+#define _MIN_SPACE(x)			((x) & 0x7)
+#define _SHORT_GI_PADDING(x)		(((x) & 0x1F) << 3)
+
+#define RXERR_TYPE_OFDM_PPDU		0
+#define RXERR_TYPE_OFDM_FALSE_ALARM	1
+#define	RXERR_TYPE_OFDM_MPDU_OK		2
+#define RXERR_TYPE_OFDM_MPDU_FAIL	3
+#define RXERR_TYPE_CCK_PPDU		4
+#define RXERR_TYPE_CCK_FALSE_ALARM	5
+#define RXERR_TYPE_CCK_MPDU_OK		6
+#define RXERR_TYPE_CCK_MPDU_FAIL	7
+#define RXERR_TYPE_HT_PPDU		8
+#define RXERR_TYPE_HT_FALSE_ALARM	9
+#define RXERR_TYPE_HT_MPDU_TOTAL	10
+#define RXERR_TYPE_HT_MPDU_OK		11
+#define RXERR_TYPE_HT_MPDU_FAIL		12
+#define RXERR_TYPE_RX_FULL_DROP		15
+
+#define RXERR_COUNTER_MASK		0xFFFFF
+#define RXERR_RPT_RST			BIT(27)
+#define _RXERR_RPT_SEL(type)		((type) << 28)
+
+#define	SCR_TXUSEDK			BIT(0)
+#define	SCR_RXUSEDK			BIT(1)
+#define	SCR_TXENCENABLE			BIT(2)
+#define	SCR_RXDECENABLE			BIT(3)
+#define	SCR_SKBYA2			BIT(4)
+#define	SCR_NOSKMC			BIT(5)
+#define SCR_TXBCUSEDK			BIT(6)
+#define SCR_RXBCUSEDK			BIT(7)
+
+#define XCLK_VLD			BIT(0)
+#define ACLK_VLD			BIT(1)
+#define UCLK_VLD			BIT(2)
+#define PCLK_VLD			BIT(3)
+#define PCIRSTB				BIT(4)
+#define V15_VLD				BIT(5)
+#define TRP_B15V_EN			BIT(7)
+#define SIC_IDLE			BIT(8)
+#define BD_MAC2				BIT(9)
+#define BD_MAC1				BIT(10)
+#define IC_MACPHY_MODE			BIT(11)
+#define BT_FUNC				BIT(16)
+#define VENDOR_ID			BIT(19)
+#define PAD_HWPD_IDN			BIT(22)
+#define TRP_VAUX_EN			BIT(23)
+#define TRP_BT_EN			BIT(24)
+#define BD_PKG_SEL			BIT(25)
+#define BD_HCI_SEL			BIT(26)
+#define TYPE_ID				BIT(27)
+
+#define USB_IS_HIGH_SPEED		0
+#define USB_IS_FULL_SPEED		1
+#define USB_SPEED_MASK			BIT(5)
+
+#define USB_NORMAL_SIE_EP_MASK		0xF
+#define USB_NORMAL_SIE_EP_SHIFT		4
+
+#define USB_TEST_EP_MASK		0x30
+#define USB_TEST_EP_SHIFT		4
+
+#define USB_AGG_EN			BIT(3)
+
+#define MAC_ADDR_LEN			6
+#define LAST_ENTRY_OF_TX_PKT_BUFFER	255
+
+#define POLLING_LLT_THRESHOLD		20
+#define POLLING_READY_TIMEOUT_COUNT	3000
+
+#define	MAX_MSS_DENSITY_2T		0x13
+#define	MAX_MSS_DENSITY_1T		0x0A
+
+#define EPROM_CMD_OPERATING_MODE_MASK	((1<<7)|(1<<6))
+#define EPROM_CMD_CONFIG		0x3
+#define EPROM_CMD_LOAD			1
+
+#define	HWSET_MAX_SIZE_92S		HWSET_MAX_SIZE
+
+#define	HAL_8192C_HW_GPIO_WPS_BIT	BIT(2)
+
+#define RA_LSSIWRITE_8821A		0xc90
+#define RB_LSSIWRITE_8821A		0xe90
+
+#define	RA_PIREAD_8821A			0xd04
+#define	RB_PIREAD_8821A			0xd44
+#define	RA_SIREAD_8821A			0xd08
+#define	RB_SIREAD_8821A			0xd48
+
+#define	RPMAC_RESET			0x100
+#define	RPMAC_TXSTART			0x104
+#define	RPMAC_TXLEGACYSIG		0x108
+#define	RPMAC_TXHTSIG1			0x10c
+#define	RPMAC_TXHTSIG2			0x110
+#define	RPMAC_PHYDEBUG			0x114
+#define	RPMAC_TXPACKETNUM		0x118
+#define	RPMAC_TXIDLE			0x11c
+#define	RPMAC_TXMACHEADER0		0x120
+#define	RPMAC_TXMACHEADER1		0x124
+#define	RPMAC_TXMACHEADER2		0x128
+#define	RPMAC_TXMACHEADER3		0x12c
+#define	RPMAC_TXMACHEADER4		0x130
+#define	RPMAC_TXMACHEADER5		0x134
+#define	RPMAC_TXDADATYPE		0x138
+#define	RPMAC_TXRANDOMSEED		0x13c
+#define	RPMAC_CCKPLCPPREAMBLE		0x140
+#define	RPMAC_CCKPLCPHEADER		0x144
+#define	RPMAC_CCKCRC16			0x148
+#define	RPMAC_OFDMRXCRC32OK		0x170
+#define	RPMAC_OFDMRXCRC32ER		0x174
+#define	RPMAC_OFDMRXPARITYER		0x178
+#define	RPMAC_OFDMRXCRC8ER		0x17c
+#define	RPMAC_CCKCRXRC16ER		0x180
+#define	RPMAC_CCKCRXRC32ER		0x184
+#define	RPMAC_CCKCRXRC32OK		0x188
+#define	RPMAC_TXSTATUS			0x18c
+
+#define	RFPGA0_RFMOD			0x800
+
+#define	RFPGA0_TXINFO			0x804
+#define	RFPGA0_PSDFUNCTION		0x808
+
+#define	RFPGA0_TXGAINSTAGE		0x80c
+
+#define	RFPGA0_RFTIMING1		0x810
+#define	RFPGA0_RFTIMING2		0x814
+
+#define	RFPGA0_XA_HSSIPARAMETER1	0x820
+#define	RFPGA0_XA_HSSIPARAMETER2	0x824
+#define	RFPGA0_XB_HSSIPARAMETER1	0x828
+#define	RFPGA0_XB_HSSIPARAMETER2	0x82c
+#define	RCCAONSEC			0x838
+
+#define	RFPGA0_XA_LSSIPARAMETER		0x840
+#define	RFPGA0_XB_LSSIPARAMETER		0x844
+#define	RL1PEAKTH			0x848
+
+#define	RFPGA0_RFWAKEUPPARAMETER	0x850
+#define	RFPGA0_RFSLEEPUPPARAMETER	0x854
+
+#define	RFPGA0_XAB_SWITCHCONTROL	0x858
+#define	RFPGA0_XCD_SWITCHCONTROL	0x85c
+
+#define	RFPGA0_XA_RFINTERFACEOE		0x860
+#define RFC_AREA			0x860
+#define	RFPGA0_XB_RFINTERFACEOE		0x864
+
+#define	RFPGA0_XAB_RFINTERFACESW	0x870
+#define	RFPGA0_XCD_RFINTERFACESW	0x874
+
+#define	RFPGA0_XAB_RFPARAMETER		0x878
+#define	RFPGA0_XCD_RFPARAMETER		0x87c
+
+#define	RFPGA0_ANALOGPARAMETER1		0x880
+#define	RFPGA0_ANALOGPARAMETER2		0x884
+#define	RFPGA0_ANALOGPARAMETER3		0x888
+#define	RFPGA0_ANALOGPARAMETER4		0x88c
+
+#define	RFPGA0_XA_LSSIREADBACK		0x8a0
+#define	RFPGA0_XB_LSSIREADBACK		0x8a4
+#define	RFPGA0_XC_LSSIREADBACK		0x8a8
+#define RRFMOD				0x8ac
+#define	RHSSIREAD_8821AE		0x8b0
+
+#define	RFPGA0_PSDREPORT		0x8b4
+#define	TRANSCEIVEA_HSPI_READBACK	0x8b8
+#define	TRANSCEIVEB_HSPI_READBACK	0x8bc
+#define RADC_BUF_CLK			0x8c4
+#define	RFPGA0_XAB_RFINTERFACERB	0x8e0
+#define	RFPGA0_XCD_RFINTERFACERB	0x8e4
+
+#define	RFPGA1_RFMOD			0x900
+
+#define	RFPGA1_TXBLOCK			0x904
+#define	RFPGA1_DEBUGSELECT		0x908
+#define	RFPGA1_TXINFO			0x90c
+
+#define	RCCK_SYSTEM			0xa00
+#define	BCCK_SYSTEM			0x10
+
+#define	RCCK0_AFESETTING		0xa04
+#define	RCCK0_CCA			0xa08
+
+#define	RCCK0_RXAGC1			0xa0c
+#define	RCCK0_RXAGC2			0xa10
+
+#define	RCCK0_RXHP			0xa14
+
+#define	RCCK0_DSPPARAMETER1		0xa18
+#define	RCCK0_DSPPARAMETER2		0xa1c
+
+#define	RCCK0_TXFILTER1			0xa20
+#define	RCCK0_TXFILTER2			0xa24
+#define	RCCK0_DEBUGPORT			0xa28
+#define	RCCK0_FALSEALARMREPORT		0xa2c
+#define	RCCK0_TRSSIREPORT		0xa50
+#define	RCCK0_RXREPORT			0xa54
+#define	RCCK0_FACOUNTERLOWER		0xa5c
+#define	RCCK0_FACOUNTERUPPER		0xa58
+#define	RCCK0_CCA_CNT			0xa60
+
+/* PageB(0xB00) */
+#define	RPDP_ANTA			0xb00
+#define	RPDP_ANTA_4			0xb04
+#define	RPDP_ANTA_8			0xb08
+#define	RPDP_ANTA_C			0xb0c
+#define	RPDP_ANTA_10			0xb10
+#define	RPDP_ANTA_14			0xb14
+#define	RPDP_ANTA_18			0xb18
+#define	RPDP_ANTA_1C			0xb1c
+#define	RPDP_ANTA_20			0xb20
+#define	RPDP_ANTA_24			0xb24
+
+#define	RCONFIG_PMPD_ANTA		0xb28
+#define	RCONFIG_RAM64x16		0xb2c
+
+#define	RBNDA				0xb30
+#define	RHSSIPAR			0xb34
+
+#define	RCONFIG_ANTA			0xb68
+#define	RCONFIG_ANTB			0xb6c
+
+#define	RPDP_ANTB			0xb70
+#define	RPDP_ANTB_4			0xb74
+#define	RPDP_ANTB_8			0xb78
+#define	RPDP_ANTB_C			0xb7c
+#define	RPDP_ANTB_10			0xb80
+#define	RPDP_ANTB_14			0xb84
+#define	RPDP_ANTB_18			0xb88
+#define	RPDP_ANTB_1C			0xb8c
+#define	RPDP_ANTB_20			0xb90
+#define	RPDP_ANTB_24			0xb94
+
+#define	RCONFIG_PMPD_ANTB		0xb98
+
+#define	RBNDB				0xba0
+
+#define	RAPK				0xbd8
+#define	RPM_RX0_ANTA			0xbdc
+#define	RPM_RX1_ANTA			0xbe0
+#define	RPM_RX2_ANTA			0xbe4
+#define	RPM_RX3_ANTA			0xbe8
+#define	RPM_RX0_ANTB			0xbec
+#define	RPM_RX1_ANTB			0xbf0
+#define	RPM_RX2_ANTB			0xbf4
+#define	RPM_RX3_ANTB			0xbf8
+
+/*RSSI Dump*/
+#define		RA_RSSI_DUMP		0xBF0
+#define		RB_RSSI_DUMP		0xBF1
+#define		RS1_RX_EVM_DUMP		0xBF4
+#define		RS2_RX_EVM_DUMP		0xBF5
+#define		RA_RX_SNR_DUMP		0xBF6
+#define		RB_RX_SNR_DUMP		0xBF7
+#define		RA_CFO_SHORT_DUMP	0xBF8
+#define		RB_CFO_SHORT_DUMP	0xBFA
+#define		RA_CFO_LONG_DUMP	0xBEC
+#define		RB_CFO_LONG_DUMP	0xBEE
+
+/*Page C*/
+#define	ROFDM0_LSTF			0xc00
+
+#define	ROFDM0_TRXPATHENABLE		0xc04
+#define	ROFDM0_TRMUXPAR			0xc08
+#define	ROFDM0_TRSWISOLATION		0xc0c
+
+#define	ROFDM0_XARXAFE			0xc10
+#define	ROFDM0_XARXIQIMBALANCE		0xc14
+#define	ROFDM0_XBRXAFE			0xc18
+#define	ROFDM0_XBRXIQIMBALANCE		0xc1c
+#define	ROFDM0_XCRXAFE			0xc20
+#define	ROFDM0_XCRXIQIMBANLANCE		0xc24
+#define	ROFDM0_XDRXAFE			0xc28
+#define	ROFDM0_XDRXIQIMBALANCE		0xc2c
+
+#define	ROFDM0_RXDETECTOR1		0xc30
+#define	ROFDM0_RXDETECTOR2		0xc34
+#define	ROFDM0_RXDETECTOR3		0xc38
+#define	ROFDM0_RXDETECTOR4		0xc3c
+
+#define	ROFDM0_RXDSP			0xc40
+#define	ROFDM0_CFOANDDAGC		0xc44
+#define	ROFDM0_CCADROPTHRESHOLD		0xc48
+#define	ROFDM0_ECCATHRESHOLD		0xc4c
+
+#define	ROFDM0_XAAGCCORE1		0xc50
+#define	ROFDM0_XAAGCCORE2		0xc54
+#define	ROFDM0_XBAGCCORE1		0xc58
+#define	ROFDM0_XBAGCCORE2		0xc5c
+#define	ROFDM0_XCAGCCORE1		0xc60
+#define	ROFDM0_XCAGCCORE2		0xc64
+#define	ROFDM0_XDAGCCORE1		0xc68
+#define	ROFDM0_XDAGCCORE2		0xc6c
+
+#define	ROFDM0_AGCPARAMETER1		0xc70
+#define	ROFDM0_AGCPARAMETER2		0xc74
+#define	ROFDM0_AGCRSSITABLE		0xc78
+#define	ROFDM0_HTSTFAGC			0xc7c
+
+#define	ROFDM0_XATXIQIMBALANCE		0xc80
+#define	ROFDM0_XATXAFE			0xc84
+#define	ROFDM0_XBTXIQIMBALANCE		0xc88
+#define	ROFDM0_XBTXAFE			0xc8c
+#define	ROFDM0_XCTXIQIMBALANCE		0xc90
+#define	ROFDM0_XCTXAFE			0xc94
+#define	ROFDM0_XDTXIQIMBALANCE		0xc98
+#define	ROFDM0_XDTXAFE			0xc9c
+
+#define ROFDM0_RXIQEXTANTA		0xca0
+#define	ROFDM0_TXCOEFF1			0xca4
+#define	ROFDM0_TXCOEFF2			0xca8
+#define	ROFDM0_TXCOEFF3			0xcac
+#define	ROFDM0_TXCOEFF4			0xcb0
+#define	ROFDM0_TXCOEFF5			0xcb4
+#define	ROFDM0_TXCOEFF6			0xcb8
+
+/*Path_A RFE cotrol */
+#define	RA_RFE_CTRL_8812		0xcb8
+/*Path_B RFE control*/
+#define	RB_RFE_CTRL_8812		0xeb8
+
+#define	ROFDM0_RXHPPARAMETER		0xce0
+#define	ROFDM0_TXPSEUDONOISEWGT		0xce4
+#define	ROFDM0_FRAMESYNC		0xcf0
+#define	ROFDM0_DFSREPORT		0xcf4
+
+#define	ROFDM1_LSTF			0xd00
+#define	ROFDM1_TRXPATHENABLE		0xd04
+
+#define	ROFDM1_CF0			0xd08
+#define	ROFDM1_CSI1			0xd10
+#define	ROFDM1_SBD			0xd14
+#define	ROFDM1_CSI2			0xd18
+#define	ROFDM1_CFOTRACKING		0xd2c
+#define	ROFDM1_TRXMESAURE1		0xd34
+#define	ROFDM1_INTFDET			0xd3c
+#define	ROFDM1_PSEUDONOISESTATEAB	0xd50
+#define	ROFDM1_PSEUDONOISESTATECD	0xd54
+#define	ROFDM1_RXPSEUDONOISEWGT		0xd58
+
+#define	ROFDM_PHYCOUNTER1		0xda0
+#define	ROFDM_PHYCOUNTER2		0xda4
+#define	ROFDM_PHYCOUNTER3		0xda8
+
+#define	ROFDM_SHORTCFOAB		0xdac
+#define	ROFDM_SHORTCFOCD		0xdb0
+#define	ROFDM_LONGCFOAB			0xdb4
+#define	ROFDM_LONGCFOCD			0xdb8
+#define	ROFDM_TAILCF0AB			0xdbc
+#define	ROFDM_TAILCF0CD			0xdc0
+#define	ROFDM_PWMEASURE1		0xdc4
+#define	ROFDM_PWMEASURE2		0xdc8
+#define	ROFDM_BWREPORT			0xdcc
+#define	ROFDM_AGCREPORT			0xdd0
+#define	ROFDM_RXSNR			0xdd4
+#define	ROFDM_RXEVMCSI			0xdd8
+#define	ROFDM_SIGREPORT			0xddc
+
+#define RTXAGC_A_CCK11_CCK1		0xc20
+#define RTXAGC_A_OFDM18_OFDM6		0xc24
+#define RTXAGC_A_OFDM54_OFDM24		0xc28
+#define RTXAGC_A_MCS03_MCS00		0xc2c
+#define RTXAGC_A_MCS07_MCS04		0xc30
+#define RTXAGC_A_MCS11_MCS08		0xc34
+#define RTXAGC_A_MCS15_MCS12		0xc38
+#define RTXAGC_A_NSS1INDEX3_NSS1INDEX0	0xc3c
+#define	RTXAGC_A_NSS1INDEX7_NSS1INDEX4	0xc40
+#define	RTXAGC_A_NSS2INDEX1_NSS1INDEX8	0xc44
+#define	RTXAGC_A_NSS2INDEX5_NSS2INDEX2	0xc48
+#define	RTXAGC_A_NSS2INDEX9_NSS2INDEX6	0xc4c
+#define	RTXAGC_B_CCK11_CCK1		0xe20
+#define	RTXAGC_B_OFDM18_OFDM6		0xe24
+#define	RTXAGC_B_OFDM54_OFDM24		0xe28
+#define	RTXAGC_B_MCS03_MCS00		0xe2c
+#define	RTXAGC_B_MCS07_MCS04		0xe30
+#define	RTXAGC_B_MCS11_MCS08		0xe34
+#define	RTXAGC_B_MCS15_MCS12		0xe38
+#define	RTXAGC_B_NSS1INDEX3_NSS1INDEX0	0xe3c
+#define	RTXAGC_B_NSS1INDEX7_NSS1INDEX4	0xe40
+#define	RTXAGC_B_NSS2INDEX1_NSS1INDEX8	0xe44
+#define	RTXAGC_B_NSS2INDEX5_NSS2INDEX2	0xe48
+#define	RTXAGC_B_NSS2INDEX9_NSS2INDEX6	0xe4c
+
+#define	RA_TXPWRTRAING			0xc54
+#define	RB_TXPWRTRAING			0xe54
+
+#define	RFPGA0_IQK			0xe28
+#define	RTX_IQK_TONE_A			0xe30
+#define	RRX_IQK_TONE_A			0xe34
+#define	RTX_IQK_PI_A			0xe38
+#define	RRX_IQK_PI_A			0xe3c
+
+#define	RTX_IQK				0xe40
+#define	RRX_IQK				0xe44
+#define	RIQK_AGC_PTS			0xe48
+#define	RIQK_AGC_RSP			0xe4c
+#define	RTX_IQK_TONE_B			0xe50
+#define	RRX_IQK_TONE_B			0xe54
+#define	RTX_IQK_PI_B			0xe58
+#define	RRX_IQK_PI_B			0xe5c
+#define	RIQK_AGC_CONT			0xe60
+
+#define	RBLUE_TOOTH			0xe6c
+#define	RRX_WAIT_CCA			0xe70
+#define	RTX_CCK_RFON			0xe74
+#define	RTX_CCK_BBON			0xe78
+#define	RTX_OFDM_RFON			0xe7c
+#define	RTX_OFDM_BBON			0xe80
+#define	RTX_TO_RX			0xe84
+#define	RTX_TO_TX			0xe88
+#define	RRX_CCK				0xe8c
+
+#define	RTX_POWER_BEFORE_IQK_A		0xe94
+#define	RTX_POWER_AFTER_IQK_A		0xe9c
+
+#define	RRX_POWER_BEFORE_IQK_A		0xea0
+#define	RRX_POWER_BEFORE_IQK_A_2	0xea4
+#define	RRX_POWER_AFTER_IQK_A		0xea8
+#define	RRX_POWER_AFTER_IQK_A_2		0xeac
+
+#define	RTX_POWER_BEFORE_IQK_B		0xeb4
+#define	RTX_POWER_AFTER_IQK_B		0xebc
+
+#define	RRX_POER_BEFORE_IQK_B		0xec0
+#define	RRX_POER_BEFORE_IQK_B_2		0xec4
+#define	RRX_POWER_AFTER_IQK_B		0xec8
+#define	RRX_POWER_AFTER_IQK_B_2		0xecc
+
+#define	RRX_OFDM			0xed0
+#define	RRX_WAIT_RIFS			0xed4
+#define	RRX_TO_RX			0xed8
+#define	RSTANDBY			0xedc
+#define	RSLEEP				0xee0
+#define	RPMPD_ANAEN			0xeec
+
+#define	RZEBRA1_HSSIENABLE		0x0
+#define	RZEBRA1_TRXENABLE1		0x1
+#define	RZEBRA1_TRXENABLE2		0x2
+#define	RZEBRA1_AGC			0x4
+#define	RZEBRA1_CHARGEPUMP		0x5
+#define	RZEBRA1_CHANNEL			0x7
+
+#define	RZEBRA1_TXGAIN			0x8
+#define	RZEBRA1_TXLPF			0x9
+#define	RZEBRA1_RXLPF			0xb
+#define	RZEBRA1_RXHPFCORNER		0xc
+
+#define	RGLOBALCTRL			0
+#define	RRTL8256_TXLPF			19
+#define	RRTL8256_RXLPF			11
+#define	RRTL8258_TXLPF			0x11
+#define	RRTL8258_RXLPF			0x13
+#define	RRTL8258_RSSILPF		0xa
+
+#define	RF_AC				0x00
+
+#define	RF_IQADJ_G1			0x01
+#define	RF_IQADJ_G2			0x02
+#define	RF_POW_TRSW			0x05
+
+#define	RF_GAIN_RX			0x06
+#define	RF_GAIN_TX			0x07
+
+#define	RF_TXM_IDAC			0x08
+#define	RF_BS_IQGEN			0x0F
+
+#define	RF_MODE1			0x10
+#define	RF_MODE2			0x11
+
+#define	RF_RX_AGC_HP			0x12
+#define	RF_TX_AGC			0x13
+#define	RF_BIAS				0x14
+#define	RF_IPA				0x15
+#define	RF_POW_ABILITY			0x17
+#define	RF_MODE_AG			0x18
+#define	RRFCHANNEL			0x18
+#define	RF_CHNLBW			0x18
+#define	RF_TOP				0x19
+
+#define	RF_RX_G1			0x1A
+#define	RF_RX_G2			0x1B
+
+#define	RF_RX_BB2			0x1C
+#define	RF_RX_BB1			0x1D
+
+#define	RF_RCK1				0x1E
+#define	RF_RCK2				0x1F
+
+#define	RF_TX_G1			0x20
+#define	RF_TX_G2			0x21
+#define	RF_TX_G3			0x22
+
+#define	RF_TX_BB1			0x23
+#define	RF_T_METER			0x24
+#define	RF_T_METER_88E			0x42
+#define  RF_T_METER_8812A		0x42
+
+#define	RF_SYN_G1			0x25
+#define	RF_SYN_G2			0x26
+#define	RF_SYN_G3			0x27
+#define	RF_SYN_G4			0x28
+#define	RF_SYN_G5			0x29
+#define	RF_SYN_G6			0x2A
+#define	RF_SYN_G7			0x2B
+#define	RF_SYN_G8			0x2C
+
+#define	RF_RCK_OS			0x30
+#define	RF_TXPA_G1			0x31
+#define	RF_TXPA_G2			0x32
+#define	RF_TXPA_G3			0x33
+
+#define	RF_TX_BIAS_A			0x35
+#define	RF_TX_BIAS_D			0x36
+#define	RF_LOBF_9			0x38
+#define	RF_RXRF_A3			0x3C
+#define	RF_TRSW				0x3F
+
+#define	RF_TXRF_A2			0x41
+#define	RF_TXPA_G4			0x46
+#define	RF_TXPA_A4			0x4B
+
+#define RF_APK				0x63
+
+#define	RF_WE_LUT			0xEF
+
+#define	BBBRESETB			0x100
+#define	BGLOBALRESETB			0x200
+#define	BOFDMTXSTART			0x4
+#define	BCCKTXSTART			0x8
+#define	BCRC32DEBUG			0x100
+#define	BPMACLOOPBACK			0x10
+#define	BTXLSIG				0xffffff
+#define	BOFDMTXRATE			0xf
+#define	BOFDMTXRESERVED			0x10
+#define	BOFDMTXLENGTH			0x1ffe0
+#define	BOFDMTXPARITY			0x20000
+#define	BTXHTSIG1			0xffffff
+#define	BTXHTMCSRATE			0x7f
+#define	BTXHTBW				0x80
+#define	BTXHTLENGTH			0xffff00
+#define	BTXHTSIG2			0xffffff
+#define	BTXHTSMOOTHING			0x1
+#define	BTXHTSOUNDING			0x2
+#define	BTXHTRESERVED			0x4
+#define	BTXHTAGGREATION			0x8
+#define	BTXHTSTBC			0x30
+#define	BTXHTADVANCECODING		0x40
+#define	BTXHTSHORTGI			0x80
+#define	BTXHTNUMBERHT_LTF		0x300
+#define	BTXHTCRC8			0x3fc00
+#define	BCOUNTERRESET			0x10000
+#define	BNUMOFOFDMTX			0xffff
+#define	BNUMOFCCKTX			0xffff0000
+#define	BTXIDLEINTERVAL			0xffff
+#define	BOFDMSERVICE			0xffff0000
+#define	BTXMACHEADER			0xffffffff
+#define	BTXDATAINIT			0xff
+#define	BTXHTMODE			0x100
+#define	BTXDATATYPE			0x30000
+#define	BTXRANDOMSEED			0xffffffff
+#define	BCCKTXPREAMBLE			0x1
+#define	BCCKTXSFD			0xffff0000
+#define	BCCKTXSIG			0xff
+#define	BCCKTXSERVICE			0xff00
+#define	BCCKLENGTHEXT			0x8000
+#define	BCCKTXLENGHT			0xffff0000
+#define	BCCKTXCRC16			0xffff
+#define	BCCKTXSTATUS			0x1
+#define	BOFDMTXSTATUS			0x2
+#define IS_BB_REG_OFFSET_92S(__offset)	\
+	((__offset >= 0x800) && (__offset <= 0xfff))
+
+#define	BRFMOD				0x1
+#define	BJAPANMODE			0x2
+#define	BCCKTXSC			0x30
+/* Block & Path enable*/
+#define ROFDMCCKEN			0x808
+#define	BCCKEN				0x10000000
+#define	BOFDMEN				0x20000000
+/* Rx antenna*/
+#define	RRXPATH				0x808
+#define	BRXPATH				0xff
+/* Tx antenna*/
+#define	RTXPATH				0x80c
+#define	BTXPATH				0x0fffffff
+/* for cck rx path selection*/
+#define	RCCK_RX				0xa04
+#define	BCCK_RX				0x0c000000
+/* Use LSIG for VHT length*/
+#define	RVHTLEN_USE_LSIG		0x8c3
+
+#define	BOFDMRXADCPHASE			0x10000
+#define	BOFDMTXDACPHASE			0x40000
+#define	BXATXAGC			0x3f
+
+#define	BXBTXAGC			0xf00
+#define	BXCTXAGC			0xf000
+#define	BXDTXAGC			0xf0000
+
+#define	BPASTART			0xf0000000
+#define	BTRSTART			0x00f00000
+#define	BRFSTART			0x0000f000
+#define	BBBSTART			0x000000f0
+#define	BBBCCKSTART			0x0000000f
+#define	BPAEND				0xf
+#define	BTREND				0x0f000000
+#define	BRFEND				0x000f0000
+#define	BCCAMASK			0x000000f0
+#define	BR2RCCAMASK			0x00000f00
+#define	BHSSI_R2TDELAY			0xf8000000
+#define	BHSSI_T2RDELAY			0xf80000
+#define	BCONTXHSSI			0x400
+#define	BIGFROMCCK			0x200
+#define	BAGCADDRESS			0x3f
+#define	BRXHPTX				0x7000
+#define	BRXHP2RX			0x38000
+#define	BRXHPCCKINI			0xc0000
+#define	BAGCTXCODE			0xc00000
+#define	BAGCRXCODE			0x300000
+
+#define	B3WIREDATALENGTH		0x800
+#define	B3WIREADDREAALENGTH		0x400
+
+#define	B3WIRERFPOWERDOWN		0x1
+#define	B5GPAPEPOLARITY			0x40000000
+#define	B2GPAPEPOLARITY			0x80000000
+#define	BRFSW_TXDEFAULTANT		0x3
+#define	BRFSW_TXOPTIONANT		0x30
+#define	BRFSW_RXDEFAULTANT		0x300
+#define	BRFSW_RXOPTIONANT		0x3000
+#define	BRFSI_3WIREDATA			0x1
+#define	BRFSI_3WIRECLOCK		0x2
+#define	BRFSI_3WIRELOAD			0x4
+#define	BRFSI_3WIRERW			0x8
+#define	BRFSI_3WIRE			0xf
+
+#define	BRFSI_RFENV			0x10
+
+#define	BRFSI_TRSW			0x20
+#define	BRFSI_TRSWB			0x40
+#define	BRFSI_ANTSW			0x100
+#define	BRFSI_ANTSWB			0x200
+#define	BRFSI_PAPE			0x400
+#define	BRFSI_PAPE5G			0x800
+#define	BBANDSELECT			0x1
+#define	BHTSIG2_GI			0x80
+#define	BHTSIG2_SMOOTHING		0x01
+#define	BHTSIG2_SOUNDING		0x02
+#define	BHTSIG2_AGGREATON		0x08
+#define	BHTSIG2_STBC			0x30
+#define	BHTSIG2_ADVCODING		0x40
+#define	BHTSIG2_NUMOFHTLTF		0x300
+#define	BHTSIG2_CRC8			0x3fc
+#define	BHTSIG1_MCS			0x7f
+#define	BHTSIG1_BANDWIDTH		0x80
+#define	BHTSIG1_HTLENGTH		0xffff
+#define	BLSIG_RATE			0xf
+#define	BLSIG_RESERVED			0x10
+#define	BLSIG_LENGTH			0x1fffe
+#define	BLSIG_PARITY			0x20
+#define	BCCKRXPHASE			0x4
+
+#define	BLSSIREADADDRESS		0x7f800000
+#define	BLSSIREADEDGE			0x80000000
+
+#define	BLSSIREADBACKDATA		0xfffff
+
+#define	BLSSIREADOKFLAG			0x1000
+#define	BCCKSAMPLERATE			0x8
+#define	BREGULATOR0STANDBY		0x1
+#define	BREGULATORPLLSTANDBY		0x2
+#define	BREGULATOR1STANDBY		0x4
+#define	BPLLPOWERUP			0x8
+#define	BDPLLPOWERUP			0x10
+#define	BDA10POWERUP			0x20
+#define	BAD7POWERUP			0x200
+#define	BDA6POWERUP			0x2000
+#define	BXTALPOWERUP			0x4000
+#define	B40MDCLKPOWERUP			0x8000
+#define	BDA6DEBUGMODE			0x20000
+#define	BDA6SWING			0x380000
+
+#define	BADCLKPHASE			0x4000000
+#define	B80MCLKDELAY			0x18000000
+#define	BAFEWATCHDOGENABLE		0x20000000
+
+#define	BXTALCAP01			0xc0000000
+#define	BXTALCAP23			0x3
+#define	BXTALCAP92X			0x0f000000
+#define BXTALCAP			0x0f000000
+
+#define	BINTDIFCLKENABLE		0x400
+#define	BEXTSIGCLKENABLE		0x800
+#define	BBANDGAP_MBIAS_POWERUP		0x10000
+#define	BAD11SH_GAIN			0xc0000
+#define	BAD11NPUT_RANGE			0x700000
+#define	BAD110P_CURRENT			0x3800000
+#define	BLPATH_LOOPBACK			0x4000000
+#define	BQPATH_LOOPBACK			0x8000000
+#define	BAFE_LOOPBACK			0x10000000
+#define	BDA10_SWING			0x7e0
+#define	BDA10_REVERSE			0x800
+#define	BDA_CLK_SOURCE			0x1000
+#define	BDA7INPUT_RANGE			0x6000
+#define	BDA7_GAIN			0x38000
+#define	BDA7OUTPUT_CM_MODE		0x40000
+#define	BDA7INPUT_CM_MODE		0x380000
+#define	BDA7CURRENT			0xc00000
+#define	BREGULATOR_ADJUST		0x7000000
+#define	BAD11POWERUP_ATTX		0x1
+#define	BDA10PS_ATTX			0x10
+#define	BAD11POWERUP_ATRX		0x100
+#define	BDA10PS_ATRX			0x1000
+#define	BCCKRX_AGC_FORMAT		0x200
+#define	BPSDFFT_SAMPLE_POINT		0xc000
+#define	BPSD_AVERAGE_NUM		0x3000
+#define	BIQPATH_CONTROL			0xc00
+#define	BPSD_FREQ			0x3ff
+#define	BPSD_ANTENNA_PATH		0x30
+#define	BPSD_IQ_SWITCH			0x40
+#define	BPSD_RX_TRIGGER			0x400000
+#define	BPSD_TX_TRIGGER			0x80000000
+#define	BPSD_SINE_TONE_SCALE		0x7f000000
+#define	BPSD_REPORT			0xffff
+
+#define	BOFDM_TXSC			0x30000000
+#define	BCCK_TXON			0x1
+#define	BOFDM_TXON			0x2
+#define	BDEBUG_PAGE			0xfff
+#define	BDEBUG_ITEM			0xff
+#define	BANTL				0x10
+#define	BANT_NONHT			0x100
+#define	BANT_HT1			0x1000
+#define	BANT_HT2			0x10000
+#define	BANT_HT1S1			0x100000
+#define	BANT_NONHTS1			0x1000000
+
+#define	BCCK_BBMODE			0x3
+#define	BCCK_TXPOWERSAVING		0x80
+#define	BCCK_RXPOWERSAVING		0x40
+
+#define	BCCK_SIDEBAND			0x10
+
+#define	BCCK_SCRAMBLE			0x8
+#define	BCCK_ANTDIVERSITY		0x8000
+#define	BCCK_CARRIER_RECOVERY		0x4000
+#define	BCCK_TXRATE			0x3000
+#define	BCCK_DCCANCEL			0x0800
+#define	BCCK_ISICANCEL			0x0400
+#define	BCCK_MATCH_FILTER		0x0200
+#define	BCCK_EQUALIZER			0x0100
+#define	BCCK_PREAMBLE_DETECT		0x800000
+#define	BCCK_FAST_FALSECCA		0x400000
+#define	BCCK_CH_ESTSTART		0x300000
+#define	BCCK_CCA_COUNT			0x080000
+#define	BCCK_CS_LIM			0x070000
+#define	BCCK_BIST_MODE			0x80000000
+#define	BCCK_CCAMASK			0x40000000
+#define	BCCK_TX_DAC_PHASE		0x4
+#define	BCCK_RX_ADC_PHASE		0x20000000
+#define	BCCKR_CP_MODE			0x0100
+#define	BCCK_TXDC_OFFSET		0xf0
+#define	BCCK_RXDC_OFFSET		0xf
+#define	BCCK_CCA_MODE			0xc000
+#define	BCCK_FALSECS_LIM		0x3f00
+#define	BCCK_CS_RATIO			0xc00000
+#define	BCCK_CORGBIT_SEL		0x300000
+#define	BCCK_PD_LIM			0x0f0000
+#define	BCCK_NEWCCA			0x80000000
+#define	BCCK_RXHP_OF_IG			0x8000
+#define	BCCK_RXIG			0x7f00
+#define	BCCK_LNA_POLARITY		0x800000
+#define	BCCK_RX1ST_BAIN			0x7f0000
+#define	BCCK_RF_EXTEND			0x20000000
+#define	BCCK_RXAGC_SATLEVEL		0x1f000000
+#define	BCCK_RXAGC_SATCOUNT		0xe0
+#define	BCCKRXRFSETTLE			0x1f
+#define	BCCK_FIXED_RXAGC		0x8000
+#define	BCCK_ANTENNA_POLARITY		0x2000
+#define	BCCK_TXFILTER_TYPE		0x0c00
+#define	BCCK_RXAGC_REPORTTYPE		0x0300
+#define	BCCK_RXDAGC_EN			0x80000000
+#define	BCCK_RXDAGC_PERIOD		0x20000000
+#define	BCCK_RXDAGC_SATLEVEL		0x1f000000
+#define	BCCK_TIMING_RECOVERY		0x800000
+#define	BCCK_TXC0			0x3f0000
+#define	BCCK_TXC1			0x3f000000
+#define	BCCK_TXC2			0x3f
+#define	BCCK_TXC3			0x3f00
+#define	BCCK_TXC4			0x3f0000
+#define	BCCK_TXC5			0x3f000000
+#define	BCCK_TXC6			0x3f
+#define	BCCK_TXC7			0x3f00
+#define	BCCK_DEBUGPORT			0xff0000
+#define	BCCK_DAC_DEBUG			0x0f000000
+#define	BCCK_FALSEALARM_ENABLE		0x8000
+#define	BCCK_FALSEALARM_READ		0x4000
+#define	BCCK_TRSSI			0x7f
+#define	BCCK_RXAGC_REPORT		0xfe
+#define	BCCK_RXREPORT_ANTSEL		0x80000000
+#define	BCCK_RXREPORT_MFOFF		0x40000000
+#define	BCCK_RXREPORT_SQLOSS		0x20000000
+#define	BCCK_RXREPORT_PKTLOSS		0x10000000
+#define	BCCK_RXREPORT_LOCKEDBIT		0x08000000
+#define	BCCK_RXREPORT_RATEERROR		0x04000000
+#define	BCCK_RXREPORT_RXRATE		0x03000000
+#define	BCCK_RXFA_COUNTER_LOWER		0xff
+#define	BCCK_RXFA_COUNTER_UPPER		0xff000000
+#define	BCCK_RXHPAGC_START		0xe000
+#define	BCCK_RXHPAGC_FINAL		0x1c00
+#define	BCCK_RXFALSEALARM_ENABLE	0x8000
+#define	BCCK_FACOUNTER_FREEZE		0x4000
+#define	BCCK_TXPATH_SEL			0x10000000
+#define	BCCK_DEFAULT_RXPATH		0xc000000
+#define	BCCK_OPTION_RXPATH		0x3000000
+
+#define	BNUM_OFSTF			0x3
+#define	BSHIFT_L			0xc0
+#define	BGI_TH				0xc
+#define	BRXPATH_A			0x1
+#define	BRXPATH_B			0x2
+#define	BRXPATH_C			0x4
+#define	BRXPATH_D			0x8
+#define	BTXPATH_A			0x1
+#define	BTXPATH_B			0x2
+#define	BTXPATH_C			0x4
+#define	BTXPATH_D			0x8
+#define	BTRSSI_FREQ			0x200
+#define	BADC_BACKOFF			0x3000
+#define	BDFIR_BACKOFF			0xc000
+#define	BTRSSI_LATCH_PHASE		0x10000
+#define	BRX_LDC_OFFSET			0xff
+#define	BRX_QDC_OFFSET			0xff00
+#define	BRX_DFIR_MODE			0x1800000
+#define	BRX_DCNF_TYPE			0xe000000
+#define	BRXIQIMB_A			0x3ff
+#define	BRXIQIMB_B			0xfc00
+#define	BRXIQIMB_C			0x3f0000
+#define	BRXIQIMB_D			0xffc00000
+#define	BDC_DC_NOTCH			0x60000
+#define	BRXNB_NOTCH			0x1f000000
+#define	BPD_TH				0xf
+#define	BPD_TH_OPT2			0xc000
+#define	BPWED_TH			0x700
+#define	BIFMF_WIN_L			0x800
+#define	BPD_OPTION			0x1000
+#define	BMF_WIN_L			0xe000
+#define	BBW_SEARCH_L			0x30000
+#define	BWIN_ENH_L			0xc0000
+#define	BBW_TH				0x700000
+#define	BED_TH2				0x3800000
+#define	BBW_OPTION			0x4000000
+#define	BRADIO_TH			0x18000000
+#define	BWINDOW_L			0xe0000000
+#define	BSBD_OPTION			0x1
+#define	BFRAME_TH			0x1c
+#define	BFS_OPTION			0x60
+#define	BDC_SLOPE_CHECK			0x80
+#define	BFGUARD_COUNTER_DC_L		0xe00
+#define	BFRAME_WEIGHT_SHORT		0x7000
+#define	BSUB_TUNE			0xe00000
+#define	BFRAME_DC_LENGTH		0xe000000
+#define	BSBD_START_OFFSET		0x30000000
+#define	BFRAME_TH_2			0x7
+#define	BFRAME_GI2_TH			0x38
+#define	BGI2_SYNC_EN			0x40
+#define	BSARCH_SHORT_EARLY		0x300
+#define	BSARCH_SHORT_LATE		0xc00
+#define	BSARCH_GI2_LATE			0x70000
+#define	BCFOANTSUM			0x1
+#define	BCFOACC				0x2
+#define	BCFOSTARTOFFSET			0xc
+#define	BCFOLOOPBACK			0x70
+#define	BCFOSUMWEIGHT			0x80
+#define	BDAGCENABLE			0x10000
+#define	BTXIQIMB_A			0x3ff
+#define	BTXIQIMB_b			0xfc00
+#define	BTXIQIMB_C			0x3f0000
+#define	BTXIQIMB_D			0xffc00000
+#define	BTXIDCOFFSET			0xff
+#define	BTXIQDCOFFSET			0xff00
+#define	BTXDFIRMODE			0x10000
+#define	BTXPESUDO_NOISEON		0x4000000
+#define	BTXPESUDO_NOISE_A		0xff
+#define	BTXPESUDO_NOISE_B		0xff00
+#define	BTXPESUDO_NOISE_C		0xff0000
+#define	BTXPESUDO_NOISE_D		0xff000000
+#define	BCCA_DROPOPTION			0x20000
+#define	BCCA_DROPTHRES			0xfff00000
+#define	BEDCCA_H			0xf
+#define	BEDCCA_L			0xf0
+#define	BLAMBDA_ED			0x300
+#define	BRX_INITIALGAIN			0x7f
+#define	BRX_ANTDIV_EN			0x80
+#define	BRX_AGC_ADDRESS_FOR_LNA		0x7f00
+#define	BRX_HIGHPOWER_FLOW		0x8000
+#define	BRX_AGC_FREEZE_THRES		0xc0000
+#define	BRX_FREEZESTEP_AGC1		0x300000
+#define	BRX_FREEZESTEP_AGC2		0xc00000
+#define	BRX_FREEZESTEP_AGC3		0x3000000
+#define	BRX_FREEZESTEP_AGC0		0xc000000
+#define	BRXRSSI_CMP_EN			0x10000000
+#define	BRXQUICK_AGCEN			0x20000000
+#define	BRXAGC_FREEZE_THRES_MODE	0x40000000
+#define	BRX_OVERFLOW_CHECKTYPE		0x80000000
+#define	BRX_AGCSHIFT			0x7f
+#define	BTRSW_TRI_ONLY			0x80
+#define	BPOWER_THRES			0x300
+#define	BRXAGC_EN			0x1
+#define	BRXAGC_TOGETHER_EN		0x2
+#define	BRXAGC_MIN			0x4
+#define	BRXHP_INI			0x7
+#define	BRXHP_TRLNA			0x70
+#define	BRXHP_RSSI			0x700
+#define	BRXHP_BBP1			0x7000
+#define	BRXHP_BBP2			0x70000
+#define	BRXHP_BBP3			0x700000
+#define	BRSSI_H				0x7f0000
+#define	BRSSI_GEN			0x7f000000
+#define	BRXSETTLE_TRSW			0x7
+#define	BRXSETTLE_LNA			0x38
+#define	BRXSETTLE_RSSI			0x1c0
+#define	BRXSETTLE_BBP			0xe00
+#define	BRXSETTLE_RXHP			0x7000
+#define	BRXSETTLE_ANTSW_RSSI		0x38000
+#define	BRXSETTLE_ANTSW			0xc0000
+#define	BRXPROCESS_TIME_DAGC		0x300000
+#define	BRXSETTLE_HSSI			0x400000
+#define	BRXPROCESS_TIME_BBPPW		0x800000
+#define	BRXANTENNA_POWER_SHIFT		0x3000000
+#define	BRSSI_TABLE_SELECT		0xc000000
+#define	BRXHP_FINAL			0x7000000
+#define	BRXHPSETTLE_BBP			0x7
+#define	BRXHTSETTLE_HSSI		0x8
+#define	BRXHTSETTLE_RXHP		0x70
+#define	BRXHTSETTLE_BBPPW		0x80
+#define	BRXHTSETTLE_IDLE		0x300
+#define	BRXHTSETTLE_RESERVED		0x1c00
+#define	BRXHT_RXHP_EN			0x8000
+#define	BRXAGC_FREEZE_THRES		0x30000
+#define	BRXAGC_TOGETHEREN		0x40000
+#define	BRXHTAGC_MIN			0x80000
+#define	BRXHTAGC_EN			0x100000
+#define	BRXHTDAGC_EN			0x200000
+#define	BRXHT_RXHP_BBP			0x1c00000
+#define	BRXHT_RXHP_FINAL		0xe0000000
+#define	BRXPW_RADIO_TH			0x3
+#define	BRXPW_RADIO_EN			0x4
+#define	BRXMF_HOLD			0x3800
+#define	BRXPD_DELAY_TH1			0x38
+#define	BRXPD_DELAY_TH2			0x1c0
+#define	BRXPD_DC_COUNT_MAX		0x600
+#define	BRXPD_DELAY_TH			0x8000
+#define	BRXPROCESS_DELAY		0xf0000
+#define	BRXSEARCHRANGE_GI2_EARLY	0x700000
+#define	BRXFRAME_FUARD_COUNTER_L	0x3800000
+#define	BRXSGI_GUARD_L			0xc000000
+#define	BRXSGI_SEARCH_L			0x30000000
+#define	BRXSGI_TH			0xc0000000
+#define	BDFSCNT0			0xff
+#define	BDFSCNT1			0xff00
+#define	BDFSFLAG			0xf0000
+#define	BMF_WEIGHT_SUM			0x300000
+#define	BMINIDX_TH			0x7f000000
+#define	BDAFORMAT			0x40000
+#define	BTXCH_EMU_ENABLE		0x01000000
+#define	BTRSW_ISOLATION_A		0x7f
+#define	BTRSW_ISOLATION_B		0x7f00
+#define	BTRSW_ISOLATION_C		0x7f0000
+#define	BTRSW_ISOLATION_D		0x7f000000
+#define	BEXT_LNA_GAIN			0x7c00
+
+#define	BSTBC_EN			0x4
+#define	BANTENNA_MAPPING		0x10
+#define	BNSS				0x20
+#define	BCFO_ANTSUM_ID			0x200
+#define	BPHY_COUNTER_RESET		0x8000000
+#define	BCFO_REPORT_GET			0x4000000
+#define	BOFDM_CONTINUE_TX		0x10000000
+#define	BOFDM_SINGLE_CARRIER		0x20000000
+#define	BOFDM_SINGLE_TONE		0x40000000
+#define	BHT_DETECT			0x100
+#define	BCFOEN				0x10000
+#define	BCFOVALUE			0xfff00000
+#define	BSIGTONE_RE			0x3f
+#define	BSIGTONE_IM			0x7f00
+#define	BCOUNTER_CCA			0xffff
+#define	BCOUNTER_PARITYFAIL		0xffff0000
+#define	BCOUNTER_RATEILLEGAL		0xffff
+#define	BCOUNTER_CRC8FAIL		0xffff0000
+#define	BCOUNTER_MCSNOSUPPORT		0xffff
+#define	BCOUNTER_FASTSYNC		0xffff
+#define	BSHORTCFO			0xfff
+#define	BSHORTCFOT_LENGTH		12
+#define	BSHORTCFOF_LENGTH		11
+#define	BLONGCFO			0x7ff
+#define	BLONGCFOT_LENGTH		11
+#define	BLONGCFOF_LENGTH		11
+#define	BTAILCFO			0x1fff
+#define	BTAILCFOT_LENGTH		13
+#define	BTAILCFOF_LENGTH		12
+#define	BNOISE_EN_PWDB			0xffff
+#define	BCC_POWER_DB			0xffff0000
+#define	BMOISE_PWDB			0xffff
+#define	BPOWERMEAST_LENGTH		10
+#define	BPOWERMEASF_LENGTH		3
+#define	BRX_HT_BW			0x1
+#define	BRXSC				0x6
+#define	BRX_HT				0x8
+#define	BNB_INTF_DET_ON			0x1
+#define	BINTF_WIN_LEN_CFG		0x30
+#define	BNB_INTF_TH_CFG			0x1c0
+#define	BRFGAIN				0x3f
+#define	BTABLESEL			0x40
+#define	BTRSW				0x80
+#define	BRXSNR_A			0xff
+#define	BRXSNR_B			0xff00
+#define	BRXSNR_C			0xff0000
+#define	BRXSNR_D			0xff000000
+#define	BSNR_EVMT_LENGTH		8
+#define	BSNR_EVMF_LENGTH		1
+#define	BCSI1ST				0xff
+#define	BCSI2ND				0xff00
+#define	BRXEVM1ST			0xff0000
+#define	BRXEVM2ND			0xff000000
+#define	BSIGEVM				0xff
+#define	BPWDB				0xff00
+#define	BSGIEN				0x10000
+
+#define	BSFACTOR_QMA1			0xf
+#define	BSFACTOR_QMA2			0xf0
+#define	BSFACTOR_QMA3			0xf00
+#define	BSFACTOR_QMA4			0xf000
+#define	BSFACTOR_QMA5			0xf0000
+#define	BSFACTOR_QMA6			0xf0000
+#define	BSFACTOR_QMA7			0xf00000
+#define	BSFACTOR_QMA8			0xf000000
+#define	BSFACTOR_QMA9			0xf0000000
+#define	BCSI_SCHEME			0x100000
+
+#define	BNOISE_LVL_TOP_SET		0x3
+#define	BCHSMOOTH			0x4
+#define	BCHSMOOTH_CFG1			0x38
+#define	BCHSMOOTH_CFG2			0x1c0
+#define	BCHSMOOTH_CFG3			0xe00
+#define	BCHSMOOTH_CFG4			0x7000
+#define	BMRCMODE			0x800000
+#define	BTHEVMCFG			0x7000000
+
+#define	BLOOP_FIT_TYPE			0x1
+#define	BUPD_CFO			0x40
+#define	BUPD_CFO_OFFDATA		0x80
+#define	BADV_UPD_CFO			0x100
+#define	BADV_TIME_CTRL			0x800
+#define	BUPD_CLKO			0x1000
+#define	BFC				0x6000
+#define	BTRACKING_MODE			0x8000
+#define	BPHCMP_ENABLE			0x10000
+#define	BUPD_CLKO_LTF			0x20000
+#define	BCOM_CH_CFO			0x40000
+#define	BCSI_ESTI_MODE			0x80000
+#define	BADV_UPD_EQZ			0x100000
+#define	BUCHCFG				0x7000000
+#define	BUPDEQZ				0x8000000
+
+#define	BRX_PESUDO_NOISE_ON		0x20000000
+#define	BRX_PESUDO_NOISE_A		0xff
+#define	BRX_PESUDO_NOISE_B		0xff00
+#define	BRX_PESUDO_NOISE_C		0xff0000
+#define	BRX_PESUDO_NOISE_D		0xff000000
+#define	BRX_PESUDO_NOISESTATE_A		0xffff
+#define	BRX_PESUDO_NOISESTATE_B		0xffff0000
+#define	BRX_PESUDO_NOISESTATE_C		0xffff
+#define	BRX_PESUDO_NOISESTATE_D		0xffff0000
+
+#define	BZEBRA1_HSSIENABLE		0x8
+#define	BZEBRA1_TRXCONTROL		0xc00
+#define	BZEBRA1_TRXGAINSETTING		0x07f
+#define	BZEBRA1_RXCOUNTER		0xc00
+#define	BZEBRA1_TXCHANGEPUMP		0x38
+#define	BZEBRA1_RXCHANGEPUMP		0x7
+#define	BZEBRA1_CHANNEL_NUM		0xf80
+#define	BZEBRA1_TXLPFBW			0x400
+#define	BZEBRA1_RXLPFBW			0x600
+
+#define	BRTL8256REG_MODE_CTRL1		0x100
+#define	BRTL8256REG_MODE_CTRL0		0x40
+#define	BRTL8256REG_TXLPFBW		0x18
+#define	BRTL8256REG_RXLPFBW		0x600
+
+#define	BRTL8258_TXLPFBW		0xc
+#define	BRTL8258_RXLPFBW		0xc00
+#define	BRTL8258_RSSILPFBW		0xc0
+
+#define	BBYTE0				0x1
+#define	BBYTE1				0x2
+#define	BBYTE2				0x4
+#define	BBYTE3				0x8
+#define	BWORD0				0x3
+#define	BWORD1				0xc
+#define	BWORD				0xf
+
+#define	MASKBYTE0			0xff
+#define	MASKBYTE1			0xff00
+#define	MASKBYTE2			0xff0000
+#define	MASKBYTE3			0xff000000
+#define	MASKHWORD			0xffff0000
+#define	MASKLWORD			0x0000ffff
+#define	MASKDWORD			0xffffffff
+#define	MASK12BITS			0xfff
+#define	MASKH4BITS			0xf0000000
+#define MASKOFDM_D			0xffc00000
+#define	MASKCCK				0x3f3f3f3f
+
+#define	MASK4BITS			0x0f
+#define	MASK20BITS			0xfffff
+#define RFREG_OFFSET_MASK		0xfffff
+
+#define	BENABLE				0x1
+#define	BDISABLE			0x0
+
+#define	LEFT_ANTENNA			0x0
+#define	RIGHT_ANTENNA			0x1
+
+#define	TCHECK_TXSTATUS			500
+#define	TUPDATE_RXCOUNTER		100
+
+#define	REG_UN_used_register		0x01bf
+
+/* Path_A RFE cotrol pinmux*/
+#define		RA_RFE_PINMUX		0xcb0
+/* Path_B RFE control pinmux*/
+#define		RB_RFE_PINMUX		0xeb0
+
+#define		RA_RFE_INV		0xcb4
+#define		RB_RFE_INV		0xeb4
+
+/* RXIQC */
+/*RxIQ imblance matrix coeff. A & B*/
+#define RA_RXIQC_AB			0xc10
+/*RxIQ imblance matrix coeff. C & D*/
+#define	RA_RXIQC_CD			0xc14
+/* Pah_A TX scaling factor*/
+#define	RA_TXSCALE			0xc1c
+/* Path_B TX scaling factor*/
+#define	RB_TXSCALE			0xe1c
+/*RxIQ imblance matrix coeff. A & B*/
+#define	RB_RXIQC_AB			0xe10
+/*RxIQ imblance matrix coeff. C & D*/
+#define	RB_RXIQC_CD			0xe14
+/*bit mask for IQC matrix element A & C*/
+#define	RXIQC_AC			0x02ff
+ /*bit mask for IQC matrix element A & C*/
+#define	RXIQC_BD			0x02ff0000
+
+/* 2 EFUSE_TEST (For RTL8723 partially) */
+#define EFUSE_SEL(x)			(((x) & 0x3) << 8)
+#define EFUSE_SEL_MASK			0x300
+#define EFUSE_WIFI_SEL_0		0x0
+
+/*REG_MULTI_FUNC_CTRL(For RTL8723 Only)*/
+/* Enable GPIO[9] as WiFi HW PDn source*/
+#define	WL_HWPDN_EN			BIT(0)
+/* WiFi HW PDn polarity control*/
+#define	WL_HWPDN_SL			BIT(1)
+/* WiFi function enable */
+#define	WL_FUNC_EN			BIT(2)
+/* Enable GPIO[9] as WiFi RF HW PDn source */
+#define	WL_HWROF_EN			BIT(3)
+/* Enable GPIO[11] as BT HW PDn source */
+#define	BT_HWPDN_EN			BIT(16)
+/* BT HW PDn polarity control */
+#define	BT_HWPDN_SL			BIT(17)
+/* BT function enable */
+#define	BT_FUNC_EN			BIT(18)
+/* Enable GPIO[11] as BT/GPS RF HW PDn source */
+#define	BT_HWROF_EN			BIT(19)
+/* Enable GPIO[10] as GPS HW PDn source */
+#define	GPS_HWPDN_EN			BIT(20)
+/* GPS HW PDn polarity control */
+#define	GPS_HWPDN_SL			BIT(21)
+/* GPS function enable */
+#define	GPS_FUNC_EN			BIT(22)
+
+#define	BMASKBYTE0			0xff
+#define	BMASKBYTE1			0xff00
+#define	BMASKBYTE2			0xff0000
+#define	BMASKBYTE3			0xff000000
+#define	BMASKHWORD			0xffff0000
+#define	BMASKLWORD			0x0000ffff
+#define	BMASKDWORD			0xffffffff
+#define	BMASK12BITS			0xfff
+#define	BMASKH4BITS			0xf0000000
+#define BMASKOFDM_D			0xffc00000
+#define	BMASKCCK			0x3f3f3f3f
+
+#define BRFREGOFFSETMASK		0xfffff
+
+#define	ODM_REG_CCK_RPT_FORMAT_11AC	0x804
+#define	ODM_REG_BB_RX_PATH_11AC		0x808
+/*PAGE 9*/
+#define	ODM_REG_OFDM_FA_RST_11AC	0x9A4
+/*PAGE A*/
+#define	ODM_REG_CCK_CCA_11AC		0xA0A
+#define	ODM_REG_CCK_FA_RST_11AC		0xA2C
+#define	ODM_REG_CCK_FA_11AC		0xA5C
+/*PAGE C*/
+#define	ODM_REG_IGI_A_11AC		0xC50
+/*PAGE E*/
+#define	ODM_REG_IGI_B_11AC		0xE50
+/*PAGE F*/
+#define	ODM_REG_OFDM_FA_11AC		0xF48
+
+/* 2 MAC REG LIST */
+
+/* DIG Related */
+#define	ODM_BIT_IGI_11AC		0xFFFFFFFF
+#define	ODM_BIT_CCK_RPT_FORMAT_11AC	BIT16
+#define	ODM_BIT_BB_RX_PATH_11AC		0xF
+
+enum AGGRE_SIZE {
+	HT_AGG_SIZE_8K = 0,
+	HT_AGG_SIZE_16K = 1,
+	HT_AGG_SIZE_32K = 2,
+	HT_AGG_SIZE_64K = 3,
+	VHT_AGG_SIZE_128K = 4,
+	VHT_AGG_SIZE_256K = 5,
+	VHT_AGG_SIZE_512K = 6,
+	VHT_AGG_SIZE_1024K = 7,
+};
+
+#define REG_AMPDU_MAX_LENGTH_8812	0x0458
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/rf.c b/drivers/net/wireless/rtlwifi/rtl8821ae/rf.c
new file mode 100644
index 0000000..2922538
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/rf.c
@@ -0,0 +1,465 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+
+static bool _rtl8821ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
+
+void rtl8821ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	switch (bandwidth) {
+	case HT_CHANNEL_WIDTH_20:
+		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 3);
+		rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 3);
+		break;
+	case HT_CHANNEL_WIDTH_20_40:
+		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 1);
+		rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 1);
+		break;
+	case HT_CHANNEL_WIDTH_80:
+		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, BIT(11)|BIT(10), 0);
+		rtl_set_rfreg(hw, RF90_PATH_B, RF_CHNLBW, BIT(11)|BIT(10), 0);
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "unknown bandwidth: %#X\n", bandwidth);
+		break;
+	}
+}
+
+void rtl8821ae_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+					  u8 *ppowerlevel)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	u32 tx_agc[2] = {0, 0}, tmpval;
+	bool turbo_scanoff = false;
+	u8 idx1, idx2;
+	u8 *ptr;
+	u8 direction;
+	u32 pwrtrac_value;
+
+	if (rtlefuse->eeprom_regulatory != 0)
+		turbo_scanoff = true;
+
+	if (mac->act_scanning) {
+		tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
+		tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
+
+		if (turbo_scanoff) {
+			for (idx1 = RF90_PATH_A;
+				idx1 <= RF90_PATH_B;
+				idx1++) {
+				tx_agc[idx1] = ppowerlevel[idx1] |
+				    (ppowerlevel[idx1] << 8) |
+				    (ppowerlevel[idx1] << 16) |
+				    (ppowerlevel[idx1] << 24);
+			}
+		}
+	} else {
+		for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+			tx_agc[idx1] = ppowerlevel[idx1] |
+			    (ppowerlevel[idx1] << 8) |
+			    (ppowerlevel[idx1] << 16) |
+			    (ppowerlevel[idx1] << 24);
+		}
+
+		if (rtlefuse->eeprom_regulatory == 0) {
+			tmpval =
+			    (rtlphy->mcs_txpwrlevel_origoffset[0][6]) +
+			    (rtlphy->mcs_txpwrlevel_origoffset[0][7] <<
+			     8);
+			tx_agc[RF90_PATH_A] += tmpval;
+
+			tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) +
+			    (rtlphy->mcs_txpwrlevel_origoffset[0][15] <<
+			     24);
+			tx_agc[RF90_PATH_B] += tmpval;
+		}
+	}
+
+	for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+		ptr = (u8 *)(&tx_agc[idx1]);
+		for (idx2 = 0; idx2 < 4; idx2++) {
+			if (*ptr > RF6052_MAX_TX_PWR)
+				*ptr = RF6052_MAX_TX_PWR;
+			ptr++;
+		}
+	}
+	rtl8821ae_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
+	if (direction == 1) {
+		tx_agc[0] += pwrtrac_value;
+		tx_agc[1] += pwrtrac_value;
+	} else if (direction == 2) {
+		tx_agc[0] -= pwrtrac_value;
+		tx_agc[1] -= pwrtrac_value;
+	}
+	tmpval = tx_agc[RF90_PATH_A];
+	rtl_set_bbreg(hw, RTXAGC_A_CCK11_CCK1, MASKDWORD, tmpval);
+
+	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+		"CCK PWR 1~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+		 RTXAGC_A_CCK11_CCK1);
+
+	tmpval = tx_agc[RF90_PATH_B];
+	rtl_set_bbreg(hw, RTXAGC_B_CCK11_CCK1, MASKDWORD, tmpval);
+
+	RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+		"CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+		 RTXAGC_B_CCK11_CCK1);
+}
+
+static void rtl8821ae_phy_get_power_base(struct ieee80211_hw *hw,
+					 u8 *ppowerlevel_ofdm,
+					 u8 *ppowerlevel_bw20,
+					 u8 *ppowerlevel_bw40, u8 channel,
+					 u32 *ofdmbase, u32 *mcsbase)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u32 powerbase0, powerbase1;
+	u8 i, powerlevel[2];
+
+	for (i = 0; i < 2; i++) {
+		powerbase0 = ppowerlevel_ofdm[i];
+
+		powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) |
+		    (powerbase0 << 8) | powerbase0;
+		*(ofdmbase + i) = powerbase0;
+		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+			" [OFDM power base index rf(%c) = 0x%x]\n",
+			 ((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
+	}
+
+	for (i = 0; i < 2; i++) {
+		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20)
+			powerlevel[i] = ppowerlevel_bw20[i];
+		else
+			powerlevel[i] = ppowerlevel_bw40[i];
+
+		powerbase1 = powerlevel[i];
+		powerbase1 = (powerbase1 << 24) |
+		    (powerbase1 << 16) | (powerbase1 << 8) | powerbase1;
+
+		*(mcsbase + i) = powerbase1;
+
+		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+			" [MCS power base index rf(%c) = 0x%x]\n",
+			 ((i == 0) ? 'A' : 'B'), *(mcsbase + i));
+	}
+}
+
+static void get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
+					       u8 channel, u8 index,
+					       u32 *powerbase0,
+					       u32 *powerbase1,
+					       u32 *p_outwriteval)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	u8 i, chnlgroup = 0, pwr_diff_limit[4], pwr_diff = 0, customer_pwr_diff;
+	u32 writeval, customer_limit, rf;
+
+	for (rf = 0; rf < 2; rf++) {
+		switch (rtlefuse->eeprom_regulatory) {
+		case 0:
+			chnlgroup = 0;
+
+			writeval =
+			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index +
+							(rf ? 8 : 0)]
+			    + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
+
+			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+				"RTK better performance, writeval(%c) = 0x%x\n",
+				 ((rf == 0) ? 'A' : 'B'), writeval);
+			break;
+		case 1:
+			if (rtlphy->pwrgroup_cnt == 1) {
+				chnlgroup = 0;
+			} else {
+				if (channel < 3)
+					chnlgroup = 0;
+				else if (channel < 6)
+					chnlgroup = 1;
+				else if (channel < 9)
+					chnlgroup = 2;
+				else if (channel < 12)
+					chnlgroup = 3;
+				else if (channel < 14)
+					chnlgroup = 4;
+				else if (channel == 14)
+					chnlgroup = 5;
+			}
+
+			writeval =
+			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
+			    [index + (rf ? 8 : 0)] + ((index < 2) ?
+						      powerbase0[rf] :
+						      powerbase1[rf]);
+
+			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+				"Realtek regulatory, 20MHz, writeval(%c) = 0x%x\n",
+				 ((rf == 0) ? 'A' : 'B'), writeval);
+
+			break;
+		case 2:
+			writeval =
+			    ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
+
+			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+				"Better regulatory, writeval(%c) = 0x%x\n",
+				 ((rf == 0) ? 'A' : 'B'), writeval);
+			break;
+		case 3:
+			chnlgroup = 0;
+
+			if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+					"customer's limit, 40MHz rf(%c) = 0x%x\n",
+					 ((rf == 0) ? 'A' : 'B'),
+					 rtlefuse->pwrgroup_ht40[rf][channel -
+								     1]);
+			} else {
+				RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+					"customer's limit, 20MHz rf(%c) = 0x%x\n",
+					 ((rf == 0) ? 'A' : 'B'),
+					 rtlefuse->pwrgroup_ht20[rf][channel -
+								     1]);
+			}
+
+			if (index < 2)
+				pwr_diff = rtlefuse->txpwr_legacyhtdiff[rf][channel-1];
+			else if (rtlphy->current_chan_bw ==  HT_CHANNEL_WIDTH_20)
+				pwr_diff =
+				  rtlefuse->txpwr_ht20diff[rf][channel-1];
+
+			if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40)
+				customer_pwr_diff =
+				  rtlefuse->pwrgroup_ht40[rf][channel-1];
+			else
+				customer_pwr_diff =
+				  rtlefuse->pwrgroup_ht20[rf][channel-1];
+
+			if (pwr_diff > customer_pwr_diff)
+				pwr_diff = 0;
+			else
+				pwr_diff = customer_pwr_diff - pwr_diff;
+
+			for (i = 0; i < 4; i++) {
+				pwr_diff_limit[i] =
+				    (u8)((rtlphy->mcs_txpwrlevel_origoffset
+				    [chnlgroup][index + (rf ? 8 : 0)] &
+				    (0x7f << (i * 8))) >> (i * 8));
+
+				if (pwr_diff_limit[i] > pwr_diff)
+					pwr_diff_limit[i] = pwr_diff;
+			}
+
+			customer_limit = (pwr_diff_limit[3] << 24) |
+			    (pwr_diff_limit[2] << 16) |
+			    (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]);
+
+			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+				"Customer's limit rf(%c) = 0x%x\n",
+				 ((rf == 0) ? 'A' : 'B'), customer_limit);
+
+			writeval = customer_limit +
+			    ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
+
+			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+				"Customer, writeval rf(%c)= 0x%x\n",
+				 ((rf == 0) ? 'A' : 'B'), writeval);
+			break;
+		default:
+			chnlgroup = 0;
+			writeval =
+			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup]
+			    [index + (rf ? 8 : 0)]
+			    + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
+
+			RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+				"RTK better performance, writeval rf(%c) = 0x%x\n",
+				 ((rf == 0) ? 'A' : 'B'), writeval);
+			break;
+		}
+
+		if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
+			writeval = writeval - 0x06060606;
+		else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+			 TXHIGHPWRLEVEL_BT2)
+			writeval = writeval - 0x0c0c0c0c;
+		*(p_outwriteval + rf) = writeval;
+	}
+}
+
+static void _rtl8821ae_write_ofdm_power_reg(struct ieee80211_hw *hw,
+					    u8 index, u32 *pvalue)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u16 regoffset_a[6] = {
+		RTXAGC_A_OFDM18_OFDM6, RTXAGC_A_OFDM54_OFDM24,
+		RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04,
+		RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12
+	};
+	u16 regoffset_b[6] = {
+		RTXAGC_B_OFDM18_OFDM6, RTXAGC_B_OFDM54_OFDM24,
+		RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04,
+		RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12
+	};
+	u8 i, rf, pwr_val[4];
+	u32 writeval;
+	u16 regoffset;
+
+	for (rf = 0; rf < 2; rf++) {
+		writeval = pvalue[rf];
+		for (i = 0; i < 4; i++) {
+			pwr_val[i] = (u8)((writeval & (0x7f <<
+							(i * 8))) >> (i * 8));
+
+			if (pwr_val[i] > RF6052_MAX_TX_PWR)
+				pwr_val[i] = RF6052_MAX_TX_PWR;
+		}
+		writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
+		    (pwr_val[1] << 8) | pwr_val[0];
+
+		if (rf == 0)
+			regoffset = regoffset_a[index];
+		else
+			regoffset = regoffset_b[index];
+		rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);
+
+		RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+			"Set 0x%x = %08x\n", regoffset, writeval);
+	}
+}
+
+void rtl8821ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+					   u8 *ppowerlevel_ofdm,
+					   u8 *ppowerlevel_bw20,
+					   u8 *ppowerlevel_bw40,
+					   u8 channel)
+{
+	u32 writeval[2], powerbase0[2], powerbase1[2];
+	u8 index;
+	u8 direction;
+	u32 pwrtrac_value;
+
+	rtl8821ae_phy_get_power_base(hw, ppowerlevel_ofdm,
+				     ppowerlevel_bw20,
+				     ppowerlevel_bw40,
+				     channel,
+				     &powerbase0[0],
+				     &powerbase1[0]);
+
+	rtl8821ae_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
+
+	for (index = 0; index < 6; index++) {
+		get_txpower_writeval_by_regulatory(hw, channel, index,
+						   &powerbase0[0],
+						   &powerbase1[0],
+						   &writeval[0]);
+		if (direction == 1) {
+			writeval[0] += pwrtrac_value;
+			writeval[1] += pwrtrac_value;
+		} else if (direction == 2) {
+			writeval[0] -= pwrtrac_value;
+			writeval[1] -= pwrtrac_value;
+		}
+		_rtl8821ae_write_ofdm_power_reg(hw, index, &writeval[0]);
+	}
+}
+
+bool rtl8821ae_phy_rf6052_config(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+
+	if (rtlphy->rf_type == RF_1T1R)
+		rtlphy->num_total_rfpath = 1;
+	else
+		rtlphy->num_total_rfpath = 2;
+
+	return _rtl8821ae_phy_rf6052_config_parafile(hw);
+}
+
+static bool _rtl8821ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+	u8 rfpath;
+	bool rtstatus = true;
+
+	for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
+		switch (rfpath) {
+		case RF90_PATH_A: {
+			if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+				rtstatus =
+				  rtl8812ae_phy_config_rf_with_headerfile(hw,
+							(enum radio_path)rfpath);
+			else
+				rtstatus =
+				  rtl8821ae_phy_config_rf_with_headerfile(hw,
+							(enum radio_path)rfpath);
+			break;
+			}
+		case RF90_PATH_B:
+			if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+				rtstatus =
+				  rtl8812ae_phy_config_rf_with_headerfile(hw,
+							(enum radio_path)rfpath);
+			else
+				rtstatus =
+				  rtl8821ae_phy_config_rf_with_headerfile(hw,
+							(enum radio_path)rfpath);
+			break;
+		case RF90_PATH_C:
+			break;
+		case RF90_PATH_D:
+			break;
+		}
+
+		if (!rtstatus) {
+			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+				 "Radio[%d] Fail!!", rfpath);
+			return false;
+		}
+	}
+
+	/*put arrays in dm.c*/
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
+	return rtstatus;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/rf.h b/drivers/net/wireless/rtlwifi/rtl8821ae/rf.h
new file mode 100644
index 0000000..d9582ee
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/rf.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8821AE_RF_H__
+#define __RTL8821AE_RF_H__
+
+#define RF6052_MAX_TX_PWR		0x3F
+#define RF6052_MAX_REG			0x3F
+
+void rtl8821ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+					u8 bandwidth);
+void rtl8821ae_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+					  u8 *ppowerlevel);
+void rtl8821ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+					   u8 *ppowerlevel_ofdm,
+					   u8 *ppowerlevel_bw20,
+					   u8 *ppowerlevel_bw40,
+					   u8 channel);
+bool rtl8821ae_phy_rf6052_config(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c
new file mode 100644
index 0000000..fc92dd6
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c
@@ -0,0 +1,484 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../core.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "hw.h"
+#include "fw.h"
+#include "sw.h"
+#include "trx.h"
+#include "led.h"
+#include "table.h"
+#include "../btcoexist/rtl_btc.h"
+
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+
+static void rtl8821ae_init_aspm_vars(struct ieee80211_hw *hw)
+{
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+	/*close ASPM for AMD defaultly */
+	rtlpci->const_amdpci_aspm = 0;
+
+	/**
+	 * ASPM PS mode.
+	 * 0 - Disable ASPM,
+	 * 1 - Enable ASPM without Clock Req,
+	 * 2 - Enable ASPM with Clock Req,
+	 * 3 - Alwyas Enable ASPM with Clock Req,
+	 * 4 - Always Enable ASPM without Clock Req.
+	 * set defult to RTL8192CE:3 RTL8192E:2
+	 */
+	rtlpci->const_pci_aspm = 3;
+
+	/*Setting for PCI-E device */
+	rtlpci->const_devicepci_aspm_setting = 0x03;
+
+	/*Setting for PCI-E bridge */
+	rtlpci->const_hostpci_aspm_setting = 0x02;
+
+	/**
+	 * In Hw/Sw Radio Off situation.
+	 * 0 - Default,
+	 * 1 - From ASPM setting without low Mac Pwr,
+	 * 2 - From ASPM setting with low Mac Pwr,
+	 * 3 - Bus D3
+	 * set default to RTL8192CE:0 RTL8192SE:2
+	 */
+	rtlpci->const_hwsw_rfoff_d3 = 0;
+
+	/**
+	 * This setting works for those device with
+	 * backdoor ASPM setting such as EPHY setting.
+	 * 0 - Not support ASPM,
+	 * 1 - Support ASPM,
+	 * 2 - According to chipset.
+	 */
+	rtlpci->const_support_pciaspm = 1;
+}
+
+static void load_wowlan_fw(struct rtl_priv *rtlpriv)
+{
+	/* callback routine to load wowlan firmware after main fw has
+	 * been loaded
+	 */
+	const struct firmware *wowlan_firmware;
+	char *fw_name = NULL;
+	int err;
+
+	/* for wowlan firmware buf */
+	rtlpriv->rtlhal.wowlan_firmware = vzalloc(0x8000);
+	if (!rtlpriv->rtlhal.wowlan_firmware) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Can't alloc buffer for wowlan fw.\n");
+		return;
+	}
+
+	if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8821AE)
+		fw_name = "rtlwifi/rtl8821aefw_wowlan.bin";
+	else
+		fw_name = "rtlwifi/rtl8812aefw_wowlan.bin";
+	err = request_firmware(&wowlan_firmware, fw_name, rtlpriv->io.dev);
+	if (err) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Failed to request wowlan firmware!\n");
+		goto error;
+	}
+
+	if (wowlan_firmware->size > 0x8000) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Wowlan Firmware is too big!\n");
+		goto error;
+	}
+
+	memcpy(rtlpriv->rtlhal.wowlan_firmware, wowlan_firmware->data,
+	       wowlan_firmware->size);
+	rtlpriv->rtlhal.wowlan_fwsize = wowlan_firmware->size;
+	release_firmware(wowlan_firmware);
+
+	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "WOWLAN FirmwareDownload OK\n");
+	return;
+error:
+	release_firmware(wowlan_firmware);
+	vfree(rtlpriv->rtlhal.wowlan_firmware);
+}
+
+/*InitializeVariables8812E*/
+int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw)
+{
+	int err = 0;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+	rtl8821ae_bt_reg_init(hw);
+	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
+	rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer();
+
+	rtlpriv->dm.dm_initialgain_enable = 1;
+	rtlpriv->dm.dm_flag = 0;
+	rtlpriv->dm.disable_framebursting = 0;
+	rtlpriv->dm.thermalvalue = 0;
+	rtlpci->transmit_config = CFENDFORM | BIT(15) | BIT(24) | BIT(25);
+
+	mac->ht_enable = true;
+	mac->ht_cur_stbc = 0;
+	mac->ht_stbc_cap = 0;
+	mac->vht_cur_ldpc = 0;
+	mac->vht_ldpc_cap = 0;
+	mac->vht_cur_stbc = 0;
+	mac->vht_stbc_cap = 0;
+
+	rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G;
+	/*following 2 is for register 5G band, refer to _rtl_init_mac80211()*/
+	rtlpriv->rtlhal.bandset = BAND_ON_BOTH;
+	rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY;
+
+	rtlpci->receive_config = (RCR_APPFCS	|
+				RCR_APP_MIC		|
+				RCR_APP_ICV		|
+				RCR_APP_PHYST_RXFF	|
+				RCR_NONQOS_VHT		|
+				RCR_HTC_LOC_CTRL	|
+				RCR_AMF			|
+				RCR_ACF			|
+			/*This bit controls the PS-Poll packet filter.*/
+				RCR_ADF			|
+				RCR_AICV		|
+				RCR_ACRC32		|
+				RCR_AB			|
+				RCR_AM			|
+				RCR_APM			|
+				0);
+
+	rtlpci->irq_mask[0] =
+	     (u32)(IMR_PSTIMEOUT			|
+				IMR_GTINT3		|
+				IMR_HSISR_IND_ON_INT	|
+				IMR_C2HCMD		|
+				IMR_HIGHDOK		|
+				IMR_MGNTDOK		|
+				IMR_BKDOK		|
+				IMR_BEDOK		|
+				IMR_VIDOK		|
+				IMR_VODOK		|
+				IMR_RDU			|
+				IMR_ROK			|
+				0);
+
+	rtlpci->irq_mask[1]	=
+		 (u32)(IMR_RXFOVW |
+				IMR_TXFOVW |
+				0);
+	rtlpci->sys_irq_mask = (u32)(HSIMR_PDN_INT_EN	|
+				      HSIMR_RON_INT_EN	|
+				      0);
+	/* for WOWLAN */
+	rtlpriv->psc.wo_wlan_mode = WAKE_ON_MAGIC_PACKET |
+				    WAKE_ON_PATTERN_MATCH;
+
+	/* for debug level */
+	rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
+	/* for LPS & IPS */
+	rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
+	rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
+	rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
+	if (rtlpriv->cfg->mod_params->disable_watchdog)
+		pr_info("watchdog disabled\n");
+	rtlpriv->psc.reg_fwctrl_lps = 3;
+	rtlpriv->psc.reg_max_lps_awakeintvl = 5;
+	rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support;
+
+	/* for ASPM, you can close aspm through
+	 * set const_support_pciaspm = 0
+	 */
+	rtl8821ae_init_aspm_vars(hw);
+
+	if (rtlpriv->psc.reg_fwctrl_lps == 1)
+		rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE;
+	else if (rtlpriv->psc.reg_fwctrl_lps == 2)
+		rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE;
+	else if (rtlpriv->psc.reg_fwctrl_lps == 3)
+		rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
+
+	rtlpriv->rtl_fw_second_cb = load_wowlan_fw;
+	/* for firmware buf */
+	rtlpriv->rtlhal.pfirmware = vzalloc(0x8000);
+	if (!rtlpriv->rtlhal.pfirmware) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Can't alloc buffer for fw.\n");
+		return 1;
+	}
+
+	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+		rtlpriv->cfg->fw_name = "rtlwifi/rtl8812aefw.bin";
+	else
+		rtlpriv->cfg->fw_name = "rtlwifi/rtl8821aefw.bin";
+
+	rtlpriv->max_fw_size = 0x8000;
+	pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
+	err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+				      rtlpriv->io.dev, GFP_KERNEL, hw,
+				      rtl_fw_cb);
+	if (err) {
+		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+			 "Failed to request firmware!\n");
+		return 1;
+	}
+	return 0;
+}
+
+void rtl8821ae_deinit_sw_vars(struct ieee80211_hw *hw)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (rtlpriv->rtlhal.pfirmware) {
+		vfree(rtlpriv->rtlhal.pfirmware);
+		rtlpriv->rtlhal.pfirmware = NULL;
+	}
+#if (USE_SPECIFIC_FW_TO_SUPPORT_WOWLAN == 1)
+	if (rtlpriv->rtlhal.wowlan_firmware) {
+		vfree(rtlpriv->rtlhal.wowlan_firmware);
+		rtlpriv->rtlhal.wowlan_firmware = NULL;
+	}
+#endif
+}
+
+/* get bt coexist status */
+bool rtl8821ae_get_btc_status(void)
+{
+	return true;
+}
+
+static struct rtl_hal_ops rtl8821ae_hal_ops = {
+	.init_sw_vars = rtl8821ae_init_sw_vars,
+	.deinit_sw_vars = rtl8821ae_deinit_sw_vars,
+	.read_eeprom_info = rtl8821ae_read_eeprom_info,
+	.interrupt_recognized = rtl8821ae_interrupt_recognized,
+	.hw_init = rtl8821ae_hw_init,
+	.hw_disable = rtl8821ae_card_disable,
+	.hw_suspend = rtl8821ae_suspend,
+	.hw_resume = rtl8821ae_resume,
+	.enable_interrupt = rtl8821ae_enable_interrupt,
+	.disable_interrupt = rtl8821ae_disable_interrupt,
+	.set_network_type = rtl8821ae_set_network_type,
+	.set_chk_bssid = rtl8821ae_set_check_bssid,
+	.set_qos = rtl8821ae_set_qos,
+	.set_bcn_reg = rtl8821ae_set_beacon_related_registers,
+	.set_bcn_intv = rtl8821ae_set_beacon_interval,
+	.update_interrupt_mask = rtl8821ae_update_interrupt_mask,
+	.get_hw_reg = rtl8821ae_get_hw_reg,
+	.set_hw_reg = rtl8821ae_set_hw_reg,
+	.update_rate_tbl = rtl8821ae_update_hal_rate_tbl,
+	.fill_tx_desc = rtl8821ae_tx_fill_desc,
+	.fill_tx_cmddesc = rtl8821ae_tx_fill_cmddesc,
+	.query_rx_desc = rtl8821ae_rx_query_desc,
+	.set_channel_access = rtl8821ae_update_channel_access_setting,
+	.radio_onoff_checking = rtl8821ae_gpio_radio_on_off_checking,
+	.set_bw_mode = rtl8821ae_phy_set_bw_mode,
+	.switch_channel = rtl8821ae_phy_sw_chnl,
+	.dm_watchdog = rtl8821ae_dm_watchdog,
+	.scan_operation_backup = rtl8821ae_phy_scan_operation_backup,
+	.set_rf_power_state = rtl8821ae_phy_set_rf_power_state,
+	.led_control = rtl8821ae_led_control,
+	.set_desc = rtl8821ae_set_desc,
+	.get_desc = rtl8821ae_get_desc,
+	.is_tx_desc_closed = rtl8821ae_is_tx_desc_closed,
+	.tx_polling = rtl8821ae_tx_polling,
+	.enable_hw_sec = rtl8821ae_enable_hw_security_config,
+	.set_key = rtl8821ae_set_key,
+	.init_sw_leds = rtl8821ae_init_sw_leds,
+	.get_bbreg = rtl8821ae_phy_query_bb_reg,
+	.set_bbreg = rtl8821ae_phy_set_bb_reg,
+	.get_rfreg = rtl8821ae_phy_query_rf_reg,
+	.set_rfreg = rtl8821ae_phy_set_rf_reg,
+	.fill_h2c_cmd = rtl8821ae_fill_h2c_cmd,
+	.get_btc_status = rtl8821ae_get_btc_status,
+	.rx_command_packet = rtl8821ae_rx_command_packet,
+	.add_wowlan_pattern = rtl8821ae_add_wowlan_pattern,
+};
+
+static struct rtl_mod_params rtl8821ae_mod_params = {
+	.sw_crypto = false,
+	.inactiveps = true,
+	.swctrl_lps = false,
+	.fwctrl_lps = true,
+	.msi_support = true,
+	.debug = DBG_EMERG,
+	.disable_watchdog = 0,
+};
+
+static struct rtl_hal_cfg rtl8821ae_hal_cfg = {
+	.bar_id = 2,
+	.write_readback = true,
+	.name = "rtl8821ae_pci",
+	.fw_name = "rtlwifi/rtl8821aefw.bin",
+	.ops = &rtl8821ae_hal_ops,
+	.mod_params = &rtl8821ae_mod_params,
+	.maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
+	.maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN,
+	.maps[SYS_CLK] = REG_SYS_CLKR,
+	.maps[MAC_RCR_AM] = AM,
+	.maps[MAC_RCR_AB] = AB,
+	.maps[MAC_RCR_ACRC32] = ACRC32,
+	.maps[MAC_RCR_ACF] = ACF,
+	.maps[MAC_RCR_AAP] = AAP,
+	.maps[MAC_HIMR] = REG_HIMR,
+	.maps[MAC_HIMRE] = REG_HIMRE,
+
+	.maps[EFUSE_ACCESS] = REG_EFUSE_ACCESS,
+
+	.maps[EFUSE_TEST] = REG_EFUSE_TEST,
+	.maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
+	.maps[EFUSE_CLK] = 0,
+	.maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL,
+	.maps[EFUSE_PWC_EV12V] = PWC_EV12V,
+	.maps[EFUSE_FEN_ELDR] = FEN_ELDR,
+	.maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN,
+	.maps[EFUSE_ANA8M] = ANA8M,
+	.maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE,
+	.maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
+	.maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
+	.maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES,
+
+	.maps[RWCAM] = REG_CAMCMD,
+	.maps[WCAMI] = REG_CAMWRITE,
+	.maps[RCAMO] = REG_CAMREAD,
+	.maps[CAMDBG] = REG_CAMDBG,
+	.maps[SECR] = REG_SECCFG,
+	.maps[SEC_CAM_NONE] = CAM_NONE,
+	.maps[SEC_CAM_WEP40] = CAM_WEP40,
+	.maps[SEC_CAM_TKIP] = CAM_TKIP,
+	.maps[SEC_CAM_AES] = CAM_AES,
+	.maps[SEC_CAM_WEP104] = CAM_WEP104,
+
+	.maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6,
+	.maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5,
+	.maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4,
+	.maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3,
+	.maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2,
+	.maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1,
+/*	.maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8,     */   /*need check*/
+	.maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7,
+	.maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6,
+	.maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5,
+	.maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4,
+	.maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3,
+	.maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2,
+	.maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1,
+/*	.maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2,*/
+/*	.maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1,*/
+
+	.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
+	.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
+	.maps[RTL_IMR_BCNINT] = IMR_BCNDMAINT0,
+	.maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
+	.maps[RTL_IMR_RDU] = IMR_RDU,
+	.maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
+	.maps[RTL_IMR_BDOK] = IMR_BCNDOK0,
+	.maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK,
+	.maps[RTL_IMR_TBDER] = IMR_TBDER,
+	.maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK,
+	.maps[RTL_IMR_TBDOK] = IMR_TBDOK,
+	.maps[RTL_IMR_BKDOK] = IMR_BKDOK,
+	.maps[RTL_IMR_BEDOK] = IMR_BEDOK,
+	.maps[RTL_IMR_VIDOK] = IMR_VIDOK,
+	.maps[RTL_IMR_VODOK] = IMR_VODOK,
+	.maps[RTL_IMR_ROK] = IMR_ROK,
+	.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNDMAINT0 | IMR_TBDOK | IMR_TBDER),
+
+	.maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M,
+	.maps[RTL_RC_CCK_RATE2M] =  DESC_RATE2M,
+	.maps[RTL_RC_CCK_RATE5_5M] =  DESC_RATE5_5M,
+	.maps[RTL_RC_CCK_RATE11M] =  DESC_RATE11M,
+	.maps[RTL_RC_OFDM_RATE6M] =  DESC_RATE6M,
+	.maps[RTL_RC_OFDM_RATE9M] =  DESC_RATE9M,
+	.maps[RTL_RC_OFDM_RATE12M] =  DESC_RATE12M,
+	.maps[RTL_RC_OFDM_RATE18M] =  DESC_RATE18M,
+	.maps[RTL_RC_OFDM_RATE24M] =  DESC_RATE24M,
+	.maps[RTL_RC_OFDM_RATE36M] =  DESC_RATE36M,
+	.maps[RTL_RC_OFDM_RATE48M] =  DESC_RATE48M,
+	.maps[RTL_RC_OFDM_RATE54M] =  DESC_RATE54M,
+
+	.maps[RTL_RC_HT_RATEMCS7] =  DESC_RATEMCS7,
+	.maps[RTL_RC_HT_RATEMCS15] =  DESC_RATEMCS15,
+
+	/*VHT hightest rate*/
+	.maps[RTL_RC_VHT_RATE_1SS_MCS7] = DESC_RATEVHT1SS_MCS7,
+	.maps[RTL_RC_VHT_RATE_1SS_MCS8] = DESC_RATEVHT1SS_MCS8,
+	.maps[RTL_RC_VHT_RATE_1SS_MCS9] = DESC_RATEVHT1SS_MCS9,
+	.maps[RTL_RC_VHT_RATE_2SS_MCS7] = DESC_RATEVHT2SS_MCS7,
+	.maps[RTL_RC_VHT_RATE_2SS_MCS8] = DESC_RATEVHT2SS_MCS8,
+	.maps[RTL_RC_VHT_RATE_2SS_MCS9] = DESC_RATEVHT2SS_MCS9,
+};
+
+static struct pci_device_id rtl8821ae_pci_ids[] = {
+	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8812, rtl8821ae_hal_cfg)},
+	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8821, rtl8821ae_hal_cfg)},
+	{},
+};
+
+MODULE_DEVICE_TABLE(pci, rtl8821ae_pci_ids);
+
+MODULE_AUTHOR("Realtek WlanFAE	<wlanfae@realtek.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 8821ae 802.11ac PCI wireless");
+MODULE_FIRMWARE("rtlwifi/rtl8821aefw.bin");
+
+module_param_named(swenc, rtl8821ae_mod_params.sw_crypto, bool, 0444);
+module_param_named(debug, rtl8821ae_mod_params.debug, int, 0444);
+module_param_named(ips, rtl8821ae_mod_params.inactiveps, bool, 0444);
+module_param_named(swlps, rtl8821ae_mod_params.swctrl_lps, bool, 0444);
+module_param_named(fwlps, rtl8821ae_mod_params.fwctrl_lps, bool, 0444);
+module_param_named(msi, rtl8821ae_mod_params.msi_support, bool, 0444);
+module_param_named(disable_watchdog, rtl8821ae_mod_params.disable_watchdog,
+		   bool, 0444);
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
+MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 1)\n");
+MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n");
+
+static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
+
+static struct pci_driver rtl8821ae_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = rtl8821ae_pci_ids,
+	.probe = rtl_pci_probe,
+	.remove = rtl_pci_disconnect,
+	.driver.pm = &rtlwifi_pm_ops,
+};
+
+module_pci_driver(rtl8821ae_driver);
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/sw.h b/drivers/net/wireless/rtlwifi/rtl8821ae/sw.h
new file mode 100644
index 0000000..d001e7c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/sw.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8821AE_SW_H__
+#define __RTL8821AE_SW_H__
+
+int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw);
+void rtl8821ae_deinit_sw_vars(struct ieee80211_hw *hw);
+void rtl8821ae_init_var_map(struct ieee80211_hw *hw);
+bool rtl8821ae_get_btc_status(void);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/table.c b/drivers/net/wireless/rtlwifi/rtl8821ae/table.c
new file mode 100644
index 0000000..62a0fb7
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/table.c
@@ -0,0 +1,4572 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on  2010/ 5/18,  1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "table.h"
+u32 RTL8812AE_PHY_REG_ARRAY[] = {
+		0x800, 0x8020D010,
+		0x804, 0x080112E0,
+		0x808, 0x0E028233,
+		0x80C, 0x12131113,
+		0x810, 0x20101263,
+		0x814, 0x020C3D10,
+		0x818, 0x03A00385,
+		0x820, 0x00000000,
+		0x824, 0x00030FE0,
+		0x828, 0x00000000,
+		0x82C, 0x002083DD,
+		0x830, 0x2AAA6C86,
+		0x834, 0x0037A706,
+		0x838, 0x06C89B44,
+		0x83C, 0x0000095B,
+		0x840, 0xC0000001,
+		0x844, 0x40003CDE,
+		0x848, 0x6210FF8B,
+		0x84C, 0x6CFDFFB8,
+		0x850, 0x28874706,
+		0x854, 0x0001520C,
+		0x858, 0x8060E000,
+		0x85C, 0x74210168,
+		0x860, 0x6929C321,
+		0x864, 0x79727432,
+		0x868, 0x8CA7A314,
+		0x86C, 0x338C2878,
+		0x870, 0x03333333,
+		0x874, 0x31602C2E,
+		0x878, 0x00003152,
+		0x87C, 0x000FC000,
+		0x8A0, 0x00000013,
+		0x8A4, 0x7F7F7F7F,
+		0x8A8, 0xA202033E,
+		0x8AC, 0x0FF0FA0A,
+		0x8B0, 0x00000600,
+		0x8B4, 0x000FC080,
+		0x8B8, 0x6C0057FF,
+		0x8BC, 0x4CA520A3,
+		0x8C0, 0x27F00020,
+		0x8C4, 0x00000000,
+		0x8C8, 0x00013169,
+		0x8CC, 0x08248492,
+		0x8D0, 0x0000B800,
+		0x8DC, 0x00000000,
+		0x8D4, 0x940008A0,
+		0x8D8, 0x290B5612,
+		0x8F8, 0x400002C0,
+		0x8FC, 0x00000000,
+	0xFF0F07D8, 0xABCD,
+		0x900, 0x00000701,
+	0xFF0F07D0, 0xCDEF,
+		0x900, 0x00000701,
+	0xCDCDCDCD, 0xCDCD,
+		0x900, 0x00000700,
+	0xFF0F07D8, 0xDEAD,
+		0x90C, 0x00000000,
+		0x910, 0x0000FC00,
+		0x914, 0x00000404,
+		0x918, 0x1C1028C0,
+		0x91C, 0x64B11A1C,
+		0x920, 0xE0767233,
+		0x924, 0x055AA500,
+		0x928, 0x00000004,
+		0x92C, 0xFFFE0000,
+		0x930, 0xFFFFFFFE,
+		0x934, 0x001FFFFF,
+		0x960, 0x00000000,
+		0x964, 0x00000000,
+		0x968, 0x00000000,
+		0x96C, 0x00000000,
+		0x970, 0x801FFFFF,
+		0x978, 0x00000000,
+		0x97C, 0x00000000,
+		0x980, 0x00000000,
+		0x984, 0x00000000,
+		0x988, 0x00000000,
+		0x990, 0x27100000,
+		0x994, 0xFFFF0100,
+		0x998, 0xFFFFFF5C,
+		0x99C, 0xFFFFFFFF,
+		0x9A0, 0x000000FF,
+		0x9A4, 0x00080080,
+		0x9A8, 0x00000000,
+		0x9AC, 0x00000000,
+		0x9B0, 0x81081008,
+		0x9B4, 0x00000000,
+		0x9B8, 0x01081008,
+		0x9BC, 0x01081008,
+		0x9D0, 0x00000000,
+		0x9D4, 0x00000000,
+		0x9D8, 0x00000000,
+		0x9DC, 0x00000000,
+		0x9E4, 0x00000002,
+		0x9E8, 0x000002D5,
+		0xA00, 0x00D047C8,
+		0xA04, 0x01FF000C,
+		0xA08, 0x8C838300,
+		0xA0C, 0x2E7F000F,
+		0xA10, 0x9500BB78,
+		0xA14, 0x11144028,
+		0xA18, 0x00881117,
+		0xA1C, 0x89140F00,
+		0xA20, 0x1A1B0000,
+		0xA24, 0x090E1317,
+		0xA28, 0x00000204,
+		0xA2C, 0x00900000,
+		0xA70, 0x101FFF00,
+		0xA74, 0x00000008,
+		0xA78, 0x00000900,
+		0xA7C, 0x225B0606,
+		0xA80, 0x218075B2,
+		0xA84, 0x001F8C80,
+		0xB00, 0x03100000,
+		0xB04, 0x0000B000,
+		0xB08, 0xAE0201EB,
+		0xB0C, 0x01003207,
+		0xB10, 0x00009807,
+		0xB14, 0x01000000,
+		0xB18, 0x00000002,
+		0xB1C, 0x00000002,
+		0xB20, 0x0000001F,
+		0xB24, 0x03020100,
+		0xB28, 0x07060504,
+		0xB2C, 0x0B0A0908,
+		0xB30, 0x0F0E0D0C,
+		0xB34, 0x13121110,
+		0xB38, 0x17161514,
+		0xB3C, 0x0000003A,
+		0xB40, 0x00000000,
+		0xB44, 0x00000000,
+		0xB48, 0x13000032,
+		0xB4C, 0x48080000,
+		0xB50, 0x00000000,
+		0xB54, 0x00000000,
+		0xB58, 0x00000000,
+		0xB5C, 0x00000000,
+		0xC00, 0x00000007,
+		0xC04, 0x00042020,
+		0xC08, 0x80410231,
+		0xC0C, 0x00000000,
+		0xC10, 0x00000100,
+		0xC14, 0x01000000,
+		0xC1C, 0x40000003,
+		0xC20, 0x12121212,
+		0xC24, 0x12121212,
+		0xC28, 0x12121212,
+		0xC2C, 0x12121212,
+		0xC30, 0x12121212,
+		0xC34, 0x12121212,
+		0xC38, 0x12121212,
+		0xC3C, 0x12121212,
+		0xC40, 0x12121212,
+		0xC44, 0x12121212,
+		0xC48, 0x12121212,
+		0xC4C, 0x12121212,
+		0xC50, 0x00000020,
+		0xC54, 0x0008121C,
+		0xC58, 0x30000C1C,
+		0xC5C, 0x00000058,
+		0xC60, 0x34344443,
+		0xC64, 0x07003333,
+		0xC68, 0x59791979,
+		0xC6C, 0x59795979,
+		0xC70, 0x19795979,
+		0xC74, 0x19795979,
+		0xC78, 0x19791979,
+		0xC7C, 0x19791979,
+		0xC80, 0x19791979,
+		0xC84, 0x19791979,
+		0xC94, 0x0100005C,
+		0xC98, 0x00000000,
+		0xC9C, 0x00000000,
+		0xCA0, 0x00000029,
+		0xCA4, 0x08040201,
+		0xCA8, 0x80402010,
+	0xFF0F0740, 0xABCD,
+		0xCB0, 0x77547717,
+	0xFF0F01C0, 0xCDEF,
+		0xCB0, 0x77547717,
+	0xFF0F02C0, 0xCDEF,
+		0xCB0, 0x77547717,
+	0xFF0F07D8, 0xCDEF,
+		0xCB0, 0x54547710,
+	0xFF0F07D0, 0xCDEF,
+		0xCB0, 0x54547710,
+	0xCDCDCDCD, 0xCDCD,
+		0xCB0, 0x77547777,
+	0xFF0F0740, 0xDEAD,
+		0xCB4, 0x00000077,
+		0xCB8, 0x00508242,
+		0xE00, 0x00000007,
+		0xE04, 0x00042020,
+		0xE08, 0x80410231,
+		0xE0C, 0x00000000,
+		0xE10, 0x00000100,
+		0xE14, 0x01000000,
+		0xE1C, 0x40000003,
+		0xE20, 0x12121212,
+		0xE24, 0x12121212,
+		0xE28, 0x12121212,
+		0xE2C, 0x12121212,
+		0xE30, 0x12121212,
+		0xE34, 0x12121212,
+		0xE38, 0x12121212,
+		0xE3C, 0x12121212,
+		0xE40, 0x12121212,
+		0xE44, 0x12121212,
+		0xE48, 0x12121212,
+		0xE4C, 0x12121212,
+		0xE50, 0x00000020,
+		0xE54, 0x0008121C,
+		0xE58, 0x30000C1C,
+		0xE5C, 0x00000058,
+		0xE60, 0x34344443,
+		0xE64, 0x07003333,
+		0xE68, 0x59791979,
+		0xE6C, 0x59795979,
+		0xE70, 0x19795979,
+		0xE74, 0x19795979,
+		0xE78, 0x19791979,
+		0xE7C, 0x19791979,
+		0xE80, 0x19791979,
+		0xE84, 0x19791979,
+		0xE94, 0x0100005C,
+		0xE98, 0x00000000,
+		0xE9C, 0x00000000,
+		0xEA0, 0x00000029,
+		0xEA4, 0x08040201,
+		0xEA8, 0x80402010,
+	0xFF0F0740, 0xABCD,
+		0xEB0, 0x77547717,
+	0xFF0F01C0, 0xCDEF,
+		0xEB0, 0x77547717,
+	0xFF0F02C0, 0xCDEF,
+		0xEB0, 0x77547717,
+	0xFF0F07D8, 0xCDEF,
+		0xEB0, 0x54547710,
+	0xFF0F07D0, 0xCDEF,
+		0xEB0, 0x54547710,
+	0xCDCDCDCD, 0xCDCD,
+		0xEB0, 0x77547777,
+	0xFF0F0740, 0xDEAD,
+		0xEB4, 0x00000077,
+		0xEB8, 0x00508242,
+};
+
+u32 RTL8821AE_PHY_REG_ARRAY[] = {
+	0x800, 0x0020D090,
+	0x804, 0x080112E0,
+	0x808, 0x0E028211,
+	0x80C, 0x92131111,
+	0x810, 0x20101261,
+	0x814, 0x020C3D10,
+	0x818, 0x03A00385,
+	0x820, 0x00000000,
+	0x824, 0x00030FE0,
+	0x828, 0x00000000,
+	0x82C, 0x002081DD,
+	0x830, 0x2AAA8E24,
+	0x834, 0x0037A706,
+	0x838, 0x06489B44,
+	0x83C, 0x0000095B,
+	0x840, 0xC0000001,
+	0x844, 0x40003CDE,
+	0x848, 0x62103F8B,
+	0x84C, 0x6CFDFFB8,
+	0x850, 0x28874706,
+	0x854, 0x0001520C,
+	0x858, 0x8060E000,
+	0x85C, 0x74210168,
+	0x860, 0x6929C321,
+	0x864, 0x79727432,
+	0x868, 0x8CA7A314,
+	0x86C, 0x888C2878,
+	0x870, 0x08888888,
+	0x874, 0x31612C2E,
+	0x878, 0x00000152,
+	0x87C, 0x000FD000,
+	0x8A0, 0x00000013,
+	0x8A4, 0x7F7F7F7F,
+	0x8A8, 0xA2000338,
+	0x8AC, 0x0FF0FA0A,
+	0x8B4, 0x000FC080,
+	0x8B8, 0x6C10D7FF,
+	0x8BC, 0x0CA52090,
+	0x8C0, 0x1BF00020,
+	0x8C4, 0x00000000,
+	0x8C8, 0x00013169,
+	0x8CC, 0x08248492,
+	0x8D4, 0x940008A0,
+	0x8D8, 0x290B5612,
+	0x8F8, 0x400002C0,
+	0x8FC, 0x00000000,
+	0x900, 0x00000700,
+	0x90C, 0x00000000,
+	0x910, 0x0000FC00,
+	0x914, 0x00000404,
+	0x918, 0x1C1028C0,
+	0x91C, 0x64B11A1C,
+	0x920, 0xE0767233,
+	0x924, 0x055AA500,
+	0x928, 0x00000004,
+	0x92C, 0xFFFE0000,
+	0x930, 0xFFFFFFFE,
+	0x934, 0x001FFFFF,
+	0x960, 0x00000000,
+	0x964, 0x00000000,
+	0x968, 0x00000000,
+	0x96C, 0x00000000,
+	0x970, 0x801FFFFF,
+	0x974, 0x000003FF,
+	0x978, 0x00000000,
+	0x97C, 0x00000000,
+	0x980, 0x00000000,
+	0x984, 0x00000000,
+	0x988, 0x00000000,
+	0x990, 0x27100000,
+	0x994, 0xFFFF0100,
+	0x998, 0xFFFFFF5C,
+	0x99C, 0xFFFFFFFF,
+	0x9A0, 0x000000FF,
+	0x9A4, 0x00480080,
+	0x9A8, 0x00000000,
+	0x9AC, 0x00000000,
+	0x9B0, 0x81081008,
+	0x9B4, 0x01081008,
+	0x9B8, 0x01081008,
+	0x9BC, 0x01081008,
+	0x9D0, 0x00000000,
+	0x9D4, 0x00000000,
+	0x9D8, 0x00000000,
+	0x9DC, 0x00000000,
+	0x9E0, 0x00005D00,
+	0x9E4, 0x00000002,
+	0x9E8, 0x00000001,
+	0xA00, 0x00D047C8,
+	0xA04, 0x01FF000C,
+	0xA08, 0x8C8A8300,
+	0xA0C, 0x2E68000F,
+	0xA10, 0x9500BB78,
+	0xA14, 0x11144028,
+	0xA18, 0x00881117,
+	0xA1C, 0x89140F00,
+	0xA20, 0x1A1B0000,
+	0xA24, 0x090E1317,
+	0xA28, 0x00000204,
+	0xA2C, 0x00900000,
+	0xA70, 0x101FFF00,
+	0xA74, 0x00000008,
+	0xA78, 0x00000900,
+	0xA7C, 0x225B0606,
+	0xA80, 0x21805490,
+	0xA84, 0x001F0000,
+	0xB00, 0x03100040,
+	0xB04, 0x0000B000,
+	0xB08, 0xAE0201EB,
+	0xB0C, 0x01003207,
+	0xB10, 0x00009807,
+	0xB14, 0x01000000,
+	0xB18, 0x00000002,
+	0xB1C, 0x00000002,
+	0xB20, 0x0000001F,
+	0xB24, 0x03020100,
+	0xB28, 0x07060504,
+	0xB2C, 0x0B0A0908,
+	0xB30, 0x0F0E0D0C,
+	0xB34, 0x13121110,
+	0xB38, 0x17161514,
+	0xB3C, 0x0000003A,
+	0xB40, 0x00000000,
+	0xB44, 0x00000000,
+	0xB48, 0x13000032,
+	0xB4C, 0x48080000,
+	0xB50, 0x00000000,
+	0xB54, 0x00000000,
+	0xB58, 0x00000000,
+	0xB5C, 0x00000000,
+	0xC00, 0x00000007,
+	0xC04, 0x00042020,
+	0xC08, 0x80410231,
+	0xC0C, 0x00000000,
+	0xC10, 0x00000100,
+	0xC14, 0x01000000,
+	0xC1C, 0x40000003,
+	0xC20, 0x2C2C2C2C,
+	0xC24, 0x30303030,
+	0xC28, 0x30303030,
+	0xC2C, 0x2C2C2C2C,
+	0xC30, 0x2C2C2C2C,
+	0xC34, 0x2C2C2C2C,
+	0xC38, 0x2C2C2C2C,
+	0xC3C, 0x2A2A2A2A,
+	0xC40, 0x2A2A2A2A,
+	0xC44, 0x2A2A2A2A,
+	0xC48, 0x2A2A2A2A,
+	0xC4C, 0x2A2A2A2A,
+	0xC50, 0x00000020,
+	0xC54, 0x001C1208,
+	0xC58, 0x30000C1C,
+	0xC5C, 0x00000058,
+	0xC60, 0x34344443,
+	0xC64, 0x07003333,
+	0xC68, 0x19791979,
+	0xC6C, 0x19791979,
+	0xC70, 0x19791979,
+	0xC74, 0x19791979,
+	0xC78, 0x19791979,
+	0xC7C, 0x19791979,
+	0xC80, 0x19791979,
+	0xC84, 0x19791979,
+	0xC94, 0x0100005C,
+	0xC98, 0x00000000,
+	0xC9C, 0x00000000,
+	0xCA0, 0x00000029,
+	0xCA4, 0x08040201,
+	0xCA8, 0x80402010,
+	0xCB0, 0x77775747,
+	0xCB4, 0x10000077,
+	0xCB8, 0x00508240,
+};
+
+u32 RTL8812AE_PHY_REG_ARRAY_PG[] = {
+	0, 0, 0, 0x00000c20, 0xffffffff, 0x34363840,
+	0, 0, 0, 0x00000c24, 0xffffffff, 0x42424444,
+	0, 0, 0, 0x00000c28, 0xffffffff, 0x30323638,
+	0, 0, 0, 0x00000c2c, 0xffffffff, 0x40424444,
+	0, 0, 0, 0x00000c30, 0xffffffff, 0x28303236,
+	0, 0, 1, 0x00000c34, 0xffffffff, 0x38404242,
+	0, 0, 1, 0x00000c38, 0xffffffff, 0x26283034,
+	0, 0, 0, 0x00000c3c, 0xffffffff, 0x40424444,
+	0, 0, 0, 0x00000c40, 0xffffffff, 0x28303236,
+	0, 0, 0, 0x00000c44, 0xffffffff, 0x42422426,
+	0, 0, 1, 0x00000c48, 0xffffffff, 0x30343840,
+	0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628,
+	0, 1, 0, 0x00000e20, 0xffffffff, 0x34363840,
+	0, 1, 0, 0x00000e24, 0xffffffff, 0x42424444,
+	0, 1, 0, 0x00000e28, 0xffffffff, 0x30323638,
+	0, 1, 0, 0x00000e2c, 0xffffffff, 0x40424444,
+	0, 1, 0, 0x00000e30, 0xffffffff, 0x28303236,
+	0, 1, 1, 0x00000e34, 0xffffffff, 0x38404242,
+	0, 1, 1, 0x00000e38, 0xffffffff, 0x26283034,
+	0, 1, 0, 0x00000e3c, 0xffffffff, 0x40424444,
+	0, 1, 0, 0x00000e40, 0xffffffff, 0x28303236,
+	0, 1, 0, 0x00000e44, 0xffffffff, 0x42422426,
+	0, 1, 1, 0x00000e48, 0xffffffff, 0x30343840,
+	0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628,
+	1, 0, 0, 0x00000c24, 0xffffffff, 0x42424444,
+	1, 0, 0, 0x00000c28, 0xffffffff, 0x30323640,
+	1, 0, 0, 0x00000c2c, 0xffffffff, 0x40424444,
+	1, 0, 0, 0x00000c30, 0xffffffff, 0x28303236,
+	1, 0, 1, 0x00000c34, 0xffffffff, 0x38404242,
+	1, 0, 1, 0x00000c38, 0xffffffff, 0x26283034,
+	1, 0, 0, 0x00000c3c, 0xffffffff, 0x40424444,
+	1, 0, 0, 0x00000c40, 0xffffffff, 0x28303236,
+	1, 0, 0, 0x00000c44, 0xffffffff, 0x42422426,
+	1, 0, 1, 0x00000c48, 0xffffffff, 0x30343840,
+	1, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628,
+	1, 1, 0, 0x00000e24, 0xffffffff, 0x42424444,
+	1, 1, 0, 0x00000e28, 0xffffffff, 0x30323640,
+	1, 1, 0, 0x00000e2c, 0xffffffff, 0x40424444,
+	1, 1, 0, 0x00000e30, 0xffffffff, 0x28303236,
+	1, 1, 1, 0x00000e34, 0xffffffff, 0x38404242,
+	1, 1, 1, 0x00000e38, 0xffffffff, 0x26283034,
+	1, 1, 0, 0x00000e3c, 0xffffffff, 0x40424444,
+	1, 1, 0, 0x00000e40, 0xffffffff, 0x28303236,
+	1, 1, 0, 0x00000e44, 0xffffffff, 0x42422426,
+	1, 1, 1, 0x00000e48, 0xffffffff, 0x30343840,
+	1, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628
+};
+
+u32 RTL8821AE_PHY_REG_ARRAY_PG[] = {
+	0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638,
+	0, 0, 0, 0x00000c24, 0xffffffff, 0x36363838,
+	0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234,
+	0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363838,
+	0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032,
+	0, 0, 0, 0x00000c3c, 0xffffffff, 0x32343636,
+	0, 0, 0, 0x00000c40, 0xffffffff, 0x24262830,
+	0, 0, 0, 0x00000c44, 0x0000ffff, 0x00002022,
+	1, 0, 0, 0x00000c24, 0xffffffff, 0x34343636,
+	1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032,
+	1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343636,
+	1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830,
+	1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343636,
+	1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830,
+	1, 0, 0, 0x00000c44, 0x0000ffff, 0x00002022
+};
+
+u32 RTL8812AE_RADIOA_ARRAY[] = {
+		0x000, 0x00010000,
+		0x018, 0x0001712A,
+		0x056, 0x00051CF2,
+		0x066, 0x00040000,
+		0x01E, 0x00080000,
+		0x089, 0x00000080,
+	0xFF0F0740, 0xABCD,
+		0x086, 0x00014B38,
+	0xFF0F02C0, 0xCDEF,
+		0x086, 0x00014B38,
+	0xFF0F01C0, 0xCDEF,
+		0x086, 0x00014B38,
+	0xFF0F07D8, 0xCDEF,
+		0x086, 0x00014B3A,
+	0xFF0F07D0, 0xCDEF,
+		0x086, 0x00014B3A,
+	0xCDCDCDCD, 0xCDCD,
+		0x086, 0x00014B38,
+	0xFF0F0740, 0xDEAD,
+		0x0B1, 0x0001FC1A,
+		0x0B3, 0x000F0810,
+		0x0B4, 0x0001A78D,
+		0x0BA, 0x00086180,
+		0x018, 0x00000006,
+		0x0EF, 0x00002000,
+	0xFF0F07D8, 0xABCD,
+		0x03B, 0x0003F218,
+		0x03B, 0x00030A58,
+		0x03B, 0x0002FA58,
+		0x03B, 0x00022590,
+		0x03B, 0x0001FA50,
+		0x03B, 0x00010248,
+		0x03B, 0x00008240,
+	0xFF0F07D0, 0xCDEF,
+		0x03B, 0x0003F218,
+		0x03B, 0x00030A58,
+		0x03B, 0x0002FA58,
+		0x03B, 0x00022590,
+		0x03B, 0x0001FA50,
+		0x03B, 0x00010248,
+		0x03B, 0x00008240,
+	0xCDCDCDCD, 0xCDCD,
+		0x03B, 0x00038A58,
+		0x03B, 0x00037A58,
+		0x03B, 0x0002A590,
+		0x03B, 0x00027A50,
+		0x03B, 0x00018248,
+		0x03B, 0x00010240,
+		0x03B, 0x00008240,
+	0xFF0F07D8, 0xDEAD,
+		0x0EF, 0x00000100,
+	0xFF0F07D8, 0xABCD,
+		0x034, 0x0000A4EE,
+		0x034, 0x00009076,
+		0x034, 0x00008073,
+		0x034, 0x00007070,
+		0x034, 0x0000606D,
+		0x034, 0x0000506A,
+		0x034, 0x00004049,
+		0x034, 0x00003046,
+		0x034, 0x00002028,
+		0x034, 0x00001025,
+		0x034, 0x00000022,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0000ADF4,
+		0x034, 0x00009DF1,
+		0x034, 0x00008DEE,
+		0x034, 0x00007DEB,
+		0x034, 0x00006DE8,
+		0x034, 0x00005CEC,
+		0x034, 0x00004CE9,
+		0x034, 0x000034EA,
+		0x034, 0x000024E7,
+		0x034, 0x0000146B,
+		0x034, 0x0000006D,
+	0xFF0F07D8, 0xDEAD,
+		0x0EF, 0x00000000,
+		0x0EF, 0x000020A2,
+		0x0DF, 0x00000080,
+		0x035, 0x00000192,
+		0x035, 0x00008192,
+		0x035, 0x00010192,
+		0x036, 0x00000024,
+		0x036, 0x00008024,
+		0x036, 0x00010024,
+		0x036, 0x00018024,
+		0x0EF, 0x00000000,
+		0x051, 0x00000C21,
+		0x052, 0x000006D9,
+		0x053, 0x000FC649,
+		0x054, 0x0000017E,
+		0x0EF, 0x00000002,
+		0x008, 0x00008400,
+		0x018, 0x0001712A,
+		0x0EF, 0x00001000,
+		0x03A, 0x00000080,
+		0x03B, 0x0003A02C,
+		0x03C, 0x00004000,
+		0x03A, 0x00000400,
+		0x03B, 0x0003202C,
+		0x03C, 0x00010000,
+		0x03A, 0x000000A0,
+		0x03B, 0x0002B064,
+		0x03C, 0x00004000,
+		0x03A, 0x000000D8,
+		0x03B, 0x00023070,
+		0x03C, 0x00004000,
+		0x03A, 0x00000468,
+		0x03B, 0x0001B870,
+		0x03C, 0x00010000,
+		0x03A, 0x00000098,
+		0x03B, 0x00012085,
+		0x03C, 0x000E4000,
+		0x03A, 0x00000418,
+		0x03B, 0x0000A080,
+		0x03C, 0x000F0000,
+		0x03A, 0x00000418,
+		0x03B, 0x00002080,
+		0x03C, 0x00010000,
+		0x03A, 0x00000080,
+		0x03B, 0x0007A02C,
+		0x03C, 0x00004000,
+		0x03A, 0x00000400,
+		0x03B, 0x0007202C,
+		0x03C, 0x00010000,
+		0x03A, 0x000000A0,
+		0x03B, 0x0006B064,
+		0x03C, 0x00004000,
+		0x03A, 0x000000D8,
+		0x03B, 0x00023070,
+		0x03C, 0x00004000,
+		0x03A, 0x00000468,
+		0x03B, 0x0005B870,
+		0x03C, 0x00010000,
+		0x03A, 0x00000098,
+		0x03B, 0x00052085,
+		0x03C, 0x000E4000,
+		0x03A, 0x00000418,
+		0x03B, 0x0004A080,
+		0x03C, 0x000F0000,
+		0x03A, 0x00000418,
+		0x03B, 0x00042080,
+		0x03C, 0x00010000,
+		0x03A, 0x00000080,
+		0x03B, 0x000BA02C,
+		0x03C, 0x00004000,
+		0x03A, 0x00000400,
+		0x03B, 0x000B202C,
+		0x03C, 0x00010000,
+		0x03A, 0x000000A0,
+		0x03B, 0x000AB064,
+		0x03C, 0x00004000,
+		0x03A, 0x000000D8,
+		0x03B, 0x000A3070,
+		0x03C, 0x00004000,
+		0x03A, 0x00000468,
+		0x03B, 0x0009B870,
+		0x03C, 0x00010000,
+		0x03A, 0x00000098,
+		0x03B, 0x00092085,
+		0x03C, 0x000E4000,
+		0x03A, 0x00000418,
+		0x03B, 0x0008A080,
+		0x03C, 0x000F0000,
+		0x03A, 0x00000418,
+		0x03B, 0x00082080,
+		0x03C, 0x00010000,
+		0x0EF, 0x00001100,
+	0xFF0F0740, 0xABCD,
+		0x034, 0x0004A0B2,
+		0x034, 0x000490AF,
+		0x034, 0x00048070,
+		0x034, 0x0004706D,
+		0x034, 0x00046050,
+		0x034, 0x0004504D,
+		0x034, 0x0004404A,
+		0x034, 0x00043047,
+		0x034, 0x0004200A,
+		0x034, 0x00041007,
+		0x034, 0x00040004,
+	0xFF0F02C0, 0xCDEF,
+		0x034, 0x0004A0B2,
+		0x034, 0x000490AF,
+		0x034, 0x00048070,
+		0x034, 0x0004706D,
+		0x034, 0x00046050,
+		0x034, 0x0004504D,
+		0x034, 0x0004404A,
+		0x034, 0x00043047,
+		0x034, 0x0004200A,
+		0x034, 0x00041007,
+		0x034, 0x00040004,
+	0xFF0F01C0, 0xCDEF,
+		0x034, 0x0004A0B2,
+		0x034, 0x000490AF,
+		0x034, 0x00048070,
+		0x034, 0x0004706D,
+		0x034, 0x00046050,
+		0x034, 0x0004504D,
+		0x034, 0x0004404A,
+		0x034, 0x00043047,
+		0x034, 0x0004200A,
+		0x034, 0x00041007,
+		0x034, 0x00040004,
+	0xFF0F07D8, 0xCDEF,
+		0x034, 0x0004A0B2,
+		0x034, 0x000490AF,
+		0x034, 0x00048070,
+		0x034, 0x0004706D,
+		0x034, 0x00046050,
+		0x034, 0x0004504D,
+		0x034, 0x0004404A,
+		0x034, 0x00043047,
+		0x034, 0x0004200A,
+		0x034, 0x00041007,
+		0x034, 0x00040004,
+	0xFF0F07D0, 0xCDEF,
+		0x034, 0x0004A0B2,
+		0x034, 0x000490AF,
+		0x034, 0x00048070,
+		0x034, 0x0004706D,
+		0x034, 0x00046050,
+		0x034, 0x0004504D,
+		0x034, 0x0004404A,
+		0x034, 0x00043047,
+		0x034, 0x0004200A,
+		0x034, 0x00041007,
+		0x034, 0x00040004,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0004ADF5,
+		0x034, 0x00049DF2,
+		0x034, 0x00048DEF,
+		0x034, 0x00047DEC,
+		0x034, 0x00046DE9,
+		0x034, 0x00045DC9,
+		0x034, 0x00044CE8,
+		0x034, 0x000438CA,
+		0x034, 0x00042889,
+		0x034, 0x0004184A,
+		0x034, 0x0004044A,
+	0xFF0F0740, 0xDEAD,
+	0xFF0F0740, 0xABCD,
+		0x034, 0x0002A0B2,
+		0x034, 0x000290AF,
+		0x034, 0x00028070,
+		0x034, 0x0002706D,
+		0x034, 0x00026050,
+		0x034, 0x0002504D,
+		0x034, 0x0002404A,
+		0x034, 0x00023047,
+		0x034, 0x0002200A,
+		0x034, 0x00021007,
+		0x034, 0x00020004,
+	0xFF0F02C0, 0xCDEF,
+		0x034, 0x0002A0B2,
+		0x034, 0x000290AF,
+		0x034, 0x00028070,
+		0x034, 0x0002706D,
+		0x034, 0x00026050,
+		0x034, 0x0002504D,
+		0x034, 0x0002404A,
+		0x034, 0x00023047,
+		0x034, 0x0002200A,
+		0x034, 0x00021007,
+		0x034, 0x00020004,
+	0xFF0F01C0, 0xCDEF,
+		0x034, 0x0002A0B2,
+		0x034, 0x000290AF,
+		0x034, 0x00028070,
+		0x034, 0x0002706D,
+		0x034, 0x00026050,
+		0x034, 0x0002504D,
+		0x034, 0x0002404A,
+		0x034, 0x00023047,
+		0x034, 0x0002200A,
+		0x034, 0x00021007,
+		0x034, 0x00020004,
+	0xFF0F07D8, 0xCDEF,
+		0x034, 0x0002A0B2,
+		0x034, 0x000290AF,
+		0x034, 0x00028070,
+		0x034, 0x0002706D,
+		0x034, 0x00026050,
+		0x034, 0x0002504D,
+		0x034, 0x0002404A,
+		0x034, 0x00023047,
+		0x034, 0x0002200A,
+		0x034, 0x00021007,
+		0x034, 0x00020004,
+	0xFF0F07D0, 0xCDEF,
+		0x034, 0x0002A0B2,
+		0x034, 0x000290AF,
+		0x034, 0x00028070,
+		0x034, 0x0002706D,
+		0x034, 0x00026050,
+		0x034, 0x0002504D,
+		0x034, 0x0002404A,
+		0x034, 0x00023047,
+		0x034, 0x0002200A,
+		0x034, 0x00021007,
+		0x034, 0x00020004,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0002ADF5,
+		0x034, 0x00029DF2,
+		0x034, 0x00028DEF,
+		0x034, 0x00027DEC,
+		0x034, 0x00026DE9,
+		0x034, 0x00025DC9,
+		0x034, 0x00024CE8,
+		0x034, 0x000238CA,
+		0x034, 0x00022889,
+		0x034, 0x0002184A,
+		0x034, 0x0002044A,
+	0xFF0F0740, 0xDEAD,
+	0xFF0F0740, 0xABCD,
+		0x034, 0x0000A0B2,
+		0x034, 0x000090AF,
+		0x034, 0x00008070,
+		0x034, 0x0000706D,
+		0x034, 0x00006050,
+		0x034, 0x0000504D,
+		0x034, 0x0000404A,
+		0x034, 0x00003047,
+		0x034, 0x0000200A,
+		0x034, 0x00001007,
+		0x034, 0x00000004,
+	0xFF0F02C0, 0xCDEF,
+		0x034, 0x0000A0B2,
+		0x034, 0x000090AF,
+		0x034, 0x00008070,
+		0x034, 0x0000706D,
+		0x034, 0x00006050,
+		0x034, 0x0000504D,
+		0x034, 0x0000404A,
+		0x034, 0x00003047,
+		0x034, 0x0000200A,
+		0x034, 0x00001007,
+		0x034, 0x00000004,
+	0xFF0F01C0, 0xCDEF,
+		0x034, 0x0000A0B2,
+		0x034, 0x000090AF,
+		0x034, 0x00008070,
+		0x034, 0x0000706D,
+		0x034, 0x00006050,
+		0x034, 0x0000504D,
+		0x034, 0x0000404A,
+		0x034, 0x00003047,
+		0x034, 0x0000200A,
+		0x034, 0x00001007,
+		0x034, 0x00000004,
+	0xFF0F07D8, 0xCDEF,
+		0x034, 0x0000A0B2,
+		0x034, 0x000090AF,
+		0x034, 0x00008070,
+		0x034, 0x0000706D,
+		0x034, 0x00006050,
+		0x034, 0x0000504D,
+		0x034, 0x0000404A,
+		0x034, 0x00003047,
+		0x034, 0x0000200A,
+		0x034, 0x00001007,
+		0x034, 0x00000004,
+	0xFF0F07D0, 0xCDEF,
+		0x034, 0x0000A0B2,
+		0x034, 0x000090AF,
+		0x034, 0x00008070,
+		0x034, 0x0000706D,
+		0x034, 0x00006050,
+		0x034, 0x0000504D,
+		0x034, 0x0000404A,
+		0x034, 0x00003047,
+		0x034, 0x0000200A,
+		0x034, 0x00001007,
+		0x034, 0x00000004,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0000AFF7,
+		0x034, 0x00009DF7,
+		0x034, 0x00008DF4,
+		0x034, 0x00007DF1,
+		0x034, 0x00006DEE,
+		0x034, 0x00005DCD,
+		0x034, 0x00004CEB,
+		0x034, 0x000038CC,
+		0x034, 0x0000288B,
+		0x034, 0x0000184C,
+		0x034, 0x0000044C,
+	0xFF0F0740, 0xDEAD,
+		0x0EF, 0x00000000,
+	0xFF0F0740, 0xABCD,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+		0x035, 0x000001D4,
+		0x035, 0x000081D4,
+		0x035, 0x000101D4,
+		0x035, 0x000201B4,
+		0x035, 0x000281B4,
+		0x035, 0x000301B4,
+		0x035, 0x000401B4,
+		0x035, 0x000481B4,
+		0x035, 0x000501B4,
+	0xFF0F02C0, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+		0x035, 0x000001D4,
+		0x035, 0x000081D4,
+		0x035, 0x000101D4,
+		0x035, 0x000201B4,
+		0x035, 0x000281B4,
+		0x035, 0x000301B4,
+		0x035, 0x000401B4,
+		0x035, 0x000481B4,
+		0x035, 0x000501B4,
+	0xFF0F01C0, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+		0x035, 0x000001D4,
+		0x035, 0x000081D4,
+		0x035, 0x000101D4,
+		0x035, 0x000201B4,
+		0x035, 0x000281B4,
+		0x035, 0x000301B4,
+		0x035, 0x000401B4,
+		0x035, 0x000481B4,
+		0x035, 0x000501B4,
+	0xFF0F07D8, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+		0x035, 0x000001D4,
+		0x035, 0x000081D4,
+		0x035, 0x000101D4,
+		0x035, 0x000201B4,
+		0x035, 0x000281B4,
+		0x035, 0x000301B4,
+		0x035, 0x000401B4,
+		0x035, 0x000481B4,
+		0x035, 0x000501B4,
+	0xFF0F07D0, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+		0x035, 0x000001D4,
+		0x035, 0x000081D4,
+		0x035, 0x000101D4,
+		0x035, 0x000201B4,
+		0x035, 0x000281B4,
+		0x035, 0x000301B4,
+		0x035, 0x000401B4,
+		0x035, 0x000481B4,
+		0x035, 0x000501B4,
+	0xCDCDCDCD, 0xCDCD,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+		0x035, 0x00000188,
+		0x035, 0x00008147,
+		0x035, 0x00010147,
+		0x035, 0x000201D7,
+		0x035, 0x000281D7,
+		0x035, 0x000301D7,
+		0x035, 0x000401D8,
+		0x035, 0x000481D8,
+		0x035, 0x000501D8,
+	0xFF0F0740, 0xDEAD,
+		0x0EF, 0x00000000,
+	0xFF0F0740, 0xABCD,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+		0x036, 0x00004BFB,
+		0x036, 0x0000CBFB,
+		0x036, 0x00014BFB,
+		0x036, 0x0001CBFB,
+		0x036, 0x00024F4B,
+		0x036, 0x0002CF4B,
+		0x036, 0x00034F4B,
+		0x036, 0x0003CF4B,
+		0x036, 0x00044F4B,
+		0x036, 0x0004CF4B,
+		0x036, 0x00054F4B,
+		0x036, 0x0005CF4B,
+	0xFF0F02C0, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+		0x036, 0x00004BFB,
+		0x036, 0x0000CBFB,
+		0x036, 0x00014BFB,
+		0x036, 0x0001CBFB,
+		0x036, 0x00024F4B,
+		0x036, 0x0002CF4B,
+		0x036, 0x00034F4B,
+		0x036, 0x0003CF4B,
+		0x036, 0x00044F4B,
+		0x036, 0x0004CF4B,
+		0x036, 0x00054F4B,
+		0x036, 0x0005CF4B,
+	0xFF0F01C0, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+		0x036, 0x00004BFB,
+		0x036, 0x0000CBFB,
+		0x036, 0x00014BFB,
+		0x036, 0x0001CBFB,
+		0x036, 0x00024F4B,
+		0x036, 0x0002CF4B,
+		0x036, 0x00034F4B,
+		0x036, 0x0003CF4B,
+		0x036, 0x00044F4B,
+		0x036, 0x0004CF4B,
+		0x036, 0x00054F4B,
+		0x036, 0x0005CF4B,
+	0xFF0F07D8, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+		0x036, 0x00004BFB,
+		0x036, 0x0000CBFB,
+		0x036, 0x00014BFB,
+		0x036, 0x0001CBFB,
+		0x036, 0x00024F4B,
+		0x036, 0x0002CF4B,
+		0x036, 0x00034F4B,
+		0x036, 0x0003CF4B,
+		0x036, 0x00044F4B,
+		0x036, 0x0004CF4B,
+		0x036, 0x00054F4B,
+		0x036, 0x0005CF4B,
+	0xFF0F07D0, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+		0x036, 0x00004BFB,
+		0x036, 0x0000CBFB,
+		0x036, 0x00014BFB,
+		0x036, 0x0001CBFB,
+		0x036, 0x00024F4B,
+		0x036, 0x0002CF4B,
+		0x036, 0x00034F4B,
+		0x036, 0x0003CF4B,
+		0x036, 0x00044F4B,
+		0x036, 0x0004CF4B,
+		0x036, 0x00054F4B,
+		0x036, 0x0005CF4B,
+	0xCDCDCDCD, 0xCDCD,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+		0x036, 0x00084EB4,
+		0x036, 0x0008CC35,
+		0x036, 0x00094C35,
+		0x036, 0x0009CC35,
+		0x036, 0x000A4935,
+		0x036, 0x000ACC35,
+		0x036, 0x000B4C35,
+		0x036, 0x000BCC35,
+		0x036, 0x000C4EB4,
+		0x036, 0x000CCEB5,
+		0x036, 0x000D4EB5,
+		0x036, 0x000DCEB5,
+	0xFF0F0740, 0xDEAD,
+		0x0EF, 0x00000000,
+		0x0EF, 0x00000008,
+	0xFF0F0740, 0xABCD,
+		0x03C, 0x000002CC,
+		0x03C, 0x00000522,
+		0x03C, 0x00000902,
+	0xFF0F02C0, 0xCDEF,
+		0x03C, 0x000002CC,
+		0x03C, 0x00000522,
+		0x03C, 0x00000902,
+	0xFF0F01C0, 0xCDEF,
+		0x03C, 0x000002CC,
+		0x03C, 0x00000522,
+		0x03C, 0x00000902,
+	0xFF0F07D8, 0xCDEF,
+		0x03C, 0x000002CC,
+		0x03C, 0x00000522,
+		0x03C, 0x00000902,
+	0xFF0F07D0, 0xCDEF,
+		0x03C, 0x000002CC,
+		0x03C, 0x00000522,
+		0x03C, 0x00000902,
+	0xCDCDCDCD, 0xCDCD,
+		0x03C, 0x000002A8,
+		0x03C, 0x000005A2,
+		0x03C, 0x00000880,
+	0xFF0F0740, 0xDEAD,
+		0x0EF, 0x00000000,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000002,
+		0x0DF, 0x00000080,
+		0x01F, 0x00040064,
+	0xFF0F0740, 0xABCD,
+		0x061, 0x000FDD43,
+		0x062, 0x00038F4B,
+		0x063, 0x00032117,
+		0x064, 0x000194AC,
+		0x065, 0x000931D1,
+	0xFF0F02C0, 0xCDEF,
+		0x061, 0x000FDD43,
+		0x062, 0x00038F4B,
+		0x063, 0x00032117,
+		0x064, 0x000194AC,
+		0x065, 0x000931D1,
+	0xFF0F01C0, 0xCDEF,
+		0x061, 0x000FDD43,
+		0x062, 0x00038F4B,
+		0x063, 0x00032117,
+		0x064, 0x000194AC,
+		0x065, 0x000931D1,
+	0xFF0F07D8, 0xCDEF,
+		0x061, 0x000FDD43,
+		0x062, 0x00038F4B,
+		0x063, 0x00032117,
+		0x064, 0x000194AC,
+		0x065, 0x000931D1,
+	0xFF0F07D0, 0xCDEF,
+		0x061, 0x000FDD43,
+		0x062, 0x00038F4B,
+		0x063, 0x00032117,
+		0x064, 0x000194AC,
+		0x065, 0x000931D1,
+	0xCDCDCDCD, 0xCDCD,
+		0x061, 0x000E5D53,
+		0x062, 0x00038FCD,
+		0x063, 0x000314EB,
+		0x064, 0x000196AC,
+		0x065, 0x000911D7,
+	0xFF0F0740, 0xDEAD,
+		0x008, 0x00008400,
+		0x01C, 0x000739D2,
+		0x0B4, 0x0001E78D,
+		0x018, 0x0001F12A,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x0B4, 0x0001A78D,
+		0x018, 0x0001712A,
+
+};
+
+u32 RTL8812AE_RADIOB_ARRAY[] = {
+		0x056, 0x00051CF2,
+		0x066, 0x00040000,
+		0x089, 0x00000080,
+	0xFF0F0740, 0xABCD,
+		0x086, 0x00014B38,
+	0xFF0F01C0, 0xCDEF,
+		0x086, 0x00014B38,
+	0xFF0F02C0, 0xCDEF,
+		0x086, 0x00014B38,
+	0xFF0F07D8, 0xCDEF,
+		0x086, 0x00014B3A,
+	0xFF0F07D0, 0xCDEF,
+		0x086, 0x00014B3A,
+	0xCDCDCDCD, 0xCDCD,
+		0x086, 0x00014B38,
+	0xFF0F0740, 0xDEAD,
+		0x018, 0x00000006,
+		0x0EF, 0x00002000,
+	0xFF0F07D8, 0xABCD,
+		0x03B, 0x0003F218,
+		0x03B, 0x00030A58,
+		0x03B, 0x0002FA58,
+		0x03B, 0x00022590,
+		0x03B, 0x0001FA50,
+		0x03B, 0x00010248,
+		0x03B, 0x00008240,
+	0xFF0F07D0, 0xCDEF,
+		0x03B, 0x0003F218,
+		0x03B, 0x00030A58,
+		0x03B, 0x0002FA58,
+		0x03B, 0x00022590,
+		0x03B, 0x0001FA50,
+		0x03B, 0x00010248,
+		0x03B, 0x00008240,
+	0xCDCDCDCD, 0xCDCD,
+		0x03B, 0x00038A58,
+		0x03B, 0x00037A58,
+		0x03B, 0x0002A590,
+		0x03B, 0x00027A50,
+		0x03B, 0x00018248,
+		0x03B, 0x00010240,
+		0x03B, 0x00008240,
+	0xFF0F07D8, 0xDEAD,
+		0x0EF, 0x00000100,
+	0xFF0F07D8, 0xABCD,
+		0x034, 0x0000A4EE,
+		0x034, 0x00009076,
+		0x034, 0x00008073,
+		0x034, 0x00007070,
+		0x034, 0x0000606D,
+		0x034, 0x0000506A,
+		0x034, 0x00004049,
+		0x034, 0x00003046,
+		0x034, 0x00002028,
+		0x034, 0x00001025,
+		0x034, 0x00000022,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0000ADF4,
+		0x034, 0x00009DF1,
+		0x034, 0x00008DEE,
+		0x034, 0x00007DEB,
+		0x034, 0x00006DE8,
+		0x034, 0x00005CEC,
+		0x034, 0x00004CE9,
+		0x034, 0x000034EA,
+		0x034, 0x000024E7,
+		0x034, 0x0000146B,
+		0x034, 0x0000006D,
+	0xFF0F07D8, 0xDEAD,
+		0x0EF, 0x00000000,
+		0x0EF, 0x000020A2,
+		0x0DF, 0x00000080,
+		0x035, 0x00000192,
+		0x035, 0x00008192,
+		0x035, 0x00010192,
+		0x036, 0x00000024,
+		0x036, 0x00008024,
+		0x036, 0x00010024,
+		0x036, 0x00018024,
+		0x0EF, 0x00000000,
+		0x051, 0x00000C21,
+		0x052, 0x000006D9,
+		0x053, 0x000FC649,
+		0x054, 0x0000017E,
+		0x0EF, 0x00000002,
+		0x008, 0x00008400,
+		0x018, 0x0001712A,
+		0x0EF, 0x00001000,
+		0x03A, 0x00000080,
+		0x03B, 0x0003A02C,
+		0x03C, 0x00004000,
+		0x03A, 0x00000400,
+		0x03B, 0x0003202C,
+		0x03C, 0x00010000,
+		0x03A, 0x000000A0,
+		0x03B, 0x0002B064,
+		0x03C, 0x00004000,
+		0x03A, 0x000000D8,
+		0x03B, 0x00023070,
+		0x03C, 0x00004000,
+		0x03A, 0x00000468,
+		0x03B, 0x0001B870,
+		0x03C, 0x00010000,
+		0x03A, 0x00000098,
+		0x03B, 0x00012085,
+		0x03C, 0x000E4000,
+		0x03A, 0x00000418,
+		0x03B, 0x0000A080,
+		0x03C, 0x000F0000,
+		0x03A, 0x00000418,
+		0x03B, 0x00002080,
+		0x03C, 0x00010000,
+		0x03A, 0x00000080,
+		0x03B, 0x0007A02C,
+		0x03C, 0x00004000,
+		0x03A, 0x00000400,
+		0x03B, 0x0007202C,
+		0x03C, 0x00010000,
+		0x03A, 0x000000A0,
+		0x03B, 0x0006B064,
+		0x03C, 0x00004000,
+		0x03A, 0x000000D8,
+		0x03B, 0x00063070,
+		0x03C, 0x00004000,
+		0x03A, 0x00000468,
+		0x03B, 0x0005B870,
+		0x03C, 0x00010000,
+		0x03A, 0x00000098,
+		0x03B, 0x00052085,
+		0x03C, 0x000E4000,
+		0x03A, 0x00000418,
+		0x03B, 0x0004A080,
+		0x03C, 0x000F0000,
+		0x03A, 0x00000418,
+		0x03B, 0x00042080,
+		0x03C, 0x00010000,
+		0x03A, 0x00000080,
+		0x03B, 0x000BA02C,
+		0x03C, 0x00004000,
+		0x03A, 0x00000400,
+		0x03B, 0x000B202C,
+		0x03C, 0x00010000,
+		0x03A, 0x000000A0,
+		0x03B, 0x000AB064,
+		0x03C, 0x00004000,
+		0x03A, 0x000000D8,
+		0x03B, 0x000A3070,
+		0x03C, 0x00004000,
+		0x03A, 0x00000468,
+		0x03B, 0x0009B870,
+		0x03C, 0x00010000,
+		0x03A, 0x00000098,
+		0x03B, 0x00092085,
+		0x03C, 0x000E4000,
+		0x03A, 0x00000418,
+		0x03B, 0x0008A080,
+		0x03C, 0x000F0000,
+		0x03A, 0x00000418,
+		0x03B, 0x00082080,
+		0x03C, 0x00010000,
+		0x0EF, 0x00001100,
+	0xFF0F0740, 0xABCD,
+		0x034, 0x0004A0B2,
+		0x034, 0x000490AF,
+		0x034, 0x00048070,
+		0x034, 0x0004706D,
+		0x034, 0x00046050,
+		0x034, 0x0004504D,
+		0x034, 0x0004404A,
+		0x034, 0x00043047,
+		0x034, 0x0004200A,
+		0x034, 0x00041007,
+		0x034, 0x00040004,
+	0xFF0F01C0, 0xCDEF,
+		0x034, 0x0004A0B2,
+		0x034, 0x000490AF,
+		0x034, 0x00048070,
+		0x034, 0x0004706D,
+		0x034, 0x00046050,
+		0x034, 0x0004504D,
+		0x034, 0x0004404A,
+		0x034, 0x00043047,
+		0x034, 0x0004200A,
+		0x034, 0x00041007,
+		0x034, 0x00040004,
+	0xFF0F02C0, 0xCDEF,
+		0x034, 0x0004A0B2,
+		0x034, 0x000490AF,
+		0x034, 0x00048070,
+		0x034, 0x0004706D,
+		0x034, 0x00046050,
+		0x034, 0x0004504D,
+		0x034, 0x0004404A,
+		0x034, 0x00043047,
+		0x034, 0x0004200A,
+		0x034, 0x00041007,
+		0x034, 0x00040004,
+	0xFF0F07D8, 0xCDEF,
+		0x034, 0x0004A0B2,
+		0x034, 0x000490AF,
+		0x034, 0x00048070,
+		0x034, 0x0004706D,
+		0x034, 0x00046050,
+		0x034, 0x0004504D,
+		0x034, 0x0004404A,
+		0x034, 0x00043047,
+		0x034, 0x0004200A,
+		0x034, 0x00041007,
+		0x034, 0x00040004,
+	0xFF0F07D0, 0xCDEF,
+		0x034, 0x0004A0B2,
+		0x034, 0x000490AF,
+		0x034, 0x00048070,
+		0x034, 0x0004706D,
+		0x034, 0x00046050,
+		0x034, 0x0004504D,
+		0x034, 0x0004404A,
+		0x034, 0x00043047,
+		0x034, 0x0004200A,
+		0x034, 0x00041007,
+		0x034, 0x00040004,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0004ADF5,
+		0x034, 0x00049DF2,
+		0x034, 0x00048DEF,
+		0x034, 0x00047DEC,
+		0x034, 0x00046DE9,
+		0x034, 0x00045DC9,
+		0x034, 0x00044CE8,
+		0x034, 0x000438CA,
+		0x034, 0x00042889,
+		0x034, 0x0004184A,
+		0x034, 0x0004044A,
+	0xFF0F0740, 0xDEAD,
+	0xFF0F0740, 0xABCD,
+		0x034, 0x0002A0B2,
+		0x034, 0x000290AF,
+		0x034, 0x00028070,
+		0x034, 0x0002706D,
+		0x034, 0x00026050,
+		0x034, 0x0002504D,
+		0x034, 0x0002404A,
+		0x034, 0x00023047,
+		0x034, 0x0002200A,
+		0x034, 0x00021007,
+		0x034, 0x00020004,
+	0xFF0F01C0, 0xCDEF,
+		0x034, 0x0002A0B2,
+		0x034, 0x000290AF,
+		0x034, 0x00028070,
+		0x034, 0x0002706D,
+		0x034, 0x00026050,
+		0x034, 0x0002504D,
+		0x034, 0x0002404A,
+		0x034, 0x00023047,
+		0x034, 0x0002200A,
+		0x034, 0x00021007,
+		0x034, 0x00020004,
+	0xFF0F02C0, 0xCDEF,
+		0x034, 0x0002A0B2,
+		0x034, 0x000290AF,
+		0x034, 0x00028070,
+		0x034, 0x0002706D,
+		0x034, 0x00026050,
+		0x034, 0x0002504D,
+		0x034, 0x0002404A,
+		0x034, 0x00023047,
+		0x034, 0x0002200A,
+		0x034, 0x00021007,
+		0x034, 0x00020004,
+	0xFF0F07D8, 0xCDEF,
+		0x034, 0x0002A0B2,
+		0x034, 0x000290AF,
+		0x034, 0x00028070,
+		0x034, 0x0002706D,
+		0x034, 0x00026050,
+		0x034, 0x0002504D,
+		0x034, 0x0002404A,
+		0x034, 0x00023047,
+		0x034, 0x0002200A,
+		0x034, 0x00021007,
+		0x034, 0x00020004,
+	0xFF0F07D0, 0xCDEF,
+		0x034, 0x0002A0B2,
+		0x034, 0x000290AF,
+		0x034, 0x00028070,
+		0x034, 0x0002706D,
+		0x034, 0x00026050,
+		0x034, 0x0002504D,
+		0x034, 0x0002404A,
+		0x034, 0x00023047,
+		0x034, 0x0002200A,
+		0x034, 0x00021007,
+		0x034, 0x00020004,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0002ADF5,
+		0x034, 0x00029DF2,
+		0x034, 0x00028DEF,
+		0x034, 0x00027DEC,
+		0x034, 0x00026DE9,
+		0x034, 0x00025DC9,
+		0x034, 0x00024CE8,
+		0x034, 0x000238CA,
+		0x034, 0x00022889,
+		0x034, 0x0002184A,
+		0x034, 0x0002044A,
+	0xFF0F0740, 0xDEAD,
+	0xFF0F0740, 0xABCD,
+		0x034, 0x0000A0B2,
+		0x034, 0x000090AF,
+		0x034, 0x00008070,
+		0x034, 0x0000706D,
+		0x034, 0x00006050,
+		0x034, 0x0000504D,
+		0x034, 0x0000404A,
+		0x034, 0x00003047,
+		0x034, 0x0000200A,
+		0x034, 0x00001007,
+		0x034, 0x00000004,
+	0xFF0F01C0, 0xCDEF,
+		0x034, 0x0000A0B2,
+		0x034, 0x000090AF,
+		0x034, 0x00008070,
+		0x034, 0x0000706D,
+		0x034, 0x00006050,
+		0x034, 0x0000504D,
+		0x034, 0x0000404A,
+		0x034, 0x00003047,
+		0x034, 0x0000200A,
+		0x034, 0x00001007,
+		0x034, 0x00000004,
+	0xFF0F02C0, 0xCDEF,
+		0x034, 0x0000A0B2,
+		0x034, 0x000090AF,
+		0x034, 0x00008070,
+		0x034, 0x0000706D,
+		0x034, 0x00006050,
+		0x034, 0x0000504D,
+		0x034, 0x0000404A,
+		0x034, 0x00003047,
+		0x034, 0x0000200A,
+		0x034, 0x00001007,
+		0x034, 0x00000004,
+	0xFF0F07D8, 0xCDEF,
+		0x034, 0x0000A0B2,
+		0x034, 0x000090AF,
+		0x034, 0x00008070,
+		0x034, 0x0000706D,
+		0x034, 0x00006050,
+		0x034, 0x0000504D,
+		0x034, 0x0000404A,
+		0x034, 0x00003047,
+		0x034, 0x0000200A,
+		0x034, 0x00001007,
+		0x034, 0x00000004,
+	0xFF0F07D0, 0xCDEF,
+		0x034, 0x0000A0B2,
+		0x034, 0x000090AF,
+		0x034, 0x00008070,
+		0x034, 0x0000706D,
+		0x034, 0x00006050,
+		0x034, 0x0000504D,
+		0x034, 0x0000404A,
+		0x034, 0x00003047,
+		0x034, 0x0000200A,
+		0x034, 0x00001007,
+		0x034, 0x00000004,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0000AFF7,
+		0x034, 0x00009DF7,
+		0x034, 0x00008DF4,
+		0x034, 0x00007DF1,
+		0x034, 0x00006DEE,
+		0x034, 0x00005DCD,
+		0x034, 0x00004CEB,
+		0x034, 0x000038CC,
+		0x034, 0x0000288B,
+		0x034, 0x0000184C,
+		0x034, 0x0000044C,
+	0xFF0F0740, 0xDEAD,
+		0x0EF, 0x00000000,
+	0xFF0F0740, 0xABCD,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+		0x035, 0x000001C5,
+		0x035, 0x000081C5,
+		0x035, 0x000101C5,
+		0x035, 0x00020174,
+		0x035, 0x00028174,
+		0x035, 0x00030174,
+		0x035, 0x00040185,
+		0x035, 0x00048185,
+		0x035, 0x00050185,
+		0x0EF, 0x00000000,
+	0xFF0F01C0, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+		0x035, 0x000001C5,
+		0x035, 0x000081C5,
+		0x035, 0x000101C5,
+		0x035, 0x00020174,
+		0x035, 0x00028174,
+		0x035, 0x00030174,
+		0x035, 0x00040185,
+		0x035, 0x00048185,
+		0x035, 0x00050185,
+		0x0EF, 0x00000000,
+	0xFF0F02C0, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+		0x035, 0x000001C5,
+		0x035, 0x000081C5,
+		0x035, 0x000101C5,
+		0x035, 0x00020174,
+		0x035, 0x00028174,
+		0x035, 0x00030174,
+		0x035, 0x00040185,
+		0x035, 0x00048185,
+		0x035, 0x00050185,
+		0x0EF, 0x00000000,
+	0xFF0F07D8, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+		0x035, 0x000001C5,
+		0x035, 0x000081C5,
+		0x035, 0x000101C5,
+		0x035, 0x00020174,
+		0x035, 0x00028174,
+		0x035, 0x00030174,
+		0x035, 0x00040185,
+		0x035, 0x00048185,
+		0x035, 0x00050185,
+		0x0EF, 0x00000000,
+	0xFF0F07D0, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+		0x035, 0x000001C5,
+		0x035, 0x000081C5,
+		0x035, 0x000101C5,
+		0x035, 0x00020174,
+		0x035, 0x00028174,
+		0x035, 0x00030174,
+		0x035, 0x00040185,
+		0x035, 0x00048185,
+		0x035, 0x00050185,
+		0x0EF, 0x00000000,
+	0xCDCDCDCD, 0xCDCD,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+		0x035, 0x00000186,
+		0x035, 0x00008186,
+		0x035, 0x00010185,
+		0x035, 0x000201D5,
+		0x035, 0x000281D5,
+		0x035, 0x000301D5,
+		0x035, 0x000401D5,
+		0x035, 0x000481D5,
+		0x035, 0x000501D5,
+		0x0EF, 0x00000000,
+	0xFF0F0740, 0xDEAD,
+	0xFF0F0740, 0xABCD,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+		0x036, 0x00005B8B,
+		0x036, 0x0000DB8B,
+		0x036, 0x00015B8B,
+		0x036, 0x0001DB8B,
+		0x036, 0x000262DB,
+		0x036, 0x0002E2DB,
+		0x036, 0x000362DB,
+		0x036, 0x0003E2DB,
+		0x036, 0x0004553B,
+		0x036, 0x0004D53B,
+		0x036, 0x0005553B,
+		0x036, 0x0005D53B,
+	0xFF0F01C0, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+		0x036, 0x00005B8B,
+		0x036, 0x0000DB8B,
+		0x036, 0x00015B8B,
+		0x036, 0x0001DB8B,
+		0x036, 0x000262DB,
+		0x036, 0x0002E2DB,
+		0x036, 0x000362DB,
+		0x036, 0x0003E2DB,
+		0x036, 0x0004553B,
+		0x036, 0x0004D53B,
+		0x036, 0x0005553B,
+		0x036, 0x0005D53B,
+	0xFF0F02C0, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+		0x036, 0x00005B8B,
+		0x036, 0x0000DB8B,
+		0x036, 0x00015B8B,
+		0x036, 0x0001DB8B,
+		0x036, 0x000262DB,
+		0x036, 0x0002E2DB,
+		0x036, 0x000362DB,
+		0x036, 0x0003E2DB,
+		0x036, 0x0004553B,
+		0x036, 0x0004D53B,
+		0x036, 0x0005553B,
+		0x036, 0x0005D53B,
+	0xFF0F07D8, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+		0x036, 0x00005B8B,
+		0x036, 0x0000DB8B,
+		0x036, 0x00015B8B,
+		0x036, 0x0001DB8B,
+		0x036, 0x000262DB,
+		0x036, 0x0002E2DB,
+		0x036, 0x000362DB,
+		0x036, 0x0003E2DB,
+		0x036, 0x0004553B,
+		0x036, 0x0004D53B,
+		0x036, 0x0005553B,
+		0x036, 0x0005D53B,
+	0xFF0F07D0, 0xCDEF,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+		0x036, 0x00005B8B,
+		0x036, 0x0000DB8B,
+		0x036, 0x00015B8B,
+		0x036, 0x0001DB8B,
+		0x036, 0x000262DB,
+		0x036, 0x0002E2DB,
+		0x036, 0x000362DB,
+		0x036, 0x0003E2DB,
+		0x036, 0x0004553B,
+		0x036, 0x0004D53B,
+		0x036, 0x0005553B,
+		0x036, 0x0005D53B,
+	0xCDCDCDCD, 0xCDCD,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+		0x036, 0x00084EB4,
+		0x036, 0x0008C9B4,
+		0x036, 0x000949B4,
+		0x036, 0x0009C9B4,
+		0x036, 0x000A4935,
+		0x036, 0x000AC935,
+		0x036, 0x000B4935,
+		0x036, 0x000BC935,
+		0x036, 0x000C4EB4,
+		0x036, 0x000CCEB4,
+		0x036, 0x000D4EB4,
+		0x036, 0x000DCEB4,
+	0xFF0F0740, 0xDEAD,
+		0x0EF, 0x00000000,
+		0x0EF, 0x00000008,
+	0xFF0F0740, 0xABCD,
+		0x03C, 0x000002DC,
+		0x03C, 0x00000524,
+		0x03C, 0x00000902,
+	0xFF0F01C0, 0xCDEF,
+		0x03C, 0x000002DC,
+		0x03C, 0x00000524,
+		0x03C, 0x00000902,
+	0xFF0F02C0, 0xCDEF,
+		0x03C, 0x000002DC,
+		0x03C, 0x00000524,
+		0x03C, 0x00000902,
+	0xFF0F07D8, 0xCDEF,
+		0x03C, 0x000002DC,
+		0x03C, 0x00000524,
+		0x03C, 0x00000902,
+	0xFF0F07D0, 0xCDEF,
+		0x03C, 0x000002DC,
+		0x03C, 0x00000524,
+		0x03C, 0x00000902,
+	0xCDCDCDCD, 0xCDCD,
+		0x03C, 0x000002AA,
+		0x03C, 0x000005A2,
+		0x03C, 0x00000880,
+	0xFF0F0740, 0xDEAD,
+		0x0EF, 0x00000000,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000002,
+		0x0DF, 0x00000080,
+	0xFF0F0740, 0xABCD,
+		0x061, 0x000EAC43,
+		0x062, 0x00038F47,
+		0x063, 0x00031157,
+		0x064, 0x0001C4AC,
+		0x065, 0x000931D1,
+	0xFF0F01C0, 0xCDEF,
+		0x061, 0x000EAC43,
+		0x062, 0x00038F47,
+		0x063, 0x00031157,
+		0x064, 0x0001C4AC,
+		0x065, 0x000931D1,
+	0xFF0F02C0, 0xCDEF,
+		0x061, 0x000EAC43,
+		0x062, 0x00038F47,
+		0x063, 0x00031157,
+		0x064, 0x0001C4AC,
+		0x065, 0x000931D1,
+	0xFF0F07D8, 0xCDEF,
+		0x061, 0x000EAC43,
+		0x062, 0x00038F47,
+		0x063, 0x00031157,
+		0x064, 0x0001C4AC,
+		0x065, 0x000931D1,
+	0xFF0F07D0, 0xCDEF,
+		0x061, 0x000EAC43,
+		0x062, 0x00038F47,
+		0x063, 0x00031157,
+		0x064, 0x0001C4AC,
+		0x065, 0x000931D1,
+	0xCDCDCDCD, 0xCDCD,
+		0x061, 0x000E5D53,
+		0x062, 0x00038FCD,
+		0x063, 0x000314EB,
+		0x064, 0x000196AC,
+		0x065, 0x000931D7,
+	0xFF0F0740, 0xDEAD,
+		0x008, 0x00008400,
+
+};
+
+u32 RTL8821AE_RADIOA_ARRAY[] = {
+		0x018, 0x0001712A,
+		0x056, 0x00051CF2,
+		0x066, 0x00040000,
+		0x000, 0x00010000,
+		0x01E, 0x00080000,
+		0x082, 0x00000830,
+		0x083, 0x00021800,
+		0x084, 0x00028000,
+		0x085, 0x00048000,
+		0x086, 0x00094838,
+		0x087, 0x00044980,
+		0x088, 0x00048000,
+		0x089, 0x0000D480,
+		0x08A, 0x00042240,
+		0x08B, 0x000F0380,
+		0x08C, 0x00090000,
+		0x08D, 0x00022852,
+		0x08E, 0x00065540,
+		0x08F, 0x00088001,
+		0x0EF, 0x00020000,
+		0x03E, 0x00000380,
+		0x03F, 0x00090018,
+		0x03E, 0x00020380,
+		0x03F, 0x000A0018,
+		0x03E, 0x00040308,
+		0x03F, 0x000A0018,
+		0x03E, 0x00060018,
+		0x03F, 0x000A0018,
+		0x0EF, 0x00000000,
+		0x018, 0x0001712A,
+		0x089, 0x00000080,
+		0x08B, 0x00080180,
+		0x0EF, 0x00001000,
+		0x03A, 0x00000244,
+		0x03B, 0x00038027,
+		0x03C, 0x00082000,
+		0x03A, 0x00000244,
+		0x03B, 0x00030113,
+		0x03C, 0x00082000,
+		0x03A, 0x0000014C,
+		0x03B, 0x00028027,
+		0x03C, 0x00082000,
+		0x03A, 0x000000CC,
+		0x03B, 0x00027027,
+		0x03C, 0x00042000,
+		0x03A, 0x0000014C,
+		0x03B, 0x0001F913,
+		0x03C, 0x00042000,
+		0x03A, 0x0000010C,
+		0x03B, 0x00017F10,
+		0x03C, 0x00012000,
+		0x03A, 0x000000D0,
+		0x03B, 0x00008027,
+		0x03C, 0x000CA000,
+		0x03A, 0x00000244,
+		0x03B, 0x00078027,
+		0x03C, 0x00082000,
+		0x03A, 0x00000244,
+		0x03B, 0x00070113,
+		0x03C, 0x00082000,
+		0x03A, 0x0000014C,
+		0x03B, 0x00068027,
+		0x03C, 0x00082000,
+		0x03A, 0x000000CC,
+		0x03B, 0x00067027,
+		0x03C, 0x00042000,
+		0x03A, 0x0000014C,
+		0x03B, 0x0005F913,
+		0x03C, 0x00042000,
+		0x03A, 0x0000010C,
+		0x03B, 0x00057F10,
+		0x03C, 0x00012000,
+		0x03A, 0x000000D0,
+		0x03B, 0x00048027,
+		0x03C, 0x000CA000,
+		0x03A, 0x00000244,
+		0x03B, 0x000B8027,
+		0x03C, 0x00082000,
+		0x03A, 0x00000244,
+		0x03B, 0x000B0113,
+		0x03C, 0x00082000,
+		0x03A, 0x0000014C,
+		0x03B, 0x000A8027,
+		0x03C, 0x00082000,
+		0x03A, 0x000000CC,
+		0x03B, 0x000A7027,
+		0x03C, 0x00042000,
+		0x03A, 0x0000014C,
+		0x03B, 0x0009F913,
+		0x03C, 0x00042000,
+		0x03A, 0x0000010C,
+		0x03B, 0x00097F10,
+		0x03C, 0x00012000,
+		0x03A, 0x000000D0,
+		0x03B, 0x00088027,
+		0x03C, 0x000CA000,
+		0x0EF, 0x00000000,
+		0x0EF, 0x00001100,
+	0xFF0F0104, 0xABCD,
+		0x034, 0x0004ADF3,
+		0x034, 0x00049DF0,
+	0xFF0F0204, 0xCDEF,
+		0x034, 0x0004ADF3,
+		0x034, 0x00049DF0,
+	0xFF0F0404, 0xCDEF,
+		0x034, 0x0004ADF3,
+		0x034, 0x00049DF0,
+	0xFF0F0200, 0xCDEF,
+		0x034, 0x0004ADF5,
+		0x034, 0x00049DF2,
+	0xFF0F02C0, 0xCDEF,
+		0x034, 0x0004A0F3,
+		0x034, 0x000490B1,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0004ADF7,
+		0x034, 0x00049DF3,
+	0xFF0F0104, 0xDEAD,
+	0xFF0F0104, 0xABCD,
+		0x034, 0x00048DED,
+		0x034, 0x00047DEA,
+		0x034, 0x00046DE7,
+		0x034, 0x00045CE9,
+		0x034, 0x00044CE6,
+		0x034, 0x000438C6,
+		0x034, 0x00042886,
+		0x034, 0x00041486,
+		0x034, 0x00040447,
+	0xFF0F0204, 0xCDEF,
+		0x034, 0x00048DED,
+		0x034, 0x00047DEA,
+		0x034, 0x00046DE7,
+		0x034, 0x00045CE9,
+		0x034, 0x00044CE6,
+		0x034, 0x000438C6,
+		0x034, 0x00042886,
+		0x034, 0x00041486,
+		0x034, 0x00040447,
+	0xFF0F0404, 0xCDEF,
+		0x034, 0x00048DED,
+		0x034, 0x00047DEA,
+		0x034, 0x00046DE7,
+		0x034, 0x00045CE9,
+		0x034, 0x00044CE6,
+		0x034, 0x000438C6,
+		0x034, 0x00042886,
+		0x034, 0x00041486,
+		0x034, 0x00040447,
+	0xFF0F02C0, 0xCDEF,
+		0x034, 0x000480AE,
+		0x034, 0x000470AB,
+		0x034, 0x0004608B,
+		0x034, 0x00045069,
+		0x034, 0x00044048,
+		0x034, 0x00043045,
+		0x034, 0x00042026,
+		0x034, 0x00041023,
+		0x034, 0x00040002,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x00048DEF,
+		0x034, 0x00047DEC,
+		0x034, 0x00046DE9,
+		0x034, 0x00045CCB,
+		0x034, 0x0004488D,
+		0x034, 0x0004348D,
+		0x034, 0x0004248A,
+		0x034, 0x0004108D,
+		0x034, 0x0004008A,
+	0xFF0F0104, 0xDEAD,
+	0xFF0F0200, 0xABCD,
+		0x034, 0x0002ADF4,
+	0xFF0F02C0, 0xCDEF,
+		0x034, 0x0002A0F3,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0002ADF7,
+	0xFF0F0200, 0xDEAD,
+	0xFF0F0104, 0xABCD,
+		0x034, 0x00029DF4,
+	0xFF0F0204, 0xCDEF,
+		0x034, 0x00029DF4,
+	0xFF0F0404, 0xCDEF,
+		0x034, 0x00029DF4,
+	0xFF0F0200, 0xCDEF,
+		0x034, 0x00029DF1,
+	0xFF0F02C0, 0xCDEF,
+		0x034, 0x000290F0,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x00029DF2,
+	0xFF0F0104, 0xDEAD,
+	0xFF0F0104, 0xABCD,
+		0x034, 0x00028DF1,
+		0x034, 0x00027DEE,
+		0x034, 0x00026DEB,
+		0x034, 0x00025CEC,
+		0x034, 0x00024CE9,
+		0x034, 0x000238CA,
+		0x034, 0x00022889,
+		0x034, 0x00021489,
+		0x034, 0x0002044A,
+	0xFF0F0204, 0xCDEF,
+		0x034, 0x00028DF1,
+		0x034, 0x00027DEE,
+		0x034, 0x00026DEB,
+		0x034, 0x00025CEC,
+		0x034, 0x00024CE9,
+		0x034, 0x000238CA,
+		0x034, 0x00022889,
+		0x034, 0x00021489,
+		0x034, 0x0002044A,
+	0xFF0F0404, 0xCDEF,
+		0x034, 0x00028DF1,
+		0x034, 0x00027DEE,
+		0x034, 0x00026DEB,
+		0x034, 0x00025CEC,
+		0x034, 0x00024CE9,
+		0x034, 0x000238CA,
+		0x034, 0x00022889,
+		0x034, 0x00021489,
+		0x034, 0x0002044A,
+	0xFF0F02C0, 0xCDEF,
+		0x034, 0x000280AF,
+		0x034, 0x000270AC,
+		0x034, 0x0002608B,
+		0x034, 0x00025069,
+		0x034, 0x00024048,
+		0x034, 0x00023045,
+		0x034, 0x00022026,
+		0x034, 0x00021023,
+		0x034, 0x00020002,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x00028DEE,
+		0x034, 0x00027DEB,
+		0x034, 0x00026CCD,
+		0x034, 0x00025CCA,
+		0x034, 0x0002488C,
+		0x034, 0x0002384C,
+		0x034, 0x00022849,
+		0x034, 0x00021449,
+		0x034, 0x0002004D,
+	0xFF0F0104, 0xDEAD,
+	0xFF0F02C0, 0xABCD,
+		0x034, 0x0000A0D7,
+		0x034, 0x000090D3,
+		0x034, 0x000080B1,
+		0x034, 0x000070AE,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x0000ADF7,
+		0x034, 0x00009DF4,
+		0x034, 0x00008DF1,
+		0x034, 0x00007DEE,
+	0xFF0F02C0, 0xDEAD,
+	0xFF0F0104, 0xABCD,
+		0x034, 0x00006DEB,
+		0x034, 0x00005CEC,
+		0x034, 0x00004CE9,
+		0x034, 0x000038CA,
+		0x034, 0x00002889,
+		0x034, 0x00001489,
+		0x034, 0x0000044A,
+	0xFF0F0204, 0xCDEF,
+		0x034, 0x00006DEB,
+		0x034, 0x00005CEC,
+		0x034, 0x00004CE9,
+		0x034, 0x000038CA,
+		0x034, 0x00002889,
+		0x034, 0x00001489,
+		0x034, 0x0000044A,
+	0xFF0F0404, 0xCDEF,
+		0x034, 0x00006DEB,
+		0x034, 0x00005CEC,
+		0x034, 0x00004CE9,
+		0x034, 0x000038CA,
+		0x034, 0x00002889,
+		0x034, 0x00001489,
+		0x034, 0x0000044A,
+	0xFF0F02C0, 0xCDEF,
+		0x034, 0x0000608D,
+		0x034, 0x0000506B,
+		0x034, 0x0000404A,
+		0x034, 0x00003047,
+		0x034, 0x00002044,
+		0x034, 0x00001025,
+		0x034, 0x00000004,
+	0xCDCDCDCD, 0xCDCD,
+		0x034, 0x00006DCD,
+		0x034, 0x00005CCD,
+		0x034, 0x00004CCA,
+		0x034, 0x0000388C,
+		0x034, 0x00002888,
+		0x034, 0x00001488,
+		0x034, 0x00000486,
+	0xFF0F0104, 0xDEAD,
+		0x0EF, 0x00000000,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000040,
+	0xFF0F0104, 0xABCD,
+		0x035, 0x00000187,
+		0x035, 0x00008187,
+		0x035, 0x00010187,
+		0x035, 0x00020188,
+		0x035, 0x00028188,
+		0x035, 0x00030188,
+		0x035, 0x00040188,
+		0x035, 0x00048188,
+		0x035, 0x00050188,
+	0xFF0F0204, 0xCDEF,
+		0x035, 0x00000187,
+		0x035, 0x00008187,
+		0x035, 0x00010187,
+		0x035, 0x00020188,
+		0x035, 0x00028188,
+		0x035, 0x00030188,
+		0x035, 0x00040188,
+		0x035, 0x00048188,
+		0x035, 0x00050188,
+	0xFF0F0404, 0xCDEF,
+		0x035, 0x00000187,
+		0x035, 0x00008187,
+		0x035, 0x00010187,
+		0x035, 0x00020188,
+		0x035, 0x00028188,
+		0x035, 0x00030188,
+		0x035, 0x00040188,
+		0x035, 0x00048188,
+		0x035, 0x00050188,
+	0xCDCDCDCD, 0xCDCD,
+		0x035, 0x00000145,
+		0x035, 0x00008145,
+		0x035, 0x00010145,
+		0x035, 0x00020196,
+		0x035, 0x00028196,
+		0x035, 0x00030196,
+		0x035, 0x000401C7,
+		0x035, 0x000481C7,
+		0x035, 0x000501C7,
+	0xFF0F0104, 0xDEAD,
+		0x0EF, 0x00000000,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000010,
+	0xFF0F0104, 0xABCD,
+		0x036, 0x00085733,
+		0x036, 0x0008D733,
+		0x036, 0x00095733,
+		0x036, 0x0009D733,
+		0x036, 0x000A64B4,
+		0x036, 0x000AE4B4,
+		0x036, 0x000B64B4,
+		0x036, 0x000BE4B4,
+		0x036, 0x000C64B4,
+		0x036, 0x000CE4B4,
+		0x036, 0x000D64B4,
+		0x036, 0x000DE4B4,
+	0xFF0F0204, 0xCDEF,
+		0x036, 0x00085733,
+		0x036, 0x0008D733,
+		0x036, 0x00095733,
+		0x036, 0x0009D733,
+		0x036, 0x000A64B4,
+		0x036, 0x000AE4B4,
+		0x036, 0x000B64B4,
+		0x036, 0x000BE4B4,
+		0x036, 0x000C64B4,
+		0x036, 0x000CE4B4,
+		0x036, 0x000D64B4,
+		0x036, 0x000DE4B4,
+	0xFF0F0404, 0xCDEF,
+		0x036, 0x00085733,
+		0x036, 0x0008D733,
+		0x036, 0x00095733,
+		0x036, 0x0009D733,
+		0x036, 0x000A64B4,
+		0x036, 0x000AE4B4,
+		0x036, 0x000B64B4,
+		0x036, 0x000BE4B4,
+		0x036, 0x000C64B4,
+		0x036, 0x000CE4B4,
+		0x036, 0x000D64B4,
+		0x036, 0x000DE4B4,
+	0xCDCDCDCD, 0xCDCD,
+		0x036, 0x000056B3,
+		0x036, 0x0000D6B3,
+		0x036, 0x000156B3,
+		0x036, 0x0001D6B3,
+		0x036, 0x00026634,
+		0x036, 0x0002E634,
+		0x036, 0x00036634,
+		0x036, 0x0003E634,
+		0x036, 0x000467B4,
+		0x036, 0x0004E7B4,
+		0x036, 0x000567B4,
+		0x036, 0x0005E7B4,
+	0xFF0F0104, 0xDEAD,
+		0x0EF, 0x00000000,
+		0x0EF, 0x00000008,
+	0xFF0F0104, 0xABCD,
+		0x03C, 0x000001C8,
+		0x03C, 0x00000492,
+	0xFF0F0204, 0xCDEF,
+		0x03C, 0x000001C8,
+		0x03C, 0x00000492,
+	0xFF0F0404, 0xCDEF,
+		0x03C, 0x000001C8,
+		0x03C, 0x00000492,
+	0xCDCDCDCD, 0xCDCD,
+		0x03C, 0x0000022A,
+		0x03C, 0x00000594,
+	0xFF0F0104, 0xDEAD,
+	0xFF0F0104, 0xABCD,
+		0x03C, 0x00000800,
+	0xFF0F0204, 0xCDEF,
+		0x03C, 0x00000800,
+	0xFF0F0404, 0xCDEF,
+		0x03C, 0x00000800,
+	0xFF0F02C0, 0xCDEF,
+		0x03C, 0x00000820,
+	0xCDCDCDCD, 0xCDCD,
+		0x03C, 0x00000900,
+	0xFF0F0104, 0xDEAD,
+		0x0EF, 0x00000000,
+		0x018, 0x0001712A,
+		0x0EF, 0x00000002,
+	0xFF0F0104, 0xABCD,
+		0x008, 0x0004E400,
+	0xFF0F0204, 0xCDEF,
+		0x008, 0x0004E400,
+	0xFF0F0404, 0xCDEF,
+		0x008, 0x0004E400,
+	0xCDCDCDCD, 0xCDCD,
+		0x008, 0x00002000,
+	0xFF0F0104, 0xDEAD,
+		0x0EF, 0x00000000,
+		0x0DF, 0x000000C0,
+		0x01F, 0x00040064,
+	0xFF0F0104, 0xABCD,
+		0x058, 0x000A7284,
+		0x059, 0x000600EC,
+	0xFF0F0204, 0xCDEF,
+		0x058, 0x000A7284,
+		0x059, 0x000600EC,
+	0xFF0F0404, 0xCDEF,
+		0x058, 0x000A7284,
+		0x059, 0x000600EC,
+	0xCDCDCDCD, 0xCDCD,
+		0x058, 0x00081184,
+		0x059, 0x0006016C,
+	0xFF0F0104, 0xDEAD,
+	0xFF0F0104, 0xABCD,
+		0x061, 0x000E8D73,
+		0x062, 0x00093FC5,
+	0xFF0F0204, 0xCDEF,
+		0x061, 0x000E8D73,
+		0x062, 0x00093FC5,
+	0xFF0F0404, 0xCDEF,
+		0x061, 0x000E8D73,
+		0x062, 0x00093FC5,
+	0xCDCDCDCD, 0xCDCD,
+		0x061, 0x000EAD53,
+		0x062, 0x00093BC4,
+	0xFF0F0104, 0xDEAD,
+	0xFF0F0104, 0xABCD,
+		0x063, 0x000110E9,
+	0xFF0F0204, 0xCDEF,
+		0x063, 0x000110E9,
+	0xFF0F0404, 0xCDEF,
+		0x063, 0x000110E9,
+	0xFF0F0200, 0xCDEF,
+		0x063, 0x000710E9,
+	0xFF0F02C0, 0xCDEF,
+		0x063, 0x000110E9,
+	0xCDCDCDCD, 0xCDCD,
+		0x063, 0x000714E9,
+	0xFF0F0104, 0xDEAD,
+	0xFF0F0104, 0xABCD,
+		0x064, 0x0001C27C,
+	0xFF0F0204, 0xCDEF,
+		0x064, 0x0001C27C,
+	0xFF0F0404, 0xCDEF,
+		0x064, 0x0001C27C,
+	0xCDCDCDCD, 0xCDCD,
+		0x064, 0x0001C67C,
+	0xFF0F0104, 0xDEAD,
+	0xFF0F0200, 0xABCD,
+		0x065, 0x00093016,
+	0xFF0F02C0, 0xCDEF,
+		0x065, 0x00093015,
+	0xCDCDCDCD, 0xCDCD,
+		0x065, 0x00091016,
+	0xFF0F0200, 0xDEAD,
+		0x018, 0x00000006,
+		0x0EF, 0x00002000,
+		0x03B, 0x0003824B,
+		0x03B, 0x0003024B,
+		0x03B, 0x0002844B,
+		0x03B, 0x00020F4B,
+		0x03B, 0x00018F4B,
+		0x03B, 0x000104B2,
+		0x03B, 0x00008049,
+		0x03B, 0x00000148,
+		0x03B, 0x0007824B,
+		0x03B, 0x0007024B,
+		0x03B, 0x0006824B,
+		0x03B, 0x00060F4B,
+		0x03B, 0x00058F4B,
+		0x03B, 0x000504B2,
+		0x03B, 0x00048049,
+		0x03B, 0x00040148,
+		0x0EF, 0x00000000,
+		0x0EF, 0x00000100,
+		0x034, 0x0000ADF3,
+		0x034, 0x00009DEF,
+		0x034, 0x00008DEC,
+		0x034, 0x00007DE9,
+		0x034, 0x00006CED,
+		0x034, 0x00005CE9,
+		0x034, 0x000044E9,
+		0x034, 0x000034E6,
+		0x034, 0x0000246A,
+		0x034, 0x00001467,
+		0x034, 0x00000068,
+		0x0EF, 0x00000000,
+		0x0ED, 0x00000010,
+		0x044, 0x0000ADF2,
+		0x044, 0x00009DEF,
+		0x044, 0x00008DEC,
+		0x044, 0x00007DE9,
+		0x044, 0x00006CEC,
+		0x044, 0x00005CE9,
+		0x044, 0x000044EC,
+		0x044, 0x000034E9,
+		0x044, 0x0000246C,
+		0x044, 0x00001469,
+		0x044, 0x0000006C,
+		0x0ED, 0x00000000,
+		0x0ED, 0x00000001,
+		0x040, 0x00038DA7,
+		0x040, 0x000300C2,
+		0x040, 0x000288E2,
+		0x040, 0x000200B8,
+		0x040, 0x000188A5,
+		0x040, 0x00010FBC,
+		0x040, 0x00008F71,
+		0x040, 0x00000240,
+		0x0ED, 0x00000000,
+		0x0EF, 0x000020A2,
+		0x0DF, 0x00000080,
+		0x035, 0x00000120,
+		0x035, 0x00008120,
+		0x035, 0x00010120,
+		0x036, 0x00000085,
+		0x036, 0x00008085,
+		0x036, 0x00010085,
+		0x036, 0x00018085,
+		0x0EF, 0x00000000,
+		0x051, 0x00000C31,
+		0x052, 0x00000622,
+		0x053, 0x000FC70B,
+		0x054, 0x0000017E,
+		0x056, 0x00051DF3,
+		0x051, 0x00000C01,
+		0x052, 0x000006D6,
+		0x053, 0x000FC649,
+		0x070, 0x00049661,
+		0x071, 0x0007843E,
+		0x072, 0x00000382,
+		0x074, 0x00051400,
+		0x035, 0x00000160,
+		0x035, 0x00008160,
+		0x035, 0x00010160,
+		0x036, 0x00000124,
+		0x036, 0x00008124,
+		0x036, 0x00010124,
+		0x036, 0x00018124,
+		0x0ED, 0x0000000C,
+		0x045, 0x00000140,
+		0x045, 0x00008140,
+		0x045, 0x00010140,
+		0x046, 0x00000124,
+		0x046, 0x00008124,
+		0x046, 0x00010124,
+		0x046, 0x00018124,
+		0x0DF, 0x00000088,
+		0x0B3, 0x000F0E18,
+		0x0B4, 0x0001214C,
+		0x0B7, 0x0003000C,
+		0x01C, 0x000539D2,
+		0x018, 0x0001F12A,
+		0x0FE, 0x00000000,
+		0x0FE, 0x00000000,
+		0x018, 0x0001712A,
+};
+
+u32 RTL8812AE_MAC_REG_ARRAY[] = {
+		0x010, 0x0000000C,
+	0xFF0F0180, 0xABCD,
+		0x025, 0x0000000F,
+	0xFF0F01C0, 0xCDEF,
+		0x025, 0x0000000F,
+	0xCDCDCDCD, 0xCDCD,
+		0x025, 0x0000006F,
+	0xFF0F0180, 0xDEAD,
+		0x072, 0x00000000,
+		0x428, 0x0000000A,
+		0x429, 0x00000010,
+		0x430, 0x00000000,
+		0x431, 0x00000000,
+		0x432, 0x00000000,
+		0x433, 0x00000001,
+		0x434, 0x00000004,
+		0x435, 0x00000005,
+		0x436, 0x00000007,
+		0x437, 0x00000008,
+		0x43C, 0x00000004,
+		0x43D, 0x00000005,
+		0x43E, 0x00000007,
+		0x43F, 0x00000008,
+		0x440, 0x0000005D,
+		0x441, 0x00000001,
+		0x442, 0x00000000,
+		0x444, 0x00000010,
+		0x445, 0x00000000,
+		0x446, 0x00000000,
+		0x447, 0x00000000,
+		0x448, 0x00000000,
+		0x449, 0x000000F0,
+		0x44A, 0x0000000F,
+		0x44B, 0x0000003E,
+		0x44C, 0x00000010,
+		0x44D, 0x00000000,
+		0x44E, 0x00000000,
+		0x44F, 0x00000000,
+		0x450, 0x00000000,
+		0x451, 0x000000F0,
+		0x452, 0x0000000F,
+		0x453, 0x00000000,
+		0x45B, 0x00000080,
+		0x460, 0x00000066,
+		0x461, 0x00000066,
+		0x4C8, 0x000000FF,
+		0x4C9, 0x00000008,
+		0x4CC, 0x000000FF,
+		0x4CD, 0x000000FF,
+		0x4CE, 0x00000001,
+		0x500, 0x00000026,
+		0x501, 0x000000A2,
+		0x502, 0x0000002F,
+		0x503, 0x00000000,
+		0x504, 0x00000028,
+		0x505, 0x000000A3,
+		0x506, 0x0000005E,
+		0x507, 0x00000000,
+		0x508, 0x0000002B,
+		0x509, 0x000000A4,
+		0x50A, 0x0000005E,
+		0x50B, 0x00000000,
+		0x50C, 0x0000004F,
+		0x50D, 0x000000A4,
+		0x50E, 0x00000000,
+		0x50F, 0x00000000,
+		0x512, 0x0000001C,
+		0x514, 0x0000000A,
+		0x516, 0x0000000A,
+		0x525, 0x0000004F,
+		0x550, 0x00000010,
+		0x551, 0x00000010,
+		0x559, 0x00000002,
+		0x55C, 0x00000050,
+		0x55D, 0x000000FF,
+		0x604, 0x00000001,
+		0x605, 0x00000030,
+		0x607, 0x00000003,
+		0x608, 0x0000000E,
+		0x609, 0x0000002A,
+		0x620, 0x000000FF,
+		0x621, 0x000000FF,
+		0x622, 0x000000FF,
+		0x623, 0x000000FF,
+		0x624, 0x000000FF,
+		0x625, 0x000000FF,
+		0x626, 0x000000FF,
+		0x627, 0x000000FF,
+		0x638, 0x00000050,
+		0x63C, 0x0000000A,
+		0x63D, 0x0000000A,
+		0x63E, 0x0000000E,
+		0x63F, 0x0000000E,
+		0x640, 0x00000080,
+		0x642, 0x00000040,
+		0x643, 0x00000000,
+		0x652, 0x000000C8,
+		0x66E, 0x00000005,
+		0x700, 0x00000021,
+		0x701, 0x00000043,
+		0x702, 0x00000065,
+		0x703, 0x00000087,
+		0x708, 0x00000021,
+		0x709, 0x00000043,
+		0x70A, 0x00000065,
+		0x70B, 0x00000087,
+		0x718, 0x00000040,
+
+};
+
+u32 RTL8821AE_MAC_REG_ARRAY[] = {
+		0x428, 0x0000000A,
+		0x429, 0x00000010,
+		0x430, 0x00000000,
+		0x431, 0x00000000,
+		0x432, 0x00000000,
+		0x433, 0x00000001,
+		0x434, 0x00000004,
+		0x435, 0x00000005,
+		0x436, 0x00000007,
+		0x437, 0x00000008,
+		0x43C, 0x00000004,
+		0x43D, 0x00000005,
+		0x43E, 0x00000007,
+		0x43F, 0x00000008,
+		0x440, 0x0000005D,
+		0x441, 0x00000001,
+		0x442, 0x00000000,
+		0x444, 0x00000010,
+		0x445, 0x00000000,
+		0x446, 0x00000000,
+		0x447, 0x00000000,
+		0x448, 0x00000000,
+		0x449, 0x000000F0,
+		0x44A, 0x0000000F,
+		0x44B, 0x0000003E,
+		0x44C, 0x00000010,
+		0x44D, 0x00000000,
+		0x44E, 0x00000000,
+		0x44F, 0x00000000,
+		0x450, 0x00000000,
+		0x451, 0x000000F0,
+		0x452, 0x0000000F,
+		0x453, 0x00000000,
+		0x456, 0x0000005E,
+		0x460, 0x00000066,
+		0x461, 0x00000066,
+		0x4C8, 0x0000003F,
+		0x4C9, 0x000000FF,
+		0x4CC, 0x000000FF,
+		0x4CD, 0x000000FF,
+		0x4CE, 0x00000001,
+		0x500, 0x00000026,
+		0x501, 0x000000A2,
+		0x502, 0x0000002F,
+		0x503, 0x00000000,
+		0x504, 0x00000028,
+		0x505, 0x000000A3,
+		0x506, 0x0000005E,
+		0x507, 0x00000000,
+		0x508, 0x0000002B,
+		0x509, 0x000000A4,
+		0x50A, 0x0000005E,
+		0x50B, 0x00000000,
+		0x50C, 0x0000004F,
+		0x50D, 0x000000A4,
+		0x50E, 0x00000000,
+		0x50F, 0x00000000,
+		0x512, 0x0000001C,
+		0x514, 0x0000000A,
+		0x516, 0x0000000A,
+		0x525, 0x0000004F,
+		0x550, 0x00000010,
+		0x551, 0x00000010,
+		0x559, 0x00000002,
+		0x55C, 0x00000050,
+		0x55D, 0x000000FF,
+		0x605, 0x00000030,
+		0x607, 0x00000007,
+		0x608, 0x0000000E,
+		0x609, 0x0000002A,
+		0x620, 0x000000FF,
+		0x621, 0x000000FF,
+		0x622, 0x000000FF,
+		0x623, 0x000000FF,
+		0x624, 0x000000FF,
+		0x625, 0x000000FF,
+		0x626, 0x000000FF,
+		0x627, 0x000000FF,
+		0x638, 0x00000050,
+		0x63C, 0x0000000A,
+		0x63D, 0x0000000A,
+		0x63E, 0x0000000E,
+		0x63F, 0x0000000E,
+		0x640, 0x00000040,
+		0x642, 0x00000040,
+		0x643, 0x00000000,
+		0x652, 0x000000C8,
+		0x66E, 0x00000005,
+		0x700, 0x00000021,
+		0x701, 0x00000043,
+		0x702, 0x00000065,
+		0x703, 0x00000087,
+		0x708, 0x00000021,
+		0x709, 0x00000043,
+		0x70A, 0x00000065,
+		0x70B, 0x00000087,
+		0x718, 0x00000040,
+};
+
+u32 RTL8812AE_AGC_TAB_ARRAY[] = {
+	0xFF0F07D8, 0xABCD,
+		0x81C, 0xFC000001,
+		0x81C, 0xFB020001,
+		0x81C, 0xFA040001,
+		0x81C, 0xF9060001,
+		0x81C, 0xF8080001,
+		0x81C, 0xF70A0001,
+		0x81C, 0xF60C0001,
+		0x81C, 0xF50E0001,
+		0x81C, 0xF4100001,
+		0x81C, 0xF3120001,
+		0x81C, 0xF2140001,
+		0x81C, 0xF1160001,
+		0x81C, 0xF0180001,
+		0x81C, 0xEF1A0001,
+		0x81C, 0xEE1C0001,
+		0x81C, 0xED1E0001,
+		0x81C, 0xEC200001,
+		0x81C, 0xEB220001,
+		0x81C, 0xEA240001,
+		0x81C, 0xCD260001,
+		0x81C, 0xCC280001,
+		0x81C, 0xCB2A0001,
+		0x81C, 0xCA2C0001,
+		0x81C, 0xC92E0001,
+		0x81C, 0xC8300001,
+		0x81C, 0xA6320001,
+		0x81C, 0xA5340001,
+		0x81C, 0xA4360001,
+		0x81C, 0xA3380001,
+		0x81C, 0xA23A0001,
+		0x81C, 0x883C0001,
+		0x81C, 0x873E0001,
+		0x81C, 0x86400001,
+		0x81C, 0x85420001,
+		0x81C, 0x84440001,
+		0x81C, 0x83460001,
+		0x81C, 0x82480001,
+		0x81C, 0x814A0001,
+		0x81C, 0x484C0001,
+		0x81C, 0x474E0001,
+		0x81C, 0x46500001,
+		0x81C, 0x45520001,
+		0x81C, 0x44540001,
+		0x81C, 0x43560001,
+		0x81C, 0x42580001,
+		0x81C, 0x415A0001,
+		0x81C, 0x255C0001,
+		0x81C, 0x245E0001,
+		0x81C, 0x23600001,
+		0x81C, 0x22620001,
+		0x81C, 0x21640001,
+		0x81C, 0x21660001,
+		0x81C, 0x21680001,
+		0x81C, 0x216A0001,
+		0x81C, 0x216C0001,
+		0x81C, 0x216E0001,
+		0x81C, 0x21700001,
+		0x81C, 0x21720001,
+		0x81C, 0x21740001,
+		0x81C, 0x21760001,
+		0x81C, 0x21780001,
+		0x81C, 0x217A0001,
+		0x81C, 0x217C0001,
+		0x81C, 0x217E0001,
+	0xFF0F07D0, 0xCDEF,
+		0x81C, 0xF9000001,
+		0x81C, 0xF8020001,
+		0x81C, 0xF7040001,
+		0x81C, 0xF6060001,
+		0x81C, 0xF5080001,
+		0x81C, 0xF40A0001,
+		0x81C, 0xF30C0001,
+		0x81C, 0xF20E0001,
+		0x81C, 0xF1100001,
+		0x81C, 0xF0120001,
+		0x81C, 0xEF140001,
+		0x81C, 0xEE160001,
+		0x81C, 0xED180001,
+		0x81C, 0xEC1A0001,
+		0x81C, 0xEB1C0001,
+		0x81C, 0xEA1E0001,
+		0x81C, 0xCD200001,
+		0x81C, 0xCC220001,
+		0x81C, 0xCB240001,
+		0x81C, 0xCA260001,
+		0x81C, 0xC9280001,
+		0x81C, 0xC82A0001,
+		0x81C, 0xC72C0001,
+		0x81C, 0xC62E0001,
+		0x81C, 0xA5300001,
+		0x81C, 0xA4320001,
+		0x81C, 0xA3340001,
+		0x81C, 0xA2360001,
+		0x81C, 0x88380001,
+		0x81C, 0x873A0001,
+		0x81C, 0x863C0001,
+		0x81C, 0x853E0001,
+		0x81C, 0x84400001,
+		0x81C, 0x83420001,
+		0x81C, 0x82440001,
+		0x81C, 0x81460001,
+		0x81C, 0x48480001,
+		0x81C, 0x474A0001,
+		0x81C, 0x464C0001,
+		0x81C, 0x454E0001,
+		0x81C, 0x44500001,
+		0x81C, 0x43520001,
+		0x81C, 0x42540001,
+		0x81C, 0x41560001,
+		0x81C, 0x25580001,
+		0x81C, 0x245A0001,
+		0x81C, 0x235C0001,
+		0x81C, 0x225E0001,
+		0x81C, 0x21600001,
+		0x81C, 0x21620001,
+		0x81C, 0x21640001,
+		0x81C, 0x21660001,
+		0x81C, 0x21680001,
+		0x81C, 0x216A0001,
+		0x81C, 0x236C0001,
+		0x81C, 0x226E0001,
+		0x81C, 0x21700001,
+		0x81C, 0x21720001,
+		0x81C, 0x21740001,
+		0x81C, 0x21760001,
+		0x81C, 0x21780001,
+		0x81C, 0x217A0001,
+		0x81C, 0x217C0001,
+		0x81C, 0x217E0001,
+	0xCDCDCDCD, 0xCDCD,
+		0x81C, 0xFF000001,
+		0x81C, 0xFF020001,
+		0x81C, 0xFF040001,
+		0x81C, 0xFF060001,
+		0x81C, 0xFF080001,
+		0x81C, 0xFE0A0001,
+		0x81C, 0xFD0C0001,
+		0x81C, 0xFC0E0001,
+		0x81C, 0xFB100001,
+		0x81C, 0xFA120001,
+		0x81C, 0xF9140001,
+		0x81C, 0xF8160001,
+		0x81C, 0xF7180001,
+		0x81C, 0xF61A0001,
+		0x81C, 0xF51C0001,
+		0x81C, 0xF41E0001,
+		0x81C, 0xF3200001,
+		0x81C, 0xF2220001,
+		0x81C, 0xF1240001,
+		0x81C, 0xF0260001,
+		0x81C, 0xEF280001,
+		0x81C, 0xEE2A0001,
+		0x81C, 0xED2C0001,
+		0x81C, 0xEC2E0001,
+		0x81C, 0xEB300001,
+		0x81C, 0xEA320001,
+		0x81C, 0xE9340001,
+		0x81C, 0xE8360001,
+		0x81C, 0xE7380001,
+		0x81C, 0xE63A0001,
+		0x81C, 0xE53C0001,
+		0x81C, 0xC73E0001,
+		0x81C, 0xC6400001,
+		0x81C, 0xC5420001,
+		0x81C, 0xC4440001,
+		0x81C, 0xC3460001,
+		0x81C, 0xC2480001,
+		0x81C, 0xC14A0001,
+		0x81C, 0xA74C0001,
+		0x81C, 0xA64E0001,
+		0x81C, 0xA5500001,
+		0x81C, 0xA4520001,
+		0x81C, 0xA3540001,
+		0x81C, 0xA2560001,
+		0x81C, 0xA1580001,
+		0x81C, 0x675A0001,
+		0x81C, 0x665C0001,
+		0x81C, 0x655E0001,
+		0x81C, 0x64600001,
+		0x81C, 0x63620001,
+		0x81C, 0x48640001,
+		0x81C, 0x47660001,
+		0x81C, 0x46680001,
+		0x81C, 0x456A0001,
+		0x81C, 0x446C0001,
+		0x81C, 0x436E0001,
+		0x81C, 0x42700001,
+		0x81C, 0x41720001,
+		0x81C, 0x41740001,
+		0x81C, 0x41760001,
+		0x81C, 0x41780001,
+		0x81C, 0x417A0001,
+		0x81C, 0x417C0001,
+		0x81C, 0x417E0001,
+	0xFF0F07D8, 0xDEAD,
+	0xFF0F0180, 0xABCD,
+		0x81C, 0xFC800001,
+		0x81C, 0xFB820001,
+		0x81C, 0xFA840001,
+		0x81C, 0xF9860001,
+		0x81C, 0xF8880001,
+		0x81C, 0xF78A0001,
+		0x81C, 0xF68C0001,
+		0x81C, 0xF58E0001,
+		0x81C, 0xF4900001,
+		0x81C, 0xF3920001,
+		0x81C, 0xF2940001,
+		0x81C, 0xF1960001,
+		0x81C, 0xF0980001,
+		0x81C, 0xEF9A0001,
+		0x81C, 0xEE9C0001,
+		0x81C, 0xED9E0001,
+		0x81C, 0xECA00001,
+		0x81C, 0xEBA20001,
+		0x81C, 0xEAA40001,
+		0x81C, 0xE9A60001,
+		0x81C, 0xE8A80001,
+		0x81C, 0xE7AA0001,
+		0x81C, 0xE6AC0001,
+		0x81C, 0xE5AE0001,
+		0x81C, 0xE4B00001,
+		0x81C, 0xE3B20001,
+		0x81C, 0xA8B40001,
+		0x81C, 0xA7B60001,
+		0x81C, 0xA6B80001,
+		0x81C, 0xA5BA0001,
+		0x81C, 0xA4BC0001,
+		0x81C, 0xA3BE0001,
+		0x81C, 0xA2C00001,
+		0x81C, 0xA1C20001,
+		0x81C, 0x68C40001,
+		0x81C, 0x67C60001,
+		0x81C, 0x66C80001,
+		0x81C, 0x65CA0001,
+		0x81C, 0x64CC0001,
+		0x81C, 0x47CE0001,
+		0x81C, 0x46D00001,
+		0x81C, 0x45D20001,
+		0x81C, 0x44D40001,
+		0x81C, 0x43D60001,
+		0x81C, 0x42D80001,
+		0x81C, 0x08DA0001,
+		0x81C, 0x07DC0001,
+		0x81C, 0x06DE0001,
+		0x81C, 0x05E00001,
+		0x81C, 0x04E20001,
+		0x81C, 0x03E40001,
+		0x81C, 0x02E60001,
+		0x81C, 0x01E80001,
+		0x81C, 0x01EA0001,
+		0x81C, 0x01EC0001,
+		0x81C, 0x01EE0001,
+		0x81C, 0x01F00001,
+		0x81C, 0x01F20001,
+		0x81C, 0x01F40001,
+		0x81C, 0x01F60001,
+		0x81C, 0x01F80001,
+		0x81C, 0x01FA0001,
+		0x81C, 0x01FC0001,
+		0x81C, 0x01FE0001,
+	0xFF0F0280, 0xCDEF,
+		0x81C, 0xFC800001,
+		0x81C, 0xFB820001,
+		0x81C, 0xFA840001,
+		0x81C, 0xF9860001,
+		0x81C, 0xF8880001,
+		0x81C, 0xF78A0001,
+		0x81C, 0xF68C0001,
+		0x81C, 0xF58E0001,
+		0x81C, 0xF4900001,
+		0x81C, 0xF3920001,
+		0x81C, 0xF2940001,
+		0x81C, 0xF1960001,
+		0x81C, 0xF0980001,
+		0x81C, 0xEF9A0001,
+		0x81C, 0xEE9C0001,
+		0x81C, 0xED9E0001,
+		0x81C, 0xECA00001,
+		0x81C, 0xEBA20001,
+		0x81C, 0xEAA40001,
+		0x81C, 0xE9A60001,
+		0x81C, 0xE8A80001,
+		0x81C, 0xE7AA0001,
+		0x81C, 0xE6AC0001,
+		0x81C, 0xE5AE0001,
+		0x81C, 0xE4B00001,
+		0x81C, 0xE3B20001,
+		0x81C, 0xA8B40001,
+		0x81C, 0xA7B60001,
+		0x81C, 0xA6B80001,
+		0x81C, 0xA5BA0001,
+		0x81C, 0xA4BC0001,
+		0x81C, 0xA3BE0001,
+		0x81C, 0xA2C00001,
+		0x81C, 0xA1C20001,
+		0x81C, 0x68C40001,
+		0x81C, 0x67C60001,
+		0x81C, 0x66C80001,
+		0x81C, 0x65CA0001,
+		0x81C, 0x64CC0001,
+		0x81C, 0x47CE0001,
+		0x81C, 0x46D00001,
+		0x81C, 0x45D20001,
+		0x81C, 0x44D40001,
+		0x81C, 0x43D60001,
+		0x81C, 0x42D80001,
+		0x81C, 0x08DA0001,
+		0x81C, 0x07DC0001,
+		0x81C, 0x06DE0001,
+		0x81C, 0x05E00001,
+		0x81C, 0x04E20001,
+		0x81C, 0x03E40001,
+		0x81C, 0x02E60001,
+		0x81C, 0x01E80001,
+		0x81C, 0x01EA0001,
+		0x81C, 0x01EC0001,
+		0x81C, 0x01EE0001,
+		0x81C, 0x01F00001,
+		0x81C, 0x01F20001,
+		0x81C, 0x01F40001,
+		0x81C, 0x01F60001,
+		0x81C, 0x01F80001,
+		0x81C, 0x01FA0001,
+		0x81C, 0x01FC0001,
+		0x81C, 0x01FE0001,
+	0xFF0F01C0, 0xCDEF,
+		0x81C, 0xFC800001,
+		0x81C, 0xFB820001,
+		0x81C, 0xFA840001,
+		0x81C, 0xF9860001,
+		0x81C, 0xF8880001,
+		0x81C, 0xF78A0001,
+		0x81C, 0xF68C0001,
+		0x81C, 0xF58E0001,
+		0x81C, 0xF4900001,
+		0x81C, 0xF3920001,
+		0x81C, 0xF2940001,
+		0x81C, 0xF1960001,
+		0x81C, 0xF0980001,
+		0x81C, 0xEF9A0001,
+		0x81C, 0xEE9C0001,
+		0x81C, 0xED9E0001,
+		0x81C, 0xECA00001,
+		0x81C, 0xEBA20001,
+		0x81C, 0xEAA40001,
+		0x81C, 0xE9A60001,
+		0x81C, 0xE8A80001,
+		0x81C, 0xE7AA0001,
+		0x81C, 0xE6AC0001,
+		0x81C, 0xE5AE0001,
+		0x81C, 0xE4B00001,
+		0x81C, 0xE3B20001,
+		0x81C, 0xA8B40001,
+		0x81C, 0xA7B60001,
+		0x81C, 0xA6B80001,
+		0x81C, 0xA5BA0001,
+		0x81C, 0xA4BC0001,
+		0x81C, 0xA3BE0001,
+		0x81C, 0xA2C00001,
+		0x81C, 0xA1C20001,
+		0x81C, 0x68C40001,
+		0x81C, 0x67C60001,
+		0x81C, 0x66C80001,
+		0x81C, 0x65CA0001,
+		0x81C, 0x64CC0001,
+		0x81C, 0x47CE0001,
+		0x81C, 0x46D00001,
+		0x81C, 0x45D20001,
+		0x81C, 0x44D40001,
+		0x81C, 0x43D60001,
+		0x81C, 0x42D80001,
+		0x81C, 0x08DA0001,
+		0x81C, 0x07DC0001,
+		0x81C, 0x06DE0001,
+		0x81C, 0x05E00001,
+		0x81C, 0x04E20001,
+		0x81C, 0x03E40001,
+		0x81C, 0x02E60001,
+		0x81C, 0x01E80001,
+		0x81C, 0x01EA0001,
+		0x81C, 0x01EC0001,
+		0x81C, 0x01EE0001,
+		0x81C, 0x01F00001,
+		0x81C, 0x01F20001,
+		0x81C, 0x01F40001,
+		0x81C, 0x01F60001,
+		0x81C, 0x01F80001,
+		0x81C, 0x01FA0001,
+		0x81C, 0x01FC0001,
+		0x81C, 0x01FE0001,
+	0xFF0F02C0, 0xCDEF,
+		0x81C, 0xFC800001,
+		0x81C, 0xFB820001,
+		0x81C, 0xFA840001,
+		0x81C, 0xF9860001,
+		0x81C, 0xF8880001,
+		0x81C, 0xF78A0001,
+		0x81C, 0xF68C0001,
+		0x81C, 0xF58E0001,
+		0x81C, 0xF4900001,
+		0x81C, 0xF3920001,
+		0x81C, 0xF2940001,
+		0x81C, 0xF1960001,
+		0x81C, 0xF0980001,
+		0x81C, 0xEF9A0001,
+		0x81C, 0xEE9C0001,
+		0x81C, 0xED9E0001,
+		0x81C, 0xECA00001,
+		0x81C, 0xEBA20001,
+		0x81C, 0xEAA40001,
+		0x81C, 0xE9A60001,
+		0x81C, 0xE8A80001,
+		0x81C, 0xE7AA0001,
+		0x81C, 0xE6AC0001,
+		0x81C, 0xE5AE0001,
+		0x81C, 0xE4B00001,
+		0x81C, 0xE3B20001,
+		0x81C, 0xA8B40001,
+		0x81C, 0xA7B60001,
+		0x81C, 0xA6B80001,
+		0x81C, 0xA5BA0001,
+		0x81C, 0xA4BC0001,
+		0x81C, 0xA3BE0001,
+		0x81C, 0xA2C00001,
+		0x81C, 0xA1C20001,
+		0x81C, 0x68C40001,
+		0x81C, 0x67C60001,
+		0x81C, 0x66C80001,
+		0x81C, 0x65CA0001,
+		0x81C, 0x64CC0001,
+		0x81C, 0x47CE0001,
+		0x81C, 0x46D00001,
+		0x81C, 0x45D20001,
+		0x81C, 0x44D40001,
+		0x81C, 0x43D60001,
+		0x81C, 0x42D80001,
+		0x81C, 0x08DA0001,
+		0x81C, 0x07DC0001,
+		0x81C, 0x06DE0001,
+		0x81C, 0x05E00001,
+		0x81C, 0x04E20001,
+		0x81C, 0x03E40001,
+		0x81C, 0x02E60001,
+		0x81C, 0x01E80001,
+		0x81C, 0x01EA0001,
+		0x81C, 0x01EC0001,
+		0x81C, 0x01EE0001,
+		0x81C, 0x01F00001,
+		0x81C, 0x01F20001,
+		0x81C, 0x01F40001,
+		0x81C, 0x01F60001,
+		0x81C, 0x01F80001,
+		0x81C, 0x01FA0001,
+		0x81C, 0x01FC0001,
+		0x81C, 0x01FE0001,
+	0xFF0F07D8, 0xCDEF,
+		0x81C, 0xFC800001,
+		0x81C, 0xFB820001,
+		0x81C, 0xFA840001,
+		0x81C, 0xF9860001,
+		0x81C, 0xF8880001,
+		0x81C, 0xF78A0001,
+		0x81C, 0xF68C0001,
+		0x81C, 0xF58E0001,
+		0x81C, 0xF4900001,
+		0x81C, 0xF3920001,
+		0x81C, 0xF2940001,
+		0x81C, 0xF1960001,
+		0x81C, 0xF0980001,
+		0x81C, 0xEF9A0001,
+		0x81C, 0xEE9C0001,
+		0x81C, 0xED9E0001,
+		0x81C, 0xECA00001,
+		0x81C, 0xEBA20001,
+		0x81C, 0xEAA40001,
+		0x81C, 0xE9A60001,
+		0x81C, 0xE8A80001,
+		0x81C, 0xE7AA0001,
+		0x81C, 0xE6AC0001,
+		0x81C, 0xE5AE0001,
+		0x81C, 0xE4B00001,
+		0x81C, 0xE3B20001,
+		0x81C, 0xA8B40001,
+		0x81C, 0xA7B60001,
+		0x81C, 0xA6B80001,
+		0x81C, 0xA5BA0001,
+		0x81C, 0xA4BC0001,
+		0x81C, 0xA3BE0001,
+		0x81C, 0xA2C00001,
+		0x81C, 0xA1C20001,
+		0x81C, 0x68C40001,
+		0x81C, 0x67C60001,
+		0x81C, 0x66C80001,
+		0x81C, 0x65CA0001,
+		0x81C, 0x64CC0001,
+		0x81C, 0x47CE0001,
+		0x81C, 0x46D00001,
+		0x81C, 0x45D20001,
+		0x81C, 0x44D40001,
+		0x81C, 0x43D60001,
+		0x81C, 0x42D80001,
+		0x81C, 0x08DA0001,
+		0x81C, 0x07DC0001,
+		0x81C, 0x06DE0001,
+		0x81C, 0x05E00001,
+		0x81C, 0x04E20001,
+		0x81C, 0x03E40001,
+		0x81C, 0x02E60001,
+		0x81C, 0x01E80001,
+		0x81C, 0x01EA0001,
+		0x81C, 0x01EC0001,
+		0x81C, 0x01EE0001,
+		0x81C, 0x01F00001,
+		0x81C, 0x01F20001,
+		0x81C, 0x01F40001,
+		0x81C, 0x01F60001,
+		0x81C, 0x01F80001,
+		0x81C, 0x01FA0001,
+		0x81C, 0x01FC0001,
+		0x81C, 0x01FE0001,
+	0xFF0F07D0, 0xCDEF,
+		0x81C, 0xFC800001,
+		0x81C, 0xFB820001,
+		0x81C, 0xFA840001,
+		0x81C, 0xF9860001,
+		0x81C, 0xF8880001,
+		0x81C, 0xF78A0001,
+		0x81C, 0xF68C0001,
+		0x81C, 0xF58E0001,
+		0x81C, 0xF4900001,
+		0x81C, 0xF3920001,
+		0x81C, 0xF2940001,
+		0x81C, 0xF1960001,
+		0x81C, 0xF0980001,
+		0x81C, 0xEF9A0001,
+		0x81C, 0xEE9C0001,
+		0x81C, 0xED9E0001,
+		0x81C, 0xECA00001,
+		0x81C, 0xEBA20001,
+		0x81C, 0xEAA40001,
+		0x81C, 0xE9A60001,
+		0x81C, 0xE8A80001,
+		0x81C, 0xE7AA0001,
+		0x81C, 0xE6AC0001,
+		0x81C, 0xE5AE0001,
+		0x81C, 0xE4B00001,
+		0x81C, 0xE3B20001,
+		0x81C, 0xA8B40001,
+		0x81C, 0xA7B60001,
+		0x81C, 0xA6B80001,
+		0x81C, 0xA5BA0001,
+		0x81C, 0xA4BC0001,
+		0x81C, 0xA3BE0001,
+		0x81C, 0xA2C00001,
+		0x81C, 0xA1C20001,
+		0x81C, 0x68C40001,
+		0x81C, 0x67C60001,
+		0x81C, 0x66C80001,
+		0x81C, 0x65CA0001,
+		0x81C, 0x64CC0001,
+		0x81C, 0x47CE0001,
+		0x81C, 0x46D00001,
+		0x81C, 0x45D20001,
+		0x81C, 0x44D40001,
+		0x81C, 0x43D60001,
+		0x81C, 0x42D80001,
+		0x81C, 0x08DA0001,
+		0x81C, 0x07DC0001,
+		0x81C, 0x06DE0001,
+		0x81C, 0x05E00001,
+		0x81C, 0x04E20001,
+		0x81C, 0x03E40001,
+		0x81C, 0x02E60001,
+		0x81C, 0x01E80001,
+		0x81C, 0x01EA0001,
+		0x81C, 0x01EC0001,
+		0x81C, 0x01EE0001,
+		0x81C, 0x01F00001,
+		0x81C, 0x01F20001,
+		0x81C, 0x01F40001,
+		0x81C, 0x01F60001,
+		0x81C, 0x01F80001,
+		0x81C, 0x01FA0001,
+		0x81C, 0x01FC0001,
+		0x81C, 0x01FE0001,
+	0xCDCDCDCD, 0xCDCD,
+		0x81C, 0xFF800001,
+		0x81C, 0xFF820001,
+		0x81C, 0xFF840001,
+		0x81C, 0xFE860001,
+		0x81C, 0xFD880001,
+		0x81C, 0xFC8A0001,
+		0x81C, 0xFB8C0001,
+		0x81C, 0xFA8E0001,
+		0x81C, 0xF9900001,
+		0x81C, 0xF8920001,
+		0x81C, 0xF7940001,
+		0x81C, 0xF6960001,
+		0x81C, 0xF5980001,
+		0x81C, 0xF49A0001,
+		0x81C, 0xF39C0001,
+		0x81C, 0xF29E0001,
+		0x81C, 0xF1A00001,
+		0x81C, 0xF0A20001,
+		0x81C, 0xEFA40001,
+		0x81C, 0xEEA60001,
+		0x81C, 0xEDA80001,
+		0x81C, 0xECAA0001,
+		0x81C, 0xEBAC0001,
+		0x81C, 0xEAAE0001,
+		0x81C, 0xE9B00001,
+		0x81C, 0xE8B20001,
+		0x81C, 0xE7B40001,
+		0x81C, 0xE6B60001,
+		0x81C, 0xE5B80001,
+		0x81C, 0xE4BA0001,
+		0x81C, 0xE3BC0001,
+		0x81C, 0xA8BE0001,
+		0x81C, 0xA7C00001,
+		0x81C, 0xA6C20001,
+		0x81C, 0xA5C40001,
+		0x81C, 0xA4C60001,
+		0x81C, 0xA3C80001,
+		0x81C, 0xA2CA0001,
+		0x81C, 0xA1CC0001,
+		0x81C, 0x68CE0001,
+		0x81C, 0x67D00001,
+		0x81C, 0x66D20001,
+		0x81C, 0x65D40001,
+		0x81C, 0x64D60001,
+		0x81C, 0x47D80001,
+		0x81C, 0x46DA0001,
+		0x81C, 0x45DC0001,
+		0x81C, 0x44DE0001,
+		0x81C, 0x43E00001,
+		0x81C, 0x42E20001,
+		0x81C, 0x08E40001,
+		0x81C, 0x07E60001,
+		0x81C, 0x06E80001,
+		0x81C, 0x05EA0001,
+		0x81C, 0x04EC0001,
+		0x81C, 0x03EE0001,
+		0x81C, 0x02F00001,
+		0x81C, 0x01F20001,
+		0x81C, 0x01F40001,
+		0x81C, 0x01F60001,
+		0x81C, 0x01F80001,
+		0x81C, 0x01FA0001,
+		0x81C, 0x01FC0001,
+		0x81C, 0x01FE0001,
+	0xFF0F0180, 0xDEAD,
+		0xC50, 0x00000022,
+		0xC50, 0x00000020,
+		0xE50, 0x00000022,
+		0xE50, 0x00000020,
+
+};
+
+u32 RTL8821AE_AGC_TAB_ARRAY[] = {
+		0x81C, 0xBF000001,
+		0x81C, 0xBF020001,
+		0x81C, 0xBF040001,
+		0x81C, 0xBF060001,
+		0x81C, 0xBE080001,
+		0x81C, 0xBD0A0001,
+		0x81C, 0xBC0C0001,
+		0x81C, 0xBA0E0001,
+		0x81C, 0xB9100001,
+		0x81C, 0xB8120001,
+		0x81C, 0xB7140001,
+		0x81C, 0xB6160001,
+		0x81C, 0xB5180001,
+		0x81C, 0xB41A0001,
+		0x81C, 0xB31C0001,
+		0x81C, 0xB21E0001,
+		0x81C, 0xB1200001,
+		0x81C, 0xB0220001,
+		0x81C, 0xAF240001,
+		0x81C, 0xAE260001,
+		0x81C, 0xAD280001,
+		0x81C, 0xAC2A0001,
+		0x81C, 0xAB2C0001,
+		0x81C, 0xAA2E0001,
+		0x81C, 0xA9300001,
+		0x81C, 0xA8320001,
+		0x81C, 0xA7340001,
+		0x81C, 0xA6360001,
+		0x81C, 0xA5380001,
+		0x81C, 0xA43A0001,
+		0x81C, 0xA33C0001,
+		0x81C, 0x673E0001,
+		0x81C, 0x66400001,
+		0x81C, 0x65420001,
+		0x81C, 0x64440001,
+		0x81C, 0x63460001,
+		0x81C, 0x62480001,
+		0x81C, 0x614A0001,
+		0x81C, 0x474C0001,
+		0x81C, 0x464E0001,
+		0x81C, 0x45500001,
+		0x81C, 0x44520001,
+		0x81C, 0x43540001,
+		0x81C, 0x42560001,
+		0x81C, 0x41580001,
+		0x81C, 0x285A0001,
+		0x81C, 0x275C0001,
+		0x81C, 0x265E0001,
+		0x81C, 0x25600001,
+		0x81C, 0x24620001,
+		0x81C, 0x0A640001,
+		0x81C, 0x09660001,
+		0x81C, 0x08680001,
+		0x81C, 0x076A0001,
+		0x81C, 0x066C0001,
+		0x81C, 0x056E0001,
+		0x81C, 0x04700001,
+		0x81C, 0x03720001,
+		0x81C, 0x02740001,
+		0x81C, 0x01760001,
+		0x81C, 0x01780001,
+		0x81C, 0x017A0001,
+		0x81C, 0x017C0001,
+		0x81C, 0x017E0001,
+	0xFF0F02C0, 0xABCD,
+		0x81C, 0xFB000101,
+		0x81C, 0xFA020101,
+		0x81C, 0xF9040101,
+		0x81C, 0xF8060101,
+		0x81C, 0xF7080101,
+		0x81C, 0xF60A0101,
+		0x81C, 0xF50C0101,
+		0x81C, 0xF40E0101,
+		0x81C, 0xF3100101,
+		0x81C, 0xF2120101,
+		0x81C, 0xF1140101,
+		0x81C, 0xF0160101,
+		0x81C, 0xEF180101,
+		0x81C, 0xEE1A0101,
+		0x81C, 0xED1C0101,
+		0x81C, 0xEC1E0101,
+		0x81C, 0xEB200101,
+		0x81C, 0xEA220101,
+		0x81C, 0xE9240101,
+		0x81C, 0xE8260101,
+		0x81C, 0xE7280101,
+		0x81C, 0xE62A0101,
+		0x81C, 0xE52C0101,
+		0x81C, 0xE42E0101,
+		0x81C, 0xE3300101,
+		0x81C, 0xA5320101,
+		0x81C, 0xA4340101,
+		0x81C, 0xA3360101,
+		0x81C, 0x87380101,
+		0x81C, 0x863A0101,
+		0x81C, 0x853C0101,
+		0x81C, 0x843E0101,
+		0x81C, 0x69400101,
+		0x81C, 0x68420101,
+		0x81C, 0x67440101,
+		0x81C, 0x66460101,
+		0x81C, 0x49480101,
+		0x81C, 0x484A0101,
+		0x81C, 0x474C0101,
+		0x81C, 0x2A4E0101,
+		0x81C, 0x29500101,
+		0x81C, 0x28520101,
+		0x81C, 0x27540101,
+		0x81C, 0x26560101,
+		0x81C, 0x25580101,
+		0x81C, 0x245A0101,
+		0x81C, 0x235C0101,
+		0x81C, 0x055E0101,
+		0x81C, 0x04600101,
+		0x81C, 0x03620101,
+		0x81C, 0x02640101,
+		0x81C, 0x01660101,
+		0x81C, 0x01680101,
+		0x81C, 0x016A0101,
+		0x81C, 0x016C0101,
+		0x81C, 0x016E0101,
+		0x81C, 0x01700101,
+		0x81C, 0x01720101,
+	0xCDCDCDCD, 0xCDCD,
+		0x81C, 0xFF000101,
+		0x81C, 0xFF020101,
+		0x81C, 0xFE040101,
+		0x81C, 0xFD060101,
+		0x81C, 0xFC080101,
+		0x81C, 0xFD0A0101,
+		0x81C, 0xFC0C0101,
+		0x81C, 0xFB0E0101,
+		0x81C, 0xFA100101,
+		0x81C, 0xF9120101,
+		0x81C, 0xF8140101,
+		0x81C, 0xF7160101,
+		0x81C, 0xF6180101,
+		0x81C, 0xF51A0101,
+		0x81C, 0xF41C0101,
+		0x81C, 0xF31E0101,
+		0x81C, 0xF2200101,
+		0x81C, 0xF1220101,
+		0x81C, 0xF0240101,
+		0x81C, 0xEF260101,
+		0x81C, 0xEE280101,
+		0x81C, 0xED2A0101,
+		0x81C, 0xEC2C0101,
+		0x81C, 0xEB2E0101,
+		0x81C, 0xEA300101,
+		0x81C, 0xE9320101,
+		0x81C, 0xE8340101,
+		0x81C, 0xE7360101,
+		0x81C, 0xE6380101,
+		0x81C, 0xE53A0101,
+		0x81C, 0xE43C0101,
+		0x81C, 0xE33E0101,
+		0x81C, 0xA5400101,
+		0x81C, 0xA4420101,
+		0x81C, 0xA3440101,
+		0x81C, 0x87460101,
+		0x81C, 0x86480101,
+		0x81C, 0x854A0101,
+		0x81C, 0x844C0101,
+		0x81C, 0x694E0101,
+		0x81C, 0x68500101,
+		0x81C, 0x67520101,
+		0x81C, 0x66540101,
+		0x81C, 0x49560101,
+		0x81C, 0x48580101,
+		0x81C, 0x475A0101,
+		0x81C, 0x2A5C0101,
+		0x81C, 0x295E0101,
+		0x81C, 0x28600101,
+		0x81C, 0x27620101,
+		0x81C, 0x26640101,
+		0x81C, 0x25660101,
+		0x81C, 0x24680101,
+		0x81C, 0x236A0101,
+		0x81C, 0x056C0101,
+		0x81C, 0x046E0101,
+		0x81C, 0x03700101,
+		0x81C, 0x02720101,
+	0xFF0F02C0, 0xDEAD,
+		0x81C, 0x01740101,
+		0x81C, 0x01760101,
+		0x81C, 0x01780101,
+		0x81C, 0x017A0101,
+		0x81C, 0x017C0101,
+		0x81C, 0x017E0101,
+		0xC50, 0x00000022,
+		0xC50, 0x00000020,
+
+};
+
+/******************************************************************************
+*                           TXPWR_LMT.TXT
+******************************************************************************/
+
+u8 *RTL8812AE_TXPWR_LMT[] = {
+	"FCC", "2.4G", "20M", "CCK", "1T", "01", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "01", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "01", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "02", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "02", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "02", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "03", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "03", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "03", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "04", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "04", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "04", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "05", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "05", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "05", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "06", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "06", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "06", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "07", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "07", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "07", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "08", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "08", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "08", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "09", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "09", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "09", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "10", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "10", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "10", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "11", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "11", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "11", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "12", "63",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "12", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "12", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "13", "63",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "13", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "13", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "14", "63",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "14", "63",
+	"MKK", "2.4G", "20M", "CCK", "1T", "14", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "01", "34",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "01", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "01", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "02", "36",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "02", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "02", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "03", "36",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "03", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "03", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "04", "36",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "04", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "04", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "05", "36",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "05", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "05", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "06", "36",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "06", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "06", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "07", "36",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "07", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "07", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "08", "36",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "08", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "08", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "09", "36",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "09", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "09", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "10", "36",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "10", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "10", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "11", "32",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "11", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "11", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "12", "63",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "12", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "12", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "13", "63",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "13", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "13", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "14", "63",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "14", "63",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "14", "63",
+	"FCC", "2.4G", "20M", "HT", "1T", "01", "34",
+	"ETSI", "2.4G", "20M", "HT", "1T", "01", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "01", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "02", "36",
+	"ETSI", "2.4G", "20M", "HT", "1T", "02", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "02", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "03", "36",
+	"ETSI", "2.4G", "20M", "HT", "1T", "03", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "03", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "04", "36",
+	"ETSI", "2.4G", "20M", "HT", "1T", "04", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "04", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "05", "36",
+	"ETSI", "2.4G", "20M", "HT", "1T", "05", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "05", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "06", "36",
+	"ETSI", "2.4G", "20M", "HT", "1T", "06", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "06", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "07", "36",
+	"ETSI", "2.4G", "20M", "HT", "1T", "07", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "07", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "08", "36",
+	"ETSI", "2.4G", "20M", "HT", "1T", "08", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "08", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "09", "36",
+	"ETSI", "2.4G", "20M", "HT", "1T", "09", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "09", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "10", "36",
+	"ETSI", "2.4G", "20M", "HT", "1T", "10", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "10", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "11", "32",
+	"ETSI", "2.4G", "20M", "HT", "1T", "11", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "11", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "12", "63",
+	"ETSI", "2.4G", "20M", "HT", "1T", "12", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "12", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "13", "63",
+	"ETSI", "2.4G", "20M", "HT", "1T", "13", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "13", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "14", "63",
+	"ETSI", "2.4G", "20M", "HT", "1T", "14", "63",
+	"MKK", "2.4G", "20M", "HT", "1T", "14", "63",
+	"FCC", "2.4G", "20M", "HT", "2T", "01", "32",
+	"ETSI", "2.4G", "20M", "HT", "2T", "01", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "01", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "02", "34",
+	"ETSI", "2.4G", "20M", "HT", "2T", "02", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "02", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "03", "34",
+	"ETSI", "2.4G", "20M", "HT", "2T", "03", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "03", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "04", "34",
+	"ETSI", "2.4G", "20M", "HT", "2T", "04", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "04", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "05", "34",
+	"ETSI", "2.4G", "20M", "HT", "2T", "05", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "05", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "06", "34",
+	"ETSI", "2.4G", "20M", "HT", "2T", "06", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "06", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "07", "34",
+	"ETSI", "2.4G", "20M", "HT", "2T", "07", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "07", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "08", "34",
+	"ETSI", "2.4G", "20M", "HT", "2T", "08", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "08", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "09", "34",
+	"ETSI", "2.4G", "20M", "HT", "2T", "09", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "09", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "10", "34",
+	"ETSI", "2.4G", "20M", "HT", "2T", "10", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "10", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "11", "30",
+	"ETSI", "2.4G", "20M", "HT", "2T", "11", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "11", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "12", "63",
+	"ETSI", "2.4G", "20M", "HT", "2T", "12", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "12", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "13", "63",
+	"ETSI", "2.4G", "20M", "HT", "2T", "13", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "13", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "14", "63",
+	"ETSI", "2.4G", "20M", "HT", "2T", "14", "63",
+	"MKK", "2.4G", "20M", "HT", "2T", "14", "63",
+	"FCC", "2.4G", "40M", "HT", "1T", "01", "63",
+	"ETSI", "2.4G", "40M", "HT", "1T", "01", "63",
+	"MKK", "2.4G", "40M", "HT", "1T", "01", "63",
+	"FCC", "2.4G", "40M", "HT", "1T", "02", "63",
+	"ETSI", "2.4G", "40M", "HT", "1T", "02", "63",
+	"MKK", "2.4G", "40M", "HT", "1T", "02", "63",
+	"FCC", "2.4G", "40M", "HT", "1T", "03", "32",
+	"ETSI", "2.4G", "40M", "HT", "1T", "03", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "03", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "04", "36",
+	"ETSI", "2.4G", "40M", "HT", "1T", "04", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "04", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "05", "36",
+	"ETSI", "2.4G", "40M", "HT", "1T", "05", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "05", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "06", "36",
+	"ETSI", "2.4G", "40M", "HT", "1T", "06", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "06", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "07", "36",
+	"ETSI", "2.4G", "40M", "HT", "1T", "07", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "07", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "08", "36",
+	"ETSI", "2.4G", "40M", "HT", "1T", "08", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "08", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "09", "36",
+	"ETSI", "2.4G", "40M", "HT", "1T", "09", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "09", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "10", "36",
+	"ETSI", "2.4G", "40M", "HT", "1T", "10", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "10", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "11", "32",
+	"ETSI", "2.4G", "40M", "HT", "1T", "11", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "11", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "12", "63",
+	"ETSI", "2.4G", "40M", "HT", "1T", "12", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "12", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "13", "63",
+	"ETSI", "2.4G", "40M", "HT", "1T", "13", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "13", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "14", "63",
+	"ETSI", "2.4G", "40M", "HT", "1T", "14", "63",
+	"MKK", "2.4G", "40M", "HT", "1T", "14", "63",
+	"FCC", "2.4G", "40M", "HT", "2T", "01", "63",
+	"ETSI", "2.4G", "40M", "HT", "2T", "01", "63",
+	"MKK", "2.4G", "40M", "HT", "2T", "01", "63",
+	"FCC", "2.4G", "40M", "HT", "2T", "02", "63",
+	"ETSI", "2.4G", "40M", "HT", "2T", "02", "63",
+	"MKK", "2.4G", "40M", "HT", "2T", "02", "63",
+	"FCC", "2.4G", "40M", "HT", "2T", "03", "30",
+	"ETSI", "2.4G", "40M", "HT", "2T", "03", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "03", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "04", "34",
+	"ETSI", "2.4G", "40M", "HT", "2T", "04", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "04", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "05", "34",
+	"ETSI", "2.4G", "40M", "HT", "2T", "05", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "05", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "06", "34",
+	"ETSI", "2.4G", "40M", "HT", "2T", "06", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "06", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "07", "34",
+	"ETSI", "2.4G", "40M", "HT", "2T", "07", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "07", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "08", "34",
+	"ETSI", "2.4G", "40M", "HT", "2T", "08", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "08", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "09", "34",
+	"ETSI", "2.4G", "40M", "HT", "2T", "09", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "09", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "10", "34",
+	"ETSI", "2.4G", "40M", "HT", "2T", "10", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "10", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "11", "30",
+	"ETSI", "2.4G", "40M", "HT", "2T", "11", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "11", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "12", "63",
+	"ETSI", "2.4G", "40M", "HT", "2T", "12", "32",
+	"MKK", "2.4G", "40M", "HT", "2T", "12", "32",
+	"FCC", "2.4G", "40M", "HT", "2T", "13", "63",
+	"ETSI", "2.4G", "40M", "HT", "2T", "13", "32",
+	"MKK", "2.4G", "40M", "HT", "2T", "13", "32",
+	"FCC", "2.4G", "40M", "HT", "2T", "14", "63",
+	"ETSI", "2.4G", "40M", "HT", "2T", "14", "63",
+	"MKK", "2.4G", "40M", "HT", "2T", "14", "63",
+	"FCC", "5G", "20M", "OFDM", "1T", "36", "30",
+	"ETSI", "5G", "20M", "OFDM", "1T", "36", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "36", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "40", "30",
+	"ETSI", "5G", "20M", "OFDM", "1T", "40", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "40", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "44", "30",
+	"ETSI", "5G", "20M", "OFDM", "1T", "44", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "44", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "48", "30",
+	"ETSI", "5G", "20M", "OFDM", "1T", "48", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "48", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "52", "36",
+	"ETSI", "5G", "20M", "OFDM", "1T", "52", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "52", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "56", "34",
+	"ETSI", "5G", "20M", "OFDM", "1T", "56", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "56", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "60", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "60", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "60", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "64", "28",
+	"ETSI", "5G", "20M", "OFDM", "1T", "64", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "64", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "100", "30",
+	"ETSI", "5G", "20M", "OFDM", "1T", "100", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "100", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "114", "30",
+	"ETSI", "5G", "20M", "OFDM", "1T", "114", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "114", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "108", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "108", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "108", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "112", "34",
+	"ETSI", "5G", "20M", "OFDM", "1T", "112", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "112", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "116", "34",
+	"ETSI", "5G", "20M", "OFDM", "1T", "116", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "116", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "120", "36",
+	"ETSI", "5G", "20M", "OFDM", "1T", "120", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "120", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "124", "34",
+	"ETSI", "5G", "20M", "OFDM", "1T", "124", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "124", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "128", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "128", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "128", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "132", "30",
+	"ETSI", "5G", "20M", "OFDM", "1T", "132", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "132", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "136", "30",
+	"ETSI", "5G", "20M", "OFDM", "1T", "136", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "136", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "140", "28",
+	"ETSI", "5G", "20M", "OFDM", "1T", "140", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "140", "32",
+	"FCC", "5G", "20M", "OFDM", "1T", "149", "36",
+	"ETSI", "5G", "20M", "OFDM", "1T", "149", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "149", "63",
+	"FCC", "5G", "20M", "OFDM", "1T", "153", "36",
+	"ETSI", "5G", "20M", "OFDM", "1T", "153", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "153", "63",
+	"FCC", "5G", "20M", "OFDM", "1T", "157", "36",
+	"ETSI", "5G", "20M", "OFDM", "1T", "157", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "157", "63",
+	"FCC", "5G", "20M", "OFDM", "1T", "161", "36",
+	"ETSI", "5G", "20M", "OFDM", "1T", "161", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "161", "63",
+	"FCC", "5G", "20M", "OFDM", "1T", "165", "36",
+	"ETSI", "5G", "20M", "OFDM", "1T", "165", "32",
+	"MKK", "5G", "20M", "OFDM", "1T", "165", "63",
+	"FCC", "5G", "20M", "HT", "1T", "36", "30",
+	"ETSI", "5G", "20M", "HT", "1T", "36", "32",
+	"MKK", "5G", "20M", "HT", "1T", "36", "32",
+	"FCC", "5G", "20M", "HT", "1T", "40", "30",
+	"ETSI", "5G", "20M", "HT", "1T", "40", "32",
+	"MKK", "5G", "20M", "HT", "1T", "40", "32",
+	"FCC", "5G", "20M", "HT", "1T", "44", "30",
+	"ETSI", "5G", "20M", "HT", "1T", "44", "32",
+	"MKK", "5G", "20M", "HT", "1T", "44", "32",
+	"FCC", "5G", "20M", "HT", "1T", "48", "30",
+	"ETSI", "5G", "20M", "HT", "1T", "48", "32",
+	"MKK", "5G", "20M", "HT", "1T", "48", "32",
+	"FCC", "5G", "20M", "HT", "1T", "52", "36",
+	"ETSI", "5G", "20M", "HT", "1T", "52", "32",
+	"MKK", "5G", "20M", "HT", "1T", "52", "32",
+	"FCC", "5G", "20M", "HT", "1T", "56", "34",
+	"ETSI", "5G", "20M", "HT", "1T", "56", "32",
+	"MKK", "5G", "20M", "HT", "1T", "56", "32",
+	"FCC", "5G", "20M", "HT", "1T", "60", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "60", "32",
+	"MKK", "5G", "20M", "HT", "1T", "60", "32",
+	"FCC", "5G", "20M", "HT", "1T", "64", "28",
+	"ETSI", "5G", "20M", "HT", "1T", "64", "32",
+	"MKK", "5G", "20M", "HT", "1T", "64", "32",
+	"FCC", "5G", "20M", "HT", "1T", "100", "30",
+	"ETSI", "5G", "20M", "HT", "1T", "100", "32",
+	"MKK", "5G", "20M", "HT", "1T", "100", "32",
+	"FCC", "5G", "20M", "HT", "1T", "114", "30",
+	"ETSI", "5G", "20M", "HT", "1T", "114", "32",
+	"MKK", "5G", "20M", "HT", "1T", "114", "32",
+	"FCC", "5G", "20M", "HT", "1T", "108", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "108", "32",
+	"MKK", "5G", "20M", "HT", "1T", "108", "32",
+	"FCC", "5G", "20M", "HT", "1T", "112", "34",
+	"ETSI", "5G", "20M", "HT", "1T", "112", "32",
+	"MKK", "5G", "20M", "HT", "1T", "112", "32",
+	"FCC", "5G", "20M", "HT", "1T", "116", "34",
+	"ETSI", "5G", "20M", "HT", "1T", "116", "32",
+	"MKK", "5G", "20M", "HT", "1T", "116", "32",
+	"FCC", "5G", "20M", "HT", "1T", "120", "36",
+	"ETSI", "5G", "20M", "HT", "1T", "120", "32",
+	"MKK", "5G", "20M", "HT", "1T", "120", "32",
+	"FCC", "5G", "20M", "HT", "1T", "124", "34",
+	"ETSI", "5G", "20M", "HT", "1T", "124", "32",
+	"MKK", "5G", "20M", "HT", "1T", "124", "32",
+	"FCC", "5G", "20M", "HT", "1T", "128", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "128", "32",
+	"MKK", "5G", "20M", "HT", "1T", "128", "32",
+	"FCC", "5G", "20M", "HT", "1T", "132", "30",
+	"ETSI", "5G", "20M", "HT", "1T", "132", "32",
+	"MKK", "5G", "20M", "HT", "1T", "132", "32",
+	"FCC", "5G", "20M", "HT", "1T", "136", "30",
+	"ETSI", "5G", "20M", "HT", "1T", "136", "32",
+	"MKK", "5G", "20M", "HT", "1T", "136", "32",
+	"FCC", "5G", "20M", "HT", "1T", "140", "28",
+	"ETSI", "5G", "20M", "HT", "1T", "140", "32",
+	"MKK", "5G", "20M", "HT", "1T", "140", "32",
+	"FCC", "5G", "20M", "HT", "1T", "149", "36",
+	"ETSI", "5G", "20M", "HT", "1T", "149", "32",
+	"MKK", "5G", "20M", "HT", "1T", "149", "63",
+	"FCC", "5G", "20M", "HT", "1T", "153", "36",
+	"ETSI", "5G", "20M", "HT", "1T", "153", "32",
+	"MKK", "5G", "20M", "HT", "1T", "153", "63",
+	"FCC", "5G", "20M", "HT", "1T", "157", "36",
+	"ETSI", "5G", "20M", "HT", "1T", "157", "32",
+	"MKK", "5G", "20M", "HT", "1T", "157", "63",
+	"FCC", "5G", "20M", "HT", "1T", "161", "36",
+	"ETSI", "5G", "20M", "HT", "1T", "161", "32",
+	"MKK", "5G", "20M", "HT", "1T", "161", "63",
+	"FCC", "5G", "20M", "HT", "1T", "165", "36",
+	"ETSI", "5G", "20M", "HT", "1T", "165", "32",
+	"MKK", "5G", "20M", "HT", "1T", "165", "63",
+	"FCC", "5G", "20M", "HT", "2T", "36", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "36", "30",
+	"MKK", "5G", "20M", "HT", "2T", "36", "30",
+	"FCC", "5G", "20M", "HT", "2T", "40", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "40", "30",
+	"MKK", "5G", "20M", "HT", "2T", "40", "30",
+	"FCC", "5G", "20M", "HT", "2T", "44", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "44", "30",
+	"MKK", "5G", "20M", "HT", "2T", "44", "30",
+	"FCC", "5G", "20M", "HT", "2T", "48", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "48", "30",
+	"MKK", "5G", "20M", "HT", "2T", "48", "30",
+	"FCC", "5G", "20M", "HT", "2T", "52", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "52", "30",
+	"MKK", "5G", "20M", "HT", "2T", "52", "30",
+	"FCC", "5G", "20M", "HT", "2T", "56", "32",
+	"ETSI", "5G", "20M", "HT", "2T", "56", "30",
+	"MKK", "5G", "20M", "HT", "2T", "56", "30",
+	"FCC", "5G", "20M", "HT", "2T", "60", "30",
+	"ETSI", "5G", "20M", "HT", "2T", "60", "30",
+	"MKK", "5G", "20M", "HT", "2T", "60", "30",
+	"FCC", "5G", "20M", "HT", "2T", "64", "26",
+	"ETSI", "5G", "20M", "HT", "2T", "64", "30",
+	"MKK", "5G", "20M", "HT", "2T", "64", "30",
+	"FCC", "5G", "20M", "HT", "2T", "100", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "100", "30",
+	"MKK", "5G", "20M", "HT", "2T", "100", "30",
+	"FCC", "5G", "20M", "HT", "2T", "114", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "114", "30",
+	"MKK", "5G", "20M", "HT", "2T", "114", "30",
+	"FCC", "5G", "20M", "HT", "2T", "108", "30",
+	"ETSI", "5G", "20M", "HT", "2T", "108", "30",
+	"MKK", "5G", "20M", "HT", "2T", "108", "30",
+	"FCC", "5G", "20M", "HT", "2T", "112", "32",
+	"ETSI", "5G", "20M", "HT", "2T", "112", "30",
+	"MKK", "5G", "20M", "HT", "2T", "112", "30",
+	"FCC", "5G", "20M", "HT", "2T", "116", "32",
+	"ETSI", "5G", "20M", "HT", "2T", "116", "30",
+	"MKK", "5G", "20M", "HT", "2T", "116", "30",
+	"FCC", "5G", "20M", "HT", "2T", "120", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "120", "30",
+	"MKK", "5G", "20M", "HT", "2T", "120", "30",
+	"FCC", "5G", "20M", "HT", "2T", "124", "32",
+	"ETSI", "5G", "20M", "HT", "2T", "124", "30",
+	"MKK", "5G", "20M", "HT", "2T", "124", "30",
+	"FCC", "5G", "20M", "HT", "2T", "128", "30",
+	"ETSI", "5G", "20M", "HT", "2T", "128", "30",
+	"MKK", "5G", "20M", "HT", "2T", "128", "30",
+	"FCC", "5G", "20M", "HT", "2T", "132", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "132", "30",
+	"MKK", "5G", "20M", "HT", "2T", "132", "30",
+	"FCC", "5G", "20M", "HT", "2T", "136", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "136", "30",
+	"MKK", "5G", "20M", "HT", "2T", "136", "30",
+	"FCC", "5G", "20M", "HT", "2T", "140", "26",
+	"ETSI", "5G", "20M", "HT", "2T", "140", "30",
+	"MKK", "5G", "20M", "HT", "2T", "140", "30",
+	"FCC", "5G", "20M", "HT", "2T", "149", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "149", "30",
+	"MKK", "5G", "20M", "HT", "2T", "149", "63",
+	"FCC", "5G", "20M", "HT", "2T", "153", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "153", "30",
+	"MKK", "5G", "20M", "HT", "2T", "153", "63",
+	"FCC", "5G", "20M", "HT", "2T", "157", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "157", "30",
+	"MKK", "5G", "20M", "HT", "2T", "157", "63",
+	"FCC", "5G", "20M", "HT", "2T", "161", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "161", "30",
+	"MKK", "5G", "20M", "HT", "2T", "161", "63",
+	"FCC", "5G", "20M", "HT", "2T", "165", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "165", "30",
+	"MKK", "5G", "20M", "HT", "2T", "165", "63",
+	"FCC", "5G", "40M", "HT", "1T", "38", "30",
+	"ETSI", "5G", "40M", "HT", "1T", "38", "32",
+	"MKK", "5G", "40M", "HT", "1T", "38", "32",
+	"FCC", "5G", "40M", "HT", "1T", "46", "30",
+	"ETSI", "5G", "40M", "HT", "1T", "46", "32",
+	"MKK", "5G", "40M", "HT", "1T", "46", "32",
+	"FCC", "5G", "40M", "HT", "1T", "54", "32",
+	"ETSI", "5G", "40M", "HT", "1T", "54", "32",
+	"MKK", "5G", "40M", "HT", "1T", "54", "32",
+	"FCC", "5G", "40M", "HT", "1T", "62", "32",
+	"ETSI", "5G", "40M", "HT", "1T", "62", "32",
+	"MKK", "5G", "40M", "HT", "1T", "62", "32",
+	"FCC", "5G", "40M", "HT", "1T", "102", "28",
+	"ETSI", "5G", "40M", "HT", "1T", "102", "32",
+	"MKK", "5G", "40M", "HT", "1T", "102", "32",
+	"FCC", "5G", "40M", "HT", "1T", "110", "32",
+	"ETSI", "5G", "40M", "HT", "1T", "110", "32",
+	"MKK", "5G", "40M", "HT", "1T", "110", "32",
+	"FCC", "5G", "40M", "HT", "1T", "118", "36",
+	"ETSI", "5G", "40M", "HT", "1T", "118", "32",
+	"MKK", "5G", "40M", "HT", "1T", "118", "32",
+	"FCC", "5G", "40M", "HT", "1T", "126", "34",
+	"ETSI", "5G", "40M", "HT", "1T", "126", "32",
+	"MKK", "5G", "40M", "HT", "1T", "126", "32",
+	"FCC", "5G", "40M", "HT", "1T", "134", "32",
+	"ETSI", "5G", "40M", "HT", "1T", "134", "32",
+	"MKK", "5G", "40M", "HT", "1T", "134", "32",
+	"FCC", "5G", "40M", "HT", "1T", "151", "36",
+	"ETSI", "5G", "40M", "HT", "1T", "151", "32",
+	"MKK", "5G", "40M", "HT", "1T", "151", "63",
+	"FCC", "5G", "40M", "HT", "1T", "159", "36",
+	"ETSI", "5G", "40M", "HT", "1T", "159", "32",
+	"MKK", "5G", "40M", "HT", "1T", "159", "63",
+	"FCC", "5G", "40M", "HT", "2T", "38", "28",
+	"ETSI", "5G", "40M", "HT", "2T", "38", "30",
+	"MKK", "5G", "40M", "HT", "2T", "38", "30",
+	"FCC", "5G", "40M", "HT", "2T", "46", "28",
+	"ETSI", "5G", "40M", "HT", "2T", "46", "30",
+	"MKK", "5G", "40M", "HT", "2T", "46", "30",
+	"FCC", "5G", "40M", "HT", "2T", "54", "30",
+	"ETSI", "5G", "40M", "HT", "2T", "54", "30",
+	"MKK", "5G", "40M", "HT", "2T", "54", "30",
+	"FCC", "5G", "40M", "HT", "2T", "62", "30",
+	"ETSI", "5G", "40M", "HT", "2T", "62", "30",
+	"MKK", "5G", "40M", "HT", "2T", "62", "30",
+	"FCC", "5G", "40M", "HT", "2T", "102", "26",
+	"ETSI", "5G", "40M", "HT", "2T", "102", "30",
+	"MKK", "5G", "40M", "HT", "2T", "102", "30",
+	"FCC", "5G", "40M", "HT", "2T", "110", "30",
+	"ETSI", "5G", "40M", "HT", "2T", "110", "30",
+	"MKK", "5G", "40M", "HT", "2T", "110", "30",
+	"FCC", "5G", "40M", "HT", "2T", "118", "34",
+	"ETSI", "5G", "40M", "HT", "2T", "118", "30",
+	"MKK", "5G", "40M", "HT", "2T", "118", "30",
+	"FCC", "5G", "40M", "HT", "2T", "126", "32",
+	"ETSI", "5G", "40M", "HT", "2T", "126", "30",
+	"MKK", "5G", "40M", "HT", "2T", "126", "30",
+	"FCC", "5G", "40M", "HT", "2T", "134", "30",
+	"ETSI", "5G", "40M", "HT", "2T", "134", "30",
+	"MKK", "5G", "40M", "HT", "2T", "134", "30",
+	"FCC", "5G", "40M", "HT", "2T", "151", "34",
+	"ETSI", "5G", "40M", "HT", "2T", "151", "30",
+	"MKK", "5G", "40M", "HT", "2T", "151", "63",
+	"FCC", "5G", "40M", "HT", "2T", "159", "34",
+	"ETSI", "5G", "40M", "HT", "2T", "159", "30",
+	"MKK", "5G", "40M", "HT", "2T", "159", "63",
+	"FCC", "5G", "80M", "VHT", "1T", "42", "30",
+	"ETSI", "5G", "80M", "VHT", "1T", "42", "32",
+	"MKK", "5G", "80M", "VHT", "1T", "42", "32",
+	"FCC", "5G", "80M", "VHT", "1T", "58", "28",
+	"ETSI", "5G", "80M", "VHT", "1T", "58", "32",
+	"MKK", "5G", "80M", "VHT", "1T", "58", "32",
+	"FCC", "5G", "80M", "VHT", "1T", "106", "30",
+	"ETSI", "5G", "80M", "VHT", "1T", "106", "32",
+	"MKK", "5G", "80M", "VHT", "1T", "106", "32",
+	"FCC", "5G", "80M", "VHT", "1T", "122", "34",
+	"ETSI", "5G", "80M", "VHT", "1T", "122", "32",
+	"MKK", "5G", "80M", "VHT", "1T", "122", "32",
+	"FCC", "5G", "80M", "VHT", "1T", "155", "36",
+	"ETSI", "5G", "80M", "VHT", "1T", "155", "32",
+	"MKK", "5G", "80M", "VHT", "1T", "155", "63",
+	"FCC", "5G", "80M", "VHT", "2T", "42", "28",
+	"ETSI", "5G", "80M", "VHT", "2T", "42", "30",
+	"MKK", "5G", "80M", "VHT", "2T", "42", "30",
+	"FCC", "5G", "80M", "VHT", "2T", "58", "26",
+	"ETSI", "5G", "80M", "VHT", "2T", "58", "30",
+	"MKK", "5G", "80M", "VHT", "2T", "58", "30",
+	"FCC", "5G", "80M", "VHT", "2T", "106", "28",
+	"ETSI", "5G", "80M", "VHT", "2T", "106", "30",
+	"MKK", "5G", "80M", "VHT", "2T", "106", "30",
+	"FCC", "5G", "80M", "VHT", "2T", "122", "32",
+	"ETSI", "5G", "80M", "VHT", "2T", "122", "30",
+	"MKK", "5G", "80M", "VHT", "2T", "122", "30",
+	"FCC", "5G", "80M", "VHT", "2T", "155", "34",
+	"ETSI", "5G", "80M", "VHT", "2T", "155", "30",
+	"MKK", "5G", "80M", "VHT", "2T", "155", "63"
+};
+
+u8 *RTL8821AE_TXPWR_LMT[] = {
+	"FCC", "2.4G", "20M", "CCK", "1T", "01", "32",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "01", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "01", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "02", "32",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "02", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "02", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "03", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "03", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "03", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "04", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "04", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "04", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "05", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "05", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "05", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "06", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "06", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "06", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "07", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "07", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "07", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "08", "36",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "08", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "08", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "09", "32",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "09", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "09", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "10", "32",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "10", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "10", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "11", "32",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "11", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "11", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "12", "63",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "12", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "12", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "13", "63",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "13", "32",
+	"MKK", "2.4G", "20M", "CCK", "1T", "13", "32",
+	"FCC", "2.4G", "20M", "CCK", "1T", "14", "63",
+	"ETSI", "2.4G", "20M", "CCK", "1T", "14", "63",
+	"MKK", "2.4G", "20M", "CCK", "1T", "14", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "01", "30",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "01", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "01", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "02", "30",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "02", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "02", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "03", "32",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "03", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "03", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "04", "32",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "04", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "04", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "05", "32",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "05", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "05", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "06", "32",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "06", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "06", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "07", "32",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "07", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "07", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "08", "32",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "08", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "08", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "09", "30",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "09", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "09", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "10", "30",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "10", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "10", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "11", "30",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "11", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "11", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "12", "63",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "12", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "12", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "13", "63",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "13", "32",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "13", "32",
+	"FCC", "2.4G", "20M", "OFDM", "1T", "14", "63",
+	"ETSI", "2.4G", "20M", "OFDM", "1T", "14", "63",
+	"MKK", "2.4G", "20M", "OFDM", "1T", "14", "63",
+	"FCC", "2.4G", "20M", "HT", "1T", "01", "26",
+	"ETSI", "2.4G", "20M", "HT", "1T", "01", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "01", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "02", "26",
+	"ETSI", "2.4G", "20M", "HT", "1T", "02", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "02", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "03", "32",
+	"ETSI", "2.4G", "20M", "HT", "1T", "03", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "03", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "04", "32",
+	"ETSI", "2.4G", "20M", "HT", "1T", "04", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "04", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "05", "32",
+	"ETSI", "2.4G", "20M", "HT", "1T", "05", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "05", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "06", "32",
+	"ETSI", "2.4G", "20M", "HT", "1T", "06", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "06", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "07", "32",
+	"ETSI", "2.4G", "20M", "HT", "1T", "07", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "07", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "08", "32",
+	"ETSI", "2.4G", "20M", "HT", "1T", "08", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "08", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "09", "26",
+	"ETSI", "2.4G", "20M", "HT", "1T", "09", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "09", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "10", "26",
+	"ETSI", "2.4G", "20M", "HT", "1T", "10", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "10", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "11", "26",
+	"ETSI", "2.4G", "20M", "HT", "1T", "11", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "11", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "12", "63",
+	"ETSI", "2.4G", "20M", "HT", "1T", "12", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "12", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "13", "63",
+	"ETSI", "2.4G", "20M", "HT", "1T", "13", "32",
+	"MKK", "2.4G", "20M", "HT", "1T", "13", "32",
+	"FCC", "2.4G", "20M", "HT", "1T", "14", "63",
+	"ETSI", "2.4G", "20M", "HT", "1T", "14", "63",
+	"MKK", "2.4G", "20M", "HT", "1T", "14", "63",
+	"FCC", "2.4G", "20M", "HT", "2T", "01", "30",
+	"ETSI", "2.4G", "20M", "HT", "2T", "01", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "01", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "02", "32",
+	"ETSI", "2.4G", "20M", "HT", "2T", "02", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "02", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "03", "32",
+	"ETSI", "2.4G", "20M", "HT", "2T", "03", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "03", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "04", "32",
+	"ETSI", "2.4G", "20M", "HT", "2T", "04", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "04", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "05", "32",
+	"ETSI", "2.4G", "20M", "HT", "2T", "05", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "05", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "06", "32",
+	"ETSI", "2.4G", "20M", "HT", "2T", "06", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "06", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "07", "32",
+	"ETSI", "2.4G", "20M", "HT", "2T", "07", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "07", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "08", "32",
+	"ETSI", "2.4G", "20M", "HT", "2T", "08", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "08", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "09", "32",
+	"ETSI", "2.4G", "20M", "HT", "2T", "09", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "09", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "10", "32",
+	"ETSI", "2.4G", "20M", "HT", "2T", "10", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "10", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "11", "30",
+	"ETSI", "2.4G", "20M", "HT", "2T", "11", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "11", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "12", "63",
+	"ETSI", "2.4G", "20M", "HT", "2T", "12", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "12", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "13", "63",
+	"ETSI", "2.4G", "20M", "HT", "2T", "13", "32",
+	"MKK", "2.4G", "20M", "HT", "2T", "13", "32",
+	"FCC", "2.4G", "20M", "HT", "2T", "14", "63",
+	"ETSI", "2.4G", "20M", "HT", "2T", "14", "63",
+	"MKK", "2.4G", "20M", "HT", "2T", "14", "63",
+	"FCC", "2.4G", "40M", "HT", "1T", "01", "63",
+	"ETSI", "2.4G", "40M", "HT", "1T", "01", "63",
+	"MKK", "2.4G", "40M", "HT", "1T", "01", "63",
+	"FCC", "2.4G", "40M", "HT", "1T", "02", "63",
+	"ETSI", "2.4G", "40M", "HT", "1T", "02", "63",
+	"MKK", "2.4G", "40M", "HT", "1T", "02", "63",
+	"FCC", "2.4G", "40M", "HT", "1T", "03", "26",
+	"ETSI", "2.4G", "40M", "HT", "1T", "03", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "03", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "04", "26",
+	"ETSI", "2.4G", "40M", "HT", "1T", "04", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "04", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "05", "26",
+	"ETSI", "2.4G", "40M", "HT", "1T", "05", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "05", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "06", "32",
+	"ETSI", "2.4G", "40M", "HT", "1T", "06", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "06", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "07", "32",
+	"ETSI", "2.4G", "40M", "HT", "1T", "07", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "07", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "08", "32",
+	"ETSI", "2.4G", "40M", "HT", "1T", "08", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "08", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "09", "26",
+	"ETSI", "2.4G", "40M", "HT", "1T", "09", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "09", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "10", "26",
+	"ETSI", "2.4G", "40M", "HT", "1T", "10", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "10", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "11", "26",
+	"ETSI", "2.4G", "40M", "HT", "1T", "11", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "11", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "12", "63",
+	"ETSI", "2.4G", "40M", "HT", "1T", "12", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "12", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "13", "63",
+	"ETSI", "2.4G", "40M", "HT", "1T", "13", "32",
+	"MKK", "2.4G", "40M", "HT", "1T", "13", "32",
+	"FCC", "2.4G", "40M", "HT", "1T", "14", "63",
+	"ETSI", "2.4G", "40M", "HT", "1T", "14", "63",
+	"MKK", "2.4G", "40M", "HT", "1T", "14", "63",
+	"FCC", "2.4G", "40M", "HT", "2T", "01", "63",
+	"ETSI", "2.4G", "40M", "HT", "2T", "01", "63",
+	"MKK", "2.4G", "40M", "HT", "2T", "01", "63",
+	"FCC", "2.4G", "40M", "HT", "2T", "02", "63",
+	"ETSI", "2.4G", "40M", "HT", "2T", "02", "63",
+	"MKK", "2.4G", "40M", "HT", "2T", "02", "63",
+	"FCC", "2.4G", "40M", "HT", "2T", "03", "30",
+	"ETSI", "2.4G", "40M", "HT", "2T", "03", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "03", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "04", "32",
+	"ETSI", "2.4G", "40M", "HT", "2T", "04", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "04", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "05", "32",
+	"ETSI", "2.4G", "40M", "HT", "2T", "05", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "05", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "06", "32",
+	"ETSI", "2.4G", "40M", "HT", "2T", "06", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "06", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "07", "32",
+	"ETSI", "2.4G", "40M", "HT", "2T", "07", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "07", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "08", "32",
+	"ETSI", "2.4G", "40M", "HT", "2T", "08", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "08", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "09", "32",
+	"ETSI", "2.4G", "40M", "HT", "2T", "09", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "09", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "10", "32",
+	"ETSI", "2.4G", "40M", "HT", "2T", "10", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "10", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "11", "30",
+	"ETSI", "2.4G", "40M", "HT", "2T", "11", "30",
+	"MKK", "2.4G", "40M", "HT", "2T", "11", "30",
+	"FCC", "2.4G", "40M", "HT", "2T", "12", "63",
+	"ETSI", "2.4G", "40M", "HT", "2T", "12", "32",
+	"MKK", "2.4G", "40M", "HT", "2T", "12", "32",
+	"FCC", "2.4G", "40M", "HT", "2T", "13", "63",
+	"ETSI", "2.4G", "40M", "HT", "2T", "13", "32",
+	"MKK", "2.4G", "40M", "HT", "2T", "13", "32",
+	"FCC", "2.4G", "40M", "HT", "2T", "14", "63",
+	"ETSI", "2.4G", "40M", "HT", "2T", "14", "63",
+	"MKK", "2.4G", "40M", "HT", "2T", "14", "63",
+	"FCC", "5G", "20M", "OFDM", "1T", "36", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "36", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "36", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "40", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "40", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "40", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "44", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "44", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "44", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "48", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "48", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "48", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "52", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "52", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "52", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "56", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "56", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "56", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "60", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "60", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "60", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "64", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "64", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "64", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "100", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "100", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "100", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "114", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "114", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "114", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "108", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "108", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "108", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "112", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "112", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "112", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "116", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "116", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "116", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "120", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "120", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "120", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "124", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "124", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "124", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "128", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "128", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "128", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "132", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "132", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "132", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "136", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "136", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "136", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "140", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "140", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "140", "30",
+	"FCC", "5G", "20M", "OFDM", "1T", "149", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "149", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "149", "63",
+	"FCC", "5G", "20M", "OFDM", "1T", "153", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "153", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "153", "63",
+	"FCC", "5G", "20M", "OFDM", "1T", "157", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "157", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "157", "63",
+	"FCC", "5G", "20M", "OFDM", "1T", "161", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "161", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "161", "63",
+	"FCC", "5G", "20M", "OFDM", "1T", "165", "32",
+	"ETSI", "5G", "20M", "OFDM", "1T", "165", "30",
+	"MKK", "5G", "20M", "OFDM", "1T", "165", "63",
+	"FCC", "5G", "20M", "HT", "1T", "36", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "36", "30",
+	"MKK", "5G", "20M", "HT", "1T", "36", "30",
+	"FCC", "5G", "20M", "HT", "1T", "40", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "40", "30",
+	"MKK", "5G", "20M", "HT", "1T", "40", "30",
+	"FCC", "5G", "20M", "HT", "1T", "44", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "44", "30",
+	"MKK", "5G", "20M", "HT", "1T", "44", "30",
+	"FCC", "5G", "20M", "HT", "1T", "48", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "48", "30",
+	"MKK", "5G", "20M", "HT", "1T", "48", "30",
+	"FCC", "5G", "20M", "HT", "1T", "52", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "52", "30",
+	"MKK", "5G", "20M", "HT", "1T", "52", "30",
+	"FCC", "5G", "20M", "HT", "1T", "56", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "56", "30",
+	"MKK", "5G", "20M", "HT", "1T", "56", "30",
+	"FCC", "5G", "20M", "HT", "1T", "60", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "60", "30",
+	"MKK", "5G", "20M", "HT", "1T", "60", "30",
+	"FCC", "5G", "20M", "HT", "1T", "64", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "64", "30",
+	"MKK", "5G", "20M", "HT", "1T", "64", "30",
+	"FCC", "5G", "20M", "HT", "1T", "100", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "100", "30",
+	"MKK", "5G", "20M", "HT", "1T", "100", "30",
+	"FCC", "5G", "20M", "HT", "1T", "114", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "114", "30",
+	"MKK", "5G", "20M", "HT", "1T", "114", "30",
+	"FCC", "5G", "20M", "HT", "1T", "108", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "108", "30",
+	"MKK", "5G", "20M", "HT", "1T", "108", "30",
+	"FCC", "5G", "20M", "HT", "1T", "112", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "112", "30",
+	"MKK", "5G", "20M", "HT", "1T", "112", "30",
+	"FCC", "5G", "20M", "HT", "1T", "116", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "116", "30",
+	"MKK", "5G", "20M", "HT", "1T", "116", "30",
+	"FCC", "5G", "20M", "HT", "1T", "120", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "120", "30",
+	"MKK", "5G", "20M", "HT", "1T", "120", "30",
+	"FCC", "5G", "20M", "HT", "1T", "124", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "124", "30",
+	"MKK", "5G", "20M", "HT", "1T", "124", "30",
+	"FCC", "5G", "20M", "HT", "1T", "128", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "128", "30",
+	"MKK", "5G", "20M", "HT", "1T", "128", "30",
+	"FCC", "5G", "20M", "HT", "1T", "132", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "132", "30",
+	"MKK", "5G", "20M", "HT", "1T", "132", "30",
+	"FCC", "5G", "20M", "HT", "1T", "136", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "136", "30",
+	"MKK", "5G", "20M", "HT", "1T", "136", "30",
+	"FCC", "5G", "20M", "HT", "1T", "140", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "140", "30",
+	"MKK", "5G", "20M", "HT", "1T", "140", "30",
+	"FCC", "5G", "20M", "HT", "1T", "149", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "149", "30",
+	"MKK", "5G", "20M", "HT", "1T", "149", "63",
+	"FCC", "5G", "20M", "HT", "1T", "153", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "153", "30",
+	"MKK", "5G", "20M", "HT", "1T", "153", "63",
+	"FCC", "5G", "20M", "HT", "1T", "157", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "157", "30",
+	"MKK", "5G", "20M", "HT", "1T", "157", "63",
+	"FCC", "5G", "20M", "HT", "1T", "161", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "161", "30",
+	"MKK", "5G", "20M", "HT", "1T", "161", "63",
+	"FCC", "5G", "20M", "HT", "1T", "165", "32",
+	"ETSI", "5G", "20M", "HT", "1T", "165", "30",
+	"MKK", "5G", "20M", "HT", "1T", "165", "63",
+	"FCC", "5G", "20M", "HT", "2T", "36", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "36", "30",
+	"MKK", "5G", "20M", "HT", "2T", "36", "30",
+	"FCC", "5G", "20M", "HT", "2T", "40", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "40", "30",
+	"MKK", "5G", "20M", "HT", "2T", "40", "30",
+	"FCC", "5G", "20M", "HT", "2T", "44", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "44", "30",
+	"MKK", "5G", "20M", "HT", "2T", "44", "30",
+	"FCC", "5G", "20M", "HT", "2T", "48", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "48", "30",
+	"MKK", "5G", "20M", "HT", "2T", "48", "30",
+	"FCC", "5G", "20M", "HT", "2T", "52", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "52", "30",
+	"MKK", "5G", "20M", "HT", "2T", "52", "30",
+	"FCC", "5G", "20M", "HT", "2T", "56", "32",
+	"ETSI", "5G", "20M", "HT", "2T", "56", "30",
+	"MKK", "5G", "20M", "HT", "2T", "56", "30",
+	"FCC", "5G", "20M", "HT", "2T", "60", "30",
+	"ETSI", "5G", "20M", "HT", "2T", "60", "30",
+	"MKK", "5G", "20M", "HT", "2T", "60", "30",
+	"FCC", "5G", "20M", "HT", "2T", "64", "26",
+	"ETSI", "5G", "20M", "HT", "2T", "64", "30",
+	"MKK", "5G", "20M", "HT", "2T", "64", "30",
+	"FCC", "5G", "20M", "HT", "2T", "100", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "100", "30",
+	"MKK", "5G", "20M", "HT", "2T", "100", "30",
+	"FCC", "5G", "20M", "HT", "2T", "114", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "114", "30",
+	"MKK", "5G", "20M", "HT", "2T", "114", "30",
+	"FCC", "5G", "20M", "HT", "2T", "108", "30",
+	"ETSI", "5G", "20M", "HT", "2T", "108", "30",
+	"MKK", "5G", "20M", "HT", "2T", "108", "30",
+	"FCC", "5G", "20M", "HT", "2T", "112", "32",
+	"ETSI", "5G", "20M", "HT", "2T", "112", "30",
+	"MKK", "5G", "20M", "HT", "2T", "112", "30",
+	"FCC", "5G", "20M", "HT", "2T", "116", "32",
+	"ETSI", "5G", "20M", "HT", "2T", "116", "30",
+	"MKK", "5G", "20M", "HT", "2T", "116", "30",
+	"FCC", "5G", "20M", "HT", "2T", "120", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "120", "30",
+	"MKK", "5G", "20M", "HT", "2T", "120", "30",
+	"FCC", "5G", "20M", "HT", "2T", "124", "32",
+	"ETSI", "5G", "20M", "HT", "2T", "124", "30",
+	"MKK", "5G", "20M", "HT", "2T", "124", "30",
+	"FCC", "5G", "20M", "HT", "2T", "128", "30",
+	"ETSI", "5G", "20M", "HT", "2T", "128", "30",
+	"MKK", "5G", "20M", "HT", "2T", "128", "30",
+	"FCC", "5G", "20M", "HT", "2T", "132", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "132", "30",
+	"MKK", "5G", "20M", "HT", "2T", "132", "30",
+	"FCC", "5G", "20M", "HT", "2T", "136", "28",
+	"ETSI", "5G", "20M", "HT", "2T", "136", "30",
+	"MKK", "5G", "20M", "HT", "2T", "136", "30",
+	"FCC", "5G", "20M", "HT", "2T", "140", "26",
+	"ETSI", "5G", "20M", "HT", "2T", "140", "30",
+	"MKK", "5G", "20M", "HT", "2T", "140", "30",
+	"FCC", "5G", "20M", "HT", "2T", "149", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "149", "30",
+	"MKK", "5G", "20M", "HT", "2T", "149", "63",
+	"FCC", "5G", "20M", "HT", "2T", "153", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "153", "30",
+	"MKK", "5G", "20M", "HT", "2T", "153", "63",
+	"FCC", "5G", "20M", "HT", "2T", "157", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "157", "30",
+	"MKK", "5G", "20M", "HT", "2T", "157", "63",
+	"FCC", "5G", "20M", "HT", "2T", "161", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "161", "30",
+	"MKK", "5G", "20M", "HT", "2T", "161", "63",
+	"FCC", "5G", "20M", "HT", "2T", "165", "34",
+	"ETSI", "5G", "20M", "HT", "2T", "165", "30",
+	"MKK", "5G", "20M", "HT", "2T", "165", "63",
+	"FCC", "5G", "40M", "HT", "1T", "38", "26",
+	"ETSI", "5G", "40M", "HT", "1T", "38", "30",
+	"MKK", "5G", "40M", "HT", "1T", "38", "30",
+	"FCC", "5G", "40M", "HT", "1T", "46", "32",
+	"ETSI", "5G", "40M", "HT", "1T", "46", "30",
+	"MKK", "5G", "40M", "HT", "1T", "46", "30",
+	"FCC", "5G", "40M", "HT", "1T", "54", "32",
+	"ETSI", "5G", "40M", "HT", "1T", "54", "30",
+	"MKK", "5G", "40M", "HT", "1T", "54", "30",
+	"FCC", "5G", "40M", "HT", "1T", "62", "24",
+	"ETSI", "5G", "40M", "HT", "1T", "62", "30",
+	"MKK", "5G", "40M", "HT", "1T", "62", "30",
+	"FCC", "5G", "40M", "HT", "1T", "102", "24",
+	"ETSI", "5G", "40M", "HT", "1T", "102", "30",
+	"MKK", "5G", "40M", "HT", "1T", "102", "30",
+	"FCC", "5G", "40M", "HT", "1T", "110", "32",
+	"ETSI", "5G", "40M", "HT", "1T", "110", "30",
+	"MKK", "5G", "40M", "HT", "1T", "110", "30",
+	"FCC", "5G", "40M", "HT", "1T", "118", "32",
+	"ETSI", "5G", "40M", "HT", "1T", "118", "30",
+	"MKK", "5G", "40M", "HT", "1T", "118", "30",
+	"FCC", "5G", "40M", "HT", "1T", "126", "32",
+	"ETSI", "5G", "40M", "HT", "1T", "126", "30",
+	"MKK", "5G", "40M", "HT", "1T", "126", "30",
+	"FCC", "5G", "40M", "HT", "1T", "134", "32",
+	"ETSI", "5G", "40M", "HT", "1T", "134", "30",
+	"MKK", "5G", "40M", "HT", "1T", "134", "30",
+	"FCC", "5G", "40M", "HT", "1T", "151", "30",
+	"ETSI", "5G", "40M", "HT", "1T", "151", "30",
+	"MKK", "5G", "40M", "HT", "1T", "151", "63",
+	"FCC", "5G", "40M", "HT", "1T", "159", "32",
+	"ETSI", "5G", "40M", "HT", "1T", "159", "30",
+	"MKK", "5G", "40M", "HT", "1T", "159", "63",
+	"FCC", "5G", "40M", "HT", "2T", "38", "28",
+	"ETSI", "5G", "40M", "HT", "2T", "38", "30",
+	"MKK", "5G", "40M", "HT", "2T", "38", "30",
+	"FCC", "5G", "40M", "HT", "2T", "46", "28",
+	"ETSI", "5G", "40M", "HT", "2T", "46", "30",
+	"MKK", "5G", "40M", "HT", "2T", "46", "30",
+	"FCC", "5G", "40M", "HT", "2T", "54", "30",
+	"ETSI", "5G", "40M", "HT", "2T", "54", "30",
+	"MKK", "5G", "40M", "HT", "2T", "54", "30",
+	"FCC", "5G", "40M", "HT", "2T", "62", "30",
+	"ETSI", "5G", "40M", "HT", "2T", "62", "30",
+	"MKK", "5G", "40M", "HT", "2T", "62", "30",
+	"FCC", "5G", "40M", "HT", "2T", "102", "26",
+	"ETSI", "5G", "40M", "HT", "2T", "102", "30",
+	"MKK", "5G", "40M", "HT", "2T", "102", "30",
+	"FCC", "5G", "40M", "HT", "2T", "110", "30",
+	"ETSI", "5G", "40M", "HT", "2T", "110", "30",
+	"MKK", "5G", "40M", "HT", "2T", "110", "30",
+	"FCC", "5G", "40M", "HT", "2T", "118", "34",
+	"ETSI", "5G", "40M", "HT", "2T", "118", "30",
+	"MKK", "5G", "40M", "HT", "2T", "118", "30",
+	"FCC", "5G", "40M", "HT", "2T", "126", "32",
+	"ETSI", "5G", "40M", "HT", "2T", "126", "30",
+	"MKK", "5G", "40M", "HT", "2T", "126", "30",
+	"FCC", "5G", "40M", "HT", "2T", "134", "30",
+	"ETSI", "5G", "40M", "HT", "2T", "134", "30",
+	"MKK", "5G", "40M", "HT", "2T", "134", "30",
+	"FCC", "5G", "40M", "HT", "2T", "151", "34",
+	"ETSI", "5G", "40M", "HT", "2T", "151", "30",
+	"MKK", "5G", "40M", "HT", "2T", "151", "63",
+	"FCC", "5G", "40M", "HT", "2T", "159", "34",
+	"ETSI", "5G", "40M", "HT", "2T", "159", "30",
+	"MKK", "5G", "40M", "HT", "2T", "159", "63",
+	"FCC", "5G", "80M", "VHT", "1T", "42", "22",
+	"ETSI", "5G", "80M", "VHT", "1T", "42", "30",
+	"MKK", "5G", "80M", "VHT", "1T", "42", "30",
+	"FCC", "5G", "80M", "VHT", "1T", "58", "20",
+	"ETSI", "5G", "80M", "VHT", "1T", "58", "30",
+	"MKK", "5G", "80M", "VHT", "1T", "58", "30",
+	"FCC", "5G", "80M", "VHT", "1T", "106", "20",
+	"ETSI", "5G", "80M", "VHT", "1T", "106", "30",
+	"MKK", "5G", "80M", "VHT", "1T", "106", "30",
+	"FCC", "5G", "80M", "VHT", "1T", "122", "20",
+	"ETSI", "5G", "80M", "VHT", "1T", "122", "30",
+	"MKK", "5G", "80M", "VHT", "1T", "122", "30",
+	"FCC", "5G", "80M", "VHT", "1T", "155", "28",
+	"ETSI", "5G", "80M", "VHT", "1T", "155", "30",
+	"MKK", "5G", "80M", "VHT", "1T", "155", "63",
+	"FCC", "5G", "80M", "VHT", "2T", "42", "28",
+	"ETSI", "5G", "80M", "VHT", "2T", "42", "30",
+	"MKK", "5G", "80M", "VHT", "2T", "42", "30",
+	"FCC", "5G", "80M", "VHT", "2T", "58", "26",
+	"ETSI", "5G", "80M", "VHT", "2T", "58", "30",
+	"MKK", "5G", "80M", "VHT", "2T", "58", "30",
+	"FCC", "5G", "80M", "VHT", "2T", "106", "28",
+	"ETSI", "5G", "80M", "VHT", "2T", "106", "30",
+	"MKK", "5G", "80M", "VHT", "2T", "106", "30",
+	"FCC", "5G", "80M", "VHT", "2T", "122", "32",
+	"ETSI", "5G", "80M", "VHT", "2T", "122", "30",
+	"MKK", "5G", "80M", "VHT", "2T", "122", "30",
+	"FCC", "5G", "80M", "VHT", "2T", "155", "34",
+	"ETSI", "5G", "80M", "VHT", "2T", "155", "30",
+	"MKK", "5G", "80M", "VHT", "2T", "155", "63"
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/table.h b/drivers/net/wireless/rtlwifi/rtl8821ae/table.h
new file mode 100644
index 0000000..24bcff6
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/table.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on  2010/ 5/18,  1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8821AE_TABLE__H_
+#define __RTL8821AE_TABLE__H_
+
+#include <linux/types.h>
+#define  RTL8821AEPHY_REG_1TARRAYLEN	344
+extern u32 RTL8821AE_PHY_REG_ARRAY[];
+#define  RTL8812AEPHY_REG_1TARRAYLEN	490
+extern u32 RTL8812AE_PHY_REG_ARRAY[];
+#define RTL8821AEPHY_REG_ARRAY_PGLEN	90
+extern u32 RTL8821AE_PHY_REG_ARRAY_PG[];
+#define RTL8812AEPHY_REG_ARRAY_PGLEN	276
+extern u32 RTL8812AE_PHY_REG_ARRAY_PG[];
+/* #define	RTL8723BE_RADIOA_1TARRAYLEN	206 */
+/* extern u8 *RTL8821AE_TXPWR_LMT_ARRAY[]; */
+#define	RTL8812AE_RADIOA_1TARRAYLEN	1264
+extern u32 RTL8812AE_RADIOA_ARRAY[];
+#define	RTL8812AE_RADIOB_1TARRAYLEN	1240
+extern u32 RTL8812AE_RADIOB_ARRAY[];
+#define	RTL8821AE_RADIOA_1TARRAYLEN	1176
+extern u32 RTL8821AE_RADIOA_ARRAY[];
+#define RTL8821AEMAC_1T_ARRAYLEN		194
+extern u32 RTL8821AE_MAC_REG_ARRAY[];
+#define RTL8812AEMAC_1T_ARRAYLEN		214
+extern u32 RTL8812AE_MAC_REG_ARRAY[];
+#define RTL8821AEAGCTAB_1TARRAYLEN		382
+extern u32 RTL8821AE_AGC_TAB_ARRAY[];
+#define RTL8812AEAGCTAB_1TARRAYLEN		1312
+extern u32 RTL8812AE_AGC_TAB_ARRAY[];
+#define RTL8812AE_TXPWR_LMT_ARRAY_LEN		3948
+extern u8 *RTL8812AE_TXPWR_LMT[];
+#define RTL8821AE_TXPWR_LMT_ARRAY_LEN		3948
+extern u8 *RTL8821AE_TXPWR_LMT[];
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c
new file mode 100644
index 0000000..383b86b
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c
@@ -0,0 +1,1236 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "../stats.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "trx.h"
+#include "led.h"
+#include "dm.h"
+#include "phy.h"
+#include "fw.h"
+
+static u8 _rtl8821ae_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
+{
+	__le16 fc = rtl_get_fc(skb);
+
+	if (unlikely(ieee80211_is_beacon(fc)))
+		return QSLT_BEACON;
+	if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
+		return QSLT_MGNT;
+
+	return skb->priority;
+}
+
+/* mac80211's rate_idx is like this:
+ *
+ * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
+ *
+ * B/G rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC_RATE1M-->DESC_RATE54M ==> idx is 0-->11,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15
+ *
+ * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
+ * A rate:
+ * (rx_status->flag & RX_FLAG_HT) = 0,
+ * DESC_RATE6M-->DESC_RATE54M ==> idx is 0-->7,
+ *
+ * N rate:
+ * (rx_status->flag & RX_FLAG_HT) = 1,
+ * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15
+ */
+static int _rtl8821ae_rate_mapping(struct ieee80211_hw *hw,
+				   bool isht, bool isvht, u8 desc_rate)
+{
+	int rate_idx;
+
+	if (!isht) {
+		if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
+			switch (desc_rate) {
+			case DESC_RATE1M:
+				rate_idx = 0;
+				break;
+			case DESC_RATE2M:
+				rate_idx = 1;
+				break;
+			case DESC_RATE5_5M:
+				rate_idx = 2;
+				break;
+			case DESC_RATE11M:
+				rate_idx = 3;
+				break;
+			case DESC_RATE6M:
+				rate_idx = 4;
+				break;
+			case DESC_RATE9M:
+				rate_idx = 5;
+				break;
+			case DESC_RATE12M:
+				rate_idx = 6;
+				break;
+			case DESC_RATE18M:
+				rate_idx = 7;
+				break;
+			case DESC_RATE24M:
+				rate_idx = 8;
+				break;
+			case DESC_RATE36M:
+				rate_idx = 9;
+				break;
+			case DESC_RATE48M:
+				rate_idx = 10;
+				break;
+			case DESC_RATE54M:
+				rate_idx = 11;
+				break;
+			default:
+				rate_idx = 0;
+				break;
+			}
+		} else {
+			switch (desc_rate) {
+			case DESC_RATE6M:
+				rate_idx = 0;
+				break;
+			case DESC_RATE9M:
+				rate_idx = 1;
+				break;
+			case DESC_RATE12M:
+				rate_idx = 2;
+				break;
+			case DESC_RATE18M:
+				rate_idx = 3;
+				break;
+			case DESC_RATE24M:
+				rate_idx = 4;
+				break;
+			case DESC_RATE36M:
+				rate_idx = 5;
+				break;
+			case DESC_RATE48M:
+				rate_idx = 6;
+				break;
+			case DESC_RATE54M:
+				rate_idx = 7;
+				break;
+			default:
+				rate_idx = 0;
+				break;
+			}
+		}
+	} else {
+		switch (desc_rate) {
+		case DESC_RATEMCS0:
+			rate_idx = 0;
+			break;
+		case DESC_RATEMCS1:
+			rate_idx = 1;
+			break;
+		case DESC_RATEMCS2:
+			rate_idx = 2;
+			break;
+		case DESC_RATEMCS3:
+			rate_idx = 3;
+			break;
+		case DESC_RATEMCS4:
+			rate_idx = 4;
+			break;
+		case DESC_RATEMCS5:
+			rate_idx = 5;
+			break;
+		case DESC_RATEMCS6:
+			rate_idx = 6;
+			break;
+		case DESC_RATEMCS7:
+			rate_idx = 7;
+			break;
+		case DESC_RATEMCS8:
+			rate_idx = 8;
+			break;
+		case DESC_RATEMCS9:
+			rate_idx = 9;
+			break;
+		case DESC_RATEMCS10:
+			rate_idx = 10;
+			break;
+		case DESC_RATEMCS11:
+			rate_idx = 11;
+			break;
+		case DESC_RATEMCS12:
+			rate_idx = 12;
+			break;
+		case DESC_RATEMCS13:
+			rate_idx = 13;
+			break;
+		case DESC_RATEMCS14:
+			rate_idx = 14;
+			break;
+		case DESC_RATEMCS15:
+			rate_idx = 15;
+			break;
+		default:
+			rate_idx = 0;
+			break;
+		}
+	}
+
+	if (isvht) {
+		switch (desc_rate) {
+		case DESC_RATEVHT1SS_MCS0:
+			rate_idx = 0;
+			break;
+		case DESC_RATEVHT1SS_MCS1:
+			rate_idx = 1;
+			break;
+		case DESC_RATEVHT1SS_MCS2:
+			rate_idx = 2;
+			break;
+		case DESC_RATEVHT1SS_MCS3:
+			rate_idx = 3;
+			break;
+		case DESC_RATEVHT1SS_MCS4:
+			rate_idx = 4;
+			break;
+		case DESC_RATEVHT1SS_MCS5:
+			rate_idx = 5;
+			break;
+		case DESC_RATEVHT1SS_MCS6:
+			rate_idx = 6;
+			break;
+		case DESC_RATEVHT1SS_MCS7:
+			rate_idx = 7;
+			break;
+		case DESC_RATEVHT1SS_MCS8:
+			rate_idx = 8;
+			break;
+		case DESC_RATEVHT1SS_MCS9:
+			rate_idx = 9;
+			break;
+		case DESC_RATEVHT2SS_MCS0:
+			rate_idx = 0;
+			break;
+		case DESC_RATEVHT2SS_MCS1:
+			rate_idx = 1;
+			break;
+		case DESC_RATEVHT2SS_MCS2:
+			rate_idx = 2;
+			break;
+		case DESC_RATEVHT2SS_MCS3:
+			rate_idx = 3;
+			break;
+		case DESC_RATEVHT2SS_MCS4:
+			rate_idx = 4;
+			break;
+		case DESC_RATEVHT2SS_MCS5:
+			rate_idx = 5;
+			break;
+		case DESC_RATEVHT2SS_MCS6:
+			rate_idx = 6;
+			break;
+		case DESC_RATEVHT2SS_MCS7:
+			rate_idx = 7;
+			break;
+		case DESC_RATEVHT2SS_MCS8:
+			rate_idx = 8;
+			break;
+		case DESC_RATEVHT2SS_MCS9:
+			rate_idx = 9;
+			break;
+		default:
+			rate_idx = 0;
+			break;
+		}
+	}
+	return rate_idx;
+}
+
+static u16 odm_cfo(char value)
+{
+	int ret_val;
+
+	if (value < 0) {
+		ret_val = 0 - value;
+		ret_val = (ret_val << 1) + (ret_val >> 1);
+		/* set bit12 as 1 for negative cfo */
+		ret_val = ret_val | BIT(12);
+	} else {
+		ret_val = value;
+		ret_val = (ret_val << 1) + (ret_val >> 1);
+	}
+	return ret_val;
+}
+
+static void query_rxphystatus(struct ieee80211_hw *hw,
+			      struct rtl_stats *pstatus, u8 *pdesc,
+			      struct rx_fwinfo_8821ae *p_drvinfo,
+			      bool bpacket_match_bssid,
+			      bool bpacket_toself, bool packet_beacon)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct phy_status_rpt *p_phystrpt = (struct phy_status_rpt *)p_drvinfo;
+	struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	char rx_pwr_all = 0, rx_pwr[4];
+	u8 rf_rx_num = 0, evm, evmdbm, pwdb_all;
+	u8 i, max_spatial_stream;
+	u32 rssi, total_rssi = 0;
+	bool is_cck = pstatus->is_cck;
+	u8 lan_idx, vga_idx;
+
+	/* Record it for next packet processing */
+	pstatus->packet_matchbssid = bpacket_match_bssid;
+	pstatus->packet_toself = bpacket_toself;
+	pstatus->packet_beacon = packet_beacon;
+	pstatus->rx_mimo_signalquality[0] = -1;
+	pstatus->rx_mimo_signalquality[1] = -1;
+
+	if (is_cck) {
+		u8 cck_highpwr;
+		u8 cck_agc_rpt;
+
+		cck_agc_rpt = p_phystrpt->cfosho[0];
+
+		/* (1)Hardware does not provide RSSI for CCK
+		 * (2)PWDB, Average PWDB cacluated by
+		 * hardware (for rate adaptive)
+		 */
+		cck_highpwr = (u8)rtlphy->cck_high_power;
+
+		lan_idx = ((cck_agc_rpt & 0xE0) >> 5);
+		vga_idx = (cck_agc_rpt & 0x1f);
+		if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8812AE) {
+			switch (lan_idx) {
+			case 7:
+				if (vga_idx <= 27)
+					/*VGA_idx = 27~2*/
+					rx_pwr_all = -100 + 2*(27-vga_idx);
+				else
+					rx_pwr_all = -100;
+				break;
+			case 6:
+				/*VGA_idx = 2~0*/
+				rx_pwr_all = -48 + 2*(2-vga_idx);
+				break;
+			case 5:
+				/*VGA_idx = 7~5*/
+				rx_pwr_all = -42 + 2*(7-vga_idx);
+				break;
+			case 4:
+				/*VGA_idx = 7~4*/
+				rx_pwr_all = -36 + 2*(7-vga_idx);
+				break;
+			case 3:
+				/*VGA_idx = 7~0*/
+				rx_pwr_all = -24 + 2*(7-vga_idx);
+				break;
+			case 2:
+				if (cck_highpwr)
+					/*VGA_idx = 5~0*/
+					rx_pwr_all = -12 + 2*(5-vga_idx);
+				else
+					rx_pwr_all = -6 + 2*(5-vga_idx);
+				break;
+			case 1:
+				rx_pwr_all = 8-2*vga_idx;
+				break;
+			case 0:
+				rx_pwr_all = 14-2*vga_idx;
+				break;
+			default:
+				break;
+			}
+			rx_pwr_all += 6;
+			pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+			if (!cck_highpwr) {
+				if (pwdb_all >= 80)
+					pwdb_all =
+					  ((pwdb_all - 80)<<1) +
+					 ((pwdb_all - 80)>>1) + 80;
+				else if ((pwdb_all <= 78) && (pwdb_all >= 20))
+					pwdb_all += 3;
+				if (pwdb_all > 100)
+					pwdb_all = 100;
+			}
+		} else { /* 8821 */
+			char pout = -6;
+
+			switch (lan_idx) {
+			case 5:
+				rx_pwr_all = pout - 32 - (2*vga_idx);
+					break;
+			case 4:
+				rx_pwr_all = pout - 24 - (2*vga_idx);
+					break;
+			case 2:
+				rx_pwr_all = pout - 11 - (2*vga_idx);
+					break;
+			case 1:
+				rx_pwr_all = pout + 5 - (2*vga_idx);
+					break;
+			case 0:
+				rx_pwr_all = pout + 21 - (2*vga_idx);
+					break;
+			}
+			pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+		}
+
+		pstatus->rx_pwdb_all = pwdb_all;
+		pstatus->recvsignalpower = rx_pwr_all;
+
+		/* (3) Get Signal Quality (EVM) */
+		if (bpacket_match_bssid) {
+			u8 sq;
+
+			if (pstatus->rx_pwdb_all > 40) {
+				sq = 100;
+			} else {
+				sq = p_phystrpt->pwdb_all;
+				if (sq > 64)
+					sq = 0;
+				else if (sq < 20)
+					sq = 100;
+				else
+					sq = ((64 - sq) * 100) / 44;
+			}
+
+			pstatus->signalquality = sq;
+			pstatus->rx_mimo_signalquality[0] = sq;
+			pstatus->rx_mimo_signalquality[1] = -1;
+		}
+	} else {
+		/* (1)Get RSSI for HT rate */
+		for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) {
+			/* we will judge RF RX path now. */
+			if (rtlpriv->dm.rfpath_rxenable[i])
+				rf_rx_num++;
+
+			rx_pwr[i] = (p_phystrpt->gain_trsw[i] & 0x7f) - 110;
+
+			/* Translate DBM to percentage. */
+			rssi = rtl_query_rxpwrpercentage(rx_pwr[i]);
+			total_rssi += rssi;
+
+			/* Get Rx snr value in DB */
+			pstatus->rx_snr[i] = p_phystrpt->rxsnr[i] / 2;
+			rtlpriv->stats.rx_snr_db[i] = p_phystrpt->rxsnr[i] / 2;
+
+			pstatus->cfo_short[i] = odm_cfo(p_phystrpt->cfosho[i]);
+			pstatus->cfo_tail[i] = odm_cfo(p_phystrpt->cfotail[i]);
+			/* Record Signal Strength for next packet */
+			pstatus->rx_mimo_signalstrength[i] = (u8)rssi;
+		}
+
+		/* (2)PWDB, Average PWDB cacluated by
+		 * hardware (for rate adaptive)
+		 */
+		rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
+
+		pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+		pstatus->rx_pwdb_all = pwdb_all;
+		pstatus->rxpower = rx_pwr_all;
+		pstatus->recvsignalpower = rx_pwr_all;
+
+		/* (3)EVM of HT rate */
+		if ((pstatus->is_ht && pstatus->rate >= DESC_RATEMCS8 &&
+		     pstatus->rate <= DESC_RATEMCS15) ||
+		    (pstatus->is_vht &&
+		     pstatus->rate >= DESC_RATEVHT2SS_MCS0 &&
+		     pstatus->rate <= DESC_RATEVHT2SS_MCS9))
+			max_spatial_stream = 2;
+		else
+			max_spatial_stream = 1;
+
+		for (i = 0; i < max_spatial_stream; i++) {
+			evm = rtl_evm_db_to_percentage(p_phystrpt->rxevm[i]);
+			evmdbm = rtl_evm_dbm_jaguar(p_phystrpt->rxevm[i]);
+
+			if (bpacket_match_bssid) {
+				/* Fill value in RFD, Get the first
+				 * spatial stream only
+				 */
+				if (i == 0)
+					pstatus->signalquality = evm;
+				pstatus->rx_mimo_signalquality[i] = evm;
+				pstatus->rx_mimo_evm_dbm[i] = evmdbm;
+			}
+		}
+		if (bpacket_match_bssid) {
+			for (i = RF90_PATH_A; i <= RF90_PATH_B; i++)
+				rtl_priv(hw)->dm.cfo_tail[i] =
+					(char)p_phystrpt->cfotail[i];
+
+			rtl_priv(hw)->dm.packet_count++;
+		}
+	}
+
+	/* UI BSS List signal strength(in percentage),
+	 * make it good looking, from 0~100.
+	 */
+	if (is_cck)
+		pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+			pwdb_all));
+	else if (rf_rx_num != 0)
+		pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+			total_rssi /= rf_rx_num));
+	/*HW antenna diversity*/
+	rtldm->fat_table.antsel_rx_keep_0 = p_phystrpt->antidx_anta;
+	rtldm->fat_table.antsel_rx_keep_1 = p_phystrpt->antidx_antb;
+}
+
+static void translate_rx_signal_stuff(struct ieee80211_hw *hw,
+				      struct sk_buff *skb,
+				      struct rtl_stats *pstatus, u8 *pdesc,
+				      struct rx_fwinfo_8821ae *p_drvinfo)
+{
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+	struct ieee80211_hdr *hdr;
+	u8 *tmp_buf;
+	u8 *praddr;
+	u8 *psaddr;
+	__le16 fc;
+	u16 type;
+	bool packet_matchbssid, packet_toself, packet_beacon;
+
+	tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
+
+	hdr = (struct ieee80211_hdr *)tmp_buf;
+	fc = hdr->frame_control;
+	type = WLAN_FC_GET_TYPE(hdr->frame_control);
+	praddr = hdr->addr1;
+	psaddr = ieee80211_get_SA(hdr);
+	ether_addr_copy(pstatus->psaddr, psaddr);
+
+	packet_matchbssid = (!ieee80211_is_ctl(fc) &&
+			     (ether_addr_equal(mac->bssid,
+					       ieee80211_has_tods(fc) ?
+					       hdr->addr1 :
+					       ieee80211_has_fromds(fc) ?
+					       hdr->addr2 : hdr->addr3)) &&
+			      (!pstatus->hwerror) &&
+			      (!pstatus->crc) && (!pstatus->icv));
+
+	packet_toself = packet_matchbssid &&
+	    (ether_addr_equal(praddr, rtlefuse->dev_addr));
+
+	if (ieee80211_is_beacon(hdr->frame_control))
+		packet_beacon = true;
+	else
+		packet_beacon = false;
+
+	if (packet_beacon && packet_matchbssid)
+		rtl_priv(hw)->dm.dbginfo.num_qry_beacon_pkt++;
+
+	if (packet_matchbssid &&
+	    ieee80211_is_data_qos(hdr->frame_control) &&
+	    !is_multicast_ether_addr(ieee80211_get_DA(hdr))) {
+		struct ieee80211_qos_hdr *hdr_qos =
+			(struct ieee80211_qos_hdr *)tmp_buf;
+		u16 tid = le16_to_cpu(hdr_qos->qos_ctrl) & 0xf;
+
+		if (tid != 0 && tid != 3)
+			rtl_priv(hw)->dm.dbginfo.num_non_be_pkt++;
+	}
+
+	query_rxphystatus(hw, pstatus, pdesc, p_drvinfo,
+			  packet_matchbssid, packet_toself,
+			  packet_beacon);
+	/*_rtl8821ae_smart_antenna(hw, pstatus); */
+	rtl_process_phyinfo(hw, tmp_buf, pstatus);
+}
+
+static void _rtl8821ae_insert_emcontent(struct rtl_tcb_desc *ptcb_desc,
+					u8 *virtualaddress)
+{
+	u32 dwtmp = 0;
+
+	memset(virtualaddress, 0, 8);
+
+	SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num);
+	if (ptcb_desc->empkt_num == 1) {
+		dwtmp = ptcb_desc->empkt_len[0];
+	} else {
+		dwtmp = ptcb_desc->empkt_len[0];
+		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0)+4;
+		dwtmp += ptcb_desc->empkt_len[1];
+	}
+	SET_EARLYMODE_LEN0(virtualaddress, dwtmp);
+
+	if (ptcb_desc->empkt_num <= 3) {
+		dwtmp = ptcb_desc->empkt_len[2];
+	} else {
+		dwtmp = ptcb_desc->empkt_len[2];
+		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0)+4;
+		dwtmp += ptcb_desc->empkt_len[3];
+	}
+	SET_EARLYMODE_LEN1(virtualaddress, dwtmp);
+	if (ptcb_desc->empkt_num <= 5) {
+		dwtmp = ptcb_desc->empkt_len[4];
+	} else {
+		dwtmp = ptcb_desc->empkt_len[4];
+		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0)+4;
+		dwtmp += ptcb_desc->empkt_len[5];
+	}
+	SET_EARLYMODE_LEN2_1(virtualaddress, dwtmp & 0xF);
+	SET_EARLYMODE_LEN2_2(virtualaddress, dwtmp >> 4);
+	if (ptcb_desc->empkt_num <= 7) {
+		dwtmp = ptcb_desc->empkt_len[6];
+	} else {
+		dwtmp = ptcb_desc->empkt_len[6];
+		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0)+4;
+		dwtmp += ptcb_desc->empkt_len[7];
+	}
+	SET_EARLYMODE_LEN3(virtualaddress, dwtmp);
+	if (ptcb_desc->empkt_num <= 9) {
+		dwtmp = ptcb_desc->empkt_len[8];
+	} else {
+		dwtmp = ptcb_desc->empkt_len[8];
+		dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0)+4;
+		dwtmp += ptcb_desc->empkt_len[9];
+	}
+	SET_EARLYMODE_LEN4(virtualaddress, dwtmp);
+}
+
+static bool rtl8821ae_get_rxdesc_is_ht(struct ieee80211_hw *hw, u8 *pdesc)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 rx_rate = 0;
+
+	rx_rate = GET_RX_DESC_RXMCS(pdesc);
+
+	RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD, "rx_rate=0x%02x.\n", rx_rate);
+
+	if ((rx_rate >= DESC_RATEMCS0) && (rx_rate <= DESC_RATEMCS15))
+		return true;
+	return false;
+}
+
+static bool rtl8821ae_get_rxdesc_is_vht(struct ieee80211_hw *hw, u8 *pdesc)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	u8 rx_rate = 0;
+
+	rx_rate = GET_RX_DESC_RXMCS(pdesc);
+
+	RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD, "rx_rate=0x%02x.\n", rx_rate);
+
+	if (rx_rate >= DESC_RATEVHT1SS_MCS0)
+		return true;
+	return false;
+}
+
+static u8 rtl8821ae_get_rx_vht_nss(struct ieee80211_hw *hw, u8 *pdesc)
+{
+	u8 rx_rate = 0;
+	u8 vht_nss = 0;
+
+	rx_rate = GET_RX_DESC_RXMCS(pdesc);
+	if ((rx_rate >= DESC_RATEVHT1SS_MCS0) &&
+	    (rx_rate <= DESC_RATEVHT1SS_MCS9))
+		vht_nss = 1;
+	else if ((rx_rate >= DESC_RATEVHT2SS_MCS0) &&
+		 (rx_rate <= DESC_RATEVHT2SS_MCS9))
+		vht_nss = 2;
+
+	return vht_nss;
+}
+
+bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw,
+			     struct rtl_stats *status,
+			     struct ieee80211_rx_status *rx_status,
+			     u8 *pdesc, struct sk_buff *skb)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rx_fwinfo_8821ae *p_drvinfo;
+	struct ieee80211_hdr *hdr;
+
+	u32 phystatus = GET_RX_DESC_PHYST(pdesc);
+
+	status->length = (u16)GET_RX_DESC_PKT_LEN(pdesc);
+	status->rx_drvinfo_size = (u8)GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
+	    RX_DRV_INFO_SIZE_UNIT;
+	status->rx_bufshift = (u8)(GET_RX_DESC_SHIFT(pdesc) & 0x03);
+	status->icv = (u16)GET_RX_DESC_ICV(pdesc);
+	status->crc = (u16)GET_RX_DESC_CRC32(pdesc);
+	status->hwerror = (status->crc | status->icv);
+	status->decrypted = !GET_RX_DESC_SWDEC(pdesc);
+	status->rate = (u8)GET_RX_DESC_RXMCS(pdesc);
+	status->shortpreamble = (u16)GET_RX_DESC_SPLCP(pdesc);
+	status->isampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1);
+	status->isfirst_ampdu = (bool)(GET_RX_DESC_PAGGR(pdesc) == 1);
+	status->timestamp_low = GET_RX_DESC_TSFL(pdesc);
+	status->rx_packet_bw = GET_RX_DESC_BW(pdesc);
+	status->macid = GET_RX_DESC_MACID(pdesc);
+	status->is_short_gi = !(bool)GET_RX_DESC_SPLCP(pdesc);
+	status->is_ht = rtl8821ae_get_rxdesc_is_ht(hw, pdesc);
+	status->is_vht = rtl8821ae_get_rxdesc_is_vht(hw, pdesc);
+	status->vht_nss = rtl8821ae_get_rx_vht_nss(hw, pdesc);
+	status->is_cck = RTL8821AE_RX_HAL_IS_CCK_RATE(status->rate);
+
+	RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD,
+		 "rx_packet_bw=%s,is_ht %d, is_vht %d, vht_nss=%d,is_short_gi %d.\n",
+		 (status->rx_packet_bw == 2) ? "80M" :
+		 (status->rx_packet_bw == 1) ? "40M" : "20M",
+		 status->is_ht, status->is_vht, status->vht_nss,
+		 status->is_short_gi);
+
+	if (GET_RX_STATUS_DESC_RPT_SEL(pdesc))
+		status->packet_report_type = C2H_PACKET;
+	else
+		status->packet_report_type = NORMAL_RX;
+
+	if (GET_RX_STATUS_DESC_PATTERN_MATCH(pdesc))
+		status->wake_match = BIT(2);
+	else if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
+		status->wake_match = BIT(1);
+	else if (GET_RX_STATUS_DESC_UNICAST_MATCH(pdesc))
+		status->wake_match = BIT(0);
+	else
+		status->wake_match = 0;
+
+	if (status->wake_match)
+		RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD,
+			 "GGGGGGGGGGGGGet Wakeup Packet!! WakeMatch=%d\n",
+			 status->wake_match);
+	rx_status->freq = hw->conf.chandef.chan->center_freq;
+	rx_status->band = hw->conf.chandef.chan->band;
+
+	hdr = (struct ieee80211_hdr *)(skb->data +
+	      status->rx_drvinfo_size + status->rx_bufshift);
+
+	if (status->crc)
+		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+	if (status->rx_packet_bw == HT_CHANNEL_WIDTH_20_40)
+		rx_status->flag |= RX_FLAG_40MHZ;
+	else if (status->rx_packet_bw == HT_CHANNEL_WIDTH_80)
+		rx_status->vht_flag |= RX_VHT_FLAG_80MHZ;
+	if (status->is_ht)
+		rx_status->flag |= RX_FLAG_HT;
+	if (status->is_vht)
+		rx_status->flag |= RX_FLAG_VHT;
+
+	if (status->is_short_gi)
+		rx_status->flag |= RX_FLAG_SHORT_GI;
+
+	rx_status->vht_nss = status->vht_nss;
+	rx_status->flag |= RX_FLAG_MACTIME_START;
+
+	/* hw will set status->decrypted true, if it finds the
+	 * frame is open data frame or mgmt frame.
+	 * So hw will not decryption robust managment frame
+	 * for IEEE80211w but still set status->decrypted
+	 * true, so here we should set it back to undecrypted
+	 * for IEEE80211w frame, and mac80211 sw will help
+	 * to decrypt it
+	 */
+	if (status->decrypted) {
+		if ((!_ieee80211_is_robust_mgmt_frame(hdr)) &&
+		    (ieee80211_has_protected(hdr->frame_control)))
+			rx_status->flag |= RX_FLAG_DECRYPTED;
+		else
+			rx_status->flag &= ~RX_FLAG_DECRYPTED;
+	}
+
+	/* rate_idx: index of data rate into band's
+	 * supported rates or MCS index if HT rates
+	 * are use (RX_FLAG_HT)
+	 */
+	rx_status->rate_idx =
+	  _rtl8821ae_rate_mapping(hw, status->is_ht,
+				  status->is_vht, status->rate);
+
+	rx_status->mactime = status->timestamp_low;
+	if (phystatus) {
+		p_drvinfo = (struct rx_fwinfo_8821ae *)(skb->data +
+			    status->rx_bufshift);
+
+		translate_rx_signal_stuff(hw, skb, status, pdesc, p_drvinfo);
+	}
+	rx_status->signal = status->recvsignalpower + 10;
+	if (status->packet_report_type == TX_REPORT2) {
+		status->macid_valid_entry[0] =
+		  GET_RX_RPT2_DESC_MACID_VALID_1(pdesc);
+		status->macid_valid_entry[1] =
+		  GET_RX_RPT2_DESC_MACID_VALID_2(pdesc);
+	}
+	return true;
+}
+
+static u8 rtl8821ae_bw_mapping(struct ieee80211_hw *hw,
+			       struct rtl_tcb_desc *ptcb_desc)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	u8 bw_setting_of_desc = 0;
+
+	RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+		 "rtl8821ae_bw_mapping, current_chan_bw %d, packet_bw %d\n",
+		 rtlphy->current_chan_bw, ptcb_desc->packet_bw);
+
+	if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) {
+		if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_80)
+			bw_setting_of_desc = 2;
+		else if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40)
+			bw_setting_of_desc = 1;
+		else
+			bw_setting_of_desc = 0;
+	} else if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+		if ((ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40) ||
+		    (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_80))
+			bw_setting_of_desc = 1;
+		else
+			bw_setting_of_desc = 0;
+	} else {
+		bw_setting_of_desc = 0;
+	}
+	return bw_setting_of_desc;
+}
+
+static u8 rtl8821ae_sc_mapping(struct ieee80211_hw *hw,
+			       struct rtl_tcb_desc *ptcb_desc)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_phy *rtlphy = &rtlpriv->phy;
+	struct rtl_mac *mac = rtl_mac(rtlpriv);
+	u8 sc_setting_of_desc = 0;
+
+	if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) {
+		if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_80) {
+			sc_setting_of_desc = VHT_DATA_SC_DONOT_CARE;
+		} else if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40) {
+			if (mac->cur_80_prime_sc ==
+			    HAL_PRIME_CHNL_OFFSET_LOWER)
+				sc_setting_of_desc =
+					VHT_DATA_SC_40_LOWER_OF_80MHZ;
+			else if (mac->cur_80_prime_sc ==
+				 HAL_PRIME_CHNL_OFFSET_UPPER)
+				sc_setting_of_desc =
+					VHT_DATA_SC_40_UPPER_OF_80MHZ;
+			else
+				RT_TRACE(rtlpriv, COMP_SEND, DBG_LOUD,
+					 "rtl8821ae_sc_mapping: Not Correct Primary40MHz Setting\n");
+		} else {
+			if ((mac->cur_40_prime_sc ==
+			     HAL_PRIME_CHNL_OFFSET_LOWER) &&
+			    (mac->cur_80_prime_sc  ==
+			     HAL_PRIME_CHNL_OFFSET_LOWER))
+				sc_setting_of_desc =
+					VHT_DATA_SC_20_LOWEST_OF_80MHZ;
+			else if ((mac->cur_40_prime_sc ==
+				  HAL_PRIME_CHNL_OFFSET_UPPER) &&
+				 (mac->cur_80_prime_sc ==
+				  HAL_PRIME_CHNL_OFFSET_LOWER))
+				sc_setting_of_desc =
+					VHT_DATA_SC_20_LOWER_OF_80MHZ;
+			else if ((mac->cur_40_prime_sc ==
+				  HAL_PRIME_CHNL_OFFSET_LOWER) &&
+				 (mac->cur_80_prime_sc ==
+				  HAL_PRIME_CHNL_OFFSET_UPPER))
+				sc_setting_of_desc =
+					VHT_DATA_SC_20_UPPER_OF_80MHZ;
+			else if ((mac->cur_40_prime_sc ==
+				  HAL_PRIME_CHNL_OFFSET_UPPER) &&
+				 (mac->cur_80_prime_sc ==
+				  HAL_PRIME_CHNL_OFFSET_UPPER))
+				sc_setting_of_desc =
+					VHT_DATA_SC_20_UPPERST_OF_80MHZ;
+			else
+				RT_TRACE(rtlpriv, COMP_SEND, DBG_LOUD,
+					 "rtl8821ae_sc_mapping: Not Correct Primary40MHz Setting\n");
+		}
+	} else if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+		if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20_40) {
+			sc_setting_of_desc = VHT_DATA_SC_DONOT_CARE;
+		} else if (ptcb_desc->packet_bw == HT_CHANNEL_WIDTH_20) {
+			if (mac->cur_40_prime_sc ==
+				HAL_PRIME_CHNL_OFFSET_UPPER) {
+				sc_setting_of_desc =
+					VHT_DATA_SC_20_UPPER_OF_80MHZ;
+			} else if (mac->cur_40_prime_sc ==
+				HAL_PRIME_CHNL_OFFSET_LOWER){
+				sc_setting_of_desc =
+					VHT_DATA_SC_20_LOWER_OF_80MHZ;
+			} else {
+				sc_setting_of_desc = VHT_DATA_SC_DONOT_CARE;
+			}
+		}
+	} else {
+		sc_setting_of_desc = VHT_DATA_SC_DONOT_CARE;
+	}
+
+	return sc_setting_of_desc;
+}
+
+void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw,
+			    struct ieee80211_hdr *hdr, u8 *pdesc_tx, u8 *txbd,
+			    struct ieee80211_tx_info *info,
+			    struct ieee80211_sta *sta,
+			    struct sk_buff *skb,
+			    u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+	u8 *pdesc = (u8 *)pdesc_tx;
+	u16 seq_number;
+	__le16 fc = hdr->frame_control;
+	unsigned int buf_len = 0;
+	unsigned int skb_len = skb->len;
+	u8 fw_qsel = _rtl8821ae_map_hwqueue_to_fwqueue(skb, hw_queue);
+	bool firstseg = ((hdr->seq_ctrl &
+			  cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
+	bool lastseg = ((hdr->frame_control &
+			 cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
+	dma_addr_t mapping;
+	u8 short_gi = 0;
+
+	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+	rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
+	/* reserve 8 byte for AMPDU early mode */
+	if (rtlhal->earlymode_enable) {
+		skb_push(skb, EM_HDR_LEN);
+		memset(skb->data, 0, EM_HDR_LEN);
+	}
+	buf_len = skb->len;
+	mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
+				 PCI_DMA_TODEVICE);
+	if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+		RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+			 "DMA mapping error");
+		return;
+	}
+	CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_8821ae));
+	if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
+		firstseg = true;
+		lastseg = true;
+	}
+	if (firstseg) {
+		if (rtlhal->earlymode_enable) {
+			SET_TX_DESC_PKT_OFFSET(pdesc, 1);
+			SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN +
+					   EM_HDR_LEN);
+			if (ptcb_desc->empkt_num) {
+				RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+					 "Insert 8 byte.pTcb->EMPktNum:%d\n",
+					  ptcb_desc->empkt_num);
+				_rtl8821ae_insert_emcontent(ptcb_desc,
+					 (u8 *)(skb->data));
+			}
+		} else {
+			SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+		}
+
+		/* ptcb_desc->use_driver_rate = true; */
+		SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
+		if (ptcb_desc->hw_rate > DESC_RATEMCS0)
+			short_gi = (ptcb_desc->use_shortgi) ? 1 : 0;
+		else
+			short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0;
+
+		SET_TX_DESC_DATA_SHORTGI(pdesc, short_gi);
+
+		if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+			SET_TX_DESC_AGG_ENABLE(pdesc, 1);
+			SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x1f);
+		}
+		SET_TX_DESC_SEQ(pdesc, seq_number);
+		SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable &&
+					!ptcb_desc->cts_enable) ? 1 : 0));
+		SET_TX_DESC_HW_RTS_ENABLE(pdesc, 0);
+		SET_TX_DESC_CTS2SELF(pdesc, ((ptcb_desc->cts_enable) ? 1 : 0));
+
+		SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
+		SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc);
+		SET_TX_DESC_RTS_SHORT(pdesc,
+			((ptcb_desc->rts_rate <= DESC_RATE54M) ?
+			(ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
+			(ptcb_desc->rts_use_shortgi ? 1 : 0)));
+
+		if (ptcb_desc->tx_enable_sw_calc_duration)
+			SET_TX_DESC_NAV_USE_HDR(pdesc, 1);
+
+		SET_TX_DESC_DATA_BW(pdesc,
+			rtl8821ae_bw_mapping(hw, ptcb_desc));
+
+		SET_TX_DESC_TX_SUB_CARRIER(pdesc,
+			rtl8821ae_sc_mapping(hw, ptcb_desc));
+
+		SET_TX_DESC_LINIP(pdesc, 0);
+		SET_TX_DESC_PKT_SIZE(pdesc, (u16)skb_len);
+		if (sta) {
+			u8 ampdu_density = sta->ht_cap.ampdu_density;
+
+			SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density);
+		}
+		if (info->control.hw_key) {
+			struct ieee80211_key_conf *keyconf =
+				info->control.hw_key;
+			switch (keyconf->cipher) {
+			case WLAN_CIPHER_SUITE_WEP40:
+			case WLAN_CIPHER_SUITE_WEP104:
+			case WLAN_CIPHER_SUITE_TKIP:
+				SET_TX_DESC_SEC_TYPE(pdesc, 0x1);
+				break;
+			case WLAN_CIPHER_SUITE_CCMP:
+				SET_TX_DESC_SEC_TYPE(pdesc, 0x3);
+				break;
+			default:
+				SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
+				break;
+			}
+		}
+
+		SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel);
+		SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
+		SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
+		SET_TX_DESC_DISABLE_FB(pdesc, ptcb_desc->disable_ratefallback ?
+				       1 : 0);
+		SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0);
+
+		if (ieee80211_is_data_qos(fc)) {
+			if (mac->rdg_en) {
+				RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+					 "Enable RDG function.\n");
+				SET_TX_DESC_RDG_ENABLE(pdesc, 1);
+				SET_TX_DESC_HTC(pdesc, 1);
+			}
+		}
+	}
+
+	SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
+	SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
+	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)buf_len);
+	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+	/* if (rtlpriv->dm.useramask) { */
+	if (1) {
+		SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index);
+		SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+	} else {
+		SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcb_desc->ratr_index);
+		SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+	}
+	if (!ieee80211_is_data_qos(fc))  {
+		SET_TX_DESC_HWSEQ_EN(pdesc, 1);
+		SET_TX_DESC_HWSEQ_SEL(pdesc, 0);
+	}
+	SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1));
+	if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+	    is_broadcast_ether_addr(ieee80211_get_DA(hdr))) {
+		SET_TX_DESC_BMC(pdesc, 1);
+	}
+
+	rtl8821ae_dm_set_tx_ant_by_tx_info(hw, pdesc, ptcb_desc->mac_id);
+	RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n");
+}
+
+void rtl8821ae_tx_fill_cmddesc(struct ieee80211_hw *hw,
+			       u8 *pdesc, bool firstseg,
+			       bool lastseg, struct sk_buff *skb)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	u8 fw_queue = QSLT_BEACON;
+
+	dma_addr_t mapping = pci_map_single(rtlpci->pdev,
+					    skb->data, skb->len,
+					    PCI_DMA_TODEVICE);
+
+	if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+		RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+			 "DMA mapping error");
+		return;
+	}
+	CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
+
+	SET_TX_DESC_FIRST_SEG(pdesc, 1);
+	SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+	SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len));
+
+	SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+
+	SET_TX_DESC_USE_RATE(pdesc, 1);
+	SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M);
+	SET_TX_DESC_DISABLE_FB(pdesc, 1);
+
+	SET_TX_DESC_DATA_BW(pdesc, 0);
+
+	SET_TX_DESC_HWSEQ_EN(pdesc, 1);
+
+	SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
+
+	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
+
+	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+
+	SET_TX_DESC_MACID(pdesc, 0);
+
+	SET_TX_DESC_OWN(pdesc, 1);
+
+	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+		      "H2C Tx Cmd Content\n",
+		      pdesc, TX_DESC_SIZE);
+}
+
+void rtl8821ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc,
+			bool istx, u8 desc_name, u8 *val)
+{
+	if (istx) {
+		switch (desc_name) {
+		case HW_DESC_OWN:
+			SET_TX_DESC_OWN(pdesc, 1);
+			break;
+		case HW_DESC_TX_NEXTDESC_ADDR:
+			SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *)val);
+			break;
+		default:
+			RT_ASSERT(false,
+				  "ERR txdesc :%d not process\n", desc_name);
+			break;
+		}
+	} else {
+		switch (desc_name) {
+		case HW_DESC_RXOWN:
+			SET_RX_DESC_OWN(pdesc, 1);
+			break;
+		case HW_DESC_RXBUFF_ADDR:
+			SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *)val);
+			break;
+		case HW_DESC_RXPKT_LEN:
+			SET_RX_DESC_PKT_LEN(pdesc, *(u32 *)val);
+			break;
+		case HW_DESC_RXERO:
+			SET_RX_DESC_EOR(pdesc, 1);
+			break;
+		default:
+			RT_ASSERT(false,
+				  "ERR rxdesc :%d not process\n", desc_name);
+			break;
+		}
+	}
+}
+
+u32 rtl8821ae_get_desc(u8 *pdesc, bool istx, u8 desc_name)
+{
+	u32 ret = 0;
+
+	if (istx) {
+		switch (desc_name) {
+		case HW_DESC_OWN:
+			ret = GET_TX_DESC_OWN(pdesc);
+			break;
+		case HW_DESC_TXBUFF_ADDR:
+			ret = GET_TX_DESC_TX_BUFFER_ADDRESS(pdesc);
+			break;
+		default:
+			RT_ASSERT(false,
+				  "ERR txdesc :%d not process\n", desc_name);
+			break;
+		}
+	} else {
+		switch (desc_name) {
+		case HW_DESC_OWN:
+			ret = GET_RX_DESC_OWN(pdesc);
+			break;
+		case HW_DESC_RXPKT_LEN:
+			ret = GET_RX_DESC_PKT_LEN(pdesc);
+			break;
+		case HW_DESC_RXBUFF_ADDR:
+			ret = GET_RX_DESC_BUFF_ADDR(pdesc);
+			break;
+		default:
+			RT_ASSERT(false,
+				  "ERR rxdesc :%d not process\n", desc_name);
+			break;
+		}
+	}
+	return ret;
+}
+
+bool rtl8821ae_is_tx_desc_closed(struct ieee80211_hw *hw,
+				 u8 hw_queue, u16 index)
+{
+	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+	u8 *entry = (u8 *)(&ring->desc[ring->idx]);
+	u8 own = (u8)rtl8821ae_get_desc(entry, true, HW_DESC_OWN);
+
+	/**
+	 *beacon packet will only use the first
+	 *descriptor defautly,and the own may not
+	 *be cleared by the hardware
+	 */
+	if (own)
+		return false;
+	return true;
+}
+
+void rtl8821ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
+{
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	if (hw_queue == BEACON_QUEUE) {
+		rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4));
+	} else {
+		rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG,
+			       BIT(0) << (hw_queue));
+	}
+}
+
+u32 rtl8821ae_rx_command_packet(struct ieee80211_hw *hw,
+				struct rtl_stats status,
+				struct sk_buff *skb)
+{
+	u32 result = 0;
+	struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+	switch (status.packet_report_type) {
+	case NORMAL_RX:
+		result = 0;
+		break;
+	case C2H_PACKET:
+		rtl8821ae_c2h_packet_handler(hw, skb->data, (u8)skb->len);
+		result = 1;
+		RT_TRACE(rtlpriv, COMP_RECV, DBG_LOUD,
+			 "skb->len=%d\n\n", skb->len);
+		break;
+	default:
+		RT_TRACE(rtlpriv, COMP_RECV, DBG_LOUD,
+			 "No this packet type!!\n");
+		break;
+	}
+
+	return result;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/trx.h b/drivers/net/wireless/rtlwifi/rtl8821ae/trx.h
new file mode 100644
index 0000000..3140904
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/trx.h
@@ -0,0 +1,620 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010  Realtek Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8821AE_TRX_H__
+#define __RTL8821AE_TRX_H__
+
+#define TX_DESC_SIZE					40
+#define TX_DESC_AGGR_SUBFRAME_SIZE		32
+
+#define RX_DESC_SIZE					32
+#define RX_DRV_INFO_SIZE_UNIT			8
+
+#define	TX_DESC_NEXT_DESC_OFFSET		40
+#define USB_HWDESC_HEADER_LEN			40
+#define CRCLENGTH						4
+
+#define SET_TX_DESC_PKT_SIZE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val)
+#define SET_TX_DESC_OFFSET(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val)
+#define SET_TX_DESC_BMC(__pdesc, __val)				\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val)
+#define SET_TX_DESC_HTC(__pdesc, __val)				\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val)
+#define SET_TX_DESC_LAST_SEG(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val)
+#define SET_TX_DESC_FIRST_SEG(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val)
+#define SET_TX_DESC_LINIP(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val)
+#define SET_TX_DESC_NO_ACM(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val)
+#define SET_TX_DESC_GF(__pdesc, __val)				\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_TX_DESC_OWN(__pdesc, __val)				\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_TX_DESC_PKT_SIZE(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 0, 16)
+#define GET_TX_DESC_OFFSET(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc, 16, 8)
+#define GET_TX_DESC_BMC(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc, 24, 1)
+#define GET_TX_DESC_HTC(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc, 25, 1)
+#define GET_TX_DESC_LAST_SEG(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_TX_DESC_FIRST_SEG(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_TX_DESC_LINIP(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_TX_DESC_NO_ACM(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_TX_DESC_GF(__pdesc)						\
+	LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_TX_DESC_OWN(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_TX_DESC_MACID(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 7, __val)
+#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val)
+#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val)
+#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val)
+#define SET_TX_DESC_PIFS(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val)
+#define SET_TX_DESC_RATE_ID(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 5, __val)
+#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val)
+#define SET_TX_DESC_SEC_TYPE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val)
+#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 5, __val)
+
+#define SET_TX_DESC_PAID(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 9, __val)
+#define SET_TX_DESC_CCA_RTS(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 10, 2, __val)
+#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 12, 1, __val)
+#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 13, 1, __val)
+#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val)
+#define SET_TX_DESC_AGG_BREAK(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val)
+#define SET_TX_DESC_MORE_FRAG(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val)
+#define SET_TX_DESC_RAW(__pdesc, __val)				\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val)
+#define SET_TX_DESC_SPE_RPT(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val)
+#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val)
+#define SET_TX_DESC_BT_INT(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 23, 1, __val)
+#define SET_TX_DESC_GID(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 6, __val)
+
+#define SET_TX_DESC_WHEADER_LEN(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 4, __val)
+#define SET_TX_DESC_CHK_EN(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 4, 1, __val)
+#define SET_TX_DESC_EARLY_MODE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 5, 1, __val)
+#define SET_TX_DESC_HWSEQ_SEL(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 6, 2, __val)
+#define SET_TX_DESC_USE_RATE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 1, __val)
+#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 9, 1, __val)
+#define SET_TX_DESC_DISABLE_FB(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 10, 1, __val)
+#define SET_TX_DESC_CTS2SELF(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 11, 1, __val)
+#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 12, 1, __val)
+#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 13, 1, __val)
+#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 15, 1, __val)
+#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 1, __val)
+#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 17, 5, __val)
+#define SET_TX_DESC_NDPA(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 22, 2, __val)
+#define SET_TX_DESC_AMPDU_MAX_TIME(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+12, 24, 8, __val)
+#define SET_TX_DESC_TX_ANT(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 24, 4, __val)
+
+#define SET_TX_DESC_TX_RATE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 7, __val)
+#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 5, __val)
+#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 4, __val)
+#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 17, 1, __val)
+#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 6, __val)
+#define SET_TX_DESC_RTS_RATE(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 5, __val)
+
+#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 4, __val)
+#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val)	\
+	SET_BITS_TO_LE_1BYTE(__pdesc+20, 4, 1, __val)
+#define SET_TX_DESC_DATA_BW(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 5, 2, __val)
+#define SET_TX_DESC_DATA_LDPC(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val)
+#define SET_TX_DESC_DATA_STBC(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 2, __val)
+#define SET_TX_DESC_CTROL_STBC(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 10, 2, __val)
+#define SET_TX_DESC_RTS_SHORT(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 12, 1, __val)
+#define SET_TX_DESC_RTS_SC(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val)
+
+#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val)
+
+#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+28, 0, 16)
+
+#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+32, 15, 1, __val)
+
+#define SET_TX_DESC_SEQ(__pdesc, __val)		\
+	SET_BITS_TO_LE_4BYTE(__pdesc+36, 12, 12, __val)
+
+#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val)
+
+#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+40, 0, 32)
+
+#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+48, 0, 32, __val)
+
+#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+48, 0, 32)
+
+#define GET_RX_DESC_PKT_LEN(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 0, 14)
+#define GET_RX_DESC_CRC32(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 14, 1)
+#define GET_RX_DESC_ICV(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 15, 1)
+#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc, 16, 4)
+#define GET_RX_DESC_SECURITY(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc, 20, 3)
+#define GET_RX_DESC_QOS(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 23, 1)
+#define GET_RX_DESC_SHIFT(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 24, 2)
+#define GET_RX_DESC_PHYST(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_RX_DESC_SWDEC(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_RX_DESC_LS(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_RX_DESC_FS(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_RX_DESC_EOR(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_RX_DESC_OWN(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_RX_DESC_PKT_LEN(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val)
+#define SET_RX_DESC_EOR(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_RX_DESC_OWN(__pdesc, __val)			\
+	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_RX_DESC_MACID(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+4, 0, 7)
+#define GET_RX_DESC_TID(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+4, 8, 4)
+#define GET_RX_DESC_AMSDU(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+4, 13, 1)
+#define GET_RX_STATUS_DESC_RXID_MATCH(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_RX_DESC_PAGGR(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_RX_DESC_A1_FIT(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_RX_DESC_CHKERR(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 20, 1)
+#define GET_RX_DESC_IPVER(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+4, 21, 1)
+#define GET_RX_STATUS_DESC_IS_TCPUDP(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 22, 1)
+#define GET_RX_STATUS_DESC_CHK_VLD(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+4, 23, 1)
+#define GET_RX_DESC_PAM(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+4, 24, 1)
+#define GET_RX_DESC_PWR(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+4, 25, 1)
+#define GET_RX_DESC_MD(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc+4, 26, 1)
+#define GET_RX_DESC_MF(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc+4, 27, 1)
+#define GET_RX_DESC_TYPE(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+4, 28, 2)
+#define GET_RX_DESC_MC(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc+4, 30, 1)
+#define GET_RX_DESC_BC(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc+4, 31, 1)
+
+#define GET_RX_DESC_SEQ(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+8, 0, 12)
+#define GET_RX_DESC_FRAG(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+8, 12, 4)
+#define GET_RX_STATUS_DESC_RX_IS_QOS(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+8, 16, 1)
+#define GET_RX_STATUS_DESC_WLANHD_IV_LEN(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+8, 18, 6)
+#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+8, 28, 1)
+
+#define GET_RX_DESC_RXMCS(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+12, 0, 7)
+#define GET_RX_DESC_HTC(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+12, 10, 1)
+#define GET_RX_STATUS_DESC_EOSP(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+12, 11, 1)
+#define GET_RX_STATUS_DESC_BSSID_FIT(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+12, 12, 2)
+
+#define GET_RX_STATUS_DESC_PATTERN_MATCH(__pdesc)	\
+	LE_BITS_TO_4BYTE(__pdesc+12, 29, 1)
+#define GET_RX_STATUS_DESC_UNICAST_MATCH(__pdesc)	\
+	LE_BITS_TO_4BYTE(__pdesc+12, 30, 1)
+#define GET_RX_STATUS_DESC_MAGIC_MATCH(__pdesc)	\
+	LE_BITS_TO_4BYTE(__pdesc+12, 31, 1)
+
+#define GET_RX_DESC_SPLCP(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+16, 0, 1)
+#define GET_RX_STATUS_DESC_LDPC(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+16, 1, 1)
+#define GET_RX_STATUS_DESC_STBC(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+16, 2, 1)
+#define GET_RX_DESC_BW(__pdesc)					\
+	LE_BITS_TO_4BYTE(__pdesc+16, 4, 2)
+
+#define GET_RX_DESC_TSFL(__pdesc)				\
+	LE_BITS_TO_4BYTE(__pdesc+20, 0, 32)
+
+#define GET_RX_DESC_BUFF_ADDR(__pdesc)			\
+	LE_BITS_TO_4BYTE(__pdesc+24, 0, 32)
+#define GET_RX_DESC_BUFF_ADDR64(__pdesc)		\
+	LE_BITS_TO_4BYTE(__pdesc+28, 0, 32)
+
+#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val)	\
+	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val)
+#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) \
+	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val)
+
+/* TX report 2 format in Rx desc*/
+
+#define GET_RX_RPT2_DESC_PKT_LEN(__status)	\
+	LE_BITS_TO_4BYTE(__status, 0, 9)
+#define GET_RX_RPT2_DESC_MACID_VALID_1(__status)	\
+	LE_BITS_TO_4BYTE(__status+16, 0, 32)
+#define GET_RX_RPT2_DESC_MACID_VALID_2(__status)	\
+	LE_BITS_TO_4BYTE(__status+20, 0, 32)
+
+#define SET_EARLYMODE_PKTNUM(__paddr, __value)	\
+	SET_BITS_TO_LE_4BYTE(__paddr, 0, 4, __value)
+#define SET_EARLYMODE_LEN0(__paddr, __value)	\
+	SET_BITS_TO_LE_4BYTE(__paddr, 4, 12, __value)
+#define SET_EARLYMODE_LEN1(__paddr, __value)	\
+	SET_BITS_TO_LE_4BYTE(__paddr, 16, 12, __value)
+#define SET_EARLYMODE_LEN2_1(__paddr, __value)	\
+	SET_BITS_TO_LE_4BYTE(__paddr, 28, 4, __value)
+#define SET_EARLYMODE_LEN2_2(__paddr, __value)	\
+	SET_BITS_TO_LE_4BYTE(__paddr+4, 0, 8, __value)
+#define SET_EARLYMODE_LEN3(__paddr, __value)	\
+	SET_BITS_TO_LE_4BYTE(__paddr+4, 8, 12, __value)
+#define SET_EARLYMODE_LEN4(__paddr, __value)	\
+	SET_BITS_TO_LE_4BYTE(__paddr+4, 20, 12, __value)
+
+#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size)		\
+do {								\
+	if (_size > TX_DESC_NEXT_DESC_OFFSET)			\
+		memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET);	\
+	else							\
+		memset(__pdesc, 0, _size);			\
+} while (0)
+
+#define RTL8821AE_RX_HAL_IS_CCK_RATE(rxmcs)\
+	(rxmcs == DESC_RATE1M ||\
+	 rxmcs == DESC_RATE2M ||\
+	 rxmcs == DESC_RATE5_5M ||\
+	 rxmcs == DESC_RATE11M)
+
+struct phy_rx_agc_info_t {
+	#ifdef __LITTLE_ENDIAN
+		u8	gain:7, trsw:1;
+	#else
+		u8	trsw:1, gain:7;
+	#endif
+};
+
+struct phy_status_rpt {
+	/* DWORD 0 */
+	u8 gain_trsw[2];
+#ifdef __LITTLE_ENDIAN
+	u16 chl_num:10;
+	u16 sub_chnl:4;
+	u16 r_rfmod:2;
+#else	/* _BIG_ENDIAN_ */
+	u16 r_rfmod:2;
+	u16 sub_chnl:4;
+	u16 chl_num:10;
+#endif
+	/* DWORD 1 */
+	u8 pwdb_all;
+	u8 cfosho[4];	/* DW 1 byte 1 DW 2 byte 0 */
+
+	/* DWORD 2 */
+	char cfotail[4];	/* DW 2 byte 1 DW 3 byte 0 */
+
+	/* DWORD 3 */
+	char rxevm[2];	/* DW 3 byte 1 DW 3 byte 2 */
+	char rxsnr[2];	/* DW 3 byte 3 DW 4 byte 0 */
+
+	/* DWORD 4 */
+	u8 pcts_msk_rpt[2];
+	u8 pdsnr[2];	/* DW 4 byte 3 DW 5 Byte 0 */
+
+	/* DWORD 5 */
+	u8 csi_current[2];
+	u8 rx_gain_c;
+
+	/* DWORD 6 */
+	u8 rx_gain_d;
+	u8 sigevm;
+	u8 resvd_0;
+	u8 antidx_anta:3;
+	u8 antidx_antb:3;
+	u8 resvd_1:2;
+} __packed;
+
+struct rx_fwinfo_8821ae {
+	u8 gain_trsw[4];
+	u8 pwdb_all;
+	u8 cfosho[4];
+	u8 cfotail[4];
+	char rxevm[2];
+	char rxsnr[4];
+	u8 pdsnr[2];
+	u8 csi_current[2];
+	u8 csi_target[2];
+	u8 sigevm;
+	u8 max_ex_pwr;
+	u8 ex_intf_flag:1;
+	u8 sgi_en:1;
+	u8 rxsc:2;
+	u8 reserve:4;
+} __packed;
+
+struct tx_desc_8821ae {
+	u32 pktsize:16;
+	u32 offset:8;
+	u32 bmc:1;
+	u32 htc:1;
+	u32 lastseg:1;
+	u32 firstseg:1;
+	u32 linip:1;
+	u32 noacm:1;
+	u32 gf:1;
+	u32 own:1;
+
+	u32 macid:6;
+	u32 rsvd0:2;
+	u32 queuesel:5;
+	u32 rd_nav_ext:1;
+	u32 lsig_txop_en:1;
+	u32 pifs:1;
+	u32 rateid:4;
+	u32 nav_usehdr:1;
+	u32 en_descid:1;
+	u32 sectype:2;
+	u32 pktoffset:8;
+
+	u32 rts_rc:6;
+	u32 data_rc:6;
+	u32 agg_en:1;
+	u32 rdg_en:1;
+	u32 bar_retryht:2;
+	u32 agg_break:1;
+	u32 morefrag:1;
+	u32 raw:1;
+	u32 ccx:1;
+	u32 ampdudensity:3;
+	u32 bt_int:1;
+	u32 ant_sela:1;
+	u32 ant_selb:1;
+	u32 txant_cck:2;
+	u32 txant_l:2;
+	u32 txant_ht:2;
+
+	u32 nextheadpage:8;
+	u32 tailpage:8;
+	u32 seq:12;
+	u32 cpu_handle:1;
+	u32 tag1:1;
+	u32 trigger_int:1;
+	u32 hwseq_en:1;
+
+	u32 rtsrate:5;
+	u32 apdcfe:1;
+	u32 qos:1;
+	u32 hwseq_ssn:1;
+	u32 userrate:1;
+	u32 dis_rtsfb:1;
+	u32 dis_datafb:1;
+	u32 cts2self:1;
+	u32 rts_en:1;
+	u32 hwrts_en:1;
+	u32 portid:1;
+	u32 pwr_status:3;
+	u32 waitdcts:1;
+	u32 cts2ap_en:1;
+	u32 txsc:2;
+	u32 stbc:2;
+	u32 txshort:1;
+	u32 txbw:1;
+	u32 rtsshort:1;
+	u32 rtsbw:1;
+	u32 rtssc:2;
+	u32 rtsstbc:2;
+
+	u32 txrate:6;
+	u32 shortgi:1;
+	u32 ccxt:1;
+	u32 txrate_fb_lmt:5;
+	u32 rtsrate_fb_lmt:4;
+	u32 retrylmt_en:1;
+	u32 txretrylmt:6;
+	u32 usb_txaggnum:8;
+
+	u32 txagca:5;
+	u32 txagcb:5;
+	u32 usemaxlen:1;
+	u32 maxaggnum:5;
+	u32 mcsg1maxlen:4;
+	u32 mcsg2maxlen:4;
+	u32 mcsg3maxlen:4;
+	u32 mcs7sgimaxlen:4;
+
+	u32 txbuffersize:16;
+	u32 sw_offset30:8;
+	u32 sw_offset31:4;
+	u32 rsvd1:1;
+	u32 antsel_c:1;
+	u32 null_0:1;
+	u32 null_1:1;
+
+	u32 txbuffaddr;
+	u32 txbufferaddr64;
+	u32 nextdescaddress;
+	u32 nextdescaddress64;
+
+	u32 reserve_pass_pcie_mm_limit[4];
+} __packed;
+
+struct rx_desc_8821ae {
+	u32 length:14;
+	u32 crc32:1;
+	u32 icverror:1;
+	u32 drv_infosize:4;
+	u32 security:3;
+	u32 qos:1;
+	u32 shift:2;
+	u32 phystatus:1;
+	u32 swdec:1;
+	u32 lastseg:1;
+	u32 firstseg:1;
+	u32 eor:1;
+	u32 own:1;
+
+	u32 macid:6;
+	u32 tid:4;
+	u32 hwrsvd:5;
+	u32 paggr:1;
+	u32 faggr:1;
+	u32 a1_fit:4;
+	u32 a2_fit:4;
+	u32 pam:1;
+	u32 pwr:1;
+	u32 moredata:1;
+	u32 morefrag:1;
+	u32 type:2;
+	u32 mc:1;
+	u32 bc:1;
+
+	u32 seq:12;
+	u32 frag:4;
+	u32 nextpktlen:14;
+	u32 nextind:1;
+	u32 rsvd:1;
+
+	u32 rxmcs:6;
+	u32 rxht:1;
+	u32 amsdu:1;
+	u32 splcp:1;
+	u32 bandwidth:1;
+	u32 htc:1;
+	u32 tcpchk_rpt:1;
+	u32 ipcchk_rpt:1;
+	u32 tcpchk_valid:1;
+	u32 hwpcerr:1;
+	u32 hwpcind:1;
+	u32 iv0:16;
+
+	u32 iv1;
+
+	u32 tsfl;
+
+	u32 bufferaddress;
+	u32 bufferaddress64;
+
+} __packed;
+
+void rtl8821ae_tx_fill_desc(struct ieee80211_hw *hw,
+			    struct ieee80211_hdr *hdr, u8 *pdesc_tx, u8 *txbd,
+			    struct ieee80211_tx_info *info,
+			    struct ieee80211_sta *sta,
+			    struct sk_buff *skb,
+			    u8 hw_queue, struct rtl_tcb_desc *ptcb_desc);
+bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw,
+			     struct rtl_stats *status,
+			     struct ieee80211_rx_status *rx_status,
+			     u8 *pdesc, struct sk_buff *skb);
+void rtl8821ae_set_desc(struct ieee80211_hw *hw, u8 *pdesc,
+			bool istx, u8 desc_name, u8 *val);
+u32 rtl8821ae_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+bool rtl8821ae_is_tx_desc_closed(struct ieee80211_hw *hw,
+				 u8 hw_queue, u16 index);
+void rtl8821ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
+void rtl8821ae_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+			       bool firstseg, bool lastseg,
+			       struct sk_buff *skb);
+u32 rtl8821ae_rx_command_packet(struct ieee80211_hw *hw,
+				struct rtl_stats status,
+				struct sk_buff *skb);
+#endif
diff --git a/drivers/net/wireless/rtlwifi/stats.c b/drivers/net/wireless/rtlwifi/stats.c
index 4f083fc..2d0736a 100644
--- a/drivers/net/wireless/rtlwifi/stats.c
+++ b/drivers/net/wireless/rtlwifi/stats.c
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -59,8 +55,23 @@
 }
 EXPORT_SYMBOL(rtl_evm_db_to_percentage);
 
+u8 rtl_evm_dbm_jaguar(char value)
+{
+	char ret_val = value;
+
+	/* -33dB~0dB to 33dB ~ 0dB*/
+	if (ret_val == -128)
+		ret_val = 127;
+	else if (ret_val < 0)
+		ret_val = 0 - ret_val;
+
+	ret_val  = ret_val >> 1;
+	return ret_val;
+}
+EXPORT_SYMBOL(rtl_evm_dbm_jaguar);
+
 static long rtl_translate_todbm(struct ieee80211_hw *hw,
-				u8 signal_strength_index)
+			 u8 signal_strength_index)
 {
 	long signal_power;
 
@@ -106,6 +117,10 @@
 	u8 rfpath;
 	u32 last_rssi, tmpval;
 
+	if (!pstatus->packet_toself && !pstatus->packet_beacon)
+		return;
+
+	rtlpriv->stats.pwdb_all_cnt += pstatus->rx_pwdb_all;
 	rtlpriv->stats.rssi_calculate_cnt++;
 
 	if (rtlpriv->stats.ui_rssi.total_num++ >= PHY_RSSI_SLID_WIN_MAX) {
@@ -151,6 +166,12 @@
 			     (pstatus->rx_mimo_signalstrength[rfpath])) /
 			    (RX_SMOOTH_FACTOR);
 		}
+		rtlpriv->stats.rx_snr_db[rfpath] = pstatus->rx_snr[rfpath];
+		rtlpriv->stats.rx_evm_dbm[rfpath] =
+					pstatus->rx_mimo_evm_dbm[rfpath];
+		rtlpriv->stats.rx_cfo_short[rfpath] =
+					pstatus->cfo_short[rfpath];
+		rtlpriv->stats.rx_cfo_tail[rfpath] = pstatus->cfo_tail[rfpath];
 	}
 }
 
@@ -176,7 +197,6 @@
 	struct rtl_sta_info *drv_priv = NULL;
 	struct ieee80211_sta *sta = NULL;
 	long undec_sm_pwdb;
-	long undec_sm_cck;
 
 	rcu_read_lock();
 	if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION)
@@ -186,33 +206,21 @@
 	if (sta) {
 		drv_priv = (struct rtl_sta_info *) sta->drv_priv;
 		undec_sm_pwdb = drv_priv->rssi_stat.undec_sm_pwdb;
-		undec_sm_cck = drv_priv->rssi_stat.undec_sm_cck;
 	} else {
 		undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
-		undec_sm_cck = rtlpriv->dm.undec_sm_cck;
 	}
 
 	if (undec_sm_pwdb < 0)
 		undec_sm_pwdb = pstatus->rx_pwdb_all;
-	if (undec_sm_cck < 0)
-		undec_sm_cck = pstatus->rx_pwdb_all;
 	if (pstatus->rx_pwdb_all > (u32) undec_sm_pwdb) {
 		undec_sm_pwdb = (((undec_sm_pwdb) *
 		      (RX_SMOOTH_FACTOR - 1)) +
 		     (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
 		undec_sm_pwdb = undec_sm_pwdb + 1;
 	} else {
-		undec_sm_pwdb = (((undec_sm_pwdb) * (RX_SMOOTH_FACTOR - 1)) +
-		     (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
-	}
-	if (pstatus->rx_pwdb_all > (u32) undec_sm_cck) {
-		undec_sm_cck = (((undec_sm_pwdb) *
+		undec_sm_pwdb = (((undec_sm_pwdb) *
 		      (RX_SMOOTH_FACTOR - 1)) +
 		     (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
-		undec_sm_cck = undec_sm_cck + 1;
-	} else {
-		undec_sm_pwdb = (((undec_sm_cck) * (RX_SMOOTH_FACTOR - 1)) +
-		     (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
 	}
 
 	if (sta) {
@@ -245,7 +253,7 @@
 	rtlpriv->stats.ui_link_quality.total_val += pstatus->signalquality;
 	rtlpriv->stats.ui_link_quality.elements[
 		rtlpriv->stats.ui_link_quality.index++] =
-						 pstatus->signalquality;
+							pstatus->signalquality;
 	if (rtlpriv->stats.ui_link_quality.index >=
 	    PHY_LINKQUALITY_SLID_WIN_MAX)
 		rtlpriv->stats.ui_link_quality.index = 0;
@@ -269,7 +277,7 @@
 }
 
 void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer,
-	struct rtl_stats *pstatus)
+			 struct rtl_stats *pstatus)
 {
 
 	if (!pstatus->packet_matchbssid)
diff --git a/drivers/net/wireless/rtlwifi/stats.h b/drivers/net/wireless/rtlwifi/stats.h
index 0dbdc52..aa4eec8 100644
--- a/drivers/net/wireless/rtlwifi/stats.h
+++ b/drivers/net/wireless/rtlwifi/stats.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -39,8 +35,9 @@
 
 u8 rtl_query_rxpwrpercentage(char antpower);
 u8 rtl_evm_db_to_percentage(char value);
+u8 rtl_evm_dbm_jaguar(char value);
 long rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig);
 void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer,
-	struct rtl_stats *pstatus);
+			 struct rtl_stats *pstatus);
 
 #endif
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index 0398d3e..10cf69c 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -75,11 +75,11 @@
 	pipe = usb_sndctrlpipe(udev, 0); /* write_out */
 	reqtype =  REALTEK_USB_VENQT_WRITE;
 
-	dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
+	dr = kzalloc(sizeof(*dr), GFP_ATOMIC);
 	if (!dr)
 		return -ENOMEM;
 
-	databuf = kmalloc(databuf_maxlen, GFP_ATOMIC);
+	databuf = kzalloc(databuf_maxlen, GFP_ATOMIC);
 	if (!databuf) {
 		kfree(dr);
 		return -ENOMEM;
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 407a793..6866dcf 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -11,10 +11,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
  * The full GNU General Public License is included in this distribution in the
  * file called LICENSE.
  *
@@ -147,7 +143,27 @@
 #define FCS_LEN				4
 #define EM_HDR_LEN			8
 
+enum rtl8192c_h2c_cmd {
+	H2C_AP_OFFLOAD = 0,
+	H2C_SETPWRMODE = 1,
+	H2C_JOINBSSRPT = 2,
+	H2C_RSVDPAGE = 3,
+	H2C_RSSI_REPORT = 5,
+	H2C_RA_MASK = 6,
+	H2C_MACID_PS_MODE = 7,
+	H2C_P2P_PS_OFFLOAD = 8,
+	H2C_MAC_MODE_SEL = 9,
+	H2C_PWRM = 15,
+	H2C_P2P_PS_CTW_CMD = 24,
+	MAX_H2CCMD
+};
+
 #define MAX_TX_COUNT			4
+#define MAX_REGULATION_NUM		4
+#define MAX_RF_PATH_NUM			4
+#define MAX_RATE_SECTION_NUM		6
+#define MAX_2_4G_BANDWITH_NUM		4
+#define MAX_5G_BANDWITH_NUM		4
 #define	MAX_RF_PATH			4
 #define	MAX_CHNL_GROUP_24G		6
 #define	MAX_CHNL_GROUP_5G		14
@@ -163,6 +179,12 @@
 #define DEL_SW_IDX_SZ		30
 #define BAND_NUM			3
 
+/* For now, it's just for 8192ee
+ * but not OK yet, keep it 0
+ */
+#define DMA_IS_64BIT 0
+#define RTL8192EE_SEG_NUM		1 /* 0:2 seg, 1: 4 seg, 2: 8 seg */
+
 enum rf_tx_num {
 	RF_1TX = 0,
 	RF_2TX,
@@ -170,6 +192,36 @@
 	RF_TX_NUM_NONIMPLEMENT,
 };
 
+#define PACKET_NORMAL			0
+#define PACKET_DHCP			1
+#define PACKET_ARP			2
+#define PACKET_EAPOL			3
+
+#define	MAX_SUPPORT_WOL_PATTERN_NUM	16
+#define	RSVD_WOL_PATTERN_NUM		1
+#define	WKFMCAM_ADDR_NUM		6
+#define	WKFMCAM_SIZE			24
+
+#define	MAX_WOL_BIT_MASK_SIZE		16
+/* MIN LEN keeps 13 here */
+#define	MIN_WOL_PATTERN_SIZE		13
+#define	MAX_WOL_PATTERN_SIZE		128
+
+#define	WAKE_ON_MAGIC_PACKET		BIT(0)
+#define	WAKE_ON_PATTERN_MATCH		BIT(1)
+
+#define	WOL_REASON_PTK_UPDATE		BIT(0)
+#define	WOL_REASON_GTK_UPDATE		BIT(1)
+#define	WOL_REASON_DISASSOC		BIT(2)
+#define	WOL_REASON_DEAUTH		BIT(3)
+#define	WOL_REASON_AP_LOST		BIT(4)
+#define	WOL_REASON_MAGIC_PKT		BIT(5)
+#define	WOL_REASON_UNICAST_PKT		BIT(6)
+#define	WOL_REASON_PATTERN_PKT		BIT(7)
+#define	WOL_REASON_RTD3_SSID_MATCH	BIT(8)
+#define	WOL_REASON_REALWOW_V2_WAKEUPPKT	BIT(9)
+#define	WOL_REASON_REALWOW_V2_ACKLOST	BIT(10)
+
 struct txpower_info_2g {
 	u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
 	u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
@@ -213,6 +265,15 @@
 	RF90_PATH_D = 3,
 };
 
+enum regulation_txpwr_lmt {
+	TXPWR_LMT_FCC = 0,
+	TXPWR_LMT_MKK = 1,
+	TXPWR_LMT_ETSI = 2,
+	TXPWR_LMT_WW = 3,
+
+	TXPWR_LMT_MAX_REGULATION_NUM = 4
+};
+
 enum rt_eeprom_type {
 	EEPROM_93C46,
 	EEPROM_93C56,
@@ -234,8 +295,9 @@
 	HARDWARE_TYPE_RTL8192DU,
 	HARDWARE_TYPE_RTL8723AE,
 	HARDWARE_TYPE_RTL8723U,
-	HARDWARE_TYPE_RTL8723BE,
 	HARDWARE_TYPE_RTL8188EE,
+	HARDWARE_TYPE_RTL8723BE,
+	HARDWARE_TYPE_RTL8192EE,
 	HARDWARE_TYPE_RTL8821AE,
 	HARDWARE_TYPE_RTL8812AE,
 
@@ -268,13 +330,7 @@
 #define	IS_HARDWARE_TYPE_8723(rtlhal)			\
 (IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal))
 
-#define RX_HAL_IS_CCK_RATE(_pdesc)\
-	(_pdesc->rxmcs == DESC92_RATE1M ||		\
-	 _pdesc->rxmcs == DESC92_RATE2M ||		\
-	 _pdesc->rxmcs == DESC92_RATE5_5M ||		\
-	 _pdesc->rxmcs == DESC92_RATE11M)
-
-#define RTL8723E_RX_HAL_IS_CCK_RATE(rxmcs)		\
+#define RX_HAL_IS_CCK_RATE(rxmcs)			\
 	((rxmcs) == DESC92_RATE1M ||			\
 	 (rxmcs) == DESC92_RATE2M ||			\
 	 (rxmcs) == DESC92_RATE5_5M ||			\
@@ -339,6 +395,7 @@
 	HW_VAR_DEFAULTKEY2,
 	HW_VAR_DEFAULTKEY3,
 	HW_VAR_SIFS,
+	HW_VAR_R2T_SIFS,
 	HW_VAR_DIFS,
 	HW_VAR_EIFS,
 	HW_VAR_SLOT_TIME,
@@ -390,6 +447,7 @@
 	HW_VAR_H2C_FW_MEDIASTATUSRPT,
 	HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
 	HW_VAR_FW_PSMODE_STATUS,
+	HW_VAR_INIT_RTS_RATE,
 	HW_VAR_RESUME_CLK_ON,
 	HW_VAR_FW_LPS_ACTION,
 	HW_VAR_1X1_RECV_COMBINE,
@@ -428,7 +486,7 @@
 	HW_VAR_DATA_FILTER,
 };
 
-enum _RT_MEDIA_STATUS {
+enum rt_media_status {
 	RT_MEDIA_DISCONNECT = 0,
 	RT_MEDIA_CONNECT = 1
 };
@@ -630,6 +688,7 @@
 	RTL_IMR_VIDOK,		/*AC_VI DMA OK Interrupt */
 	RTL_IMR_VODOK,		/*AC_VO DMA Interrupt */
 	RTL_IMR_ROK,		/*Receive DMA OK Interrupt */
+	RTL_IMR_HSISR_IND,	/*HSISR Interrupt*/
 	RTL_IBSS_INT_MASKS,	/*(RTL_IMR_BCNINT | RTL_IMR_TBDOK |
 				 * RTL_IMR_TBDER) */
 	RTL_IMR_C2HCMD,		/*fw interrupt*/
@@ -653,6 +712,13 @@
 	RTL_RC_HT_RATEMCS7,
 	RTL_RC_HT_RATEMCS15,
 
+	RTL_RC_VHT_RATE_1SS_MCS7,
+	RTL_RC_VHT_RATE_1SS_MCS8,
+	RTL_RC_VHT_RATE_1SS_MCS9,
+	RTL_RC_VHT_RATE_2SS_MCS7,
+	RTL_RC_VHT_RATE_2SS_MCS8,
+	RTL_RC_VHT_RATE_2SS_MCS9,
+
 	/*keep it last */
 	RTL_VAR_MAP_MAX,
 };
@@ -744,7 +810,9 @@
 	WIRELESS_MODE_N_24G = 0x10,
 	WIRELESS_MODE_N_5G = 0x20,
 	WIRELESS_MODE_AC_5G = 0x40,
-	WIRELESS_MODE_AC_24G  = 0x80
+	WIRELESS_MODE_AC_24G  = 0x80,
+	WIRELESS_MODE_AC_ONLY = 0x100,
+	WIRELESS_MODE_MAX = 0x800
 };
 
 #define IS_WIRELESS_MODE_A(wirelessmode)	\
@@ -798,6 +866,30 @@
 	RT_POLARITY_HIGH_ACT = 1,
 };
 
+/* After 8188E, we use V2 reason define. 88C/8723A use V1 reason. */
+enum fw_wow_reason_v2 {
+	FW_WOW_V2_PTK_UPDATE_EVENT = 0x01,
+	FW_WOW_V2_GTK_UPDATE_EVENT = 0x02,
+	FW_WOW_V2_DISASSOC_EVENT = 0x04,
+	FW_WOW_V2_DEAUTH_EVENT = 0x08,
+	FW_WOW_V2_FW_DISCONNECT_EVENT = 0x10,
+	FW_WOW_V2_MAGIC_PKT_EVENT = 0x21,
+	FW_WOW_V2_UNICAST_PKT_EVENT = 0x22,
+	FW_WOW_V2_PATTERN_PKT_EVENT = 0x23,
+	FW_WOW_V2_RTD3_SSID_MATCH_EVENT = 0x24,
+	FW_WOW_V2_REALWOW_V2_WAKEUPPKT = 0x30,
+	FW_WOW_V2_REALWOW_V2_ACKLOST = 0x31,
+	FW_WOW_V2_REASON_MAX = 0xff,
+};
+
+enum wolpattern_type {
+	UNICAST_PATTERN = 0,
+	MULTICAST_PATTERN = 1,
+	BROADCAST_PATTERN = 2,
+	DONT_CARE_DA = 3,
+	UNKNOWN_TYPE = 4,
+};
+
 struct octet_string {
 	u8 *octet;
 	u16 length;
@@ -898,6 +990,7 @@
 	long last_sigstrength_inpercent;
 
 	u32 rssi_calculate_cnt;
+	u32 pwdb_all_cnt;
 
 	/*Transformed, in dbm. Beautified signal
 	   strength for UI, not correct. */
@@ -1106,6 +1199,8 @@
 
 	u8 pwrgroup_cnt;
 	u8 cck_high_power;
+	/* this is for 88E & 8723A */
+	u32 mcs_txpwrlevel_origoffset[MAX_PG_GROUP][16];
 	/* MAX_PG_GROUP groups of pwr diff by rates */
 	u32 mcs_offset[MAX_PG_GROUP][16];
 	u32 tx_power_by_rate_offset[TX_PWR_BY_RATE_NUM_BAND]
@@ -1126,6 +1221,17 @@
 	u8 cur_bw20_txpwridx;
 	u8 cur_bw40_txpwridx;
 
+	char txpwr_limit_2_4g[MAX_REGULATION_NUM]
+			     [MAX_2_4G_BANDWITH_NUM]
+			     [MAX_RATE_SECTION_NUM]
+			     [CHANNEL_MAX_NUMBER_2G]
+			     [MAX_RF_PATH_NUM];
+	char txpwr_limit_5g[MAX_REGULATION_NUM]
+			   [MAX_5G_BANDWITH_NUM]
+			   [MAX_RATE_SECTION_NUM]
+			   [CHANNEL_MAX_NUMBER_5G]
+			   [MAX_RF_PATH_NUM];
+
 	u32 rfreg_chnlval[2];
 	bool apk_done;
 	u32 reg_rf3c[2];	/* pathA / pathB  */
@@ -1249,11 +1355,22 @@
 	/* skb wait queue */
 	struct sk_buff_head skb_waitq[MAX_TID_COUNT];
 
+	u8 ht_stbc_cap;
+	u8 ht_cur_stbc;
+
+	/*vht support*/
+	u8 vht_enable;
+	u8 bw_80;
+	u8 vht_cur_ldpc;
+	u8 vht_cur_stbc;
+	u8 vht_stbc_cap;
+	u8 vht_ldpc_cap;
+
 	/*RDG*/
 	bool rdg_en;
 
 	/*AP*/
-	u8 bssid[6];
+	u8 bssid[ETH_ALEN] __aligned(2);
 	u32 vendor;
 	u8 mcs[16];	/* 16 bytes mcs for HT rates. */
 	u32 basic_rates; /* b/g rates */
@@ -1261,7 +1378,7 @@
 	u8 sgi_40;
 	u8 sgi_20;
 	u8 bw_40;
-	u8 mode;		/* wireless mode */
+	u16 mode;		/* wireless mode */
 	u8 slot_time;
 	u8 short_preamble;
 	u8 use_cts_protect;
@@ -1358,6 +1475,18 @@
 	u32 version;		/*version of chip */
 	u8 state;		/*stop 0, start 1 */
 	u8 board_type;
+	u8 external_pa;
+
+	u8 pa_mode;
+	u8 pa_type_2g;
+	u8 pa_type_5g;
+	u8 lna_type_2g;
+	u8 lna_type_5g;
+	u8 external_pa_2g;
+	u8 external_lna_2g;
+	u8 external_pa_5g;
+	u8 external_lna_5g;
+	u8 rfe_type;
 
 	/*firmware */
 	u32 fwsize;
@@ -1413,6 +1542,20 @@
 
 	u16 rx_tag;/*for 92ee*/
 	u8 rts_en;
+
+	/*for wowlan*/
+	bool wow_enable;
+	bool enter_pnp_sleep;
+	bool wake_from_pnp_sleep;
+	bool wow_enabled;
+	__kernel_time_t last_suspend_sec;
+	u32 wowlan_fwsize;
+	u8 *wowlan_firmware;
+
+	u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/
+
+	bool real_wow_v2_enable;
+	bool re_init_llt_table;
 };
 
 struct rtl_security {
@@ -1759,6 +1902,15 @@
 	struct rtl_p2p_ps_info p2p_ps_info;
 	u8 pwr_mode;
 	u8 smart_ps;
+
+	/* wake up on line */
+	u8 wo_wlan_mode;
+	u8 arp_offload_enable;
+	u8 gtk_offload_enable;
+	/* Used for WOL, indicates the reason for waking event.*/
+	u32 wakeup_reason;
+	/* Record the last waking time for comparison with setting key. */
+	u64 last_wakeup_time;
 };
 
 struct rtl_stats {
@@ -1794,17 +1946,26 @@
 	u16 wakeup:1;
 	u32 timestamp_low;
 	u32 timestamp_high;
+	bool shift;
 
 	u8 rx_drvinfo_size;
 	u8 rx_bufshift;
 	bool isampdu;
 	bool isfirst_ampdu;
 	bool rx_is40Mhzpacket;
+	u8 rx_packet_bw;
 	u32 rx_pwdb_all;
 	u8 rx_mimo_signalstrength[4];	/*in 0~100 index */
+	s8 rx_mimo_signalquality[4];
+	u8 rx_mimo_evm_dbm[4];
+	u16 cfo_short[4];		/* per-path's Cfo_short */
+	u16 cfo_tail[4];
+
 	s8 rx_mimo_sig_qual[4];
 	u8 rx_pwr[4]; /* per-path's pwdb */
 	u8 rx_snr[4]; /* per-path's SNR */
+	u8 bandwidth;
+	u8 bt_coex_pwr_adjust;
 	bool packet_matchbssid;
 	bool is_cck;
 	bool is_ht;
@@ -1812,6 +1973,10 @@
 	bool packet_beacon;	/*for rssi */
 	char cck_adc_pwdb[4];	/*for rx path selection */
 
+	bool is_vht;
+	bool is_short_gi;
+	u8 vht_nss;
+
 	u8 packet_report_type;
 
 	u32 macid;
@@ -1844,7 +2009,7 @@
 };
 
 struct rtl_tcb_desc {
-	u8 packet_bw:1;
+	u8 packet_bw:2;
 	u8 multicast:1;
 	u8 broadcast:1;
 
@@ -1874,11 +2039,19 @@
 	u8 empkt_num;
 	/* The max value by HW */
 	u32 empkt_len[10];
-	bool btx_enable_sw_calc_duration;
+	bool tx_enable_sw_calc_duration;
 };
 
 struct rtl92c_firmware_header;
 
+struct rtl_wow_pattern {
+	u8 type;
+	u16 crc;
+	u32 mask[4];
+};
+
+struct rtl8723e_firmware_header;
+
 struct rtl_hal_ops {
 	int (*init_sw_vars) (struct ieee80211_hw *hw);
 	void (*deinit_sw_vars) (struct ieee80211_hw *hw);
@@ -1928,7 +2101,6 @@
 	void (*fill_tx_cmddesc) (struct ieee80211_hw *hw, u8 *pdesc,
 				 bool firstseg, bool lastseg,
 				 struct sk_buff *skb);
-	bool (*cmd_send_packet)(struct ieee80211_hw *hw, struct sk_buff *skb);
 	bool (*query_rx_desc) (struct ieee80211_hw *hw,
 			       struct rtl_stats *stats,
 			       struct ieee80211_rx_status *rx_status,
@@ -1983,9 +2155,12 @@
 	void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id,
 			      u32 cmd_len, u8 *p_cmdbuffer);
 	bool (*get_btc_status) (void);
-	bool (*is_fw_header) (struct rtl92c_firmware_header *hdr);
+	bool (*is_fw_header)(struct rtl8723e_firmware_header *hdr);
 	u32 (*rx_command_packet)(struct ieee80211_hw *hw,
 				 struct rtl_stats status, struct sk_buff *skb);
+	void (*add_wowlan_pattern)(struct ieee80211_hw *hw,
+				   struct rtl_wow_pattern *rtl_pattern,
+				   u8 index);
 };
 
 struct rtl_intf_ops {
@@ -2000,7 +2175,7 @@
 			   struct ieee80211_sta *sta,
 			   struct sk_buff *skb,
 			   struct rtl_tcb_desc *ptcb_desc);
-	void (*flush)(struct ieee80211_hw *hw, bool drop);
+	void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop);
 	int (*reset_trx_ring) (struct ieee80211_hw *hw);
 	bool (*waitq_insert) (struct ieee80211_hw *hw,
 			      struct ieee80211_sta *sta,
@@ -2029,9 +2204,13 @@
 	/* default: 1 = using linked fw power save */
 	bool fwctrl_lps;
 
-	/* default: 0 = not using MSI interrupts mode */
-	/* submodules should set their own defalut value */
+	/* default: 0 = not using MSI interrupts mode
+	 * submodules should set their own default value
+	 */
 	bool msi_support;
+
+	/* default 0: 1 means disable */
+	bool disable_watchdog;
 };
 
 struct rtl_hal_usbint_cfg {
@@ -2312,10 +2491,11 @@
 	void (*btc_init_hal_vars) (struct rtl_priv *rtlpriv);
 	void (*btc_init_hw_config) (struct rtl_priv *rtlpriv);
 	void (*btc_ips_notify) (struct rtl_priv *rtlpriv, u8 type);
+	void (*btc_lps_notify)(struct rtl_priv *rtlpriv, u8 type);
 	void (*btc_scan_notify) (struct rtl_priv *rtlpriv, u8 scantype);
 	void (*btc_connect_notify) (struct rtl_priv *rtlpriv, u8 action);
 	void (*btc_mediastatus_notify) (struct rtl_priv *rtlpriv,
-					enum _RT_MEDIA_STATUS mstatus);
+					enum rt_media_status mstatus);
 	void (*btc_periodical) (struct rtl_priv *rtlpriv);
 	void (*btc_halt_notify) (void);
 	void (*btc_btinfo_notify) (struct rtl_priv *rtlpriv,
@@ -2323,6 +2503,8 @@
 	bool (*btc_is_limited_dig) (struct rtl_priv *rtlpriv);
 	bool (*btc_is_disable_edca_turbo) (struct rtl_priv *rtlpriv);
 	bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv);
+	void (*btc_special_packet_notify)(struct rtl_priv *rtlpriv,
+					  u8 pkt_type);
 };
 
 struct proxim {
@@ -2336,6 +2518,8 @@
 
 struct rtl_priv {
 	struct ieee80211_hw *hw;
+	/* Used to load a second firmware */
+	void (*rtl_fw_second_cb)(struct rtl_priv *rtlpriv);
 	struct completion firmware_loading_complete;
 	struct list_head list;
 	struct rtl_priv *buddy_priv;
@@ -2411,6 +2595,9 @@
 	 */
 	bool use_new_trx_flow;
 
+#ifdef CONFIG_PM
+	struct wiphy_wowlan_support wowlan;
+#endif
 	/*This must be the last item so
 	   that it points to the data allocated
 	   beyond  this structure like:
@@ -2659,6 +2846,26 @@
 	(des)[2] = (src)[2], (des)[3] = (src)[3],\
 	(des)[4] = (src)[4], (des)[5] = (src)[5])
 
+#define	LDPC_HT_ENABLE_RX			BIT(0)
+#define	LDPC_HT_ENABLE_TX			BIT(1)
+#define	LDPC_HT_TEST_TX_ENABLE			BIT(2)
+#define	LDPC_HT_CAP_TX				BIT(3)
+
+#define	STBC_HT_ENABLE_RX			BIT(0)
+#define	STBC_HT_ENABLE_TX			BIT(1)
+#define	STBC_HT_TEST_TX_ENABLE			BIT(2)
+#define	STBC_HT_CAP_TX				BIT(3)
+
+#define	LDPC_VHT_ENABLE_RX			BIT(0)
+#define	LDPC_VHT_ENABLE_TX			BIT(1)
+#define	LDPC_VHT_TEST_TX_ENABLE			BIT(2)
+#define	LDPC_VHT_CAP_TX				BIT(3)
+
+#define	STBC_VHT_ENABLE_RX			BIT(0)
+#define	STBC_VHT_ENABLE_TX			BIT(1)
+#define	STBC_VHT_TEST_TX_ENABLE			BIT(2)
+#define	STBC_VHT_CAP_TX				BIT(3)
+
 static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr)
 {
 	return rtlpriv->io.read8_sync(rtlpriv, addr);
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c
index a0aa8fa..735be53 100644
--- a/drivers/net/wireless/ti/wl1251/spi.c
+++ b/drivers/net/wireless/ti/wl1251/spi.c
@@ -345,7 +345,6 @@
 {
 	struct wl1251 *wl = spi_get_drvdata(spi);
 
-	free_irq(wl->irq, wl);
 	wl1251_free_hw(wl);
 	regulator_disable(wl->vio);
 
diff --git a/drivers/net/wireless/ti/wlcore/debug.h b/drivers/net/wireless/ti/wlcore/debug.h
index 0420bd4..27bfb7c 100644
--- a/drivers/net/wireless/ti/wlcore/debug.h
+++ b/drivers/net/wireless/ti/wlcore/debug.h
@@ -65,7 +65,7 @@
 	pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
 
 #define wl1271_warning(fmt, arg...) \
-	pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
+	pr_warn(DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
 
 #define wl1271_notice(fmt, arg...) \
 	pr_info(DRIVER_PREFIX fmt "\n", ##arg)
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c
index 392c882..69601f6 100644
--- a/drivers/net/wireless/ti/wlcore/spi.c
+++ b/drivers/net/wireless/ti/wlcore/spi.c
@@ -327,23 +327,22 @@
 	struct wl12xx_spi_glue *glue;
 	struct wlcore_platdev_data pdev_data;
 	struct resource res[1];
-	int ret = -ENOMEM;
+	int ret;
 
 	memset(&pdev_data, 0x00, sizeof(pdev_data));
 
 	pdev_data.pdata = dev_get_platdata(&spi->dev);
 	if (!pdev_data.pdata) {
 		dev_err(&spi->dev, "no platform data\n");
-		ret = -ENODEV;
-		goto out;
+		return -ENODEV;
 	}
 
 	pdev_data.if_ops = &spi_ops;
 
-	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+	glue = devm_kzalloc(&spi->dev, sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
 		dev_err(&spi->dev, "can't allocate glue\n");
-		goto out;
+		return -ENOMEM;
 	}
 
 	glue->dev = &spi->dev;
@@ -357,14 +356,13 @@
 	ret = spi_setup(spi);
 	if (ret < 0) {
 		dev_err(glue->dev, "spi_setup failed\n");
-		goto out_free_glue;
+		return ret;
 	}
 
 	glue->core = platform_device_alloc("wl12xx", PLATFORM_DEVID_AUTO);
 	if (!glue->core) {
 		dev_err(glue->dev, "can't allocate platform_device\n");
-		ret = -ENOMEM;
-		goto out_free_glue;
+		return -ENOMEM;
 	}
 
 	glue->core->dev.parent = &spi->dev;
@@ -398,11 +396,6 @@
 
 out_dev_put:
 	platform_device_put(glue->core);
-
-out_free_glue:
-	kfree(glue);
-
-out:
 	return ret;
 }
 
@@ -411,7 +404,6 @@
 	struct wl12xx_spi_glue *glue = spi_get_drvdata(spi);
 
 	platform_device_unregister(glue->core);
-	kfree(glue);
 
 	return 0;
 }
diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c
index ff31939..0ea756b 100644
--- a/drivers/nfc/st21nfca/i2c.c
+++ b/drivers/nfc/st21nfca/i2c.c
@@ -271,6 +271,7 @@
 static int get_frame_size(u8 *buf, int buflen)
 {
 	int len = 0;
+
 	if (buf[len + 1] == ST21NFCA_SOF_EOF)
 		return 0;
 
@@ -311,6 +312,7 @@
 static int st21nfca_hci_i2c_repack(struct sk_buff *skb)
 {
 	int i, j, r, size;
+
 	if (skb->len < 1 || (skb->len > 1 && skb->data[1] != 0))
 		return -EBADMSG;
 
@@ -525,24 +527,19 @@
 	}
 
 	/* GPIO request and configuration */
-	r = devm_gpio_request(&client->dev, gpio, "clf_enable");
+	r = devm_gpio_request_one(&client->dev, gpio, GPIOF_OUT_INIT_HIGH,
+				  "clf_enable");
 	if (r) {
 		nfc_err(&client->dev, "Failed to request enable pin\n");
 		return -ENODEV;
 	}
 
-	r = gpio_direction_output(gpio, 1);
-	if (r) {
-		nfc_err(&client->dev, "Failed to set enable pin direction as output\n");
-		return -ENODEV;
-	}
 	phy->gpio_ena = gpio;
 
 	/* IRQ */
 	r = irq_of_parse_and_map(pp, 0);
 	if (r < 0) {
-		nfc_err(&client->dev,
-				"Unable to get irq, error: %d\n", r);
+		nfc_err(&client->dev, "Unable to get irq, error: %d\n", r);
 		return r;
 	}
 
@@ -576,32 +573,20 @@
 	phy->gpio_ena = pdata->gpio_ena;
 	phy->irq_polarity = pdata->irq_polarity;
 
-	r = devm_gpio_request(&client->dev, phy->gpio_irq, "wake_up");
+	r = devm_gpio_request_one(&client->dev, phy->gpio_irq, GPIOF_IN,
+				  "wake_up");
 	if (r) {
 		pr_err("%s : gpio_request failed\n", __FILE__);
 		return -ENODEV;
 	}
 
-	r = gpio_direction_input(phy->gpio_irq);
-	if (r) {
-		pr_err("%s : gpio_direction_input failed\n", __FILE__);
-		return -ENODEV;
-	}
-
 	if (phy->gpio_ena > 0) {
-		r = devm_gpio_request(&client->dev,
-					phy->gpio_ena, "clf_enable");
+		r = devm_gpio_request_one(&client->dev, phy->gpio_ena,
+					  GPIOF_OUT_INIT_HIGH, "clf_enable");
 		if (r) {
 			pr_err("%s : ena gpio_request failed\n", __FILE__);
 			return -ENODEV;
 		}
-		r = gpio_direction_output(phy->gpio_ena, 1);
-
-		if (r) {
-			pr_err("%s : ena gpio_direction_output failed\n",
-			       __FILE__);
-			return -ENODEV;
-		}
 	}
 
 	/* IRQ */
@@ -711,7 +696,6 @@
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = ST21NFCA_HCI_I2C_DRIVER_NAME,
-		.owner = THIS_MODULE,
 		.of_match_table = of_match_ptr(of_st21nfca_i2c_match),
 	},
 	.probe = st21nfca_hci_i2c_probe,
diff --git a/drivers/nfc/st21nfca/st21nfca.c b/drivers/nfc/st21nfca/st21nfca.c
index a902b05..a89e56c 100644
--- a/drivers/nfc/st21nfca/st21nfca.c
+++ b/drivers/nfc/st21nfca/st21nfca.c
@@ -34,7 +34,7 @@
 #define ST21NFCA_RF_READER_CMD_PRESENCE_CHECK	0x30
 
 #define ST21NFCA_RF_READER_ISO15693_GATE	0x12
-#define ST21NFCA_RF_READER_ISO15693_INVENTORY 0x01
+#define ST21NFCA_RF_READER_ISO15693_INVENTORY	0x01
 
 /*
  * Reader gate for communication with contact-less cards using Type A
@@ -45,21 +45,42 @@
 #define ST21NFCA_RF_READER_14443_3_A_ATQA	0x03
 #define ST21NFCA_RF_READER_14443_3_A_SAK	0x04
 
+#define ST21NFCA_RF_READER_F_DATARATE		0x01
+#define ST21NFCA_RF_READER_F_DATARATE_106	0x01
+#define ST21NFCA_RF_READER_F_DATARATE_212	0x02
+#define ST21NFCA_RF_READER_F_DATARATE_424	0x04
+#define ST21NFCA_RF_READER_F_POL_REQ		0x02
+#define ST21NFCA_RF_READER_F_POL_REQ_DEFAULT	0xffff0000
+#define ST21NFCA_RF_READER_F_NFCID2		0x03
+#define ST21NFCA_RF_READER_F_NFCID1		0x04
+
+#define ST21NFCA_RF_CARD_F_MODE			0x01
+#define ST21NFCA_RF_CARD_F_NFCID2_LIST		0x04
+#define ST21NFCA_RF_CARD_F_NFCID1		0x05
+#define ST21NFCA_RF_CARD_F_SENS_RES		0x06
+#define ST21NFCA_RF_CARD_F_SEL_RES		0x07
+#define ST21NFCA_RF_CARD_F_DATARATE		0x08
+#define ST21NFCA_RF_CARD_F_DATARATE_212_424	0x01
+
 #define ST21NFCA_DEVICE_MGNT_GATE		0x01
 #define ST21NFCA_DEVICE_MGNT_PIPE		0x02
 
-#define ST21NFCA_DM_GETINFO         0x13
-#define ST21NFCA_DM_GETINFO_PIPE_LIST       0x02
-#define ST21NFCA_DM_GETINFO_PIPE_INFO       0x01
-#define ST21NFCA_DM_PIPE_CREATED        0x02
-#define ST21NFCA_DM_PIPE_OPEN           0x04
-#define ST21NFCA_DM_RF_ACTIVE           0x80
-#define ST21NFCA_DM_DISCONNECT		0x30
+#define ST21NFCA_DM_GETINFO			0x13
+#define ST21NFCA_DM_GETINFO_PIPE_LIST		0x02
+#define ST21NFCA_DM_GETINFO_PIPE_INFO		0x01
+#define ST21NFCA_DM_PIPE_CREATED		0x02
+#define ST21NFCA_DM_PIPE_OPEN			0x04
+#define ST21NFCA_DM_RF_ACTIVE			0x80
+#define ST21NFCA_DM_DISCONNECT			0x30
 
 #define ST21NFCA_DM_IS_PIPE_OPEN(p) \
 	((p & 0x0f) == (ST21NFCA_DM_PIPE_CREATED | ST21NFCA_DM_PIPE_OPEN))
 
-#define ST21NFCA_NFC_MODE	0x03	/* NFC_MODE parameter*/
+#define ST21NFCA_NFC_MODE			0x03	/* NFC_MODE parameter*/
+#define ST21NFCA_EVT_FIELD_ON			0x11
+#define ST21NFCA_EVT_CARD_DEACTIVATED		0x12
+#define ST21NFCA_EVT_CARD_ACTIVATED		0x13
+#define ST21NFCA_EVT_FIELD_OFF			0x14
 
 static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES);
 
@@ -355,8 +376,8 @@
 			if (r < 0)
 				return r;
 
-			pol_req =
-			    be32_to_cpu(ST21NFCA_RF_READER_F_POL_REQ_DEFAULT);
+			pol_req = be32_to_cpu((__force __be32)
+					ST21NFCA_RF_READER_F_POL_REQ_DEFAULT);
 			r = nfc_hci_set_param(hdev, ST21NFCA_RF_READER_F_GATE,
 					      ST21NFCA_RF_READER_F_POL_REQ,
 					      (u8 *) &pol_req, 4);
@@ -790,6 +811,7 @@
 				       struct nfc_target *target)
 {
 	u8 fwi = 0x11;
+
 	switch (target->hci_reader_gate) {
 	case NFC_HCI_RF_READER_A_GATE:
 	case NFC_HCI_RF_READER_B_GATE:
@@ -839,20 +861,16 @@
 		if (gate == ST21NFCA_RF_CARD_F_GATE) {
 			r = st21nfca_tm_event_send_data(hdev, skb, gate);
 			if (r < 0)
-				goto exit;
+				return r;
 			return 0;
-		} else {
-			info->dep_info.curr_nfc_dep_pni = 0;
-			return 1;
 		}
-		break;
+		info->dep_info.curr_nfc_dep_pni = 0;
+		return 1;
 	default:
 		return 1;
 	}
 	kfree_skb(skb);
 	return 0;
-exit:
-	return r;
 }
 
 static struct nfc_hci_ops st21nfca_hci_ops = {
@@ -904,8 +922,11 @@
 	 * persistent info to discriminate 2 identical chips
 	 */
 	dev_num = find_first_zero_bit(dev_mask, ST21NFCA_NUM_DEVICES);
+
 	if (dev_num >= ST21NFCA_NUM_DEVICES)
-		goto err_alloc_hdev;
+		return -ENODEV;
+
+	set_bit(dev_num, dev_mask);
 
 	scnprintf(init_data.session_id, sizeof(init_data.session_id), "%s%2x",
 		  "ST21AH", dev_num);
diff --git a/drivers/nfc/st21nfca/st21nfca.h b/drivers/nfc/st21nfca/st21nfca.h
index 96fe5a6..a0b77f1 100644
--- a/drivers/nfc/st21nfca/st21nfca.h
+++ b/drivers/nfc/st21nfca/st21nfca.h
@@ -82,30 +82,9 @@
 #define ST21NFCA_WR_XCHG_DATA            0x10
 
 #define ST21NFCA_RF_READER_F_GATE               0x14
-#define ST21NFCA_RF_READER_F_DATARATE 0x01
-#define ST21NFCA_RF_READER_F_DATARATE_106 0x01
-#define ST21NFCA_RF_READER_F_DATARATE_212 0x02
-#define ST21NFCA_RF_READER_F_DATARATE_424 0x04
-#define ST21NFCA_RF_READER_F_POL_REQ    0x02
-#define ST21NFCA_RF_READER_F_POL_REQ_DEFAULT    0xffff0000
-#define ST21NFCA_RF_READER_F_NFCID2 0x03
-#define ST21NFCA_RF_READER_F_NFCID1 0x04
-#define ST21NFCA_RF_READER_F_SENS_RES 0x05
 
 #define ST21NFCA_RF_CARD_F_GATE 0x24
-#define ST21NFCA_RF_CARD_F_MODE 0x01
-#define ST21NFCA_RF_CARD_F_NFCID2_LIST 0x04
-#define ST21NFCA_RF_CARD_F_NFCID1 0x05
-#define ST21NFCA_RF_CARD_F_SENS_RES 0x06
-#define ST21NFCA_RF_CARD_F_SEL_RES 0x07
-#define ST21NFCA_RF_CARD_F_DATARATE 0x08
-#define ST21NFCA_RF_CARD_F_DATARATE_106 0x00
-#define ST21NFCA_RF_CARD_F_DATARATE_212_424 0x01
 
 #define ST21NFCA_EVT_SEND_DATA 0x10
-#define ST21NFCA_EVT_FIELD_ON 0x11
-#define ST21NFCA_EVT_CARD_DEACTIVATED 0x12
-#define ST21NFCA_EVT_CARD_ACTIVATED 0x13
-#define ST21NFCA_EVT_FIELD_OFF 0x14
 
 #endif /* __LOCAL_ST21NFCA_H_ */
diff --git a/drivers/nfc/st21nfca/st21nfca_dep.c b/drivers/nfc/st21nfca/st21nfca_dep.c
index b2d9957..bfb6df5 100644
--- a/drivers/nfc/st21nfca/st21nfca_dep.c
+++ b/drivers/nfc/st21nfca/st21nfca_dep.c
@@ -121,6 +121,7 @@
 
 	struct nfc_dev *dev;
 	struct sk_buff *skb;
+
 	if (info) {
 		dev = info->hdev->ndev;
 		skb = info->dep_info.tx_pending;
@@ -128,9 +129,8 @@
 		device_lock(&dev->dev);
 
 		nfc_hci_send_cmd_async(info->hdev, ST21NFCA_RF_READER_F_GATE,
-							ST21NFCA_WR_XCHG_DATA,
-							skb->data, skb->len,
-							info->async_cb, info);
+				ST21NFCA_WR_XCHG_DATA, skb->data, skb->len,
+				info->async_cb, info);
 		device_unlock(&dev->dev);
 		kfree_skb(skb);
 	}
@@ -185,8 +185,10 @@
 
 	info->dep_info.curr_nfc_dep_pni = 0;
 
-	return nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE,
+	r = nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE,
 				ST21NFCA_EVT_SEND_DATA, skb->data, skb->len);
+	kfree_skb(skb);
+	return r;
 }
 
 static int st21nfca_tm_recv_atr_req(struct nfc_hci_dev *hdev,
@@ -197,10 +199,6 @@
 	int r;
 
 	skb_trim(skb, skb->len - 1);
-	if (IS_ERR(skb)) {
-		r = PTR_ERR(skb);
-		goto exit;
-	}
 
 	if (!skb->len) {
 		r = -EIO;
@@ -214,6 +212,11 @@
 
 	atr_req = (struct st21nfca_atr_req *)skb->data;
 
+	if (atr_req->length < sizeof(struct st21nfca_atr_req)) {
+		r = -EPROTO;
+		goto exit;
+	}
+
 	r = st21nfca_tm_send_atr_res(hdev, atr_req);
 	if (r)
 		goto exit;
@@ -237,7 +240,6 @@
 	struct st21nfca_psl_res *psl_res;
 	struct sk_buff *skb;
 	u8 bitrate[2] = {0, 0};
-
 	int r;
 
 	skb = alloc_skb(sizeof(struct st21nfca_psl_res), GFP_KERNEL);
@@ -254,6 +256,8 @@
 
 	r = nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE,
 				ST21NFCA_EVT_SEND_DATA, skb->data, skb->len);
+	if (r < 0)
+		goto error;
 
 	/*
 	 * ST21NFCA only support P2P passive.
@@ -269,8 +273,11 @@
 	}
 
 	/* Send an event to change bitrate change event to card f */
-	return nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE,
+	r = nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE,
 			ST21NFCA_EVT_CARD_F_BITRATE, bitrate, 2);
+error:
+	kfree_skb(skb);
+	return r;
 }
 
 static int st21nfca_tm_recv_psl_req(struct nfc_hci_dev *hdev,
@@ -280,11 +287,6 @@
 	int r;
 
 	skb_trim(skb, skb->len - 1);
-	if (IS_ERR(skb)) {
-		r = PTR_ERR(skb);
-		skb = NULL;
-		goto exit;
-	}
 
 	if (!skb->len) {
 		r = -EIO;
@@ -314,7 +316,7 @@
 	*skb_push(skb, 1) = skb->len;
 
 	r = nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE,
-				ST21NFCA_EVT_SEND_DATA, skb->data, skb->len);
+			ST21NFCA_EVT_SEND_DATA, skb->data, skb->len);
 	kfree_skb(skb);
 
 	return r;
@@ -330,11 +332,6 @@
 	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
 
 	skb_trim(skb, skb->len - 1);
-	if (IS_ERR(skb)) {
-		r = PTR_ERR(skb);
-		skb = NULL;
-		goto exit;
-	}
 
 	size = 4;
 
@@ -368,12 +365,6 @@
 		break;
 	}
 
-	if (IS_ERR(skb)) {
-		r = PTR_ERR(skb);
-		skb = NULL;
-		goto exit;
-	}
-
 	skb_pull(skb, size);
 
 	return nfc_tm_data_received(hdev->ndev, skb);
@@ -437,8 +428,6 @@
 	*skb_push(skb, 1) = info->dep_info.to | 0x10;
 
 	st21nfca_im_send_pdu(info, skb);
-
-	kfree_skb(skb);
 }
 
 #define ST21NFCA_CB_TYPE_READER_F 1
@@ -452,7 +441,7 @@
 	if (err != 0)
 		return;
 
-	if (IS_ERR(skb))
+	if (!skb)
 		return;
 
 	switch (info->async_cb_type) {
@@ -484,8 +473,7 @@
 						ST21NFCA_PP2LRI(atr_res->ppi));
 		break;
 	default:
-		if (err == 0)
-			kfree_skb(skb);
+		kfree_skb(skb);
 		break;
 	}
 }
@@ -522,7 +510,7 @@
 	memset(atr_req->nfcid3, 0, NFC_NFCID3_MAXSIZE);
 	target = hdev->ndev->targets;
 
-	if (target->sensf_res)
+	if (target->sensf_res_len > 0)
 		memcpy(atr_req->nfcid3, target->sensf_res,
 				target->sensf_res_len);
 	else
@@ -565,7 +553,7 @@
 	if (err != 0)
 		return;
 
-	if (IS_ERR(skb))
+	if (!skb)
 		return;
 
 	switch (info->async_cb_type) {
@@ -615,8 +603,7 @@
 	}
 
 exit:
-	if (err == 0)
-		kfree_skb(skb);
+	kfree_skb(skb);
 }
 
 int st21nfca_im_send_dep_req(struct nfc_hci_dev *hdev, struct sk_buff *skb)
diff --git a/drivers/nfc/st21nfcb/i2c.c b/drivers/nfc/st21nfcb/i2c.c
index 8af880e..c5d2427 100644
--- a/drivers/nfc/st21nfcb/i2c.c
+++ b/drivers/nfc/st21nfcb/i2c.c
@@ -17,24 +17,16 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/crc-ccitt.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/of_irq.h>
 #include <linux/of_gpio.h>
-#include <linux/miscdevice.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/nfc.h>
-#include <linux/firmware.h>
-#include <linux/unaligned/access_ok.h>
 #include <linux/platform_data/st21nfcb.h>
 
-#include <net/nfc/nci.h>
-#include <net/nfc/llc.h>
-#include <net/nfc/nfc.h>
-
 #include "ndlc.h"
 
 #define DRIVER_DESC "NCI NFC driver for ST21NFCB"
@@ -63,12 +55,6 @@
 	unsigned int irq_polarity;
 
 	int powered;
-
-	/*
-	 * < 0 if hardware error occured (e.g. i2c err)
-	 * and prevents normal operation.
-	 */
-	int hard_fault;
 };
 
 #define I2C_DUMP_SKB(info, skb)					\
@@ -122,8 +108,8 @@
 
 	I2C_DUMP_SKB("st21nfcb_nci_i2c_write", skb);
 
-	if (phy->hard_fault != 0)
-		return phy->hard_fault;
+	if (phy->ndlc->hard_fault != 0)
+		return phy->ndlc->hard_fault;
 
 	r = i2c_master_send(client, skb->data, skb->len);
 	if (r == -EREMOTEIO) {  /* Retry, chip was in standby */
@@ -168,11 +154,11 @@
 	if (r == -EREMOTEIO) {  /* Retry, chip was in standby */
 		usleep_range(1000, 4000);
 		r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE);
-	} else if (r != ST21NFCB_NCI_I2C_MIN_SIZE) {
-		nfc_err(&client->dev, "cannot read ndlc & nci header\n");
-		return -EREMOTEIO;
 	}
 
+	if (r != ST21NFCB_NCI_I2C_MIN_SIZE)
+		return -EREMOTEIO;
+
 	len = be16_to_cpu(*(__be16 *) (buf + 2));
 	if (len > ST21NFCB_NCI_I2C_MAX_SIZE) {
 		nfc_err(&client->dev, "invalid frame len\n");
@@ -224,7 +210,7 @@
 	client = phy->i2c_dev;
 	dev_dbg(&client->dev, "IRQ\n");
 
-	if (phy->hard_fault)
+	if (phy->ndlc->hard_fault)
 		return IRQ_HANDLED;
 
 	if (!phy->powered) {
@@ -233,13 +219,8 @@
 	}
 
 	r = st21nfcb_nci_i2c_read(phy, &skb);
-	if (r == -EREMOTEIO) {
-		phy->hard_fault = r;
-                ndlc_recv(phy->ndlc, NULL);
+	if (r == -EREMOTEIO || r == -ENOMEM || r == -EBADMSG)
 		return IRQ_HANDLED;
-	} else if (r == -ENOMEM || r == -EBADMSG) {
-		return IRQ_HANDLED;
-	}
 
 	ndlc_recv(phy->ndlc, skb);
 
@@ -273,25 +254,18 @@
 	}
 
 	/* GPIO request and configuration */
-	r = devm_gpio_request(&client->dev, gpio, "clf_reset");
+	r = devm_gpio_request_one(&client->dev, gpio,
+				GPIOF_OUT_INIT_HIGH, "clf_reset");
 	if (r) {
 		nfc_err(&client->dev, "Failed to request reset pin\n");
 		return -ENODEV;
 	}
-
-	r = gpio_direction_output(gpio, 1);
-	if (r) {
-		nfc_err(&client->dev,
-			"Failed to set reset pin direction as output\n");
-		return -ENODEV;
-	}
 	phy->gpio_reset = gpio;
 
 	/* IRQ */
 	r = irq_of_parse_and_map(pp, 0);
 	if (r < 0) {
-		nfc_err(&client->dev,
-				"Unable to get irq, error: %d\n", r);
+		nfc_err(&client->dev, "Unable to get irq, error: %d\n", r);
 		return r;
 	}
 
@@ -325,32 +299,20 @@
 	phy->gpio_reset = pdata->gpio_reset;
 	phy->irq_polarity = pdata->irq_polarity;
 
-	r = devm_gpio_request(&client->dev, phy->gpio_irq, "wake_up");
+	r = devm_gpio_request_one(&client->dev, phy->gpio_irq,
+				GPIOF_IN, "clf_irq");
 	if (r) {
 		pr_err("%s : gpio_request failed\n", __FILE__);
 		return -ENODEV;
 	}
 
-	r = gpio_direction_input(phy->gpio_irq);
-	if (r) {
-		pr_err("%s : gpio_direction_input failed\n", __FILE__);
-		return -ENODEV;
-	}
-
-	r = devm_gpio_request(&client->dev,
-			      phy->gpio_reset, "clf_reset");
+	r = devm_gpio_request_one(&client->dev,
+			phy->gpio_reset, GPIOF_OUT_INIT_HIGH, "clf_reset");
 	if (r) {
 		pr_err("%s : reset gpio_request failed\n", __FILE__);
 		return -ENODEV;
 	}
 
-	r = gpio_direction_output(phy->gpio_reset, 1);
-	if (r) {
-		pr_err("%s : reset gpio_direction_output failed\n",
-			__FILE__);
-		return -ENODEV;
-	}
-
 	/* IRQ */
 	irq = gpio_to_irq(phy->gpio_irq);
 	if (irq < 0) {
@@ -448,7 +410,6 @@
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = ST21NFCB_NCI_I2C_DRIVER_NAME,
-		.owner = THIS_MODULE,
 		.of_match_table = of_match_ptr(of_st21nfcb_i2c_match),
 	},
 	.probe = st21nfcb_nci_i2c_probe,
diff --git a/drivers/nfc/st21nfcb/ndlc.c b/drivers/nfc/st21nfcb/ndlc.c
index 83c97c3..e7bff89 100644
--- a/drivers/nfc/st21nfcb/ndlc.c
+++ b/drivers/nfc/st21nfcb/ndlc.c
@@ -112,6 +112,10 @@
 		ndlc->t1_active = true;
 		mod_timer(&ndlc->t1_timer, time_sent +
 			msecs_to_jiffies(NDLC_TIMER_T1));
+		/* start timer t2 for chip availability */
+		ndlc->t2_active = true;
+		mod_timer(&ndlc->t2_timer, time_sent +
+			msecs_to_jiffies(NDLC_TIMER_T2));
 	}
 }
 
@@ -207,7 +211,7 @@
 		ndlc->t2_active = false;
 		ndlc->t1_active = false;
 		del_timer_sync(&ndlc->t1_timer);
-
+		del_timer_sync(&ndlc->t2_timer);
 		ndlc_close(ndlc);
 		ndlc->hard_fault = -EREMOTEIO;
 	}
diff --git a/drivers/nfc/st21nfcb/ndlc.h b/drivers/nfc/st21nfcb/ndlc.h
index c30a2f0..b28140e 100644
--- a/drivers/nfc/st21nfcb/ndlc.h
+++ b/drivers/nfc/st21nfcb/ndlc.h
@@ -42,6 +42,10 @@
 
 	struct device *dev;
 
+	/*
+	 * < 0 if hardware error occured
+	 * and prevents normal operation.
+	 */
 	int hard_fault;
 };
 
diff --git a/drivers/nfc/st21nfcb/st21nfcb.c b/drivers/nfc/st21nfcb/st21nfcb.c
index 4d95863..ea63d58 100644
--- a/drivers/nfc/st21nfcb/st21nfcb.c
+++ b/drivers/nfc/st21nfcb/st21nfcb.c
@@ -22,10 +22,11 @@
 #include <net/nfc/nci_core.h>
 
 #include "st21nfcb.h"
-#include "ndlc.h"
 
 #define DRIVER_DESC "NCI NFC driver for ST21NFCB"
 
+#define ST21NFCB_NCI1_X_PROPRIETARY_ISO15693 0x83
+
 static int st21nfcb_nci_open(struct nci_dev *ndev)
 {
 	struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
@@ -65,10 +66,18 @@
 	return ndlc_send(info->ndlc, skb);
 }
 
+static __u32 st21nfcb_nci_get_rfprotocol(struct nci_dev *ndev,
+					 __u8 rf_protocol)
+{
+	return rf_protocol == ST21NFCB_NCI1_X_PROPRIETARY_ISO15693 ?
+		NFC_PROTO_ISO15693_MASK : 0;
+}
+
 static struct nci_ops st21nfcb_nci_ops = {
 	.open = st21nfcb_nci_open,
 	.close = st21nfcb_nci_close,
 	.send = st21nfcb_nci_send,
+	.get_rfprotocol = st21nfcb_nci_get_rfprotocol,
 };
 
 int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
@@ -88,30 +97,26 @@
 		| NFC_PROTO_FELICA_MASK
 		| NFC_PROTO_ISO14443_MASK
 		| NFC_PROTO_ISO14443_B_MASK
+		| NFC_PROTO_ISO15693_MASK
 		| NFC_PROTO_NFC_DEP_MASK;
 
 	ndlc->ndev = nci_allocate_device(&st21nfcb_nci_ops, protocols,
 					phy_headroom, phy_tailroom);
 	if (!ndlc->ndev) {
 		pr_err("Cannot allocate nfc ndev\n");
-		r = -ENOMEM;
-		goto err_alloc_ndev;
+		return -ENOMEM;
 	}
 	info->ndlc = ndlc;
 
 	nci_set_drvdata(ndlc->ndev, info);
 
 	r = nci_register_device(ndlc->ndev);
-	if (r)
-		goto err_regdev;
+	if (r) {
+		pr_err("Cannot register nfc device to nci core\n");
+		nci_free_device(ndlc->ndev);
+	}
 
 	return r;
-err_regdev:
-	nci_free_device(ndlc->ndev);
-
-err_alloc_ndev:
-	kfree(info);
-	return r;
 }
 EXPORT_SYMBOL_GPL(st21nfcb_nci_probe);
 
diff --git a/drivers/nfc/st21nfcb/st21nfcb.h b/drivers/nfc/st21nfcb/st21nfcb.h
index 4bbbebb..ea58a56 100644
--- a/drivers/nfc/st21nfcb/st21nfcb.h
+++ b/drivers/nfc/st21nfcb/st21nfcb.h
@@ -19,8 +19,6 @@
 #ifndef __LOCAL_ST21NFCB_H_
 #define __LOCAL_ST21NFCB_H_
 
-#include <net/nfc/nci_core.h>
-
 #include "ndlc.h"
 
 /* Define private flags: */
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
index 3b78b03..d2ccd28 100644
--- a/drivers/nfc/trf7970a.c
+++ b/drivers/nfc/trf7970a.c
@@ -36,7 +36,13 @@
  * The trf7970a is very timing sensitive and the VIN, EN2, and EN
  * pins must asserted in that order and with specific delays in between.
  * The delays used in the driver were provided by TI and have been
- * confirmed to work with this driver.
+ * confirmed to work with this driver.  There is a bug with the current
+ * version of the trf7970a that requires that EN2 remain low no matter
+ * what.  If it goes high, it will generate an RF field even when in
+ * passive target mode.  TI has indicated that the chip will work okay
+ * when EN2 is left low.  The 'en2-rf-quirk' device tree property
+ * indicates that trf7970a currently being used has the erratum and
+ * that EN2 must be kept low.
  *
  * Timeouts are implemented using the delayed workqueue kernel facility.
  * Timeouts are required so things don't hang when there is no response
@@ -56,7 +62,7 @@
  * way to abort a command that's already been sent to the tag is so turn
  * off power to the tag.  If we do that, though, we'd have to go through
  * the entire anticollision procedure again but the digital layer doesn't
- * support that.  So, if an abort is received before trf7970a_in_send_cmd()
+ * support that.  So, if an abort is received before trf7970a_send_cmd()
  * has sent the command to the tag, it simply returns -ECANCELED.  If the
  * command has already been sent to the tag, then the driver continues
  * normally and recieves the response data (or error) but just before
@@ -77,6 +83,13 @@
  * been received and there isn't an error).  The delay is 20 ms since delays
  * of ~16 ms have been observed during testing.
  *
+ * When transmitting a frame larger than the FIFO size (127 bytes), the
+ * driver will wait 20 ms for the FIFO to drain past the low-watermark
+ * and generate an interrupt.  The low-watermark set to 32 bytes so the
+ * interrupt should fire after 127 - 32 = 95 bytes have been sent.  At
+ * the lowest possible bit rate (6.62 kbps for 15693), it will take up
+ * to ~14.35 ms so 20 ms is used for the timeout.
+ *
  * Type 2 write and sector select commands respond with a 4-bit ACK or NACK.
  * Having only 4 bits in the FIFO won't normally generate an interrupt so
  * driver enables the '4_bit_RX' bit of the Special Functions register 1
@@ -99,40 +112,43 @@
  * Note under Table 1-1 in section 1.6 of
  * http://www.ti.com/lit/ug/scbu011/scbu011.pdf, that wait should be at least
  * 10 ms for TI Tag-it HF-I tags; however testing has shown that is not long
- * enough.  For this reason, the driver waits 20 ms which seems to work
+ * enough so 20 ms is used.  So the timer is set to 40 ms - 20 ms to drain
+ * up to 127 bytes in the FIFO at the lowest bit rate plus another 20 ms to
+ * ensure the wait is long enough before sending the EOF.  This seems to work
  * reliably.
  */
 
 #define TRF7970A_SUPPORTED_PROTOCOLS \
 		(NFC_PROTO_MIFARE_MASK | NFC_PROTO_ISO14443_MASK |	\
 		 NFC_PROTO_ISO14443_B_MASK | NFC_PROTO_FELICA_MASK | \
-		 NFC_PROTO_ISO15693_MASK)
+		 NFC_PROTO_ISO15693_MASK | NFC_PROTO_NFC_DEP_MASK)
 
 #define TRF7970A_AUTOSUSPEND_DELAY		30000 /* 30 seconds */
 
-/* TX data must be prefixed with a FIFO reset cmd, a cmd that depends
- * on what the current framing is, the address of the TX length byte 1
- * register (0x1d), and the 2 byte length of the data to be transmitted.
- * That totals 5 bytes.
- */
-#define TRF7970A_TX_SKB_HEADROOM		5
-
 #define TRF7970A_RX_SKB_ALLOC_SIZE		256
 
-#define TRF7970A_FIFO_SIZE			128
+#define TRF7970A_FIFO_SIZE			127
 
 /* TX length is 3 nibbles long ==> 4KB - 1 bytes max */
 #define TRF7970A_TX_MAX				(4096 - 1)
 
+#define TRF7970A_WAIT_FOR_TX_IRQ		20
 #define TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT	20
-#define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT	3
-#define TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF	20
+#define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT	20
+#define TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF	40
+
+/* Guard times for various RF technologies (in us) */
+#define TRF7970A_GUARD_TIME_NFCA		5000
+#define TRF7970A_GUARD_TIME_NFCB		5000
+#define TRF7970A_GUARD_TIME_NFCF		20000
+#define TRF7970A_GUARD_TIME_15693		1000
 
 /* Quirks */
 /* Erratum: When reading IRQ Status register on trf7970a, we must issue a
  * read continuous command for IRQ Status and Collision Position registers.
  */
-#define TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA	BIT(0)
+#define TRF7970A_QUIRK_IRQ_STATUS_READ		BIT(0)
+#define TRF7970A_QUIRK_EN2_MUST_STAY_LOW	BIT(1)
 
 /* Direct commands */
 #define TRF7970A_CMD_IDLE			0x00
@@ -149,8 +165,8 @@
 #define TRF7970A_CMD_CLOSE_SLOT			0x15
 #define TRF7970A_CMD_BLOCK_RX			0x16
 #define TRF7970A_CMD_ENABLE_RX			0x17
-#define TRF7970A_CMD_TEST_EXT_RF		0x18
-#define TRF7970A_CMD_TEST_INT_RF		0x19
+#define TRF7970A_CMD_TEST_INT_RF		0x18
+#define TRF7970A_CMD_TEST_EXT_RF		0x19
 #define TRF7970A_CMD_RX_GAIN_ADJUST		0x1a
 
 /* Bits determining whether its a direct command or register R/W,
@@ -224,6 +240,15 @@
 #define TRF7970A_ISO_CTRL_14443B_848		0x0f
 #define TRF7970A_ISO_CTRL_FELICA_212		0x1a
 #define TRF7970A_ISO_CTRL_FELICA_424		0x1b
+#define TRF7970A_ISO_CTRL_NFC_NFCA_106		0x01
+#define TRF7970A_ISO_CTRL_NFC_NFCF_212		0x02
+#define TRF7970A_ISO_CTRL_NFC_NFCF_424		0x03
+#define TRF7970A_ISO_CTRL_NFC_CE_14443A		0x00
+#define TRF7970A_ISO_CTRL_NFC_CE_14443B		0x01
+#define TRF7970A_ISO_CTRL_NFC_CE		BIT(2)
+#define TRF7970A_ISO_CTRL_NFC_ACTIVE		BIT(3)
+#define TRF7970A_ISO_CTRL_NFC_INITIATOR		BIT(4)
+#define TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE	BIT(5)
 #define TRF7970A_ISO_CTRL_RFID			BIT(5)
 #define TRF7970A_ISO_CTRL_DIR_MODE		BIT(6)
 #define TRF7970A_ISO_CTRL_RX_CRC_N		BIT(7)	/* true == No CRC */
@@ -249,12 +274,32 @@
 #define TRF7970A_MODULATOR_EN_OOK		BIT(6)
 #define TRF7970A_MODULATOR_27MHZ		BIT(7)
 
+#define TRF7970A_RX_SPECIAL_SETTINGS_NO_LIM	BIT(0)
+#define TRF7970A_RX_SPECIAL_SETTINGS_AGCR	BIT(1)
+#define TRF7970A_RX_SPECIAL_SETTINGS_GD_0DB	(0x0 << 2)
+#define TRF7970A_RX_SPECIAL_SETTINGS_GD_5DB	(0x1 << 2)
+#define TRF7970A_RX_SPECIAL_SETTINGS_GD_10DB	(0x2 << 2)
+#define TRF7970A_RX_SPECIAL_SETTINGS_GD_15DB	(0x3 << 2)
+#define TRF7970A_RX_SPECIAL_SETTINGS_HBT	BIT(4)
+#define TRF7970A_RX_SPECIAL_SETTINGS_M848	BIT(5)
+#define TRF7970A_RX_SPECIAL_SETTINGS_C424	BIT(6)
+#define TRF7970A_RX_SPECIAL_SETTINGS_C212	BIT(7)
+
+#define TRF7970A_REG_IO_CTRL_VRS(v)		((v) & 0x07)
+#define TRF7970A_REG_IO_CTRL_IO_LOW		BIT(5)
+#define TRF7970A_REG_IO_CTRL_EN_EXT_PA		BIT(6)
+#define TRF7970A_REG_IO_CTRL_AUTO_REG		BIT(7)
+
 /* IRQ Status Register Bits */
 #define TRF7970A_IRQ_STATUS_NORESP		BIT(0) /* ISO15693 only */
+#define TRF7970A_IRQ_STATUS_NFC_COL_ERROR	BIT(0)
 #define TRF7970A_IRQ_STATUS_COL			BIT(1)
 #define TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR	BIT(2)
+#define TRF7970A_IRQ_STATUS_NFC_RF		BIT(2)
 #define TRF7970A_IRQ_STATUS_PARITY_ERROR	BIT(3)
+#define TRF7970A_IRQ_STATUS_NFC_SDD		BIT(3)
 #define TRF7970A_IRQ_STATUS_CRC_ERROR		BIT(4)
+#define TRF7970A_IRQ_STATUS_NFC_PROTO_ERROR	BIT(4)
 #define TRF7970A_IRQ_STATUS_FIFO		BIT(5)
 #define TRF7970A_IRQ_STATUS_SRX			BIT(6)
 #define TRF7970A_IRQ_STATUS_TX			BIT(7)
@@ -265,6 +310,10 @@
 		 TRF7970A_IRQ_STATUS_PARITY_ERROR |		\
 		 TRF7970A_IRQ_STATUS_CRC_ERROR)
 
+#define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK	(BIT(2) | BIT(1) | BIT(0))
+#define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK	(BIT(5) | BIT(4) | BIT(3))
+#define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK	BIT(6)
+
 #define TRF7970A_SPECIAL_FCN_REG1_COL_7_6		BIT(0)
 #define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL		BIT(1)
 #define TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX		BIT(2)
@@ -281,6 +330,49 @@
 #define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_16	0x2
 #define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32	0x3
 
+#define TRF7970A_NFC_LOW_FIELD_LEVEL_RFDET(v)	((v) & 0x07)
+#define TRF7970A_NFC_LOW_FIELD_LEVEL_CLEX_DIS	BIT(7)
+
+#define TRF7970A_NFC_TARGET_LEVEL_RFDET(v)	((v) & 0x07)
+#define TRF7970A_NFC_TARGET_LEVEL_HI_RF		BIT(3)
+#define TRF7970A_NFC_TARGET_LEVEL_SDD_EN	BIT(3)
+#define TRF7970A_NFC_TARGET_LEVEL_LD_S_4BYTES	(0x0 << 6)
+#define TRF7970A_NFC_TARGET_LEVEL_LD_S_7BYTES	(0x1 << 6)
+#define TRF7970A_NFC_TARGET_LEVEL_LD_S_10BYTES	(0x2 << 6)
+
+#define TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_106		BIT(0)
+#define TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_212		BIT(1)
+#define TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_424		(BIT(0) | BIT(1))
+#define TRF79070A_NFC_TARGET_PROTOCOL_PAS_14443B	BIT(2)
+#define TRF79070A_NFC_TARGET_PROTOCOL_PAS_106		BIT(3)
+#define TRF79070A_NFC_TARGET_PROTOCOL_FELICA		BIT(4)
+#define TRF79070A_NFC_TARGET_PROTOCOL_RF_L		BIT(6)
+#define TRF79070A_NFC_TARGET_PROTOCOL_RF_H		BIT(7)
+
+#define TRF79070A_NFC_TARGET_PROTOCOL_106A		\
+	 (TRF79070A_NFC_TARGET_PROTOCOL_RF_H |		\
+	  TRF79070A_NFC_TARGET_PROTOCOL_RF_L |		\
+	  TRF79070A_NFC_TARGET_PROTOCOL_PAS_106 |	\
+	  TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_106)
+
+#define TRF79070A_NFC_TARGET_PROTOCOL_106B		\
+	 (TRF79070A_NFC_TARGET_PROTOCOL_RF_H |		\
+	  TRF79070A_NFC_TARGET_PROTOCOL_RF_L |		\
+	  TRF79070A_NFC_TARGET_PROTOCOL_PAS_14443B |	\
+	  TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_106)
+
+#define TRF79070A_NFC_TARGET_PROTOCOL_212F		\
+	 (TRF79070A_NFC_TARGET_PROTOCOL_RF_H |		\
+	  TRF79070A_NFC_TARGET_PROTOCOL_RF_L |		\
+	  TRF79070A_NFC_TARGET_PROTOCOL_FELICA |	\
+	  TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_212)
+
+#define TRF79070A_NFC_TARGET_PROTOCOL_424F		\
+	 (TRF79070A_NFC_TARGET_PROTOCOL_RF_H |		\
+	  TRF79070A_NFC_TARGET_PROTOCOL_RF_L |		\
+	  TRF79070A_NFC_TARGET_PROTOCOL_FELICA |	\
+	  TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_424)
+
 #define TRF7970A_FIFO_STATUS_OVERFLOW		BIT(7)
 
 /* NFC (ISO/IEC 14443A) Type 2 Tag commands */
@@ -317,13 +409,16 @@
 		(ISO15693_REQ_FLAG_SUB_CARRIER | ISO15693_REQ_FLAG_DATA_RATE)
 
 enum trf7970a_state {
-	TRF7970A_ST_OFF,
+	TRF7970A_ST_PWR_OFF,
+	TRF7970A_ST_RF_OFF,
 	TRF7970A_ST_IDLE,
 	TRF7970A_ST_IDLE_RX_BLOCKED,
 	TRF7970A_ST_WAIT_FOR_TX_FIFO,
 	TRF7970A_ST_WAIT_FOR_RX_DATA,
 	TRF7970A_ST_WAIT_FOR_RX_DATA_CONT,
 	TRF7970A_ST_WAIT_TO_ISSUE_EOF,
+	TRF7970A_ST_LISTENING,
+	TRF7970A_ST_LISTENING_MD,
 	TRF7970A_ST_MAX
 };
 
@@ -334,6 +429,7 @@
 	struct regulator		*regulator;
 	struct nfc_digital_dev		*ddev;
 	u32				quirks;
+	bool				is_initiator;
 	bool				aborting;
 	struct sk_buff			*tx_skb;
 	struct sk_buff			*rx_skb;
@@ -344,8 +440,10 @@
 	u8				iso_ctrl_tech;
 	u8				modulator_sys_clk_ctrl;
 	u8				special_fcn_reg1;
+	unsigned int			guard_time;
 	int				technology;
 	int				framing;
+	u8				md_rf_tech;
 	u8				tx_cmd;
 	bool				issue_eof;
 	int				en2_gpio;
@@ -386,15 +484,28 @@
 	return ret;
 }
 
-static int trf7970a_read_cont(struct trf7970a *trf, u8 reg,
-		u8 *buf, size_t len)
+static int trf7970a_read_cont(struct trf7970a *trf, u8 reg, u8 *buf, size_t len)
 {
 	u8 addr = reg | TRF7970A_CMD_BIT_RW | TRF7970A_CMD_BIT_CONTINUOUS;
+	struct spi_transfer t[2];
+	struct spi_message m;
 	int ret;
 
 	dev_dbg(trf->dev, "read_cont(0x%x, %zd)\n", addr, len);
 
-	ret = spi_write_then_read(trf->spi, &addr, 1, buf, len);
+	spi_message_init(&m);
+
+	memset(&t, 0, sizeof(t));
+
+	t[0].tx_buf = &addr;
+	t[0].len = sizeof(addr);
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].rx_buf = buf;
+	t[1].len = len;
+	spi_message_add_tail(&t[1], &m);
+
+	ret = spi_sync(trf->spi, &m);
 	if (ret)
 		dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr,
 				ret);
@@ -424,7 +535,7 @@
 
 	addr = TRF7970A_IRQ_STATUS | TRF7970A_CMD_BIT_RW;
 
-	if (trf->quirks & TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA) {
+	if (trf->quirks & TRF7970A_QUIRK_IRQ_STATUS_READ) {
 		addr |= TRF7970A_CMD_BIT_CONTINUOUS;
 		ret = spi_write_then_read(trf->spi, &addr, 1, buf, 2);
 	} else {
@@ -440,10 +551,60 @@
 	return ret;
 }
 
+static int trf7970a_read_target_proto(struct trf7970a *trf, u8 *target_proto)
+{
+	int ret;
+	u8 buf[2];
+	u8 addr;
+
+	addr = TRF79070A_NFC_TARGET_PROTOCOL | TRF7970A_CMD_BIT_RW |
+		TRF7970A_CMD_BIT_CONTINUOUS;
+
+	ret = spi_write_then_read(trf->spi, &addr, 1, buf, 2);
+	if (ret)
+		dev_err(trf->dev, "%s - target_proto: Read failed: %d\n",
+				__func__, ret);
+	else
+		*target_proto = buf[0];
+
+	return ret;
+}
+
+static int trf7970a_mode_detect(struct trf7970a *trf, u8 *rf_tech)
+{
+	int ret;
+	u8 target_proto, tech;
+
+	ret = trf7970a_read_target_proto(trf, &target_proto);
+	if (ret)
+		return ret;
+
+	switch (target_proto) {
+	case TRF79070A_NFC_TARGET_PROTOCOL_106A:
+		tech = NFC_DIGITAL_RF_TECH_106A;
+		break;
+	case TRF79070A_NFC_TARGET_PROTOCOL_106B:
+		tech = NFC_DIGITAL_RF_TECH_106B;
+		break;
+	case TRF79070A_NFC_TARGET_PROTOCOL_212F:
+		tech = NFC_DIGITAL_RF_TECH_212F;
+		break;
+	case TRF79070A_NFC_TARGET_PROTOCOL_424F:
+		tech = NFC_DIGITAL_RF_TECH_424F;
+		break;
+	default:
+		dev_dbg(trf->dev, "%s - mode_detect: target_proto: 0x%x\n",
+				__func__, target_proto);
+		return -EIO;
+	}
+
+	*rf_tech = tech;
+
+	return ret;
+}
+
 static void trf7970a_send_upstream(struct trf7970a *trf)
 {
-	u8 rssi;
-
 	dev_kfree_skb_any(trf->tx_skb);
 	trf->tx_skb = NULL;
 
@@ -452,13 +613,6 @@
 				16, 1, trf->rx_skb->data, trf->rx_skb->len,
 				false);
 
-	/* According to the manual it is "good form" to reset the fifo and
-	 * read the RSSI levels & oscillator status register here.  It doesn't
-	 * explain why.
-	 */
-	trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
-	trf7970a_read(trf, TRF7970A_RSSI_OSC_STATUS, &rssi);
-
 	trf->state = TRF7970A_ST_IDLE;
 
 	if (trf->aborting) {
@@ -481,6 +635,8 @@
 {
 	dev_dbg(trf->dev, "Error - state: %d, errno: %d\n", trf->state, errno);
 
+	cancel_delayed_work(&trf->timeout_work);
+
 	kfree_skb(trf->rx_skb);
 	trf->rx_skb = ERR_PTR(errno);
 
@@ -488,15 +644,29 @@
 }
 
 static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb,
-		unsigned int len)
+		unsigned int len, u8 *prefix, unsigned int prefix_len)
 {
+	struct spi_transfer t[2];
+	struct spi_message m;
 	unsigned int timeout;
 	int ret;
 
 	print_hex_dump_debug("trf7970a tx data: ", DUMP_PREFIX_NONE,
 			16, 1, skb->data, len, false);
 
-	ret = spi_write(trf->spi, skb->data, len);
+	spi_message_init(&m);
+
+	memset(&t, 0, sizeof(t));
+
+	t[0].tx_buf = prefix;
+	t[0].len = prefix_len;
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].tx_buf = skb->data;
+	t[1].len = len;
+	spi_message_add_tail(&t[1], &m);
+
+	ret = spi_sync(trf->spi, &m);
 	if (ret) {
 		dev_err(trf->dev, "%s - Can't send tx data: %d\n", __func__,
 				ret);
@@ -514,7 +684,11 @@
 			timeout = TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF;
 		} else {
 			trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
-			timeout = trf->timeout;
+
+			if (!trf->timeout)
+				timeout = TRF7970A_WAIT_FOR_TX_IRQ;
+			else
+				timeout = trf->timeout;
 		}
 	}
 
@@ -532,6 +706,7 @@
 	unsigned int len;
 	int ret;
 	u8 fifo_bytes;
+	u8 prefix;
 
 	ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
 	if (ret) {
@@ -541,18 +716,21 @@
 
 	dev_dbg(trf->dev, "Filling FIFO - fifo_bytes: 0x%x\n", fifo_bytes);
 
-	if (fifo_bytes & TRF7970A_FIFO_STATUS_OVERFLOW) {
-		dev_err(trf->dev, "%s - fifo overflow: 0x%x\n", __func__,
-				fifo_bytes);
-		trf7970a_send_err_upstream(trf, -EIO);
-		return;
-	}
+	fifo_bytes &= ~TRF7970A_FIFO_STATUS_OVERFLOW;
 
 	/* Calculate how much more data can be written to the fifo */
 	len = TRF7970A_FIFO_SIZE - fifo_bytes;
+	if (!len) {
+		schedule_delayed_work(&trf->timeout_work,
+			msecs_to_jiffies(TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT));
+		return;
+	}
+
 	len = min(skb->len, len);
 
-	ret = trf7970a_transmit(trf, skb, len);
+	prefix = TRF7970A_CMD_BIT_CONTINUOUS | TRF7970A_FIFO_IO_REGISTER;
+
+	ret = trf7970a_transmit(trf, skb, len, &prefix, sizeof(prefix));
 	if (ret)
 		trf7970a_send_err_upstream(trf, ret);
 }
@@ -576,16 +754,11 @@
 
 	dev_dbg(trf->dev, "Draining FIFO - fifo_bytes: 0x%x\n", fifo_bytes);
 
+	fifo_bytes &= ~TRF7970A_FIFO_STATUS_OVERFLOW;
+
 	if (!fifo_bytes)
 		goto no_rx_data;
 
-	if (fifo_bytes & TRF7970A_FIFO_STATUS_OVERFLOW) {
-		dev_err(trf->dev, "%s - fifo overflow: 0x%x\n", __func__,
-				fifo_bytes);
-		trf7970a_send_err_upstream(trf, -EIO);
-		return;
-	}
-
 	if (fifo_bytes > skb_tailroom(skb)) {
 		skb = skb_copy_expand(skb, skb_headroom(skb),
 				max_t(int, fifo_bytes,
@@ -615,6 +788,21 @@
 		status = TRF7970A_IRQ_STATUS_SRX;
 	} else {
 		trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA_CONT;
+
+		ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
+		if (ret) {
+			trf7970a_send_err_upstream(trf, ret);
+			return;
+		}
+
+		fifo_bytes &= ~TRF7970A_FIFO_STATUS_OVERFLOW;
+
+		/* If there are bytes in the FIFO, set status to '0' so
+		 * the if stmt below doesn't fire and the driver will wait
+		 * for the trf7970a to generate another RX interrupt.
+		 */
+		if (fifo_bytes)
+			status = 0;
 	}
 
 no_rx_data:
@@ -634,11 +822,11 @@
 {
 	struct trf7970a *trf = dev_id;
 	int ret;
-	u8 status;
+	u8 status, fifo_bytes, iso_ctrl;
 
 	mutex_lock(&trf->lock);
 
-	if (trf->state == TRF7970A_ST_OFF) {
+	if (trf->state == TRF7970A_ST_RF_OFF) {
 		mutex_unlock(&trf->lock);
 		return IRQ_NONE;
 	}
@@ -660,12 +848,12 @@
 	switch (trf->state) {
 	case TRF7970A_ST_IDLE:
 	case TRF7970A_ST_IDLE_RX_BLOCKED:
-		/* If getting interrupts caused by RF noise, turn off the
-		 * receiver to avoid unnecessary interrupts.  It will be
-		 * turned back on in trf7970a_in_send_cmd() when the next
-		 * command is issued.
+		/* If initiator and getting interrupts caused by RF noise,
+		 * turn off the receiver to avoid unnecessary interrupts.
+		 * It will be turned back on in trf7970a_send_cmd() when
+		 * the next command is issued.
 		 */
-		if (status & TRF7970A_IRQ_STATUS_ERROR) {
+		if (trf->is_initiator && (status & TRF7970A_IRQ_STATUS_ERROR)) {
 			trf7970a_cmd(trf, TRF7970A_CMD_BLOCK_RX);
 			trf->state = TRF7970A_ST_IDLE_RX_BLOCKED;
 		}
@@ -687,8 +875,68 @@
 			trf->ignore_timeout =
 				!cancel_delayed_work(&trf->timeout_work);
 			trf7970a_drain_fifo(trf, status);
-		} else if (status == TRF7970A_IRQ_STATUS_TX) {
+		} else if (status & TRF7970A_IRQ_STATUS_FIFO) {
+			ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS,
+					&fifo_bytes);
+
+			fifo_bytes &= ~TRF7970A_FIFO_STATUS_OVERFLOW;
+
+			if (ret)
+				trf7970a_send_err_upstream(trf, ret);
+			else if (!fifo_bytes)
+				trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+		} else if ((status == TRF7970A_IRQ_STATUS_TX) ||
+				(!trf->is_initiator &&
+				 (status == (TRF7970A_IRQ_STATUS_TX |
+					     TRF7970A_IRQ_STATUS_NFC_RF)))) {
 			trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+
+			if (!trf->timeout) {
+				trf->ignore_timeout = !cancel_delayed_work(
+						&trf->timeout_work);
+				trf->rx_skb = ERR_PTR(0);
+				trf7970a_send_upstream(trf);
+				break;
+			}
+
+			if (trf->is_initiator)
+				break;
+
+			iso_ctrl = trf->iso_ctrl;
+
+			switch (trf->framing) {
+			case NFC_DIGITAL_FRAMING_NFCA_STANDARD:
+				trf->tx_cmd = TRF7970A_CMD_TRANSMIT_NO_CRC;
+				iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
+				trf->iso_ctrl = 0xff; /* Force ISO_CTRL write */
+				break;
+			case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
+				trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+				iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
+				trf->iso_ctrl = 0xff; /* Force ISO_CTRL write */
+				break;
+			case NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE:
+				ret = trf7970a_write(trf,
+					TRF7970A_SPECIAL_FCN_REG1,
+					TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL);
+				if (ret)
+					goto err_unlock_exit;
+
+				trf->special_fcn_reg1 =
+					TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL;
+				break;
+			default:
+				break;
+			}
+
+			if (iso_ctrl != trf->iso_ctrl) {
+				ret = trf7970a_write(trf, TRF7970A_ISO_CTRL,
+						iso_ctrl);
+				if (ret)
+					goto err_unlock_exit;
+
+				trf->iso_ctrl = iso_ctrl;
+			}
 		} else {
 			trf7970a_send_err_upstream(trf, -EIO);
 		}
@@ -697,11 +945,37 @@
 		if (status != TRF7970A_IRQ_STATUS_TX)
 			trf7970a_send_err_upstream(trf, -EIO);
 		break;
+	case TRF7970A_ST_LISTENING:
+		if (status & TRF7970A_IRQ_STATUS_SRX) {
+			trf->ignore_timeout =
+				!cancel_delayed_work(&trf->timeout_work);
+			trf7970a_drain_fifo(trf, status);
+		} else if (!(status & TRF7970A_IRQ_STATUS_NFC_RF)) {
+			trf7970a_send_err_upstream(trf, -EIO);
+		}
+		break;
+	case TRF7970A_ST_LISTENING_MD:
+		if (status & TRF7970A_IRQ_STATUS_SRX) {
+			trf->ignore_timeout =
+				!cancel_delayed_work(&trf->timeout_work);
+
+			ret = trf7970a_mode_detect(trf, &trf->md_rf_tech);
+			if (ret) {
+				trf7970a_send_err_upstream(trf, ret);
+			} else {
+				trf->state = TRF7970A_ST_LISTENING;
+				trf7970a_drain_fifo(trf, status);
+			}
+		} else if (!(status & TRF7970A_IRQ_STATUS_NFC_RF)) {
+			trf7970a_send_err_upstream(trf, -EIO);
+		}
+		break;
 	default:
 		dev_err(trf->dev, "%s - Driver in invalid state: %d\n",
 				__func__, trf->state);
 	}
 
+err_unlock_exit:
 	mutex_unlock(&trf->lock);
 	return IRQ_HANDLED;
 }
@@ -742,7 +1016,7 @@
 	if (trf->ignore_timeout)
 		trf->ignore_timeout = false;
 	else if (trf->state == TRF7970A_ST_WAIT_FOR_RX_DATA_CONT)
-		trf7970a_send_upstream(trf); /* No more rx data so send up */
+		trf7970a_drain_fifo(trf, TRF7970A_IRQ_STATUS_SRX);
 	else if (trf->state == TRF7970A_ST_WAIT_TO_ISSUE_EOF)
 		trf7970a_issue_eof(trf);
 	else
@@ -765,11 +1039,16 @@
 	if (ret)
 		goto err_out;
 
-	/* Must clear NFC Target Detection Level reg due to erratum */
-	ret = trf7970a_write(trf, TRF7970A_NFC_TARGET_LEVEL, 0);
+	usleep_range(1000, 2000);
+
+	trf->chip_status_ctrl &= ~TRF7970A_CHIP_STATUS_RF_ON;
+
+	ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL, 0);
 	if (ret)
 		goto err_out;
 
+	trf->modulator_sys_clk_ctrl = 0;
+
 	ret = trf7970a_write(trf, TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS,
 			TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 |
 			TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32);
@@ -792,6 +1071,10 @@
 
 static void trf7970a_switch_rf_off(struct trf7970a *trf)
 {
+	if ((trf->state == TRF7970A_ST_PWR_OFF) ||
+			(trf->state == TRF7970A_ST_RF_OFF))
+		return;
+
 	dev_dbg(trf->dev, "Switching rf off\n");
 
 	trf->chip_status_ctrl &= ~TRF7970A_CHIP_STATUS_RF_ON;
@@ -799,24 +1082,41 @@
 	trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL, trf->chip_status_ctrl);
 
 	trf->aborting = false;
-	trf->state = TRF7970A_ST_OFF;
+	trf->state = TRF7970A_ST_RF_OFF;
 
 	pm_runtime_mark_last_busy(trf->dev);
 	pm_runtime_put_autosuspend(trf->dev);
 }
 
-static void trf7970a_switch_rf_on(struct trf7970a *trf)
+static int trf7970a_switch_rf_on(struct trf7970a *trf)
 {
+	int ret;
+
 	dev_dbg(trf->dev, "Switching rf on\n");
 
 	pm_runtime_get_sync(trf->dev);
 
+	if (trf->state != TRF7970A_ST_RF_OFF) { /* Power on, RF off */
+		dev_err(trf->dev, "%s - Incorrect state: %d\n", __func__,
+				trf->state);
+		return -EINVAL;
+	}
+
+	ret = trf7970a_init(trf);
+	if (ret) {
+		dev_err(trf->dev, "%s - Can't initialize: %d\n", __func__, ret);
+		return ret;
+	}
+
 	trf->state = TRF7970A_ST_IDLE;
+
+	return 0;
 }
 
 static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on)
 {
 	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+	int ret = 0;
 
 	dev_dbg(trf->dev, "Switching RF - state: %d, on: %d\n", trf->state, on);
 
@@ -824,8 +1124,9 @@
 
 	if (on) {
 		switch (trf->state) {
-		case TRF7970A_ST_OFF:
-			trf7970a_switch_rf_on(trf);
+		case TRF7970A_ST_PWR_OFF:
+		case TRF7970A_ST_RF_OFF:
+			ret = trf7970a_switch_rf_on(trf);
 			break;
 		case TRF7970A_ST_IDLE:
 		case TRF7970A_ST_IDLE_RX_BLOCKED:
@@ -834,26 +1135,31 @@
 			dev_err(trf->dev, "%s - Invalid request: %d %d\n",
 					__func__, trf->state, on);
 			trf7970a_switch_rf_off(trf);
+			ret = -EINVAL;
 		}
 	} else {
 		switch (trf->state) {
-		case TRF7970A_ST_OFF:
+		case TRF7970A_ST_PWR_OFF:
+		case TRF7970A_ST_RF_OFF:
 			break;
 		default:
 			dev_err(trf->dev, "%s - Invalid request: %d %d\n",
 					__func__, trf->state, on);
+			ret = -EINVAL;
 			/* FALLTHROUGH */
 		case TRF7970A_ST_IDLE:
 		case TRF7970A_ST_IDLE_RX_BLOCKED:
+		case TRF7970A_ST_WAIT_FOR_RX_DATA:
+		case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT:
 			trf7970a_switch_rf_off(trf);
 		}
 	}
 
 	mutex_unlock(&trf->lock);
-	return 0;
+	return ret;
 }
 
-static int trf7970a_config_rf_tech(struct trf7970a *trf, int tech)
+static int trf7970a_in_config_rf_tech(struct trf7970a *trf, int tech)
 {
 	int ret = 0;
 
@@ -863,22 +1169,27 @@
 	case NFC_DIGITAL_RF_TECH_106A:
 		trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_14443A_106;
 		trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_OOK;
+		trf->guard_time = TRF7970A_GUARD_TIME_NFCA;
 		break;
 	case NFC_DIGITAL_RF_TECH_106B:
 		trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_14443B_106;
 		trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
+		trf->guard_time = TRF7970A_GUARD_TIME_NFCB;
 		break;
 	case NFC_DIGITAL_RF_TECH_212F:
 		trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_FELICA_212;
 		trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
+		trf->guard_time = TRF7970A_GUARD_TIME_NFCF;
 		break;
 	case NFC_DIGITAL_RF_TECH_424F:
 		trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_FELICA_424;
 		trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
+		trf->guard_time = TRF7970A_GUARD_TIME_NFCF;
 		break;
 	case NFC_DIGITAL_RF_TECH_ISO15693:
 		trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648;
 		trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_OOK;
+		trf->guard_time = TRF7970A_GUARD_TIME_15693;
 		break;
 	default:
 		dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech);
@@ -887,12 +1198,54 @@
 
 	trf->technology = tech;
 
+	/* If in initiator mode and not changing the RF tech due to a
+	 * PSL sequence (indicated by 'trf->iso_ctrl == 0xff' from
+	 * trf7970a_init()), clear the NFC Target Detection Level register
+	 * due to erratum.
+	 */
+	if (trf->iso_ctrl == 0xff)
+		ret = trf7970a_write(trf, TRF7970A_NFC_TARGET_LEVEL, 0);
+
 	return ret;
 }
 
-static int trf7970a_config_framing(struct trf7970a *trf, int framing)
+static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field)
+{
+	int ret;
+	u8 rssi;
+
+	ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL,
+			trf->chip_status_ctrl | TRF7970A_CHIP_STATUS_REC_ON);
+	if (ret)
+		return ret;
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_TEST_EXT_RF);
+	if (ret)
+		return ret;
+
+	usleep_range(50, 60);
+
+	ret = trf7970a_read(trf, TRF7970A_RSSI_OSC_STATUS, &rssi);
+	if (ret)
+		return ret;
+
+	ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL,
+			trf->chip_status_ctrl);
+	if (ret)
+		return ret;
+
+	if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK)
+		*is_rf_field = true;
+	else
+		*is_rf_field = false;
+
+	return 0;
+}
+
+static int trf7970a_in_config_framing(struct trf7970a *trf, int framing)
 {
 	u8 iso_ctrl = trf->iso_ctrl_tech;
+	bool is_rf_field = false;
 	int ret;
 
 	dev_dbg(trf->dev, "framing: %d\n", framing);
@@ -911,6 +1264,8 @@
 	case NFC_DIGITAL_FRAMING_NFCF_T3T:
 	case NFC_DIGITAL_FRAMING_ISO15693_INVENTORY:
 	case NFC_DIGITAL_FRAMING_ISO15693_T5T:
+	case NFC_DIGITAL_FRAMING_NFCA_NFC_DEP:
+	case NFC_DIGITAL_FRAMING_NFCF_NFC_DEP:
 		trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
 		iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
 		break;
@@ -925,6 +1280,15 @@
 
 	trf->framing = framing;
 
+	if (!(trf->chip_status_ctrl & TRF7970A_CHIP_STATUS_RF_ON)) {
+		ret = trf7970a_is_rf_field(trf, &is_rf_field);
+		if (ret)
+			return ret;
+
+		if (is_rf_field)
+			return -EBUSY;
+	}
+
 	if (iso_ctrl != trf->iso_ctrl) {
 		ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, iso_ctrl);
 		if (ret)
@@ -947,7 +1311,7 @@
 
 		trf->chip_status_ctrl |= TRF7970A_CHIP_STATUS_RF_ON;
 
-		usleep_range(5000, 6000);
+		usleep_range(trf->guard_time, trf->guard_time + 1000);
 	}
 
 	return 0;
@@ -963,21 +1327,28 @@
 
 	mutex_lock(&trf->lock);
 
-	if (trf->state == TRF7970A_ST_OFF)
-		trf7970a_switch_rf_on(trf);
+	trf->is_initiator = true;
+
+	if ((trf->state == TRF7970A_ST_PWR_OFF) ||
+			(trf->state == TRF7970A_ST_RF_OFF)) {
+		ret = trf7970a_switch_rf_on(trf);
+		if (ret)
+			goto err_unlock;
+	}
 
 	switch (type) {
 	case NFC_DIGITAL_CONFIG_RF_TECH:
-		ret = trf7970a_config_rf_tech(trf, param);
+		ret = trf7970a_in_config_rf_tech(trf, param);
 		break;
 	case NFC_DIGITAL_CONFIG_FRAMING:
-		ret = trf7970a_config_framing(trf, param);
+		ret = trf7970a_in_config_framing(trf, param);
 		break;
 	default:
 		dev_dbg(trf->dev, "Unknown type: %d\n", type);
 		ret = -EINVAL;
 	}
 
+err_unlock:
 	mutex_unlock(&trf->lock);
 	return ret;
 }
@@ -1067,14 +1438,15 @@
 	return 0;
 }
 
-static int trf7970a_in_send_cmd(struct nfc_digital_dev *ddev,
+static int trf7970a_send_cmd(struct nfc_digital_dev *ddev,
 		struct sk_buff *skb, u16 timeout,
 		nfc_digital_cmd_complete_t cb, void *arg)
 {
 	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
-	char *prefix;
+	u8 prefix[5];
 	unsigned int len;
 	int ret;
+	u8 status;
 
 	dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
 			trf->state, timeout, skb->len);
@@ -1099,6 +1471,249 @@
 		goto out_err;
 	}
 
+	if (timeout) {
+		trf->rx_skb = nfc_alloc_recv_skb(TRF7970A_RX_SKB_ALLOC_SIZE,
+				GFP_KERNEL);
+		if (!trf->rx_skb) {
+			dev_dbg(trf->dev, "Can't alloc rx_skb\n");
+			ret = -ENOMEM;
+			goto out_err;
+		}
+	}
+
+	if (trf->state == TRF7970A_ST_IDLE_RX_BLOCKED) {
+		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
+		if (ret)
+			goto out_err;
+
+		trf->state = TRF7970A_ST_IDLE;
+	}
+
+	if (trf->is_initiator) {
+		ret = trf7970a_per_cmd_config(trf, skb);
+		if (ret)
+			goto out_err;
+	}
+
+	trf->ddev = ddev;
+	trf->tx_skb = skb;
+	trf->cb = cb;
+	trf->cb_arg = arg;
+	trf->timeout = timeout;
+	trf->ignore_timeout = false;
+
+	len = skb->len;
+
+	/* TX data must be prefixed with a FIFO reset cmd, a cmd that depends
+	 * on what the current framing is, the address of the TX length byte 1
+	 * register (0x1d), and the 2 byte length of the data to be transmitted.
+	 * That totals 5 bytes.
+	 */
+	prefix[0] = TRF7970A_CMD_BIT_CTRL |
+			TRF7970A_CMD_BIT_OPCODE(TRF7970A_CMD_FIFO_RESET);
+	prefix[1] = TRF7970A_CMD_BIT_CTRL |
+			TRF7970A_CMD_BIT_OPCODE(trf->tx_cmd);
+	prefix[2] = TRF7970A_CMD_BIT_CONTINUOUS | TRF7970A_TX_LENGTH_BYTE1;
+
+	if (trf->framing == NFC_DIGITAL_FRAMING_NFCA_SHORT) {
+		prefix[3] = 0x00;
+		prefix[4] = 0x0f; /* 7 bits */
+	} else {
+		prefix[3] = (len & 0xf00) >> 4;
+		prefix[3] |= ((len & 0xf0) >> 4);
+		prefix[4] = ((len & 0x0f) << 4);
+	}
+
+	len = min_t(int, skb->len, TRF7970A_FIFO_SIZE);
+
+	/* Clear possible spurious interrupt */
+	ret = trf7970a_read_irqstatus(trf, &status);
+	if (ret)
+		goto out_err;
+
+	ret = trf7970a_transmit(trf, skb, len, prefix, sizeof(prefix));
+	if (ret) {
+		kfree_skb(trf->rx_skb);
+		trf->rx_skb = NULL;
+	}
+
+out_err:
+	mutex_unlock(&trf->lock);
+	return ret;
+}
+
+static int trf7970a_tg_config_rf_tech(struct trf7970a *trf, int tech)
+{
+	int ret = 0;
+
+	dev_dbg(trf->dev, "rf technology: %d\n", tech);
+
+	switch (tech) {
+	case NFC_DIGITAL_RF_TECH_106A:
+		trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE |
+			TRF7970A_ISO_CTRL_NFC_CE |
+			TRF7970A_ISO_CTRL_NFC_CE_14443A;
+		trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_OOK;
+		break;
+	case NFC_DIGITAL_RF_TECH_212F:
+		trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE |
+			TRF7970A_ISO_CTRL_NFC_NFCF_212;
+		trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
+		break;
+	case NFC_DIGITAL_RF_TECH_424F:
+		trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE |
+			TRF7970A_ISO_CTRL_NFC_NFCF_424;
+		trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
+		break;
+	default:
+		dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech);
+		return -EINVAL;
+	}
+
+	trf->technology = tech;
+
+	/* Normally we write the ISO_CTRL register in
+	 * trf7970a_tg_config_framing() because the framing can change
+	 * the value written.  However, when sending a PSL RES,
+	 * digital_tg_send_psl_res_complete() doesn't call
+	 * trf7970a_tg_config_framing() so we must write the register
+	 * here.
+	 */
+	if ((trf->framing == NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED) &&
+			(trf->iso_ctrl_tech != trf->iso_ctrl)) {
+		ret = trf7970a_write(trf, TRF7970A_ISO_CTRL,
+				trf->iso_ctrl_tech);
+
+		trf->iso_ctrl = trf->iso_ctrl_tech;
+	}
+
+	return ret;
+}
+
+/* Since this is a target routine, several of the framing calls are
+ * made between receiving the request and sending the response so they
+ * should take effect until after the response is sent.  This is accomplished
+ * by skipping the ISO_CTRL register write here and doing it in the interrupt
+ * handler.
+ */
+static int trf7970a_tg_config_framing(struct trf7970a *trf, int framing)
+{
+	u8 iso_ctrl = trf->iso_ctrl_tech;
+	int ret;
+
+	dev_dbg(trf->dev, "framing: %d\n", framing);
+
+	switch (framing) {
+	case NFC_DIGITAL_FRAMING_NFCA_NFC_DEP:
+		trf->tx_cmd = TRF7970A_CMD_TRANSMIT_NO_CRC;
+		iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
+		break;
+	case NFC_DIGITAL_FRAMING_NFCA_STANDARD:
+	case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
+	case NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE:
+		/* These ones are applied in the interrupt handler */
+		iso_ctrl = trf->iso_ctrl; /* Don't write to ISO_CTRL yet */
+		break;
+	case NFC_DIGITAL_FRAMING_NFCF_NFC_DEP:
+		trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+		iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
+		break;
+	case NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED:
+		trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+		iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
+		break;
+	default:
+		dev_dbg(trf->dev, "Unsupported Framing: %d\n", framing);
+		return -EINVAL;
+	}
+
+	trf->framing = framing;
+
+	if (iso_ctrl != trf->iso_ctrl) {
+		ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, iso_ctrl);
+		if (ret)
+			return ret;
+
+		trf->iso_ctrl = iso_ctrl;
+
+		ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL,
+				trf->modulator_sys_clk_ctrl);
+		if (ret)
+			return ret;
+	}
+
+	if (!(trf->chip_status_ctrl & TRF7970A_CHIP_STATUS_RF_ON)) {
+		ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL,
+				trf->chip_status_ctrl |
+					TRF7970A_CHIP_STATUS_RF_ON);
+		if (ret)
+			return ret;
+
+		trf->chip_status_ctrl |= TRF7970A_CHIP_STATUS_RF_ON;
+	}
+
+	return 0;
+}
+
+static int trf7970a_tg_configure_hw(struct nfc_digital_dev *ddev, int type,
+		int param)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+	int ret;
+
+	dev_dbg(trf->dev, "Configure hw - type: %d, param: %d\n", type, param);
+
+	mutex_lock(&trf->lock);
+
+	trf->is_initiator = false;
+
+	if ((trf->state == TRF7970A_ST_PWR_OFF) ||
+			(trf->state == TRF7970A_ST_RF_OFF)) {
+		ret = trf7970a_switch_rf_on(trf);
+		if (ret)
+			goto err_unlock;
+	}
+
+	switch (type) {
+	case NFC_DIGITAL_CONFIG_RF_TECH:
+		ret = trf7970a_tg_config_rf_tech(trf, param);
+		break;
+	case NFC_DIGITAL_CONFIG_FRAMING:
+		ret = trf7970a_tg_config_framing(trf, param);
+		break;
+	default:
+		dev_dbg(trf->dev, "Unknown type: %d\n", type);
+		ret = -EINVAL;
+	}
+
+err_unlock:
+	mutex_unlock(&trf->lock);
+	return ret;
+}
+
+static int _trf7970a_tg_listen(struct nfc_digital_dev *ddev, u16 timeout,
+		nfc_digital_cmd_complete_t cb, void *arg, bool mode_detect)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+	int ret;
+
+	mutex_lock(&trf->lock);
+
+	if ((trf->state != TRF7970A_ST_IDLE) &&
+			(trf->state != TRF7970A_ST_IDLE_RX_BLOCKED)) {
+		dev_err(trf->dev, "%s - Bogus state: %d\n", __func__,
+				trf->state);
+		ret = -EIO;
+		goto out_err;
+	}
+
+	if (trf->aborting) {
+		dev_dbg(trf->dev, "Abort process complete\n");
+		trf->aborting = false;
+		ret = -ECANCELED;
+		goto out_err;
+	}
+
 	trf->rx_skb = nfc_alloc_recv_skb(TRF7970A_RX_SKB_ALLOC_SIZE,
 			GFP_KERNEL);
 	if (!trf->rx_skb) {
@@ -1107,102 +1722,92 @@
 		goto out_err;
 	}
 
-	if (trf->state == TRF7970A_ST_IDLE_RX_BLOCKED) {
-		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
-		if (ret)
-			goto out_err;
+	ret = trf7970a_write(trf, TRF7970A_RX_SPECIAL_SETTINGS,
+			TRF7970A_RX_SPECIAL_SETTINGS_HBT |
+			TRF7970A_RX_SPECIAL_SETTINGS_M848 |
+			TRF7970A_RX_SPECIAL_SETTINGS_C424 |
+			TRF7970A_RX_SPECIAL_SETTINGS_C212);
+	if (ret)
+		goto out_err;
 
-		trf->state = TRF7970A_ST_IDLE;
-	}
+	ret = trf7970a_write(trf, TRF7970A_REG_IO_CTRL,
+			TRF7970A_REG_IO_CTRL_VRS(0x1));
+	if (ret)
+		goto out_err;
 
-	ret = trf7970a_per_cmd_config(trf, skb);
+	ret = trf7970a_write(trf, TRF7970A_NFC_LOW_FIELD_LEVEL,
+			TRF7970A_NFC_LOW_FIELD_LEVEL_RFDET(0x3));
+	if (ret)
+		goto out_err;
+
+	ret = trf7970a_write(trf, TRF7970A_NFC_TARGET_LEVEL,
+			TRF7970A_NFC_TARGET_LEVEL_RFDET(0x7));
 	if (ret)
 		goto out_err;
 
 	trf->ddev = ddev;
-	trf->tx_skb = skb;
 	trf->cb = cb;
 	trf->cb_arg = arg;
 	trf->timeout = timeout;
 	trf->ignore_timeout = false;
 
-	len = skb->len;
-	prefix = skb_push(skb, TRF7970A_TX_SKB_HEADROOM);
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
+	if (ret)
+		goto out_err;
 
-	/* TX data must be prefixed with a FIFO reset cmd, a cmd that depends
-	 * on what the current framing is, the address of the TX length byte 1
-	 * register (0x1d), and the 2 byte length of the data to be transmitted.
-	 */
-	prefix[0] = TRF7970A_CMD_BIT_CTRL |
-			TRF7970A_CMD_BIT_OPCODE(TRF7970A_CMD_FIFO_RESET);
-	prefix[1] = TRF7970A_CMD_BIT_CTRL |
-			TRF7970A_CMD_BIT_OPCODE(trf->tx_cmd);
-	prefix[2] = TRF7970A_CMD_BIT_CONTINUOUS | TRF7970A_TX_LENGTH_BYTE1;
+	trf->state = mode_detect ? TRF7970A_ST_LISTENING_MD :
+				   TRF7970A_ST_LISTENING;
 
-	if (trf->framing == NFC_DIGITAL_FRAMING_NFCA_SHORT) {
-		prefix[3] = 0x00;
-		prefix[4] = 0x0f; /* 7 bits */
-	} else {
-		prefix[3] = (len & 0xf00) >> 4;
-		prefix[3] |= ((len & 0xf0) >> 4);
-		prefix[4] = ((len & 0x0f) << 4);
-	}
-
-	len = min_t(int, skb->len, TRF7970A_FIFO_SIZE);
-
-	usleep_range(1000, 2000);
-
-	ret = trf7970a_transmit(trf, skb, len);
-	if (ret) {
-		kfree_skb(trf->rx_skb);
-		trf->rx_skb = NULL;
-	}
+	schedule_delayed_work(&trf->timeout_work, msecs_to_jiffies(timeout));
 
 out_err:
 	mutex_unlock(&trf->lock);
 	return ret;
 }
 
-static int trf7970a_tg_configure_hw(struct nfc_digital_dev *ddev,
-		int type, int param)
-{
-	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
-
-	dev_dbg(trf->dev, "Unsupported interface\n");
-
-	return -EINVAL;
-}
-
-static int trf7970a_tg_send_cmd(struct nfc_digital_dev *ddev,
-		struct sk_buff *skb, u16 timeout,
+static int trf7970a_tg_listen(struct nfc_digital_dev *ddev, u16 timeout,
 		nfc_digital_cmd_complete_t cb, void *arg)
 {
 	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
 
-	dev_dbg(trf->dev, "Unsupported interface\n");
+	dev_dbg(trf->dev, "Listen - state: %d, timeout: %d ms\n",
+			trf->state, timeout);
 
-	return -EINVAL;
+	return _trf7970a_tg_listen(ddev, timeout, cb, arg, false);
 }
 
-static int trf7970a_tg_listen(struct nfc_digital_dev *ddev,
+static int trf7970a_tg_listen_md(struct nfc_digital_dev *ddev,
 		u16 timeout, nfc_digital_cmd_complete_t cb, void *arg)
 {
 	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+	int ret;
 
-	dev_dbg(trf->dev, "Unsupported interface\n");
+	dev_dbg(trf->dev, "Listen MD - state: %d, timeout: %d ms\n",
+			trf->state, timeout);
 
-	return -EINVAL;
+	ret = trf7970a_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH,
+			NFC_DIGITAL_RF_TECH_106A);
+	if (ret)
+		return ret;
+
+	ret = trf7970a_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
+			NFC_DIGITAL_FRAMING_NFCA_NFC_DEP);
+	if (ret)
+		return ret;
+
+	return _trf7970a_tg_listen(ddev, timeout, cb, arg, true);
 }
 
-static int trf7970a_tg_listen_mdaa(struct nfc_digital_dev *ddev,
-		struct digital_tg_mdaa_params *mdaa_params,
-		u16 timeout, nfc_digital_cmd_complete_t cb, void *arg)
+static int trf7970a_tg_get_rf_tech(struct nfc_digital_dev *ddev, u8 *rf_tech)
 {
 	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
 
-	dev_dbg(trf->dev, "Unsupported interface\n");
+	dev_dbg(trf->dev, "Get RF Tech - state: %d, rf_tech: %d\n",
+			trf->state, trf->md_rf_tech);
 
-	return -EINVAL;
+	*rf_tech = trf->md_rf_tech;
+
+	return 0;
 }
 
 static void trf7970a_abort_cmd(struct nfc_digital_dev *ddev)
@@ -1220,6 +1825,11 @@
 	case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
 		trf->aborting = true;
 		break;
+	case TRF7970A_ST_LISTENING:
+		trf->ignore_timeout = !cancel_delayed_work(&trf->timeout_work);
+		trf7970a_send_err_upstream(trf, -ECANCELED);
+		dev_dbg(trf->dev, "Abort process complete\n");
+		break;
 	default:
 		break;
 	}
@@ -1229,15 +1839,114 @@
 
 static struct nfc_digital_ops trf7970a_nfc_ops = {
 	.in_configure_hw	= trf7970a_in_configure_hw,
-	.in_send_cmd		= trf7970a_in_send_cmd,
+	.in_send_cmd		= trf7970a_send_cmd,
 	.tg_configure_hw	= trf7970a_tg_configure_hw,
-	.tg_send_cmd		= trf7970a_tg_send_cmd,
+	.tg_send_cmd		= trf7970a_send_cmd,
 	.tg_listen		= trf7970a_tg_listen,
-	.tg_listen_mdaa		= trf7970a_tg_listen_mdaa,
+	.tg_listen_md		= trf7970a_tg_listen_md,
+	.tg_get_rf_tech		= trf7970a_tg_get_rf_tech,
 	.switch_rf		= trf7970a_switch_rf,
 	.abort_cmd		= trf7970a_abort_cmd,
 };
 
+static int trf7970a_power_up(struct trf7970a *trf)
+{
+	int ret;
+
+	dev_dbg(trf->dev, "Powering up - state: %d\n", trf->state);
+
+	if (trf->state != TRF7970A_ST_PWR_OFF)
+		return 0;
+
+	ret = regulator_enable(trf->regulator);
+	if (ret) {
+		dev_err(trf->dev, "%s - Can't enable VIN: %d\n", __func__, ret);
+		return ret;
+	}
+
+	usleep_range(5000, 6000);
+
+	if (!(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) {
+		gpio_set_value(trf->en2_gpio, 1);
+		usleep_range(1000, 2000);
+	}
+
+	gpio_set_value(trf->en_gpio, 1);
+
+	usleep_range(20000, 21000);
+
+	trf->state = TRF7970A_ST_RF_OFF;
+
+	return 0;
+}
+
+static int trf7970a_power_down(struct trf7970a *trf)
+{
+	int ret;
+
+	dev_dbg(trf->dev, "Powering down - state: %d\n", trf->state);
+
+	if (trf->state == TRF7970A_ST_PWR_OFF)
+		return 0;
+
+	if (trf->state != TRF7970A_ST_RF_OFF) {
+		dev_dbg(trf->dev, "Can't power down - not RF_OFF state (%d)\n",
+				trf->state);
+		return -EBUSY;
+	}
+
+	gpio_set_value(trf->en_gpio, 0);
+	gpio_set_value(trf->en2_gpio, 0);
+
+	ret = regulator_disable(trf->regulator);
+	if (ret)
+		dev_err(trf->dev, "%s - Can't disable VIN: %d\n", __func__,
+				ret);
+
+	trf->state = TRF7970A_ST_PWR_OFF;
+
+	return ret;
+}
+
+static int trf7970a_startup(struct trf7970a *trf)
+{
+	int ret;
+
+	ret = trf7970a_power_up(trf);
+	if (ret)
+		return ret;
+
+	pm_runtime_set_active(trf->dev);
+	pm_runtime_enable(trf->dev);
+	pm_runtime_mark_last_busy(trf->dev);
+
+	return 0;
+}
+
+static void trf7970a_shutdown(struct trf7970a *trf)
+{
+	switch (trf->state) {
+	case TRF7970A_ST_WAIT_FOR_TX_FIFO:
+	case TRF7970A_ST_WAIT_FOR_RX_DATA:
+	case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT:
+	case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
+	case TRF7970A_ST_LISTENING:
+		trf7970a_send_err_upstream(trf, -ECANCELED);
+		/* FALLTHROUGH */
+	case TRF7970A_ST_IDLE:
+	case TRF7970A_ST_IDLE_RX_BLOCKED:
+		trf7970a_switch_rf_off(trf);
+		break;
+	default:
+		break;
+	}
+
+	pm_runtime_disable(trf->dev);
+	pm_runtime_set_suspended(trf->dev);
+
+	trf7970a_power_down(trf);
+}
+
 static int trf7970a_get_autosuspend_delay(struct device_node *np)
 {
 	int autosuspend_delay, ret;
@@ -1246,15 +1955,18 @@
 	if (ret)
 		autosuspend_delay = TRF7970A_AUTOSUSPEND_DELAY;
 
-	of_node_put(np);
-
 	return autosuspend_delay;
 }
 
+static int trf7970a_get_vin_voltage_override(struct device_node *np,
+		u32 *vin_uvolts)
+{
+	return of_property_read_u32(np, "vin-voltage-override", vin_uvolts);
+}
+
 static int trf7970a_probe(struct spi_device *spi)
 {
 	struct device_node *np = spi->dev.of_node;
-	const struct spi_device_id *id = spi_get_device_id(spi);
 	struct trf7970a *trf;
 	int uvolts, autosuspend_delay, ret;
 
@@ -1267,14 +1979,22 @@
 	if (!trf)
 		return -ENOMEM;
 
-	trf->state = TRF7970A_ST_OFF;
+	trf->state = TRF7970A_ST_PWR_OFF;
 	trf->dev = &spi->dev;
 	trf->spi = spi;
-	trf->quirks = id->driver_data;
 
 	spi->mode = SPI_MODE_1;
 	spi->bits_per_word = 8;
 
+	ret = spi_setup(spi);
+	if (ret < 0) {
+		dev_err(trf->dev, "Can't set up SPI Communication\n");
+		return ret;
+	}
+
+	if (of_property_read_bool(np, "irq-status-read-quirk"))
+		trf->quirks |= TRF7970A_QUIRK_IRQ_STATUS_READ;
+
 	/* There are two enable pins - both must be present */
 	trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0);
 	if (!gpio_is_valid(trf->en_gpio)) {
@@ -1283,7 +2003,7 @@
 	}
 
 	ret = devm_gpio_request_one(trf->dev, trf->en_gpio,
-			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN");
+			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "trf7970a EN");
 	if (ret) {
 		dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret);
 		return ret;
@@ -1296,12 +2016,15 @@
 	}
 
 	ret = devm_gpio_request_one(trf->dev, trf->en2_gpio,
-			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN2");
+			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "trf7970a EN2");
 	if (ret) {
 		dev_err(trf->dev, "Can't request EN2 GPIO: %d\n", ret);
 		return ret;
 	}
 
+	if (of_property_read_bool(np, "en2-rf-quirk"))
+		trf->quirks |= TRF7970A_QUIRK_EN2_MUST_STAY_LOW;
+
 	ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL,
 			trf7970a_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 			"trf7970a", trf);
@@ -1326,15 +2049,17 @@
 		goto err_destroy_lock;
 	}
 
-	uvolts = regulator_get_voltage(trf->regulator);
+	ret = trf7970a_get_vin_voltage_override(np, &uvolts);
+	if (ret)
+		uvolts = regulator_get_voltage(trf->regulator);
 
 	if (uvolts > 4000000)
 		trf->chip_status_ctrl = TRF7970A_CHIP_STATUS_VRS5_3;
 
 	trf->ddev = nfc_digital_allocate_device(&trf7970a_nfc_ops,
 			TRF7970A_SUPPORTED_PROTOCOLS,
-			NFC_DIGITAL_DRV_CAPS_IN_CRC, TRF7970A_TX_SKB_HEADROOM,
-			0);
+			NFC_DIGITAL_DRV_CAPS_IN_CRC |
+				NFC_DIGITAL_DRV_CAPS_TG_CRC, 0, 0);
 	if (!trf->ddev) {
 		dev_err(trf->dev, "Can't allocate NFC digital device\n");
 		ret = -ENOMEM;
@@ -1349,19 +2074,23 @@
 
 	pm_runtime_set_autosuspend_delay(trf->dev, autosuspend_delay);
 	pm_runtime_use_autosuspend(trf->dev);
-	pm_runtime_enable(trf->dev);
+
+	ret = trf7970a_startup(trf);
+	if (ret)
+		goto err_free_ddev;
 
 	ret = nfc_digital_register_device(trf->ddev);
 	if (ret) {
 		dev_err(trf->dev, "Can't register NFC digital device: %d\n",
 				ret);
-		goto err_free_ddev;
+		goto err_shutdown;
 	}
 
 	return 0;
 
+err_shutdown:
+	trf7970a_shutdown(trf);
 err_free_ddev:
-	pm_runtime_disable(trf->dev);
 	nfc_digital_free_device(trf->ddev);
 err_disable_regulator:
 	regulator_disable(trf->regulator);
@@ -1376,25 +2105,10 @@
 
 	mutex_lock(&trf->lock);
 
-	switch (trf->state) {
-	case TRF7970A_ST_WAIT_FOR_TX_FIFO:
-	case TRF7970A_ST_WAIT_FOR_RX_DATA:
-	case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT:
-	case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
-		trf7970a_send_err_upstream(trf, -ECANCELED);
-		/* FALLTHROUGH */
-	case TRF7970A_ST_IDLE:
-	case TRF7970A_ST_IDLE_RX_BLOCKED:
-		pm_runtime_put_sync(trf->dev);
-		break;
-	default:
-		break;
-	}
+	trf7970a_shutdown(trf);
 
 	mutex_unlock(&trf->lock);
 
-	pm_runtime_disable(trf->dev);
-
 	nfc_digital_unregister_device(trf->ddev);
 	nfc_digital_free_device(trf->ddev);
 
@@ -1405,6 +2119,41 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int trf7970a_suspend(struct device *dev)
+{
+	struct spi_device *spi = container_of(dev, struct spi_device, dev);
+	struct trf7970a *trf = spi_get_drvdata(spi);
+
+	dev_dbg(dev, "Suspend\n");
+
+	mutex_lock(&trf->lock);
+
+	trf7970a_shutdown(trf);
+
+	mutex_unlock(&trf->lock);
+
+	return 0;
+}
+
+static int trf7970a_resume(struct device *dev)
+{
+	struct spi_device *spi = container_of(dev, struct spi_device, dev);
+	struct trf7970a *trf = spi_get_drvdata(spi);
+	int ret;
+
+	dev_dbg(dev, "Resume\n");
+
+	mutex_lock(&trf->lock);
+
+	ret = trf7970a_startup(trf);
+
+	mutex_unlock(&trf->lock);
+
+	return ret;
+}
+#endif
+
 #ifdef CONFIG_PM_RUNTIME
 static int trf7970a_pm_runtime_suspend(struct device *dev)
 {
@@ -1414,18 +2163,11 @@
 
 	dev_dbg(dev, "Runtime suspend\n");
 
-	if (trf->state != TRF7970A_ST_OFF) {
-		dev_dbg(dev, "Can't suspend - not in OFF state (%d)\n",
-				trf->state);
-		return -EBUSY;
-	}
+	mutex_lock(&trf->lock);
 
-	gpio_set_value(trf->en_gpio, 0);
-	gpio_set_value(trf->en2_gpio, 0);
+	ret = trf7970a_power_down(trf);
 
-	ret = regulator_disable(trf->regulator);
-	if (ret)
-		dev_err(dev, "%s - Can't disable VIN: %d\n", __func__, ret);
+	mutex_unlock(&trf->lock);
 
 	return ret;
 }
@@ -1438,39 +2180,22 @@
 
 	dev_dbg(dev, "Runtime resume\n");
 
-	ret = regulator_enable(trf->regulator);
-	if (ret) {
-		dev_err(dev, "%s - Can't enable VIN: %d\n", __func__, ret);
-		return ret;
-	}
+	ret = trf7970a_power_up(trf);
+	if (!ret)
+		pm_runtime_mark_last_busy(dev);
 
-	usleep_range(5000, 6000);
-
-	gpio_set_value(trf->en2_gpio, 1);
-	usleep_range(1000, 2000);
-	gpio_set_value(trf->en_gpio, 1);
-
-	usleep_range(20000, 21000);
-
-	ret = trf7970a_init(trf);
-	if (ret) {
-		dev_err(dev, "%s - Can't initialize: %d\n", __func__, ret);
-		return ret;
-	}
-
-	pm_runtime_mark_last_busy(dev);
-
-	return 0;
+	return ret;
 }
 #endif
 
 static const struct dev_pm_ops trf7970a_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(trf7970a_suspend, trf7970a_resume)
 	SET_RUNTIME_PM_OPS(trf7970a_pm_runtime_suspend,
 			trf7970a_pm_runtime_resume, NULL)
 };
 
 static const struct spi_device_id trf7970a_id_table[] = {
-	{ "trf7970a", TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA },
+	{ "trf7970a", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(spi, trf7970a_id_table);
diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c
index 4a6fe82..80b9bdc 100644
--- a/drivers/ssb/driver_gpio.c
+++ b/drivers/ssb/driver_gpio.c
@@ -475,7 +475,8 @@
 {
 	if (ssb_chipco_available(&bus->chipco) ||
 	    ssb_extif_available(&bus->extif)) {
-		return gpiochip_remove(&bus->gpio);
+		gpiochip_remove(&bus->gpio);
+		return 0;
 	} else {
 		SSB_WARN_ON(1);
 	}
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index bbb9de7..8356303 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -267,7 +267,7 @@
 	u8 core_unit;
 
 	u32 addr;
-	u32 addr1;
+	u32 addr_s[8];
 	u32 wrap;
 
 	void __iomem *io_addr;
@@ -323,6 +323,8 @@
 		struct pci_dev *host_pci;
 		/* Pointer to the SDIO device (only for BCMA_HOSTTYPE_SDIO) */
 		struct sdio_func *host_sdio;
+		/* Pointer to platform device (only for BCMA_HOSTTYPE_SOC) */
+		struct platform_device *host_pdev;
 	};
 
 	struct bcma_chipinfo chipinfo;
@@ -332,10 +334,10 @@
 	struct bcma_device *mapped_core;
 	struct list_head cores;
 	u8 nr_cores;
-	u8 init_done:1;
 	u8 num;
 
 	struct bcma_drv_cc drv_cc;
+	struct bcma_drv_cc_b drv_cc_b;
 	struct bcma_drv_pci drv_pci[2];
 	struct bcma_drv_pcie2 drv_pcie2;
 	struct bcma_drv_mips drv_mips;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 7475a55..b151bb0 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -644,6 +644,12 @@
 #endif
 };
 
+struct bcma_drv_cc_b {
+	struct bcma_device *core;
+	u8 setup_done:1;
+	void __iomem *mii;
+};
+
 /* Register access */
 #define bcma_cc_read32(cc, offset) \
 	bcma_read32((cc)->core, offset)
@@ -699,4 +705,6 @@
 
 extern u32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc);
 
+void bcma_chipco_b_mii_write(struct bcma_drv_cc_b *ccb, u32 offset, u32 value);
+
 #endif /* LINUX_BCMA_DRIVER_CC_H_ */
diff --git a/include/linux/bcma/bcma_regs.h b/include/linux/bcma/bcma_regs.h
index 917dcd7..e64ae7b 100644
--- a/include/linux/bcma/bcma_regs.h
+++ b/include/linux/bcma/bcma_regs.h
@@ -39,6 +39,11 @@
 #define  BCMA_RESET_CTL_RESET		0x0001
 #define BCMA_RESET_ST			0x0804
 
+#define BCMA_NS_ROM_IOST_BOOT_DEV_MASK	0x0003
+#define BCMA_NS_ROM_IOST_BOOT_DEV_NOR	0x0000
+#define BCMA_NS_ROM_IOST_BOOT_DEV_NAND	0x0001
+#define BCMA_NS_ROM_IOST_BOOT_DEV_ROM	0x0002
+
 /* BCMA PCI config space registers. */
 #define BCMA_PCI_PMCSR			0x44
 #define  BCMA_PCI_PE			0x100
diff --git a/include/linux/bcma/bcma_soc.h b/include/linux/bcma/bcma_soc.h
index 4203c55..f24d245 100644
--- a/include/linux/bcma/bcma_soc.h
+++ b/include/linux/bcma/bcma_soc.h
@@ -10,6 +10,7 @@
 };
 
 int __init bcma_host_soc_register(struct bcma_soc *soc);
+int __init bcma_host_soc_init(struct bcma_soc *soc);
 
 int bcma_bus_register(struct bcma_bus *bus);
 
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 63ab387..b1be39c 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -6,6 +6,7 @@
  * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
  * Copyright (c) 2005, Devicescape Software, Inc.
  * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -165,8 +166,12 @@
 
 #define IEEE80211_MAX_MESH_ID_LEN	32
 
+#define IEEE80211_FIRST_TSPEC_TSID	8
 #define IEEE80211_NUM_TIDS		16
 
+/* number of user priorities 802.11 uses */
+#define IEEE80211_NUM_UPS		8
+
 #define IEEE80211_QOS_CTL_LEN		2
 /* 1d tag mask */
 #define IEEE80211_QOS_CTL_TAG1D_MASK		0x0007
@@ -838,6 +843,16 @@
 
 #define WLAN_SA_QUERY_TR_ID_LEN 2
 
+/**
+ * struct ieee80211_tpc_report_ie
+ *
+ * This structure refers to "TPC Report element"
+ */
+struct ieee80211_tpc_report_ie {
+	u8 tx_power;
+	u8 link_margin;
+} __packed;
+
 struct ieee80211_mgmt {
 	__le16 frame_control;
 	__le16 duration;
@@ -973,6 +988,13 @@
 					u8 action_code;
 					u8 operating_mode;
 				} __packed vht_opmode_notif;
+				struct {
+					u8 action_code;
+					u8 dialog_token;
+					u8 tpc_elem_id;
+					u8 tpc_elem_length;
+					struct ieee80211_tpc_report_ie tpc;
+				} __packed tpc_report;
 			} u;
 		} __packed action;
 	} u;
@@ -1806,7 +1828,8 @@
 	WLAN_EID_DMG_TSPEC = 146,
 	WLAN_EID_DMG_AT = 147,
 	WLAN_EID_DMG_CAP = 148,
-	/* 149-150 reserved for Cisco */
+	/* 149 reserved for Cisco */
+	WLAN_EID_CISCO_VENDOR_SPECIFIC = 150,
 	WLAN_EID_DMG_OPERATION = 151,
 	WLAN_EID_DMG_BSS_PARAM_CHANGE = 152,
 	WLAN_EID_DMG_BEAM_REFINEMENT = 153,
@@ -1865,6 +1888,7 @@
 	WLAN_CATEGORY_DLS = 2,
 	WLAN_CATEGORY_BACK = 3,
 	WLAN_CATEGORY_PUBLIC = 4,
+	WLAN_CATEGORY_RADIO_MEASUREMENT = 5,
 	WLAN_CATEGORY_HT = 7,
 	WLAN_CATEGORY_SA_QUERY = 8,
 	WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
@@ -2378,4 +2402,51 @@
 #define TU_TO_JIFFIES(x)	(usecs_to_jiffies((x) * 1024))
 #define TU_TO_EXP_TIME(x)	(jiffies + TU_TO_JIFFIES(x))
 
+/**
+ * ieee80211_action_contains_tpc - checks if the frame contains TPC element
+ * @skb: the skb containing the frame, length will be checked
+ *
+ * This function checks if it's either TPC report action frame or Link
+ * Measurement report action frame as defined in IEEE Std. 802.11-2012 8.5.2.5
+ * and 8.5.7.5 accordingly.
+ */
+static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb)
+{
+	struct ieee80211_mgmt *mgmt = (void *)skb->data;
+
+	if (!ieee80211_is_action(mgmt->frame_control))
+		return false;
+
+	if (skb->len < IEEE80211_MIN_ACTION_SIZE +
+		       sizeof(mgmt->u.action.u.tpc_report))
+		return false;
+
+	/*
+	 * TPC report - check that:
+	 * category = 0 (Spectrum Management) or 5 (Radio Measurement)
+	 * spectrum management action = 3 (TPC/Link Measurement report)
+	 * TPC report EID = 35
+	 * TPC report element length = 2
+	 *
+	 * The spectrum management's tpc_report struct is used here both for
+	 * parsing tpc_report and radio measurement's link measurement report
+	 * frame, since the relevant part is identical in both frames.
+	 */
+	if (mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT &&
+	    mgmt->u.action.category != WLAN_CATEGORY_RADIO_MEASUREMENT)
+		return false;
+
+	/* both spectrum mgmt and link measurement have same action code */
+	if (mgmt->u.action.u.tpc_report.action_code !=
+	    WLAN_ACTION_SPCT_TPC_RPRT)
+		return false;
+
+	if (mgmt->u.action.u.tpc_report.tpc_elem_id != WLAN_EID_TPC_REPORT ||
+	    mgmt->u.action.u.tpc_report.tpc_elem_length !=
+	    sizeof(struct ieee80211_tpc_report_ie))
+		return false;
+
+	return true;
+}
+
 #endif /* LINUX_IEEE80211_H */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 6ed0bb7..1fa99a3 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2245,6 +2245,8 @@
 #define PCI_VENDOR_ID_MORETON		0x15aa
 #define PCI_DEVICE_ID_RASTEL_2PORT	0x2000
 
+#define PCI_VENDOR_ID_VMWARE		0x15ad
+
 #define PCI_VENDOR_ID_ZOLTRIX		0x15b0
 #define PCI_DEVICE_ID_ZOLTRIX_2BD0	0x2bd0
 
@@ -2536,6 +2538,7 @@
 #define PCI_DEVICE_ID_INTEL_EESSC	0x0008
 #define PCI_DEVICE_ID_INTEL_SNB_IMC	0x0100
 #define PCI_DEVICE_ID_INTEL_IVB_IMC	0x0154
+#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC	0x0150
 #define PCI_DEVICE_ID_INTEL_HSW_IMC	0x0c00
 #define PCI_DEVICE_ID_INTEL_PXHD_0	0x0320
 #define PCI_DEVICE_ID_INTEL_PXHD_1	0x0321
@@ -2557,6 +2560,7 @@
 #define PCI_DEVICE_ID_INTEL_MFD_EMMC0	0x0823
 #define PCI_DEVICE_ID_INTEL_MFD_EMMC1	0x0824
 #define PCI_DEVICE_ID_INTEL_MRST_SD2	0x084F
+#define PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB	0x095E
 #define PCI_DEVICE_ID_INTEL_I960	0x0960
 #define PCI_DEVICE_ID_INTEL_I960RM	0x0962
 #define PCI_DEVICE_ID_INTEL_CENTERTON_ILB	0x0c60
@@ -2818,7 +2822,22 @@
 #define PCI_DEVICE_ID_INTEL_UNC_R2PCIE	0x3c43
 #define PCI_DEVICE_ID_INTEL_UNC_R3QPI0	0x3c44
 #define PCI_DEVICE_ID_INTEL_UNC_R3QPI1	0x3c45
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS	0x3c71	/* 15.1 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR0	0x3c72	/* 16.2 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR1	0x3c73	/* 16.3 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR2	0x3c76	/* 16.6 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR3	0x3c77	/* 16.7 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0	0x3ca0	/* 14.0 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA	0x3ca8	/* 15.0 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0	0x3caa	/* 15.2 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1	0x3cab	/* 15.3 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2	0x3cac	/* 15.4 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3	0x3cad	/* 15.5 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO	0x3cb8	/* 17.0 */
 #define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX	0x3ce0
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0	0x3cf4	/* 12.6 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_BR		0x3cf5	/* 13.6 */
+#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1	0x3cf6	/* 12.7 */
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB	0x402f
 #define PCI_DEVICE_ID_INTEL_5100_16	0x65f0
 #define PCI_DEVICE_ID_INTEL_5100_19	0x65f3
@@ -2860,6 +2879,7 @@
 #define PCI_DEVICE_ID_INTEL_82372FB_1	0x7601
 #define PCI_DEVICE_ID_INTEL_SCH_LPC	0x8119
 #define PCI_DEVICE_ID_INTEL_SCH_IDE	0x811a
+#define PCI_DEVICE_ID_INTEL_E6XX_CU	0x8183
 #define PCI_DEVICE_ID_INTEL_ITC_LPC	0x8186
 #define PCI_DEVICE_ID_INTEL_82454GX	0x84c4
 #define PCI_DEVICE_ID_INTEL_82450GX	0x84c5
diff --git a/include/media/davinci/dm644x_ccdc.h b/include/media/davinci/dm644x_ccdc.h
index 852e96c..984fb79 100644
--- a/include/media/davinci/dm644x_ccdc.h
+++ b/include/media/davinci/dm644x_ccdc.h
@@ -114,7 +114,7 @@
 	/* Number of fault pixel */
 	unsigned short fp_num;
 	/* Address of fault pixel table */
-	unsigned int fpc_table_addr;
+	unsigned long fpc_table_addr;
 };
 
 /* Structure for CCDC configuration parameters for raw capture mode passed
diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h
index c9d06d9..398279d 100644
--- a/include/media/omap3isp.h
+++ b/include/media/omap3isp.h
@@ -57,6 +57,8 @@
  *		0 - Active high, 1 - Active low
  * @vs_pol: Vertical synchronization polarity
  *		0 - Active high, 1 - Active low
+ * @fld_pol: Field signal polarity
+ *		0 - Positive, 1 - Negative
  * @data_pol: Data polarity
  *		0 - Normal, 1 - One's complement
  */
@@ -65,6 +67,7 @@
 	unsigned int clk_pol:1;
 	unsigned int hs_pol:1;
 	unsigned int vs_pol:1;
+	unsigned int fld_pol:1;
 	unsigned int data_pol:1;
 };
 
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 80f9518..e7a1514 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -135,6 +135,7 @@
 #define RC_MAP_DM1105_NEC                "rc-dm1105-nec"
 #define RC_MAP_DNTV_LIVE_DVBT_PRO        "rc-dntv-live-dvbt-pro"
 #define RC_MAP_DNTV_LIVE_DVB_T           "rc-dntv-live-dvb-t"
+#define RC_MAP_DVBSKY                    "rc-dvbsky"
 #define RC_MAP_EMPTY                     "rc-empty"
 #define RC_MAP_EM_TERRATEC               "rc-em-terratec"
 #define RC_MAP_ENCORE_ENLTV2             "rc-encore-enltv2"
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 2b1ffed..69a9595 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -360,8 +360,8 @@
  * @buf_struct_size: size of the driver-specific buffer structure;
  *		"0" indicates the driver doesn't want to use a custom buffer
  *		structure type, so sizeof(struct vb2_buffer) will is used
- * @timestamp_flags: Timestamp flags; V4L2_BUF_FLAGS_TIMESTAMP_* and
- *		V4L2_BUF_FLAGS_TSTAMP_SRC_*
+ * @timestamp_flags: Timestamp flags; V4L2_BUF_FLAG_TIMESTAMP_* and
+ *		V4L2_BUF_FLAG_TSTAMP_SRC_*
  * @gfp_flags:	additional gfp flags used when allocating the buffers.
  *		Typically this is 0, but it may be e.g. GFP_DMA or __GFP_DMA32
  *		to force the buffer allocation to a specific memory zone.
@@ -370,6 +370,7 @@
  *		cannot be started unless at least this number of buffers
  *		have been queued into the driver.
  *
+ * @mmap_lock:	private mutex used when buffers are allocated/freed/mmapped
  * @memory:	current memory type used
  * @bufs:	videobuf buffer structures
  * @num_buffers: number of allocated/used buffers
@@ -406,6 +407,7 @@
 	u32				min_buffers_needed;
 
 /* private: internal use only */
+	struct mutex			mmap_lock;
 	enum v4l2_memory		memory;
 	struct vb2_buffer		*bufs[VIDEO_MAX_FRAME];
 	unsigned int			num_buffers;
@@ -598,6 +600,15 @@
 	return 0;
 }
 
+/**
+ * vb2_start_streaming_called() - return streaming status of driver
+ * @q:		videobuf queue
+ */
+static inline bool vb2_start_streaming_called(struct vb2_queue *q)
+{
+	return q->start_streaming_called;
+}
+
 /*
  * The following functions are not part of the vb2 core API, but are simple
  * helper functions that you can use in your struct v4l2_file_operations,
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 373000d..58695ff 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -120,9 +120,9 @@
 #define BT_RCVMTU		13
 
 __printf(1, 2)
-int bt_info(const char *fmt, ...);
+void bt_info(const char *fmt, ...);
 __printf(1, 2)
-int bt_err(const char *fmt, ...);
+void bt_err(const char *fmt, ...);
 
 #define BT_INFO(fmt, ...)	bt_info(fmt "\n", ##__VA_ARGS__)
 #define BT_ERR(fmt, ...)	bt_err(fmt "\n", ##__VA_ARGS__)
@@ -284,6 +284,7 @@
 struct bt_skb_cb {
 	__u8 pkt_type;
 	__u8 incoming;
+	__u16 opcode;
 	__u16 expect;
 	__u8 force_active;
 	struct l2cap_chan *chan;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 3f8547f..6e8f249 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -385,6 +385,7 @@
 #define HCI_ERROR_AUTH_FAILURE		0x05
 #define HCI_ERROR_MEMORY_EXCEEDED	0x07
 #define HCI_ERROR_CONNECTION_TIMEOUT	0x08
+#define HCI_ERROR_REJ_LIMITED_RESOURCES	0x0d
 #define HCI_ERROR_REJ_BAD_ADDR		0x0f
 #define HCI_ERROR_REMOTE_USER_TERM	0x13
 #define HCI_ERROR_REMOTE_LOW_RESOURCES	0x14
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6f884e6..37ff1ae 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -302,7 +302,7 @@
 	__u32			req_status;
 	__u32			req_result;
 
-	struct crypto_blkcipher	*tfm_aes;
+	void			*smp_data;
 
 	struct discovery_state	discovery;
 	struct hci_conn_hash	conn_hash;
@@ -539,7 +539,6 @@
 	HCI_CONN_RSWITCH_PEND,
 	HCI_CONN_MODE_CHANGE_PEND,
 	HCI_CONN_SCO_SETUP_PEND,
-	HCI_CONN_LE_SMP_PEND,
 	HCI_CONN_MGMT_CONNECTED,
 	HCI_CONN_SSP_ENABLED,
 	HCI_CONN_SC_ENABLED,
@@ -553,6 +552,7 @@
 	HCI_CONN_FIPS,
 	HCI_CONN_STK_ENCRYPT,
 	HCI_CONN_AUTH_INITIATOR,
+	HCI_CONN_DROP,
 };
 
 static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
@@ -702,7 +702,7 @@
 	return NULL;
 }
 
-void hci_disconnect(struct hci_conn *conn, __u8 reason);
+int hci_disconnect(struct hci_conn *conn, __u8 reason);
 bool hci_setup_sync(struct hci_conn *conn, __u16 handle);
 void hci_sco_setup(struct hci_conn *conn, __u8 status);
 
@@ -756,9 +756,10 @@
  * _get()/_drop() in it, but require the caller to have a valid ref (FIXME).
  */
 
-static inline void hci_conn_get(struct hci_conn *conn)
+static inline struct hci_conn *hci_conn_get(struct hci_conn *conn)
 {
 	get_device(&conn->dev);
+	return conn;
 }
 
 static inline void hci_conn_put(struct hci_conn *conn)
@@ -790,7 +791,7 @@
 				if (!conn->out)
 					timeo *= 2;
 			} else {
-				timeo = msecs_to_jiffies(10);
+				timeo = 0;
 			}
 			break;
 
@@ -799,7 +800,7 @@
 			break;
 
 		default:
-			timeo = msecs_to_jiffies(10);
+			timeo = 0;
 			break;
 		}
 
@@ -925,7 +926,6 @@
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
 int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
-int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
 int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
 
 void hci_init_sysfs(struct hci_dev *hdev);
@@ -970,6 +970,9 @@
 #define lmp_host_le_capable(dev)   (!!((dev)->features[1][0] & LMP_HOST_LE))
 #define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR))
 
+#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
+				!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
+
 /* ----- HCI protocols ----- */
 #define HCI_PROTO_DEFER             0x01
 
@@ -1258,6 +1261,8 @@
 void hci_req_add_le_scan_disable(struct hci_request *req);
 void hci_req_add_le_passive_scan(struct hci_request *req);
 
+void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req);
+
 struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
 			       const void *param, u32 timeout);
 struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
@@ -1336,8 +1341,7 @@
 int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
 			     u8 link_type, u8 addr_type, u32 passkey,
 			     u8 entered);
-void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-		      u8 addr_type, u8 status);
+void mgmt_auth_failed(struct hci_conn *conn, u8 status);
 void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
 void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
 void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
@@ -1353,6 +1357,7 @@
 void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 		      u8 addr_type, s8 rssi, u8 *name, u8 name_len);
 void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
+bool mgmt_powering_down(struct hci_dev *hdev);
 void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent);
 void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk);
 void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 8df15ad..ead99f0 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -633,10 +633,11 @@
 	struct sk_buff_head	pending_rx;
 	struct work_struct	pending_rx_work;
 
+	struct work_struct	id_addr_update_work;
+
 	__u8			disc_reason;
 
-	struct delayed_work	security_timer;
-	struct smp_chan		*smp_chan;
+	struct l2cap_chan	*smp;
 
 	struct list_head	chan_l;
 	struct mutex		chan_lock;
@@ -708,6 +709,8 @@
 	FLAG_EFS_ENABLE,
 	FLAG_DEFER_SETUP,
 	FLAG_LE_CONN_REQ_SENT,
+	FLAG_PENDING_SECURITY,
+	FLAG_HOLD_HCI_CONN,
 };
 
 enum {
@@ -837,18 +840,43 @@
 	return NULL;
 }
 
+static inline int l2cap_chan_no_recv(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+	return -ENOSYS;
+}
+
+static inline struct sk_buff *l2cap_chan_no_alloc_skb(struct l2cap_chan *chan,
+						      unsigned long hdr_len,
+						      unsigned long len, int nb)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
 static inline void l2cap_chan_no_teardown(struct l2cap_chan *chan, int err)
 {
 }
 
+static inline void l2cap_chan_no_close(struct l2cap_chan *chan)
+{
+}
+
 static inline void l2cap_chan_no_ready(struct l2cap_chan *chan)
 {
 }
 
+static inline void l2cap_chan_no_state_change(struct l2cap_chan *chan,
+					      int state, int err)
+{
+}
+
 static inline void l2cap_chan_no_defer(struct l2cap_chan *chan)
 {
 }
 
+static inline void l2cap_chan_no_suspend(struct l2cap_chan *chan)
+{
+}
+
 static inline void l2cap_chan_no_resume(struct l2cap_chan *chan)
 {
 }
@@ -911,14 +939,13 @@
 void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void l2cap_chan_del(struct l2cap_chan *chan, int err);
-void l2cap_conn_update_id_addr(struct hci_conn *hcon);
 void l2cap_send_conn_req(struct l2cap_chan *chan);
 void l2cap_move_start(struct l2cap_chan *chan);
 void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
 		       u8 status);
 void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);
 
-void l2cap_conn_get(struct l2cap_conn *conn);
+struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn);
 void l2cap_conn_put(struct l2cap_conn *conn);
 
 int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user);
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ea128ff..87362c1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4,6 +4,7 @@
  * 802.11 device and configuration interface
  *
  * Copyright 2006-2010	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -663,6 +664,7 @@
  * @crypto: crypto settings
  * @privacy: the BSS uses privacy
  * @auth_type: Authentication type (algorithm)
+ * @smps_mode: SMPS mode
  * @inactivity_timeout: time in seconds to determine station's inactivity.
  * @p2p_ctwindow: P2P CT Window
  * @p2p_opp_ps: P2P opportunistic PS
@@ -681,6 +683,7 @@
 	struct cfg80211_crypto_settings crypto;
 	bool privacy;
 	enum nl80211_auth_type auth_type;
+	enum nl80211_smps_mode smps_mode;
 	int inactivity_timeout;
 	u8 p2p_ctwindow;
 	bool p2p_opp_ps;
@@ -1503,12 +1506,14 @@
  * @tsf: TSF contained in the frame that carried these IEs
  * @rcu_head: internal use, for freeing
  * @len: length of the IEs
+ * @from_beacon: these IEs are known to come from a beacon
  * @data: IE data
  */
 struct cfg80211_bss_ies {
 	u64 tsf;
 	struct rcu_head rcu_head;
 	int len;
+	bool from_beacon;
 	u8 data[];
 };
 
@@ -1605,10 +1610,12 @@
  *
  * @ASSOC_REQ_DISABLE_HT:  Disable HT (802.11n)
  * @ASSOC_REQ_DISABLE_VHT:  Disable VHT
+ * @ASSOC_REQ_USE_RRM: Declare RRM capability in this association
  */
 enum cfg80211_assoc_req_flags {
 	ASSOC_REQ_DISABLE_HT		= BIT(0),
 	ASSOC_REQ_DISABLE_VHT		= BIT(1),
+	ASSOC_REQ_USE_RRM		= BIT(2),
 };
 
 /**
@@ -1800,6 +1807,7 @@
  * @WIPHY_PARAM_FRAG_THRESHOLD: wiphy->frag_threshold has changed
  * @WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed
  * @WIPHY_PARAM_COVERAGE_CLASS: coverage class changed
+ * @WIPHY_PARAM_DYN_ACK: dynack has been enabled
  */
 enum wiphy_params_flags {
 	WIPHY_PARAM_RETRY_SHORT		= 1 << 0,
@@ -1807,6 +1815,7 @@
 	WIPHY_PARAM_FRAG_THRESHOLD	= 1 << 2,
 	WIPHY_PARAM_RTS_THRESHOLD	= 1 << 3,
 	WIPHY_PARAM_COVERAGE_CLASS	= 1 << 4,
+	WIPHY_PARAM_DYN_ACK		= 1 << 5,
 };
 
 /*
@@ -1973,14 +1982,12 @@
 
 /**
  * struct cfg80211_gtk_rekey_data - rekey data
- * @kek: key encryption key
- * @kck: key confirmation key
- * @replay_ctr: replay counter
+ * @kek: key encryption key (NL80211_KEK_LEN bytes)
+ * @kck: key confirmation key (NL80211_KCK_LEN bytes)
+ * @replay_ctr: replay counter (NL80211_REPLAY_CTR_LEN bytes)
  */
 struct cfg80211_gtk_rekey_data {
-	u8 kek[NL80211_KEK_LEN];
-	u8 kck[NL80211_KCK_LEN];
-	u8 replay_ctr[NL80211_REPLAY_CTR_LEN];
+	const u8 *kek, *kck, *replay_ctr;
 };
 
 /**
@@ -2313,6 +2320,17 @@
  * @set_ap_chanwidth: Set the AP (including P2P GO) mode channel width for the
  *	given interface This is used e.g. for dynamic HT 20/40 MHz channel width
  *	changes during the lifetime of the BSS.
+ *
+ * @add_tx_ts: validate (if admitted_time is 0) or add a TX TS to the device
+ *	with the given parameters; action frame exchange has been handled by
+ *	userspace so this just has to modify the TX path to take the TS into
+ *	account.
+ *	If the admitted time is 0 just validate the parameters to make sure
+ *	the session can be created at all; it is valid to just always return
+ *	success for that but that may result in inefficient behaviour (handshake
+ *	with the peer followed by immediate teardown when the addition is later
+ *	rejected)
+ * @del_tx_ts: remove an existing TX TS
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2553,6 +2571,12 @@
 
 	int	(*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev,
 				    struct cfg80211_chan_def *chandef);
+
+	int	(*add_tx_ts)(struct wiphy *wiphy, struct net_device *dev,
+			     u8 tsid, const u8 *peer, u8 user_prio,
+			     u16 admitted_time);
+	int	(*del_tx_ts)(struct wiphy *wiphy, struct net_device *dev,
+			     u8 tsid, const u8 *peer);
 };
 
 /*
@@ -2599,9 +2623,13 @@
  * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.
  * @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in
  *	beaconing mode (AP, IBSS, Mesh, ...).
+ * @WIPHY_FLAG_SUPPORTS_WMM_ADMISSION: the device supports setting up WMM
+ *	TSPEC sessions (TID aka TSID 0-7) with the NL80211_CMD_ADD_TX_TS
+ *	command. Standard IEEE 802.11 TSPEC setup is not yet supported, it
+ *	needs to be able to handle Block-Ack agreements and other things.
  */
 enum wiphy_flags {
-	/* use hole at 0 */
+	WIPHY_FLAG_SUPPORTS_WMM_ADMISSION	= BIT(0),
 	/* use hole at 1 */
 	/* use hole at 2 */
 	WIPHY_FLAG_NETNS_OK			= BIT(3),
@@ -3768,11 +3796,25 @@
 }
 
 /**
- * cfg80211_inform_bss - inform cfg80211 of a new BSS
+ * enum cfg80211_bss_frame_type - frame type that the BSS data came from
+ * @CFG80211_BSS_FTYPE_UNKNOWN: driver doesn't know whether the data is
+ *	from a beacon or probe response
+ * @CFG80211_BSS_FTYPE_BEACON: data comes from a beacon
+ * @CFG80211_BSS_FTYPE_PRESP: data comes from a probe response
+ */
+enum cfg80211_bss_frame_type {
+	CFG80211_BSS_FTYPE_UNKNOWN,
+	CFG80211_BSS_FTYPE_BEACON,
+	CFG80211_BSS_FTYPE_PRESP,
+};
+
+/**
+ * cfg80211_inform_bss_width - inform cfg80211 of a new BSS
  *
  * @wiphy: the wiphy reporting the BSS
  * @rx_channel: The channel the frame was received on
  * @scan_width: width of the control channel
+ * @ftype: frame type (if known)
  * @bssid: the BSSID of the BSS
  * @tsf: the TSF sent by the peer in the beacon/probe response (or 0)
  * @capability: the capability field sent by the peer
@@ -3792,6 +3834,7 @@
 cfg80211_inform_bss_width(struct wiphy *wiphy,
 			  struct ieee80211_channel *rx_channel,
 			  enum nl80211_bss_scan_width scan_width,
+			  enum cfg80211_bss_frame_type ftype,
 			  const u8 *bssid, u64 tsf, u16 capability,
 			  u16 beacon_interval, const u8 *ie, size_t ielen,
 			  s32 signal, gfp_t gfp);
@@ -3799,12 +3842,13 @@
 static inline struct cfg80211_bss * __must_check
 cfg80211_inform_bss(struct wiphy *wiphy,
 		    struct ieee80211_channel *rx_channel,
+		    enum cfg80211_bss_frame_type ftype,
 		    const u8 *bssid, u64 tsf, u16 capability,
 		    u16 beacon_interval, const u8 *ie, size_t ielen,
 		    s32 signal, gfp_t gfp)
 {
 	return cfg80211_inform_bss_width(wiphy, rx_channel,
-					 NL80211_BSS_CHAN_WIDTH_20,
+					 NL80211_BSS_CHAN_WIDTH_20, ftype,
 					 bssid, tsf, capability,
 					 beacon_interval, ie, ielen, signal,
 					 gfp);
@@ -3905,6 +3949,7 @@
  *	moves to cfg80211 in this call
  * @buf: authentication frame (header + body)
  * @len: length of the frame data
+ * @uapsd_queues: bitmap of ACs configured to uapsd. -1 if n/a.
  *
  * After being asked to associate via cfg80211_ops::assoc() the driver must
  * call either this function or cfg80211_auth_timeout().
@@ -3913,7 +3958,8 @@
  */
 void cfg80211_rx_assoc_resp(struct net_device *dev,
 			    struct cfg80211_bss *bss,
-			    const u8 *buf, size_t len);
+			    const u8 *buf, size_t len,
+			    int uapsd_queues);
 
 /**
  * cfg80211_assoc_timeout - notification of timed out association
@@ -4415,7 +4461,6 @@
  * @buf: Management frame (header + body)
  * @len: length of the frame data
  * @flags: flags, as defined in enum nl80211_rxmgmt_flags
- * @gfp: context flags
  *
  * This function is called whenever an Action frame is received for a station
  * mode interface, but is not processed in kernel.
@@ -4426,7 +4471,7 @@
  * driver is responsible for rejecting the frame.
  */
 bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm,
-		      const u8 *buf, size_t len, u32 flags, gfp_t gfp);
+		      const u8 *buf, size_t len, u32 flags);
 
 /**
  * cfg80211_mgmt_tx_status - notification of TX status for management frame
diff --git a/include/net/lib80211.h b/include/net/lib80211.h
index be95b92..aab0f42 100644
--- a/include/net/lib80211.h
+++ b/include/net/lib80211.h
@@ -32,11 +32,6 @@
 #include <linux/timer.h>
 #include <linux/seq_file.h>
 
-/* print_ssid() is intended to be used in debug (and possibly error)
- * messages. It should never be used for passing ssid to user space. */
-const char *print_ssid(char *buf, const char *ssid, u8 ssid_len);
-#define DECLARE_SSID_BUF(var) char var[IEEE80211_MAX_SSID_LEN * 4 + 1] __maybe_unused
-
 #define NUM_WEP_KEYS	4
 
 enum {
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index c413611..c5ba507 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4,6 +4,7 @@
  * Copyright 2002-2005, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007-2010	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1226,7 +1227,8 @@
  *
  * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the
  *	driver to indicate that it requires IV generation for this
- *	particular key.
+ *	particular key. Setting this flag does not necessarily mean that SKBs
+ *	will have sufficient tailroom for ICV or MIC.
  * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by
  *	the driver for a TKIP key if it requires Michael MIC
  *	generation in software.
@@ -1238,7 +1240,9 @@
  * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver
  *	if space should be prepared for the IV, but the IV
  *	itself should not be generated. Do not set together with
- *	@IEEE80211_KEY_FLAG_GENERATE_IV on the same key.
+ *	@IEEE80211_KEY_FLAG_GENERATE_IV on the same key. Setting this flag does
+ *	not necessarily mean that SKBs will have sufficient tailroom for ICV or
+ *	MIC.
  * @IEEE80211_KEY_FLAG_RX_MGMT: This key will be used to decrypt received
  *	management frames. The flag can help drivers that have a hardware
  *	crypto implementation that doesn't deal with management frames
@@ -1405,7 +1409,7 @@
  * @supp_rates: Bitmap of supported rates (per band)
  * @ht_cap: HT capabilities of this STA; restricted to our own capabilities
  * @vht_cap: VHT capabilities of this STA; restricted to our own capabilities
- * @wme: indicates whether the STA supports WME. Only valid during AP-mode.
+ * @wme: indicates whether the STA supports QoS/WME.
  * @drv_priv: data area for driver use, will always be aligned to
  *	sizeof(void *), size is determined in hw information.
  * @uapsd_queues: bitmap of queues configured for uapsd. Only valid
@@ -1533,16 +1537,6 @@
  * @IEEE80211_HW_MFP_CAPABLE:
  *	Hardware supports management frame protection (MFP, IEEE 802.11w).
  *
- * @IEEE80211_HW_SUPPORTS_STATIC_SMPS:
- *	Hardware supports static spatial multiplexing powersave,
- *	ie. can turn off all but one chain even on HT connections
- *	that should be using more chains.
- *
- * @IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS:
- *	Hardware supports dynamic spatial multiplexing powersave,
- *	ie. can turn off all but one chain and then wake the rest
- *	up as required after, for example, rts/cts handshake.
- *
  * @IEEE80211_HW_SUPPORTS_UAPSD:
  *	Hardware supports Unscheduled Automatic Power Save Delivery
  *	(U-APSD) in managed mode. The mode is configured with
@@ -1606,6 +1600,9 @@
  *	is not enabled the default action is to disconnect when getting the
  *	CSA frame.
  *
+ * @IEEE80211_HW_SUPPORTS_CLONED_SKBS: The driver will never modify the payload
+ *	or tailroom of TX skbs without copying them first.
+ *
  * @IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS: The HW supports scanning on all bands
  *	in one command, mac80211 doesn't have to run separate scans per band.
  */
@@ -1625,8 +1622,7 @@
 	IEEE80211_HW_SUPPORTS_DYNAMIC_PS		= 1<<12,
 	IEEE80211_HW_MFP_CAPABLE			= 1<<13,
 	IEEE80211_HW_WANT_MONITOR_VIF			= 1<<14,
-	IEEE80211_HW_SUPPORTS_STATIC_SMPS		= 1<<15,
-	IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS		= 1<<16,
+	/* free slots */
 	IEEE80211_HW_SUPPORTS_UAPSD			= 1<<17,
 	IEEE80211_HW_REPORTS_TX_ACK_STATUS		= 1<<18,
 	IEEE80211_HW_CONNECTION_MONITOR			= 1<<19,
@@ -1639,7 +1635,7 @@
 	IEEE80211_HW_TIMING_BEACON_ONLY			= 1<<26,
 	IEEE80211_HW_SUPPORTS_HT_CCK_RATES		= 1<<27,
 	IEEE80211_HW_CHANCTX_STA_CSA			= 1<<28,
-	/* bit 29 unused */
+	IEEE80211_HW_SUPPORTS_CLONED_SKBS		= 1<<29,
 	IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS		= 1<<30,
 };
 
@@ -2666,7 +2662,9 @@
  *
  * @set_coverage_class: Set slot time for given coverage class as specified
  *	in IEEE 802.11-2007 section 17.3.8.6 and modify ACK timeout
- *	accordingly. This callback is not required and may sleep.
+ *	accordingly; coverage class equals to -1 to enable ACK timeout
+ *	estimation algorithm (dynack). To disable dynack set valid value for
+ *	coverage class. This callback is not required and may sleep.
  *
  * @testmode_cmd: Implement a cfg80211 test mode command. The passed @vif may
  *	be %NULL. The callback can sleep.
@@ -2950,7 +2948,7 @@
 	int (*get_survey)(struct ieee80211_hw *hw, int idx,
 		struct survey_info *survey);
 	void (*rfkill_poll)(struct ieee80211_hw *hw);
-	void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class);
+	void (*set_coverage_class)(struct ieee80211_hw *hw, s16 coverage_class);
 #ifdef CPTCFG_NL80211_TESTMODE
 	int (*testmode_cmd)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			    void *data, int len);
diff --git a/include/net/nfc/nci.h b/include/net/nfc/nci.h
index fbfa4e4..9eca9ae 100644
--- a/include/net/nfc/nci.h
+++ b/include/net/nfc/nci.h
@@ -2,6 +2,7 @@
  *  The NFC Controller Interface is the communication protocol between an
  *  NFC Controller (NFCC) and a Device Host (DH).
  *
+ *  Copyright (C) 2014 Marvell International Ltd.
  *  Copyright (C) 2011 Texas Instruments, Inc.
  *
  *  Written by Ilan Elias <ilane@ti.com>
@@ -65,19 +66,18 @@
 #define NCI_NFC_F_PASSIVE_POLL_MODE				0x02
 #define NCI_NFC_A_ACTIVE_POLL_MODE				0x03
 #define NCI_NFC_F_ACTIVE_POLL_MODE				0x05
-#define NCI_NFC_15693_PASSIVE_POLL_MODE				0x06
+#define NCI_NFC_V_PASSIVE_POLL_MODE				0x06
 #define NCI_NFC_A_PASSIVE_LISTEN_MODE				0x80
 #define NCI_NFC_B_PASSIVE_LISTEN_MODE				0x81
 #define NCI_NFC_F_PASSIVE_LISTEN_MODE				0x82
 #define NCI_NFC_A_ACTIVE_LISTEN_MODE				0x83
 #define NCI_NFC_F_ACTIVE_LISTEN_MODE				0x85
-#define NCI_NFC_15693_PASSIVE_LISTEN_MODE			0x86
 
 /* NCI RF Technologies */
 #define NCI_NFC_RF_TECHNOLOGY_A					0x00
 #define NCI_NFC_RF_TECHNOLOGY_B					0x01
 #define NCI_NFC_RF_TECHNOLOGY_F					0x02
-#define NCI_NFC_RF_TECHNOLOGY_15693				0x03
+#define NCI_NFC_RF_TECHNOLOGY_V					0x03
 
 /* NCI Bit Rates */
 #define NCI_NFC_BIT_RATE_106					0x00
@@ -87,6 +87,7 @@
 #define NCI_NFC_BIT_RATE_1695					0x04
 #define NCI_NFC_BIT_RATE_3390					0x05
 #define NCI_NFC_BIT_RATE_6780					0x06
+#define NCI_NFC_BIT_RATE_26					0x20
 
 /* NCI RF Protocols */
 #define NCI_RF_PROTOCOL_UNKNOWN					0x00
@@ -95,6 +96,7 @@
 #define NCI_RF_PROTOCOL_T3T					0x03
 #define NCI_RF_PROTOCOL_ISO_DEP					0x04
 #define NCI_RF_PROTOCOL_NFC_DEP					0x05
+#define NCI_RF_PROTOCOL_T5T					0x06
 
 /* NCI RF Interfaces */
 #define NCI_RF_INTERFACE_NFCEE_DIRECT				0x00
@@ -328,6 +330,12 @@
 	__u8	sensf_res[18];	/* 16 or 18 Bytes */
 } __packed;
 
+struct rf_tech_specific_params_nfcv_poll {
+	__u8	res_flags;
+	__u8	dsfid;
+	__u8	uid[8];	/* 8 Bytes */
+} __packed;
+
 struct nci_rf_discover_ntf {
 	__u8	rf_discovery_id;
 	__u8	rf_protocol;
@@ -338,6 +346,7 @@
 		struct rf_tech_specific_params_nfca_poll nfca_poll;
 		struct rf_tech_specific_params_nfcb_poll nfcb_poll;
 		struct rf_tech_specific_params_nfcf_poll nfcf_poll;
+		struct rf_tech_specific_params_nfcv_poll nfcv_poll;
 	} rf_tech_specific_params;
 
 	__u8	ntf_type;
@@ -372,6 +381,7 @@
 		struct rf_tech_specific_params_nfca_poll nfca_poll;
 		struct rf_tech_specific_params_nfcb_poll nfcb_poll;
 		struct rf_tech_specific_params_nfcf_poll nfcf_poll;
+		struct rf_tech_specific_params_nfcv_poll nfcv_poll;
 	} rf_tech_specific_params;
 
 	__u8	data_exch_rf_tech_and_mode;
diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h
index 1f9a0f5..75d10e6 100644
--- a/include/net/nfc/nci_core.h
+++ b/include/net/nfc/nci_core.h
@@ -64,10 +64,11 @@
 struct nci_dev;
 
 struct nci_ops {
-	int (*open)(struct nci_dev *ndev);
-	int (*close)(struct nci_dev *ndev);
-	int (*send)(struct nci_dev *ndev, struct sk_buff *skb);
-	int (*setup)(struct nci_dev *ndev);
+	int   (*open)(struct nci_dev *ndev);
+	int   (*close)(struct nci_dev *ndev);
+	int   (*send)(struct nci_dev *ndev, struct sk_buff *skb);
+	int   (*setup)(struct nci_dev *ndev);
+	__u32 (*get_rfprotocol)(struct nci_dev *ndev, __u8 rf_protocol);
 };
 
 #define NCI_MAX_SUPPORTED_RF_INTERFACES		4
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f1db15b..4b28dc0 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -722,6 +722,22 @@
  *	QoS mapping is relevant for IP packets, it is only valid during an
  *	association. This is cleared on disassociation and AP restart.
  *
+ * @NL80211_CMD_ADD_TX_TS: Ask the kernel to add a traffic stream for the given
+ *	%NL80211_ATTR_TSID and %NL80211_ATTR_MAC with %NL80211_ATTR_USER_PRIO
+ *	and %NL80211_ATTR_ADMITTED_TIME parameters.
+ *	Note that the action frame handshake with the AP shall be handled by
+ *	userspace via the normal management RX/TX framework, this only sets
+ *	up the TX TS in the driver/device.
+ *	If the admitted time attribute is not added then the request just checks
+ *	if a subsequent setup could be successful, the intent is to use this to
+ *	avoid setting up a session with the AP when local restrictions would
+ *	make that impossible. However, the subsequent "real" setup may still
+ *	fail even if the check was successful.
+ * @NL80211_CMD_DEL_TX_TS: Remove an existing TS with the %NL80211_ATTR_TSID
+ *	and %NL80211_ATTR_MAC parameters. It isn't necessary to call this
+ *	before removing a station entry entirely, or before disassociating
+ *	or similar, cleanup will happen in the driver/device in this case.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -893,6 +909,9 @@
 
 	NL80211_CMD_SET_QOS_MAP,
 
+	NL80211_CMD_ADD_TX_TS,
+	NL80211_CMD_DEL_TX_TS,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1594,6 +1613,31 @@
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  *	the TDLS link initiator.
  *
+ * @NL80211_ATTR_USE_RRM: flag for indicating whether the current connection
+ *	shall support Radio Resource Measurements (11k). This attribute can be
+ *	used with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests.
+ *	User space applications are expected to use this flag only if the
+ *	underlying device supports these minimal RRM features:
+ *		%NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES,
+ *		%NL80211_FEATURE_QUIET,
+ *	If this flag is used, driver must add the Power Capabilities IE to the
+ *	association request. In addition, it must also set the RRM capability
+ *	flag in the association request's Capability Info field.
+ *
+ * @NL80211_ATTR_WIPHY_DYN_ACK: flag attribute used to enable ACK timeout
+ *	estimation algorithm (dynack). In order to activate dynack
+ *	%NL80211_FEATURE_ACKTO_ESTIMATION feature flag must be set by lower
+ *	drivers to indicate dynack capability. Dynack is automatically disabled
+ *	setting valid value for coverage class.
+ *
+ * @NL80211_ATTR_TSID: a TSID value (u8 attribute)
+ * @NL80211_ATTR_USER_PRIO: user priority value (u8 attribute)
+ * @NL80211_ATTR_ADMITTED_TIME: admitted time in units of 32 microseconds
+ *	(per second) (u16 attribute)
+ *
+ * @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see
+ *	&enum nl80211_smps_mode.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1936,6 +1980,16 @@
 
 	NL80211_ATTR_TDLS_INITIATOR,
 
+	NL80211_ATTR_USE_RRM,
+
+	NL80211_ATTR_WIPHY_DYN_ACK,
+
+	NL80211_ATTR_TSID,
+	NL80211_ATTR_USER_PRIO,
+	NL80211_ATTR_ADMITTED_TIME,
+
+	NL80211_ATTR_SMPS_MODE,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -3055,14 +3109,20 @@
  * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets)
  * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
  * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ *	(if @NL80211_BSS_PRESP_DATA is present then this is known to be
+ *	from a probe response, otherwise it may be from the same beacon
+ *	that the NL80211_BSS_BEACON_TSF will be from)
  * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
  * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
  * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
  *	raw information elements from the probe response/beacon (bin);
- *	if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
- *	from a Probe Response frame; otherwise they are from a Beacon frame.
+ *	if the %NL80211_BSS_BEACON_IES attribute is present and the data is
+ *	different then the IEs here are from a Probe Response frame; otherwise
+ *	they are from a Beacon frame.
  *	However, if the driver does not indicate the source of the IEs, these
  *	IEs may be from either frame subtype.
+ *	If present, the @NL80211_BSS_PRESP_DATA attribute indicates that the
+ *	data here is known to be from a probe response, without any heuristics.
  * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
  *	in mBm (100 * dBm) (s32)
  * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
@@ -3074,6 +3134,10 @@
  *	yet been received
  * @NL80211_BSS_CHAN_WIDTH: channel width of the control channel
  *	(u32, enum nl80211_bss_scan_width)
+ * @NL80211_BSS_BEACON_TSF: TSF of the last received beacon (u64)
+ *	(not present if no beacon frame has been received yet)
+ * @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and
+ *	@NL80211_BSS_TSF is known to be from a probe response (flag attribute)
  * @__NL80211_BSS_AFTER_LAST: internal
  * @NL80211_BSS_MAX: highest BSS attribute
  */
@@ -3091,6 +3155,8 @@
 	NL80211_BSS_SEEN_MS_AGO,
 	NL80211_BSS_BEACON_IES,
 	NL80211_BSS_CHAN_WIDTH,
+	NL80211_BSS_BEACON_TSF,
+	NL80211_BSS_PRESP_DATA,
 
 	/* keep last */
 	__NL80211_BSS_AFTER_LAST,
@@ -3956,6 +4022,26 @@
  * @NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE: This driver supports dynamic
  *	channel bandwidth change (e.g., HT 20 <-> 40 MHz channel) during the
  *	lifetime of a BSS.
+ * @NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES: This device adds a DS Parameter
+ *	Set IE to probe requests.
+ * @NL80211_FEATURE_WFA_TPC_IE_IN_PROBES: This device adds a WFA TPC Report IE
+ *	to probe requests.
+ * @NL80211_FEATURE_QUIET: This device, in client mode, supports Quiet Period
+ *	requests sent to it by an AP.
+ * @NL80211_FEATURE_TX_POWER_INSERTION: This device is capable of inserting the
+ *	current tx power value into the TPC Report IE in the spectrum
+ *	management TPC Report action frame, and in the Radio Measurement Link
+ *	Measurement Report action frame.
+ * @NL80211_FEATURE_ACKTO_ESTIMATION: This driver supports dynamic ACK timeout
+ *	estimation (dynack). %NL80211_ATTR_WIPHY_DYN_ACK flag attribute is used
+ *	to enable dynack.
+ * @NL80211_FEATURE_STATIC_SMPS: Device supports static spatial
+ *	multiplexing powersave, ie. can turn off all but one chain
+ *	even on HT connections that should be using more chains.
+ * @NL80211_FEATURE_DYNAMIC_SMPS: Device supports dynamic spatial
+ *	multiplexing powersave, ie. can turn off all but one chain
+ *	and then wake the rest up as required after, for example,
+ *	rts/cts handshake.
  */
 enum nl80211_feature_flags {
 	NL80211_FEATURE_SK_TX_STATUS			= 1 << 0,
@@ -3977,6 +4063,13 @@
 	NL80211_FEATURE_USERSPACE_MPM			= 1 << 16,
 	NL80211_FEATURE_ACTIVE_MONITOR			= 1 << 17,
 	NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE	= 1 << 18,
+	NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES	= 1 << 19,
+	NL80211_FEATURE_WFA_TPC_IE_IN_PROBES		= 1 << 20,
+	NL80211_FEATURE_QUIET				= 1 << 21,
+	NL80211_FEATURE_TX_POWER_INSERTION		= 1 << 22,
+	NL80211_FEATURE_ACKTO_ESTIMATION		= 1 << 23,
+	NL80211_FEATURE_STATIC_SMPS			= 1 << 24,
+	NL80211_FEATURE_DYNAMIC_SMPS			= 1 << 25,
 };
 
 /**
@@ -4051,6 +4144,25 @@
 };
 
 /**
+ * enum nl80211_smps_mode - SMPS mode
+ *
+ * Requested SMPS mode (for AP mode)
+ *
+ * @NL80211_SMPS_OFF: SMPS off (use all antennas).
+ * @NL80211_SMPS_STATIC: static SMPS (use a single antenna)
+ * @NL80211_SMPS_DYNAMIC: dynamic smps (start with a single antenna and
+ *	turn on other antennas after CTS/RTS).
+ */
+enum nl80211_smps_mode {
+	NL80211_SMPS_OFF,
+	NL80211_SMPS_STATIC,
+	NL80211_SMPS_DYNAMIC,
+
+	__NL80211_SMPS_AFTER_LAST,
+	NL80211_SMPS_MAX = __NL80211_SMPS_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_radar_event - type of radar event for DFS operation
  *
  * Type of event to be used with NL80211_ATTR_RADAR_EVENT to inform userspace
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index e946e43..661f119 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -746,6 +746,8 @@
 	V4L2_AUTO_FOCUS_RANGE_INFINITY		= 3,
 };
 
+#define V4L2_CID_PAN_SPEED			(V4L2_CID_CAMERA_CLASS_BASE+32)
+#define V4L2_CID_TILT_SPEED			(V4L2_CID_CAMERA_CLASS_BASE+33)
 
 /* FM Modulator class control IDs */
 
@@ -865,6 +867,10 @@
 #define V4L2_CID_VBLANK				(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 1)
 #define V4L2_CID_HBLANK				(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2)
 #define V4L2_CID_ANALOGUE_GAIN			(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3)
+#define V4L2_CID_TEST_PATTERN_RED		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 4)
+#define V4L2_CID_TEST_PATTERN_GREENR		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 5)
+#define V4L2_CID_TEST_PATTERN_BLUE		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 6)
+#define V4L2_CID_TEST_PATTERN_GREENB		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7)
 
 
 /* Image processing controls */
diff --git a/include/uapi/linux/v4l2-dv-timings.h b/include/uapi/linux/v4l2-dv-timings.h
index 6c8f159..6a0764c 100644
--- a/include/uapi/linux/v4l2-dv-timings.h
+++ b/include/uapi/linux/v4l2-dv-timings.h
@@ -21,17 +21,8 @@
 #ifndef _V4L2_DV_TIMINGS_H
 #define _V4L2_DV_TIMINGS_H
 
-#if __GNUC__ < 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ < 6))
-/* Sadly gcc versions older than 4.6 have a bug in how they initialize
-   anonymous unions where they require additional curly brackets.
-   This violates the C1x standard. This workaround adds the curly brackets
-   if needed. */
 #define V4L2_INIT_BT_TIMINGS(_width, args...) \
 	{ .bt = { _width , ## args } }
-#else
-#define V4L2_INIT_BT_TIMINGS(_width, args...) \
-	.bt = { _width , ## args }
-#endif
 
 /* CEA-861-E timings (i.e. standard HDTV timings) */
 
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 3c31308..accc4ef 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -79,6 +79,7 @@
 /*  Four-character-code (FOURCC) */
 #define v4l2_fourcc(a, b, c, d)\
 	((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24))
+#define v4l2_fourcc_be(a, b, c, d)	(v4l2_fourcc(a, b, c, d) | (1 << 31))
 
 /*
  *	E N U M S
@@ -307,6 +308,8 @@
 #define V4L2_PIX_FMT_XRGB555 v4l2_fourcc('X', 'R', '1', '5') /* 16  XRGB-1-5-5-5  */
 #define V4L2_PIX_FMT_RGB565  v4l2_fourcc('R', 'G', 'B', 'P') /* 16  RGB-5-6-5     */
 #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16  RGB-5-5-5 BE  */
+#define V4L2_PIX_FMT_ARGB555X v4l2_fourcc_be('A', 'R', '1', '5') /* 16  ARGB-5-5-5 BE */
+#define V4L2_PIX_FMT_XRGB555X v4l2_fourcc_be('X', 'R', '1', '5') /* 16  XRGB-5-5-5 BE */
 #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16  RGB-5-6-5 BE  */
 #define V4L2_PIX_FMT_BGR666  v4l2_fourcc('B', 'G', 'R', 'H') /* 18  BGR-6-6-6	  */
 #define V4L2_PIX_FMT_BGR24   v4l2_fourcc('B', 'G', 'R', '3') /* 24  BGR-8-8-8     */
@@ -1285,11 +1288,11 @@
 	union {
 		__s32 value;
 		__s64 value64;
-		char *string;
-		__u8 *p_u8;
-		__u16 *p_u16;
-		__u32 *p_u32;
-		void *ptr;
+		char __user *string;
+		__u8 __user *p_u8;
+		__u16 __user *p_u16;
+		__u32 __user *p_u32;
+		void __user *ptr;
 	};
 } __attribute__ ((packed));
 
diff --git a/include/uapi/linux/wil6210_uapi.h b/include/uapi/linux/wil6210_uapi.h
new file mode 100644
index 0000000..6a3cddd
--- /dev/null
+++ b/include/uapi/linux/wil6210_uapi.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WIL6210_UAPI_H__
+#define __WIL6210_UAPI_H__
+
+#if !defined(__KERNEL__)
+#define __user
+#endif
+
+#include <linux/sockios.h>
+
+/* Numbers SIOCDEVPRIVATE and SIOCDEVPRIVATE + 1
+ * are used by Android devices to implement PNO (preferred network offload).
+ * Albeit it is temporary solution, use different numbers to avoid conflicts
+ */
+
+/**
+ * Perform 32-bit I/O operation to the card memory
+ *
+ * User code should arrange data in memory like this:
+ *
+ *	struct wil_memio io;
+ *	struct ifreq ifr = {
+ *		.ifr_data = &io,
+ *	};
+ */
+#define WIL_IOCTL_MEMIO (SIOCDEVPRIVATE + 2)
+
+/**
+ * Perform block I/O operation to the card memory
+ *
+ * User code should arrange data in memory like this:
+ *
+ *	void *buf;
+ *	struct wil_memio_block io = {
+ *		.block = buf,
+ *	};
+ *	struct ifreq ifr = {
+ *		.ifr_data = &io,
+ *	};
+ */
+#define WIL_IOCTL_MEMIO_BLOCK (SIOCDEVPRIVATE + 3)
+
+/**
+ * operation to perform
+ *
+ * @wil_mmio_op_mask - bits defining operation,
+ * @wil_mmio_addr_mask - bits defining addressing mode
+ */
+enum wil_memio_op {
+	wil_mmio_read = 0,
+	wil_mmio_write = 1,
+	wil_mmio_op_mask = 0xff,
+	wil_mmio_addr_linker = 0 << 8,
+	wil_mmio_addr_ahb = 1 << 8,
+	wil_mmio_addr_bar = 2 << 8,
+	wil_mmio_addr_mask = 0xff00,
+};
+
+struct wil_memio {
+	uint32_t op; /* enum wil_memio_op */
+	uint32_t addr; /* should be 32-bit aligned */
+	uint32_t val;
+};
+
+struct wil_memio_block {
+	uint32_t op; /* enum wil_memio_op */
+	uint32_t addr; /* should be 32-bit aligned */
+	uint32_t size; /* should be multiple of 4 */
+	void __user *block; /* block address */
+};
+
+#endif /* __WIL6210_UAPI_H__ */
diff --git a/net/Kconfig b/net/Kconfig
index 4051fdf..6272420 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -6,6 +6,7 @@
 	bool "Networking support"
 	select NLATTR
 	select GENERIC_NET_UTILS
+	select ANON_INODES
 	---help---
 	  Unless you really know what you are doing, you should say Y here.
 	  The reason is that some programs need kernel networking support even
@@ -176,10 +177,11 @@
 	  If unsure, say Y.
 
 config BRIDGE_NETFILTER
-	bool "Bridged IP/ARP packets filtering"
-	depends on BRIDGE && NETFILTER && INET
+	tristate "Bridged IP/ARP packets filtering"
+	depends on BRIDGE
+	depends on NETFILTER && INET
 	depends on NETFILTER_ADVANCED
-	default y
+	default m
 	---help---
 	  Enabling this option will let arptables resp. iptables see bridged
 	  ARP resp. IP traffic. If you want a bridging firewall, you probably
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 206b65c..c2e0d14 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -39,6 +39,7 @@
 
 struct skb_cb {
 	struct in6_addr addr;
+	struct in6_addr gw;
 	struct l2cap_chan *chan;
 	int status;
 };
@@ -158,6 +159,54 @@
 	return NULL;
 }
 
+static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev,
+						  struct in6_addr *daddr,
+						  struct sk_buff *skb)
+{
+	struct lowpan_peer *peer, *tmp;
+	struct in6_addr *nexthop;
+	struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
+	int count = atomic_read(&dev->peer_count);
+
+	BT_DBG("peers %d addr %pI6c rt %p", count, daddr, rt);
+
+	/* If we have multiple 6lowpan peers, then check where we should
+	 * send the packet. If only one peer exists, then we can send the
+	 * packet right away.
+	 */
+	if (count == 1)
+		return list_first_entry(&dev->peers, struct lowpan_peer,
+					list);
+
+	if (!rt) {
+		nexthop = &lowpan_cb(skb)->gw;
+
+		if (ipv6_addr_any(nexthop))
+			return NULL;
+	} else {
+		nexthop = rt6_nexthop(rt);
+
+		/* We need to remember the address because it is needed
+		 * by bt_xmit() when sending the packet. In bt_xmit(), the
+		 * destination routing info is not set.
+		 */
+		memcpy(&lowpan_cb(skb)->gw, nexthop, sizeof(struct in6_addr));
+	}
+
+	BT_DBG("gw %pI6c", nexthop);
+
+	list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+		BT_DBG("dst addr %pMR dst type %d ip %pI6c",
+		       &peer->chan->dst, peer->chan->dst_type,
+		       &peer->peer_addr);
+
+		if (!ipv6_addr_cmp(&peer->peer_addr, nexthop))
+			return peer;
+	}
+
+	return NULL;
+}
+
 static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn)
 {
 	struct lowpan_dev *entry, *tmp;
@@ -377,58 +426,85 @@
 	*addr_type = get_addr_type_from_eui64(addr->b[5]);
 }
 
-static int header_create(struct sk_buff *skb, struct net_device *netdev,
-		         unsigned short type, const void *_daddr,
-		         const void *_saddr, unsigned int len)
+static int setup_header(struct sk_buff *skb, struct net_device *netdev,
+			bdaddr_t *peer_addr, u8 *peer_addr_type)
 {
-	struct ipv6hdr *hdr;
+	struct in6_addr ipv6_daddr;
 	struct lowpan_dev *dev;
 	struct lowpan_peer *peer;
 	bdaddr_t addr, *any = BDADDR_ANY;
-	u8 *saddr, *daddr = any->b;
-	u8 addr_type;
-
-	if (type != ETH_P_IPV6)
-		return -EINVAL;
-
-	hdr = ipv6_hdr(skb);
+	u8 *daddr = any->b;
+	int err, status = 0;
 
 	dev = lowpan_dev(netdev);
 
-	if (ipv6_addr_is_multicast(&hdr->daddr)) {
-		memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
-		       sizeof(struct in6_addr));
+	memcpy(&ipv6_daddr, &lowpan_cb(skb)->addr, sizeof(ipv6_daddr));
+
+	if (ipv6_addr_is_multicast(&ipv6_daddr)) {
 		lowpan_cb(skb)->chan = NULL;
 	} else {
 		unsigned long flags;
+		u8 addr_type;
 
 		/* Get destination BT device from skb.
 		 * If there is no such peer then discard the packet.
 		 */
-		convert_dest_bdaddr(&hdr->daddr, &addr, &addr_type);
+		convert_dest_bdaddr(&ipv6_daddr, &addr, &addr_type);
 
 		BT_DBG("dest addr %pMR type %d IP %pI6c", &addr,
-		       addr_type, &hdr->daddr);
+		       addr_type, &ipv6_daddr);
 
 		read_lock_irqsave(&devices_lock, flags);
 		peer = peer_lookup_ba(dev, &addr, addr_type);
 		read_unlock_irqrestore(&devices_lock, flags);
 
 		if (!peer) {
-			BT_DBG("no such peer %pMR found", &addr);
-			return -ENOENT;
+			/* The packet might be sent to 6lowpan interface
+			 * because of routing (either via default route
+			 * or user set route) so get peer according to
+			 * the destination address.
+			 */
+			read_lock_irqsave(&devices_lock, flags);
+			peer = peer_lookup_dst(dev, &ipv6_daddr, skb);
+			read_unlock_irqrestore(&devices_lock, flags);
+			if (!peer) {
+				BT_DBG("no such peer %pMR found", &addr);
+				return -ENOENT;
+			}
 		}
 
 		daddr = peer->eui64_addr;
-
-		memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
-		       sizeof(struct in6_addr));
+		*peer_addr = addr;
+		*peer_addr_type = addr_type;
 		lowpan_cb(skb)->chan = peer->chan;
+
+		status = 1;
 	}
 
-	saddr = dev->netdev->dev_addr;
+	lowpan_header_compress(skb, netdev, ETH_P_IPV6, daddr,
+			       dev->netdev->dev_addr, skb->len);
 
-	return lowpan_header_compress(skb, netdev, type, daddr, saddr, len);
+	err = dev_hard_header(skb, netdev, ETH_P_IPV6, NULL, NULL, 0);
+	if (err < 0)
+		return err;
+
+	return status;
+}
+
+static int header_create(struct sk_buff *skb, struct net_device *netdev,
+			 unsigned short type, const void *_daddr,
+			 const void *_saddr, unsigned int len)
+{
+	struct ipv6hdr *hdr;
+
+	if (type != ETH_P_IPV6)
+		return -EINVAL;
+
+	hdr = ipv6_hdr(skb);
+
+	memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, sizeof(struct in6_addr));
+
+	return 0;
 }
 
 /* Packet to BT LE device */
@@ -470,11 +546,12 @@
 	return err;
 }
 
-static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
+static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct sk_buff *local_skb;
 	struct lowpan_dev *entry, *tmp;
 	unsigned long flags;
+	int err = 0;
 
 	read_lock_irqsave(&devices_lock, flags);
 
@@ -488,55 +565,77 @@
 		dev = lowpan_dev(entry->netdev);
 
 		list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) {
+			int ret;
+
 			local_skb = skb_clone(skb, GFP_ATOMIC);
 
-			send_pkt(pentry->chan, local_skb, netdev);
+			BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p",
+			       netdev->name,
+			       &pentry->chan->dst, pentry->chan->dst_type,
+			       &pentry->peer_addr, pentry->chan);
+			ret = send_pkt(pentry->chan, local_skb, netdev);
+			if (ret < 0)
+				err = ret;
 
 			kfree_skb(local_skb);
 		}
 	}
 
 	read_unlock_irqrestore(&devices_lock, flags);
+
+	return err;
 }
 
 static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	int err = 0;
-	struct lowpan_dev *dev;
-	struct lowpan_peer *peer;
 	bdaddr_t addr;
 	u8 addr_type;
+	struct sk_buff *tmpskb;
 
-	if (ipv6_addr_is_multicast(&lowpan_cb(skb)->addr)) {
-		/* We need to send the packet to every device
-		 * behind this interface.
-		 */
-		send_mcast_pkt(skb, netdev);
-	} else {
-		unsigned long flags;
-
-		convert_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type);
-		dev = lowpan_dev(netdev);
-
-		read_lock_irqsave(&devices_lock, flags);
-		peer = peer_lookup_ba(dev, &addr, addr_type);
-		read_unlock_irqrestore(&devices_lock, flags);
-
-		BT_DBG("xmit %s to %pMR type %d IP %pI6c peer %p",
-		       netdev->name, &addr, addr_type,
-		       &lowpan_cb(skb)->addr, peer);
-
-		if (peer && peer->chan)
-			err = send_pkt(peer->chan, skb, netdev);
-		else
-			err = -ENOENT;
+	/* We must take a copy of the skb before we modify/replace the ipv6
+	 * header as the header could be used elsewhere
+	 */
+	tmpskb = skb_unshare(skb, GFP_ATOMIC);
+	if (!tmpskb) {
+		kfree_skb(skb);
+		return NET_XMIT_DROP;
 	}
+	skb = tmpskb;
+
+	/* Return values from setup_header()
+	 *  <0 - error, packet is dropped
+	 *   0 - this is a multicast packet
+	 *   1 - this is unicast packet
+	 */
+	err = setup_header(skb, netdev, &addr, &addr_type);
+	if (err < 0) {
+		kfree_skb(skb);
+		return NET_XMIT_DROP;
+	}
+
+	if (err) {
+		if (lowpan_cb(skb)->chan) {
+			BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p",
+			       netdev->name, &addr, addr_type,
+			       &lowpan_cb(skb)->addr, lowpan_cb(skb)->chan);
+			err = send_pkt(lowpan_cb(skb)->chan, skb, netdev);
+		} else {
+			err = -ENOENT;
+		}
+	} else {
+		/* We need to send the packet to every device behind this
+		 * interface.
+		 */
+		err = send_mcast_pkt(skb, netdev);
+	}
+
 	dev_kfree_skb(skb);
 
 	if (err)
 		BT_DBG("ERROR: xmit failed (%d)", err);
 
-	return (err < 0) ? NET_XMIT_DROP : err;
+	return err < 0 ? NET_XMIT_DROP : err;
 }
 
 static const struct net_device_ops netdev_ops = {
@@ -556,7 +655,8 @@
 	dev->needed_tailroom	= 0;
 	dev->mtu		= IPV6_MIN_MTU;
 	dev->tx_queue_len	= 0;
-	dev->flags		= IFF_RUNNING | IFF_POINTOPOINT;
+	dev->flags		= IFF_RUNNING | IFF_POINTOPOINT |
+				  IFF_MULTICAST;
 	dev->watchdog_timeo	= 0;
 
 	dev->netdev_ops		= &netdev_ops;
@@ -671,6 +771,14 @@
 	return chan;
 }
 
+static void set_ip_addr_bits(u8 addr_type, u8 *addr)
+{
+	if (addr_type == BDADDR_LE_PUBLIC)
+		*addr |= 0x02;
+	else
+		*addr &= ~0x02;
+}
+
 static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan,
 					struct lowpan_dev *dev)
 {
@@ -693,6 +801,11 @@
 	memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8,
 	       EUI64_ADDR_LEN);
 
+	/* IPv6 address needs to have the U/L bit set properly so toggle
+	 * it back here.
+	 */
+	set_ip_addr_bits(chan->dst_type, (u8 *)&peer->peer_addr.s6_addr + 8);
+
 	write_lock_irqsave(&devices_lock, flags);
 	INIT_LIST_HEAD(&peer->list);
 	peer_add(dev, peer);
@@ -772,16 +885,16 @@
 	ifup(dev->netdev);
 }
 
-static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *chan)
+static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
 {
-	struct l2cap_chan *pchan;
+	struct l2cap_chan *chan;
 
-	pchan = chan_open(chan);
-	pchan->ops = chan->ops;
+	chan = chan_open(pchan);
+	chan->ops = pchan->ops;
 
 	BT_DBG("chan %p pchan %p", chan, pchan);
 
-	return pchan;
+	return chan;
 }
 
 static void delete_netdev(struct work_struct *work)
@@ -876,6 +989,9 @@
 
 	BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb);
 
+	if (!skb)
+		return;
+
 	lowpan_cb(skb)->status = -EAGAIN;
 }
 
@@ -885,12 +1001,15 @@
 
 	BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb);
 
+	if (!skb)
+		return;
+
 	lowpan_cb(skb)->status = 0;
 }
 
 static long chan_get_sndtimeo_cb(struct l2cap_chan *chan)
 {
-	return msecs_to_jiffies(1000);
+	return L2CAP_CONN_TIMEOUT;
 }
 
 static const struct l2cap_ops bt_6lowpan_chan_ops = {
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 4dca029..339c74a 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -709,8 +709,11 @@
 
 static int __init bt_init(void)
 {
+	struct sk_buff *skb;
 	int err;
 
+	BUILD_BUG_ON(sizeof(struct bt_skb_cb) > sizeof(skb->cb));
+
 	BT_INFO("Core ver %s", VERSION);
 
 	bt_debugfs = debugfs_create_dir("bluetooth", NULL);
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index 016cdb6..2640d78 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -149,15 +149,14 @@
 	if (ret) {
 		BT_DBG("crypto_ahash_setkey failed: err %d", ret);
 	} else {
-		struct {
-			struct shash_desc shash;
-			char ctx[crypto_shash_descsize(tfm)];
-		} desc;
+		char desc[sizeof(struct shash_desc) +
+			crypto_shash_descsize(tfm)] CRYPTO_MINALIGN_ATTR;
+		struct shash_desc *shash = (struct shash_desc *)desc;
 
-		desc.shash.tfm = tfm;
-		desc.shash.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+		shash->tfm = tfm;
+		shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 
-		ret = crypto_shash_digest(&desc.shash, plaintext, psize,
+		ret = crypto_shash_digest(shash, plaintext, psize,
 					  output);
 	}
 
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index faff624..b9517bd 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -36,19 +36,25 @@
 struct sco_param {
 	u16 pkt_type;
 	u16 max_latency;
+	u8  retrans_effort;
+};
+
+static const struct sco_param esco_param_cvsd[] = {
+	{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a,	0x01 }, /* S3 */
+	{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007,	0x01 }, /* S2 */
+	{ EDR_ESCO_MASK | ESCO_EV3,   0x0007,	0x01 }, /* S1 */
+	{ EDR_ESCO_MASK | ESCO_HV3,   0xffff,	0x01 }, /* D1 */
+	{ EDR_ESCO_MASK | ESCO_HV1,   0xffff,	0x01 }, /* D0 */
 };
 
 static const struct sco_param sco_param_cvsd[] = {
-	{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a }, /* S3 */
-	{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007 }, /* S2 */
-	{ EDR_ESCO_MASK | ESCO_EV3,   0x0007 }, /* S1 */
-	{ EDR_ESCO_MASK | ESCO_HV3,   0xffff }, /* D1 */
-	{ EDR_ESCO_MASK | ESCO_HV1,   0xffff }, /* D0 */
+	{ EDR_ESCO_MASK | ESCO_HV3,   0xffff,	0xff }, /* D1 */
+	{ EDR_ESCO_MASK | ESCO_HV1,   0xffff,	0xff }, /* D0 */
 };
 
-static const struct sco_param sco_param_wideband[] = {
-	{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d }, /* T2 */
-	{ EDR_ESCO_MASK | ESCO_EV3,   0x0008 }, /* T1 */
+static const struct sco_param esco_param_msbc[] = {
+	{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d,	0x02 }, /* T2 */
+	{ EDR_ESCO_MASK | ESCO_EV3,   0x0008,	0x02 }, /* T1 */
 };
 
 static void hci_le_create_connection_cancel(struct hci_conn *conn)
@@ -116,23 +122,36 @@
 {
 	struct hci_cp_reject_sync_conn_req cp;
 
-	cp.reason = HCI_ERROR_REMOTE_USER_TERM;
+	cp.reason = HCI_ERROR_REJ_LIMITED_RESOURCES;
 	bacpy(&cp.bdaddr, &conn->dst);
 
 	hci_send_cmd(conn->hdev, HCI_OP_REJECT_SYNC_CONN_REQ, sizeof(cp), &cp);
 }
 
-void hci_disconnect(struct hci_conn *conn, __u8 reason)
+int hci_disconnect(struct hci_conn *conn, __u8 reason)
 {
 	struct hci_cp_disconnect cp;
 
 	BT_DBG("hcon %p", conn);
 
+	/* When we are master of an established connection and it enters
+	 * the disconnect timeout, then go ahead and try to read the
+	 * current clock offset.  Processing of the result is done
+	 * within the event handling and hci_clock_offset_evt function.
+	 */
+	if (conn->type == ACL_LINK && conn->role == HCI_ROLE_MASTER) {
+		struct hci_dev *hdev = conn->hdev;
+		struct hci_cp_read_clock_offset cp;
+
+		cp.handle = cpu_to_le16(conn->handle);
+		hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET, sizeof(cp), &cp);
+	}
+
 	conn->state = BT_DISCONN;
 
 	cp.handle = cpu_to_le16(conn->handle);
 	cp.reason = reason;
-	hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
+	return hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
 }
 
 static void hci_amp_disconn(struct hci_conn *conn)
@@ -188,21 +207,26 @@
 
 	switch (conn->setting & SCO_AIRMODE_MASK) {
 	case SCO_AIRMODE_TRANSP:
-		if (conn->attempt > ARRAY_SIZE(sco_param_wideband))
+		if (conn->attempt > ARRAY_SIZE(esco_param_msbc))
 			return false;
-		cp.retrans_effort = 0x02;
-		param = &sco_param_wideband[conn->attempt - 1];
+		param = &esco_param_msbc[conn->attempt - 1];
 		break;
 	case SCO_AIRMODE_CVSD:
-		if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
-			return false;
-		cp.retrans_effort = 0x01;
-		param = &sco_param_cvsd[conn->attempt - 1];
+		if (lmp_esco_capable(conn->link)) {
+			if (conn->attempt > ARRAY_SIZE(esco_param_cvsd))
+				return false;
+			param = &esco_param_cvsd[conn->attempt - 1];
+		} else {
+			if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
+				return false;
+			param = &sco_param_cvsd[conn->attempt - 1];
+		}
 		break;
 	default:
 		return false;
 	}
 
+	cp.retrans_effort = param->retrans_effort;
 	cp.pkt_type = __cpu_to_le16(param->pkt_type);
 	cp.max_latency = __cpu_to_le16(param->max_latency);
 
@@ -325,25 +349,6 @@
 			hci_amp_disconn(conn);
 		} else {
 			__u8 reason = hci_proto_disconn_ind(conn);
-
-			/* When we are master of an established connection
-			 * and it enters the disconnect timeout, then go
-			 * ahead and try to read the current clock offset.
-			 *
-			 * Processing of the result is done within the
-			 * event handling and hci_clock_offset_evt function.
-			 */
-			if (conn->type == ACL_LINK &&
-			    conn->role == HCI_ROLE_MASTER) {
-				struct hci_dev *hdev = conn->hdev;
-				struct hci_cp_read_clock_offset cp;
-
-				cp.handle = cpu_to_le16(conn->handle);
-
-				hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET,
-					     sizeof(cp), &cp);
-			}
-
 			hci_disconnect(conn, reason);
 		}
 		break;
@@ -595,6 +600,7 @@
 					   conn->dst_type);
 	if (params && params->conn) {
 		hci_conn_drop(params->conn);
+		hci_conn_put(params->conn);
 		params->conn = NULL;
 	}
 
@@ -1290,11 +1296,16 @@
 
 	BT_DBG("%s hcon %p", hdev->name, conn);
 
+	if (test_bit(HCI_CONN_DROP, &conn->flags)) {
+		BT_DBG("Refusing to create new hci_chan");
+		return NULL;
+	}
+
 	chan = kzalloc(sizeof(*chan), GFP_KERNEL);
 	if (!chan)
 		return NULL;
 
-	chan->conn = conn;
+	chan->conn = hci_conn_get(conn);
 	skb_queue_head_init(&chan->data_q);
 	chan->state = BT_CONNECTED;
 
@@ -1314,7 +1325,10 @@
 
 	synchronize_rcu();
 
-	hci_conn_drop(conn);
+	/* Prevent new hci_chan's to be created for this hci_conn */
+	set_bit(HCI_CONN_DROP, &conn->flags);
+
+	hci_conn_put(conn);
 
 	skb_queue_purge(&chan->data_q);
 	kfree(chan);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 1d9c29a..cb05d7f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1898,6 +1898,8 @@
 		debugfs_create_u16("discov_interleaved_timeout", 0644,
 				   hdev->debugfs,
 				   &hdev->discov_interleaved_timeout);
+
+		smp_register(hdev);
 	}
 
 	return 0;
@@ -2539,6 +2541,7 @@
 	list_for_each_entry(p, &hdev->le_conn_params, list) {
 		if (p->conn) {
 			hci_conn_drop(p->conn);
+			hci_conn_put(p->conn);
 			p->conn = NULL;
 		}
 		list_del_init(&p->action);
@@ -3238,7 +3241,7 @@
 	}
 
 	list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
-		if (smp_irk_matches(hdev->tfm_aes, irk->val, rpa)) {
+		if (smp_irk_matches(hdev, irk->val, rpa)) {
 			bacpy(&irk->rpa, rpa);
 			return irk;
 		}
@@ -3723,6 +3726,18 @@
 	return 0;
 }
 
+static void hci_conn_params_free(struct hci_conn_params *params)
+{
+	if (params->conn) {
+		hci_conn_drop(params->conn);
+		hci_conn_put(params->conn);
+	}
+
+	list_del(&params->action);
+	list_del(&params->list);
+	kfree(params);
+}
+
 /* This function requires the caller holds hdev->lock */
 void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
 {
@@ -3732,12 +3747,7 @@
 	if (!params)
 		return;
 
-	if (params->conn)
-		hci_conn_drop(params->conn);
-
-	list_del(&params->action);
-	list_del(&params->list);
-	kfree(params);
+	hci_conn_params_free(params);
 
 	hci_update_background_scan(hdev);
 
@@ -3764,13 +3774,8 @@
 {
 	struct hci_conn_params *params, *tmp;
 
-	list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) {
-		if (params->conn)
-			hci_conn_drop(params->conn);
-		list_del(&params->action);
-		list_del(&params->list);
-		kfree(params);
-	}
+	list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list)
+		hci_conn_params_free(params);
 
 	hci_update_background_scan(hdev);
 
@@ -3867,6 +3872,7 @@
 	if (test_bit(HCI_LE_ADV, &hdev->dev_flags) ||
 	    hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) {
 		BT_DBG("Deferring random address update");
+		set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
 		return;
 	}
 
@@ -3892,7 +3898,7 @@
 		    !bacmp(&hdev->random_addr, &hdev->rpa))
 			return 0;
 
-		err = smp_generate_rpa(hdev->tfm_aes, hdev->irk, &hdev->rpa);
+		err = smp_generate_rpa(hdev, hdev->irk, &hdev->rpa);
 		if (err < 0) {
 			BT_ERR("%s failed to generate new RPA", hdev->name);
 			return err;
@@ -4100,18 +4106,9 @@
 
 	dev_set_name(&hdev->dev, "%s", hdev->name);
 
-	hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0,
-					       CRYPTO_ALG_ASYNC);
-	if (IS_ERR(hdev->tfm_aes)) {
-		BT_ERR("Unable to create crypto context");
-		error = PTR_ERR(hdev->tfm_aes);
-		hdev->tfm_aes = NULL;
-		goto err_wqueue;
-	}
-
 	error = device_add(&hdev->dev);
 	if (error < 0)
-		goto err_tfm;
+		goto err_wqueue;
 
 	hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
 				    RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops,
@@ -4153,8 +4150,6 @@
 
 	return id;
 
-err_tfm:
-	crypto_free_blkcipher(hdev->tfm_aes);
 err_wqueue:
 	destroy_workqueue(hdev->workqueue);
 	destroy_workqueue(hdev->req_workqueue);
@@ -4206,8 +4201,7 @@
 		rfkill_destroy(hdev->rfkill);
 	}
 
-	if (hdev->tfm_aes)
-		crypto_free_blkcipher(hdev->tfm_aes);
+	smp_unregister(hdev);
 
 	device_del(&hdev->dev);
 
@@ -4380,26 +4374,6 @@
 	return remain;
 }
 
-int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
-{
-	int rem = 0;
-
-	if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
-		return -EILSEQ;
-
-	while (count) {
-		rem = hci_reassembly(hdev, type, data, count, type - 1);
-		if (rem < 0)
-			return rem;
-
-		data += (count - rem);
-		count = rem;
-	}
-
-	return rem;
-}
-EXPORT_SYMBOL(hci_recv_fragment);
-
 #define STREAM_REASSEMBLY 0
 
 int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
@@ -4553,6 +4527,7 @@
 	BT_DBG("skb len %d", skb->len);
 
 	bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
+	bt_cb(skb)->opcode = opcode;
 
 	return skb;
 }
@@ -5690,3 +5665,52 @@
 	if (err)
 		BT_ERR("Failed to run HCI request: err %d", err);
 }
+
+static bool disconnected_whitelist_entries(struct hci_dev *hdev)
+{
+	struct bdaddr_list *b;
+
+	list_for_each_entry(b, &hdev->whitelist, list) {
+		struct hci_conn *conn;
+
+		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &b->bdaddr);
+		if (!conn)
+			return true;
+
+		if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
+			return true;
+	}
+
+	return false;
+}
+
+void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req)
+{
+	u8 scan;
+
+	if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
+		return;
+
+	if (!hdev_is_powered(hdev))
+		return;
+
+	if (mgmt_powering_down(hdev))
+		return;
+
+	if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
+	    disconnected_whitelist_entries(hdev))
+		scan = SCAN_PAGE;
+	else
+		scan = SCAN_DISABLED;
+
+	if (test_bit(HCI_PSCAN, &hdev->flags) == !!(scan & SCAN_PAGE))
+		return;
+
+	if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
+		scan |= SCAN_INQUIRY;
+
+	if (req)
+		hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+	else
+		hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index a600082..8b0a2a6 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2071,6 +2071,8 @@
 			cp.handle = ev->handle;
 			hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
 				     sizeof(cp), &cp);
+
+			hci_update_page_scan(hdev, NULL);
 		}
 
 		/* Set packet type for incoming connection */
@@ -2247,9 +2249,12 @@
 	mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
 				reason, mgmt_connected);
 
-	if (conn->type == ACL_LINK &&
-	    test_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
-		hci_remove_link_key(hdev, &conn->dst);
+	if (conn->type == ACL_LINK) {
+		if (test_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
+			hci_remove_link_key(hdev, &conn->dst);
+
+		hci_update_page_scan(hdev, NULL);
+	}
 
 	params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
 	if (params) {
@@ -2315,8 +2320,7 @@
 			conn->sec_level = conn->pending_sec_level;
 		}
 	} else {
-		mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
-				 ev->status);
+		mgmt_auth_failed(conn, ev->status);
 	}
 
 	clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
@@ -2434,6 +2438,12 @@
 		}
 	}
 
+	/* We should disregard the current RPA and generate a new one
+	 * whenever the encryption procedure fails.
+	 */
+	if (ev->status && conn->type == LE_LINK)
+		set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
+
 	clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
 
 	if (ev->status && conn->state == BT_CONNECTED) {
@@ -3895,8 +3905,7 @@
 	 * event gets always produced as initiator and is also mapped to
 	 * the mgmt_auth_failed event */
 	if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status)
-		mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
-				 ev->status);
+		mgmt_auth_failed(conn, ev->status);
 
 	hci_conn_drop(conn);
 
@@ -4188,16 +4197,16 @@
 		conn->dst_type = irk->addr_type;
 	}
 
-	if (conn->dst_type == ADDR_LE_DEV_PUBLIC)
-		addr_type = BDADDR_LE_PUBLIC;
-	else
-		addr_type = BDADDR_LE_RANDOM;
-
 	if (ev->status) {
 		hci_le_conn_failed(conn, ev->status);
 		goto unlock;
 	}
 
+	if (conn->dst_type == ADDR_LE_DEV_PUBLIC)
+		addr_type = BDADDR_LE_PUBLIC;
+	else
+		addr_type = BDADDR_LE_RANDOM;
+
 	/* Drop the connection if the device is blocked */
 	if (hci_bdaddr_list_lookup(&hdev->blacklist, &conn->dst, addr_type)) {
 		hci_conn_drop(conn);
@@ -4220,11 +4229,13 @@
 
 	hci_proto_connect_cfm(conn, ev->status);
 
-	params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
+	params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst,
+					   conn->dst_type);
 	if (params) {
 		list_del_init(&params->action);
 		if (params->conn) {
 			hci_conn_drop(params->conn);
+			hci_conn_put(params->conn);
 			params->conn = NULL;
 		}
 	}
@@ -4316,7 +4327,7 @@
 		 * the parameters get removed and keep the reference
 		 * count consistent once the connection is established.
 		 */
-		params->conn = conn;
+		params->conn = hci_conn_get(conn);
 		return;
 	}
 
@@ -4501,10 +4512,7 @@
 	memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
 	cp.handle = cpu_to_le16(conn->handle);
 
-	if (ltk->authenticated)
-		conn->pending_sec_level = BT_SECURITY_HIGH;
-	else
-		conn->pending_sec_level = BT_SECURITY_MEDIUM;
+	conn->pending_sec_level = smp_ltk_sec_level(ltk);
 
 	conn->enc_key_size = ltk->enc_size;
 
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 8ade49c..1687cc7 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -919,7 +919,7 @@
 
 	/* connection management */
 	bacpy(&session->bdaddr, bdaddr);
-	session->conn = conn;
+	session->conn = l2cap_conn_get(conn);
 	session->user.probe = hidp_session_probe;
 	session->user.remove = hidp_session_remove;
 	session->ctrl_sock = ctrl_sock;
@@ -945,13 +945,13 @@
 	if (ret)
 		goto err_free;
 
-	l2cap_conn_get(session->conn);
 	get_file(session->intr_sock->file);
 	get_file(session->ctrl_sock->file);
 	*out = session;
 	return 0;
 
 err_free:
+	l2cap_conn_put(session->conn);
 	kfree(session);
 	return ret;
 }
@@ -1331,10 +1331,8 @@
 
 	conn = NULL;
 	l2cap_chan_lock(chan);
-	if (chan->conn) {
-		l2cap_conn_get(chan->conn);
-		conn = chan->conn;
-	}
+	if (chan->conn)
+		conn = l2cap_conn_get(chan->conn);
 	l2cap_chan_unlock(chan);
 
 	if (!conn)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 46547b9..b6f9777 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -210,6 +210,10 @@
 {
 	write_lock(&chan_list_lock);
 
+	/* Override the defaults (which are for conn-oriented) */
+	chan->omtu = L2CAP_DEFAULT_MTU;
+	chan->chan_type = L2CAP_CHAN_FIXED;
+
 	chan->scid = scid;
 
 	write_unlock(&chan_list_lock);
@@ -542,7 +546,10 @@
 
 	l2cap_chan_hold(chan);
 
-	hci_conn_hold(conn->hcon);
+	/* Only keep a reference for fixed channels if they requested it */
+	if (chan->chan_type != L2CAP_CHAN_FIXED ||
+	    test_bit(FLAG_HOLD_HCI_CONN, &chan->flags))
+		hci_conn_hold(conn->hcon);
 
 	list_add(&chan->list, &conn->chan_l);
 }
@@ -562,6 +569,8 @@
 
 	BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
 
+	chan->ops->teardown(chan, err);
+
 	if (conn) {
 		struct amp_mgr *mgr = conn->hcon->amp_mgr;
 		/* Delete from channel list */
@@ -571,7 +580,12 @@
 
 		chan->conn = NULL;
 
-		if (chan->scid != L2CAP_CID_A2MP)
+		/* Reference was only held for non-fixed channels or
+		 * fixed channels that explicitly requested it using the
+		 * FLAG_HOLD_HCI_CONN flag.
+		 */
+		if (chan->chan_type != L2CAP_CHAN_FIXED ||
+		    test_bit(FLAG_HOLD_HCI_CONN, &chan->flags))
 			hci_conn_drop(conn->hcon);
 
 		if (mgr && mgr->bredr_chan == chan)
@@ -585,8 +599,6 @@
 		amp_disconnect_logical_link(hs_hchan);
 	}
 
-	chan->ops->teardown(chan, err);
-
 	if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
 		return;
 
@@ -619,9 +631,11 @@
 }
 EXPORT_SYMBOL_GPL(l2cap_chan_del);
 
-void l2cap_conn_update_id_addr(struct hci_conn *hcon)
+static void l2cap_conn_update_id_addr(struct work_struct *work)
 {
-	struct l2cap_conn *conn = hcon->l2cap_data;
+	struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
+					       id_addr_update_work);
+	struct hci_conn *hcon = conn->hcon;
 	struct l2cap_chan *chan;
 
 	mutex_lock(&conn->chan_lock);
@@ -1082,6 +1096,9 @@
 
 static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
 {
+	if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
+		return true;
+
 	return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
 }
 
@@ -1266,6 +1283,24 @@
 	}
 }
 
+static void l2cap_request_info(struct l2cap_conn *conn)
+{
+	struct l2cap_info_req req;
+
+	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
+		return;
+
+	req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+
+	conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
+	conn->info_ident = l2cap_get_ident(conn);
+
+	schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
+
+	l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ,
+		       sizeof(req), &req);
+}
+
 static void l2cap_do_start(struct l2cap_chan *chan)
 {
 	struct l2cap_conn *conn = chan->conn;
@@ -1275,26 +1310,17 @@
 		return;
 	}
 
-	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
-		if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
-			return;
-
-		if (l2cap_chan_check_security(chan, true) &&
-		    __l2cap_no_conn_pending(chan)) {
-			l2cap_start_connection(chan);
-		}
-	} else {
-		struct l2cap_info_req req;
-		req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
-
-		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
-		conn->info_ident = l2cap_get_ident(conn);
-
-		schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
-
-		l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ,
-			       sizeof(req), &req);
+	if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)) {
+		l2cap_request_info(conn);
+		return;
 	}
+
+	if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
+		return;
+
+	if (l2cap_chan_check_security(chan, true) &&
+	    __l2cap_no_conn_pending(chan))
+		l2cap_start_connection(chan);
 }
 
 static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
@@ -1353,6 +1379,7 @@
 		l2cap_chan_lock(chan);
 
 		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
+			l2cap_chan_ready(chan);
 			l2cap_chan_unlock(chan);
 			continue;
 		}
@@ -1417,71 +1444,18 @@
 	mutex_unlock(&conn->chan_lock);
 }
 
-/* Find socket with cid and source/destination bdaddr.
- * Returns closest match, locked.
- */
-static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
-						    bdaddr_t *src,
-						    bdaddr_t *dst)
-{
-	struct l2cap_chan *c, *c1 = NULL;
-
-	read_lock(&chan_list_lock);
-
-	list_for_each_entry(c, &chan_list, global_l) {
-		if (state && c->state != state)
-			continue;
-
-		if (c->scid == cid) {
-			int src_match, dst_match;
-			int src_any, dst_any;
-
-			/* Exact match. */
-			src_match = !bacmp(&c->src, src);
-			dst_match = !bacmp(&c->dst, dst);
-			if (src_match && dst_match) {
-				read_unlock(&chan_list_lock);
-				return c;
-			}
-
-			/* Closest match */
-			src_any = !bacmp(&c->src, BDADDR_ANY);
-			dst_any = !bacmp(&c->dst, BDADDR_ANY);
-			if ((src_match && dst_any) || (src_any && dst_match) ||
-			    (src_any && dst_any))
-				c1 = c;
-		}
-	}
-
-	read_unlock(&chan_list_lock);
-
-	return c1;
-}
-
 static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 {
 	struct hci_conn *hcon = conn->hcon;
 	struct hci_dev *hdev = hcon->hdev;
-	struct l2cap_chan *chan, *pchan;
-	u8 dst_type;
 
-	BT_DBG("");
+	BT_DBG("%s conn %p", hdev->name, conn);
 
-	/* Check if we have socket listening on cid */
-	pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT,
-					  &hcon->src, &hcon->dst);
-	if (!pchan)
-		return;
-
-	/* Client ATT sockets should override the server one */
-	if (__l2cap_get_chan_by_dcid(conn, L2CAP_CID_ATT))
-		return;
-
-	dst_type = bdaddr_type(hcon, hcon->dst_type);
-
-	/* If device is blocked, do not create a channel for it */
-	if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type))
-		return;
+	/* For outgoing pairing which doesn't necessarily have an
+	 * associated socket (e.g. mgmt_pair_device).
+	 */
+	if (hcon->out)
+		smp_conn_security(hcon, hcon->pending_sec_level);
 
 	/* For LE slave connections, make sure the connection interval
 	 * is in the range of the minium and maximum interval that has
@@ -1501,22 +1475,6 @@
 		l2cap_send_cmd(conn, l2cap_get_ident(conn),
 			       L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req);
 	}
-
-	l2cap_chan_lock(pchan);
-
-	chan = pchan->ops->new_connection(pchan);
-	if (!chan)
-		goto clean;
-
-	bacpy(&chan->src, &hcon->src);
-	bacpy(&chan->dst, &hcon->dst);
-	chan->src_type = bdaddr_type(hcon, hcon->src_type);
-	chan->dst_type = dst_type;
-
-	__l2cap_chan_add(conn, chan);
-
-clean:
-	l2cap_chan_unlock(pchan);
 }
 
 static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -1526,17 +1484,11 @@
 
 	BT_DBG("conn %p", conn);
 
-	/* For outgoing pairing which doesn't necessarily have an
-	 * associated socket (e.g. mgmt_pair_device).
-	 */
-	if (hcon->out && hcon->type == LE_LINK)
-		smp_conn_security(hcon, hcon->pending_sec_level);
+	if (hcon->type == ACL_LINK)
+		l2cap_request_info(conn);
 
 	mutex_lock(&conn->chan_lock);
 
-	if (hcon->type == LE_LINK)
-		l2cap_le_conn_ready(conn);
-
 	list_for_each_entry(chan, &conn->chan_l, list) {
 
 		l2cap_chan_lock(chan);
@@ -1549,8 +1501,8 @@
 		if (hcon->type == LE_LINK) {
 			l2cap_le_start(chan);
 		} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
-			l2cap_chan_ready(chan);
-
+			if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
+				l2cap_chan_ready(chan);
 		} else if (chan->state == BT_CONNECT) {
 			l2cap_do_start(chan);
 		}
@@ -1560,6 +1512,9 @@
 
 	mutex_unlock(&conn->chan_lock);
 
+	if (hcon->type == LE_LINK)
+		l2cap_le_conn_ready(conn);
+
 	queue_work(hcon->hdev->workqueue, &conn->pending_rx_work);
 }
 
@@ -1695,8 +1650,14 @@
 	if (work_pending(&conn->pending_rx_work))
 		cancel_work_sync(&conn->pending_rx_work);
 
+	if (work_pending(&conn->id_addr_update_work))
+		cancel_work_sync(&conn->id_addr_update_work);
+
 	l2cap_unregister_all_users(conn);
 
+	/* Force the connection to be immediately dropped */
+	hcon->disc_timeout = 0;
+
 	mutex_lock(&conn->chan_lock);
 
 	/* Kill channels */
@@ -1719,29 +1680,11 @@
 	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
 		cancel_delayed_work_sync(&conn->info_timer);
 
-	if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
-		cancel_delayed_work_sync(&conn->security_timer);
-		smp_chan_destroy(conn);
-	}
-
 	hcon->l2cap_data = NULL;
 	conn->hchan = NULL;
 	l2cap_conn_put(conn);
 }
 
-static void security_timeout(struct work_struct *work)
-{
-	struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
-					       security_timer.work);
-
-	BT_DBG("conn %p", conn);
-
-	if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
-		smp_chan_destroy(conn);
-		l2cap_conn_del(conn->hcon, ETIMEDOUT);
-	}
-}
-
 static void l2cap_conn_free(struct kref *ref)
 {
 	struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref);
@@ -1750,9 +1693,10 @@
 	kfree(conn);
 }
 
-void l2cap_conn_get(struct l2cap_conn *conn)
+struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn)
 {
 	kref_get(&conn->ref);
+	return conn;
 }
 EXPORT_SYMBOL(l2cap_conn_get);
 
@@ -1794,6 +1738,7 @@
 			src_match = !bacmp(&c->src, src);
 			dst_match = !bacmp(&c->dst, dst);
 			if (src_match && dst_match) {
+				l2cap_chan_hold(c);
 				read_unlock(&chan_list_lock);
 				return c;
 			}
@@ -1807,6 +1752,9 @@
 		}
 	}
 
+	if (c1)
+		l2cap_chan_hold(c1);
+
 	read_unlock(&chan_list_lock);
 
 	return c1;
@@ -2027,10 +1975,12 @@
 					   tx_skb->data + L2CAP_HDR_SIZE);
 		}
 
+		/* Update FCS */
 		if (chan->fcs == L2CAP_FCS_CRC16) {
-			u16 fcs = crc16(0, (u8 *) tx_skb->data, tx_skb->len);
-			put_unaligned_le16(fcs, skb_put(tx_skb,
-							L2CAP_FCS_SIZE));
+			u16 fcs = crc16(0, (u8 *) tx_skb->data,
+					tx_skb->len - L2CAP_FCS_SIZE);
+			put_unaligned_le16(fcs, skb_tail_pointer(tx_skb) -
+						L2CAP_FCS_SIZE);
 		}
 
 		l2cap_do_send(chan, tx_skb);
@@ -2334,7 +2284,6 @@
 	} else {
 		sar = L2CAP_SAR_START;
 		sdu_len = len;
-		pdu_len -= L2CAP_SDULEN_SIZE;
 	}
 
 	while (len > 0) {
@@ -2349,10 +2298,8 @@
 		__skb_queue_tail(seg_queue, skb);
 
 		len -= pdu_len;
-		if (sdu_len) {
+		if (sdu_len)
 			sdu_len = 0;
-			pdu_len += L2CAP_SDULEN_SIZE;
-		}
 
 		if (len <= pdu_len) {
 			sar = L2CAP_SAR_END;
@@ -2418,12 +2365,8 @@
 
 	BT_DBG("chan %p, msg %p, len %zu", chan, msg, len);
 
-	pdu_len = chan->conn->mtu - L2CAP_HDR_SIZE;
-
-	pdu_len = min_t(size_t, pdu_len, chan->remote_mps);
-
 	sdu_len = len;
-	pdu_len -= L2CAP_SDULEN_SIZE;
+	pdu_len = chan->remote_mps - L2CAP_SDULEN_SIZE;
 
 	while (len > 0) {
 		if (len <= pdu_len)
@@ -3884,6 +3827,7 @@
 response:
 	l2cap_chan_unlock(pchan);
 	mutex_unlock(&conn->chan_lock);
+	l2cap_chan_put(pchan);
 
 sendresp:
 	rsp.scid   = cpu_to_le16(scid);
@@ -5487,6 +5431,11 @@
 
 	if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
 		l2cap_state_change(chan, BT_CONNECT2);
+		/* The following result value is actually not defined
+		 * for LE CoC but we use it to let the function know
+		 * that it should bail out after doing its cleanup
+		 * instead of sending a response.
+		 */
 		result = L2CAP_CR_PEND;
 		chan->ops->defer(chan);
 	} else {
@@ -5497,6 +5446,7 @@
 response_unlock:
 	l2cap_chan_unlock(pchan);
 	mutex_unlock(&conn->chan_lock);
+	l2cap_chan_put(pchan);
 
 	if (result == L2CAP_CR_PEND)
 		return 0;
@@ -6845,12 +6795,12 @@
 	struct l2cap_chan *chan;
 
 	if (hcon->type != ACL_LINK)
-		goto drop;
+		goto free_skb;
 
 	chan = l2cap_global_chan_by_psm(0, psm, &hcon->src, &hcon->dst,
 					ACL_LINK);
 	if (!chan)
-		goto drop;
+		goto free_skb;
 
 	BT_DBG("chan %p, len %d", chan, skb->len);
 
@@ -6864,36 +6814,14 @@
 	bacpy(&bt_cb(skb)->bdaddr, &hcon->dst);
 	bt_cb(skb)->psm = psm;
 
-	if (!chan->ops->recv(chan, skb))
+	if (!chan->ops->recv(chan, skb)) {
+		l2cap_chan_put(chan);
 		return;
+	}
 
 drop:
-	kfree_skb(skb);
-}
-
-static void l2cap_att_channel(struct l2cap_conn *conn,
-			      struct sk_buff *skb)
-{
-	struct hci_conn *hcon = conn->hcon;
-	struct l2cap_chan *chan;
-
-	if (hcon->type != LE_LINK)
-		goto drop;
-
-	chan = l2cap_global_chan_by_scid(BT_CONNECTED, L2CAP_CID_ATT,
-					 &hcon->src, &hcon->dst);
-	if (!chan)
-		goto drop;
-
-	BT_DBG("chan %p, len %d", chan, skb->len);
-
-	if (chan->imtu < skb->len)
-		goto drop;
-
-	if (!chan->ops->recv(chan, skb))
-		return;
-
-drop:
+	l2cap_chan_put(chan);
+free_skb:
 	kfree_skb(skb);
 }
 
@@ -6942,19 +6870,10 @@
 		l2cap_conless_channel(conn, psm, skb);
 		break;
 
-	case L2CAP_CID_ATT:
-		l2cap_att_channel(conn, skb);
-		break;
-
 	case L2CAP_CID_LE_SIGNALING:
 		l2cap_le_sig_channel(conn, skb);
 		break;
 
-	case L2CAP_CID_SMP:
-		if (smp_sig_channel(conn, skb))
-			l2cap_conn_del(conn->hcon, EACCES);
-		break;
-
 	default:
 		l2cap_data_channel(conn, cid, skb);
 		break;
@@ -6993,8 +6912,7 @@
 
 	kref_init(&conn->ref);
 	hcon->l2cap_data = conn;
-	conn->hcon = hcon;
-	hci_conn_get(conn->hcon);
+	conn->hcon = hci_conn_get(hcon);
 	conn->hchan = hchan;
 
 	BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
@@ -7023,13 +6941,11 @@
 	INIT_LIST_HEAD(&conn->chan_l);
 	INIT_LIST_HEAD(&conn->users);
 
-	if (hcon->type == LE_LINK)
-		INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
-	else
-		INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
+	INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
 
 	skb_queue_head_init(&conn->pending_rx);
 	INIT_WORK(&conn->pending_rx_work, process_pending_rx);
+	INIT_WORK(&conn->id_addr_update_work, l2cap_conn_update_id_addr);
 
 	conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
 
@@ -7064,8 +6980,6 @@
 
 	hci_dev_lock(hdev);
 
-	l2cap_chan_lock(chan);
-
 	if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid &&
 	    chan->chan_type != L2CAP_CHAN_RAW) {
 		err = -EINVAL;
@@ -7162,19 +7076,20 @@
 		goto done;
 	}
 
+	mutex_lock(&conn->chan_lock);
+	l2cap_chan_lock(chan);
+
 	if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
 		hci_conn_drop(hcon);
 		err = -EBUSY;
-		goto done;
+		goto chan_unlock;
 	}
 
 	/* Update source addr of the socket */
 	bacpy(&chan->src, &hcon->src);
 	chan->src_type = bdaddr_type(hcon, hcon->src_type);
 
-	l2cap_chan_unlock(chan);
-	l2cap_chan_add(conn, chan);
-	l2cap_chan_lock(chan);
+	__l2cap_chan_add(conn, chan);
 
 	/* l2cap_chan_add takes its own ref so we can drop this one */
 	hci_conn_drop(hcon);
@@ -7200,8 +7115,10 @@
 
 	err = 0;
 
-done:
+chan_unlock:
 	l2cap_chan_unlock(chan);
+	mutex_unlock(&conn->chan_lock);
+done:
 	hci_dev_unlock(hdev);
 	hci_dev_put(hdev);
 	return err;
@@ -7239,19 +7156,99 @@
 	return exact ? lm1 : lm2;
 }
 
+/* Find the next fixed channel in BT_LISTEN state, continue iteration
+ * from an existing channel in the list or from the beginning of the
+ * global list (by passing NULL as first parameter).
+ */
+static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c,
+						  bdaddr_t *src, u8 link_type)
+{
+	read_lock(&chan_list_lock);
+
+	if (c)
+		c = list_next_entry(c, global_l);
+	else
+		c = list_entry(chan_list.next, typeof(*c), global_l);
+
+	list_for_each_entry_from(c, &chan_list, global_l) {
+		if (c->chan_type != L2CAP_CHAN_FIXED)
+			continue;
+		if (c->state != BT_LISTEN)
+			continue;
+		if (bacmp(&c->src, src) && bacmp(&c->src, BDADDR_ANY))
+			continue;
+		if (link_type == ACL_LINK && c->src_type != BDADDR_BREDR)
+			continue;
+		if (link_type == LE_LINK && c->src_type == BDADDR_BREDR)
+			continue;
+
+		l2cap_chan_hold(c);
+		read_unlock(&chan_list_lock);
+		return c;
+	}
+
+	read_unlock(&chan_list_lock);
+
+	return NULL;
+}
+
 void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
 {
+	struct hci_dev *hdev = hcon->hdev;
 	struct l2cap_conn *conn;
+	struct l2cap_chan *pchan;
+	u8 dst_type;
 
 	BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
 
-	if (!status) {
-		conn = l2cap_conn_add(hcon);
-		if (conn)
-			l2cap_conn_ready(conn);
-	} else {
+	if (status) {
 		l2cap_conn_del(hcon, bt_to_errno(status));
+		return;
 	}
+
+	conn = l2cap_conn_add(hcon);
+	if (!conn)
+		return;
+
+	dst_type = bdaddr_type(hcon, hcon->dst_type);
+
+	/* If device is blocked, do not create channels for it */
+	if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type))
+		return;
+
+	/* Find fixed channels and notify them of the new connection. We
+	 * use multiple individual lookups, continuing each time where
+	 * we left off, because the list lock would prevent calling the
+	 * potentially sleeping l2cap_chan_lock() function.
+	 */
+	pchan = l2cap_global_fixed_chan(NULL, &hdev->bdaddr, hcon->type);
+	while (pchan) {
+		struct l2cap_chan *chan, *next;
+
+		/* Client fixed channels should override server ones */
+		if (__l2cap_get_chan_by_dcid(conn, pchan->scid))
+			goto next;
+
+		l2cap_chan_lock(pchan);
+		chan = pchan->ops->new_connection(pchan);
+		if (chan) {
+			bacpy(&chan->src, &hcon->src);
+			bacpy(&chan->dst, &hcon->dst);
+			chan->src_type = bdaddr_type(hcon, hcon->src_type);
+			chan->dst_type = dst_type;
+
+			__l2cap_chan_add(conn, chan);
+		}
+
+		l2cap_chan_unlock(pchan);
+next:
+		next = l2cap_global_fixed_chan(pchan, &hdev->bdaddr,
+					       hcon->type);
+		l2cap_chan_put(pchan);
+		pchan = next;
+	}
+
+	l2cap_conn_ready(conn);
 }
 
 int l2cap_disconn_ind(struct hci_conn *hcon)
@@ -7299,12 +7296,6 @@
 
 	BT_DBG("conn %p status 0x%2.2x encrypt %u", conn, status, encrypt);
 
-	if (hcon->type == LE_LINK) {
-		if (!status && encrypt)
-			smp_distribute_keys(conn);
-		cancel_delayed_work(&conn->security_timer);
-	}
-
 	mutex_lock(&conn->chan_lock);
 
 	list_for_each_entry(chan, &conn->chan_l, list) {
@@ -7318,15 +7309,8 @@
 			continue;
 		}
 
-		if (chan->scid == L2CAP_CID_ATT) {
-			if (!status && encrypt) {
-				chan->sec_level = hcon->sec_level;
-				l2cap_chan_ready(chan);
-			}
-
-			l2cap_chan_unlock(chan);
-			continue;
-		}
+		if (!status && encrypt)
+			chan->sec_level = hcon->sec_level;
 
 		if (!__l2cap_no_conn_pending(chan)) {
 			l2cap_chan_unlock(chan);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 4a941cd..c53387f 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -99,15 +99,6 @@
 	if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
 		return -EINVAL;
 
-	if (la.l2_cid) {
-		/* When the socket gets created it defaults to
-		 * CHAN_CONN_ORIENTED, so we need to overwrite the
-		 * default here.
-		 */
-		chan->chan_type = L2CAP_CHAN_FIXED;
-		chan->omtu = L2CAP_DEFAULT_MTU;
-	}
-
 	if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
 		/* We only allow ATT user space socket */
 		if (la.l2_cid &&
@@ -155,6 +146,14 @@
 	case L2CAP_CHAN_RAW:
 		chan->sec_level = BT_SECURITY_SDP;
 		break;
+	case L2CAP_CHAN_FIXED:
+		/* Fixed channels default to the L2CAP core not holding a
+		 * hci_conn reference for them. For fixed channels mapping to
+		 * L2CAP sockets we do want to hold a reference so set the
+		 * appropriate flag to request it.
+		 */
+		set_bit(FLAG_HOLD_HCI_CONN, &chan->flags);
+		break;
 	}
 
 	bacpy(&chan->src, &la.l2_bdaddr);
@@ -790,6 +789,7 @@
 		if (chan->scid == L2CAP_CID_ATT) {
 			if (smp_conn_security(conn->hcon, sec.level))
 				break;
+			set_bit(FLAG_PENDING_SECURITY, &chan->flags);
 			sk->sk_state = BT_CONFIG;
 			chan->state = BT_CONFIG;
 
@@ -1373,6 +1373,11 @@
 {
 	struct sock *sk = chan->data;
 
+	if (test_and_clear_bit(FLAG_PENDING_SECURITY, &chan->flags)) {
+		sk->sk_state = BT_CONNECTED;
+		chan->state = BT_CONNECTED;
+	}
+
 	clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
 	sk->sk_state_change(sk);
 }
diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c
index 941ad75..b36bc04 100644
--- a/net/bluetooth/lib.c
+++ b/net/bluetooth/lib.c
@@ -135,40 +135,34 @@
 }
 EXPORT_SYMBOL(bt_to_errno);
 
-int bt_info(const char *format, ...)
+void bt_info(const char *format, ...)
 {
 	struct va_format vaf;
 	va_list args;
-	int r;
 
 	va_start(args, format);
 
 	vaf.fmt = format;
 	vaf.va = &args;
 
-	r = pr_info("%pV", &vaf);
+	pr_info("%pV", &vaf);
 
 	va_end(args);
-
-	return r;
 }
 EXPORT_SYMBOL(bt_info);
 
-int bt_err(const char *format, ...)
+void bt_err(const char *format, ...)
 {
 	struct va_format vaf;
 	va_list args;
-	int r;
 
 	va_start(args, format);
 
 	vaf.fmt = format;
 	vaf.va = &args;
 
-	r = pr_err("%pV", &vaf);
+	pr_err("%pV", &vaf);
 
 	va_end(args);
-
-	return r;
 }
 EXPORT_SYMBOL(bt_err);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index b8554d4..efb71b0 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -129,9 +129,6 @@
 
 #define CACHE_TIMEOUT	msecs_to_jiffies(2 * 1000)
 
-#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
-				!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
-
 struct pending_cmd {
 	struct list_head list;
 	u16 opcode;
@@ -1536,9 +1533,11 @@
 
 	/* When the discoverable mode gets changed, make sure
 	 * that class of device has the limited discoverable
-	 * bit correctly set.
+	 * bit correctly set. Also update page scan based on whitelist
+	 * entries.
 	 */
 	hci_req_init(&req, hdev);
+	hci_update_page_scan(hdev, &req);
 	update_class(&req);
 	hci_req_run(&req, NULL);
 
@@ -1785,6 +1784,7 @@
 
 	if (conn_changed || discov_changed) {
 		new_settings(hdev, cmd->sk);
+		hci_update_page_scan(hdev, NULL);
 		if (discov_changed)
 			mgmt_update_adv_data(hdev);
 		hci_update_background_scan(hdev);
@@ -1818,6 +1818,7 @@
 		return err;
 
 	if (changed) {
+		hci_update_page_scan(hdev, NULL);
 		hci_update_background_scan(hdev);
 		return new_settings(hdev, sk);
 	}
@@ -2787,7 +2788,6 @@
 {
 	struct mgmt_cp_disconnect *cp = data;
 	struct mgmt_rp_disconnect rp;
-	struct hci_cp_disconnect dc;
 	struct pending_cmd *cmd;
 	struct hci_conn *conn;
 	int err;
@@ -2835,10 +2835,7 @@
 		goto failed;
 	}
 
-	dc.handle = cpu_to_le16(conn->handle);
-	dc.reason = HCI_ERROR_REMOTE_USER_TERM;
-
-	err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
+	err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
 	if (err < 0)
 		mgmt_pending_remove(cmd);
 
@@ -3062,6 +3059,7 @@
 	conn->disconn_cfm_cb = NULL;
 
 	hci_conn_drop(conn);
+	hci_conn_put(conn);
 
 	mgmt_pending_remove(cmd);
 }
@@ -3211,7 +3209,7 @@
 	}
 
 	conn->io_capability = cp->io_cap;
-	cmd->user_data = conn;
+	cmd->user_data = hci_conn_get(conn);
 
 	if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
 	    hci_conn_security(conn, sec_level, auth_type, true))
@@ -4381,27 +4379,6 @@
 	return err;
 }
 
-static void set_bredr_scan(struct hci_request *req)
-{
-	struct hci_dev *hdev = req->hdev;
-	u8 scan = 0;
-
-	/* Ensure that fast connectable is disabled. This function will
-	 * not do anything if the page scan parameters are already what
-	 * they should be.
-	 */
-	write_fast_connectable(req, false);
-
-	if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
-	    !list_empty(&hdev->whitelist))
-		scan |= SCAN_PAGE;
-	if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
-		scan |= SCAN_INQUIRY;
-
-	if (scan)
-		hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-}
-
 static void set_bredr_complete(struct hci_dev *hdev, u8 status)
 {
 	struct pending_cmd *cmd;
@@ -4507,9 +4484,8 @@
 
 	hci_req_init(&req, hdev);
 
-	if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
-	    !list_empty(&hdev->whitelist))
-		set_bredr_scan(&req);
+	write_fast_connectable(&req, false);
+	hci_update_page_scan(hdev, &req);
 
 	/* Since only the advertising data flags will change, there
 	 * is no need to update the scan response data.
@@ -4935,6 +4911,7 @@
 		     match->mgmt_status, &rp, sizeof(rp));
 
 	hci_conn_drop(conn);
+	hci_conn_put(conn);
 
 	mgmt_pending_remove(cmd);
 }
@@ -5091,7 +5068,7 @@
 		}
 
 		hci_conn_hold(conn);
-		cmd->user_data = conn;
+		cmd->user_data = hci_conn_get(conn);
 
 		conn->conn_info_timestamp = jiffies;
 	} else {
@@ -5155,8 +5132,10 @@
 	cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
 		     &rp, sizeof(rp));
 	mgmt_pending_remove(cmd);
-	if (conn)
+	if (conn) {
 		hci_conn_drop(conn);
+		hci_conn_put(conn);
+	}
 
 unlock:
 	hci_dev_unlock(hdev);
@@ -5219,7 +5198,7 @@
 
 	if (conn) {
 		hci_conn_hold(conn);
-		cmd->user_data = conn;
+		cmd->user_data = hci_conn_get(conn);
 
 		hci_cp.handle = cpu_to_le16(conn->handle);
 		hci_cp.which = 0x01; /* Piconet clock */
@@ -5235,27 +5214,6 @@
 	return err;
 }
 
-/* Helper for Add/Remove Device commands */
-static void update_page_scan(struct hci_dev *hdev, u8 scan)
-{
-	if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
-		return;
-
-	if (!hdev_is_powered(hdev))
-		return;
-
-	/* If HCI_CONNECTABLE is set then Add/Remove Device should not
-	 * make any changes to page scanning.
-	 */
-	if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
-		return;
-
-	if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
-		scan |= SCAN_INQUIRY;
-
-	hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-}
-
 static void device_added(struct sock *sk, struct hci_dev *hdev,
 			 bdaddr_t *bdaddr, u8 type, u8 action)
 {
@@ -5291,8 +5249,6 @@
 	hci_dev_lock(hdev);
 
 	if (cp->addr.type == BDADDR_BREDR) {
-		bool update_scan;
-
 		/* Only incoming connections action is supported for now */
 		if (cp->action != 0x01) {
 			err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
@@ -5301,15 +5257,12 @@
 			goto unlock;
 		}
 
-		update_scan = list_empty(&hdev->whitelist);
-
 		err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
 					  cp->addr.type);
 		if (err)
 			goto unlock;
 
-		if (update_scan)
-			update_page_scan(hdev, SCAN_PAGE);
+		hci_update_page_scan(hdev, NULL);
 
 		goto added;
 	}
@@ -5392,8 +5345,7 @@
 				goto unlock;
 			}
 
-			if (list_empty(&hdev->whitelist))
-				update_page_scan(hdev, SCAN_DISABLED);
+			hci_update_page_scan(hdev, NULL);
 
 			device_removed(sk, hdev, &cp->addr.bdaddr,
 				       cp->addr.type);
@@ -5444,7 +5396,7 @@
 			kfree(b);
 		}
 
-		update_page_scan(hdev, SCAN_DISABLED);
+		hci_update_page_scan(hdev, NULL);
 
 		list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
 			if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
@@ -5969,8 +5921,8 @@
 			    sizeof(link_sec), &link_sec);
 
 	if (lmp_bredr_capable(hdev)) {
-		if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
-			set_bredr_scan(&req);
+		write_fast_connectable(&req, false);
+		hci_update_page_scan(hdev, &req);
 		update_class(&req);
 		update_name(&req);
 		update_eir(&req);
@@ -6281,25 +6233,35 @@
 	mgmt_pending_remove(cmd);
 }
 
+bool mgmt_powering_down(struct hci_dev *hdev)
+{
+	struct pending_cmd *cmd;
+	struct mgmt_mode *cp;
+
+	cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
+	if (!cmd)
+		return false;
+
+	cp = cmd->param;
+	if (!cp->val)
+		return true;
+
+	return false;
+}
+
 void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
 			      u8 link_type, u8 addr_type, u8 reason,
 			      bool mgmt_connected)
 {
 	struct mgmt_ev_device_disconnected ev;
-	struct pending_cmd *power_off;
 	struct sock *sk = NULL;
 
-	power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
-	if (power_off) {
-		struct mgmt_mode *cp = power_off->param;
-
-		/* The connection is still in hci_conn_hash so test for 1
-		 * instead of 0 to know if this is the last one.
-		 */
-		if (!cp->val && hci_conn_count(hdev) == 1) {
-			cancel_delayed_work(&hdev->power_off);
-			queue_work(hdev->req_workqueue, &hdev->power_off.work);
-		}
+	/* The connection is still in hci_conn_hash so test for 1
+	 * instead of 0 to know if this is the last one.
+	 */
+	if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
+		cancel_delayed_work(&hdev->power_off);
+		queue_work(hdev->req_workqueue, &hdev->power_off.work);
 	}
 
 	if (!mgmt_connected)
@@ -6359,19 +6321,13 @@
 			 u8 addr_type, u8 status)
 {
 	struct mgmt_ev_connect_failed ev;
-	struct pending_cmd *power_off;
 
-	power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
-	if (power_off) {
-		struct mgmt_mode *cp = power_off->param;
-
-		/* The connection is still in hci_conn_hash so test for 1
-		 * instead of 0 to know if this is the last one.
-		 */
-		if (!cp->val && hci_conn_count(hdev) == 1) {
-			cancel_delayed_work(&hdev->power_off);
-			queue_work(hdev->req_workqueue, &hdev->power_off.work);
-		}
+	/* The connection is still in hci_conn_hash so test for 1
+	 * instead of 0 to know if this is the last one.
+	 */
+	if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
+		cancel_delayed_work(&hdev->power_off);
+		queue_work(hdev->req_workqueue, &hdev->power_off.work);
 	}
 
 	bacpy(&ev.addr.bdaddr, bdaddr);
@@ -6529,16 +6485,23 @@
 	return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
 }
 
-void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-		      u8 addr_type, u8 status)
+void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
 {
 	struct mgmt_ev_auth_failed ev;
+	struct pending_cmd *cmd;
+	u8 status = mgmt_status(hci_status);
 
-	bacpy(&ev.addr.bdaddr, bdaddr);
-	ev.addr.type = link_to_bdaddr(link_type, addr_type);
-	ev.status = mgmt_status(status);
+	bacpy(&ev.addr.bdaddr, &conn->dst);
+	ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
+	ev.status = status;
 
-	mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
+	cmd = find_pairing(conn);
+
+	mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
+		    cmd ? cmd->sk : NULL);
+
+	if (cmd)
+		pairing_complete(cmd, status);
 }
 
 void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index fd32943..f09b6b6 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -31,9 +31,12 @@
 
 #include "smp.h"
 
+#define SMP_ALLOW_CMD(smp, code)	set_bit(code, &smp->allow_cmd)
+
 #define SMP_TIMEOUT	msecs_to_jiffies(30000)
 
 #define AUTH_REQ_MASK   0x07
+#define KEY_DIST_MASK	0x07
 
 enum {
 	SMP_FLAG_TK_VALID,
@@ -44,7 +47,10 @@
 };
 
 struct smp_chan {
-	struct l2cap_conn *conn;
+	struct l2cap_conn	*conn;
+	struct delayed_work	security_timer;
+	unsigned long           allow_cmd; /* Bitmask of allowed commands */
+
 	u8		preq[7]; /* SMP Pairing Request */
 	u8		prsp[7]; /* SMP Pairing Response */
 	u8		prnd[16]; /* SMP Pairing Random (local) */
@@ -139,12 +145,18 @@
 	return 0;
 }
 
-bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
-		     bdaddr_t *bdaddr)
+bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr)
 {
+	struct l2cap_chan *chan = hdev->smp_data;
+	struct crypto_blkcipher *tfm;
 	u8 hash[3];
 	int err;
 
+	if (!chan || !chan->data)
+		return false;
+
+	tfm = chan->data;
+
 	BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk);
 
 	err = smp_ah(tfm, irk, &bdaddr->b[3], hash);
@@ -154,10 +166,17 @@
 	return !memcmp(bdaddr->b, hash, 3);
 }
 
-int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa)
+int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa)
 {
+	struct l2cap_chan *chan = hdev->smp_data;
+	struct crypto_blkcipher *tfm;
 	int err;
 
+	if (!chan || !chan->data)
+		return -EOPNOTSUPP;
+
+	tfm = chan->data;
+
 	get_random_bytes(&rpa->b[3], 3);
 
 	rpa->b[5] &= 0x3f;	/* Clear two most significant bits */
@@ -235,47 +254,38 @@
 	return err;
 }
 
-static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
-				     u16 dlen, void *data)
-{
-	struct sk_buff *skb;
-	struct l2cap_hdr *lh;
-	int len;
-
-	len = L2CAP_HDR_SIZE + sizeof(code) + dlen;
-
-	if (len > conn->mtu)
-		return NULL;
-
-	skb = bt_skb_alloc(len, GFP_ATOMIC);
-	if (!skb)
-		return NULL;
-
-	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-	lh->len = cpu_to_le16(sizeof(code) + dlen);
-	lh->cid = cpu_to_le16(L2CAP_CID_SMP);
-
-	memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
-
-	memcpy(skb_put(skb, dlen), data, dlen);
-
-	return skb;
-}
-
 static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
 {
-	struct sk_buff *skb = smp_build_cmd(conn, code, len, data);
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp;
+	struct kvec iv[2];
+	struct msghdr msg;
+
+	if (!chan)
+		return;
 
 	BT_DBG("code 0x%2.2x", code);
 
-	if (!skb)
+	iv[0].iov_base = &code;
+	iv[0].iov_len = 1;
+
+	iv[1].iov_base = data;
+	iv[1].iov_len = len;
+
+	memset(&msg, 0, sizeof(msg));
+
+	msg.msg_iov = (struct iovec *) &iv;
+	msg.msg_iovlen = 2;
+
+	l2cap_chan_send(chan, &msg, 1 + len);
+
+	if (!chan->data)
 		return;
 
-	skb->priority = HCI_PRIO_MAX;
-	hci_send_acl(conn->hchan, skb, 0);
+	smp = chan->data;
 
-	cancel_delayed_work_sync(&conn->security_timer);
-	schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT);
+	cancel_delayed_work_sync(&smp->security_timer);
+	schedule_delayed_work(&smp->security_timer, SMP_TIMEOUT);
 }
 
 static __u8 authreq_to_seclevel(__u8 authreq)
@@ -302,7 +312,8 @@
 			      struct smp_cmd_pairing *req,
 			      struct smp_cmd_pairing *rsp, __u8 authreq)
 {
-	struct smp_chan *smp = conn->smp_chan;
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
 	struct hci_conn *hcon = conn->hcon;
 	struct hci_dev *hdev = hcon->hdev;
 	u8 local_dist = 0, remote_dist = 0;
@@ -345,7 +356,8 @@
 
 static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
 {
-	struct smp_chan *smp = conn->smp_chan;
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
 
 	if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
 	    (max_key_size < SMP_MIN_ENC_KEY_SIZE))
@@ -356,21 +368,60 @@
 	return 0;
 }
 
+static void smp_chan_destroy(struct l2cap_conn *conn)
+{
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
+	bool complete;
+
+	BUG_ON(!smp);
+
+	cancel_delayed_work_sync(&smp->security_timer);
+
+	complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags);
+	mgmt_smp_complete(conn->hcon, complete);
+
+	kfree(smp->csrk);
+	kfree(smp->slave_csrk);
+
+	crypto_free_blkcipher(smp->tfm_aes);
+
+	/* If pairing failed clean up any keys we might have */
+	if (!complete) {
+		if (smp->ltk) {
+			list_del(&smp->ltk->list);
+			kfree(smp->ltk);
+		}
+
+		if (smp->slave_ltk) {
+			list_del(&smp->slave_ltk->list);
+			kfree(smp->slave_ltk);
+		}
+
+		if (smp->remote_irk) {
+			list_del(&smp->remote_irk->list);
+			kfree(smp->remote_irk);
+		}
+	}
+
+	chan->data = NULL;
+	kfree(smp);
+	hci_conn_drop(conn->hcon);
+}
+
 static void smp_failure(struct l2cap_conn *conn, u8 reason)
 {
 	struct hci_conn *hcon = conn->hcon;
+	struct l2cap_chan *chan = conn->smp;
 
 	if (reason)
 		smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
 			     &reason);
 
 	clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags);
-	mgmt_auth_failed(hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type,
-			 HCI_ERROR_AUTH_FAILURE);
+	mgmt_auth_failed(hcon, HCI_ERROR_AUTH_FAILURE);
 
-	cancel_delayed_work_sync(&conn->security_timer);
-
-	if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
+	if (chan->data)
 		smp_chan_destroy(conn);
 }
 
@@ -405,7 +456,8 @@
 						u8 local_io, u8 remote_io)
 {
 	struct hci_conn *hcon = conn->hcon;
-	struct smp_chan *smp = conn->smp_chan;
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
 	u8 method;
 	u32 passkey = 0;
 	int ret = 0;
@@ -442,8 +494,11 @@
 	}
 
 	/* Not Just Works/Confirm results in MITM Authentication */
-	if (method != JUST_CFM)
+	if (method != JUST_CFM) {
 		set_bit(SMP_FLAG_MITM_AUTH, &smp->flags);
+		if (hcon->pending_sec_level < BT_SECURITY_HIGH)
+			hcon->pending_sec_level = BT_SECURITY_HIGH;
+	}
 
 	/* If both devices have Keyoard-Display I/O, the master
 	 * Confirms and the slave Enters the passkey.
@@ -503,6 +558,11 @@
 
 	smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
 
+	if (conn->hcon->out)
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
+	else
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
+
 	return 0;
 }
 
@@ -574,711 +634,10 @@
 	return 0;
 }
 
-static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
-{
-	struct smp_chan *smp;
-
-	smp = kzalloc(sizeof(*smp), GFP_ATOMIC);
-	if (!smp) {
-		clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
-		return NULL;
-	}
-
-	smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
-	if (IS_ERR(smp->tfm_aes)) {
-		BT_ERR("Unable to create ECB crypto context");
-		kfree(smp);
-		clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
-		return NULL;
-	}
-
-	smp->conn = conn;
-	conn->smp_chan = smp;
-
-	hci_conn_hold(conn->hcon);
-
-	return smp;
-}
-
-void smp_chan_destroy(struct l2cap_conn *conn)
-{
-	struct smp_chan *smp = conn->smp_chan;
-	bool complete;
-
-	BUG_ON(!smp);
-
-	complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags);
-	mgmt_smp_complete(conn->hcon, complete);
-
-	kfree(smp->csrk);
-	kfree(smp->slave_csrk);
-
-	crypto_free_blkcipher(smp->tfm_aes);
-
-	/* If pairing failed clean up any keys we might have */
-	if (!complete) {
-		if (smp->ltk) {
-			list_del(&smp->ltk->list);
-			kfree(smp->ltk);
-		}
-
-		if (smp->slave_ltk) {
-			list_del(&smp->slave_ltk->list);
-			kfree(smp->slave_ltk);
-		}
-
-		if (smp->remote_irk) {
-			list_del(&smp->remote_irk->list);
-			kfree(smp->remote_irk);
-		}
-	}
-
-	kfree(smp);
-	conn->smp_chan = NULL;
-	hci_conn_drop(conn->hcon);
-}
-
-int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
-{
-	struct l2cap_conn *conn = hcon->l2cap_data;
-	struct smp_chan *smp;
-	u32 value;
-
-	BT_DBG("");
-
-	if (!conn || !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
-		return -ENOTCONN;
-
-	smp = conn->smp_chan;
-
-	switch (mgmt_op) {
-	case MGMT_OP_USER_PASSKEY_REPLY:
-		value = le32_to_cpu(passkey);
-		memset(smp->tk, 0, sizeof(smp->tk));
-		BT_DBG("PassKey: %d", value);
-		put_unaligned_le32(value, smp->tk);
-		/* Fall Through */
-	case MGMT_OP_USER_CONFIRM_REPLY:
-		set_bit(SMP_FLAG_TK_VALID, &smp->flags);
-		break;
-	case MGMT_OP_USER_PASSKEY_NEG_REPLY:
-	case MGMT_OP_USER_CONFIRM_NEG_REPLY:
-		smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED);
-		return 0;
-	default:
-		smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED);
-		return -EOPNOTSUPP;
-	}
-
-	/* If it is our turn to send Pairing Confirm, do so now */
-	if (test_bit(SMP_FLAG_CFM_PENDING, &smp->flags)) {
-		u8 rsp = smp_confirm(smp);
-		if (rsp)
-			smp_failure(conn, rsp);
-	}
-
-	return 0;
-}
-
-static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	struct smp_cmd_pairing rsp, *req = (void *) skb->data;
-	struct hci_dev *hdev = conn->hcon->hdev;
-	struct smp_chan *smp;
-	u8 key_size, auth, sec_level;
-	int ret;
-
-	BT_DBG("conn %p", conn);
-
-	if (skb->len < sizeof(*req))
-		return SMP_INVALID_PARAMS;
-
-	if (conn->hcon->role != HCI_ROLE_SLAVE)
-		return SMP_CMD_NOTSUPP;
-
-	if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
-		smp = smp_chan_create(conn);
-	else
-		smp = conn->smp_chan;
-
-	if (!smp)
-		return SMP_UNSPECIFIED;
-
-	if (!test_bit(HCI_BONDABLE, &hdev->dev_flags) &&
-	    (req->auth_req & SMP_AUTH_BONDING))
-		return SMP_PAIRING_NOTSUPP;
-
-	smp->preq[0] = SMP_CMD_PAIRING_REQ;
-	memcpy(&smp->preq[1], req, sizeof(*req));
-	skb_pull(skb, sizeof(*req));
-
-	/* We didn't start the pairing, so match remote */
-	auth = req->auth_req;
-
-	sec_level = authreq_to_seclevel(auth);
-	if (sec_level > conn->hcon->pending_sec_level)
-		conn->hcon->pending_sec_level = sec_level;
-
-	/* If we need MITM check that it can be acheived */
-	if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
-		u8 method;
-
-		method = get_auth_method(smp, conn->hcon->io_capability,
-					 req->io_capability);
-		if (method == JUST_WORKS || method == JUST_CFM)
-			return SMP_AUTH_REQUIREMENTS;
-	}
-
-	build_pairing_cmd(conn, req, &rsp, auth);
-
-	key_size = min(req->max_key_size, rsp.max_key_size);
-	if (check_enc_key_size(conn, key_size))
-		return SMP_ENC_KEY_SIZE;
-
-	get_random_bytes(smp->prnd, sizeof(smp->prnd));
-
-	smp->prsp[0] = SMP_CMD_PAIRING_RSP;
-	memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
-
-	smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
-
-	/* Request setup of TK */
-	ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability);
-	if (ret)
-		return SMP_UNSPECIFIED;
-
-	return 0;
-}
-
-static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
-	struct smp_chan *smp = conn->smp_chan;
-	u8 key_size, auth = SMP_AUTH_NONE;
-	int ret;
-
-	BT_DBG("conn %p", conn);
-
-	if (skb->len < sizeof(*rsp))
-		return SMP_INVALID_PARAMS;
-
-	if (conn->hcon->role != HCI_ROLE_MASTER)
-		return SMP_CMD_NOTSUPP;
-
-	skb_pull(skb, sizeof(*rsp));
-
-	req = (void *) &smp->preq[1];
-
-	key_size = min(req->max_key_size, rsp->max_key_size);
-	if (check_enc_key_size(conn, key_size))
-		return SMP_ENC_KEY_SIZE;
-
-	/* If we need MITM check that it can be acheived */
-	if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
-		u8 method;
-
-		method = get_auth_method(smp, req->io_capability,
-					 rsp->io_capability);
-		if (method == JUST_WORKS || method == JUST_CFM)
-			return SMP_AUTH_REQUIREMENTS;
-	}
-
-	get_random_bytes(smp->prnd, sizeof(smp->prnd));
-
-	smp->prsp[0] = SMP_CMD_PAIRING_RSP;
-	memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
-
-	/* Update remote key distribution in case the remote cleared
-	 * some bits that we had enabled in our request.
-	 */
-	smp->remote_key_dist &= rsp->resp_key_dist;
-
-	if ((req->auth_req & SMP_AUTH_BONDING) &&
-	    (rsp->auth_req & SMP_AUTH_BONDING))
-		auth = SMP_AUTH_BONDING;
-
-	auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM;
-
-	ret = tk_request(conn, 0, auth, req->io_capability, rsp->io_capability);
-	if (ret)
-		return SMP_UNSPECIFIED;
-
-	set_bit(SMP_FLAG_CFM_PENDING, &smp->flags);
-
-	/* Can't compose response until we have been confirmed */
-	if (test_bit(SMP_FLAG_TK_VALID, &smp->flags))
-		return smp_confirm(smp);
-
-	return 0;
-}
-
-static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	struct smp_chan *smp = conn->smp_chan;
-
-	BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
-
-	if (skb->len < sizeof(smp->pcnf))
-		return SMP_INVALID_PARAMS;
-
-	memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
-	skb_pull(skb, sizeof(smp->pcnf));
-
-	if (conn->hcon->out)
-		smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
-			     smp->prnd);
-	else if (test_bit(SMP_FLAG_TK_VALID, &smp->flags))
-		return smp_confirm(smp);
-	else
-		set_bit(SMP_FLAG_CFM_PENDING, &smp->flags);
-
-	return 0;
-}
-
-static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	struct smp_chan *smp = conn->smp_chan;
-
-	BT_DBG("conn %p", conn);
-
-	if (skb->len < sizeof(smp->rrnd))
-		return SMP_INVALID_PARAMS;
-
-	memcpy(smp->rrnd, skb->data, sizeof(smp->rrnd));
-	skb_pull(skb, sizeof(smp->rrnd));
-
-	return smp_random(smp);
-}
-
-static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
-{
-	struct smp_ltk *key;
-	struct hci_conn *hcon = conn->hcon;
-
-	key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type,
-				   hcon->role);
-	if (!key)
-		return false;
-
-	if (sec_level > BT_SECURITY_MEDIUM && !key->authenticated)
-		return false;
-
-	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
-		return true;
-
-	hci_le_start_enc(hcon, key->ediv, key->rand, key->val);
-	hcon->enc_key_size = key->enc_size;
-
-	/* We never store STKs for master role, so clear this flag */
-	clear_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags);
-
-	return true;
-}
-
-bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level)
-{
-	if (sec_level == BT_SECURITY_LOW)
-		return true;
-
-	/* If we're encrypted with an STK always claim insufficient
-	 * security. This way we allow the connection to be re-encrypted
-	 * with an LTK, even if the LTK provides the same level of
-	 * security. Only exception is if we don't have an LTK (e.g.
-	 * because of key distribution bits).
-	 */
-	if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) &&
-	    hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type,
-				 hcon->role))
-		return false;
-
-	if (hcon->sec_level >= sec_level)
-		return true;
-
-	return false;
-}
-
-static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	struct smp_cmd_security_req *rp = (void *) skb->data;
-	struct smp_cmd_pairing cp;
-	struct hci_conn *hcon = conn->hcon;
-	struct smp_chan *smp;
-	u8 sec_level;
-
-	BT_DBG("conn %p", conn);
-
-	if (skb->len < sizeof(*rp))
-		return SMP_INVALID_PARAMS;
-
-	if (hcon->role != HCI_ROLE_MASTER)
-		return SMP_CMD_NOTSUPP;
-
-	sec_level = authreq_to_seclevel(rp->auth_req);
-	if (smp_sufficient_security(hcon, sec_level))
-		return 0;
-
-	if (sec_level > hcon->pending_sec_level)
-		hcon->pending_sec_level = sec_level;
-
-	if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
-		return 0;
-
-	if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
-		return 0;
-
-	smp = smp_chan_create(conn);
-	if (!smp)
-		return SMP_UNSPECIFIED;
-
-	if (!test_bit(HCI_BONDABLE, &hcon->hdev->dev_flags) &&
-	    (rp->auth_req & SMP_AUTH_BONDING))
-		return SMP_PAIRING_NOTSUPP;
-
-	skb_pull(skb, sizeof(*rp));
-
-	memset(&cp, 0, sizeof(cp));
-	build_pairing_cmd(conn, &cp, NULL, rp->auth_req);
-
-	smp->preq[0] = SMP_CMD_PAIRING_REQ;
-	memcpy(&smp->preq[1], &cp, sizeof(cp));
-
-	smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
-
-	return 0;
-}
-
-int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
-{
-	struct l2cap_conn *conn = hcon->l2cap_data;
-	struct smp_chan *smp;
-	__u8 authreq;
-
-	BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
-
-	/* This may be NULL if there's an unexpected disconnection */
-	if (!conn)
-		return 1;
-
-	if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags))
-		return 1;
-
-	if (smp_sufficient_security(hcon, sec_level))
-		return 1;
-
-	if (sec_level > hcon->pending_sec_level)
-		hcon->pending_sec_level = sec_level;
-
-	if (hcon->role == HCI_ROLE_MASTER)
-		if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
-			return 0;
-
-	if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
-		return 0;
-
-	smp = smp_chan_create(conn);
-	if (!smp)
-		return 1;
-
-	authreq = seclevel_to_authreq(sec_level);
-
-	/* Require MITM if IO Capability allows or the security level
-	 * requires it.
-	 */
-	if (hcon->io_capability != HCI_IO_NO_INPUT_OUTPUT ||
-	    hcon->pending_sec_level > BT_SECURITY_MEDIUM)
-		authreq |= SMP_AUTH_MITM;
-
-	if (hcon->role == HCI_ROLE_MASTER) {
-		struct smp_cmd_pairing cp;
-
-		build_pairing_cmd(conn, &cp, NULL, authreq);
-		smp->preq[0] = SMP_CMD_PAIRING_REQ;
-		memcpy(&smp->preq[1], &cp, sizeof(cp));
-
-		smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
-	} else {
-		struct smp_cmd_security_req cp;
-		cp.auth_req = authreq;
-		smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
-	}
-
-	set_bit(SMP_FLAG_INITIATOR, &smp->flags);
-
-	return 0;
-}
-
-static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	struct smp_cmd_encrypt_info *rp = (void *) skb->data;
-	struct smp_chan *smp = conn->smp_chan;
-
-	BT_DBG("conn %p", conn);
-
-	if (skb->len < sizeof(*rp))
-		return SMP_INVALID_PARAMS;
-
-	/* Ignore this PDU if it wasn't requested */
-	if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY))
-		return 0;
-
-	skb_pull(skb, sizeof(*rp));
-
-	memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
-
-	return 0;
-}
-
-static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	struct smp_cmd_master_ident *rp = (void *) skb->data;
-	struct smp_chan *smp = conn->smp_chan;
-	struct hci_dev *hdev = conn->hcon->hdev;
-	struct hci_conn *hcon = conn->hcon;
-	struct smp_ltk *ltk;
-	u8 authenticated;
-
-	BT_DBG("conn %p", conn);
-
-	if (skb->len < sizeof(*rp))
-		return SMP_INVALID_PARAMS;
-
-	/* Ignore this PDU if it wasn't requested */
-	if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY))
-		return 0;
-
-	/* Mark the information as received */
-	smp->remote_key_dist &= ~SMP_DIST_ENC_KEY;
-
-	skb_pull(skb, sizeof(*rp));
-
-	hci_dev_lock(hdev);
-	authenticated = (hcon->sec_level == BT_SECURITY_HIGH);
-	ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, SMP_LTK,
-			  authenticated, smp->tk, smp->enc_key_size,
-			  rp->ediv, rp->rand);
-	smp->ltk = ltk;
-	if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
-		smp_distribute_keys(conn);
-	hci_dev_unlock(hdev);
-
-	return 0;
-}
-
-static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	struct smp_cmd_ident_info *info = (void *) skb->data;
-	struct smp_chan *smp = conn->smp_chan;
-
-	BT_DBG("");
-
-	if (skb->len < sizeof(*info))
-		return SMP_INVALID_PARAMS;
-
-	/* Ignore this PDU if it wasn't requested */
-	if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
-		return 0;
-
-	skb_pull(skb, sizeof(*info));
-
-	memcpy(smp->irk, info->irk, 16);
-
-	return 0;
-}
-
-static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
-				   struct sk_buff *skb)
-{
-	struct smp_cmd_ident_addr_info *info = (void *) skb->data;
-	struct smp_chan *smp = conn->smp_chan;
-	struct hci_conn *hcon = conn->hcon;
-	bdaddr_t rpa;
-
-	BT_DBG("");
-
-	if (skb->len < sizeof(*info))
-		return SMP_INVALID_PARAMS;
-
-	/* Ignore this PDU if it wasn't requested */
-	if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
-		return 0;
-
-	/* Mark the information as received */
-	smp->remote_key_dist &= ~SMP_DIST_ID_KEY;
-
-	skb_pull(skb, sizeof(*info));
-
-	hci_dev_lock(hcon->hdev);
-
-	/* Strictly speaking the Core Specification (4.1) allows sending
-	 * an empty address which would force us to rely on just the IRK
-	 * as "identity information". However, since such
-	 * implementations are not known of and in order to not over
-	 * complicate our implementation, simply pretend that we never
-	 * received an IRK for such a device.
-	 */
-	if (!bacmp(&info->bdaddr, BDADDR_ANY)) {
-		BT_ERR("Ignoring IRK with no identity address");
-		goto distribute;
-	}
-
-	bacpy(&smp->id_addr, &info->bdaddr);
-	smp->id_addr_type = info->addr_type;
-
-	if (hci_bdaddr_is_rpa(&hcon->dst, hcon->dst_type))
-		bacpy(&rpa, &hcon->dst);
-	else
-		bacpy(&rpa, BDADDR_ANY);
-
-	smp->remote_irk = hci_add_irk(conn->hcon->hdev, &smp->id_addr,
-				      smp->id_addr_type, smp->irk, &rpa);
-
-distribute:
-	smp_distribute_keys(conn);
-
-	hci_dev_unlock(hcon->hdev);
-
-	return 0;
-}
-
-static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	struct smp_cmd_sign_info *rp = (void *) skb->data;
-	struct smp_chan *smp = conn->smp_chan;
-	struct hci_dev *hdev = conn->hcon->hdev;
-	struct smp_csrk *csrk;
-
-	BT_DBG("conn %p", conn);
-
-	if (skb->len < sizeof(*rp))
-		return SMP_INVALID_PARAMS;
-
-	/* Ignore this PDU if it wasn't requested */
-	if (!(smp->remote_key_dist & SMP_DIST_SIGN))
-		return 0;
-
-	/* Mark the information as received */
-	smp->remote_key_dist &= ~SMP_DIST_SIGN;
-
-	skb_pull(skb, sizeof(*rp));
-
-	hci_dev_lock(hdev);
-	csrk = kzalloc(sizeof(*csrk), GFP_KERNEL);
-	if (csrk) {
-		csrk->master = 0x01;
-		memcpy(csrk->val, rp->csrk, sizeof(csrk->val));
-	}
-	smp->csrk = csrk;
-	if (!(smp->remote_key_dist & SMP_DIST_SIGN))
-		smp_distribute_keys(conn);
-	hci_dev_unlock(hdev);
-
-	return 0;
-}
-
-int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
-{
-	struct hci_conn *hcon = conn->hcon;
-	__u8 code, reason;
-	int err = 0;
-
-	if (hcon->type != LE_LINK) {
-		kfree_skb(skb);
-		return 0;
-	}
-
-	if (skb->len < 1) {
-		kfree_skb(skb);
-		return -EILSEQ;
-	}
-
-	if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) {
-		err = -EOPNOTSUPP;
-		reason = SMP_PAIRING_NOTSUPP;
-		goto done;
-	}
-
-	code = skb->data[0];
-	skb_pull(skb, sizeof(code));
-
-	/*
-	 * The SMP context must be initialized for all other PDUs except
-	 * pairing and security requests. If we get any other PDU when
-	 * not initialized simply disconnect (done if this function
-	 * returns an error).
-	 */
-	if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ &&
-	    !conn->smp_chan) {
-		BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code);
-		kfree_skb(skb);
-		return -EOPNOTSUPP;
-	}
-
-	switch (code) {
-	case SMP_CMD_PAIRING_REQ:
-		reason = smp_cmd_pairing_req(conn, skb);
-		break;
-
-	case SMP_CMD_PAIRING_FAIL:
-		smp_failure(conn, 0);
-		reason = 0;
-		err = -EPERM;
-		break;
-
-	case SMP_CMD_PAIRING_RSP:
-		reason = smp_cmd_pairing_rsp(conn, skb);
-		break;
-
-	case SMP_CMD_SECURITY_REQ:
-		reason = smp_cmd_security_req(conn, skb);
-		break;
-
-	case SMP_CMD_PAIRING_CONFIRM:
-		reason = smp_cmd_pairing_confirm(conn, skb);
-		break;
-
-	case SMP_CMD_PAIRING_RANDOM:
-		reason = smp_cmd_pairing_random(conn, skb);
-		break;
-
-	case SMP_CMD_ENCRYPT_INFO:
-		reason = smp_cmd_encrypt_info(conn, skb);
-		break;
-
-	case SMP_CMD_MASTER_IDENT:
-		reason = smp_cmd_master_ident(conn, skb);
-		break;
-
-	case SMP_CMD_IDENT_INFO:
-		reason = smp_cmd_ident_info(conn, skb);
-		break;
-
-	case SMP_CMD_IDENT_ADDR_INFO:
-		reason = smp_cmd_ident_addr_info(conn, skb);
-		break;
-
-	case SMP_CMD_SIGN_INFO:
-		reason = smp_cmd_sign_info(conn, skb);
-		break;
-
-	default:
-		BT_DBG("Unknown command code 0x%2.2x", code);
-
-		reason = SMP_CMD_NOTSUPP;
-		err = -EOPNOTSUPP;
-		goto done;
-	}
-
-done:
-	if (reason)
-		smp_failure(conn, reason);
-
-	kfree_skb(skb);
-	return err;
-}
-
 static void smp_notify_keys(struct l2cap_conn *conn)
 {
-	struct smp_chan *smp = conn->smp_chan;
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
 	struct hci_conn *hcon = conn->hcon;
 	struct hci_dev *hdev = hcon->hdev;
 	struct smp_cmd_pairing *req = (void *) &smp->preq[1];
@@ -1293,7 +652,7 @@
 		 */
 		bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
 		hcon->dst_type = smp->remote_irk->addr_type;
-		l2cap_conn_update_id_addr(hcon);
+		queue_work(hdev->workqueue, &conn->id_addr_update_work);
 
 		/* When receiving an indentity resolving key for
 		 * a remote device that does not use a resolvable
@@ -1342,24 +701,37 @@
 	}
 }
 
-int smp_distribute_keys(struct l2cap_conn *conn)
+static void smp_allow_key_dist(struct smp_chan *smp)
+{
+	/* Allow the first expected phase 3 PDU. The rest of the PDUs
+	 * will be allowed in each PDU handler to ensure we receive
+	 * them in the correct order.
+	 */
+	if (smp->remote_key_dist & SMP_DIST_ENC_KEY)
+		SMP_ALLOW_CMD(smp, SMP_CMD_ENCRYPT_INFO);
+	else if (smp->remote_key_dist & SMP_DIST_ID_KEY)
+		SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_INFO);
+	else if (smp->remote_key_dist & SMP_DIST_SIGN)
+		SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO);
+}
+
+static void smp_distribute_keys(struct smp_chan *smp)
 {
 	struct smp_cmd_pairing *req, *rsp;
-	struct smp_chan *smp = conn->smp_chan;
+	struct l2cap_conn *conn = smp->conn;
 	struct hci_conn *hcon = conn->hcon;
 	struct hci_dev *hdev = hcon->hdev;
 	__u8 *keydist;
 
 	BT_DBG("conn %p", conn);
 
-	if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
-		return 0;
-
 	rsp = (void *) &smp->prsp[1];
 
 	/* The responder sends its keys first */
-	if (hcon->out && (smp->remote_key_dist & 0x07))
-		return 0;
+	if (hcon->out && (smp->remote_key_dist & KEY_DIST_MASK)) {
+		smp_allow_key_dist(smp);
+		return;
+	}
 
 	req = (void *) &smp->preq[1];
 
@@ -1444,15 +816,936 @@
 	}
 
 	/* If there are still keys to be received wait for them */
-	if ((smp->remote_key_dist & 0x07))
-		return 0;
+	if (smp->remote_key_dist & KEY_DIST_MASK) {
+		smp_allow_key_dist(smp);
+		return;
+	}
 
-	clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags);
-	cancel_delayed_work_sync(&conn->security_timer);
 	set_bit(SMP_FLAG_COMPLETE, &smp->flags);
 	smp_notify_keys(conn);
 
 	smp_chan_destroy(conn);
+}
+
+static void smp_timeout(struct work_struct *work)
+{
+	struct smp_chan *smp = container_of(work, struct smp_chan,
+					    security_timer.work);
+	struct l2cap_conn *conn = smp->conn;
+
+	BT_DBG("conn %p", conn);
+
+	hci_disconnect(conn->hcon, HCI_ERROR_REMOTE_USER_TERM);
+}
+
+static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
+{
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp;
+
+	smp = kzalloc(sizeof(*smp), GFP_ATOMIC);
+	if (!smp)
+		return NULL;
+
+	smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(smp->tfm_aes)) {
+		BT_ERR("Unable to create ECB crypto context");
+		kfree(smp);
+		return NULL;
+	}
+
+	smp->conn = conn;
+	chan->data = smp;
+
+	SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_FAIL);
+
+	INIT_DELAYED_WORK(&smp->security_timer, smp_timeout);
+
+	hci_conn_hold(conn->hcon);
+
+	return smp;
+}
+
+int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
+{
+	struct l2cap_conn *conn = hcon->l2cap_data;
+	struct l2cap_chan *chan;
+	struct smp_chan *smp;
+	u32 value;
+	int err;
+
+	BT_DBG("");
+
+	if (!conn)
+		return -ENOTCONN;
+
+	chan = conn->smp;
+	if (!chan)
+		return -ENOTCONN;
+
+	l2cap_chan_lock(chan);
+	if (!chan->data) {
+		err = -ENOTCONN;
+		goto unlock;
+	}
+
+	smp = chan->data;
+
+	switch (mgmt_op) {
+	case MGMT_OP_USER_PASSKEY_REPLY:
+		value = le32_to_cpu(passkey);
+		memset(smp->tk, 0, sizeof(smp->tk));
+		BT_DBG("PassKey: %d", value);
+		put_unaligned_le32(value, smp->tk);
+		/* Fall Through */
+	case MGMT_OP_USER_CONFIRM_REPLY:
+		set_bit(SMP_FLAG_TK_VALID, &smp->flags);
+		break;
+	case MGMT_OP_USER_PASSKEY_NEG_REPLY:
+	case MGMT_OP_USER_CONFIRM_NEG_REPLY:
+		smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED);
+		err = 0;
+		goto unlock;
+	default:
+		smp_failure(conn, SMP_PASSKEY_ENTRY_FAILED);
+		err = -EOPNOTSUPP;
+		goto unlock;
+	}
+
+	err = 0;
+
+	/* If it is our turn to send Pairing Confirm, do so now */
+	if (test_bit(SMP_FLAG_CFM_PENDING, &smp->flags)) {
+		u8 rsp = smp_confirm(smp);
+		if (rsp)
+			smp_failure(conn, rsp);
+	}
+
+unlock:
+	l2cap_chan_unlock(chan);
+	return err;
+}
+
+static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct smp_cmd_pairing rsp, *req = (void *) skb->data;
+	struct l2cap_chan *chan = conn->smp;
+	struct hci_dev *hdev = conn->hcon->hdev;
+	struct smp_chan *smp;
+	u8 key_size, auth, sec_level;
+	int ret;
+
+	BT_DBG("conn %p", conn);
+
+	if (skb->len < sizeof(*req))
+		return SMP_INVALID_PARAMS;
+
+	if (conn->hcon->role != HCI_ROLE_SLAVE)
+		return SMP_CMD_NOTSUPP;
+
+	if (!chan->data)
+		smp = smp_chan_create(conn);
+	else
+		smp = chan->data;
+
+	if (!smp)
+		return SMP_UNSPECIFIED;
+
+	/* We didn't start the pairing, so match remote */
+	auth = req->auth_req & AUTH_REQ_MASK;
+
+	if (!test_bit(HCI_BONDABLE, &hdev->dev_flags) &&
+	    (auth & SMP_AUTH_BONDING))
+		return SMP_PAIRING_NOTSUPP;
+
+	smp->preq[0] = SMP_CMD_PAIRING_REQ;
+	memcpy(&smp->preq[1], req, sizeof(*req));
+	skb_pull(skb, sizeof(*req));
+
+	if (conn->hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
+		sec_level = BT_SECURITY_MEDIUM;
+	else
+		sec_level = authreq_to_seclevel(auth);
+
+	if (sec_level > conn->hcon->pending_sec_level)
+		conn->hcon->pending_sec_level = sec_level;
+
+	/* If we need MITM check that it can be acheived */
+	if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
+		u8 method;
+
+		method = get_auth_method(smp, conn->hcon->io_capability,
+					 req->io_capability);
+		if (method == JUST_WORKS || method == JUST_CFM)
+			return SMP_AUTH_REQUIREMENTS;
+	}
+
+	build_pairing_cmd(conn, req, &rsp, auth);
+
+	key_size = min(req->max_key_size, rsp.max_key_size);
+	if (check_enc_key_size(conn, key_size))
+		return SMP_ENC_KEY_SIZE;
+
+	get_random_bytes(smp->prnd, sizeof(smp->prnd));
+
+	smp->prsp[0] = SMP_CMD_PAIRING_RSP;
+	memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
+
+	smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
+	SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
+
+	/* Request setup of TK */
+	ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability);
+	if (ret)
+		return SMP_UNSPECIFIED;
 
 	return 0;
 }
+
+static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
+	u8 key_size, auth;
+	int ret;
+
+	BT_DBG("conn %p", conn);
+
+	if (skb->len < sizeof(*rsp))
+		return SMP_INVALID_PARAMS;
+
+	if (conn->hcon->role != HCI_ROLE_MASTER)
+		return SMP_CMD_NOTSUPP;
+
+	skb_pull(skb, sizeof(*rsp));
+
+	req = (void *) &smp->preq[1];
+
+	key_size = min(req->max_key_size, rsp->max_key_size);
+	if (check_enc_key_size(conn, key_size))
+		return SMP_ENC_KEY_SIZE;
+
+	auth = rsp->auth_req & AUTH_REQ_MASK;
+
+	/* If we need MITM check that it can be acheived */
+	if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
+		u8 method;
+
+		method = get_auth_method(smp, req->io_capability,
+					 rsp->io_capability);
+		if (method == JUST_WORKS || method == JUST_CFM)
+			return SMP_AUTH_REQUIREMENTS;
+	}
+
+	get_random_bytes(smp->prnd, sizeof(smp->prnd));
+
+	smp->prsp[0] = SMP_CMD_PAIRING_RSP;
+	memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
+
+	/* Update remote key distribution in case the remote cleared
+	 * some bits that we had enabled in our request.
+	 */
+	smp->remote_key_dist &= rsp->resp_key_dist;
+
+	auth |= req->auth_req;
+
+	ret = tk_request(conn, 0, auth, req->io_capability, rsp->io_capability);
+	if (ret)
+		return SMP_UNSPECIFIED;
+
+	set_bit(SMP_FLAG_CFM_PENDING, &smp->flags);
+
+	/* Can't compose response until we have been confirmed */
+	if (test_bit(SMP_FLAG_TK_VALID, &smp->flags))
+		return smp_confirm(smp);
+
+	return 0;
+}
+
+static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
+
+	BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
+
+	if (skb->len < sizeof(smp->pcnf))
+		return SMP_INVALID_PARAMS;
+
+	memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
+	skb_pull(skb, sizeof(smp->pcnf));
+
+	if (conn->hcon->out) {
+		smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
+			     smp->prnd);
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
+		return 0;
+	}
+
+	if (test_bit(SMP_FLAG_TK_VALID, &smp->flags))
+		return smp_confirm(smp);
+	else
+		set_bit(SMP_FLAG_CFM_PENDING, &smp->flags);
+
+	return 0;
+}
+
+static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
+
+	BT_DBG("conn %p", conn);
+
+	if (skb->len < sizeof(smp->rrnd))
+		return SMP_INVALID_PARAMS;
+
+	memcpy(smp->rrnd, skb->data, sizeof(smp->rrnd));
+	skb_pull(skb, sizeof(smp->rrnd));
+
+	return smp_random(smp);
+}
+
+static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
+{
+	struct smp_ltk *key;
+	struct hci_conn *hcon = conn->hcon;
+
+	key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type,
+				   hcon->role);
+	if (!key)
+		return false;
+
+	if (smp_ltk_sec_level(key) < sec_level)
+		return false;
+
+	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
+		return true;
+
+	hci_le_start_enc(hcon, key->ediv, key->rand, key->val);
+	hcon->enc_key_size = key->enc_size;
+
+	/* We never store STKs for master role, so clear this flag */
+	clear_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags);
+
+	return true;
+}
+
+bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level)
+{
+	if (sec_level == BT_SECURITY_LOW)
+		return true;
+
+	/* If we're encrypted with an STK always claim insufficient
+	 * security. This way we allow the connection to be re-encrypted
+	 * with an LTK, even if the LTK provides the same level of
+	 * security. Only exception is if we don't have an LTK (e.g.
+	 * because of key distribution bits).
+	 */
+	if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) &&
+	    hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type,
+				 hcon->role))
+		return false;
+
+	if (hcon->sec_level >= sec_level)
+		return true;
+
+	return false;
+}
+
+static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct smp_cmd_security_req *rp = (void *) skb->data;
+	struct smp_cmd_pairing cp;
+	struct hci_conn *hcon = conn->hcon;
+	struct smp_chan *smp;
+	u8 sec_level, auth;
+
+	BT_DBG("conn %p", conn);
+
+	if (skb->len < sizeof(*rp))
+		return SMP_INVALID_PARAMS;
+
+	if (hcon->role != HCI_ROLE_MASTER)
+		return SMP_CMD_NOTSUPP;
+
+	auth = rp->auth_req & AUTH_REQ_MASK;
+
+	if (hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
+		sec_level = BT_SECURITY_MEDIUM;
+	else
+		sec_level = authreq_to_seclevel(auth);
+
+	if (smp_sufficient_security(hcon, sec_level))
+		return 0;
+
+	if (sec_level > hcon->pending_sec_level)
+		hcon->pending_sec_level = sec_level;
+
+	if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
+		return 0;
+
+	smp = smp_chan_create(conn);
+	if (!smp)
+		return SMP_UNSPECIFIED;
+
+	if (!test_bit(HCI_BONDABLE, &hcon->hdev->dev_flags) &&
+	    (auth & SMP_AUTH_BONDING))
+		return SMP_PAIRING_NOTSUPP;
+
+	skb_pull(skb, sizeof(*rp));
+
+	memset(&cp, 0, sizeof(cp));
+	build_pairing_cmd(conn, &cp, NULL, auth);
+
+	smp->preq[0] = SMP_CMD_PAIRING_REQ;
+	memcpy(&smp->preq[1], &cp, sizeof(cp));
+
+	smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
+	SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP);
+
+	return 0;
+}
+
+int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
+{
+	struct l2cap_conn *conn = hcon->l2cap_data;
+	struct l2cap_chan *chan;
+	struct smp_chan *smp;
+	__u8 authreq;
+	int ret;
+
+	BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
+
+	/* This may be NULL if there's an unexpected disconnection */
+	if (!conn)
+		return 1;
+
+	chan = conn->smp;
+
+	if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags))
+		return 1;
+
+	if (smp_sufficient_security(hcon, sec_level))
+		return 1;
+
+	if (sec_level > hcon->pending_sec_level)
+		hcon->pending_sec_level = sec_level;
+
+	if (hcon->role == HCI_ROLE_MASTER)
+		if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
+			return 0;
+
+	l2cap_chan_lock(chan);
+
+	/* If SMP is already in progress ignore this request */
+	if (chan->data) {
+		ret = 0;
+		goto unlock;
+	}
+
+	smp = smp_chan_create(conn);
+	if (!smp) {
+		ret = 1;
+		goto unlock;
+	}
+
+	authreq = seclevel_to_authreq(sec_level);
+
+	/* Require MITM if IO Capability allows or the security level
+	 * requires it.
+	 */
+	if (hcon->io_capability != HCI_IO_NO_INPUT_OUTPUT ||
+	    hcon->pending_sec_level > BT_SECURITY_MEDIUM)
+		authreq |= SMP_AUTH_MITM;
+
+	if (hcon->role == HCI_ROLE_MASTER) {
+		struct smp_cmd_pairing cp;
+
+		build_pairing_cmd(conn, &cp, NULL, authreq);
+		smp->preq[0] = SMP_CMD_PAIRING_REQ;
+		memcpy(&smp->preq[1], &cp, sizeof(cp));
+
+		smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP);
+	} else {
+		struct smp_cmd_security_req cp;
+		cp.auth_req = authreq;
+		smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_REQ);
+	}
+
+	set_bit(SMP_FLAG_INITIATOR, &smp->flags);
+	ret = 0;
+
+unlock:
+	l2cap_chan_unlock(chan);
+	return ret;
+}
+
+static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct smp_cmd_encrypt_info *rp = (void *) skb->data;
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
+
+	BT_DBG("conn %p", conn);
+
+	if (skb->len < sizeof(*rp))
+		return SMP_INVALID_PARAMS;
+
+	SMP_ALLOW_CMD(smp, SMP_CMD_MASTER_IDENT);
+
+	skb_pull(skb, sizeof(*rp));
+
+	memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
+
+	return 0;
+}
+
+static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct smp_cmd_master_ident *rp = (void *) skb->data;
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
+	struct hci_dev *hdev = conn->hcon->hdev;
+	struct hci_conn *hcon = conn->hcon;
+	struct smp_ltk *ltk;
+	u8 authenticated;
+
+	BT_DBG("conn %p", conn);
+
+	if (skb->len < sizeof(*rp))
+		return SMP_INVALID_PARAMS;
+
+	/* Mark the information as received */
+	smp->remote_key_dist &= ~SMP_DIST_ENC_KEY;
+
+	if (smp->remote_key_dist & SMP_DIST_ID_KEY)
+		SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_INFO);
+	else if (smp->remote_key_dist & SMP_DIST_SIGN)
+		SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO);
+
+	skb_pull(skb, sizeof(*rp));
+
+	hci_dev_lock(hdev);
+	authenticated = (hcon->sec_level == BT_SECURITY_HIGH);
+	ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, SMP_LTK,
+			  authenticated, smp->tk, smp->enc_key_size,
+			  rp->ediv, rp->rand);
+	smp->ltk = ltk;
+	if (!(smp->remote_key_dist & KEY_DIST_MASK))
+		smp_distribute_keys(smp);
+	hci_dev_unlock(hdev);
+
+	return 0;
+}
+
+static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct smp_cmd_ident_info *info = (void *) skb->data;
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
+
+	BT_DBG("");
+
+	if (skb->len < sizeof(*info))
+		return SMP_INVALID_PARAMS;
+
+	SMP_ALLOW_CMD(smp, SMP_CMD_IDENT_ADDR_INFO);
+
+	skb_pull(skb, sizeof(*info));
+
+	memcpy(smp->irk, info->irk, 16);
+
+	return 0;
+}
+
+static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
+				   struct sk_buff *skb)
+{
+	struct smp_cmd_ident_addr_info *info = (void *) skb->data;
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
+	struct hci_conn *hcon = conn->hcon;
+	bdaddr_t rpa;
+
+	BT_DBG("");
+
+	if (skb->len < sizeof(*info))
+		return SMP_INVALID_PARAMS;
+
+	/* Mark the information as received */
+	smp->remote_key_dist &= ~SMP_DIST_ID_KEY;
+
+	if (smp->remote_key_dist & SMP_DIST_SIGN)
+		SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO);
+
+	skb_pull(skb, sizeof(*info));
+
+	hci_dev_lock(hcon->hdev);
+
+	/* Strictly speaking the Core Specification (4.1) allows sending
+	 * an empty address which would force us to rely on just the IRK
+	 * as "identity information". However, since such
+	 * implementations are not known of and in order to not over
+	 * complicate our implementation, simply pretend that we never
+	 * received an IRK for such a device.
+	 */
+	if (!bacmp(&info->bdaddr, BDADDR_ANY)) {
+		BT_ERR("Ignoring IRK with no identity address");
+		goto distribute;
+	}
+
+	bacpy(&smp->id_addr, &info->bdaddr);
+	smp->id_addr_type = info->addr_type;
+
+	if (hci_bdaddr_is_rpa(&hcon->dst, hcon->dst_type))
+		bacpy(&rpa, &hcon->dst);
+	else
+		bacpy(&rpa, BDADDR_ANY);
+
+	smp->remote_irk = hci_add_irk(conn->hcon->hdev, &smp->id_addr,
+				      smp->id_addr_type, smp->irk, &rpa);
+
+distribute:
+	if (!(smp->remote_key_dist & KEY_DIST_MASK))
+		smp_distribute_keys(smp);
+
+	hci_dev_unlock(hcon->hdev);
+
+	return 0;
+}
+
+static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct smp_cmd_sign_info *rp = (void *) skb->data;
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
+	struct hci_dev *hdev = conn->hcon->hdev;
+	struct smp_csrk *csrk;
+
+	BT_DBG("conn %p", conn);
+
+	if (skb->len < sizeof(*rp))
+		return SMP_INVALID_PARAMS;
+
+	/* Mark the information as received */
+	smp->remote_key_dist &= ~SMP_DIST_SIGN;
+
+	skb_pull(skb, sizeof(*rp));
+
+	hci_dev_lock(hdev);
+	csrk = kzalloc(sizeof(*csrk), GFP_KERNEL);
+	if (csrk) {
+		csrk->master = 0x01;
+		memcpy(csrk->val, rp->csrk, sizeof(csrk->val));
+	}
+	smp->csrk = csrk;
+	smp_distribute_keys(smp);
+	hci_dev_unlock(hdev);
+
+	return 0;
+}
+
+static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+	struct l2cap_conn *conn = chan->conn;
+	struct hci_conn *hcon = conn->hcon;
+	struct smp_chan *smp;
+	__u8 code, reason;
+	int err = 0;
+
+	if (hcon->type != LE_LINK) {
+		kfree_skb(skb);
+		return 0;
+	}
+
+	if (skb->len < 1)
+		return -EILSEQ;
+
+	if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) {
+		reason = SMP_PAIRING_NOTSUPP;
+		goto done;
+	}
+
+	code = skb->data[0];
+	skb_pull(skb, sizeof(code));
+
+	smp = chan->data;
+
+	if (code > SMP_CMD_MAX)
+		goto drop;
+
+	if (smp && !test_and_clear_bit(code, &smp->allow_cmd))
+		goto drop;
+
+	/* If we don't have a context the only allowed commands are
+	 * pairing request and security request.
+	 */
+	if (!smp && code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ)
+		goto drop;
+
+	switch (code) {
+	case SMP_CMD_PAIRING_REQ:
+		reason = smp_cmd_pairing_req(conn, skb);
+		break;
+
+	case SMP_CMD_PAIRING_FAIL:
+		smp_failure(conn, 0);
+		err = -EPERM;
+		break;
+
+	case SMP_CMD_PAIRING_RSP:
+		reason = smp_cmd_pairing_rsp(conn, skb);
+		break;
+
+	case SMP_CMD_SECURITY_REQ:
+		reason = smp_cmd_security_req(conn, skb);
+		break;
+
+	case SMP_CMD_PAIRING_CONFIRM:
+		reason = smp_cmd_pairing_confirm(conn, skb);
+		break;
+
+	case SMP_CMD_PAIRING_RANDOM:
+		reason = smp_cmd_pairing_random(conn, skb);
+		break;
+
+	case SMP_CMD_ENCRYPT_INFO:
+		reason = smp_cmd_encrypt_info(conn, skb);
+		break;
+
+	case SMP_CMD_MASTER_IDENT:
+		reason = smp_cmd_master_ident(conn, skb);
+		break;
+
+	case SMP_CMD_IDENT_INFO:
+		reason = smp_cmd_ident_info(conn, skb);
+		break;
+
+	case SMP_CMD_IDENT_ADDR_INFO:
+		reason = smp_cmd_ident_addr_info(conn, skb);
+		break;
+
+	case SMP_CMD_SIGN_INFO:
+		reason = smp_cmd_sign_info(conn, skb);
+		break;
+
+	default:
+		BT_DBG("Unknown command code 0x%2.2x", code);
+		reason = SMP_CMD_NOTSUPP;
+		goto done;
+	}
+
+done:
+	if (!err) {
+		if (reason)
+			smp_failure(conn, reason);
+		kfree_skb(skb);
+	}
+
+	return err;
+
+drop:
+	BT_ERR("%s unexpected SMP command 0x%02x from %pMR", hcon->hdev->name,
+	       code, &hcon->dst);
+	kfree_skb(skb);
+	return 0;
+}
+
+static void smp_teardown_cb(struct l2cap_chan *chan, int err)
+{
+	struct l2cap_conn *conn = chan->conn;
+
+	BT_DBG("chan %p", chan);
+
+	if (chan->data)
+		smp_chan_destroy(conn);
+
+	conn->smp = NULL;
+	l2cap_chan_put(chan);
+}
+
+static void smp_resume_cb(struct l2cap_chan *chan)
+{
+	struct smp_chan *smp = chan->data;
+	struct l2cap_conn *conn = chan->conn;
+	struct hci_conn *hcon = conn->hcon;
+
+	BT_DBG("chan %p", chan);
+
+	if (!smp)
+		return;
+
+	if (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
+		return;
+
+	cancel_delayed_work(&smp->security_timer);
+
+	smp_distribute_keys(smp);
+}
+
+static void smp_ready_cb(struct l2cap_chan *chan)
+{
+	struct l2cap_conn *conn = chan->conn;
+
+	BT_DBG("chan %p", chan);
+
+	conn->smp = chan;
+	l2cap_chan_hold(chan);
+}
+
+static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+	int err;
+
+	BT_DBG("chan %p", chan);
+
+	err = smp_sig_channel(chan, skb);
+	if (err) {
+		struct smp_chan *smp = chan->data;
+
+		if (smp)
+			cancel_delayed_work_sync(&smp->security_timer);
+
+		hci_disconnect(chan->conn->hcon, HCI_ERROR_AUTH_FAILURE);
+	}
+
+	return err;
+}
+
+static struct sk_buff *smp_alloc_skb_cb(struct l2cap_chan *chan,
+					unsigned long hdr_len,
+					unsigned long len, int nb)
+{
+	struct sk_buff *skb;
+
+	skb = bt_skb_alloc(hdr_len + len, GFP_KERNEL);
+	if (!skb)
+		return ERR_PTR(-ENOMEM);
+
+	skb->priority = HCI_PRIO_MAX;
+	bt_cb(skb)->chan = chan;
+
+	return skb;
+}
+
+static const struct l2cap_ops smp_chan_ops = {
+	.name			= "Security Manager",
+	.ready			= smp_ready_cb,
+	.recv			= smp_recv_cb,
+	.alloc_skb		= smp_alloc_skb_cb,
+	.teardown		= smp_teardown_cb,
+	.resume			= smp_resume_cb,
+
+	.new_connection		= l2cap_chan_no_new_connection,
+	.state_change		= l2cap_chan_no_state_change,
+	.close			= l2cap_chan_no_close,
+	.defer			= l2cap_chan_no_defer,
+	.suspend		= l2cap_chan_no_suspend,
+	.set_shutdown		= l2cap_chan_no_set_shutdown,
+	.get_sndtimeo		= l2cap_chan_no_get_sndtimeo,
+	.memcpy_fromiovec	= l2cap_chan_no_memcpy_fromiovec,
+};
+
+static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
+{
+	struct l2cap_chan *chan;
+
+	BT_DBG("pchan %p", pchan);
+
+	chan = l2cap_chan_create();
+	if (!chan)
+		return NULL;
+
+	chan->chan_type	= pchan->chan_type;
+	chan->ops	= &smp_chan_ops;
+	chan->scid	= pchan->scid;
+	chan->dcid	= chan->scid;
+	chan->imtu	= pchan->imtu;
+	chan->omtu	= pchan->omtu;
+	chan->mode	= pchan->mode;
+
+	BT_DBG("created chan %p", chan);
+
+	return chan;
+}
+
+static const struct l2cap_ops smp_root_chan_ops = {
+	.name			= "Security Manager Root",
+	.new_connection		= smp_new_conn_cb,
+
+	/* None of these are implemented for the root channel */
+	.close			= l2cap_chan_no_close,
+	.alloc_skb		= l2cap_chan_no_alloc_skb,
+	.recv			= l2cap_chan_no_recv,
+	.state_change		= l2cap_chan_no_state_change,
+	.teardown		= l2cap_chan_no_teardown,
+	.ready			= l2cap_chan_no_ready,
+	.defer			= l2cap_chan_no_defer,
+	.suspend		= l2cap_chan_no_suspend,
+	.resume			= l2cap_chan_no_resume,
+	.set_shutdown		= l2cap_chan_no_set_shutdown,
+	.get_sndtimeo		= l2cap_chan_no_get_sndtimeo,
+	.memcpy_fromiovec	= l2cap_chan_no_memcpy_fromiovec,
+};
+
+int smp_register(struct hci_dev *hdev)
+{
+	struct l2cap_chan *chan;
+	struct crypto_blkcipher	*tfm_aes;
+
+	BT_DBG("%s", hdev->name);
+
+	tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm_aes)) {
+		int err = PTR_ERR(tfm_aes);
+		BT_ERR("Unable to create crypto context");
+		return err;
+	}
+
+	chan = l2cap_chan_create();
+	if (!chan) {
+		crypto_free_blkcipher(tfm_aes);
+		return -ENOMEM;
+	}
+
+	chan->data = tfm_aes;
+
+	l2cap_add_scid(chan, L2CAP_CID_SMP);
+
+	l2cap_chan_set_defaults(chan);
+
+	bacpy(&chan->src, &hdev->bdaddr);
+	chan->src_type = BDADDR_LE_PUBLIC;
+	chan->state = BT_LISTEN;
+	chan->mode = L2CAP_MODE_BASIC;
+	chan->imtu = L2CAP_DEFAULT_MTU;
+	chan->ops = &smp_root_chan_ops;
+
+	hdev->smp_data = chan;
+
+	return 0;
+}
+
+void smp_unregister(struct hci_dev *hdev)
+{
+	struct l2cap_chan *chan = hdev->smp_data;
+	struct crypto_blkcipher *tfm_aes;
+
+	if (!chan)
+		return;
+
+	BT_DBG("%s chan %p", hdev->name, chan);
+
+	tfm_aes = chan->data;
+	if (tfm_aes) {
+		chan->data = NULL;
+		crypto_free_blkcipher(tfm_aes);
+	}
+
+	hdev->smp_data = NULL;
+	l2cap_chan_put(chan);
+}
diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h
index 796f4f4..86a683a 100644
--- a/net/bluetooth/smp.h
+++ b/net/bluetooth/smp.h
@@ -102,6 +102,8 @@
 	__u8	auth_req;
 } __packed;
 
+#define SMP_CMD_MAX		0x0b
+
 #define SMP_PASSKEY_ENTRY_FAILED	0x01
 #define SMP_OOB_NOT_AVAIL		0x02
 #define SMP_AUTH_REQUIREMENTS		0x03
@@ -123,17 +125,23 @@
 	SMP_LTK_SLAVE,
 };
 
+static inline u8 smp_ltk_sec_level(struct smp_ltk *key)
+{
+	if (key->authenticated)
+		return BT_SECURITY_HIGH;
+
+	return BT_SECURITY_MEDIUM;
+}
+
 /* SMP Commands */
 bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level);
 int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
-int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
-int smp_distribute_keys(struct l2cap_conn *conn);
 int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
 
-void smp_chan_destroy(struct l2cap_conn *conn);
+bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr);
+int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa);
 
-bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
-		     bdaddr_t *bdaddr);
-int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa);
+int smp_register(struct hci_dev *hdev);
+void smp_unregister(struct hci_dev *hdev);
 
 #endif /* __SMP_H */
diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c
index bed2702..69cbc62 100644
--- a/net/ieee802154/6lowpan_rtnl.c
+++ b/net/ieee802154/6lowpan_rtnl.c
@@ -71,18 +71,33 @@
 	struct list_head list;
 };
 
+/* don't save pan id, it's intra pan */
+struct lowpan_addr {
+	u8 mode;
+	union {
+		/* IPv6 needs big endian here */
+		__be64 extended_addr;
+		__be16 short_addr;
+	} u;
+};
+
+struct lowpan_addr_info {
+	struct lowpan_addr daddr;
+	struct lowpan_addr saddr;
+};
+
 static inline struct
 lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
 {
 	return netdev_priv(dev);
 }
 
-static inline void lowpan_address_flip(u8 *src, u8 *dest)
+static inline struct
+lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb)
 {
-	int i;
-
-	for (i = 0; i < IEEE802154_ADDR_LEN; i++)
-		(dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i];
+	WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct lowpan_addr_info));
+	return (struct lowpan_addr_info *)(skb->data -
+			sizeof(struct lowpan_addr_info));
 }
 
 static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
@@ -91,8 +106,7 @@
 {
 	const u8 *saddr = _saddr;
 	const u8 *daddr = _daddr;
-	struct ieee802154_addr sa, da;
-	struct ieee802154_mac_cb *cb = mac_cb_init(skb);
+	struct lowpan_addr_info *info;
 
 	/* TODO:
 	 * if this package isn't ipv6 one, where should it be routed?
@@ -106,41 +120,17 @@
 	raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
 	raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
 
-	lowpan_header_compress(skb, dev, type, daddr, saddr, len);
+	info = lowpan_skb_priv(skb);
 
-	/* NOTE1: I'm still unsure about the fact that compression and WPAN
-	 * header are created here and not later in the xmit. So wait for
-	 * an opinion of net maintainers.
-	 */
-	/* NOTE2: to be absolutely correct, we must derive PANid information
-	 * from MAC subif of the 'dev' and 'real_dev' network devices, but
-	 * this isn't implemented in mainline yet, so currently we assign 0xff
-	 */
-	cb->type = IEEE802154_FC_TYPE_DATA;
+	/* TODO: Currently we only support extended_addr */
+	info->daddr.mode = IEEE802154_ADDR_LONG;
+	memcpy(&info->daddr.u.extended_addr, daddr,
+	       sizeof(info->daddr.u.extended_addr));
+	info->saddr.mode = IEEE802154_ADDR_LONG;
+	memcpy(&info->saddr.u.extended_addr, saddr,
+	       sizeof(info->daddr.u.extended_addr));
 
-	/* prepare wpan address data */
-	sa.mode = IEEE802154_ADDR_LONG;
-	sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
-	sa.extended_addr = ieee802154_devaddr_from_raw(saddr);
-
-	/* intra-PAN communications */
-	da.pan_id = sa.pan_id;
-
-	/* if the destination address is the broadcast address, use the
-	 * corresponding short address
-	 */
-	if (lowpan_is_addr_broadcast(daddr)) {
-		da.mode = IEEE802154_ADDR_SHORT;
-		da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
-	} else {
-		da.mode = IEEE802154_ADDR_LONG;
-		da.extended_addr = ieee802154_devaddr_from_raw(daddr);
-	}
-
-	cb->ackreq = !lowpan_is_addr_broadcast(daddr);
-
-	return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
-			type, (void *)&da, (void *)&sa, 0);
+	return 0;
 }
 
 static int lowpan_give_skb_to_devices(struct sk_buff *skb,
@@ -338,13 +328,68 @@
 	return rc;
 }
 
+static int lowpan_header(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ieee802154_addr sa, da;
+	struct ieee802154_mac_cb *cb = mac_cb_init(skb);
+	struct lowpan_addr_info info;
+	void *daddr, *saddr;
+
+	memcpy(&info, lowpan_skb_priv(skb), sizeof(info));
+
+	/* TODO: Currently we only support extended_addr */
+	daddr = &info.daddr.u.extended_addr;
+	saddr = &info.saddr.u.extended_addr;
+
+	lowpan_header_compress(skb, dev, ETH_P_IPV6, daddr, saddr, skb->len);
+
+	cb->type = IEEE802154_FC_TYPE_DATA;
+
+	/* prepare wpan address data */
+	sa.mode = IEEE802154_ADDR_LONG;
+	sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+	sa.extended_addr = ieee802154_devaddr_from_raw(saddr);
+
+	/* intra-PAN communications */
+	da.pan_id = sa.pan_id;
+
+	/* if the destination address is the broadcast address, use the
+	 * corresponding short address
+	 */
+	if (lowpan_is_addr_broadcast((const u8 *)daddr)) {
+		da.mode = IEEE802154_ADDR_SHORT;
+		da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
+		cb->ackreq = false;
+	} else {
+		da.mode = IEEE802154_ADDR_LONG;
+		da.extended_addr = ieee802154_devaddr_from_raw(daddr);
+		cb->ackreq = true;
+	}
+
+	return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
+			ETH_P_IPV6, (void *)&da, (void *)&sa, 0);
+}
+
 static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ieee802154_hdr wpan_hdr;
-	int max_single;
+	int max_single, ret;
 
 	pr_debug("package xmit\n");
 
+	/* We must take a copy of the skb before we modify/replace the ipv6
+	 * header as the header could be used elsewhere
+	 */
+	skb = skb_unshare(skb, GFP_ATOMIC);
+	if (!skb)
+		return NET_XMIT_DROP;
+
+	ret = lowpan_header(skb, dev);
+	if (ret < 0) {
+		kfree_skb(skb);
+		return NET_XMIT_DROP;
+	}
+
 	if (ieee802154_hdr_peek(skb, &wpan_hdr) < 0) {
 		kfree_skb(skb);
 		return NET_XMIT_DROP;
diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c
index f257489..4862bb5 100644
--- a/net/ieee802154/reassembly.c
+++ b/net/ieee802154/reassembly.c
@@ -514,7 +514,7 @@
 
 static struct ctl_table_header *lowpan_ctl_header;
 
-static int lowpan_frags_sysctl_register(void)
+static int __init lowpan_frags_sysctl_register(void)
 {
 	lowpan_ctl_header = register_net_sysctl(&init_net,
 						"net/ieee802154/6lowpan",
@@ -536,7 +536,7 @@
 {
 }
 
-static inline int lowpan_frags_sysctl_register(void)
+static inline int __init lowpan_frags_sysctl_register(void)
 {
 	return 0;
 }
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index f0e84bc..a48bad4 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -227,7 +227,7 @@
 void __ieee80211_start_rx_ba_session(struct sta_info *sta,
 				     u8 dialog_token, u16 timeout,
 				     u16 start_seq_num, u16 ba_policy, u16 tid,
-				     u16 buf_size, bool tx)
+				     u16 buf_size, bool tx, bool auto_seq)
 {
 	struct ieee80211_local *local = sta->sdata->local;
 	struct tid_ampdu_rx *tid_agg_rx;
@@ -326,6 +326,7 @@
 	tid_agg_rx->buf_size = buf_size;
 	tid_agg_rx->timeout = timeout;
 	tid_agg_rx->stored_mpdu_num = 0;
+	tid_agg_rx->auto_seq = auto_seq;
 	status = WLAN_STATUS_SUCCESS;
 
 	/* activate it for RX */
@@ -367,7 +368,7 @@
 
 	__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
 					start_seq_num, ba_policy, tid,
-					buf_size, true);
+					buf_size, true, false);
 }
 
 void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 3dd6a16..2ca7a9f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2,6 +2,7 @@
  * mac80211 configuration hooks for cfg80211
  *
  * Copyright 2006-2010	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This file is GPLv2 as found in COPYING.
  */
@@ -682,8 +683,19 @@
 	if (old)
 		return -EALREADY;
 
-	/* TODO: make hostapd tell us what it wants */
-	sdata->smps_mode = IEEE80211_SMPS_OFF;
+	switch (params->smps_mode) {
+	case NL80211_SMPS_OFF:
+		sdata->smps_mode = IEEE80211_SMPS_OFF;
+		break;
+	case NL80211_SMPS_STATIC:
+		sdata->smps_mode = IEEE80211_SMPS_STATIC;
+		break;
+	case NL80211_SMPS_DYNAMIC:
+		sdata->smps_mode = IEEE80211_SMPS_DYNAMIC;
+		break;
+	default:
+		return -EINVAL;
+	}
 	sdata->needed_rx_chains = sdata->local->rx_chains;
 
 	mutex_lock(&local->mtx);
@@ -1011,15 +1023,8 @@
 			clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
 	}
 
-	if (mask & BIT(NL80211_STA_FLAG_WME)) {
-		if (set & BIT(NL80211_STA_FLAG_WME)) {
-			set_sta_flag(sta, WLAN_STA_WME);
-			sta->sta.wme = true;
-		} else {
-			clear_sta_flag(sta, WLAN_STA_WME);
-			sta->sta.wme = false;
-		}
-	}
+	if (mask & BIT(NL80211_STA_FLAG_WME))
+		sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME);
 
 	if (mask & BIT(NL80211_STA_FLAG_MFP)) {
 		if (set & BIT(NL80211_STA_FLAG_MFP))
@@ -1984,8 +1989,13 @@
 			return err;
 	}
 
-	if (changed & WIPHY_PARAM_COVERAGE_CLASS) {
-		err = drv_set_coverage_class(local, wiphy->coverage_class);
+	if ((changed & WIPHY_PARAM_COVERAGE_CLASS) ||
+	    (changed & WIPHY_PARAM_DYN_ACK)) {
+		s16 coverage_class;
+
+		coverage_class = changed & WIPHY_PARAM_COVERAGE_CLASS ?
+					wiphy->coverage_class : -1;
+		err = drv_set_coverage_class(local, coverage_class);
 
 		if (err)
 			return err;
@@ -2358,6 +2368,58 @@
 	return 0;
 }
 
+static bool ieee80211_coalesce_started_roc(struct ieee80211_local *local,
+					   struct ieee80211_roc_work *new_roc,
+					   struct ieee80211_roc_work *cur_roc)
+{
+	unsigned long j = jiffies;
+	unsigned long cur_roc_end = cur_roc->hw_start_time +
+				    msecs_to_jiffies(cur_roc->duration);
+	struct ieee80211_roc_work *next_roc;
+	int new_dur;
+
+	if (WARN_ON(!cur_roc->started || !cur_roc->hw_begun))
+		return false;
+
+	if (time_after(j + IEEE80211_ROC_MIN_LEFT, cur_roc_end))
+		return false;
+
+	ieee80211_handle_roc_started(new_roc);
+
+	new_dur = new_roc->duration - jiffies_to_msecs(cur_roc_end - j);
+
+	/* cur_roc is long enough - add new_roc to the dependents list. */
+	if (new_dur <= 0) {
+		list_add_tail(&new_roc->list, &cur_roc->dependents);
+		return true;
+	}
+
+	new_roc->duration = new_dur;
+
+	/*
+	 * if cur_roc was already coalesced before, we might
+	 * want to extend the next roc instead of adding
+	 * a new one.
+	 */
+	next_roc = list_entry(cur_roc->list.next,
+			      struct ieee80211_roc_work, list);
+	if (&next_roc->list != &local->roc_list &&
+	    next_roc->chan == new_roc->chan &&
+	    next_roc->sdata == new_roc->sdata &&
+	    !WARN_ON(next_roc->started)) {
+		list_add_tail(&new_roc->list, &next_roc->dependents);
+		next_roc->duration = max(next_roc->duration,
+					 new_roc->duration);
+		next_roc->type = max(next_roc->type, new_roc->type);
+		return true;
+	}
+
+	/* add right after cur_roc */
+	list_add(&new_roc->list, &cur_roc->list);
+
+	return true;
+}
+
 static int ieee80211_start_roc_work(struct ieee80211_local *local,
 				    struct ieee80211_sub_if_data *sdata,
 				    struct ieee80211_channel *channel,
@@ -2463,8 +2525,6 @@
 
 		/* If it has already started, it's more difficult ... */
 		if (local->ops->remain_on_channel) {
-			unsigned long j = jiffies;
-
 			/*
 			 * In the offloaded ROC case, if it hasn't begun, add
 			 * this new one to the dependent list to be handled
@@ -2487,28 +2547,8 @@
 				break;
 			}
 
-			if (time_before(j + IEEE80211_ROC_MIN_LEFT,
-					tmp->hw_start_time +
-					msecs_to_jiffies(tmp->duration))) {
-				int new_dur;
-
-				ieee80211_handle_roc_started(roc);
-
-				new_dur = roc->duration -
-					  jiffies_to_msecs(tmp->hw_start_time +
-							   msecs_to_jiffies(
-								tmp->duration) -
-							   j);
-
-				if (new_dur > 0) {
-					/* add right after tmp */
-					list_add(&roc->list, &tmp->list);
-				} else {
-					list_add_tail(&roc->list,
-						      &tmp->dependents);
-				}
+			if (ieee80211_coalesce_started_roc(local, roc, tmp))
 				queued = true;
-			}
 		} else if (del_timer_sync(&tmp->work.timer)) {
 			unsigned long new_end;
 
@@ -3352,7 +3392,7 @@
 	band = chanctx_conf->def.chan->band;
 	sta = sta_info_get_bss(sdata, peer);
 	if (sta) {
-		qos = test_sta_flag(sta, WLAN_STA_WME);
+		qos = sta->sta.wme;
 	} else {
 		rcu_read_unlock();
 		return -ENOLINK;
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 399ad82..4c74e8d 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -549,12 +549,12 @@
 
 		compat = cfg80211_chandef_compatible(
 				&sdata->vif.bss_conf.chandef, compat);
-		if (!compat)
+		if (WARN_ON_ONCE(!compat))
 			break;
 	}
 	rcu_read_unlock();
 
-	if (WARN_ON_ONCE(!compat))
+	if (!compat)
 		return;
 
 	ieee80211_change_chanctx(local, ctx, compat);
@@ -639,41 +639,6 @@
 	return ret;
 }
 
-static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx_conf *conf;
-	struct ieee80211_chanctx *ctx;
-	bool use_reserved_switch = false;
-
-	lockdep_assert_held(&local->chanctx_mtx);
-
-	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-					 lockdep_is_held(&local->chanctx_mtx));
-	if (!conf)
-		return;
-
-	ctx = container_of(conf, struct ieee80211_chanctx, conf);
-
-	if (sdata->reserved_chanctx) {
-		if (sdata->reserved_chanctx->replace_state ==
-		    IEEE80211_CHANCTX_REPLACES_OTHER &&
-		    ieee80211_chanctx_num_reserved(local,
-						   sdata->reserved_chanctx) > 1)
-			use_reserved_switch = true;
-
-		ieee80211_vif_unreserve_chanctx(sdata);
-	}
-
-	ieee80211_assign_vif_chanctx(sdata, NULL);
-	if (ieee80211_chanctx_refcount(local, ctx) == 0)
-		ieee80211_free_chanctx(local, ctx);
-
-	/* Unreserving may ready an in-place reservation. */
-	if (use_reserved_switch)
-		ieee80211_vif_use_reserved_switch(local);
-}
-
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
 				   struct ieee80211_chanctx *chanctx)
 {
@@ -764,63 +729,6 @@
 	drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
 }
 
-int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
-			      const struct cfg80211_chan_def *chandef,
-			      enum ieee80211_chanctx_mode mode)
-{
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_chanctx *ctx;
-	u8 radar_detect_width = 0;
-	int ret;
-
-	lockdep_assert_held(&local->mtx);
-
-	WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
-
-	mutex_lock(&local->chanctx_mtx);
-
-	ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
-					    chandef,
-					    sdata->wdev.iftype);
-	if (ret < 0)
-		goto out;
-	if (ret > 0)
-		radar_detect_width = BIT(chandef->width);
-
-	sdata->radar_required = ret;
-
-	ret = ieee80211_check_combinations(sdata, chandef, mode,
-					   radar_detect_width);
-	if (ret < 0)
-		goto out;
-
-	__ieee80211_vif_release_channel(sdata);
-
-	ctx = ieee80211_find_chanctx(local, chandef, mode);
-	if (!ctx)
-		ctx = ieee80211_new_chanctx(local, chandef, mode);
-	if (IS_ERR(ctx)) {
-		ret = PTR_ERR(ctx);
-		goto out;
-	}
-
-	sdata->vif.bss_conf.chandef = *chandef;
-
-	ret = ieee80211_assign_vif_chanctx(sdata, ctx);
-	if (ret) {
-		/* if assign fails refcount stays the same */
-		if (ieee80211_chanctx_refcount(local, ctx) == 0)
-			ieee80211_free_chanctx(local, ctx);
-		goto out;
-	}
-
-	ieee80211_recalc_smps_chanctx(local, ctx);
-	ieee80211_recalc_radar_chanctx(local, ctx);
- out:
-	mutex_unlock(&local->chanctx_mtx);
-	return ret;
-}
-
 static void
 __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 				      bool clear)
@@ -1269,8 +1177,7 @@
 	return err;
 }
 
-int
-ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
+static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
 {
 	struct ieee80211_sub_if_data *sdata, *sdata_tmp;
 	struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
@@ -1522,6 +1429,98 @@
 	return err;
 }
 
+static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_chanctx_conf *conf;
+	struct ieee80211_chanctx *ctx;
+	bool use_reserved_switch = false;
+
+	lockdep_assert_held(&local->chanctx_mtx);
+
+	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+					 lockdep_is_held(&local->chanctx_mtx));
+	if (!conf)
+		return;
+
+	ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+	if (sdata->reserved_chanctx) {
+		if (sdata->reserved_chanctx->replace_state ==
+		    IEEE80211_CHANCTX_REPLACES_OTHER &&
+		    ieee80211_chanctx_num_reserved(local,
+						   sdata->reserved_chanctx) > 1)
+			use_reserved_switch = true;
+
+		ieee80211_vif_unreserve_chanctx(sdata);
+	}
+
+	ieee80211_assign_vif_chanctx(sdata, NULL);
+	if (ieee80211_chanctx_refcount(local, ctx) == 0)
+		ieee80211_free_chanctx(local, ctx);
+
+	/* Unreserving may ready an in-place reservation. */
+	if (use_reserved_switch)
+		ieee80211_vif_use_reserved_switch(local);
+}
+
+int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
+			      const struct cfg80211_chan_def *chandef,
+			      enum ieee80211_chanctx_mode mode)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_chanctx *ctx;
+	u8 radar_detect_width = 0;
+	int ret;
+
+	lockdep_assert_held(&local->mtx);
+
+	WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
+
+	mutex_lock(&local->chanctx_mtx);
+
+	ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
+					    chandef,
+					    sdata->wdev.iftype);
+	if (ret < 0)
+		goto out;
+	if (ret > 0)
+		radar_detect_width = BIT(chandef->width);
+
+	sdata->radar_required = ret;
+
+	ret = ieee80211_check_combinations(sdata, chandef, mode,
+					   radar_detect_width);
+	if (ret < 0)
+		goto out;
+
+	__ieee80211_vif_release_channel(sdata);
+
+	ctx = ieee80211_find_chanctx(local, chandef, mode);
+	if (!ctx)
+		ctx = ieee80211_new_chanctx(local, chandef, mode);
+	if (IS_ERR(ctx)) {
+		ret = PTR_ERR(ctx);
+		goto out;
+	}
+
+	sdata->vif.bss_conf.chandef = *chandef;
+
+	ret = ieee80211_assign_vif_chanctx(sdata, ctx);
+	if (ret) {
+		/* if assign fails refcount stays the same */
+		if (ieee80211_chanctx_refcount(local, ctx) == 0)
+			ieee80211_free_chanctx(local, ctx);
+		goto out;
+	}
+
+	ieee80211_recalc_smps_chanctx(local, ctx);
+	ieee80211_recalc_radar_chanctx(local, ctx);
+ out:
+	mutex_unlock(&local->chanctx_mtx);
+	return ret;
+}
+
 int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_local *local = sdata->local;
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 8c26a44..fc8e234 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -3,6 +3,7 @@
  * mac80211 debugfs for wireless PHYs
  *
  * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * GPLv2
  *
@@ -302,11 +303,6 @@
 		sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n");
 	if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE)
 		sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n");
-	if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS)
-		sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n");
-	if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)
-		sf += scnprintf(buf + sf, mxln - sf,
-				"SUPPORTS_DYNAMIC_SMPS\n");
 	if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
 		sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n");
 	if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index ff4fa15..bb625e9 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -226,12 +226,12 @@
 	struct ieee80211_local *local = sdata->local;
 	int err;
 
-	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) &&
+	if (!(local->hw.wiphy->features & NL80211_FEATURE_STATIC_SMPS) &&
 	    smps_mode == IEEE80211_SMPS_STATIC)
 		return -EINVAL;
 
 	/* auto should be dynamic if in PS mode */
-	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) &&
+	if (!(local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS) &&
 	    (smps_mode == IEEE80211_SMPS_DYNAMIC ||
 	     smps_mode == IEEE80211_SMPS_AUTOMATIC))
 		return -EINVAL;
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 86173c0..bafe489 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -2,6 +2,7 @@
  * Copyright 2003-2005	Devicescape Software, Inc.
  * Copyright (c) 2006	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -77,7 +78,8 @@
 			    TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
 			    TEST(PS_DRIVER), TEST(AUTHORIZED),
 			    TEST(SHORT_PREAMBLE),
-			    TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
+			    sta->sta.wme ? "WME\n" : "",
+			    TEST(WDS), TEST(CLEAR_PS_FILT),
 			    TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
 			    TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
 			    TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index dc78f69..6da526b 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -450,7 +450,7 @@
 }
 
 static inline int drv_set_coverage_class(struct ieee80211_local *local,
-					 u8 value)
+					 s16 value)
 {
 	int ret = 0;
 	might_sleep();
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 9713dc5..56b5357 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -6,6 +6,7 @@
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1038,7 +1039,7 @@
 		}
 
 		if (sta && elems->wmm_info)
-			set_sta_flag(sta, WLAN_STA_WME);
+			sta->sta.wme = true;
 
 		if (sta && elems->ht_operation && elems->ht_cap_elem &&
 		    sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 2c4fdc0..a02fa58 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -3,6 +3,7 @@
  * Copyright 2005, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007-2010	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -354,6 +355,7 @@
 	IEEE80211_STA_DISABLE_80P80MHZ	= BIT(12),
 	IEEE80211_STA_DISABLE_160MHZ	= BIT(13),
 	IEEE80211_STA_DISABLE_WMM	= BIT(14),
+	IEEE80211_STA_ENABLE_RRM	= BIT(15),
 };
 
 struct ieee80211_mgd_auth_data {
@@ -1370,6 +1372,7 @@
 	const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
 	const u8 *country_elem;
 	const u8 *pwr_constr_elem;
+	const u8 *cisco_dtpc_elem;
 	const struct ieee80211_timeout_interval_ie *timeout_int;
 	const u8 *opmode_notif;
 	const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
@@ -1590,7 +1593,7 @@
 void __ieee80211_start_rx_ba_session(struct sta_info *sta,
 				     u8 dialog_token, u16 timeout,
 				     u16 start_seq_num, u16 ba_policy, u16 tid,
-				     u16 buf_size, bool tx);
+				     u16 buf_size, bool tx, bool auto_seq);
 void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
 					 enum ieee80211_agg_stop_reason reason);
 void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
@@ -1872,7 +1875,6 @@
 int __must_check
 ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata);
 int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata);
-int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local);
 
 int __must_check
 ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
@@ -1921,7 +1923,7 @@
 			size_t extra_ies_len);
 int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
 			const u8 *peer, enum nl80211_tdls_operation oper);
-
+void ieee80211_tdls_peer_del_work(struct work_struct *wk);
 
 extern const struct ethtool_ops ieee80211_ethtool_ops;
 
@@ -1932,4 +1934,3 @@
 #endif
 
 #endif /* IEEE80211_I_H */
-void ieee80211_tdls_peer_del_work(struct work_struct *wk);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 7434ffe..b7402fe 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -5,6 +5,7 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1192,19 +1193,11 @@
 			rx_agg = (void *)&skb->cb;
 			mutex_lock(&local->sta_mtx);
 			sta = sta_info_get_bss(sdata, rx_agg->addr);
-			if (sta) {
-				u16 last_seq;
-
-				last_seq = IEEE80211_SEQ_TO_SN(le16_to_cpu(
-					sta->last_seq_ctrl[rx_agg->tid]));
-
+			if (sta)
 				__ieee80211_start_rx_ba_session(sta,
-						0, 0,
-						ieee80211_sn_inc(last_seq),
-						1, rx_agg->tid,
+						0, 0, 0, 1, rx_agg->tid,
 						IEEE80211_MAX_AMPDU_BUF,
-						false);
-			}
+						false, true);
 			mutex_unlock(&local->sta_mtx);
 		} else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_STOP) {
 			rx_agg = (void *)&skb->cb;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index d808cff..4712150 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -3,6 +3,7 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007-2008	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -130,9 +131,7 @@
 	if (!ret) {
 		key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 
-		if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-		      (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
-		      (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+		if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
 			sdata->crypto_tx_tailroom_needed_cnt--;
 
 		WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
@@ -180,9 +179,7 @@
 	sta = key->sta;
 	sdata = key->sdata;
 
-	if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-	      (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
-	      (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+	if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
 		increment_tailroom_need_count(sdata);
 
 	ret = drv_set_key(key->local, DISABLE_KEY, sdata,
@@ -425,7 +422,7 @@
 		ieee80211_aes_key_free(key->u.ccmp.tfm);
 	if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
 		ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
-	kfree(key);
+	kzfree(key);
 }
 
 static void __ieee80211_key_destroy(struct ieee80211_key *key,
@@ -878,9 +875,7 @@
 	if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
 		key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 
-		if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-		      (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
-		      (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+		if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
 			increment_tailroom_need_count(key->sdata);
 	}
 
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index ba84fb9..bc8ae88 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -2,6 +2,7 @@
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index cf032a8..a6699dc 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -729,7 +729,7 @@
 	tbl = rcu_dereference(mesh_paths);
 	for_each_mesh_entry(tbl, node, i) {
 		mpath = node->mpath;
-		if (rcu_dereference(mpath->next_hop) == sta &&
+		if (rcu_access_pointer(mpath->next_hop) == sta &&
 		    mpath->flags & MESH_PATH_ACTIVE &&
 		    !(mpath->flags & MESH_PATH_FIXED)) {
 			spin_lock_bh(&mpath->state_lock);
@@ -794,7 +794,7 @@
 	tbl = resize_dereference_mesh_paths();
 	for_each_mesh_entry(tbl, node, i) {
 		mpath = node->mpath;
-		if (rcu_dereference(mpath->next_hop) == sta) {
+		if (rcu_access_pointer(mpath->next_hop) == sta) {
 			spin_lock(&tbl->hashwlock[i]);
 			__mesh_path_del(tbl, node);
 			spin_unlock(&tbl->hashwlock[i]);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index c47194d..b488e18 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -431,14 +431,12 @@
 		return NULL;
 
 	sta->plink_state = NL80211_PLINK_LISTEN;
+	sta->sta.wme = true;
 
 	sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
 	sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
 	sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
 
-	set_sta_flag(sta, WLAN_STA_WME);
-	sta->sta.wme = true;
-
 	return sta;
 }
 
@@ -1004,7 +1002,6 @@
 	enum ieee80211_self_protected_actioncode ftype;
 	u32 changed = 0;
 	u8 ie_len = elems->peering_len;
-	__le16 _plid, _llid;
 	u16 plid, llid = 0;
 
 	if (!elems->peering) {
@@ -1039,13 +1036,10 @@
 	/* Note the lines below are correct, the llid in the frame is the plid
 	 * from the point of view of this host.
 	 */
-	memcpy(&_plid, PLINK_GET_LLID(elems->peering), sizeof(__le16));
-	plid = le16_to_cpu(_plid);
+	plid = get_unaligned_le16(PLINK_GET_LLID(elems->peering));
 	if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
-	    (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) {
-		memcpy(&_llid, PLINK_GET_PLID(elems->peering), sizeof(__le16));
-		llid = le16_to_cpu(_llid);
-	}
+	    (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
+		llid = get_unaligned_le16(PLINK_GET_PLID(elems->peering));
 
 	/* WARNING: Only for sta pointer, is dropped & re-acquired */
 	rcu_read_lock();
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b82a12a..2de8870 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -5,6 +5,7 @@
  * Copyright 2005, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -149,6 +150,7 @@
 ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
 			     struct ieee80211_supported_band *sband,
 			     struct ieee80211_channel *channel,
+			     const struct ieee80211_ht_cap *ht_cap,
 			     const struct ieee80211_ht_operation *ht_oper,
 			     const struct ieee80211_vht_operation *vht_oper,
 			     struct cfg80211_chan_def *chandef, bool tracking)
@@ -162,13 +164,19 @@
 	chandef->center_freq1 = channel->center_freq;
 	chandef->center_freq2 = 0;
 
-	if (!ht_oper || !sband->ht_cap.ht_supported) {
+	if (!ht_cap || !ht_oper || !sband->ht_cap.ht_supported) {
 		ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
 		goto out;
 	}
 
 	chandef->width = NL80211_CHAN_WIDTH_20;
 
+	if (!(ht_cap->cap_info &
+	      cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40))) {
+		ret = IEEE80211_STA_DISABLE_40MHZ;
+		goto out;
+	}
+
 	ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
 						  channel->band);
 	/* check that channel matches the right operating channel */
@@ -328,6 +336,7 @@
 
 static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
 			       struct sta_info *sta,
+			       const struct ieee80211_ht_cap *ht_cap,
 			       const struct ieee80211_ht_operation *ht_oper,
 			       const struct ieee80211_vht_operation *vht_oper,
 			       const u8 *bssid, u32 *changed)
@@ -367,8 +376,9 @@
 	sband = local->hw.wiphy->bands[chan->band];
 
 	/* calculate new channel (type) based on HT/VHT operation IEs */
-	flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper,
-					     vht_oper, &chandef, true);
+	flags = ieee80211_determine_chantype(sdata, sband, chan,
+					     ht_cap, ht_oper, vht_oper,
+					     &chandef, true);
 
 	/*
 	 * Downgrade the new channel if we associated with restricted
@@ -663,6 +673,9 @@
 	    (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
 		capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
 
+	if (ifmgd->flags & IEEE80211_STA_ENABLE_RRM)
+		capab |= WLAN_CAPABILITY_RADIO_MEASURE;
+
 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
 	memset(mgmt, 0, 24);
 	memcpy(mgmt->da, assoc_data->bss->bssid, ETH_ALEN);
@@ -728,16 +741,17 @@
 		}
 	}
 
-	if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
-		/* 1. power capabilities */
+	if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT ||
+	    capab & WLAN_CAPABILITY_RADIO_MEASURE) {
 		pos = skb_put(skb, 4);
 		*pos++ = WLAN_EID_PWR_CAPABILITY;
 		*pos++ = 2;
 		*pos++ = 0; /* min tx power */
 		 /* max tx power */
 		*pos++ = ieee80211_chandef_max_power(&chanctx_conf->def);
+	}
 
-		/* 2. supported channels */
+	if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
 		/* TODO: get this in reg domain format */
 		pos = skb_put(skb, 2 * sband->n_channels + 2);
 		*pos++ = WLAN_EID_SUPPORTED_CHANNELS;
@@ -1157,19 +1171,21 @@
 			  TU_TO_EXP_TIME(csa_ie.count * cbss->beacon_interval));
 }
 
-static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
-				       struct ieee80211_channel *channel,
-				       const u8 *country_ie, u8 country_ie_len,
-				       const u8 *pwr_constr_elem)
+static bool
+ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
+				 struct ieee80211_channel *channel,
+				 const u8 *country_ie, u8 country_ie_len,
+				 const u8 *pwr_constr_elem,
+				 int *chan_pwr, int *pwr_reduction)
 {
 	struct ieee80211_country_ie_triplet *triplet;
 	int chan = ieee80211_frequency_to_channel(channel->center_freq);
-	int i, chan_pwr, chan_increment, new_ap_level;
+	int i, chan_increment;
 	bool have_chan_pwr = false;
 
 	/* Invalid IE */
 	if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
-		return 0;
+		return false;
 
 	triplet = (void *)(country_ie + 3);
 	country_ie_len -= 3;
@@ -1197,7 +1213,7 @@
 		for (i = 0; i < triplet->chans.num_channels; i++) {
 			if (first_channel + i * chan_increment == chan) {
 				have_chan_pwr = true;
-				chan_pwr = triplet->chans.max_power;
+				*chan_pwr = triplet->chans.max_power;
 				break;
 			}
 		}
@@ -1209,18 +1225,76 @@
 		country_ie_len -= 3;
 	}
 
-	if (!have_chan_pwr)
+	if (have_chan_pwr)
+		*pwr_reduction = *pwr_constr_elem;
+	return have_chan_pwr;
+}
+
+static void ieee80211_find_cisco_dtpc(struct ieee80211_sub_if_data *sdata,
+				      struct ieee80211_channel *channel,
+				      const u8 *cisco_dtpc_ie,
+				      int *pwr_level)
+{
+	/* From practical testing, the first data byte of the DTPC element
+	 * seems to contain the requested dBm level, and the CLI on Cisco
+	 * APs clearly state the range is -127 to 127 dBm, which indicates
+	 * a signed byte, although it seemingly never actually goes negative.
+	 * The other byte seems to always be zero.
+	 */
+	*pwr_level = (__s8)cisco_dtpc_ie[4];
+}
+
+static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
+				       struct ieee80211_channel *channel,
+				       struct ieee80211_mgmt *mgmt,
+				       const u8 *country_ie, u8 country_ie_len,
+				       const u8 *pwr_constr_ie,
+				       const u8 *cisco_dtpc_ie)
+{
+	bool has_80211h_pwr = false, has_cisco_pwr = false;
+	int chan_pwr = 0, pwr_reduction_80211h = 0;
+	int pwr_level_cisco, pwr_level_80211h;
+	int new_ap_level;
+
+	if (country_ie && pwr_constr_ie &&
+	    mgmt->u.probe_resp.capab_info &
+		cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) {
+		has_80211h_pwr = ieee80211_find_80211h_pwr_constr(
+			sdata, channel, country_ie, country_ie_len,
+			pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h);
+		pwr_level_80211h =
+			max_t(int, 0, chan_pwr - pwr_reduction_80211h);
+	}
+
+	if (cisco_dtpc_ie) {
+		ieee80211_find_cisco_dtpc(
+			sdata, channel, cisco_dtpc_ie, &pwr_level_cisco);
+		has_cisco_pwr = true;
+	}
+
+	if (!has_80211h_pwr && !has_cisco_pwr)
 		return 0;
 
-	new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem);
+	/* If we have both 802.11h and Cisco DTPC, apply both limits
+	 * by picking the smallest of the two power levels advertised.
+	 */
+	if (has_80211h_pwr &&
+	    (!has_cisco_pwr || pwr_level_80211h <= pwr_level_cisco)) {
+		sdata_info(sdata,
+			   "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
+			   pwr_level_80211h, chan_pwr, pwr_reduction_80211h,
+			   sdata->u.mgd.bssid);
+		new_ap_level = pwr_level_80211h;
+	} else {  /* has_cisco_pwr is always true here. */
+		sdata_info(sdata,
+			   "Limiting TX power to %d dBm as advertised by %pM\n",
+			   pwr_level_cisco, sdata->u.mgd.bssid);
+		new_ap_level = pwr_level_cisco;
+	}
 
 	if (sdata->ap_power_level == new_ap_level)
 		return 0;
 
-	sdata_info(sdata,
-		   "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
-		   new_ap_level, chan_pwr, *pwr_constr_elem,
-		   sdata->u.mgd.bssid);
 	sdata->ap_power_level = new_ap_level;
 	if (__ieee80211_recalc_txpower(sdata))
 		return BSS_CHANGED_TXPOWER;
@@ -2677,8 +2751,7 @@
 	if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
 		set_sta_flag(sta, WLAN_STA_MFP);
 
-	if (elems.wmm_param)
-		set_sta_flag(sta, WLAN_STA_WME);
+	sta->sta.wme = elems.wmm_param;
 
 	err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
 	if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
@@ -2744,6 +2817,7 @@
 	struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
 	u16 capab_info, status_code, aid;
 	struct ieee802_11_elems elems;
+	int ac, uapsd_queues = -1;
 	u8 *pos;
 	bool reassoc;
 	struct cfg80211_bss *bss;
@@ -2813,9 +2887,15 @@
 		 * is set can cause the interface to go idle
 		 */
 		ieee80211_destroy_assoc_data(sdata, true);
+
+		/* get uapsd queues configuration */
+		uapsd_queues = 0;
+		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+			if (sdata->tx_conf[ac].uapsd)
+				uapsd_queues |= BIT(ac);
 	}
 
-	cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len);
+	cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len, uapsd_queues);
 }
 
 static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
@@ -2885,7 +2965,9 @@
 /*
  * This is the canonical list of information elements we care about,
  * the filter code also gives us all changes to the Microsoft OUI
- * (00:50:F2) vendor IE which is used for WMM which we need to track.
+ * (00:50:F2) vendor IE which is used for WMM which we need to track,
+ * as well as the DTPC IE (part of the Cisco OUI) used for signaling
+ * changes to requested client power.
  *
  * We implement beacon filtering in software since that means we can
  * avoid processing the frame here and in cfg80211, and userspace
@@ -3174,7 +3256,8 @@
 	mutex_lock(&local->sta_mtx);
 	sta = sta_info_get(sdata, bssid);
 
-	if (ieee80211_config_bw(sdata, sta, elems.ht_operation,
+	if (ieee80211_config_bw(sdata, sta,
+				elems.ht_cap_elem, elems.ht_operation,
 				elems.vht_operation, bssid, &changed)) {
 		mutex_unlock(&local->sta_mtx);
 		ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
@@ -3190,13 +3273,11 @@
 					    rx_status->band, true);
 	mutex_unlock(&local->sta_mtx);
 
-	if (elems.country_elem && elems.pwr_constr_elem &&
-	    mgmt->u.probe_resp.capab_info &
-				cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
-		changed |= ieee80211_handle_pwr_constr(sdata, chan,
-						       elems.country_elem,
-						       elems.country_elem_len,
-						       elems.pwr_constr_elem);
+	changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
+					       elems.country_elem,
+					       elems.country_elem_len,
+					       elems.pwr_constr_elem,
+					       elems.cisco_dtpc_elem);
 
 	ieee80211_bss_info_change_notify(sdata, changed);
 }
@@ -3724,7 +3805,7 @@
 	ifmgd->uapsd_max_sp_len = sdata->local->hw.uapsd_max_sp_len;
 	ifmgd->p2p_noa_index = -1;
 
-	if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)
+	if (sdata->local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS)
 		ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC;
 	else
 		ifmgd->req_smps = IEEE80211_SMPS_OFF;
@@ -3808,6 +3889,7 @@
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+	const struct ieee80211_ht_cap *ht_cap = NULL;
 	const struct ieee80211_ht_operation *ht_oper = NULL;
 	const struct ieee80211_vht_operation *vht_oper = NULL;
 	struct ieee80211_supported_band *sband;
@@ -3824,14 +3906,17 @@
 
 	if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
 	    sband->ht_cap.ht_supported) {
-		const u8 *ht_oper_ie, *ht_cap;
+		const u8 *ht_oper_ie, *ht_cap_ie;
 
 		ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION);
 		if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper))
 			ht_oper = (void *)(ht_oper_ie + 2);
 
-		ht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY);
-		if (!ht_cap || ht_cap[1] < sizeof(struct ieee80211_ht_cap)) {
+		ht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY);
+		if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap))
+			ht_cap = (void *)(ht_cap_ie + 2);
+
+		if (!ht_cap) {
 			ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
 			ht_oper = NULL;
 		}
@@ -3862,7 +3947,7 @@
 
 	ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
 						     cbss->channel,
-						     ht_oper, vht_oper,
+						     ht_cap, ht_oper, vht_oper,
 						     &chandef, false);
 
 	sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
@@ -4395,6 +4480,11 @@
 		ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED;
 	}
 
+	if (req->flags & ASSOC_REQ_USE_RRM)
+		ifmgd->flags |= IEEE80211_STA_ENABLE_RRM;
+	else
+		ifmgd->flags &= ~IEEE80211_STA_ENABLE_RRM;
+
 	if (req->crypto.control_port)
 		ifmgd->flags |= IEEE80211_STA_CONTROL_PORT;
 	else
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 8f764b4..2cd8250 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -75,7 +75,7 @@
 {
 	int j = MAX_THR_RATES;
 
-	while (j > 0 && mi->r[i].cur_tp > mi->r[tp_list[j - 1]].cur_tp)
+	while (j > 0 && mi->r[i].stats.cur_tp > mi->r[tp_list[j - 1]].stats.cur_tp)
 		j--;
 	if (j < MAX_THR_RATES - 1)
 		memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1));
@@ -92,7 +92,7 @@
 	ratetbl->rate[offset].idx = r->rix;
 	ratetbl->rate[offset].count = r->adjusted_retry_count;
 	ratetbl->rate[offset].count_cts = r->retry_count_cts;
-	ratetbl->rate[offset].count_rts = r->retry_count_rtscts;
+	ratetbl->rate[offset].count_rts = r->stats.retry_count_rtscts;
 }
 
 static void
@@ -140,44 +140,46 @@
 
 	for (i = 0; i < mi->n_rates; i++) {
 		struct minstrel_rate *mr = &mi->r[i];
+		struct minstrel_rate_stats *mrs = &mi->r[i].stats;
 
 		usecs = mr->perfect_tx_time;
 		if (!usecs)
 			usecs = 1000000;
 
-		if (unlikely(mr->attempts > 0)) {
-			mr->sample_skipped = 0;
-			mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts);
-			mr->succ_hist += mr->success;
-			mr->att_hist += mr->attempts;
-			mr->probability = minstrel_ewma(mr->probability,
-							mr->cur_prob,
-							EWMA_LEVEL);
+		if (unlikely(mrs->attempts > 0)) {
+			mrs->sample_skipped = 0;
+			mrs->cur_prob = MINSTREL_FRAC(mrs->success,
+						      mrs->attempts);
+			mrs->succ_hist += mrs->success;
+			mrs->att_hist += mrs->attempts;
+			mrs->probability = minstrel_ewma(mrs->probability,
+							 mrs->cur_prob,
+							 EWMA_LEVEL);
 		} else
-			mr->sample_skipped++;
+			mrs->sample_skipped++;
 
-		mr->last_success = mr->success;
-		mr->last_attempts = mr->attempts;
-		mr->success = 0;
-		mr->attempts = 0;
+		mrs->last_success = mrs->success;
+		mrs->last_attempts = mrs->attempts;
+		mrs->success = 0;
+		mrs->attempts = 0;
 
 		/* Update throughput per rate, reset thr. below 10% success */
-		if (mr->probability < MINSTREL_FRAC(10, 100))
-			mr->cur_tp = 0;
+		if (mrs->probability < MINSTREL_FRAC(10, 100))
+			mrs->cur_tp = 0;
 		else
-			mr->cur_tp = mr->probability * (1000000 / usecs);
+			mrs->cur_tp = mrs->probability * (1000000 / usecs);
 
 		/* Sample less often below the 10% chance of success.
 		 * Sample less often above the 95% chance of success. */
-		if (mr->probability > MINSTREL_FRAC(95, 100) ||
-		    mr->probability < MINSTREL_FRAC(10, 100)) {
-			mr->adjusted_retry_count = mr->retry_count >> 1;
+		if (mrs->probability > MINSTREL_FRAC(95, 100) ||
+		    mrs->probability < MINSTREL_FRAC(10, 100)) {
+			mr->adjusted_retry_count = mrs->retry_count >> 1;
 			if (mr->adjusted_retry_count > 2)
 				mr->adjusted_retry_count = 2;
 			mr->sample_limit = 4;
 		} else {
 			mr->sample_limit = -1;
-			mr->adjusted_retry_count = mr->retry_count;
+			mr->adjusted_retry_count = mrs->retry_count;
 		}
 		if (!mr->adjusted_retry_count)
 			mr->adjusted_retry_count = 2;
@@ -190,11 +192,11 @@
 		 * choose the maximum throughput rate as max_prob_rate
 		 * (2) if all success probabilities < 95%, the rate with
 		 * highest success probability is choosen as max_prob_rate */
-		if (mr->probability >= MINSTREL_FRAC(95, 100)) {
-			if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp)
+		if (mrs->probability >= MINSTREL_FRAC(95, 100)) {
+			if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp)
 				tmp_prob_rate = i;
 		} else {
-			if (mr->probability >= mi->r[tmp_prob_rate].probability)
+			if (mrs->probability >= mi->r[tmp_prob_rate].stats.probability)
 				tmp_prob_rate = i;
 		}
 	}
@@ -240,14 +242,14 @@
 		if (ndx < 0)
 			continue;
 
-		mi->r[ndx].attempts += ar[i].count;
+		mi->r[ndx].stats.attempts += ar[i].count;
 
 		if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
-			mi->r[ndx].success += success;
+			mi->r[ndx].stats.success += success;
 	}
 
 	if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0))
-		mi->sample_count++;
+		mi->sample_packets++;
 
 	if (mi->sample_deferred > 0)
 		mi->sample_deferred--;
@@ -265,7 +267,7 @@
 	unsigned int retry = mr->adjusted_retry_count;
 
 	if (info->control.use_rts)
-		retry = max(2U, min(mr->retry_count_rtscts, retry));
+		retry = max(2U, min(mr->stats.retry_count_rtscts, retry));
 	else if (info->control.use_cts_prot)
 		retry = max(2U, min(mr->retry_count_cts, retry));
 	return retry;
@@ -317,15 +319,15 @@
 		sampling_ratio = mp->lookaround_rate;
 
 	/* increase sum packet counter */
-	mi->packet_count++;
+	mi->total_packets++;
 
 #ifdef CPTCFG_MAC80211_DEBUGFS
 	if (mp->fixed_rate_idx != -1)
 		return;
 #endif
 
-	delta = (mi->packet_count * sampling_ratio / 100) -
-			(mi->sample_count + mi->sample_deferred / 2);
+	delta = (mi->total_packets * sampling_ratio / 100) -
+			(mi->sample_packets + mi->sample_deferred / 2);
 
 	/* delta < 0: no sampling required */
 	prev_sample = mi->prev_sample;
@@ -333,10 +335,10 @@
 	if (delta < 0 || (!mrr_capable && prev_sample))
 		return;
 
-	if (mi->packet_count >= 10000) {
+	if (mi->total_packets >= 10000) {
 		mi->sample_deferred = 0;
-		mi->sample_count = 0;
-		mi->packet_count = 0;
+		mi->sample_packets = 0;
+		mi->total_packets = 0;
 	} else if (delta > mi->n_rates * 2) {
 		/* With multi-rate retry, not every planned sample
 		 * attempt actually gets used, due to the way the retry
@@ -347,7 +349,7 @@
 		 * starts getting worse, minstrel would start bursting
 		 * out lots of sampling frames, which would result
 		 * in a large throughput loss. */
-		mi->sample_count += (delta - mi->n_rates * 2);
+		mi->sample_packets += (delta - mi->n_rates * 2);
 	}
 
 	/* get next random rate sample */
@@ -361,7 +363,7 @@
 	 */
 	if (mrr_capable &&
 	    msr->perfect_tx_time > mr->perfect_tx_time &&
-	    msr->sample_skipped < 20) {
+	    msr->stats.sample_skipped < 20) {
 		/* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark
 		 * packets that have the sampling rate deferred to the
 		 * second MRR stage. Increase the sample counter only
@@ -375,7 +377,7 @@
 		if (!msr->sample_limit != 0)
 			return;
 
-		mi->sample_count++;
+		mi->sample_packets++;
 		if (msr->sample_limit > 0)
 			msr->sample_limit--;
 	}
@@ -384,7 +386,7 @@
 	 * has a probability of >95%, we shouldn't be attempting
 	 * to use it, as this only wastes precious airtime */
 	if (!mrr_capable &&
-	   (mi->r[ndx].probability > MINSTREL_FRAC(95, 100)))
+	   (mi->r[ndx].stats.probability > MINSTREL_FRAC(95, 100)))
 		return;
 
 	mi->prev_sample = true;
@@ -459,6 +461,7 @@
 
 	for (i = 0; i < sband->n_bitrates; i++) {
 		struct minstrel_rate *mr = &mi->r[n];
+		struct minstrel_rate_stats *mrs = &mi->r[n].stats;
 		unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0;
 		unsigned int tx_time_single;
 		unsigned int cw = mp->cw_min;
@@ -471,6 +474,7 @@
 
 		n++;
 		memset(mr, 0, sizeof(*mr));
+		memset(mrs, 0, sizeof(*mrs));
 
 		mr->rix = i;
 		shift = ieee80211_chandef_get_shift(chandef);
@@ -482,9 +486,9 @@
 		/* calculate maximum number of retransmissions before
 		 * fallback (based on maximum segment size) */
 		mr->sample_limit = -1;
-		mr->retry_count = 1;
+		mrs->retry_count = 1;
 		mr->retry_count_cts = 1;
-		mr->retry_count_rtscts = 1;
+		mrs->retry_count_rtscts = 1;
 		tx_time = mr->perfect_tx_time + mi->sp_ack_dur;
 		do {
 			/* add one retransmission */
@@ -501,13 +505,13 @@
 				(mr->retry_count_cts < mp->max_retry))
 				mr->retry_count_cts++;
 			if ((tx_time_rtscts < mp->segment_size) &&
-				(mr->retry_count_rtscts < mp->max_retry))
-				mr->retry_count_rtscts++;
+				(mrs->retry_count_rtscts < mp->max_retry))
+				mrs->retry_count_rtscts++;
 		} while ((tx_time < mp->segment_size) &&
-				(++mr->retry_count < mp->max_retry));
-		mr->adjusted_retry_count = mr->retry_count;
+				(++mr->stats.retry_count < mp->max_retry));
+		mr->adjusted_retry_count = mrs->retry_count;
 		if (!(sband->bitrates[i].flags & IEEE80211_RATE_ERP_G))
-			mr->retry_count_cts = mr->retry_count;
+			mr->retry_count_cts = mrs->retry_count;
 	}
 
 	for (i = n; i < sband->n_bitrates; i++) {
@@ -665,7 +669,7 @@
 	/* convert pkt per sec in kbps (1200 is the average pkt size used for
 	 * computing cur_tp
 	 */
-	return MINSTREL_TRUNC(mi->r[idx].cur_tp) * 1200 * 8 / 1024;
+	return MINSTREL_TRUNC(mi->r[idx].stats.cur_tp) * 1200 * 8 / 1024;
 }
 
 const struct rate_control_ops mac80211_minstrel = {
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index eba85e5..554ca0b 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -31,6 +31,27 @@
 	return (new * (EWMA_DIV - weight) + old * weight) / EWMA_DIV;
 }
 
+struct minstrel_rate_stats {
+	/* current / last sampling period attempts/success counters */
+	unsigned int attempts, last_attempts;
+	unsigned int success, last_success;
+
+	/* total attempts/success counters */
+	u64 att_hist, succ_hist;
+
+	/* current throughput */
+	unsigned int cur_tp;
+
+	/* packet delivery probabilities */
+	unsigned int cur_prob, probability;
+
+	/* maximum retry counts */
+	unsigned int retry_count;
+	unsigned int retry_count_rtscts;
+
+	u8 sample_skipped;
+	bool retry_updated;
+};
 
 struct minstrel_rate {
 	int bitrate;
@@ -40,26 +61,10 @@
 	unsigned int ack_time;
 
 	int sample_limit;
-	unsigned int retry_count;
 	unsigned int retry_count_cts;
-	unsigned int retry_count_rtscts;
 	unsigned int adjusted_retry_count;
 
-	u32 success;
-	u32 attempts;
-	u32 last_attempts;
-	u32 last_success;
-	u8 sample_skipped;
-
-	/* parts per thousand */
-	u32 cur_prob;
-	u32 probability;
-
-	/* per-rate throughput */
-	u32 cur_tp;
-
-	u64 succ_hist;
-	u64 att_hist;
+	struct minstrel_rate_stats stats;
 };
 
 struct minstrel_sta_info {
@@ -73,8 +78,8 @@
 
 	u8 max_tp_rate[MAX_THR_RATES];
 	u8 max_prob_rate;
-	unsigned int packet_count;
-	unsigned int sample_count;
+	unsigned int total_packets;
+	unsigned int sample_packets;
 	int sample_deferred;
 
 	unsigned int sample_row;
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c
index fd0b9ca..edde723 100644
--- a/net/mac80211/rc80211_minstrel_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_debugfs.c
@@ -72,6 +72,7 @@
 			"this succ/attempt   success    attempts\n");
 	for (i = 0; i < mi->n_rates; i++) {
 		struct minstrel_rate *mr = &mi->r[i];
+		struct minstrel_rate_stats *mrs = &mi->r[i].stats;
 
 		*(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' ';
 		*(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' ';
@@ -81,24 +82,24 @@
 		p += sprintf(p, "%3u%s", mr->bitrate / 2,
 				(mr->bitrate & 1 ? ".5" : "  "));
 
-		tp = MINSTREL_TRUNC(mr->cur_tp / 10);
-		prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
-		eprob = MINSTREL_TRUNC(mr->probability * 1000);
+		tp = MINSTREL_TRUNC(mrs->cur_tp / 10);
+		prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
+		eprob = MINSTREL_TRUNC(mrs->probability * 1000);
 
 		p += sprintf(p, "  %6u.%1u   %6u.%1u   %6u.%1u        "
 				"   %3u(%3u)  %8llu    %8llu\n",
 				tp / 10, tp % 10,
 				eprob / 10, eprob % 10,
 				prob / 10, prob % 10,
-				mr->last_success,
-				mr->last_attempts,
-				(unsigned long long)mr->succ_hist,
-				(unsigned long long)mr->att_hist);
+				mrs->last_success,
+				mrs->last_attempts,
+				(unsigned long long)mrs->succ_hist,
+				(unsigned long long)mrs->att_hist);
 	}
 	p += sprintf(p, "\nTotal packet count::    ideal %d      "
 			"lookaround %d\n\n",
-			mi->packet_count - mi->sample_count,
-			mi->sample_count);
+			mi->total_packets - mi->sample_packets,
+			mi->sample_packets);
 	ms->len = p - ms->buf;
 
 	return 0;
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index f77baec..08f80e8 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -135,7 +135,7 @@
 static int
 minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
 {
-	return GROUP_IDX((rate->idx / 8) + 1,
+	return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1,
 			 !!(rate->flags & IEEE80211_TX_RC_SHORT_GI),
 			 !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
 }
@@ -233,12 +233,151 @@
 }
 
 /*
+ * Find & sort topmost throughput rates
+ *
+ * If multiple rates provide equal throughput the sorting is based on their
+ * current success probability. Higher success probability is preferred among
+ * MCS groups, CCK rates do not provide aggregation and are therefore at last.
+ */
+static void
+minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u8 index,
+			       u8 *tp_list)
+{
+	int cur_group, cur_idx, cur_thr, cur_prob;
+	int tmp_group, tmp_idx, tmp_thr, tmp_prob;
+	int j = MAX_THR_RATES;
+
+	cur_group = index / MCS_GROUP_RATES;
+	cur_idx = index  % MCS_GROUP_RATES;
+	cur_thr = mi->groups[cur_group].rates[cur_idx].cur_tp;
+	cur_prob = mi->groups[cur_group].rates[cur_idx].probability;
+
+	tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
+	tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
+	tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
+	tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability;
+
+	while (j > 0 && (cur_thr > tmp_thr ||
+	      (cur_thr == tmp_thr && cur_prob > tmp_prob))) {
+		j--;
+		tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
+		tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
+		tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
+		tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability;
+	}
+
+	if (j < MAX_THR_RATES - 1) {
+		memmove(&tp_list[j + 1], &tp_list[j], (sizeof(*tp_list) *
+		       (MAX_THR_RATES - (j + 1))));
+	}
+	if (j < MAX_THR_RATES)
+		tp_list[j] = index;
+}
+
+/*
+ * Find and set the topmost probability rate per sta and per group
+ */
+static void
+minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u8 index)
+{
+	struct minstrel_mcs_group_data *mg;
+	struct minstrel_rate_stats *mr;
+	int tmp_group, tmp_idx, tmp_tp, tmp_prob, max_tp_group;
+
+	mg = &mi->groups[index / MCS_GROUP_RATES];
+	mr = &mg->rates[index % MCS_GROUP_RATES];
+
+	tmp_group = mi->max_prob_rate / MCS_GROUP_RATES;
+	tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES;
+	tmp_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
+	tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability;
+
+	/* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from
+	 * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */
+	max_tp_group = mi->max_tp_rate[0] / MCS_GROUP_RATES;
+	if((index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) &&
+	    (max_tp_group != MINSTREL_CCK_GROUP))
+		return;
+
+	if (mr->probability > MINSTREL_FRAC(75, 100)) {
+		if (mr->cur_tp > tmp_tp)
+			mi->max_prob_rate = index;
+		if (mr->cur_tp > mg->rates[mg->max_group_prob_rate].cur_tp)
+			mg->max_group_prob_rate = index;
+	} else {
+		if (mr->probability > tmp_prob)
+			mi->max_prob_rate = index;
+		if (mr->probability > mg->rates[mg->max_group_prob_rate].probability)
+			mg->max_group_prob_rate = index;
+	}
+}
+
+
+/*
+ * Assign new rate set per sta and use CCK rates only if the fastest
+ * rate (max_tp_rate[0]) is from CCK group. This prohibits such sorted
+ * rate sets where MCS and CCK rates are mixed, because CCK rates can
+ * not use aggregation.
+ */
+static void
+minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi,
+				 u8 tmp_mcs_tp_rate[MAX_THR_RATES],
+				 u8 tmp_cck_tp_rate[MAX_THR_RATES])
+{
+	unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp;
+	int i;
+
+	tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES;
+	tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES;
+	tmp_cck_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
+
+	tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES;
+	tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES;
+	tmp_mcs_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
+
+	if (tmp_cck_tp > tmp_mcs_tp) {
+		for(i = 0; i < MAX_THR_RATES; i++) {
+			minstrel_ht_sort_best_tp_rates(mi, tmp_cck_tp_rate[i],
+						       tmp_mcs_tp_rate);
+		}
+	}
+
+}
+
+/*
+ * Try to increase robustness of max_prob rate by decrease number of
+ * streams if possible.
+ */
+static inline void
+minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
+{
+	struct minstrel_mcs_group_data *mg;
+	struct minstrel_rate_stats *mr;
+	int tmp_max_streams, group;
+	int tmp_tp = 0;
+
+	tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] /
+			  MCS_GROUP_RATES].streams;
+	for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+		mg = &mi->groups[group];
+		if (!mg->supported || group == MINSTREL_CCK_GROUP)
+			continue;
+		mr = minstrel_get_ratestats(mi, mg->max_group_prob_rate);
+		if (tmp_tp < mr->cur_tp &&
+		   (minstrel_mcs_groups[group].streams < tmp_max_streams)) {
+				mi->max_prob_rate = mg->max_group_prob_rate;
+				tmp_tp = mr->cur_tp;
+		}
+	}
+}
+
+/*
  * Update rate statistics and select new primary rates
  *
  * Rules for rate selection:
  *  - max_prob_rate must use only one stream, as a tradeoff between delivery
  *    probability and throughput during strong fluctuations
- *  - as long as the max prob rate has a probability of more than 3/4, pick
+ *  - as long as the max prob rate has a probability of more than 75%, pick
  *    higher throughput rates, even if the probablity is a bit lower
  */
 static void
@@ -246,9 +385,9 @@
 {
 	struct minstrel_mcs_group_data *mg;
 	struct minstrel_rate_stats *mr;
-	int cur_prob, cur_prob_tp, cur_tp, cur_tp2;
-	int group, i, index;
-	bool mi_rates_valid = false;
+	int group, i, j;
+	u8 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES];
+	u8 tmp_cck_tp_rate[MAX_THR_RATES], index;
 
 	if (mi->ampdu_packets > 0) {
 		mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len,
@@ -260,13 +399,14 @@
 	mi->sample_slow = 0;
 	mi->sample_count = 0;
 
-	for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
-		bool mg_rates_valid = false;
+	/* Initialize global rate indexes */
+	for(j = 0; j < MAX_THR_RATES; j++){
+		tmp_mcs_tp_rate[j] = 0;
+		tmp_cck_tp_rate[j] = 0;
+	}
 
-		cur_prob = 0;
-		cur_prob_tp = 0;
-		cur_tp = 0;
-		cur_tp2 = 0;
+	/* Find best rate sets within all MCS groups*/
+	for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
 
 		mg = &mi->groups[group];
 		if (!mg->supported)
@@ -274,24 +414,16 @@
 
 		mi->sample_count++;
 
+		/* (re)Initialize group rate indexes */
+		for(j = 0; j < MAX_THR_RATES; j++)
+			tmp_group_tp_rate[j] = group;
+
 		for (i = 0; i < MCS_GROUP_RATES; i++) {
 			if (!(mg->supported & BIT(i)))
 				continue;
 
 			index = MCS_GROUP_RATES * group + i;
 
-			/* initialize rates selections starting indexes */
-			if (!mg_rates_valid) {
-				mg->max_tp_rate = mg->max_tp_rate2 =
-					mg->max_prob_rate = i;
-				if (!mi_rates_valid) {
-					mi->max_tp_rate = mi->max_tp_rate2 =
-						mi->max_prob_rate = index;
-					mi_rates_valid = true;
-				}
-				mg_rates_valid = true;
-			}
-
 			mr = &mg->rates[i];
 			mr->retry_updated = false;
 			minstrel_calc_rate_ewma(mr);
@@ -300,82 +432,47 @@
 			if (!mr->cur_tp)
 				continue;
 
-			if ((mr->cur_tp > cur_prob_tp && mr->probability >
-			     MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) {
-				mg->max_prob_rate = index;
-				cur_prob = mr->probability;
-				cur_prob_tp = mr->cur_tp;
+			/* Find max throughput rate set */
+			if (group != MINSTREL_CCK_GROUP) {
+				minstrel_ht_sort_best_tp_rates(mi, index,
+							       tmp_mcs_tp_rate);
+			} else if (group == MINSTREL_CCK_GROUP) {
+				minstrel_ht_sort_best_tp_rates(mi, index,
+							       tmp_cck_tp_rate);
 			}
 
-			if (mr->cur_tp > cur_tp) {
-				swap(index, mg->max_tp_rate);
-				cur_tp = mr->cur_tp;
-				mr = minstrel_get_ratestats(mi, index);
-			}
+			/* Find max throughput rate set within a group */
+			minstrel_ht_sort_best_tp_rates(mi, index,
+						       tmp_group_tp_rate);
 
-			if (index >= mg->max_tp_rate)
-				continue;
-
-			if (mr->cur_tp > cur_tp2) {
-				mg->max_tp_rate2 = index;
-				cur_tp2 = mr->cur_tp;
-			}
+			/* Find max probability rate per group and global */
+			minstrel_ht_set_best_prob_rate(mi, index);
 		}
+
+		memcpy(mg->max_group_tp_rate, tmp_group_tp_rate,
+		       sizeof(mg->max_group_tp_rate));
 	}
 
+	/* Assign new rate set per sta */
+	minstrel_ht_assign_best_tp_rates(mi, tmp_mcs_tp_rate, tmp_cck_tp_rate);
+	memcpy(mi->max_tp_rate, tmp_mcs_tp_rate, sizeof(mi->max_tp_rate));
+
+	/* Try to increase robustness of max_prob_rate*/
+	minstrel_ht_prob_rate_reduce_streams(mi);
+
 	/* try to sample all available rates during each interval */
 	mi->sample_count *= 8;
 
-	cur_prob = 0;
-	cur_prob_tp = 0;
-	cur_tp = 0;
-	cur_tp2 = 0;
-	for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
-		mg = &mi->groups[group];
-		if (!mg->supported)
-			continue;
-
-		mr = minstrel_get_ratestats(mi, mg->max_tp_rate);
-		if (cur_tp < mr->cur_tp) {
-			mi->max_tp_rate2 = mi->max_tp_rate;
-			cur_tp2 = cur_tp;
-			mi->max_tp_rate = mg->max_tp_rate;
-			cur_tp = mr->cur_tp;
-			mi->max_prob_streams = minstrel_mcs_groups[group].streams - 1;
-		}
-
-		mr = minstrel_get_ratestats(mi, mg->max_tp_rate2);
-		if (cur_tp2 < mr->cur_tp) {
-			mi->max_tp_rate2 = mg->max_tp_rate2;
-			cur_tp2 = mr->cur_tp;
-		}
-	}
-
-	if (mi->max_prob_streams < 1)
-		mi->max_prob_streams = 1;
-
-	for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
-		mg = &mi->groups[group];
-		if (!mg->supported)
-			continue;
-		mr = minstrel_get_ratestats(mi, mg->max_prob_rate);
-		if (cur_prob_tp < mr->cur_tp &&
-		    minstrel_mcs_groups[group].streams <= mi->max_prob_streams) {
-			mi->max_prob_rate = mg->max_prob_rate;
-			cur_prob = mr->cur_prob;
-			cur_prob_tp = mr->cur_tp;
-		}
-	}
-
 #ifdef CPTCFG_MAC80211_DEBUGFS
 	/* use fixed index if set */
 	if (mp->fixed_rate_idx != -1) {
-		mi->max_tp_rate = mp->fixed_rate_idx;
-		mi->max_tp_rate2 = mp->fixed_rate_idx;
+		for (i = 0; i < 4; i++)
+			mi->max_tp_rate[i] = mp->fixed_rate_idx;
 		mi->max_prob_rate = mp->fixed_rate_idx;
 	}
 #endif
 
+	/* Reset update timer */
 	mi->stats_update = jiffies;
 }
 
@@ -420,8 +517,7 @@
 }
 
 static void
-minstrel_downgrade_rate(struct minstrel_ht_sta *mi, unsigned int *idx,
-			bool primary)
+minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u8 *idx, bool primary)
 {
 	int group, orig_group;
 
@@ -437,9 +533,9 @@
 			continue;
 
 		if (primary)
-			*idx = mi->groups[group].max_tp_rate;
+			*idx = mi->groups[group].max_group_tp_rate[0];
 		else
-			*idx = mi->groups[group].max_tp_rate2;
+			*idx = mi->groups[group].max_group_tp_rate[1];
 		break;
 	}
 }
@@ -524,19 +620,19 @@
 	 * check for sudden death of spatial multiplexing,
 	 * downgrade to a lower number of streams if necessary.
 	 */
-	rate = minstrel_get_ratestats(mi, mi->max_tp_rate);
+	rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]);
 	if (rate->attempts > 30 &&
 	    MINSTREL_FRAC(rate->success, rate->attempts) <
 	    MINSTREL_FRAC(20, 100)) {
-		minstrel_downgrade_rate(mi, &mi->max_tp_rate, true);
+		minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true);
 		update = true;
 	}
 
-	rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2);
+	rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]);
 	if (rate2->attempts > 30 &&
 	    MINSTREL_FRAC(rate2->success, rate2->attempts) <
 	    MINSTREL_FRAC(20, 100)) {
-		minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false);
+		minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false);
 		update = true;
 	}
 
@@ -661,12 +757,12 @@
 	if (!rates)
 		return;
 
-	/* Start with max_tp_rate */
-	minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate);
+	/* Start with max_tp_rate[0] */
+	minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate[0]);
 
 	if (mp->hw->max_rates >= 3) {
-		/* At least 3 tx rates supported, use max_tp_rate2 next */
-		minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate2);
+		/* At least 3 tx rates supported, use max_tp_rate[1] next */
+		minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate[1]);
 	}
 
 	if (mp->hw->max_rates >= 2) {
@@ -691,7 +787,7 @@
 {
 	struct minstrel_rate_stats *mr;
 	struct minstrel_mcs_group_data *mg;
-	unsigned int sample_dur, sample_group;
+	unsigned int sample_dur, sample_group, cur_max_tp_streams;
 	int sample_idx = 0;
 
 	if (mi->sample_wait > 0) {
@@ -718,8 +814,8 @@
 	 * to the frame. Hence, don't use sampling for the currently
 	 * used rates.
 	 */
-	if (sample_idx == mi->max_tp_rate ||
-	    sample_idx == mi->max_tp_rate2 ||
+	if (sample_idx == mi->max_tp_rate[0] ||
+	    sample_idx == mi->max_tp_rate[1] ||
 	    sample_idx == mi->max_prob_rate)
 		return -1;
 
@@ -734,9 +830,12 @@
 	 * Make sure that lower rates get sampled only occasionally,
 	 * if the link is working perfectly.
 	 */
+
+	cur_max_tp_streams = minstrel_mcs_groups[mi->max_tp_rate[0] /
+		MCS_GROUP_RATES].streams;
 	sample_dur = minstrel_get_duration(sample_idx);
-	if (sample_dur >= minstrel_get_duration(mi->max_tp_rate2) &&
-	    (mi->max_prob_streams <
+	if (sample_dur >= minstrel_get_duration(mi->max_tp_rate[1]) &&
+	    (cur_max_tp_streams - 1 <
 	     minstrel_mcs_groups[sample_group].streams ||
 	     sample_dur >= minstrel_get_duration(mi->max_prob_rate))) {
 		if (mr->sample_skipped < 20)
@@ -1041,8 +1140,8 @@
 	if (!msp->is_ht)
 		return mac80211_minstrel.get_expected_throughput(priv_sta);
 
-	i = mi->max_tp_rate / MCS_GROUP_RATES;
-	j = mi->max_tp_rate % MCS_GROUP_RATES;
+	i = mi->max_tp_rate[0] / MCS_GROUP_RATES;
+	j = mi->max_tp_rate[0] % MCS_GROUP_RATES;
 
 	/* convert cur_tp from pkt per second in kbps */
 	return mi->groups[i].rates[j].cur_tp * AVG_PKT_SIZE * 8 / 1024;
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
index 6dea374..0a76823 100644
--- a/net/mac80211/rc80211_minstrel_ht.h
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -26,28 +26,6 @@
 
 extern const struct mcs_group minstrel_mcs_groups[];
 
-struct minstrel_rate_stats {
-	/* current / last sampling period attempts/success counters */
-	unsigned int attempts, last_attempts;
-	unsigned int success, last_success;
-
-	/* total attempts/success counters */
-	u64 att_hist, succ_hist;
-
-	/* current throughput */
-	unsigned int cur_tp;
-
-	/* packet delivery probabilities */
-	unsigned int cur_prob, probability;
-
-	/* maximum retry counts */
-	unsigned int retry_count;
-	unsigned int retry_count_rtscts;
-
-	bool retry_updated;
-	u8 sample_skipped;
-};
-
 struct minstrel_mcs_group_data {
 	u8 index;
 	u8 column;
@@ -55,10 +33,9 @@
 	/* bitfield of supported MCS rates of this group */
 	u8 supported;
 
-	/* selected primary rates */
-	unsigned int max_tp_rate;
-	unsigned int max_tp_rate2;
-	unsigned int max_prob_rate;
+	/* sorted rate set within a MCS group*/
+	u8 max_group_tp_rate[MAX_THR_RATES];
+	u8 max_group_prob_rate;
 
 	/* MCS rate statistics */
 	struct minstrel_rate_stats rates[MCS_GROUP_RATES];
@@ -74,15 +51,9 @@
 	/* ampdu length (EWMA) */
 	unsigned int avg_ampdu_len;
 
-	/* best throughput rate */
-	unsigned int max_tp_rate;
-
-	/* second best throughput rate */
-	unsigned int max_tp_rate2;
-
-	/* best probability rate */
-	unsigned int max_prob_rate;
-	unsigned int max_prob_streams;
+	/* overall sorted rate set */
+	u8 max_tp_rate[MAX_THR_RATES];
+	u8 max_prob_rate;
 
 	/* time of last status update */
 	unsigned long stats_update;
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
index 3e7d793..a72ad46 100644
--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -46,8 +46,10 @@
 		else
 			p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);
 
-		*(p++) = (idx == mi->max_tp_rate) ? 'T' : ' ';
-		*(p++) = (idx == mi->max_tp_rate2) ? 't' : ' ';
+		*(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' ';
+		*(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' ';
+		*(p++) = (idx == mi->max_tp_rate[2]) ? 'C' : ' ';
+		*(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' ';
 		*(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
 
 		if (i == max_mcs) {
@@ -100,8 +102,8 @@
 
 	file->private_data = ms;
 	p = ms->buf;
-	p += sprintf(p, "type         rate     throughput  ewma prob   this prob  "
-			"retry   this succ/attempt   success    attempts\n");
+	p += sprintf(p, "type           rate     throughput  ewma prob   "
+		     "this prob  retry   this succ/attempt   success    attempts\n");
 
 	p = minstrel_ht_stats_dump(mi, max_mcs, p);
 	for (i = 0; i < max_mcs; i++)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index d39df6a..09f5387 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3,6 +3,7 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007-2010	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -835,6 +836,16 @@
 
 	spin_lock(&tid_agg_rx->reorder_lock);
 
+	/*
+	 * Offloaded BA sessions have no known starting sequence number so pick
+	 * one from first Rxed frame for this tid after BA was started.
+	 */
+	if (unlikely(tid_agg_rx->auto_seq)) {
+		tid_agg_rx->auto_seq = false;
+		tid_agg_rx->ssn = mpdu_seq_num;
+		tid_agg_rx->head_seq_num = mpdu_seq_num;
+	}
+
 	buf_size = tid_agg_rx->buf_size;
 	head_seq_num = tid_agg_rx->head_seq_num;
 
@@ -2725,7 +2736,7 @@
 		sig = status->signal;
 
 	if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig,
-			     rx->skb->data, rx->skb->len, 0, GFP_ATOMIC)) {
+			     rx->skb->data, rx->skb->len, 0)) {
 		if (rx->sta)
 			rx->sta->rx_packets++;
 		dev_kfree_skb(rx->skb);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index a0a9381..af0d094 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -6,6 +6,7 @@
  * Copyright 2005, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1094,7 +1095,7 @@
 	if (rcu_access_pointer(local->sched_scan_sdata)) {
 		ret = drv_sched_scan_stop(local, sdata);
 		if (!ret)
-			rcu_assign_pointer(local->sched_scan_sdata, NULL);
+			RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
 	}
 out:
 	mutex_unlock(&local->mtx);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ea238cd..9cefdbd 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1,6 +1,7 @@
 /*
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1182,7 +1183,7 @@
 	struct sk_buff *skb;
 	int size = sizeof(*nullfunc);
 	__le16 fc;
-	bool qos = test_sta_flag(sta, WLAN_STA_WME);
+	bool qos = sta->sta.wme;
 	struct ieee80211_tx_info *info;
 	struct ieee80211_chanctx_conf *chanctx_conf;
 
@@ -1837,7 +1838,7 @@
 		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
 	if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))
 		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
-	if (test_sta_flag(sta, WLAN_STA_WME))
+	if (sta->sta.wme)
 		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME);
 	if (test_sta_flag(sta, WLAN_STA_MFP))
 		sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 08ef729..3aabd74 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -1,5 +1,6 @@
 /*
  * Copyright 2002-2005, Devicescape Software, Inc.
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -31,7 +32,6 @@
  *	when virtual port control is not in use.
  * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
  *	frames.
- * @WLAN_STA_WME: Station is a QoS-STA.
  * @WLAN_STA_WDS: Station is one of our WDS peers.
  * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
  *	IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
@@ -69,7 +69,6 @@
 	WLAN_STA_PS_STA,
 	WLAN_STA_AUTHORIZED,
 	WLAN_STA_SHORT_PREAMBLE,
-	WLAN_STA_WME,
 	WLAN_STA_WDS,
 	WLAN_STA_CLEAR_PS_FILT,
 	WLAN_STA_MFP,
@@ -169,6 +168,8 @@
  * @dialog_token: dialog token for aggregation session
  * @rcu_head: RCU head used for freeing this struct
  * @reorder_lock: serializes access to reorder buffer, see below.
+ * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and
+ *	and ssn.
  *
  * This structure's lifetime is managed by RCU, assignments to
  * the array holding it must hold the aggregation mutex.
@@ -192,6 +193,7 @@
 	u16 buf_size;
 	u16 timeout;
 	u8 dialog_token;
+	bool auto_seq;
 };
 
 /**
@@ -448,6 +450,9 @@
 	enum ieee80211_smps_mode known_smps_mode;
 	const struct ieee80211_cipher_scheme *cipher_scheme;
 
+	/* TDLS timeout data */
+	unsigned long last_tdls_pkt_time;
+
 	/* keep last! */
 	struct ieee80211_sta sta;
 };
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index aa06dca..89290e3 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -3,6 +3,7 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2008-2010	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -537,6 +538,8 @@
  *  - current throughput (higher value for higher tpt)?
  */
 #define STA_LOST_PKT_THRESHOLD	50
+#define STA_LOST_TDLS_PKT_THRESHOLD	10
+#define STA_LOST_TDLS_PKT_TIME		(10*HZ) /* 10secs since last ACK */
 
 static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
 {
@@ -547,7 +550,20 @@
 	    !(info->flags & IEEE80211_TX_STAT_AMPDU))
 		return;
 
-	if (++sta->lost_packets < STA_LOST_PKT_THRESHOLD)
+	sta->lost_packets++;
+	if (!sta->sta.tdls && sta->lost_packets < STA_LOST_PKT_THRESHOLD)
+		return;
+
+	/*
+	 * If we're in TDLS mode, make sure that all STA_LOST_TDLS_PKT_THRESHOLD
+	 * of the last packets were lost, and that no ACK was received in the
+	 * last STA_LOST_TDLS_PKT_TIME ms, before triggering the CQM packet-loss
+	 * mechanism.
+	 */
+	if (sta->sta.tdls &&
+	    (sta->lost_packets < STA_LOST_TDLS_PKT_THRESHOLD ||
+	     time_before(jiffies,
+			 sta->last_tdls_pkt_time + STA_LOST_TDLS_PKT_TIME)))
 		return;
 
 	cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
@@ -694,6 +710,10 @@
 			if (info->flags & IEEE80211_TX_STAT_ACK) {
 				if (sta->lost_packets)
 					sta->lost_packets = 0;
+
+				/* Track when last TDLS packet was ACKed */
+				if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
+					sta->last_tdls_pkt_time = jiffies;
 			} else {
 				ieee80211_lost_packet(sta, skb);
 			}
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index 1b21050..4ea25de 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -3,6 +3,7 @@
  *
  * Copyright 2006-2010	Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2014, Intel Corporation
+ * Copyright 2014  Intel Mobile Communications GmbH
  *
  * This file is GPLv2 as found in COPYING.
  */
@@ -316,8 +317,7 @@
 	}
 
 	/* add the QoS param IE if both the peer and we support it */
-	if (local->hw.queues >= IEEE80211_NUM_ACS &&
-	    test_sta_flag(sta, WLAN_STA_WME))
+	if (local->hw.queues >= IEEE80211_NUM_ACS && sta->sta.wme)
 		ieee80211_tdls_add_wmm_param_ie(sdata, skb);
 
 	/* add any custom IEs that go before HT operation */
@@ -412,6 +412,9 @@
 	tf->ether_type = cpu_to_be16(ETH_P_TDLS);
 	tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
 
+	/* network header is after the ethernet header */
+	skb_set_network_header(skb, ETH_HLEN);
+
 	switch (action_code) {
 	case WLAN_TDLS_SETUP_REQUEST:
 		tf->category = WLAN_CATEGORY_TDLS;
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 3ace203..5153d12 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -672,13 +672,13 @@
 );
 
 TRACE_EVENT(drv_set_coverage_class,
-	TP_PROTO(struct ieee80211_local *local, u8 value),
+	TP_PROTO(struct ieee80211_local *local, s16 value),
 
 	TP_ARGS(local, value),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
-		__field(u8, value)
+		__field(s16, value)
 	),
 
 	TP_fast_assign(
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 190aa16..86ea121 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3,6 +3,7 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1478,7 +1479,10 @@
 		tail_need = max_t(int, tail_need, 0);
 	}
 
-	if (skb_cloned(skb))
+	if (skb_cloned(skb) &&
+	    (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CLONED_SKBS) ||
+	     !skb_clone_writable(skb, ETH_HLEN) ||
+	     sdata->crypto_tx_tailroom_needed_cnt))
 		I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
 	else if (head_need || tail_need)
 		I802_DEBUG_INC(local->tx_expand_skb_head);
@@ -1785,9 +1789,8 @@
  * @skb: packet to be sent
  * @dev: incoming interface
  *
- * Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will
- * not be freed, and caller is responsible for either retrying later or freeing
- * skb).
+ * Returns: NETDEV_TX_OK both on success and on failure. On failure skb will
+ *	be freed.
  *
  * This function takes in an Ethernet header and encapsulates it with suitable
  * IEEE 802.11 header based on which interface the packet is coming in. The
@@ -1844,7 +1847,7 @@
 			memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
 			hdrlen = 30;
 			authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
-			wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+			wme_sta = sta->sta.wme;
 		}
 		ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
 					u.ap);
@@ -1957,7 +1960,7 @@
 			if (sta) {
 				authorized = test_sta_flag(sta,
 							WLAN_STA_AUTHORIZED);
-				wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+				wme_sta = sta->sta.wme;
 				tdls_peer = test_sta_flag(sta,
 							  WLAN_STA_TDLS_PEER);
 				tdls_auth = test_sta_flag(sta,
@@ -2035,7 +2038,7 @@
 		sta = sta_info_get(sdata, hdr.addr1);
 		if (sta) {
 			authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
-			wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+			wme_sta = sta->sta.wme;
 		}
 	}
 
@@ -2070,30 +2073,23 @@
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
 	if (unlikely(!multicast && skb->sk &&
 		     skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) {
-		struct sk_buff *orig_skb = skb;
+		struct sk_buff *ack_skb = skb_clone_sk(skb);
 
-		skb = skb_clone(skb, GFP_ATOMIC);
-		if (skb) {
+		if (ack_skb) {
 			unsigned long flags;
 			int id;
 
 			spin_lock_irqsave(&local->ack_status_lock, flags);
-			id = idr_alloc(&local->ack_status_frames, orig_skb,
+			id = idr_alloc(&local->ack_status_frames, ack_skb,
 				       1, 0x10000, GFP_ATOMIC);
 			spin_unlock_irqrestore(&local->ack_status_lock, flags);
 
 			if (id >= 0) {
 				info_id = id;
 				info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
-			} else if (skb_shared(skb)) {
-				kfree_skb(orig_skb);
 			} else {
-				kfree_skb(skb);
-				skb = orig_skb;
+				kfree_skb(ack_skb);
 			}
-		} else {
-			/* couldn't clone -- lose tx status ... */
-			skb = orig_skb;
 		}
 	}
 #endif
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 725af7a..3c61060 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3,6 +3,7 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1014,6 +1015,31 @@
 			}
 			elems->pwr_constr_elem = pos;
 			break;
+		case WLAN_EID_CISCO_VENDOR_SPECIFIC:
+			/* Lots of different options exist, but we only care
+			 * about the Dynamic Transmit Power Control element.
+			 * First check for the Cisco OUI, then for the DTPC
+			 * tag (0x00).
+			 */
+			if (elen < 4) {
+				elem_parse_failed = true;
+				break;
+			}
+
+			if (pos[0] != 0x00 || pos[1] != 0x40 ||
+			    pos[2] != 0x96 || pos[3] != 0x00)
+				break;
+
+			if (elen != 6) {
+				elem_parse_failed = true;
+				break;
+			}
+
+			if (calc_crc)
+				crc = crc32_be(crc, pos - 2, elen + 2);
+
+			elems->cisco_dtpc_elem = pos;
+			break;
 		case WLAN_EID_TIMEOUT_INTERVAL:
 			if (elen >= sizeof(struct ieee80211_timeout_interval_ie))
 				elems->timeout_int = (void *)pos;
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 7963d9c..77509d8 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -1,5 +1,6 @@
 /*
  * Copyright 2004, Instant802 Networks, Inc.
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -118,7 +119,7 @@
 	case NL80211_IFTYPE_AP_VLAN:
 		sta = rcu_dereference(sdata->u.vlan.sta);
 		if (sta) {
-			qos = test_sta_flag(sta, WLAN_STA_WME);
+			qos = sta->sta.wme;
 			break;
 		}
 	case NL80211_IFTYPE_AP:
@@ -145,7 +146,7 @@
 	if (!sta && ra && !is_multicast_ether_addr(ra)) {
 		sta = sta_info_get(sdata, ra);
 		if (sta)
-			qos = test_sta_flag(sta, WLAN_STA_WME);
+			qos = sta->sta.wme;
 	}
 	rcu_read_unlock();
 
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index f7d4ca4..983527a 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -64,8 +64,11 @@
 	if (!info->control.hw_key)
 		tail += IEEE80211_TKIP_ICV_LEN;
 
-	if (WARN_ON(skb_tailroom(skb) < tail ||
-		    skb_headroom(skb) < IEEE80211_TKIP_IV_LEN))
+	if (WARN(skb_tailroom(skb) < tail ||
+		 skb_headroom(skb) < IEEE80211_TKIP_IV_LEN,
+		 "mmic: not enough head/tail (%d/%d,%d/%d)\n",
+		 skb_headroom(skb), IEEE80211_TKIP_IV_LEN,
+		 skb_tailroom(skb), tail))
 		return TX_DROP;
 
 	key = &tx->key->conf.key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY];
diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
index 7f820a1..a14cf9e 100644
--- a/net/mac802154/rx.c
+++ b/net/mac802154/rx.c
@@ -86,9 +86,8 @@
 static void mac802154_rx_worker(struct work_struct *work)
 {
 	struct rx_work *rw = container_of(work, struct rx_work, work);
-	struct sk_buff *skb = rw->skb;
 
-	mac802154_subif_rx(rw->dev, skb, rw->lqi);
+	mac802154_subif_rx(rw->dev, rw->skb, rw->lqi);
 	kfree(rw);
 }
 
@@ -101,7 +100,7 @@
 	if (!skb)
 		return;
 
-	work = kzalloc(sizeof(struct rx_work), GFP_ATOMIC);
+	work = kzalloc(sizeof(*work), GFP_ATOMIC);
 	if (!work)
 		return;
 
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index 8124353..fdf4c0e 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -89,8 +89,7 @@
 
 	if (!(priv->phy->channels_supported[page] & (1 << chan))) {
 		WARN_ON(1);
-		kfree_skb(skb);
-		return NETDEV_TX_OK;
+		goto err_tx;
 	}
 
 	mac802154_monitors_rx(mac802154_to_priv(&priv->hw), skb);
@@ -103,12 +102,10 @@
 		data[1] = crc >> 8;
 	}
 
-	if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) {
-		kfree_skb(skb);
-		return NETDEV_TX_OK;
-	}
+	if (skb_cow_head(skb, priv->hw.extra_tx_headroom))
+		goto err_tx;
 
-	work = kzalloc(sizeof(struct xmit_work), GFP_ATOMIC);
+	work = kzalloc(sizeof(*work), GFP_ATOMIC);
 	if (!work) {
 		kfree_skb(skb);
 		return NETDEV_TX_BUSY;
@@ -129,4 +126,8 @@
 	queue_work(priv->dev_workqueue, &work->work);
 
 	return NETDEV_TX_OK;
+
+err_tx:
+	kfree_skb(skb);
+	return NETDEV_TX_OK;
 }
diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c
index 5478388..4ab86a5 100644
--- a/net/mac802154/wpan.c
+++ b/net/mac802154/wpan.c
@@ -90,7 +90,7 @@
 	}
 	case SIOCSIFADDR:
 		dev_warn(&dev->dev,
-			 "Using DEBUGing ioctl SIOCSIFADDR isn't recommened!\n");
+			 "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n");
 		if (sa->family != AF_IEEE802154 ||
 		    sa->addr.addr_type != IEEE802154_ADDR_SHORT ||
 		    sa->addr.pan_id == IEEE802154_PANID_BROADCAST ||
@@ -475,8 +475,7 @@
 	rc = mac802154_llsec_decrypt(&sdata->sec, skb);
 	if (rc) {
 		pr_debug("decryption failed: %i\n", rc);
-		kfree_skb(skb);
-		return NET_RX_DROP;
+		goto fail;
 	}
 
 	sdata->dev->stats.rx_packets++;
@@ -488,9 +487,12 @@
 	default:
 		pr_warn("ieee802154: bad frame received (type = %d)\n",
 			mac_cb(skb)->type);
-		kfree_skb(skb);
-		return NET_RX_DROP;
+		goto fail;
 	}
+
+fail:
+	kfree_skb(skb);
+	return NET_RX_DROP;
 }
 
 static void mac802154_print_addr(const char *name,
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c
index e1638da..b60aa35 100644
--- a/net/nfc/digital_dep.c
+++ b/net/nfc/digital_dep.c
@@ -33,6 +33,8 @@
 #define DIGITAL_ATR_REQ_MAX_SIZE 64
 
 #define DIGITAL_LR_BITS_PAYLOAD_SIZE_254B 0x30
+#define DIGITAL_FSL_BITS_PAYLOAD_SIZE_254B \
+				(DIGITAL_LR_BITS_PAYLOAD_SIZE_254B >> 4)
 #define DIGITAL_GB_BIT	0x02
 
 #define DIGITAL_NFC_DEP_PFB_TYPE(pfb) ((pfb) & 0xE0)
@@ -127,6 +129,98 @@
 	return 0;
 }
 
+static void digital_in_recv_psl_res(struct nfc_digital_dev *ddev, void *arg,
+				    struct sk_buff *resp)
+{
+	struct nfc_target *target = arg;
+	struct digital_psl_res *psl_res;
+	int rc;
+
+	if (IS_ERR(resp)) {
+		rc = PTR_ERR(resp);
+		resp = NULL;
+		goto exit;
+	}
+
+	rc = ddev->skb_check_crc(resp);
+	if (rc) {
+		PROTOCOL_ERR("14.4.1.6");
+		goto exit;
+	}
+
+	rc = digital_skb_pull_dep_sod(ddev, resp);
+	if (rc) {
+		PROTOCOL_ERR("14.4.1.2");
+		goto exit;
+	}
+
+	psl_res = (struct digital_psl_res *)resp->data;
+
+	if ((resp->len != sizeof(*psl_res)) ||
+	    (psl_res->dir != DIGITAL_NFC_DEP_FRAME_DIR_IN) ||
+	    (psl_res->cmd != DIGITAL_CMD_PSL_RES)) {
+		rc = -EIO;
+		goto exit;
+	}
+
+	rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH,
+				     NFC_DIGITAL_RF_TECH_424F);
+	if (rc)
+		goto exit;
+
+	rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
+				     NFC_DIGITAL_FRAMING_NFCF_NFC_DEP);
+	if (rc)
+		goto exit;
+
+	if (!DIGITAL_DRV_CAPS_IN_CRC(ddev) &&
+	    (ddev->curr_rf_tech == NFC_DIGITAL_RF_TECH_106A)) {
+		ddev->skb_add_crc = digital_skb_add_crc_f;
+		ddev->skb_check_crc = digital_skb_check_crc_f;
+	}
+
+	ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_424F;
+
+	nfc_dep_link_is_up(ddev->nfc_dev, target->idx, NFC_COMM_ACTIVE,
+			   NFC_RF_INITIATOR);
+
+	ddev->curr_nfc_dep_pni = 0;
+
+exit:
+	dev_kfree_skb(resp);
+
+	if (rc)
+		ddev->curr_protocol = 0;
+}
+
+static int digital_in_send_psl_req(struct nfc_digital_dev *ddev,
+				   struct nfc_target *target)
+{
+	struct sk_buff *skb;
+	struct digital_psl_req *psl_req;
+
+	skb = digital_skb_alloc(ddev, sizeof(*psl_req));
+	if (!skb)
+		return -ENOMEM;
+
+	skb_put(skb, sizeof(*psl_req));
+
+	psl_req = (struct digital_psl_req *)skb->data;
+
+	psl_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT;
+	psl_req->cmd = DIGITAL_CMD_PSL_REQ;
+	psl_req->did = 0;
+	psl_req->brs = (0x2 << 3) | 0x2; /* 424F both directions */
+	psl_req->fsl = DIGITAL_FSL_BITS_PAYLOAD_SIZE_254B;
+
+	digital_skb_push_dep_sod(ddev, skb);
+
+	ddev->skb_add_crc(skb);
+
+	return digital_in_send_cmd(ddev, skb, 500, digital_in_recv_psl_res,
+				   target);
+}
+
 static void digital_in_recv_atr_res(struct nfc_digital_dev *ddev, void *arg,
 				 struct sk_buff *resp)
 {
@@ -166,6 +260,13 @@
 	if (rc)
 		goto exit;
 
+	if ((ddev->protocols & NFC_PROTO_FELICA_MASK) &&
+	    (ddev->curr_rf_tech != NFC_DIGITAL_RF_TECH_424F)) {
+		rc = digital_in_send_psl_req(ddev, target);
+		if (!rc)
+			goto exit;
+	}
+
 	rc = nfc_dep_link_is_up(ddev->nfc_dev, target->idx, NFC_COMM_ACTIVE,
 				NFC_RF_INITIATOR);
 
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 2b400e1..90b16cb 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -231,6 +231,14 @@
 		cmd.num_disc_configs++;
 	}
 
+	if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
+	    (protocols & NFC_PROTO_ISO15693_MASK)) {
+		cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
+			NCI_NFC_V_PASSIVE_POLL_MODE;
+		cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
+		cmd.num_disc_configs++;
+	}
+
 	nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_CMD,
 		     (1 + (cmd.num_disc_configs * sizeof(struct disc_config))),
 		     &cmd);
@@ -751,10 +759,6 @@
 	struct device *dev = &ndev->nfc_dev->dev;
 	char name[32];
 
-	rc = nfc_register_device(ndev->nfc_dev);
-	if (rc)
-		goto exit;
-
 	ndev->flags = 0;
 
 	INIT_WORK(&ndev->cmd_work, nci_cmd_work);
@@ -762,7 +766,7 @@
 	ndev->cmd_wq = create_singlethread_workqueue(name);
 	if (!ndev->cmd_wq) {
 		rc = -ENOMEM;
-		goto unreg_exit;
+		goto exit;
 	}
 
 	INIT_WORK(&ndev->rx_work, nci_rx_work);
@@ -792,6 +796,10 @@
 
 	mutex_init(&ndev->req_lock);
 
+	rc = nfc_register_device(ndev->nfc_dev);
+	if (rc)
+		goto destroy_rx_wq_exit;
+
 	goto exit;
 
 destroy_rx_wq_exit:
@@ -800,9 +808,6 @@
 destroy_cmd_wq_exit:
 	destroy_workqueue(ndev->cmd_wq);
 
-unreg_exit:
-	nfc_unregister_device(ndev->nfc_dev);
-
 exit:
 	return rc;
 }
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
index 6c3aef8..427ef2c 100644
--- a/net/nfc/nci/data.c
+++ b/net/nfc/nci/data.c
@@ -241,9 +241,12 @@
 	/* strip the nci data header */
 	skb_pull(skb, NCI_DATA_HDR_SIZE);
 
-	if (ndev->target_active_prot == NFC_PROTO_MIFARE) {
+	if (ndev->target_active_prot == NFC_PROTO_MIFARE ||
+	    ndev->target_active_prot == NFC_PROTO_JEWEL ||
+	    ndev->target_active_prot == NFC_PROTO_FELICA ||
+	    ndev->target_active_prot == NFC_PROTO_ISO15693) {
 		/* frame I/F => remove the status byte */
-		pr_debug("NFC_PROTO_MIFARE => remove the status byte\n");
+		pr_debug("frame I/F => remove the status byte\n");
 		skb_trim(skb, (skb->len - 1));
 	}
 
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
index df91bb9..205b35f 100644
--- a/net/nfc/nci/ntf.c
+++ b/net/nfc/nci/ntf.c
@@ -2,6 +2,7 @@
  *  The NFC Controller Interface is the communication protocol between an
  *  NFC Controller (NFCC) and a Device Host (DH).
  *
+ *  Copyright (C) 2014 Marvell International Ltd.
  *  Copyright (C) 2011 Texas Instruments, Inc.
  *
  *  Written by Ilan Elias <ilane@ti.com>
@@ -155,6 +156,24 @@
 	return data;
 }
 
+static __u8 *nci_extract_rf_params_nfcv_passive_poll(struct nci_dev *ndev,
+			struct rf_tech_specific_params_nfcv_poll *nfcv_poll,
+						     __u8 *data)
+{
+	++data;
+	nfcv_poll->dsfid = *data++;
+	memcpy(nfcv_poll->uid, data, NFC_ISO15693_UID_MAXSIZE);
+	data += NFC_ISO15693_UID_MAXSIZE;
+	return data;
+}
+
+__u32 nci_get_prop_rf_protocol(struct nci_dev *ndev, __u8 rf_protocol)
+{
+	if (ndev->ops->get_rfprotocol)
+		return ndev->ops->get_rfprotocol(ndev, rf_protocol);
+	return 0;
+}
+
 static int nci_add_new_protocol(struct nci_dev *ndev,
 				struct nfc_target *target,
 				__u8 rf_protocol,
@@ -164,6 +183,7 @@
 	struct rf_tech_specific_params_nfca_poll *nfca_poll;
 	struct rf_tech_specific_params_nfcb_poll *nfcb_poll;
 	struct rf_tech_specific_params_nfcf_poll *nfcf_poll;
+	struct rf_tech_specific_params_nfcv_poll *nfcv_poll;
 	__u32 protocol;
 
 	if (rf_protocol == NCI_RF_PROTOCOL_T1T)
@@ -179,8 +199,10 @@
 		protocol = NFC_PROTO_FELICA_MASK;
 	else if (rf_protocol == NCI_RF_PROTOCOL_NFC_DEP)
 		protocol = NFC_PROTO_NFC_DEP_MASK;
+	else if (rf_protocol == NCI_RF_PROTOCOL_T5T)
+		protocol = NFC_PROTO_ISO15693_MASK;
 	else
-		protocol = 0;
+		protocol = nci_get_prop_rf_protocol(ndev, rf_protocol);
 
 	if (!(protocol & ndev->poll_prots)) {
 		pr_err("the target found does not have the desired protocol\n");
@@ -213,6 +235,12 @@
 			memcpy(target->sensf_res, nfcf_poll->sensf_res,
 			       target->sensf_res_len);
 		}
+	} else if (rf_tech_and_mode == NCI_NFC_V_PASSIVE_POLL_MODE) {
+		nfcv_poll = (struct rf_tech_specific_params_nfcv_poll *)params;
+
+		target->is_iso15693 = 1;
+		target->iso15693_dsfid = nfcv_poll->dsfid;
+		memcpy(target->iso15693_uid, nfcv_poll->uid, NFC_ISO15693_UID_MAXSIZE);
 	} else {
 		pr_err("unsupported rf_tech_and_mode 0x%x\n", rf_tech_and_mode);
 		return -EPROTO;
@@ -305,6 +333,11 @@
 				&(ntf.rf_tech_specific_params.nfcf_poll), data);
 			break;
 
+		case NCI_NFC_V_PASSIVE_POLL_MODE:
+			data = nci_extract_rf_params_nfcv_passive_poll(ndev,
+				&(ntf.rf_tech_specific_params.nfcv_poll), data);
+			break;
+
 		default:
 			pr_err("unsupported rf_tech_and_mode 0x%x\n",
 			       ntf.rf_tech_and_mode);
@@ -455,6 +488,11 @@
 				&(ntf.rf_tech_specific_params.nfcf_poll), data);
 			break;
 
+		case NCI_NFC_V_PASSIVE_POLL_MODE:
+			data = nci_extract_rf_params_nfcv_passive_poll(ndev,
+				&(ntf.rf_tech_specific_params.nfcv_poll), data);
+			break;
+
 		default:
 			pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
 			       ntf.activation_rf_tech_and_mode);
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index faa05ba..8f21d4e 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -4,6 +4,7 @@
  * any point in time.
  *
  * Copyright 2009	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  */
 
 #include <linux/export.h>
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 78c471d..45d0435 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -2,6 +2,7 @@
  * This is the linux wireless configuration interface.
  *
  * Copyright 2006-2010		Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -499,12 +500,6 @@
 	int i;
 	u16 ifmodes = wiphy->interface_modes;
 
-	/*
-	 * There are major locking problems in nl80211/mac80211 for CSA,
-	 * disable for all drivers until this has been reworked.
-	 */
-	wiphy->flags &= ~WIPHY_FLAG_HAS_CHANNEL_SWITCH;
-
 #ifdef CONFIG_PM
 	if (WARN_ON(wiphy->wowlan &&
 		    (wiphy->wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
@@ -642,6 +637,9 @@
 	if (IS_ERR(rdev->wiphy.debugfsdir))
 		rdev->wiphy.debugfsdir = NULL;
 
+	cfg80211_debugfs_rdev_add(rdev);
+	nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
+
 	if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
 		struct regulatory_request request;
 
@@ -653,8 +651,6 @@
 		nl80211_send_reg_change_event(&request);
 	}
 
-	cfg80211_debugfs_rdev_add(rdev);
-
 	rdev->wiphy.registered = true;
 	rtnl_unlock();
 
@@ -666,8 +662,6 @@
 		return res;
 	}
 
-	nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
-
 	return 0;
 }
 EXPORT_SYMBOL(wiphy_register);
@@ -1028,7 +1022,7 @@
 			rdev->devlist_generation++;
 			cfg80211_mlme_purge_registrations(wdev);
 #ifdef CPTCFG_CFG80211_WEXT
-			kfree(wdev->wext.keys);
+			kzfree(wdev->wext.keys);
 #endif
 		}
 		/*
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 7b87843..49a70c9 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -115,7 +115,7 @@
 	}
 
 	if (WARN_ON(wdev->connect_keys))
-		kfree(wdev->connect_keys);
+		kzfree(wdev->connect_keys);
 	wdev->connect_keys = connkeys;
 
 	wdev->ibss_fixed = params->channel_fixed;
@@ -161,7 +161,7 @@
 
 	ASSERT_WDEV_LOCK(wdev);
 
-	kfree(wdev->connect_keys);
+	kzfree(wdev->connect_keys);
 	wdev->connect_keys = NULL;
 
 	rdev_set_qos_map(rdev, dev, NULL);
diff --git a/net/wireless/lib80211.c b/net/wireless/lib80211.c
index a55c27b..4596115 100644
--- a/net/wireless/lib80211.c
+++ b/net/wireless/lib80211.c
@@ -46,38 +46,6 @@
 static void lib80211_crypt_quiescing(struct lib80211_crypt_info *info);
 static void lib80211_crypt_deinit_handler(unsigned long data);
 
-const char *print_ssid(char *buf, const char *ssid, u8 ssid_len)
-{
-	const char *s = ssid;
-	char *d = buf;
-
-	ssid_len = min_t(u8, ssid_len, IEEE80211_MAX_SSID_LEN);
-	while (ssid_len--) {
-		if (isprint(*s)) {
-			*d++ = *s++;
-			continue;
-		}
-
-		*d++ = '\\';
-		if (*s == '\0')
-			*d++ = '0';
-		else if (*s == '\n')
-			*d++ = 'n';
-		else if (*s == '\r')
-			*d++ = 'r';
-		else if (*s == '\t')
-			*d++ = 't';
-		else if (*s == '\\')
-			*d++ = '\\';
-		else
-			d += snprintf(d, 3, "%03o", *s);
-		s++;
-	}
-	*d = '\0';
-	return buf;
-}
-EXPORT_SYMBOL(print_ssid);
-
 int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name,
 				spinlock_t *lock)
 {
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 3ddad8d..9b18d93 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -19,7 +19,7 @@
 
 
 void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
-			    const u8 *buf, size_t len)
+			    const u8 *buf, size_t len, int uapsd_queues)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct wiphy *wiphy = wdev->wiphy;
@@ -43,7 +43,7 @@
 		return;
 	}
 
-	nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
+	nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues);
 	/* update current_bss etc., consumes the bss reference */
 	__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
 				  status_code,
@@ -605,7 +605,7 @@
 }
 
 bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
-		      const u8 *buf, size_t len, u32 flags, gfp_t gfp)
+		      const u8 *buf, size_t len, u32 flags)
 {
 	struct wiphy *wiphy = wdev->wiphy;
 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
@@ -648,7 +648,7 @@
 		/* Indicate the received Action frame to user space */
 		if (nl80211_send_mgmt(rdev, wdev, reg->nlportid,
 				      freq, sig_mbm,
-				      buf, len, flags, gfp))
+				      buf, len, flags, GFP_ATOMIC))
 			continue;
 
 		result = true;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e25a50c..f84c236 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2,6 +2,7 @@
  * This is the new netlink-based wireless configuration interface.
  *
  * Copyright 2006-2010	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  */
 
 #include <linux/if.h>
@@ -225,6 +226,7 @@
 	[NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
 	[NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },
 	[NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 },
+	[NL80211_ATTR_WIPHY_DYN_ACK] = { .type = NLA_FLAG },
 
 	[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
 	[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
@@ -388,6 +390,11 @@
 	[NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
 	[NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
 	[NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
+	[NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
+	[NL80211_ATTR_TSID] = { .type = NLA_U8 },
+	[NL80211_ATTR_USER_PRIO] = { .type = NLA_U8 },
+	[NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
+	[NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
 };
 
 /* policy for the key attributes */
@@ -1507,6 +1514,9 @@
 			if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
 				CMD(channel_switch, CHANNEL_SWITCH);
 			CMD(set_qos_map, SET_QOS_MAP);
+			if (rdev->wiphy.flags &
+					WIPHY_FLAG_SUPPORTS_WMM_ADMISSION)
+				CMD(add_tx_ts, ADD_TX_TS);
 		}
 		/* add into the if now */
 #undef CMD
@@ -2239,11 +2249,21 @@
 	}
 
 	if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
+		if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK])
+			return -EINVAL;
+
 		coverage_class = nla_get_u8(
 			info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
 		changed |= WIPHY_PARAM_COVERAGE_CLASS;
 	}
 
+	if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
+		if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION))
+			return -EOPNOTSUPP;
+
+		changed |= WIPHY_PARAM_DYN_ACK;
+	}
+
 	if (changed) {
 		u8 old_retry_short, old_retry_long;
 		u32 old_frag_threshold, old_rts_threshold;
@@ -3329,6 +3349,29 @@
 			return PTR_ERR(params.acl);
 	}
 
+	if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
+		params.smps_mode =
+			nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
+		switch (params.smps_mode) {
+		case NL80211_SMPS_OFF:
+			break;
+		case NL80211_SMPS_STATIC:
+			if (!(rdev->wiphy.features &
+			      NL80211_FEATURE_STATIC_SMPS))
+				return -EINVAL;
+			break;
+		case NL80211_SMPS_DYNAMIC:
+			if (!(rdev->wiphy.features &
+			      NL80211_FEATURE_DYNAMIC_SMPS))
+				return -EINVAL;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		params.smps_mode = NL80211_SMPS_OFF;
+	}
+
 	wdev_lock(wdev);
 	err = rdev_start_ap(rdev, dev, &params);
 	if (!err) {
@@ -6038,7 +6081,6 @@
 	const struct cfg80211_bss_ies *ies;
 	void *hdr;
 	struct nlattr *bss;
-	bool tsf = false;
 
 	ASSERT_WDEV_LOCK(wdev);
 
@@ -6065,18 +6107,27 @@
 		goto nla_put_failure;
 
 	rcu_read_lock();
+	/* indicate whether we have probe response data or not */
+	if (rcu_access_pointer(res->proberesp_ies) &&
+	    nla_put_flag(msg, NL80211_BSS_PRESP_DATA))
+		goto fail_unlock_rcu;
+
+	/* this pointer prefers to be pointed to probe response data
+	 * but is always valid
+	 */
 	ies = rcu_dereference(res->ies);
 	if (ies) {
 		if (nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf))
 			goto fail_unlock_rcu;
-		tsf = true;
 		if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
 					ies->len, ies->data))
 			goto fail_unlock_rcu;
 	}
+
+	/* and this pointer is always (unless driver didn't know) beacon data */
 	ies = rcu_dereference(res->beacon_ies);
-	if (ies) {
-		if (!tsf && nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf))
+	if (ies && ies->from_beacon) {
+		if (nla_put_u64(msg, NL80211_BSS_BEACON_TSF, ies->tsf))
 			goto fail_unlock_rcu;
 		if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
 					ies->len, ies->data))
@@ -6582,6 +6633,14 @@
 		       sizeof(req.vht_capa));
 	}
 
+	if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
+		if (!(rdev->wiphy.features &
+		      NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) ||
+		    !(rdev->wiphy.features & NL80211_FEATURE_QUIET))
+			return -EINVAL;
+		req.flags |= ASSOC_REQ_USE_RRM;
+	}
+
 	err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
 	if (!err) {
 		wdev_lock(dev->ieee80211_ptr);
@@ -6844,7 +6903,7 @@
 
 	err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
 	if (err)
-		kfree(connkeys);
+		kzfree(connkeys);
 	return err;
 }
 
@@ -7216,7 +7275,7 @@
 
 	if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
 		if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
-			kfree(connkeys);
+			kzfree(connkeys);
 			return -EINVAL;
 		}
 		memcpy(&connect.ht_capa,
@@ -7234,7 +7293,7 @@
 
 	if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
 		if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
-			kfree(connkeys);
+			kzfree(connkeys);
 			return -EINVAL;
 		}
 		memcpy(&connect.vht_capa,
@@ -7242,11 +7301,19 @@
 		       sizeof(connect.vht_capa));
 	}
 
+	if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
+		if (!(rdev->wiphy.features &
+		      NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) ||
+		    !(rdev->wiphy.features & NL80211_FEATURE_QUIET))
+			return -EINVAL;
+		connect.flags |= ASSOC_REQ_USE_RRM;
+	}
+
 	wdev_lock(dev->ieee80211_ptr);
 	err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL);
 	wdev_unlock(dev->ieee80211_ptr);
 	if (err)
-		kfree(connkeys);
+		kzfree(connkeys);
 	return err;
 }
 
@@ -8938,13 +9005,9 @@
 	if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
 		return -ERANGE;
 
-	memcpy(rekey_data.kek, nla_data(tb[NL80211_REKEY_DATA_KEK]),
-	       NL80211_KEK_LEN);
-	memcpy(rekey_data.kck, nla_data(tb[NL80211_REKEY_DATA_KCK]),
-	       NL80211_KCK_LEN);
-	memcpy(rekey_data.replay_ctr,
-	       nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]),
-	       NL80211_REPLAY_CTR_LEN);
+	rekey_data.kek = nla_data(tb[NL80211_REKEY_DATA_KEK]);
+	rekey_data.kck = nla_data(tb[NL80211_REKEY_DATA_KCK]);
+	rekey_data.replay_ctr = nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]);
 
 	wdev_lock(wdev);
 	if (!wdev->current_bss) {
@@ -9378,6 +9441,93 @@
 	return ret;
 }
 
+static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	const u8 *peer;
+	u8 tsid, up;
+	u16 admitted_time = 0;
+	int err;
+
+	if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION))
+		return -EOPNOTSUPP;
+
+	if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
+	    !info->attrs[NL80211_ATTR_USER_PRIO])
+		return -EINVAL;
+
+	tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
+	if (tsid >= IEEE80211_NUM_TIDS)
+		return -EINVAL;
+
+	up = nla_get_u8(info->attrs[NL80211_ATTR_USER_PRIO]);
+	if (up >= IEEE80211_NUM_UPS)
+		return -EINVAL;
+
+	/* WMM uses TIDs 0-7 even for TSPEC */
+	if (tsid < IEEE80211_FIRST_TSPEC_TSID) {
+		if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION))
+			return -EINVAL;
+	} else {
+		/* TODO: handle 802.11 TSPEC/admission control
+		 * need more attributes for that (e.g. BA session requirement)
+		 */
+		return -EINVAL;
+	}
+
+	peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+	if (info->attrs[NL80211_ATTR_ADMITTED_TIME]) {
+		admitted_time =
+			nla_get_u16(info->attrs[NL80211_ATTR_ADMITTED_TIME]);
+		if (!admitted_time)
+			return -EINVAL;
+	}
+
+	wdev_lock(wdev);
+	switch (wdev->iftype) {
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_P2P_CLIENT:
+		if (wdev->current_bss)
+			break;
+		err = -ENOTCONN;
+		goto out;
+	default:
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	err = rdev_add_tx_ts(rdev, dev, tsid, peer, up, admitted_time);
+
+ out:
+	wdev_unlock(wdev);
+	return err;
+}
+
+static int nl80211_del_tx_ts(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	const u8 *peer;
+	u8 tsid;
+	int err;
+
+	if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC])
+		return -EINVAL;
+
+	tsid = nla_get_u8(info->attrs[NL80211_ATTR_TSID]);
+	peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+	wdev_lock(wdev);
+	err = rdev_del_tx_ts(rdev, dev, tsid, peer);
+	wdev_unlock(wdev);
+
+	return err;
+}
+
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -9388,6 +9538,7 @@
 /* If a netdev is associated, it must be UP, P2P must be started */
 #define NL80211_FLAG_NEED_WDEV_UP	(NL80211_FLAG_NEED_WDEV |\
 					 NL80211_FLAG_CHECK_NETDEV_UP)
+#define NL80211_FLAG_CLEAR_SKB		0x20
 
 static int nl80211_pre_doit(__genl_const struct genl_ops *ops, struct sk_buff *skb,
 			    struct genl_info *info)
@@ -9471,8 +9622,20 @@
 			dev_put(info->user_ptr[1]);
 		}
 	}
+
 	if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
 		rtnl_unlock();
+
+	/* If needed, clear the netlink message payload from the SKB
+	 * as it might contain key data that shouldn't stick around on
+	 * the heap after the SKB is freed. The netlink message header
+	 * is still needed for further processing, so leave it intact.
+	 */
+	if (ops->internal_flags & NL80211_FLAG_CLEAR_SKB) {
+		struct nlmsghdr *nlh = nlmsg_hdr(skb);
+
+		memset(nlmsg_data(nlh), 0, nlmsg_len(nlh));
+	}
 }
 
 static __genl_const struct genl_ops nl80211_ops[] = {
@@ -9540,7 +9703,8 @@
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-				  NL80211_FLAG_NEED_RTNL,
+				  NL80211_FLAG_NEED_RTNL |
+				  NL80211_FLAG_CLEAR_SKB,
 	},
 	{
 		.cmd = NL80211_CMD_NEW_KEY,
@@ -9548,7 +9712,8 @@
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-				  NL80211_FLAG_NEED_RTNL,
+				  NL80211_FLAG_NEED_RTNL |
+				  NL80211_FLAG_CLEAR_SKB,
 	},
 	{
 		.cmd = NL80211_CMD_DEL_KEY,
@@ -9726,7 +9891,8 @@
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-				  NL80211_FLAG_NEED_RTNL,
+				  NL80211_FLAG_NEED_RTNL |
+				  NL80211_FLAG_CLEAR_SKB,
 	},
 	{
 		.cmd = NL80211_CMD_ASSOCIATE,
@@ -9960,7 +10126,8 @@
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-				  NL80211_FLAG_NEED_RTNL,
+				  NL80211_FLAG_NEED_RTNL |
+				  NL80211_FLAG_CLEAR_SKB,
 	},
 	{
 		.cmd = NL80211_CMD_TDLS_MGMT,
@@ -10118,6 +10285,22 @@
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_ADD_TX_TS,
+		.doit = nl80211_add_tx_ts,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
+		.cmd = NL80211_CMD_DEL_TX_TS,
+		.doit = nl80211_del_tx_ts,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
 };
 
 /* notification functions */
@@ -10386,7 +10569,8 @@
 static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
 				    struct net_device *netdev,
 				    const u8 *buf, size_t len,
-				    enum nl80211_commands cmd, gfp_t gfp)
+				    enum nl80211_commands cmd, gfp_t gfp,
+				    int uapsd_queues)
 {
 	struct sk_buff *msg;
 	void *hdr;
@@ -10406,6 +10590,19 @@
 	    nla_put(msg, NL80211_ATTR_FRAME, len, buf))
 		goto nla_put_failure;
 
+	if (uapsd_queues >= 0) {
+		struct nlattr *nla_wmm =
+			nla_nest_start(msg, NL80211_ATTR_STA_WME);
+		if (!nla_wmm)
+			goto nla_put_failure;
+
+		if (nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
+			       uapsd_queues))
+			goto nla_put_failure;
+
+		nla_nest_end(msg, nla_wmm);
+	}
+
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
@@ -10422,15 +10619,15 @@
 			  size_t len, gfp_t gfp)
 {
 	nl80211_send_mlme_event(rdev, netdev, buf, len,
-				NL80211_CMD_AUTHENTICATE, gfp);
+				NL80211_CMD_AUTHENTICATE, gfp, -1);
 }
 
 void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
 			   struct net_device *netdev, const u8 *buf,
-			   size_t len, gfp_t gfp)
+			   size_t len, gfp_t gfp, int uapsd_queues)
 {
 	nl80211_send_mlme_event(rdev, netdev, buf, len,
-				NL80211_CMD_ASSOCIATE, gfp);
+				NL80211_CMD_ASSOCIATE, gfp, uapsd_queues);
 }
 
 void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
@@ -10438,7 +10635,7 @@
 			 size_t len, gfp_t gfp)
 {
 	nl80211_send_mlme_event(rdev, netdev, buf, len,
-				NL80211_CMD_DEAUTHENTICATE, gfp);
+				NL80211_CMD_DEAUTHENTICATE, gfp, -1);
 }
 
 void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
@@ -10446,7 +10643,7 @@
 			   size_t len, gfp_t gfp)
 {
 	nl80211_send_mlme_event(rdev, netdev, buf, len,
-				NL80211_CMD_DISASSOCIATE, gfp);
+				NL80211_CMD_DISASSOCIATE, gfp, -1);
 }
 
 void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
@@ -10467,7 +10664,7 @@
 		cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
 
 	trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
-	nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC);
+	nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1);
 }
 EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
 
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 49c9a48..7ad70d6 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -23,7 +23,8 @@
 			  const u8 *buf, size_t len, gfp_t gfp);
 void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
 			   struct net_device *netdev,
-			   const u8 *buf, size_t len, gfp_t gfp);
+			   const u8 *buf, size_t len, gfp_t gfp,
+			   int uapsd_queues);
 void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
 			 struct net_device *netdev,
 			 const u8 *buf, size_t len, gfp_t gfp);
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 765b3f7..6a1867f 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -915,4 +915,35 @@
 	return ret;
 }
 
+static inline int
+rdev_add_tx_ts(struct cfg80211_registered_device *rdev,
+	       struct net_device *dev, u8 tsid, const u8 *peer,
+	       u8 user_prio, u16 admitted_time)
+{
+	int ret = -EOPNOTSUPP;
+
+	trace_rdev_add_tx_ts(&rdev->wiphy, dev, tsid, peer,
+			     user_prio, admitted_time);
+	if (rdev->ops->add_tx_ts)
+		ret = rdev->ops->add_tx_ts(&rdev->wiphy, dev, tsid, peer,
+					   user_prio, admitted_time);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+
+	return ret;
+}
+
+static inline int
+rdev_del_tx_ts(struct cfg80211_registered_device *rdev,
+	       struct net_device *dev, u8 tsid, const u8 *peer)
+{
+	int ret = -EOPNOTSUPP;
+
+	trace_rdev_del_tx_ts(&rdev->wiphy, dev, tsid, peer);
+	if (rdev->ops->del_tx_ts)
+		ret = rdev->ops->del_tx_ts(&rdev->wiphy, dev, tsid, peer);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+
+	return ret;
+}
+
 #endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index e18324e..78d0648 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -3,6 +3,7 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2008-2011	Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -798,6 +799,57 @@
 	return 0;
 }
 
+/* check whether old rule contains new rule */
+static bool rule_contains(struct ieee80211_reg_rule *r1,
+			  struct ieee80211_reg_rule *r2)
+{
+	/* for simplicity, currently consider only same flags */
+	if (r1->flags != r2->flags)
+		return false;
+
+	/* verify r1 is more restrictive */
+	if ((r1->power_rule.max_antenna_gain >
+	     r2->power_rule.max_antenna_gain) ||
+	    r1->power_rule.max_eirp > r2->power_rule.max_eirp)
+		return false;
+
+	/* make sure r2's range is contained within r1 */
+	if (r1->freq_range.start_freq_khz > r2->freq_range.start_freq_khz ||
+	    r1->freq_range.end_freq_khz < r2->freq_range.end_freq_khz)
+		return false;
+
+	/* and finally verify that r1.max_bw >= r2.max_bw */
+	if (r1->freq_range.max_bandwidth_khz <
+	    r2->freq_range.max_bandwidth_khz)
+		return false;
+
+	return true;
+}
+
+/* add or extend current rules. do nothing if rule is already contained */
+static void add_rule(struct ieee80211_reg_rule *rule,
+		     struct ieee80211_reg_rule *reg_rules, u32 *n_rules)
+{
+	struct ieee80211_reg_rule *tmp_rule;
+	int i;
+
+	for (i = 0; i < *n_rules; i++) {
+		tmp_rule = &reg_rules[i];
+		/* rule is already contained - do nothing */
+		if (rule_contains(tmp_rule, rule))
+			return;
+
+		/* extend rule if possible */
+		if (rule_contains(rule, tmp_rule)) {
+			memcpy(tmp_rule, rule, sizeof(*rule));
+			return;
+		}
+	}
+
+	memcpy(&reg_rules[*n_rules], rule, sizeof(*rule));
+	(*n_rules)++;
+}
+
 /**
  * regdom_intersect - do the intersection between two regulatory domains
  * @rd1: first regulatory domain
@@ -817,12 +869,10 @@
 {
 	int r, size_of_regd;
 	unsigned int x, y;
-	unsigned int num_rules = 0, rule_idx = 0;
+	unsigned int num_rules = 0;
 	const struct ieee80211_reg_rule *rule1, *rule2;
-	struct ieee80211_reg_rule *intersected_rule;
+	struct ieee80211_reg_rule intersected_rule;
 	struct ieee80211_regdomain *rd;
-	/* This is just a dummy holder to help us count */
-	struct ieee80211_reg_rule dummy_rule;
 
 	if (!rd1 || !rd2)
 		return NULL;
@@ -840,7 +890,7 @@
 		for (y = 0; y < rd2->n_reg_rules; y++) {
 			rule2 = &rd2->reg_rules[y];
 			if (!reg_rules_intersect(rd1, rd2, rule1, rule2,
-						 &dummy_rule))
+						 &intersected_rule))
 				num_rules++;
 		}
 	}
@@ -855,34 +905,24 @@
 	if (!rd)
 		return NULL;
 
-	for (x = 0; x < rd1->n_reg_rules && rule_idx < num_rules; x++) {
+	for (x = 0; x < rd1->n_reg_rules; x++) {
 		rule1 = &rd1->reg_rules[x];
-		for (y = 0; y < rd2->n_reg_rules && rule_idx < num_rules; y++) {
+		for (y = 0; y < rd2->n_reg_rules; y++) {
 			rule2 = &rd2->reg_rules[y];
-			/*
-			 * This time around instead of using the stack lets
-			 * write to the target rule directly saving ourselves
-			 * a memcpy()
-			 */
-			intersected_rule = &rd->reg_rules[rule_idx];
 			r = reg_rules_intersect(rd1, rd2, rule1, rule2,
-						intersected_rule);
+						&intersected_rule);
 			/*
 			 * No need to memset here the intersected rule here as
 			 * we're not using the stack anymore
 			 */
 			if (r)
 				continue;
-			rule_idx++;
+
+			add_rule(&intersected_rule, rd->reg_rules,
+				 &rd->n_reg_rules);
 		}
 	}
 
-	if (rule_idx != num_rules) {
-		kfree(rd);
-		return NULL;
-	}
-
-	rd->n_reg_rules = num_rules;
 	rd->alpha2[0] = '9';
 	rd->alpha2[1] = '8';
 	rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region,
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index e64a685..f3ac474 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -2,6 +2,7 @@
  * cfg80211 scan result handling
  *
  * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  */
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -884,6 +885,7 @@
 cfg80211_inform_bss_width(struct wiphy *wiphy,
 			  struct ieee80211_channel *rx_channel,
 			  enum nl80211_bss_scan_width scan_width,
+			  enum cfg80211_bss_frame_type ftype,
 			  const u8 *bssid, u64 tsf, u16 capability,
 			  u16 beacon_interval, const u8 *ie, size_t ielen,
 			  s32 signal, gfp_t gfp)
@@ -911,21 +913,32 @@
 	tmp.pub.beacon_interval = beacon_interval;
 	tmp.pub.capability = capability;
 	/*
-	 * Since we do not know here whether the IEs are from a Beacon or Probe
+	 * If we do not know here whether the IEs are from a Beacon or Probe
 	 * Response frame, we need to pick one of the options and only use it
 	 * with the driver that does not provide the full Beacon/Probe Response
 	 * frame. Use Beacon frame pointer to avoid indicating that this should
 	 * override the IEs pointer should we have received an earlier
 	 * indication of Probe Response data.
 	 */
-	ies = kmalloc(sizeof(*ies) + ielen, gfp);
+	ies = kzalloc(sizeof(*ies) + ielen, gfp);
 	if (!ies)
 		return NULL;
 	ies->len = ielen;
 	ies->tsf = tsf;
+	ies->from_beacon = false;
 	memcpy(ies->data, ie, ielen);
 
-	rcu_assign_pointer(tmp.pub.beacon_ies, ies);
+	switch (ftype) {
+	case CFG80211_BSS_FTYPE_BEACON:
+		ies->from_beacon = true;
+		/* fall through to assign */
+	case CFG80211_BSS_FTYPE_UNKNOWN:
+		rcu_assign_pointer(tmp.pub.beacon_ies, ies);
+		break;
+	case CFG80211_BSS_FTYPE_PRESP:
+		rcu_assign_pointer(tmp.pub.proberesp_ies, ies);
+		break;
+	}
 	rcu_assign_pointer(tmp.pub.ies, ies);
 
 	signal_valid = abs(rx_channel->center_freq - channel->center_freq) <=
@@ -982,11 +995,12 @@
 	if (!channel)
 		return NULL;
 
-	ies = kmalloc(sizeof(*ies) + ielen, gfp);
+	ies = kzalloc(sizeof(*ies) + ielen, gfp);
 	if (!ies)
 		return NULL;
 	ies->len = ielen;
 	ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
+	ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control);
 	memcpy(ies->data, mgmt->u.probe_resp.variable, ielen);
 
 	if (ieee80211_is_probe_resp(mgmt->frame_control))
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 7fb5063..f365a0c 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -641,7 +641,7 @@
 	}
 
 	if (status != WLAN_STATUS_SUCCESS) {
-		kfree(wdev->connect_keys);
+		kzfree(wdev->connect_keys);
 		wdev->connect_keys = NULL;
 		wdev->ssid_len = 0;
 		if (bss) {
@@ -918,7 +918,7 @@
 	ASSERT_WDEV_LOCK(wdev);
 
 	if (WARN_ON(wdev->connect_keys)) {
-		kfree(wdev->connect_keys);
+		kzfree(wdev->connect_keys);
 		wdev->connect_keys = NULL;
 	}
 
@@ -978,7 +978,7 @@
 
 	ASSERT_WDEV_LOCK(wdev);
 
-	kfree(wdev->connect_keys);
+	kzfree(wdev->connect_keys);
 	wdev->connect_keys = NULL;
 
 	if (wdev->conn)
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 7024001..c9b6b8e 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1896,6 +1896,51 @@
 		  WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG)
 );
 
+TRACE_EVENT(rdev_add_tx_ts,
+	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+		 u8 tsid, const u8 *peer, u8 user_prio, u16 admitted_time),
+	TP_ARGS(wiphy, netdev, tsid, peer, user_prio, admitted_time),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		NETDEV_ENTRY
+		MAC_ENTRY(peer)
+		__field(u8, tsid)
+		__field(u8, user_prio)
+		__field(u16, admitted_time)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		NETDEV_ASSIGN;
+		MAC_ASSIGN(peer, peer);
+		__entry->tsid = tsid;
+		__entry->user_prio = user_prio;
+		__entry->admitted_time = admitted_time;
+	),
+	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", TSID %d, UP %d, time %d",
+		  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer),
+		  __entry->tsid, __entry->user_prio, __entry->admitted_time)
+);
+
+TRACE_EVENT(rdev_del_tx_ts,
+	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+		 u8 tsid, const u8 *peer),
+	TP_ARGS(wiphy, netdev, tsid, peer),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		NETDEV_ENTRY
+		MAC_ENTRY(peer)
+		__field(u8, tsid)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		NETDEV_ASSIGN;
+		MAC_ASSIGN(peer, peer);
+		__entry->tsid = tsid;
+	),
+	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", TSID %d",
+		  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tsid)
+);
+
 /*************************************************************
  *	     cfg80211 exported functions traces		     *
  *************************************************************/
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 728f1c0..5e233a5 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -2,6 +2,7 @@
  * Wireless utility functions
  *
  * Copyright 2007-2009	Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  */
 #include <linux/export.h>
 #include <linux/bitops.h>
@@ -796,7 +797,7 @@
 				netdev_err(dev, "failed to set mgtdef %d\n", i);
 	}
 
-	kfree(wdev->connect_keys);
+	kzfree(wdev->connect_keys);
 	wdev->connect_keys = NULL;
 }
 
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 11120bb..0f47948 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -496,6 +496,8 @@
 			err = 0;
 		if (!err) {
 			if (!addr) {
+				memset(wdev->wext.keys->data[idx], 0,
+				       sizeof(wdev->wext.keys->data[idx]));
 				wdev->wext.keys->params[idx].key_len = 0;
 				wdev->wext.keys->params[idx].cipher = 0;
 			}
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index c7e5c8e..368611c 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -57,7 +57,7 @@
 	err = cfg80211_connect(rdev, wdev->netdev,
 			       &wdev->wext.connect, ck, prev_bssid);
 	if (err)
-		kfree(ck);
+		kzfree(ck);
 
 	return err;
 }
diff --git a/versions b/versions
index a13d801..1be7d6d 100644
--- a/versions
+++ b/versions
@@ -1,3 +1,3 @@
-BACKPORTS_VERSION="v3.17.1-1-0-g2ced168"
-BACKPORTED_KERNEL_VERSION="v3.17.1-0-g9db8a8b"
+BACKPORTS_VERSION="v3.18-rc1-1-0-g1f4af51"
+BACKPORTED_KERNEL_VERSION="v3.18-rc1-0-gf114040"
 BACKPORTED_KERNEL_NAME="Linux"